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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2020-02-01 05:35:40 +0300
committerYimingWu <xp8110@outlook.com>2020-02-01 05:35:40 +0300
commitf7770cb97bb9d19d0806f67da9377129fd4d09b0 (patch)
tree2cd22d612ffba3a509d5548332c9cc8a06a1a638 /source/blender
parentb47883a990ee68e659a8a8b44729be9b8e0d002f (diff)
parentdc3f073d1c5255e79763dfff3ef17f6216f1b391 (diff)
Merge remote-tracking branch 'origin/master' into temp-lanpr-review
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/alembic/CMakeLists.txt10
-rw-r--r--source/blender/alembic/intern/abc_curves.cc2
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc6
-rw-r--r--source/blender/alembic/intern/abc_hair.cc2
-rw-r--r--source/blender/alembic/intern/abc_mball.cc3
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc4
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc2
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc2
-rw-r--r--source/blender/avi/CMakeLists.txt1
-rw-r--r--source/blender/blenfont/CMakeLists.txt2
-rw-r--r--source/blender/blenfont/intern/blf.c5
-rw-r--r--source/blender/blenkernel/BKE_animsys.h4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_cloth.h20
-rw-r--r--source/blender/blenkernel/BKE_collection.h2
-rw-r--r--source/blender/blenkernel/BKE_collision.h5
-rw-r--r--source/blender/blenkernel/BKE_displist_tangent.h26
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h28
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h1
-rw-r--r--source/blender/blenkernel/BKE_idprop.h2
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h1
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_object.h1
-rw-r--r--source/blender/blenkernel/BKE_paint.h48
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h7
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt24
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c21
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c22
-rw-r--r--source/blender/blenkernel/intern/armature.c8
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c10
-rw-r--r--source/blender/blenkernel/intern/cloth.c118
-rw-r--r--source/blender/blenkernel/intern/collection.c5
-rw-r--r--source/blender/blenkernel/intern/collision.c703
-rw-r--r--source/blender/blenkernel/intern/constraint.c66
-rw-r--r--source/blender/blenkernel/intern/curve.c137
-rw-r--r--source/blender/blenkernel/intern/deform.c2
-rw-r--r--source/blender/blenkernel/intern/displist_tangent.c279
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c6
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c548
-rw-r--r--source/blender/blenkernel/intern/editmesh.c93
-rw-r--r--source/blender/blenkernel/intern/fcurve.c107
-rw-r--r--source/blender/blenkernel/intern/fluid.c850
-rw-r--r--source/blender/blenkernel/intern/gpencil.c14
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c8
-rw-r--r--source/blender/blenkernel/intern/idprop.c15
-rw-r--r--source/blender/blenkernel/intern/image.c52
-rw-r--r--source/blender/blenkernel/intern/library_query.c36
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c24
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c27
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c2
-rw-r--r--source/blender/blenkernel/intern/multires.c18
-rw-r--r--source/blender/blenkernel/intern/nla.c4
-rw-r--r--source/blender/blenkernel/intern/node.c16
-rw-r--r--source/blender/blenkernel/intern/object.c70
-rw-r--r--source/blender/blenkernel/intern/object_update.c3
-rw-r--r--source/blender/blenkernel/intern/paint.c27
-rw-r--r--source/blender/blenkernel/intern/particle.c49
-rw-r--r--source/blender/blenkernel/intern/particle_system.c68
-rw-r--r--source/blender/blenkernel/intern/pbvh.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c48
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c12
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c4
-rw-r--r--source/blender/blenkernel/intern/sequencer.c108
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c77
-rw-r--r--source/blender/blenkernel/intern/softbody.c6
-rw-r--r--source/blender/blenkernel/intern/sound.c14
-rw-r--r--source/blender/blenkernel/intern/studiolight.c5
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.c8
-rw-r--r--source/blender/blenlib/BLI_boxpack_2d.h13
-rw-r--r--source/blender/blenlib/BLI_expr_pylike_eval.h1
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h8
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_path_util.h6
-rw-r--r--source/blender/blenlib/BLI_rect.h8
-rw-r--r--source/blender/blenlib/BLI_task.h5
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c79
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c108
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c3495
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c18
-rw-r--r--source/blender/blenlib/intern/math_matrix.c21
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c6
-rw-r--r--source/blender/blenlib/intern/path_util.c14
-rw-r--r--source/blender/blenlib/intern/rct.c164
-rw-r--r--source/blender/blenlib/intern/string.c19
-rw-r--r--source/blender/blenloader/intern/readfile.c51
-rw-r--r--source/blender/blenloader/intern/versioning_280.c103
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c2
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c11
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c11
-rw-r--r--source/blender/blenloader/intern/writefile.c148
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c12
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h2
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c7
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c648
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c1015
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.h6
-rw-r--r--source/blender/collada/BCAnimationCurve.h3
-rw-r--r--source/blender/collada/CMakeLists.txt3
-rw-r--r--source/blender/collada/DocumentExporter.cpp4
-rw-r--r--source/blender/collada/DocumentImporter.cpp4
-rw-r--r--source/blender/collada/EffectExporter.cpp4
-rw-r--r--source/blender/collada/Materials.cpp1
-rw-r--r--source/blender/collada/MeshImporter.cpp8
-rw-r--r--source/blender/collada/collada_utils.cpp21
-rw-r--r--source/blender/collada/collada_utils.h5
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp18
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h2
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cpp2
-rw-r--r--source/blender/depsgraph/CMakeLists.txt5
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc13
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc182
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h12
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc29
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc367
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h30
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc57
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc35
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc120
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc1
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug.cc40
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug.h33
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc6
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc2
-rw-r--r--source/blender/depsgraph/intern/debug/deg_time_average.h71
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc79
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h49
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc11
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc15
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.cc28
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc32
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc30
-rw-r--r--source/blender/depsgraph/intern/depsgraph_relation.cc73
-rw-r--r--source/blender/depsgraph/intern/depsgraph_relation.h63
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc58
-rw-r--r--source/blender/depsgraph/intern/depsgraph_update.cc8
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc226
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc165
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc19
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc17
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc144
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h65
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc8
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc30
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc20
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc12
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc40
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_factory.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc12
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_time.cc1
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c21
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c34
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c26
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c8
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/ltc_lib.glsl36
-rw-r--r--source/blender/draw/engines/external/external_engine.c51
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c6
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c52
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c1
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c32
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c23
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c18
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c3
-rw-r--r--source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl111
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl24
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl4
-rw-r--r--source/blender/draw/engines/select/select_engine.c56
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl47
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl21
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c38
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c44
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c27
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h10
-rw-r--r--source/blender/draw/intern/draw_cache.c158
-rw-r--r--source/blender/draw/intern/draw_cache.h13
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h8
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c56
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h19
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c19
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c247
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c192
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c8
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c58
-rw-r--r--source/blender/draw/intern/draw_debug.c4
-rw-r--r--source/blender/draw/intern/draw_hair_private.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c23
-rw-r--r--source/blender/draw/intern/draw_manager_data.c20
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c3
-rw-r--r--source/blender/draw/intern/draw_manager_text.c2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c24
-rw-r--r--source/blender/editors/animation/anim_filter.c12
-rw-r--r--source/blender/editors/animation/anim_markers.c8
-rw-r--r--source/blender/editors/animation/keyframing.c76
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c6
-rw-r--r--source/blender/editors/armature/armature_utils.c15
-rw-r--r--source/blender/editors/curve/editcurve_paint.c10
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt2
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c240
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c70
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c8
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c8
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c48
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c7
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c4
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c80
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c34
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c215
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h6
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c43
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c135
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h6
-rw-r--r--source/blender/editors/include/ED_gpencil.h20
-rw-r--r--source/blender/editors/include/ED_keyframing.h6
-rw-r--r--source/blender/editors/include/ED_mesh.h31
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_transform.h28
-rw-r--r--source/blender/editors/include/ED_util.h8
-rw-r--r--source/blender/editors/include/ED_uvedit.h70
-rw-r--r--source/blender/editors/include/UI_icons.h24
-rw-r--r--source/blender/editors/include/UI_interface.h7
-rw-r--r--source/blender/editors/include/UI_resources.h5
-rw-r--r--source/blender/editors/interface/interface_align.c2
-rw-r--r--source/blender/editors/interface/interface_anim.c75
-rw-r--r--source/blender/editors/interface/interface_handlers.c88
-rw-r--r--source/blender/editors/interface/interface_icons.c91
-rw-r--r--source/blender/editors/interface/interface_icons_event.c196
-rw-r--r--source/blender/editors/interface/interface_layout.c30
-rw-r--r--source/blender/editors/interface/interface_panel.c35
-rw-r--r--source/blender/editors/interface/interface_region_hud.c2
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c4
-rw-r--r--source/blender/editors/interface/interface_region_popover.c4
-rw-r--r--source/blender/editors/interface/interface_region_popup.c32
-rw-r--r--source/blender/editors/interface/interface_region_search.c2
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c43
-rw-r--r--source/blender/editors/interface/interface_templates.c21
-rw-r--r--source/blender/editors/interface/interface_widgets.c10
-rw-r--r--source/blender/editors/interface/resources.c15
-rw-r--r--source/blender/editors/interface/view2d.c5
-rw-r--r--source/blender/editors/io/io_alembic.c4
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/io/io_usd.c45
-rw-r--r--source/blender/editors/mesh/editmesh_add.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_automerge.c28
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c46
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c9
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c18
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_screw.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c4
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c32
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c12
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c4
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c11
-rw-r--r--source/blender/editors/mesh/editmesh_path.c6
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c10
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c17
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c10
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c184
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c7
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c64
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c32
-rw-r--r--source/blender/editors/mesh/meshtools.c21
-rw-r--r--source/blender/editors/object/object_add.c25
-rw-r--r--source/blender/editors/object/object_data_transform.c5
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_modifier.c5
-rw-r--r--source/blender/editors/object/object_random.c2
-rw-r--r--source/blender/editors/object/object_relations.c71
-rw-r--r--source/blender/editors/object/object_remesh.c4
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c2
-rw-r--r--source/blender/editors/physics/particle_object.c5
-rw-r--r--source/blender/editors/physics/physics_fluid.c37
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_opengl.c128
-rw-r--r--source/blender/editors/scene/scene_edit.c2
-rw-r--r--source/blender/editors/screen/area.c58
-rw-r--r--source/blender/editors/screen/area_query.c12
-rw-r--r--source/blender/editors/screen/area_utils.c29
-rw-r--r--source/blender/editors/screen/screen_context.c59
-rw-r--r--source/blender/editors/screen/screen_ops.c73
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c56
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h5
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c30
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c678
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c27
-rw-r--r--source/blender/editors/sound/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_action/action_data.c26
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_action/action_select.c2
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c12
-rw-r--r--source/blender/editors/space_clip/space_clip.c6
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c6
-rw-r--r--source/blender/editors/space_console/console_draw.c107
-rw-r--r--source/blender/editors/space_file/file_ops.c2
-rw-r--r--source/blender/editors/space_file/filelist.c28
-rw-r--r--source/blender/editors/space_file/fsmenu.c170
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_graph/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c76
-rw-r--r--source/blender/editors/space_graph/graph_edit.c15
-rw-r--r--source/blender/editors/space_graph/space_graph.c6
-rw-r--r--source/blender/editors/space_image/image_ops.c61
-rw-r--r--source/blender/editors/space_image/space_image.c24
-rw-r--r--source/blender/editors/space_info/info_draw.c153
-rw-r--r--source/blender/editors/space_info/textview.c229
-rw-r--r--source/blender/editors/space_info/textview.h21
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c212
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c36
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c63
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c50
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c137
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c13
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c10
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c65
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c2
-rw-r--r--source/blender/editors/space_text/text_format_lua.c16
-rw-r--r--source/blender/editors/space_text/text_format_osl.c18
-rw-r--r--source/blender/editors/space_text/text_format_pov.c30
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c14
-rw-r--r--source/blender/editors/space_text/text_format_py.c175
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c106
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c19
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c258
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c17
-rw-r--r--source/blender/editors/transform/transform_convert.c20
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c65
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c4
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c20
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c10
-rw-r--r--source/blender/editors/transform/transform_draw.c114
-rw-r--r--source/blender/editors/transform/transform_generics.c88
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c413
-rw-r--r--source/blender/editors/transform/transform_ops.c2
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap_object.c71
-rw-r--r--source/blender/editors/undo/ed_undo.c34
-rw-r--r--source/blender/editors/util/ed_util.c107
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c207
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c125
-rw-r--r--source/blender/freestyle/CMakeLists.txt3
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.cpp4
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.h5
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp5
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp4
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h4
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_material.h12
-rw-r--r--source/blender/gpu/GPU_texture.h6
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c26
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c83
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h5
-rw-r--r--source/blender/gpu/intern/gpu_draw.c588
-rw-r--r--source/blender/gpu/intern/gpu_platform.c3
-rw-r--r--source/blender/gpu/intern/gpu_texture.c62
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl95
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl37
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl2
-rw-r--r--source/blender/imbuf/CMakeLists.txt13
-rw-r--r--source/blender/imbuf/intern/bmp.c157
-rw-r--r--source/blender/imbuf/intern/oiio/CMakeLists.txt11
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/openexr/CMakeLists.txt3
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp4
-rw-r--r--source/blender/makesdna/DNA_ID.h5
-rw-r--r--source/blender/makesdna/DNA_armature_types.h3
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h5
-rw-r--r--source/blender/makesdna/DNA_brush_types.h15
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h12
-rw-r--r--source/blender/makesdna/DNA_curve_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h1
-rw-r--r--source/blender/makesdna/DNA_image_types.h16
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h534
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h4
-rw-r--r--source/blender/makesdna/DNA_object_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_particle_types.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_screen_types.h12
-rw-r--r--source/blender/makesdna/DNA_texture_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h10
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h6
-rw-r--r--source/blender/makesdna/intern/makesdna.c6
-rw-r--r--source/blender/makesrna/RNA_define.h10
-rw-r--r--source/blender/makesrna/RNA_enum_types.h3
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt7
-rw-r--r--source/blender/makesrna/intern/rna_access.c60
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c8
-rw-r--r--source/blender/makesrna/intern/rna_brush.c16
-rw-r--r--source/blender/makesrna/intern/rna_color.c3
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c50
-rw-r--r--source/blender/makesrna/intern/rna_curve.c31
-rw-r--r--source/blender/makesrna/intern/rna_define.c30
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c411
-rw-r--r--source/blender/makesrna/intern/rna_image.c3
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c14
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c11
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c5
-rw-r--r--source/blender/makesrna/intern/rna_nla.c3
-rw-r--r--source/blender/makesrna/intern/rna_object.c83
-rw-r--r--source/blender/makesrna/intern/rna_particle.c76
-rw-r--r--source/blender/makesrna/intern/rna_pose.c12
-rw-r--r--source/blender/makesrna/intern/rna_scene.c34
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c12
-rw-r--r--source/blender/makesrna/intern/rna_space.c36
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c85
-rw-r--r--source/blender/makesrna/intern/rna_wm.c9
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c48
-rw-r--r--source/blender/makesrna/intern/rna_workspace_api.c4
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c11
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c3
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c3
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c6
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c138
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c65
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c19
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c46
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c1
-rw-r--r--source/blender/physics/CMakeLists.txt6
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp176
-rw-r--r--source/blender/python/BPY_extern.h1
-rw-r--r--source/blender/python/bmesh/CMakeLists.txt3
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c4
-rw-r--r--source/blender/python/generic/CMakeLists.txt2
-rw-r--r--source/blender/python/gpu/CMakeLists.txt2
-rw-r--r--source/blender/python/intern/CMakeLists.txt16
-rw-r--r--source/blender/python/intern/bpy_app.c3
-rw-r--r--source/blender/python/intern/bpy_app_usd.c107
-rw-r--r--source/blender/python/intern/bpy_app_usd.h29
-rw-r--r--source/blender/python/intern/bpy_interface.c13
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt3
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c3
-rw-r--r--source/blender/render/intern/source/imagetexture.c6
-rw-r--r--source/blender/render/intern/source/render_result.c4
-rw-r--r--source/blender/usd/CMakeLists.txt28
-rw-r--r--source/blender/usd/intern/abstract_hierarchy_iterator.cc54
-rw-r--r--source/blender/usd/intern/abstract_hierarchy_iterator.h11
-rw-r--r--source/blender/usd/intern/usd_capi.cc19
-rw-r--r--source/blender/usd/intern/usd_hierarchy_iterator.cc3
-rw-r--r--source/blender/usd/usd.h3
-rw-r--r--source/blender/windowmanager/CMakeLists.txt8
-rw-r--r--source/blender/windowmanager/WM_api.h62
-rw-r--r--source/blender/windowmanager/WM_keymap.h2
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h4
-rw-r--r--source/blender/windowmanager/WM_types.h33
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c3
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c6
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c12
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c16
-rw-r--r--source/blender/windowmanager/intern/wm.c9
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c3
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c13
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c427
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c865
-rw-r--r--source/blender/windowmanager/intern/wm_files.c6
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c28
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c25
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c20
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c118
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c24
-rw-r--r--source/blender/windowmanager/intern/wm_window.c55
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c4
-rw-r--r--source/blender/windowmanager/wm_event_system.h3
-rw-r--r--source/blender/windowmanager/wm_event_types.h12
556 files changed, 15979 insertions, 10941 deletions
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
index 82812fb81cf..4618246013a 100644
--- a/source/blender/alembic/CMakeLists.txt
+++ b/source/blender/alembic/CMakeLists.txt
@@ -75,10 +75,20 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+
+ ${ALEMBIC_LIBRARIES}
+ ${OPENEXR_LIBRARIES}
)
if(WITH_ALEMBIC_HDF5)
add_definitions(-DWITH_ALEMBIC_HDF5)
+ list(APPEND LIB
+ ${HDF5_LIBRARIES}
+ )
endif()
+list(APPEND LIB
+ ${BOOST_LIBRARIES}
+)
+
blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 50aa13bea4f..3b143356c04 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -28,9 +28,9 @@
#include "abc_transform.h"
#include "abc_util.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index cacf0676481..c2201c706bc 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -558,7 +558,11 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x
else if (m_settings.export_particles &&
(psys->part->type == PART_EMITTER || psys->part->type == PART_FLUID_FLIP ||
psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_BUBBLE ||
- psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_TRACER)) {
+ psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_TRACER ||
+ psys->part->type == PART_FLUID_SPRAYFOAM ||
+ psys->part->type == PART_FLUID_SPRAYBUBBLE ||
+ psys->part->type == PART_FLUID_FOAMBUBBLE ||
+ psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE)) {
m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
}
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index 98387be2e61..7eaecd271f4 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -25,9 +25,9 @@
#include "abc_transform.h"
#include "abc_util.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc
index 732ceffe467..db4b9d82ebf 100644
--- a/source/blender/alembic/intern/abc_mball.cc
+++ b/source/blender/alembic/intern/abc_mball.cc
@@ -22,6 +22,8 @@
#include "abc_mesh.h"
#include "abc_transform.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -35,7 +37,6 @@ extern "C" {
#include "BKE_object.h"
#include "DEG_depsgraph.h"
-#include "MEM_guardedalloc.h"
}
AbcMBallWriter::AbcMBallWriter(Main *bmain,
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index edcb6263da3..3eee390d7d3 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -25,6 +25,8 @@
#include "abc_transform.h"
#include "abc_util.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -46,8 +48,6 @@ extern "C" {
#include "BKE_modifier.h"
#include "BKE_object.h"
-#include "MEM_guardedalloc.h"
-
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index 739276dffa6..c11ca7d57b9 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -23,9 +23,9 @@
#include "abc_transform.h"
#include "abc_util.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index 5efa8c8a446..5519cbef53c 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -32,9 +32,9 @@
#include "abc_transform.h"
#include "abc_util.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_curve_types.h"
#include "DNA_modifier_types.h"
diff --git a/source/blender/avi/CMakeLists.txt b/source/blender/avi/CMakeLists.txt
index 721905ec9d4..eafb299944d 100644
--- a/source/blender/avi/CMakeLists.txt
+++ b/source/blender/avi/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
)
set(LIB
+ ${JPEG_LIBRARIES}
)
blender_add_lib(bf_avi "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index ba8697a44b6..fa02d6d21c9 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -54,6 +54,8 @@ set(SRC
set(LIB
bf_gpu
bf_intern_guardedalloc
+
+ ${FREETYPE_LIBRARY}
)
if(WIN32)
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 10bb1bd3c9c..2b592c9e550 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -935,10 +935,7 @@ void blf_draw_buffer__start(FontBLF *font)
{
FontBufInfoBLF *buf_info = &font->buf_info;
- buf_info->col_char[0] = buf_info->col_init[0] * 255;
- buf_info->col_char[1] = buf_info->col_init[1] * 255;
- buf_info->col_char[2] = buf_info->col_init[2] * 255;
- buf_info->col_char[3] = buf_info->col_init[3] * 255;
+ rgba_float_to_uchar(buf_info->col_char, buf_info->col_init);
if (buf_info->display) {
copy_v4_v4(buf_info->col_float, buf_info->col_init);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 963e3158d46..9da17d777cd 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -249,6 +249,10 @@ typedef enum eAnimData_Recalc {
ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM),
} eAnimData_Recalc;
+bool BKE_animsys_store_rna_setting(struct PointerRNA *ptr,
+ const char *rna_path,
+ const int array_index,
+ struct PathResolvedRNA *r_result);
bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value);
bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 9855c2202cc..2acef7847bc 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -26,8 +26,8 @@
*
* \note Use #STRINGIFY() rather than defining with quotes.
*/
-#define BLENDER_VERSION 282
-#define BLENDER_SUBVERSION 6
+#define BLENDER_VERSION 283
+#define BLENDER_SUBVERSION 2
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 17de53be42a..2862dda8ead 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -74,11 +74,11 @@ typedef struct ClothSolverResult {
* own connectivity of the mesh based on the actual edges in the mesh.
*/
typedef struct Cloth {
- struct ClothVertex *verts; /* The vertices that represent this cloth. */
- struct LinkNode *springs; /* The springs connecting the mesh. */
- unsigned int numsprings; /* The count of springs. */
- unsigned int mvert_num; /* The number of verts == m * n. */
- unsigned int tri_num;
+ struct ClothVertex *verts; /* The vertices that represent this cloth. */
+ struct LinkNode *springs; /* The springs connecting the mesh. */
+ unsigned int numsprings; /* The count of springs. */
+ unsigned int mvert_num; /* The number of verts == m * n. */
+ unsigned int primitive_num; /* Number of triangles for cloth and edges for hair. */
unsigned char old_solver_type; /* unused, only 1 solver here */
unsigned char pad2;
short pad3;
@@ -89,6 +89,7 @@ typedef struct Cloth {
struct EdgeSet *edgeset; /* used for selfcollisions */
int last_frame;
float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
+ struct MEdge *edges; /* Used for hair collisions. */
} Cloth;
/**
@@ -265,15 +266,6 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph,
float step,
float dt);
-void cloth_find_point_contacts(struct Depsgraph *depsgraph,
- struct Object *ob,
- struct ClothModifierData *clmd,
- float step,
- float dt,
- ColliderContacts **r_collider_contacts,
- int *r_totcolliders);
-void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
-
////////////////////////////////////////////////
/////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 0d33d86ec16..47ed42cade9 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -142,6 +142,8 @@ bool BKE_collection_child_add(struct Main *bmain,
struct Collection *parent,
struct Collection *child);
+bool BKE_collection_child_add_no_sync(struct Collection *parent, struct Collection *child);
+
bool BKE_collection_child_remove(struct Main *bmain,
struct Collection *parent,
struct Collection *child);
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 5d7a5094eb5..5bf697e5df9 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -125,7 +125,10 @@ void bvhtree_update_from_mvert(BVHTree *bvhtree,
// move Collision modifier object inter-frame with step = [0,1]
// defined in collisions.c
-void collision_move_object(struct CollisionModifierData *collmd, float step, float prevstep);
+void collision_move_object(struct CollisionModifierData *collmd,
+ const float step,
+ const float prevstep,
+ const bool moving_bvh);
void collision_get_collider_velocity(float vel_old[3],
float vel_new[3],
diff --git a/source/blender/blenkernel/BKE_displist_tangent.h b/source/blender/blenkernel/BKE_displist_tangent.h
new file mode 100644
index 00000000000..3af7c513f67
--- /dev/null
+++ b/source/blender/blenkernel/BKE_displist_tangent.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.
+ */
+
+#ifndef __BKE_DISPLIST_TANGENT_H__
+#define __BKE_DISPLIST_TANGENT_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+void BKE_displist_tangent_calc(const DispList *dl, float (*fnormals)[3], float (**r_tangent)[4]);
+
+#endif /* __BKE_DISPLIST_TANGENT_H__ */
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 1b9e318146e..80cb0f1482b 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -35,6 +35,7 @@ struct Depsgraph;
struct EditMeshData;
struct Mesh;
struct MeshStatVis;
+struct Object;
struct Scene;
/**
@@ -65,18 +66,11 @@ typedef struct BMEditMesh {
/*derivedmesh stuff*/
CustomData_MeshMasks lastDataMask;
- unsigned char (*derivedVertColor)[4];
- int derivedVertColorLen;
- unsigned char (*derivedFaceColor)[4];
- int derivedFaceColorLen;
/*selection mode*/
short selectmode;
short mat_nr;
- /* Object this editmesh came from (if it came from one) */
- struct Object *ob;
-
/*temp variables for x-mirror editing*/
int mirror_cdlayer; /* -1 is invalid */
@@ -96,20 +90,14 @@ BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
void BKE_editmesh_free_derivedmesh(BMEditMesh *em);
void BKE_editmesh_free(BMEditMesh *em);
-void BKE_editmesh_color_free(BMEditMesh *em);
-void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
+float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
+ struct BMEditMesh *em,
+ struct Scene *scene,
+ struct Object *ob,
+ int *r_vert_len))[3];
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3];
-void BKE_editmesh_lnorspace_update(BMEditMesh *em);
-void BKE_editmesh_ensure_autosmooth(BMEditMesh *em);
+void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
+void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
-/* editderivedmesh.c */
-/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
-void BKE_editmesh_statvis_calc(BMEditMesh *em,
- struct EditMeshData *emd,
- const struct MeshStatVis *statvis);
-
-float (*BKE_editmesh_vert_coords_alloc(
- struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_vert_len))[3];
-
#endif /* __BKE_EDITMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 426e0ed4b0e..405b052f477 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -107,6 +107,7 @@ bool driver_get_variable_property(struct ChannelDriver *driver,
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);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 94c2a94d420..2b02895043f 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -83,6 +83,8 @@ void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
typedef void (*IDPWalkFunc)(void *userData, IDProperty *idp);
+void IDP_AssignID(IDProperty *prop, ID *id, const int flag);
+
/*-------- Group Functions -------*/
/** Sync values from one group to another, only where they match */
diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h
index bd442c97000..153ad9bb915 100644
--- a/source/blender/blenkernel/BKE_lightprobe.h
+++ b/source/blender/blenkernel/BKE_lightprobe.h
@@ -29,6 +29,7 @@ struct LightProbe;
struct Main;
void BKE_lightprobe_init(struct LightProbe *probe);
+void BKE_lightprobe_type_set(struct LightProbe *probe, const short lightprobe_type);
void *BKE_lightprobe_add(struct Main *bmain, const char *name);
void BKE_lightprobe_copy_data(struct Main *bmain,
struct LightProbe *probe_dst,
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 90afec54561..570541eb990 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -177,7 +177,6 @@ int BKE_mesh_nurbs_displist_to_mdata(struct Object *ob,
void BKE_mesh_from_nurbs_displist(struct Main *bmain,
struct Object *ob,
struct ListBase *dispbase,
- const bool use_orco_uv,
const char *obdata_name,
bool temporary);
void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 11f151af44d..b599e1e1b2c 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -545,7 +545,8 @@ void nodeRemoveNode(struct Main *bmain,
struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree,
const struct bNode *node_src,
- const int flag);
+ const int flag,
+ const bool unique_name);
/* Same as BKE_node_copy_ex() but stores pointers to a new node and its sockets in the source
* node.
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index ec6ec027810..54cd172655e 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -66,7 +66,6 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_free(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
-void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index fdd3bd7cd86..db35fbde2c8 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -85,19 +85,33 @@ typedef enum ePaintMode {
#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PAINT_MODE_SCULPT_UV)
/* overlay invalidation */
-typedef enum eOverlayControlFlags {
+typedef enum ePaintOverlayControlFlags {
PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY = 1,
PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY = (1 << 2),
PAINT_OVERLAY_INVALID_CURVE = (1 << 3),
PAINT_OVERLAY_OVERRIDE_CURSOR = (1 << 4),
PAINT_OVERLAY_OVERRIDE_PRIMARY = (1 << 5),
PAINT_OVERLAY_OVERRIDE_SECONDARY = (1 << 6),
-} eOverlayControlFlags;
+} ePaintOverlayControlFlags;
#define PAINT_OVERRIDE_MASK \
(PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \
PAINT_OVERLAY_OVERRIDE_CURSOR)
+/* Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
+ * flip or mirror transform values depending on where the vertex is and where the transform
+ * operation started to support XYZ symmetry on those operations in a predictable way. */
+
+#define PAINT_SYMM_AREA_DEFAULT 0
+
+typedef enum ePaintSymmetryAreas {
+ PAINT_SYMM_AREA_X = (1 << 0),
+ PAINT_SYMM_AREA_Y = (1 << 1),
+ PAINT_SYMM_AREA_Z = (1 << 2),
+} ePaintSymmetryAreas;
+
+#define PAINT_SYMM_AREAS 8
+
void BKE_paint_invalidate_overlay_tex(struct Scene *scene,
struct ViewLayer *view_layer,
const struct Tex *tex);
@@ -105,8 +119,8 @@ void BKE_paint_invalidate_cursor_overlay(struct Scene *scene,
struct ViewLayer *view_layer,
struct CurveMapping *curve);
void BKE_paint_invalidate_overlay_all(void);
-eOverlayControlFlags BKE_paint_get_overlay_flags(void);
-void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag);
+ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void);
+void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum eOverlayFlags flag);
/* palettes */
@@ -211,6 +225,29 @@ struct SculptVertexPaintGeomMap {
struct MeshElemMap *vert_to_poly;
};
+/* Pose Brush IK Chain */
+typedef struct SculptPoseIKChainSegment {
+ float orig[3];
+ float head[3];
+
+ float initial_orig[3];
+ float initial_head[3];
+ float len;
+ float rot[4];
+ float *weights;
+
+ /* Store a 4x4 transform matrix for each of the possible combinations of enabled XYZ symmetry
+ * axis. */
+ float trans_mat[PAINT_SYMM_AREAS][4][4];
+ float pivot_mat[PAINT_SYMM_AREAS][4][4];
+ float pivot_mat_inv[PAINT_SYMM_AREAS][4][4];
+} SculptPoseIKChainSegment;
+
+typedef struct SculptPoseIKChain {
+ SculptPoseIKChainSegment *segments;
+ int tot_segments;
+} SculptPoseIKChain;
+
/* Session data (mode-specific) */
typedef struct SculptSession {
@@ -273,7 +310,10 @@ typedef struct SculptSession {
/* Dynamic mesh preview */
int *preview_vert_index_list;
int preview_vert_index_count;
+
+ /* Pose Brush Preview */
float pose_origin[3];
+ SculptPoseIKChain *pose_ik_chain_preview;
/* Transform operator */
float pivot_pos[3];
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 006915d6c45..d73e40291a0 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -173,6 +173,8 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
bool BKE_scene_uses_blender_workbench(const struct Scene *scene);
bool BKE_scene_uses_cycles(const struct Scene *scene);
+void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src);
+
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
bool BKE_scene_check_rigidbody_active(const struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 770318883c0..bc312c7bb2b 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -208,6 +208,7 @@ struct SeqEffectHandle {
*
* sequencer render functions
* ********************************************************************** */
+double BKE_sequencer_rendersize_to_scale_factor(int size);
struct ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown);
struct ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context,
@@ -412,7 +413,10 @@ bool BKE_sequence_base_shuffle_ex(struct ListBase *seqbasep,
bool BKE_sequence_base_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
-bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene);
+bool BKE_sequence_base_shuffle_time(ListBase *seqbasep,
+ struct Scene *evil_scene,
+ ListBase *markers,
+ const bool use_sync_markers);
bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase);
void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render);
struct Sequence *BKE_sequence_dupli_recursive(const struct Scene *scene_src,
@@ -503,6 +507,7 @@ enum {
SEQ_SIDE_LEFT,
SEQ_SIDE_RIGHT,
SEQ_SIDE_BOTH,
+ SEQ_SIDE_NO_CHANGE,
};
int BKE_sequencer_find_next_prev_edit(struct Scene *scene,
int cfra,
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index cd48e4d7f3b..70aa028a2c7 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -58,7 +58,7 @@ typedef enum {
struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
- struct Scene *scene,
+ const struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index cd03f80d9ec..2885495c3b0 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -105,8 +105,8 @@ set(SRC
intern/data_transfer.c
intern/deform.c
intern/displist.c
+ intern/displist_tangent.c
intern/dynamicpaint.c
- intern/editderivedmesh.c
intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
@@ -272,6 +272,7 @@ set(SRC
BKE_data_transfer.h
BKE_deform.h
BKE_displist.h
+ BKE_displist_tangent.h
BKE_dynamicpaint.h
BKE_editlattice.h
BKE_editmesh.h
@@ -424,6 +425,10 @@ if(WITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${AUDASPACE_C_LIBRARIES}
+ ${AUDASPACE_PY_LIBRARIES}
+ )
endif()
if(WITH_BULLET)
@@ -436,6 +441,8 @@ if(WITH_BULLET)
list(APPEND LIB
bf_intern_rigidbody
extern_bullet
+
+ ${BULLET_LIBRARIES}
)
add_definitions(-DWITH_BULLET)
endif()
@@ -490,6 +497,9 @@ if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${FFMPEG_LIBRARIES}
+ )
add_definitions(-DWITH_FFMPEG)
remove_strict_c_flags_file(
@@ -543,6 +553,9 @@ if(WITH_LZO)
list(APPEND INC_SYS
${LZO_INCLUDE_DIR}
)
+ list(APPEND LIB
+ ${LZO_LIBRARIES}
+ )
add_definitions(-DWITH_SYSTEM_LZO)
else()
list(APPEND INC_SYS
@@ -573,6 +586,9 @@ if(WITH_FFTW3)
list(APPEND INC_SYS
${FFTW3_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${FFTW3_LIBRARIES}
+ )
add_definitions(-DFFTW3=1)
endif()
@@ -599,6 +615,9 @@ if(WITH_OPENSUBDIV)
list(APPEND INC_SYS
${OPENSUBDIV_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${OPENSUBDIV_LIBRARIES}
+ )
add_definitions(-DWITH_OPENSUBDIV)
endif()
@@ -634,6 +653,9 @@ if(WITH_TBB)
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
endif()
# # Warnings as errors, this is too strict!
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 8be7a947a67..f9e7627a8dd 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -789,14 +789,6 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc
}
}
-static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
-{
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- Mesh *me = ob->data;
- BKE_mesh_runtime_ensure_edit_data(me);
- BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
-}
-
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo,
@@ -1494,7 +1486,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Modifier evaluation modes. */
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */
/* Modifier evaluation contexts for different types of modifiers. */
const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE};
@@ -1703,22 +1694,12 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else if (!deformed_verts && mesh_cage) {
/* cage should already have up to date normals */
mesh_final = mesh_cage;
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_statvis) {
- editmesh_update_statvis_color(scene, ob);
- }
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_statvis) {
- editmesh_update_statvis_color(scene, ob);
- }
}
if (deformed_verts) {
@@ -1858,7 +1839,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
BMEditMesh *em,
CustomData_MeshMasks *dataMask)
{
- BLI_assert(em->ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ BLI_assert(obedit->id.tag & LIB_TAG_COPIED_ON_WRITE);
BKE_object_free_derived_caches(obedit);
if (DEG_is_active(depsgraph)) {
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 32420e2e894..be6622e5d42 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1665,11 +1665,11 @@ void BKE_keyingsets_free(ListBase *list)
/* ***************************************** */
/* Evaluation Data-Setting Backend */
-static bool animsys_store_rna_setting(PointerRNA *ptr,
- /* typically 'fcu->rna_path', 'fcu->array_index' */
- const char *rna_path,
- const int array_index,
- PathResolvedRNA *r_result)
+bool BKE_animsys_store_rna_setting(PointerRNA *ptr,
+ /* typically 'fcu->rna_path', 'fcu->array_index' */
+ const char *rna_path,
+ const int array_index,
+ PathResolvedRNA *r_result)
{
bool success = false;
const char *path = rna_path;
@@ -1880,7 +1880,7 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr,
}
PathResolvedRNA orig_anim_rna;
/* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */
- if (animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) {
+ if (BKE_animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) {
BKE_animsys_write_rna_setting(&orig_anim_rna, value);
}
}
@@ -1910,7 +1910,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
continue;
}
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
BKE_animsys_write_rna_setting(&anim_rna, curval);
if (flush_to_original) {
@@ -1944,7 +1944,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* NOTE: for 'layering' option later on, we should check if we should remove old value
* before adding new to only be done when drivers only changed. */
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
ok = BKE_animsys_write_rna_setting(&anim_rna, curval);
}
@@ -2023,7 +2023,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
BKE_animsys_write_rna_setting(&anim_rna, curval);
}
@@ -3803,7 +3803,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
/* for each override, simply execute... */
for (aor = adt->overrides.first; aor; aor = aor->next) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
BKE_animsys_write_rna_setting(&anim_rna, aor->value);
}
}
@@ -4125,7 +4125,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu
// printf("\told val = %f\n", fcu->curval);
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
/* Evaluate driver, and write results to COW-domain destination */
const float ctime = DEG_get_ctime(depsgraph);
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index c588ee80c78..e4da10797ff 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2293,13 +2293,17 @@ void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
* If vec is the Y vector from purely rotational mat, result should be exact. */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
{
- float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
+ float vecmat[3][3], vecmatinv[3][3], rollmat[3][3], q[4];
+ /* Compute the orientation relative to the vector with zero roll. */
vec_roll_to_mat3(vec, 0.0f, vecmat);
invert_m3_m3(vecmatinv, vecmat);
mul_m3_m3m3(rollmat, vecmatinv, mat);
- *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
+ /* Extract the twist angle as the roll value. */
+ mat3_to_quat(q, rollmat);
+
+ *r_roll = quat_split_swing_and_twist(q, 1, NULL, NULL);
}
/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 7c12747283c..cd950e05415 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -73,7 +73,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK) {
- success = BKE_blendfile_read(C, mfu->filename, NULL, 0);
+ success = BKE_blendfile_read(C, mfu->filename, &(const struct BlendFileReadParams){0}, NULL);
}
else {
success = BKE_blendfile_read_from_memfile(
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index b5f2ca0f117..721eb9a2a37 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -893,9 +893,11 @@ void BKE_brush_debug_print_state(Brush *br)
BR_TEST(add_col[0], f);
BR_TEST(add_col[1], f);
BR_TEST(add_col[2], f);
+ BR_TEST(add_col[3], f);
BR_TEST(sub_col[0], f);
BR_TEST(sub_col[1], f);
BR_TEST(sub_col[2], f);
+ BR_TEST(sub_col[3], f);
printf("\n");
@@ -926,7 +928,7 @@ void BKE_brush_sculpt_reset(Brush *br)
br->curve_preset = BRUSH_CURVE_POW4;
br->spacing = 5;
break;
- case SCULPT_TOOL_TOPOLOGY:
+ case SCULPT_TOOL_SLIDE_RELAX:
br->spacing = 10;
br->alpha = 1.0f;
break;
@@ -990,6 +992,7 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_POSE:
br->pose_smooth_iterations = 4;
+ br->pose_ik_segments = 1;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
@@ -1006,6 +1009,11 @@ void BKE_brush_sculpt_reset(Brush *br)
}
/* Cursor colors */
+
+ /* Default Alpha */
+ br->add_col[3] = 0.90f;
+ br->sub_col[3] = 0.90f;
+
switch (br->sculpt_tool) {
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_DRAW_SHARP:
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index c26800aefba..7332c3e0d43 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -190,22 +190,36 @@ static BVHTree *bvhtree_build_from_cloth(ClothModifierData *clmd, float epsilon)
vt = cloth->tri;
/* in the moment, return zero if no faces there */
- if (!cloth->tri_num) {
+ if (!cloth->primitive_num) {
return NULL;
}
/* create quadtree with k=26 */
- bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26);
+ bvhtree = BLI_bvhtree_new(cloth->primitive_num, epsilon, 4, 26);
/* fill tree */
- for (i = 0; i < cloth->tri_num; i++, vt++) {
- float co[3][3];
+ if (clmd->hairdata == NULL) {
+ for (i = 0; i < cloth->primitive_num; i++, vt++) {
+ float co[3][3];
- copy_v3_v3(co[0], verts[vt->tri[0]].xold);
- copy_v3_v3(co[1], verts[vt->tri[1]].xold);
- copy_v3_v3(co[2], verts[vt->tri[2]].xold);
+ copy_v3_v3(co[0], verts[vt->tri[0]].xold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].xold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].xold);
- BLI_bvhtree_insert(bvhtree, i, co[0], 3);
+ BLI_bvhtree_insert(bvhtree, i, co[0], 3);
+ }
+ }
+ else {
+ MEdge *edges = cloth->edges;
+
+ for (i = 0; i < cloth->primitive_num; i++) {
+ float co[2][3];
+
+ copy_v3_v3(co[0], verts[edges[i].v1].xold);
+ copy_v3_v3(co[1], verts[edges[i].v2].xold);
+
+ BLI_bvhtree_insert(bvhtree, i, co[0], 2);
+ }
}
/* balance tree */
@@ -222,6 +236,8 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
ClothVertex *verts = cloth->verts;
const MVertTri *vt;
+ BLI_assert(!(clmd->hairdata != NULL && self));
+
if (self) {
bvhtree = cloth->bvhselftree;
}
@@ -236,39 +252,59 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
vt = cloth->tri;
/* update vertex position in bvh tree */
- if (verts && vt) {
- for (i = 0; i < cloth->tri_num; i++, vt++) {
- float co[3][3], co_moving[3][3];
- bool ret;
-
- /* copy new locations into array */
- if (moving) {
- copy_v3_v3(co[0], verts[vt->tri[0]].txold);
- copy_v3_v3(co[1], verts[vt->tri[1]].txold);
- copy_v3_v3(co[2], verts[vt->tri[2]].txold);
-
- /* update moving positions */
- copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
- copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
- copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
-
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
- }
- else {
- copy_v3_v3(co[0], verts[vt->tri[0]].tx);
- copy_v3_v3(co[1], verts[vt->tri[1]].tx);
- copy_v3_v3(co[2], verts[vt->tri[2]].tx);
+ if (clmd->hairdata == NULL) {
+ if (verts && vt) {
+ for (i = 0; i < cloth->primitive_num; i++, vt++) {
+ float co[3][3], co_moving[3][3];
+ bool ret;
+
+ /* copy new locations into array */
+ if (moving) {
+ copy_v3_v3(co[0], verts[vt->tri[0]].txold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].txold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].txold);
+
+ /* update moving positions */
+ copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
+
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
+ }
+ else {
+ copy_v3_v3(co[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co[2], verts[vt->tri[2]].tx);
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
- }
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
+ }
- /* check if tree is already full */
- if (ret == false) {
- break;
+ /* check if tree is already full */
+ if (ret == false) {
+ break;
+ }
}
+
+ BLI_bvhtree_update_tree(bvhtree);
}
+ }
+ else {
+ if (verts) {
+ MEdge *edges = cloth->edges;
+
+ for (i = 0; i < cloth->primitive_num; i++) {
+ float co[2][3];
- BLI_bvhtree_update_tree(bvhtree);
+ copy_v3_v3(co[0], verts[edges[i].v1].tx);
+ copy_v3_v3(co[1], verts[edges[i].v2].tx);
+
+ if (!BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 2)) {
+ break;
+ }
+ }
+
+ BLI_bvhtree_update_tree(bvhtree);
+ }
}
}
@@ -900,7 +936,13 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
}
/* save face information */
- clmd->clothObject->tri_num = looptri_num;
+ if (clmd->hairdata == NULL) {
+ clmd->clothObject->primitive_num = looptri_num;
+ }
+ else {
+ clmd->clothObject->primitive_num = mesh->totedge;
+ }
+
clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
if (clmd->clothObject->tri == NULL) {
cloth_free_modifier(clmd);
@@ -910,6 +952,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
}
BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
+ clmd->clothObject->edges = mesh->medge;
+
/* Free the springs since they can't be correct if the vertices
* changed.
*/
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index ed306dfa4df..0014fd3e7c0 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -1065,6 +1065,11 @@ bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child
return true;
}
+bool BKE_collection_child_add_no_sync(Collection *parent, Collection *child)
+{
+ return collection_child_add(parent, child, 0, true);
+}
+
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
{
if (!collection_child_remove(parent, child)) {
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 91d66e16dde..5db42618a9e 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLI_threads.h"
@@ -77,9 +78,11 @@ typedef struct SelfColDetectData {
***********************************/
/* step is limited from 0 (frame start position) to 1 (frame end position) */
-void collision_move_object(CollisionModifierData *collmd, float step, float prevstep)
+void collision_move_object(CollisionModifierData *collmd,
+ const float step,
+ const float prevstep,
+ const bool moving_bvh)
{
- float oldx[3];
unsigned int i = 0;
/* the collider doesn't move this frame */
@@ -92,13 +95,17 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
}
for (i = 0; i < collmd->mvert_num; i++) {
- interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep);
- interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
- sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx);
+ interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, prevstep);
+ interp_v3_v3v3(collmd->current_xnew[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
+ sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
}
- bvhtree_update_from_mvert(
- collmd->bvhtree, collmd->current_x, NULL, collmd->tri, collmd->tri_num, false);
+ bvhtree_update_from_mvert(collmd->bvhtree,
+ collmd->current_xnew,
+ collmd->current_x,
+ collmd->tri,
+ collmd->tri_num,
+ moving_bvh);
}
BVHTree *bvhtree_build_from_mvert(const MVert *mvert,
@@ -187,17 +194,17 @@ BLI_INLINE int next_ind(int i)
return (++i < 3) ? i : 0;
}
-static float compute_collision_point(float a1[3],
- const float a2[3],
- const float a3[3],
- const float b1[3],
- const float b2[3],
- const float b3[3],
- bool culling,
- bool use_normal,
- float r_a[3],
- float r_b[3],
- float r_vec[3])
+static float compute_collision_point_tri_tri(const float a1[3],
+ const float a2[3],
+ const float a3[3],
+ const float b1[3],
+ const float b2[3],
+ const float b3[3],
+ bool culling,
+ bool use_normal,
+ float r_a[3],
+ float r_b[3],
+ float r_vec[3])
{
float a[3][3];
float b[3][3];
@@ -417,6 +424,179 @@ static float compute_collision_point(float a1[3],
return dist;
}
+static float compute_collision_point_edge_tri(const float a1[3],
+ const float a2[3],
+ const float b1[3],
+ const float b2[3],
+ const float b3[3],
+ bool culling,
+ bool use_normal,
+ float r_a[3],
+ float r_b[3],
+ float r_vec[3])
+{
+ float a[2][3];
+ float b[3][3];
+ float dist = FLT_MAX;
+ float tmp_co1[3], tmp_co2[3];
+ float isect_a[3];
+ bool isect = false;
+ float tmp, tmp_vec[3];
+ float normal[3], cent[3];
+ bool backside = false;
+
+ copy_v3_v3(a[0], a1);
+ copy_v3_v3(a[1], a2);
+
+ copy_v3_v3(b[0], b1);
+ copy_v3_v3(b[1], b2);
+ copy_v3_v3(b[2], b3);
+
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+
+ /* Find intersection. */
+ if (isect_line_segment_tri_v3(a[0], a[1], b[0], b[1], b[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_a, a[0], a[1], tmp);
+ isect = true;
+ }
+
+ /* Determine collision side. */
+ if (culling) {
+ if (isect) {
+ backside = true;
+ }
+ else {
+ mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
+
+ for (int i = 0; i < 2; i++) {
+ sub_v3_v3v3(tmp_vec, a[i], cent);
+ if (dot_v3v3(tmp_vec, normal) < 0.0f) {
+ backside = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (isect) {
+ /* Edge intersection. */
+ copy_v3_v3(r_a, isect_a);
+ copy_v3_v3(r_b, isect_a);
+
+ copy_v3_v3(r_vec, normal);
+
+ return 0.0f;
+ }
+
+ if (backside) {
+ float maxdist = 0.0f;
+ bool found = false;
+
+ /* Point projections. */
+ for (int i = 0; i < 2; i++) {
+ if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ madd_v3_v3v3fl(r_b, a[i], normal, tmp);
+ found = true;
+ }
+ }
+ }
+
+ /* Edge projections. */
+ for (int i = 0; i < 3; i++) {
+ float dir[3];
+
+ sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
+ cross_v3_v3v3(dir, tmp_vec, normal);
+
+ if (isect_line_plane_v3(tmp_co1, a[0], a[1], b[i], dir) &&
+ point_in_slice_seg(tmp_co1, a[0], a[1]) &&
+ point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) {
+ closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
+ sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
+ tmp = len_v3(tmp_vec);
+
+ if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ found = true;
+ }
+ }
+ }
+
+ /* If no point is found, will fallback onto regular proximity test below. */
+ if (found) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+
+ if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+
+ return 0.0f;
+ }
+ }
+
+ /* Closest point. */
+ for (int i = 0; i < 2; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
+ tmp = len_squared_v3v3(tmp_co1, a[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ copy_v3_v3(r_b, tmp_co1);
+ }
+ }
+
+ /* Closest edge. */
+ if (!isect) {
+ for (int j = 0; j < 3; j++) {
+ isect_seg_seg_v3(a[0], a[1], b[j], b[next_ind(j)], tmp_co1, tmp_co2);
+ tmp = len_squared_v3v3(tmp_co1, tmp_co2);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ }
+ }
+ }
+
+ if (isect) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ dist = 0.0f;
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_a, r_b);
+ dist = sqrtf(dist);
+ }
+
+ if (culling && use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+ else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
+ return FLT_MAX;
+ }
+
+ return dist;
+}
+
// w3 is not perfect
static void collision_compute_barycentric(
const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
@@ -488,6 +668,7 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ const bool is_hair = (clmd->hairdata != NULL);
cloth1 = clmd->clothObject;
@@ -503,32 +684,41 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
continue;
}
- /* Compute barycentric coordinates for both collision points. */
- collision_compute_barycentric(collpair->pa,
- cloth1->verts[collpair->ap1].tx,
- cloth1->verts[collpair->ap2].tx,
- cloth1->verts[collpair->ap3].tx,
- &w1,
- &w2,
- &w3);
+ /* Compute barycentric coordinates and relative "velocity" for both collision points. */
+ if (is_hair) {
+ w2 = line_point_factor_v3(
+ collpair->pa, cloth1->verts[collpair->ap1].tx, cloth1->verts[collpair->ap2].tx);
+
+ w1 = 1.0f - w2;
+
+ interp_v3_v3v3(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w2);
+ }
+ else {
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1,
+ &w2,
+ &w3);
+
+ collision_interpolateOnTriangle(v1,
+ cloth1->verts[collpair->ap1].tv,
+ cloth1->verts[collpair->ap2].tv,
+ cloth1->verts[collpair->ap3].tv,
+ w1,
+ w2,
+ w3);
+ }
collision_compute_barycentric(collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
+ collmd->current_xnew[collpair->bp1].co,
+ collmd->current_xnew[collpair->bp2].co,
+ collmd->current_xnew[collpair->bp3].co,
&u1,
&u2,
&u3);
- /* Calculate relative "velocity". */
- collision_interpolateOnTriangle(v1,
- cloth1->verts[collpair->ap1].tv,
- cloth1->verts[collpair->ap2].tv,
- cloth1->verts[collpair->ap3].tv,
- w1,
- w2,
- w3);
-
collision_interpolateOnTriangle(v2,
collmd->current_v[collpair->bp1].co,
collmd->current_v[collpair->bp2].co,
@@ -570,7 +760,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i1, vrel_t_pre, w1 * impulse);
VECADDMUL(i2, vrel_t_pre, w2 * impulse);
- VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+
+ if (!is_hair) {
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+ }
}
/* Apply velocity stopping impulse. */
@@ -582,8 +775,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i2, collpair->normal, w2 * impulse);
cloth1->verts[collpair->ap2].impulse_count++;
- VECADDMUL(i3, collpair->normal, w3 * impulse);
- cloth1->verts[collpair->ap3].impulse_count++;
+ if (!is_hair) {
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ cloth1->verts[collpair->ap3].impulse_count++;
+ }
time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
@@ -603,7 +798,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i1, collpair->normal, impulse);
VECADDMUL(i2, collpair->normal, impulse);
- VECADDMUL(i3, collpair->normal, impulse);
+
+ if (!is_hair) {
+ VECADDMUL(i3, collpair->normal, impulse);
+ }
}
result = 1;
@@ -621,11 +819,17 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
VECADDMUL(i1, collpair->normal, w1 * impulse);
VECADDMUL(i2, collpair->normal, w2 * impulse);
- VECADDMUL(i3, collpair->normal, w3 * impulse);
+
+ if (!is_hair) {
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ }
cloth1->verts[collpair->ap1].impulse_count++;
cloth1->verts[collpair->ap2].impulse_count++;
- cloth1->verts[collpair->ap3].impulse_count++;
+
+ if (!is_hair) {
+ cloth1->verts[collpair->ap3].impulse_count++;
+ }
result = 1;
}
@@ -650,9 +854,11 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
cloth1->verts[collpair->ap2].impulse[j] = i2[j];
}
- if (cloth1->verts[collpair->ap3].impulse_count > 0 &&
- ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) {
- cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ if (!is_hair) {
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) {
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ }
}
}
}
@@ -869,17 +1075,17 @@ static void cloth_collision(void *__restrict userdata,
tri_b = &collmd->tri[data->overlap[index].indexB];
/* Compute distance and normal. */
- distance = compute_collision_point(verts1[tri_a->tri[0]].tx,
- verts1[tri_a->tri[1]].tx,
- verts1[tri_a->tri[2]].tx,
- collmd->current_x[tri_b->tri[0]].co,
- collmd->current_x[tri_b->tri[1]].co,
- collmd->current_x[tri_b->tri[2]].co,
- data->culling,
- data->use_normal,
- pa,
- pb,
- vect);
+ distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx,
+ verts1[tri_a->tri[1]].tx,
+ verts1[tri_a->tri[2]].tx,
+ collmd->current_xnew[tri_b->tri[0]].co,
+ collmd->current_xnew[tri_b->tri[1]].co,
+ collmd->current_xnew[tri_b->tri[2]].co,
+ data->culling,
+ data->use_normal,
+ pa,
+ pb,
+ vect);
if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
collpair[index].ap1 = tri_a->tri[0];
@@ -940,17 +1146,17 @@ static void cloth_selfcollision(void *__restrict userdata,
}
/* Compute distance and normal. */
- distance = compute_collision_point(verts1[tri_a->tri[0]].tx,
- verts1[tri_a->tri[1]].tx,
- verts1[tri_a->tri[2]].tx,
- verts1[tri_b->tri[0]].tx,
- verts1[tri_b->tri[1]].tx,
- verts1[tri_b->tri[2]].tx,
- false,
- false,
- pa,
- pb,
- vect);
+ distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx,
+ verts1[tri_a->tri[1]].tx,
+ verts1[tri_a->tri[2]].tx,
+ verts1[tri_b->tri[0]].tx,
+ verts1[tri_b->tri[1]].tx,
+ verts1[tri_b->tri[2]].tx,
+ false,
+ false,
+ pa,
+ pb,
+ vect);
if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
collpair[index].ap1 = tri_a->tri[0];
@@ -977,6 +1183,64 @@ static void cloth_selfcollision(void *__restrict userdata,
}
}
+static void hair_collision(void *__restrict userdata,
+ const int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ ColDetectData *data = (ColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollisionModifierData *collmd = data->collmd;
+ CollPair *collpair = data->collisions;
+ const MVertTri *tri_coll;
+ const MEdge *edge_coll;
+ ClothVertex *verts1 = clmd->clothObject->verts;
+ float distance = 0.0f;
+ float epsilon1 = clmd->coll_parms->epsilon;
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ float pa[3], pb[3], vect[3];
+
+ /* TODO: This is not efficient. Might be wise to instead build an array before iterating, to
+ * avoid walking the list every time. */
+ edge_coll = &clmd->clothObject->edges[data->overlap[index].indexA];
+ tri_coll = &collmd->tri[data->overlap[index].indexB];
+
+ /* Compute distance and normal. */
+ distance = compute_collision_point_edge_tri(verts1[edge_coll->v1].tx,
+ verts1[edge_coll->v2].tx,
+ collmd->current_x[tri_coll->tri[0]].co,
+ collmd->current_x[tri_coll->tri[1]].co,
+ collmd->current_x[tri_coll->tri[2]].co,
+ data->culling,
+ data->use_normal,
+ pa,
+ pb,
+ vect);
+
+ if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = edge_coll->v1;
+ collpair[index].ap2 = edge_coll->v2;
+
+ collpair[index].bp1 = tri_coll->tri[0];
+ collpair[index].bp2 = tri_coll->tri[1];
+ collpair[index].bp3 = tri_coll->tri[2];
+
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
+
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
+
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
+ }
+}
+
static void add_collision_object(ListBase *relations,
Object *ob,
int level,
@@ -1117,7 +1381,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti
col->ob = ob;
col->collmd = cmd;
/* make sure collider is properly set up */
- collision_move_object(cmd, 1.0, 0.0);
+ collision_move_object(cmd, 1.0, 0.0, true);
BLI_addtail(cache, col);
}
}
@@ -1142,6 +1406,7 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd,
bool culling,
bool use_normal)
{
+ const bool is_hair = (clmd->hairdata != NULL);
*collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
ColDetectData data = {
@@ -1157,7 +1422,8 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = true;
- BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
+ BLI_task_parallel_range(
+ 0, numresult, &data, is_hair ? hair_collision : cloth_collision, &settings);
return data.collided;
}
@@ -1302,8 +1568,14 @@ int cloth_bvh_collision(
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
bvhtree_update_from_cloth(clmd, false, false);
- collobjs = BKE_collision_objects_create(
- depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ /* Enable self collision if this is a hair sim */
+ const bool is_hair = (clmd->hairdata != NULL);
+
+ collobjs = BKE_collision_objects_create(depsgraph,
+ is_hair ? NULL : ob,
+ clmd->coll_parms->group,
+ &numcollobj,
+ eModifierType_Collision);
if (collobjs) {
coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
@@ -1319,7 +1591,7 @@ int cloth_bvh_collision(
}
/* Move object to position (step) in time. */
- collision_move_object(collmd, step + dt, step);
+ collision_move_object(collmd, step + dt, step, false);
overlap_obj[i] = BLI_bvhtree_overlap(
cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL);
@@ -1468,286 +1740,3 @@ void collision_get_collider_velocity(float vel_old[3],
/* XXX assume constant velocity of the collider for now */
copy_v3_v3(vel_old, vel_new);
}
-
-BLI_INLINE bool cloth_point_face_collision_params(const float p1[3],
- const float p2[3],
- const float v0[3],
- const float v1[3],
- const float v2[3],
- float r_nor[3],
- float *r_lambda,
- float r_w[3])
-{
- float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
- float nor_v0p2, nor_p1p2;
-
- sub_v3_v3v3(edge1, v1, v0);
- sub_v3_v3v3(edge2, v2, v0);
- cross_v3_v3v3(r_nor, edge1, edge2);
- normalize_v3(r_nor);
-
- sub_v3_v3v3(v0p2, p2, v0);
- nor_v0p2 = dot_v3v3(v0p2, r_nor);
- madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
- interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
-
- sub_v3_v3v3(p1p2, p2, p1);
- nor_p1p2 = dot_v3v3(p1p2, r_nor);
- *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
-
- return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
-}
-
-static CollPair *cloth_point_collpair(float p1[3],
- const float p2[3],
- const MVert *mverts,
- int bp1,
- int bp2,
- int bp3,
- int index_cloth,
- int index_coll,
- float epsilon,
- CollPair *collpair)
-{
- const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
- float lambda /*, distance1 */, distance2;
- float facenor[3], v1p1[3], v1p2[3];
- float w[3];
-
- if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) {
- return collpair;
- }
-
- sub_v3_v3v3(v1p1, p1, co1);
- // distance1 = dot_v3v3(v1p1, facenor);
- sub_v3_v3v3(v1p2, p2, co1);
- distance2 = dot_v3v3(v1p2, facenor);
- // if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f))
- if (distance2 > epsilon) {
- return collpair;
- }
-
- collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */
- collpair->face2 = index_coll;
- collpair->ap1 = index_cloth;
- collpair->ap2 = collpair->ap3 = -1; /* unused */
- collpair->bp1 = bp1;
- collpair->bp2 = bp2;
- collpair->bp3 = bp3;
-
- /* note: using the second point here, which is
- * the current updated position that needs to be corrected
- */
- copy_v3_v3(collpair->pa, p2);
- collpair->distance = distance2;
- mul_v3_v3fl(collpair->vector, facenor, -distance2);
-
- interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w);
-
- copy_v3_v3(collpair->normal, facenor);
- collpair->time = lambda;
- collpair->flag = 0;
-
- collpair++;
- return collpair;
-}
-
-/* Determines collisions on overlap,
- * collisions are written to collpair[i] and collision+number_collision_found is returned. */
-static CollPair *cloth_point_collision(ModifierData *md1,
- ModifierData *md2,
- BVHTreeOverlap *overlap,
- float epsilon,
- CollPair *collpair,
- float UNUSED(dt))
-{
- ClothModifierData *clmd = (ClothModifierData *)md1;
- CollisionModifierData *collmd = (CollisionModifierData *)md2;
- /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
- ClothVertex *vert = NULL;
- const MVertTri *vt;
- const MVert *mverts = collmd->current_x;
-
- vert = &clmd->clothObject->verts[overlap->indexA];
- vt = &collmd->tri[overlap->indexB];
-
- collpair = cloth_point_collpair(vert->tx,
- vert->x,
- mverts,
- vt->tri[0],
- vt->tri[1],
- vt->tri[2],
- overlap->indexA,
- overlap->indexB,
- epsilon,
- collpair);
-
- return collpair;
-}
-
-static void cloth_points_objcollisions_nearcheck(ClothModifierData *clmd,
- CollisionModifierData *collmd,
- CollPair **collisions,
- CollPair **collisions_index,
- int numresult,
- BVHTreeOverlap *overlap,
- float epsilon,
- double dt)
-{
- int i;
-
- /* can return 2 collisions in total */
- *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array");
- *collisions_index = *collisions;
-
- for (i = 0; i < numresult; i++) {
- *collisions_index = cloth_point_collision(
- (ModifierData *)clmd, (ModifierData *)collmd, overlap + i, epsilon, *collisions_index, dt);
- }
-}
-
-void cloth_find_point_contacts(Depsgraph *depsgraph,
- Object *ob,
- ClothModifierData *clmd,
- float step,
- float dt,
- ColliderContacts **r_collider_contacts,
- int *r_totcolliders)
-{
- Cloth *cloth = clmd->clothObject;
- BVHTree *cloth_bvh;
- unsigned int i = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
-
- ColliderContacts *collider_contacts;
-
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
-
- /* Check we do have collision objects to test against, before doing anything else. */
- collobjs = BKE_collision_objects_create(
- depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- if (!collobjs) {
- *r_collider_contacts = NULL;
- *r_totcolliders = 0;
- return;
- }
-
- // create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
- /* fill tree */
- for (i = 0; i < mvert_num; i++) {
- float co[6];
-
- copy_v3_v3(&co[0 * 3], verts[i].x);
- copy_v3_v3(&co[1 * 3], verts[i].tx);
-
- BLI_bvhtree_insert(cloth_bvh, i, co, 2);
- }
- /* balance tree */
- BLI_bvhtree_balance(cloth_bvh);
-
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
- collob, eModifierType_Collision);
- if (!collmd->bvhtree) {
- continue;
- }
-
- /* move object to position (step) in time */
- collision_move_object(collmd, step + dt, step);
- }
-
- collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair");
-
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- ColliderContacts *ct = collider_contacts + i;
- Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
- collob, eModifierType_Collision);
- BVHTreeOverlap *overlap;
- unsigned int result = 0;
- float epsilon;
-
- ct->ob = collob;
- ct->collmd = collmd;
- ct->collisions = NULL;
- ct->totcollisions = 0;
-
- if (!collmd->bvhtree) {
- continue;
- }
-
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- // go to next object if no overlap is there
- if (result && overlap) {
- CollPair *collisions_index;
-
- /* check if collisions really happen (costly near check) */
- cloth_points_objcollisions_nearcheck(
- clmd, collmd, &ct->collisions, &collisions_index, result, overlap, epsilon, dt);
- ct->totcollisions = (int)(collisions_index - ct->collisions);
-
- /* Resolve nearby collisions. */
-#if 0
- ret += cloth_points_objcollisions_resolve(
- clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt);
-#endif
- }
-
- if (overlap) {
- MEM_freeN(overlap);
- }
- }
-
- BKE_collision_objects_free(collobjs);
-
- BLI_bvhtree_free(cloth_bvh);
-
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
-
- // verts come from clmd
- for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->vgroup_mass > 0) {
- if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
- continue;
- }
- }
-
- add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv);
- }
- ////////////////////////////////////////////////////////////
-
- *r_collider_contacts = collider_contacts;
- *r_totcolliders = numcollobj;
-}
-
-void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders)
-{
- if (collider_contacts) {
- int i;
- for (i = 0; i < totcolliders; i++) {
- ColliderContacts *ct = collider_contacts + i;
- if (ct->collisions) {
- MEM_freeN(ct->collisions);
- }
- }
- MEM_freeN(collider_contacts);
- }
-}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index c397fbcf115..a17a09297c5 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -2062,36 +2062,21 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- if (data->mix_mode == TRANSLIKE_MIX_REPLACE) {
- /* just copy the entire transform matrix of the target */
- copy_m4_m4(cob->matrix, ct->matrix);
- }
- else {
- float old_loc[3], old_rot[3][3], old_size[3];
- float new_loc[3], new_rot[3][3], new_size[3];
-
- /* Separate matrices so they can be combined in a way that avoids shear. */
- mat4_to_loc_rot_size(old_loc, old_rot, old_size, cob->matrix);
- mat4_to_loc_rot_size(new_loc, new_rot, new_size, ct->matrix);
-
- switch (data->mix_mode) {
- case TRANSLIKE_MIX_BEFORE:
- mul_v3_m4v3(new_loc, ct->matrix, old_loc);
- mul_m3_m3m3(new_rot, new_rot, old_rot);
- mul_v3_v3(new_size, old_size);
- break;
+ switch (data->mix_mode) {
+ case TRANSLIKE_MIX_REPLACE:
+ copy_m4_m4(cob->matrix, ct->matrix);
+ break;
- case TRANSLIKE_MIX_AFTER:
- mul_v3_m4v3(new_loc, cob->matrix, new_loc);
- mul_m3_m3m3(new_rot, old_rot, new_rot);
- mul_v3_v3(new_size, old_size);
- break;
+ case TRANSLIKE_MIX_BEFORE:
+ mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
+ break;
- default:
- BLI_assert(false);
- }
+ case TRANSLIKE_MIX_AFTER:
+ mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
+ break;
- loc_rot_size_to_mat4(cob->matrix, new_loc, new_rot, new_size);
+ default:
+ BLI_assert(!"Unknown Copy Transforms mix mode");
}
}
}
@@ -2555,6 +2540,9 @@ static void actcon_new_data(void *cdata)
/* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */
data->type = 20;
+
+ /* Set the mix mode to After Original with anti-shear scale handling. */
+ data->mix_mode = ACTCON_MIX_AFTER;
}
static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -2695,18 +2683,28 @@ static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
}
}
-static void actcon_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
+static void actcon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
+ bActionConstraint *data = con->data;
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- float temp[4][4];
+ switch (data->mix_mode) {
+ case ACTCON_MIX_BEFORE:
+ mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
+ break;
- /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix
- * function has already taken care of everything else.
- */
- copy_m4_m4(temp, cob->matrix);
- mul_m4_m4m4(cob->matrix, temp, ct->matrix);
+ case ACTCON_MIX_AFTER:
+ mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
+ break;
+
+ case ACTCON_MIX_AFTER_FULL:
+ mul_m4_m4m4(cob->matrix, cob->matrix, ct->matrix);
+ break;
+
+ default:
+ BLI_assert(!"Unknown Action mix mode");
+ }
}
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 12bb7b573bd..4f0ff8bdcd3 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1805,91 +1805,88 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp)
}
}
else {
- short dnr;
-
- /* bevel now in three parts, for proper vertex normals */
- /* part 1, back */
-
- if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) {
- dnr = nr = 2 + cu->bevresol;
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- nr = 3 + 2 * cu->bevresol;
- }
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->flag = DL_BACK_CURVE;
- dl->nr = nr;
-
- /* half a circle */
- fp = dl->verts;
- dangle = ((float)M_PI_2 / (dnr - 1));
- angle = -(nr - 1) * dangle;
-
- for (a = 0; a < nr; a++) {
+ /* The general case for nonzero extrusion or an incomplete loop. */
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve");
+ if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
+ /* The full loop. */
+ nr = 4 * cu->bevresol + 6;
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ }
+ else if ((cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) {
+ /* Half the loop. */
+ nr = 2 * (cu->bevresol + 1) + ((cu->ext1 == 0.0f) ? 1 : 2);
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ }
+ else {
+ /* One quarter of the loop (just front or back). */
+ nr = (cu->ext1 == 0.0f) ? cu->bevresol + 2 : cu->bevresol + 3;
+ dl->flag = (cu->flag & CU_FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE;
+ }
+
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve");
+ BLI_addtail(disp, dl);
+ /* Use a different type depending on whether the loop is complete or not. */
+ dl->type = ((cu->flag & (CU_FRONT | CU_BACK)) == 0) ? DL_POLY : DL_SEGM;
+ dl->parts = 1;
+ dl->nr = nr;
+
+ fp = dl->verts;
+ dangle = (float)M_PI_2 / (cu->bevresol + 1);
+ angle = 0.0;
+
+ /* Build the back section. */
+ if (cu->flag & CU_BACK || !(cu->flag & CU_FRONT)) {
+ angle = (float)M_PI_2 * 3.0f;
+ for (a = 0; a < cu->bevresol + 2; a++) {
fp[0] = 0.0;
fp[1] = (float)(cosf(angle) * (cu->ext2));
fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
angle += dangle;
fp += 3;
}
+ if ((cu->ext1 != 0.0f) && !(cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) {
+ /* Add the extrusion if we're only building the back. */
+ fp[0] = 0.0;
+ fp[1] = cu->ext2;
+ fp[2] = cu->ext1;
+ }
}
- /* part 2, sidefaces */
- if (cu->ext1 != 0.0f) {
- nr = 2;
-
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->nr = nr;
-
- fp = dl->verts;
- fp[1] = cu->ext2;
- fp[2] = -cu->ext1;
- fp[4] = cu->ext2;
- fp[5] = cu->ext1;
-
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- dl = MEM_dupallocN(dl);
- dl->verts = MEM_dupallocN(dl->verts);
- BLI_addtail(disp, dl);
-
- fp = dl->verts;
- fp[1] = -fp[1];
- fp[2] = -fp[2];
- fp[4] = -fp[4];
- fp[5] = -fp[5];
+ /* Build the front section. */
+ if (cu->flag & CU_FRONT || !(cu->flag & CU_BACK)) {
+ if ((cu->ext1 != 0.0f) && !(cu->flag & CU_BACK) && (cu->flag & CU_FRONT)) {
+ /* Add the extrusion if we're only building the back. */
+ fp[0] = 0.0;
+ fp[1] = cu->ext2;
+ fp[2] = -cu->ext1;
+ fp += 3;
+ }
+ /* 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++) {
+ fp[0] = 0.0;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
}
}
- /* part 3, front */
- if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) {
- dnr = nr = 2 + cu->bevresol;
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- nr = 3 + 2 * cu->bevresol;
+ /* Build the other half only if we're building the full loop. */
+ if (!(cu->flag & (CU_FRONT | CU_BACK))) {
+ for (a = 0; a < cu->bevresol + 1; a++) {
+ fp[0] = 0.0;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
}
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->flag = DL_FRONT_CURVE;
- dl->parts = 1;
- dl->nr = nr;
-
- /* half a circle */
- fp = dl->verts;
- angle = 0.0;
- dangle = ((float)M_PI_2 / (dnr - 1));
- for (a = 0; a < nr; a++) {
+ angle = (float)M_PI;
+ for (a = 0; a < cu->bevresol + 1; a++) {
fp[0] = 0.0;
fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
angle += dangle;
fp += 3;
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index a964cab3fa5..79dcdd15bf7 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -345,7 +345,7 @@ void defvert_normalize_lock_single(MDeformVert *dvert,
else if (dvert->totweight == 1) {
MDeformWeight *dw = dvert->dw;
if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if (def_nr_lock != 0) {
+ if (def_nr_lock != dw->def_nr) {
dw->weight = 1.0f;
}
}
diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c
new file mode 100644
index 00000000000..4ac8d47feba
--- /dev/null
+++ b/source/blender/blenkernel/intern/displist_tangent.c
@@ -0,0 +1,279 @@
+/*
+ * 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 "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BKE_displist.h"
+#include "BKE_displist_tangent.h"
+
+#include "MEM_guardedalloc.h"
+
+/* interface */
+#include "mikktspace.h"
+
+typedef struct {
+ const DispList *dl;
+ float (*tangent)[4]; /* destination */
+ /** Face normal for flat shading. */
+ float (*fnormals)[3];
+ /** Use by surfaces. Size of the surface in faces. */
+ int u_len, v_len;
+} SGLSLDisplistToTangent;
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name DL_INDEX3 tangents
+ * \{ */
+
+static int dl3_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+
+ return dlt->dl->parts;
+}
+
+static int dl3_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+ UNUSED_VARS(pContext, face_num);
+
+ return 3;
+}
+
+static void dl3_ts_GetPosition(const SMikkTSpaceContext *pContext,
+ float r_co[3],
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ const float(*verts)[3] = (float(*)[3])dlt->dl->verts;
+ const int(*idx)[3] = (int(*)[3])dlt->dl->index;
+
+ copy_v3_v3(r_co, verts[idx[face_num][vert_index]]);
+}
+
+static void dl3_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
+ float r_uv[2],
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ const int(*idx)[3] = (int(*)[3])dlt->dl->index;
+
+ r_uv[0] = idx[face_num][vert_index] / (float)(dlt->dl->nr - 1);
+ r_uv[1] = 0.0f;
+}
+
+static void dl3_ts_GetNormal(const SMikkTSpaceContext *pContext,
+ float r_no[3],
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ UNUSED_VARS(face_num, vert_index);
+
+ copy_v3_v3(r_no, dlt->dl->nors);
+}
+
+static void dl3_ts_SetTSpace(const SMikkTSpaceContext *pContext,
+ const float fvTangent[3],
+ const float fSign,
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ UNUSED_VARS(face_num, vert_index);
+
+ copy_v3_v3(dlt->tangent[0], fvTangent);
+ dlt->tangent[0][3] = fSign;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name DL_SURF tangents
+ * \{ */
+
+static int dlsurf_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+
+ return dlt->v_len * dlt->u_len;
+}
+
+static int dlsurf_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+ UNUSED_VARS(pContext, face_num);
+
+ return 4;
+}
+
+static int face_to_vert_index(SGLSLDisplistToTangent *dlt,
+ const int face_num,
+ const int vert_index)
+{
+ int u = face_num % dlt->u_len;
+ int v = face_num / dlt->u_len;
+
+ if (vert_index == 0) {
+ u += 1;
+ }
+ else if (vert_index == 1) {
+ u += 1;
+ v += 1;
+ }
+ else if (vert_index == 2) {
+ v += 1;
+ }
+
+ /* Cyclic correction. */
+ u = u % dlt->dl->nr;
+ v = v % dlt->dl->parts;
+
+ return v * dlt->dl->nr + u;
+}
+
+static void dlsurf_ts_GetPosition(const SMikkTSpaceContext *pContext,
+ float r_co[3],
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ const float(*verts)[3] = (float(*)[3])dlt->dl->verts;
+
+ copy_v3_v3(r_co, verts[face_to_vert_index(dlt, face_num, vert_index)]);
+}
+
+static void dlsurf_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
+ float r_uv[2],
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+
+ int idx = face_to_vert_index(dlt, face_num, vert_index);
+
+ /* Note: For some reason the shading U and V are swapped compared to the
+ * one described in the surface format. */
+ r_uv[0] = (idx / dlt->dl->nr) / (float)(dlt->v_len);
+ r_uv[1] = (idx % dlt->dl->nr) / (float)(dlt->u_len);
+
+ if (r_uv[0] == 0.0f && ELEM(vert_index, 1, 2)) {
+ r_uv[0] = 1.0f;
+ }
+ if (r_uv[1] == 0.0f && ELEM(vert_index, 0, 1)) {
+ r_uv[1] = 1.0f;
+ }
+}
+
+static void dlsurf_ts_GetNormal(const SMikkTSpaceContext *pContext,
+ float r_no[3],
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ const float(*nors)[3] = (float(*)[3])dlt->dl->nors;
+
+ if (dlt->fnormals) {
+ copy_v3_v3(r_no, dlt->fnormals[face_num]);
+ }
+ else {
+ copy_v3_v3(r_no, nors[face_to_vert_index(dlt, face_num, vert_index)]);
+ }
+}
+
+static void dlsurf_ts_SetTSpace(const SMikkTSpaceContext *pContext,
+ const float fvTangent[3],
+ const float fSign,
+ const int face_num,
+ const int vert_index)
+{
+ SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
+ UNUSED_VARS(face_num, vert_index);
+
+ float *r_tan = dlt->tangent[face_num * 4 + vert_index];
+ copy_v3_v3(r_tan, fvTangent);
+ r_tan[3] = fSign;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Entry point
+ * \{ */
+
+void BKE_displist_tangent_calc(const DispList *dl, float (*fnormals)[3], float (**r_tangent)[4])
+{
+ if (dl->type == DL_INDEX3) {
+ /* INDEX3 have only one tangent so we don't need actual allocation. */
+ BLI_assert(*r_tangent != NULL);
+
+ SGLSLDisplistToTangent mesh2tangent = {
+ .tangent = *r_tangent,
+ .dl = dl,
+ };
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = &mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = dl3_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dl3_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dl3_ts_GetPosition;
+ sInterface.m_getTexCoord = dl3_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dl3_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dl3_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+ else if (dl->type == DL_SURF) {
+ SGLSLDisplistToTangent mesh2tangent = {
+ .dl = dl,
+ .u_len = dl->nr - ((dl->flag & DL_CYCL_U) ? 0 : 1),
+ .v_len = dl->parts - ((dl->flag & DL_CYCL_V) ? 0 : 1),
+ .fnormals = fnormals,
+ };
+
+ int loop_len = mesh2tangent.u_len * mesh2tangent.v_len * 4;
+
+ if (*r_tangent == NULL) {
+ *r_tangent = MEM_mallocN(sizeof(float[4]) * loop_len, "displist tangents");
+ }
+ mesh2tangent.tangent = *r_tangent;
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = &mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = dlsurf_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dlsurf_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dlsurf_ts_GetPosition;
+ sInterface.m_getTexCoord = dlsurf_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dlsurf_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dlsurf_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+ else {
+ /* Unsupported. */
+ BLI_assert(0);
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 74a523bfbdc..a70e5b67a15 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -6285,7 +6285,11 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
PART_FLUID_SPRAY,
PART_FLUID_BUBBLE,
PART_FLUID_FOAM,
- PART_FLUID_TRACER) &&
+ PART_FLUID_TRACER,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE) &&
psys_check_enabled(brushObj, brush->psys, for_render)) {
/* Paint a particle system */
dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
deleted file mode 100644
index 2df3d2f0fe9..00000000000
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup bke
- *
- * basic design:
- *
- * the bmesh derivedmesh exposes the mesh as triangles. it stores pointers
- * to three loops per triangle. the derivedmesh stores a cache of tessellations
- * for each face. this cache will smartly update as needed (though at first
- * it'll simply be more brute force). keeping track of face/edge counts may
- * be a small problem.
- *
- * this won't be the most efficient thing, considering that internal edges and
- * faces of tessellations are exposed. looking up an edge by index in particular
- * is likely to be a little slow.
- */
-
-#include "atomic_ops.h"
-
-#include "BLI_math.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_bitmap.h"
-#include "BLI_task.h"
-
-#include "BKE_cdderivedmesh.h"
-#include "BKE_deform.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_iterators.h"
-#include "BKE_editmesh.h"
-#include "BKE_editmesh_bvh.h"
-#include "BKE_editmesh_cache.h"
-#include "BKE_editmesh_tangent.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_mesh_types.h"
-
-#include "MEM_guardedalloc.h"
-
-/* -------------------------------------------------------------------- */
-/* StatVis Functions */
-
-static void axis_from_enum_v3(float v[3], const char axis)
-{
- zero_v3(v);
- if (axis < 3) {
- v[axis] = 1.0f;
- }
- else {
- v[axis - 3] = -1.0f;
- }
-}
-
-static void statvis_calc_overhang(BMEditMesh *em,
- const float (*polyNos)[3],
- /* values for calculating */
- const float min,
- const float max,
- const char axis,
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- BMIter iter;
- BMesh *bm = em->bm;
- BMFace *f;
- float dir[3];
- int index;
- const float minmax_irange = 1.0f / (max - min);
- bool is_max;
-
- /* fallback */
- unsigned char col_fallback[4] = {64, 64, 64, 255}; /* gray */
- unsigned char col_fallback_max[4] = {0, 0, 0, 255}; /* max color */
-
- BLI_assert(min <= max);
-
- axis_from_enum_v3(dir, axis);
-
- if (LIKELY(em->ob)) {
- mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
- normalize_v3(dir);
- }
-
- /* fallback max */
- {
- float fcol[3];
- BKE_defvert_weight_to_rgb(fcol, 1.0f);
- rgb_float_to_uchar(col_fallback_max, fcol);
- }
-
- /* now convert into global space */
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
- float fac = angle_normalized_v3v3(polyNos ? polyNos[index] : f->no, dir) / (float)M_PI;
-
- /* remap */
- if ((is_max = (fac <= max)) && (fac >= min)) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- fac = 1.0f - fac;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[index], fcol);
- }
- else {
- const unsigned char *fallback = is_max ? col_fallback_max : col_fallback;
- copy_v4_v4_uchar(r_face_colors[index], fallback);
- }
- }
-}
-
-/* so we can use jitter values for face interpolation */
-static void uv_from_jitter_v2(float uv[2])
-{
- uv[0] += 0.5f;
- uv[1] += 0.5f;
- if (uv[0] + uv[1] > 1.0f) {
- uv[0] = 1.0f - uv[0];
- uv[1] = 1.0f - uv[1];
- }
-
- CLAMP(uv[0], 0.0f, 1.0f);
- CLAMP(uv[1], 0.0f, 1.0f);
-}
-
-static void statvis_calc_thickness(BMEditMesh *em,
- const float (*vertexCos)[3],
- /* values for calculating */
- const float min,
- const float max,
- const int samples,
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
- float *face_dists = (float *)r_face_colors; /* cheating */
- const bool use_jit = samples < 32;
- float jit_ofs[32][2];
- BMesh *bm = em->bm;
- const int tottri = em->tottri;
- const float minmax_irange = 1.0f / (max - min);
- int i;
-
- struct BMLoop *(*looptris)[3] = em->looptris;
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- struct BMBVHTree *bmtree;
-
- BLI_assert(min <= max);
-
- copy_vn_fl(face_dists, em->bm->totface, max);
-
- if (use_jit) {
- int j;
- BLI_assert(samples < 32);
- BLI_jitter_init(jit_ofs, samples);
-
- for (j = 0; j < samples; j++) {
- uv_from_jitter_v2(jit_ofs[j]);
- }
- }
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- if (vertexCos) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
-
- for (i = 0; i < tottri; i++) {
- BMFace *f_hit;
- BMLoop **ltri = looptris[i];
- const int index = BM_elem_index_get(ltri[0]->f);
- const float *cos[3];
- float ray_co[3];
- float ray_no[3];
-
- if (vertexCos) {
- cos[0] = vertexCos[BM_elem_index_get(ltri[0]->v)];
- cos[1] = vertexCos[BM_elem_index_get(ltri[1]->v)];
- cos[2] = vertexCos[BM_elem_index_get(ltri[2]->v)];
- }
- else {
- cos[0] = ltri[0]->v->co;
- cos[1] = ltri[1]->v->co;
- cos[2] = ltri[2]->v->co;
- }
-
- normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
-
-#define FACE_RAY_TEST_ANGLE \
- 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)); \
- angle_fac = 1.0f - angle_fac; \
- angle_fac = angle_fac * angle_fac * angle_fac; \
- angle_fac = 1.0f - angle_fac; \
- dist /= angle_fac; \
- if (dist < face_dists[index]) { \
- face_dists[index] = dist; \
- } \
- } \
- (void)0
-
- if (use_jit) {
- int j;
- for (j = 0; j < samples; j++) {
- float dist = face_dists[index];
- interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
- madd_v3_v3fl(ray_co, ray_no, eps_offset);
-
- FACE_RAY_TEST_ANGLE;
- }
- }
- else {
- float dist = face_dists[index];
- mid_v3_v3v3v3(ray_co, cos[0], cos[1], cos[2]);
- madd_v3_v3fl(ray_co, ray_no, eps_offset);
-
- FACE_RAY_TEST_ANGLE;
- }
- }
-
- BKE_bmbvh_free(bmtree);
-
- /* convert floats into color! */
- for (i = 0; i < bm->totface; i++) {
- float fac = face_dists[i];
-
- /* important not '<=' */
- if (fac < max) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- fac = 1.0f - fac;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[i], fcol);
- }
- else {
- copy_v4_v4_uchar(r_face_colors[i], col_fallback);
- }
- }
-}
-
-static void statvis_calc_intersect(BMEditMesh *em,
- const float (*vertexCos)[3],
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- BMesh *bm = em->bm;
- int i;
-
- /* fallback */
- // const char col_fallback[4] = {64, 64, 64, 255};
- float fcol[3];
- unsigned char col[3];
-
- struct BMBVHTree *bmtree;
- BVHTreeOverlap *overlap;
- unsigned int overlap_len;
-
- memset(r_face_colors, 64, sizeof(int) * em->bm->totface);
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- if (vertexCos) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
-
- overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
-
- /* same for all faces */
- BKE_defvert_weight_to_rgb(fcol, 1.0f);
- rgb_float_to_uchar(col, fcol);
-
- if (overlap) {
- for (i = 0; i < overlap_len; i++) {
- BMFace *f_hit_pair[2] = {
- em->looptris[overlap[i].indexA][0]->f,
- em->looptris[overlap[i].indexB][0]->f,
- };
- int j;
-
- for (j = 0; j < 2; j++) {
- BMFace *f_hit = f_hit_pair[j];
- int index;
-
- index = BM_elem_index_get(f_hit);
-
- copy_v3_v3_uchar(r_face_colors[index], col);
- }
- }
- MEM_freeN(overlap);
- }
-
- BKE_bmbvh_free(bmtree);
-}
-
-static void statvis_calc_distort(BMEditMesh *em,
- const float (*vertexCos)[3],
- const float (*polyNos)[3],
- /* values for calculating */
- const float min,
- const float max,
- /* result */
- unsigned char (*r_face_colors)[4])
-{
- BMIter iter;
- BMesh *bm = em->bm;
- BMFace *f;
- const float *f_no;
- int index;
- const float minmax_irange = 1.0f / (max - min);
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- /* now convert into global space */
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
- float fac;
-
- if (f->len == 3) {
- fac = -1.0f;
- }
- else {
- BMLoop *l_iter, *l_first;
- if (vertexCos) {
- f_no = polyNos[index];
- }
- else {
- f_no = f->no;
- }
-
- fac = 0.0f;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- float no_corner[3];
- if (vertexCos) {
- normal_tri_v3(no_corner,
- vertexCos[BM_elem_index_get(l_iter->prev->v)],
- vertexCos[BM_elem_index_get(l_iter->v)],
- vertexCos[BM_elem_index_get(l_iter->next->v)]);
- }
- else {
- 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) {
- negate_v3(no_corner);
- }
- fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
- } while ((l_iter = l_iter->next) != l_first);
- fac *= 2.0f;
- }
-
- /* remap */
- if (fac >= min) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[index], fcol);
- }
- else {
- copy_v4_v4_uchar(r_face_colors[index], col_fallback);
- }
- }
-}
-
-static void statvis_calc_sharp(BMEditMesh *em,
- const float (*vertexCos)[3],
- /* values for calculating */
- const float min,
- const float max,
- /* result */
- unsigned char (*r_vert_colors)[4])
-{
- float *vert_angles = (float *)r_vert_colors; /* cheating */
- BMIter iter;
- BMesh *bm = em->bm;
- BMEdge *e;
- // float f_no[3];
- const float minmax_irange = 1.0f / (max - min);
- int i;
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- (void)vertexCos; /* TODO */
-
- copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
-
- /* first assign float values to verts */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- float angle = BM_edge_calc_face_angle_signed(e);
- float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
- float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
- *col1 = max_ff(*col1, angle);
- *col2 = max_ff(*col2, angle);
- }
-
- /* convert floats into color! */
- for (i = 0; i < bm->totvert; i++) {
- float fac = vert_angles[i];
-
- /* important not '<=' */
- if (fac > min) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_vert_colors[i], fcol);
- }
- else {
- copy_v4_v4_uchar(r_vert_colors[i], col_fallback);
- }
- }
-}
-
-void BKE_editmesh_statvis_calc(BMEditMesh *em, EditMeshData *emd, const MeshStatVis *statvis)
-{
- switch (statvis->type) {
- case SCE_STATVIS_OVERHANG: {
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_overhang(em,
- emd ? emd->polyNos : NULL,
- statvis->overhang_min / (float)M_PI,
- statvis->overhang_max / (float)M_PI,
- statvis->overhang_axis,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_THICKNESS: {
- const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_thickness(em,
- emd ? emd->vertexCos : NULL,
- statvis->thickness_min * scale,
- statvis->thickness_max * scale,
- statvis->thickness_samples,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_INTERSECT: {
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_intersect(em, emd ? emd->vertexCos : NULL, em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_DISTORT: {
- BKE_editmesh_color_ensure(em, BM_FACE);
-
- if (emd) {
- BKE_editmesh_cache_ensure_poly_normals(em, emd);
- }
-
- statvis_calc_distort(em,
- emd ? emd->vertexCos : NULL,
- emd ? emd->polyNos : NULL,
- statvis->distort_min,
- statvis->distort_max,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_SHARP: {
- BKE_editmesh_color_ensure(em, BM_VERT);
- statvis_calc_sharp(em,
- emd ? emd->vertexCos : NULL,
- statvis->sharp_min,
- statvis->sharp_max,
- /* in this case they are vertex colors */
- em->derivedVertColor);
- break;
- }
- }
-}
-
-/* -------------------------------------------------------------------- */
-/* Editmesh Vert Coords */
-
-struct CageUserData {
- int totvert;
- float (*cos_cage)[3];
- BLI_bitmap *visit_bitmap;
-};
-
-static void cage_mapped_verts_callback(void *userData,
- int index,
- const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
-{
- struct CageUserData *data = userData;
-
- if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
- BLI_BITMAP_ENABLE(data->visit_bitmap, index);
- copy_v3_v3(data->cos_cage[index], co);
- }
-}
-
-float (*BKE_editmesh_vert_coords_alloc(
- struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_vert_len))[3]
-{
- Mesh *cage;
- BLI_bitmap *visit_bitmap;
- struct CageUserData data;
- float(*cos_cage)[3];
-
- cage = editbmesh_get_eval_cage(depsgraph, scene, em->ob, em, &CD_MASK_BAREMESH);
- cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
-
- /* when initializing cage verts, we only want the first cage coordinate for each vertex,
- * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
- visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
-
- data.totvert = em->bm->totvert;
- data.cos_cage = cos_cage;
- data.visit_bitmap = visit_bitmap;
-
- BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
-
- MEM_freeN(visit_bitmap);
-
- if (r_vert_len) {
- *r_vert_len = em->bm->totvert;
- }
-
- return cos_cage;
-}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index b135574a650..9b67a4fb925 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -33,6 +33,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_object.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
@@ -55,11 +56,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
em_copy->bb_cage = NULL;
- em_copy->derivedVertColor = NULL;
- em_copy->derivedVertColorLen = 0;
- em_copy->derivedFaceColor = NULL;
- em_copy->derivedFaceColorLen = 0;
-
em_copy->bm = BM_mesh_copy(em->bm);
/* The tessellation is NOT calculated on the copy here,
@@ -163,8 +159,6 @@ void BKE_editmesh_free(BMEditMesh *em)
{
BKE_editmesh_free_derivedmesh(em);
- BKE_editmesh_color_free(em);
-
if (em->looptris) {
MEM_freeN(em->looptris);
}
@@ -174,44 +168,57 @@ void BKE_editmesh_free(BMEditMesh *em)
}
}
-void BKE_editmesh_color_free(BMEditMesh *em)
+struct CageUserData {
+ int totvert;
+ float (*cos_cage)[3];
+ BLI_bitmap *visit_bitmap;
+};
+
+static void cage_mapped_verts_callback(void *userData,
+ int index,
+ const float co[3],
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- if (em->derivedVertColor) {
- MEM_freeN(em->derivedVertColor);
- }
- if (em->derivedFaceColor) {
- MEM_freeN(em->derivedFaceColor);
- }
- em->derivedVertColor = NULL;
- em->derivedFaceColor = NULL;
+ struct CageUserData *data = userData;
- em->derivedVertColorLen = 0;
- em->derivedFaceColorLen = 0;
+ if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
+ BLI_BITMAP_ENABLE(data->visit_bitmap, index);
+ copy_v3_v3(data->cos_cage[index], co);
+ }
}
-void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
+float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
+ BMEditMesh *em,
+ struct Scene *scene,
+ Object *ob,
+ int *r_vert_len))[3]
{
- switch (htype) {
- case BM_VERT:
- if (em->derivedVertColorLen != em->bm->totvert) {
- BKE_editmesh_color_free(em);
- em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert,
- __func__);
- em->derivedVertColorLen = em->bm->totvert;
- }
- break;
- case BM_FACE:
- if (em->derivedFaceColorLen != em->bm->totface) {
- BKE_editmesh_color_free(em);
- em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface,
- __func__);
- em->derivedFaceColorLen = em->bm->totface;
- }
- break;
- default:
- BLI_assert(0);
- break;
+ Mesh *cage;
+ BLI_bitmap *visit_bitmap;
+ struct CageUserData data;
+ float(*cos_cage)[3];
+
+ cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH);
+ cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
+
+ /* when initializing cage verts, we only want the first cage coordinate for each vertex,
+ * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
+ visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+
+ data.totvert = em->bm->totvert;
+ data.cos_cage = cos_cage;
+ data.visit_bitmap = visit_bitmap;
+
+ BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
+
+ MEM_freeN(visit_bitmap);
+
+ if (r_vert_len) {
+ *r_vert_len = em->bm->totvert;
}
+
+ return cos_cage;
}
float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
@@ -219,7 +226,7 @@ float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
return BM_mesh_vert_coords_alloc(em->bm, r_vert_len);
}
-void BKE_editmesh_lnorspace_update(BMEditMesh *em)
+void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
{
BMesh *bm = em->bm;
@@ -231,7 +238,6 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em)
* with related sharp edges (and hence autosmooth is 'lost').
* Not sure how critical this is, and how to fix that issue? */
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
- Mesh *me = em->ob->data;
if (me->flag & ME_AUTOSMOOTH) {
BM_edges_sharp_from_angle_set(bm, me->smoothresh);
}
@@ -241,12 +247,11 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em)
}
/* If autosmooth not already set, set it */
-void BKE_editmesh_ensure_autosmooth(BMEditMesh *em)
+void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
{
- Mesh *me = em->ob->data;
if (!(me->flag & ME_AUTOSMOOTH)) {
me->flag |= ME_AUTOSMOOTH;
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_lnorspace_update(em, me);
}
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 3876033eaaa..833b8409f7d 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -1171,16 +1171,16 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
*/
void sort_time_fcurve(FCurve *fcu)
{
- bool ok = true;
/* keep adjusting order of beztriples until nothing moves (bubble-sort) */
- while (ok) {
- ok = 0;
+ if (fcu->bezt) {
+ BezTriple *bezt;
+ uint a;
- /* currently, will only be needed when there are beztriples */
- if (fcu->bezt) {
- BezTriple *bezt;
- unsigned int a;
+ bool ok = true;
+ while (ok) {
+ ok = 0;
+ /* currently, will only be needed when there are beztriples */
/* loop over ALL points to adjust position in array and recalculate handles */
for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
@@ -1191,20 +1191,22 @@ void sort_time_fcurve(FCurve *fcu)
SWAP(BezTriple, *bezt, *(bezt + 1));
ok = 1;
}
-
- /* if either one of both of the points exceeds crosses over the keyframe time... */
- if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) {
- /* swap handles if they have switched sides for some reason */
- swap_v2_v2(bezt->vec[0], bezt->vec[2]);
- }
- else {
- /* clamp handles */
- CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
- CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
- }
}
}
}
+
+ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
+ /* if either one of both of the points exceeds crosses over the keyframe time... */
+ if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) {
+ /* swap handles if they have switched sides for some reason */
+ swap_v2_v2(bezt->vec[0], bezt->vec[2]);
+ }
+ else {
+ /* clamp handles */
+ CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
+ CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
+ }
+ }
}
}
@@ -2140,20 +2142,34 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
/* 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 + 1);
- int i = 0;
+ const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM);
+ int i = VAR_INDEX_CUSTOM;
- names[i++] = "frame";
+ 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 + 1);
+ 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,
@@ -2163,10 +2179,10 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver,
{
/* Prepare parameter values. */
int vars_len = BLI_listbase_count(&driver->variables);
- double *vars = BLI_array_alloca(vars, vars_len + 1);
- int i = 0;
+ double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM);
+ int i = VAR_INDEX_CUSTOM;
- vars[i++] = time;
+ vars[VAR_INDEX_FRAME] = time;
for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
vars[i++] = driver_get_variable_value(driver, dvar);
@@ -2174,7 +2190,8 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver,
/* Evaluate expression. */
double result_val;
- eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val);
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(
+ expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val);
const char *message;
switch (status) {
@@ -2243,6 +2260,44 @@ 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,
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 96be64dea75..f19137bf796 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -85,6 +85,9 @@
/** Time step default value for nice appearance. */
#define DT_DEFAULT 0.1f
+/** Max value for phi initialization */
+#define PHI_MAX 9999.0f
+
static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need_lock);
#ifdef WITH_FLUID
@@ -330,22 +333,22 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
{
char temp_dir[FILE_MAX];
int flags = mds->cache_flag;
-
- /* Ensure cache directory is not relative */
const char *relbase = modifier_path_relbase_from_global(ob);
- BLI_path_abs(mds->cache_directory, relbase);
if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
@@ -354,6 +357,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
@@ -362,6 +366,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
@@ -372,6 +377,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
FLUID_DOMAIN_OUTDATED_PARTICLES);
BLI_path_join(
temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
@@ -381,6 +387,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
@@ -612,7 +619,7 @@ typedef struct ObstaclesFromDMData {
bool has_velocity;
float *vert_vel;
float *velocity_x, *velocity_y, *velocity_z;
- int *num_objects;
+ float *num_objects;
float *distances_map;
} ObstaclesFromDMData;
@@ -623,10 +630,10 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata,
ObstaclesFromDMData *data = userdata;
FluidDomainSettings *mds = data->mds;
- /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
- const float surface_distance = 2.0f; // 0.867f;
- /* Note: Use larger surface distance to cover larger area with obvel. Manta will use these obvels
- * and extrapolate them (inside and outside obstacle) */
+ /* Distance between two opposing vertices in a unit cube.
+ * I.e. the unit cube diagonal or sqrt(3).
+ * This value is our nearest neighbour search distance. */
+ const float surface_distance = 1.732;
for (int x = mds->res_min[0]; x < mds->res_max[0]; x++) {
for (int y = mds->res_min[1]; y < mds->res_max[1]; y++) {
@@ -640,7 +647,7 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata,
surface_distance; /* find_nearest uses squared distance */
bool has_inc_obj = false;
- /* find the nearest point on the mesh */
+ /* Find the nearest point on the mesh. */
if (BLI_bvhtree_find_nearest(
data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
-1) {
@@ -698,15 +705,9 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata,
}
else {
/* Apply (i.e. add) effector object velocity */
- data->velocity_x[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
- hit_vel[0] * data->mes->vel_multi :
- hit_vel[0];
- data->velocity_y[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
- hit_vel[1] * data->mes->vel_multi :
- hit_vel[1];
- data->velocity_z[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ?
- hit_vel[2] * data->mes->vel_multi :
- hit_vel[2];
+ data->velocity_x[index] += hit_vel[0];
+ data->velocity_y[index] += hit_vel[1];
+ data->velocity_z[index] += hit_vel[2];
# ifdef DEBUG_PRINT
/* Debugging: Print object velocities. */
printf("adding effector object vel: [%f, %f, %f], dx is: %f\n",
@@ -745,7 +746,7 @@ static void obstacles_from_mesh(Object *coll_ob,
float *velocity_x,
float *velocity_y,
float *velocity_z,
- int *num_objects,
+ float *num_objects,
float dt)
{
if (!mes->mesh) {
@@ -918,32 +919,21 @@ static void update_obstacles(Depsgraph *depsgraph,
float *vel_x_guide = manta_get_guide_velocity_x(mds->fluid);
float *vel_y_guide = manta_get_guide_velocity_y(mds->fluid);
float *vel_z_guide = manta_get_guide_velocity_z(mds->fluid);
- float *vel_x_orig = manta_get_velocity_x(mds->fluid);
- float *vel_y_orig = manta_get_velocity_y(mds->fluid);
- float *vel_z_orig = manta_get_velocity_z(mds->fluid);
- float *density = manta_smoke_get_density(mds->fluid);
- float *fuel = manta_smoke_get_fuel(mds->fluid);
- float *flame = manta_smoke_get_flame(mds->fluid);
- float *r = manta_smoke_get_color_r(mds->fluid);
- float *g = manta_smoke_get_color_g(mds->fluid);
- float *b = manta_smoke_get_color_b(mds->fluid);
float *phi_obs_in = manta_get_phiobs_in(mds->fluid);
float *phi_guide_in = manta_get_phiguide_in(mds->fluid);
- int *obstacles = manta_smoke_get_obstacle(mds->fluid);
- int *num_obstacles = manta_get_num_obstacle(mds->fluid);
- int *num_guides = manta_get_num_guide(mds->fluid);
+ float *num_obstacles = manta_get_num_obstacle(mds->fluid);
+ float *num_guides = manta_get_num_guide(mds->fluid);
uint z;
- float tmp = 0;
/* Grid reset before writing again. */
for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
/* Use big value that's not inf to initialize levelset grids. */
if (phi_obs_in) {
- phi_obs_in[z] = FLT_MAX;
+ phi_obs_in[z] = PHI_MAX;
}
if (phi_guide_in) {
- phi_guide_in[z] = FLT_MAX;
+ phi_guide_in[z] = PHI_MAX;
}
if (num_obstacles) {
num_obstacles[z] = 0;
@@ -1019,44 +1009,6 @@ static void update_obstacles(Depsgraph *depsgraph,
}
BKE_collision_objects_free(coll_ob_array);
-
- /* Obstacle cells should not contain any velocity from the smoke simulation. */
- for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
- if (obstacles[z] & 2) /* Mantaflow convention: FlagObstacle. */
- {
- if (vel_x_orig && vel_y_orig && vel_z_orig) {
- vel_x_orig[z] = 0.0f;
- vel_y_orig[z] = 0.0f;
- vel_z_orig[z] = 0.0f;
- }
- if (density) {
- density[z] = 0.0f;
- }
- if (fuel) {
- fuel[z] = 0.0f;
- flame[z] = 0.0f;
- }
- if (r) {
- r[z] = 0.0f;
- g[z] = 0.0f;
- b[z] = 0.0f;
- }
- }
- /* Average velocities from multiple obstacles in one cell. */
- if (num_obstacles && num_obstacles[z]) {
- tmp = 1.0f / num_obstacles[z];
- vel_x[z] *= tmp;
- vel_y[z] *= tmp;
- vel_z[z] *= tmp;
- }
- /* Average velocities from multiple guides in one cell. */
- if (num_guides && num_guides[z]) {
- tmp = 1.0f / num_guides[z];
- vel_x_guide[z] *= tmp;
- vel_y_guide[z] *= tmp;
- vel_z_guide[z] *= tmp;
- }
- }
}
/** \} */
@@ -1067,10 +1019,8 @@ static void update_obstacles(Depsgraph *depsgraph,
typedef struct EmissionMap {
float *influence;
- float *influence_high;
float *velocity;
float *distances;
- float *distances_high;
int min[3], max[3], res[3];
int hmin[3], hmax[3], hres[3];
int total_cells, valid;
@@ -1127,7 +1077,7 @@ static void clamp_bounds_in_domain(FluidDomainSettings *mds,
}
}
-static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
+static void em_allocateData(EmissionMap *em, bool use_velocity)
{
int i, res[3];
@@ -1149,23 +1099,6 @@ static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
/* Initialize to infinity. */
memset(em->distances, 0x7f7f7f7f, sizeof(float) * em->total_cells);
- /* Allocate high resolution map if required. */
- if (hires_mul > 1) {
- int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
-
- for (i = 0; i < 3; i++) {
- em->hmin[i] = em->min[i] * hires_mul;
- em->hmax[i] = em->max[i] * hires_mul;
- em->hres[i] = em->res[i] * hires_mul;
- }
-
- em->influence_high = MEM_calloc_arrayN(
- total_cells_high, sizeof(float), "manta_flow_influence_high");
- em->distances_high = MEM_malloc_arrayN(
- total_cells_high, sizeof(float), "manta_flow_distances_high");
- /* Initialize to infinity. */
- memset(em->distances_high, 0x7f7f7f7f, sizeof(float) * total_cells_high);
- }
em->valid = true;
}
@@ -1174,22 +1107,15 @@ static void em_freeData(EmissionMap *em)
if (em->influence) {
MEM_freeN(em->influence);
}
- if (em->influence_high) {
- MEM_freeN(em->influence_high);
- }
if (em->velocity) {
MEM_freeN(em->velocity);
}
if (em->distances) {
MEM_freeN(em->distances);
}
- if (em->distances_high) {
- MEM_freeN(em->distances_high);
- }
}
-static void em_combineMaps(
- EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
+static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int additive, float sample_size)
{
int i, x, y, z;
@@ -1209,7 +1135,7 @@ static void em_combineMaps(
}
}
/* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+ em_allocateData(output, (em1.velocity || em2->velocity));
/* base resolution inputs */
for (x = output->min[0]; x < output->max[0]; x++) {
@@ -1265,48 +1191,6 @@ static void em_combineMaps(
}
}
- /* initialize high resolution input if available */
- if (output->influence_high) {
- for (x = output->hmin[0]; x < output->hmax[0]; x++) {
- for (y = output->hmin[1]; y < output->hmax[1]; y++) {
- for (z = output->hmin[2]; z < output->hmax[2]; z++) {
- int index_out = manta_get_index(x - output->hmin[0],
- output->hres[0],
- y - output->hmin[1],
- output->hres[1],
- z - output->hmin[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
- z >= em1.hmin[2] && z < em1.hmax[2]) {
- int index_in = manta_get_index(
- x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
- /* values */
- output->influence_high[index_out] = em1.influence_high[index_in];
- }
-
- /* apply second input if in range */
- if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
- z >= em2->hmin[2] && z < em2->hmax[2]) {
- int index_in = manta_get_index(
- x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
-
- /* values */
- if (additive) {
- output->influence_high[index_out] += em2->distances_high[index_in] * sample_size;
- }
- else {
- output->distances_high[index_out] = MAX2(em2->distances_high[index_in],
- output->distances_high[index_out]);
- }
- output->distances_high[index_out] = MIN2(em2->distances_high[index_in],
- output->distances_high[index_out]);
- }
- } // high res loop
- }
- }
- }
-
/* free original data */
em_freeData(&em1);
}
@@ -1314,17 +1198,13 @@ static void em_combineMaps(
typedef struct EmitFromParticlesData {
FluidFlowSettings *mfs;
KDTree_3d *tree;
- int hires_multiplier;
EmissionMap *em;
float *particle_vel;
- float hr;
-
int *min, *max, *res;
float solid;
float smooth;
- float hr_smooth;
} EmitFromParticlesData;
static void emit_from_particles_task_cb(void *__restrict userdata,
@@ -1334,62 +1214,26 @@ static void emit_from_particles_task_cb(void *__restrict userdata,
EmitFromParticlesData *data = userdata;
FluidFlowSettings *mfs = data->mfs;
EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
for (int x = data->min[0]; x < data->max[0]; x++) {
for (int y = data->min[1]; y < data->max[1]; y++) {
- /* Take low res samples where possible. */
- if (hires_multiplier <= 1 ||
- !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* Get low res space coordinates. */
- float inv_multiplier = 1.0f / hires_multiplier;
- const int lx = x * inv_multiplier;
- const int ly = y * inv_multiplier;
- const int lz = z * inv_multiplier;
-
- const int index = manta_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* Find particle distance from the kdtree. */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence[index] = (nearest.dist < data->solid) ?
- 1.0f :
- (1.0f - (nearest.dist - data->solid) / data->smooth);
- /* Uses particle velocity as initial velocity for smoke. */
- if (mfs->flags & FLUID_FLOW_INITVELOCITY &&
- (mfs->psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(
- &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], mfs->vel_multi);
- }
- }
- }
-
- /* Take high res samples if required. */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = manta_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {
- lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- /* Find particle distance from the kdtree. */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->hr_smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence_high[index] = (nearest.dist < data->solid) ?
- 1.0f :
- (1.0f - (nearest.dist - data->solid) / data->smooth);
+ const int index = manta_get_index(
+ x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
+ const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f};
+
+ /* Find particle distance from the kdtree. */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ /* Uses particle velocity as initial velocity for smoke. */
+ if (mfs->flags & FLUID_FLOW_INITVELOCITY && (mfs->psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(
+ &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], mfs->vel_multi);
}
}
}
@@ -1419,7 +1263,6 @@ static void emit_from_particles(Object *flow_ob,
/* radius based flow */
const float solid = mfs->particle_size * 0.5f;
const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
- int hires_multiplier = 1;
KDTree_3d *tree = NULL;
sim.depsgraph = depsgraph;
@@ -1456,12 +1299,6 @@ static void emit_from_particles(Object *flow_ob,
/* setup particle radius emission if enabled */
if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) {
tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
-
- /* check need for high resolution map */
- if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = mds->noise_scale;
- }
-
bounds_margin = (int)ceil(solid + smooth);
}
@@ -1509,7 +1346,7 @@ static void emit_from_particles(Object *flow_ob,
/* set emission map */
clamp_bounds_in_domain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt);
- em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier);
+ em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY);
if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) {
for (p = 0; p < valid_particles; p++) {
@@ -1544,16 +1381,12 @@ static void emit_from_particles(Object *flow_ob,
}
else if (valid_particles > 0) { // FLUID_FLOW_USE_PART_SIZE
int min[3], max[3], res[3];
- const float hr = 1.0f / ((float)hires_multiplier);
- /* Slightly adjust high res anti-alias smoothness based on number of divisions
- * to allow smaller details but yet not differing too much from the low res size. */
- const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
/* setup loop bounds */
for (int i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
+ min[i] = em->min[i];
+ max[i] = em->max[i];
+ res[i] = em->res[i];
}
BLI_kdtree_3d_balance(tree);
@@ -1561,8 +1394,6 @@ static void emit_from_particles(Object *flow_ob,
EmitFromParticlesData data = {
.mfs = mfs,
.tree = tree,
- .hires_multiplier = hires_multiplier,
- .hr = hr,
.em = em,
.particle_vel = particle_vel,
.min = min,
@@ -1570,7 +1401,6 @@ static void emit_from_particles(Object *flow_ob,
.res = res,
.solid = solid,
.smooth = smooth,
- .hr_smooth = hr_smooth,
};
TaskParallelSettings settings;
@@ -1602,13 +1432,14 @@ static void update_mesh_distances(int index,
float surface_thickness,
int use_plane_init)
{
- float min_dist = FLT_MAX;
+ float min_dist = PHI_MAX;
- /* Ensure that planes get initialized correctly. */
+ /* a) Planar initialization */
if (use_plane_init) {
BVHTreeNearest nearest = {0};
nearest.index = -1;
- nearest.dist_sq = surface_thickness;
+ nearest.dist_sq = surface_thickness *
+ surface_thickness; /* find_nearest uses squared distance */
if (BLI_bvhtree_find_nearest(
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
@@ -1616,12 +1447,14 @@ static void update_mesh_distances(int index,
sub_v3_v3v3(ray, ray_start, nearest.co);
min_dist = len_v3(ray);
min_dist = (-1.0f) * fabsf(min_dist);
- mesh_distances[index] = MIN2(mesh_distances[index], min_dist);
+ mesh_distances[index] = min_dist;
}
return;
}
- /* First pass: Ray-casts in 26 directions
+ /* b) Volumetric initialization: Ray-casts around mesh object. */
+
+ /* Ray-casts in 26 directions.
* (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */
float ray_dirs[26][3] = {
{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
@@ -1633,15 +1466,16 @@ static void update_mesh_distances(int index,
{-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0];
- /* Count for ray misses (no face hit) and cases where ray direction matches face normal
- * direction. */
+ /* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face
+ * normal direction. From this information it can be derived whether a cell is inside or outside
+ * the mesh. */
int miss_cnt = 0, dir_cnt = 0;
- min_dist = FLT_MAX;
+ min_dist = PHI_MAX;
for (int i = 0; i < ray_cnt; i++) {
BVHTreeRayHit hit_tree = {0};
hit_tree.index = -1;
- hit_tree.dist = FLT_MAX;
+ hit_tree.dist = PHI_MAX;
normalize_v3(ray_dirs[i]);
BLI_bvhtree_ray_cast(tree_data->tree,
@@ -1652,14 +1486,13 @@ static void update_mesh_distances(int index,
tree_data->raycast_callback,
tree_data);
- /* Ray did not hit mesh. Current point definitely not inside mesh. Inside mesh all rays have to
- * hit. */
+ /* Ray did not hit mesh.
+ * Current point definitely not inside mesh. Inside mesh as all rays have to hit. */
if (hit_tree.index == -1) {
miss_cnt++;
- continue;
}
- /* Ray and normal are in pointing opposite directions. */
+ /* Ray and normal are pointing in opposite directions. */
if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
dir_cnt++;
}
@@ -1669,7 +1502,8 @@ static void update_mesh_distances(int index,
}
}
- /* Point lies inside mesh. Use negative sign for distance value. */
+ /* Point lies inside mesh. Use negative sign for distance value.
+ * This "if statement" has 2 conditions that can be true for points outside mesh. */
if (!(miss_cnt > 0 || dir_cnt == ray_cnt)) {
min_dist = (-1.0f) * fabsf(min_dist);
}
@@ -1677,45 +1511,13 @@ static void update_mesh_distances(int index,
/* Update global distance array but ensure that older entries are not overridden. */
mesh_distances[index] = MIN2(mesh_distances[index], min_dist);
- /* Second pass: Use nearest neighbor search on mesh surface. */
- BVHTreeNearest nearest = {0};
- nearest.index = -1;
- nearest.dist_sq = 5;
-
- if (BLI_bvhtree_find_nearest(
- tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
- float ray[3] = {0};
- sub_v3_v3v3(ray, nearest.co, ray_start);
- min_dist = len_v3(ray);
- // CLAMP(min_dist, 0.5, min_dist);
-
- BVHTreeRayHit hit_tree = {0};
- hit_tree.index = -1;
- hit_tree.dist = FLT_MAX;
-
- normalize_v3(ray);
- BLI_bvhtree_ray_cast(
- tree_data->tree, ray_start, ray, 0.0f, &hit_tree, tree_data->raycast_callback, tree_data);
-
- /* Only proceed if casted ray hit the mesh surface. */
- if (hit_tree.index != -1) {
-
- /* Ray and normal are in pointing same directions: Point must lie inside mesh. */
- if (dot_v3v3(ray, hit_tree.no) > 0) {
- min_dist = (-1.0f) * fabsf(min_dist);
- }
-
- /* Update distance value with more accurate one from this nearest neighbor search.
- * Skip if new value would be outside and current value has inside value already. */
- if (!(min_dist > 0 && mesh_distances[index] <= 0)) {
- mesh_distances[index] = min_dist;
- }
- }
- }
-
+ /* Subtract optional surface thickness value and virtually increase the object size. */
if (surface_thickness) {
mesh_distances[index] -= surface_thickness;
}
+
+ /* Sanity check: Ensure that distances don't explode. */
+ CLAMP(mesh_distances[index], -PHI_MAX, PHI_MAX);
}
static void sample_mesh(FluidFlowSettings *mfs,
@@ -1743,16 +1545,23 @@ static void sample_mesh(FluidFlowSettings *mfs,
BVHTreeNearest nearest = {0};
float volume_factor = 0.0f;
- float sample_str = 0.0f;
+ float emission_strength = 0.0f;
hit.index = -1;
- hit.dist = FLT_MAX;
+ hit.dist = PHI_MAX;
nearest.index = -1;
- nearest.dist_sq = mfs->surface_distance *
- mfs->surface_distance; /* find_nearest uses squared distance */
- /* Check volume collision */
- if (mfs->volume_density) {
+ /* Distance between two opposing vertices in a unit cube.
+ * I.e. the unit cube diagonal or sqrt(3).
+ * This value is our nearest neighbour search distance. */
+ const float surface_distance = 1.732;
+ nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance. */
+
+ bool is_gas_flow = (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE ||
+ mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE);
+
+ /* Emission inside the flow object. */
+ if (is_gas_flow && mfs->volume_density) {
if (BLI_bvhtree_ray_cast(tree_data->tree,
ray_start,
ray_dir,
@@ -1761,14 +1570,13 @@ static void sample_mesh(FluidFlowSettings *mfs,
tree_data->raycast_callback,
tree_data) != -1) {
float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
+ /* If ray and hit face normal are facing same direction hit point is inside a closed mesh. */
if (dot >= 0) {
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two faces */
+ /* Also cast a ray in opposite direction to make sure point is at least surrounded by two
+ * faces. */
negate_v3(ray_dir);
hit.index = -1;
- hit.dist = FLT_MAX;
+ hit.dist = PHI_MAX;
BLI_bvhtree_ray_cast(tree_data->tree,
ray_start,
@@ -1784,48 +1592,36 @@ static void sample_mesh(FluidFlowSettings *mfs,
}
}
- /* find the nearest point on the mesh */
+ /* Find the nearest point on the mesh. */
if (BLI_bvhtree_find_nearest(
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
float weights[3];
int v1, v2, v3, f_index = nearest.index;
float n1[3], n2[3], n3[3], hit_normal[3];
- /* emit from surface based on distance */
- if (mfs->surface_distance) {
- sample_str = sqrtf(nearest.dist_sq) / mfs->surface_distance;
- CLAMP(sample_str, 0.0f, 1.0f);
- sample_str = pow(1.0f - sample_str, 0.5f);
- }
- else {
- sample_str = 0.0f;
- }
-
- /* calculate barycentric weights for nearest point */
+ /* Calculate barycentric weights for nearest point. */
v1 = mloop[mlooptri[f_index].tri[0]].v;
v2 = mloop[mlooptri[f_index].tri[1]].v;
v3 = mloop[mlooptri[f_index].tri[2]].v;
interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
+ /* Initial velocity of flow object. */
if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) {
- /* apply normal directional velocity */
+ /* Apply normal directional velocity. */
if (mfs->vel_normal) {
- /* interpolate vertex normal vectors to get nearest point normal */
+ /* Interpolate vertex normal vectors to get nearest point normal. */
normal_short_to_float_v3(n1, mvert[v1].no);
normal_short_to_float_v3(n2, mvert[v2].no);
normal_short_to_float_v3(n3, mvert[v3].no);
interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
normalize_v3(hit_normal);
- /* apply normal directional and random velocity
- * - TODO: random disabled for now since it doesn't really work well
- * as pressure calc smoothens it out. */
+
+ /* 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;
- /* TODO: for fire emitted from mesh surface we can use
- * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
}
- /* apply object velocity */
+ /* Apply object velocity. */
if (has_velocity && mfs->vel_multi) {
float hit_vel[3];
interp_v3_v3v3v3(
@@ -1843,50 +1639,59 @@ static void sample_mesh(FluidFlowSettings *mfs,
velocity_map[index * 3 + 2] += mfs->vel_coord[2];
}
- /* apply vertex group influence if used */
- if (defgrp_index != -1 && dvert) {
- float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
- defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
- defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
- sample_str *= weight_mask;
- }
-
- /* apply emission texture */
- if ((mfs->flags & FLUID_FLOW_TEXTUREEMIT) && mfs->noise_texture) {
- float tex_co[3] = {0};
- TexResult texres;
+ /* Compute emission strength for smoke flow. */
+ if (is_gas_flow) {
+ /* Emission from surface is based on UI configurable distance value. */
+ if (mfs->surface_distance) {
+ emission_strength = sqrtf(nearest.dist_sq) / mfs->surface_distance;
+ CLAMP(emission_strength, 0.0f, 1.0f);
+ emission_strength = pow(1.0f - emission_strength, 0.5f);
+ }
+ else {
+ emission_strength = 0.0f;
+ }
- if (mfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) {
- tex_co[0] = ((x - flow_center[0]) / base_res[0]) / mfs->texture_size;
- tex_co[1] = ((y - flow_center[1]) / base_res[1]) / mfs->texture_size;
- tex_co[2] = ((z - flow_center[2]) / base_res[2] - mfs->texture_offset) / mfs->texture_size;
+ /* Apply vertex group influence if it is being used. */
+ if (defgrp_index != -1 && dvert) {
+ float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+ defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+ defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+ emission_strength *= weight_mask;
}
- else if (mloopuv) {
- const float *uv[3];
- uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
- uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
- uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
-
- interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
-
- /* map between -1.0f and 1.0f */
- tex_co[0] = tex_co[0] * 2.0f - 1.0f;
- tex_co[1] = tex_co[1] * 2.0f - 1.0f;
- tex_co[2] = mfs->texture_offset;
+
+ /* Apply emission texture. */
+ if ((mfs->flags & FLUID_FLOW_TEXTUREEMIT) && mfs->noise_texture) {
+ float tex_co[3] = {0};
+ TexResult texres;
+
+ if (mfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) {
+ tex_co[0] = ((x - flow_center[0]) / base_res[0]) / mfs->texture_size;
+ tex_co[1] = ((y - flow_center[1]) / base_res[1]) / mfs->texture_size;
+ tex_co[2] = ((z - flow_center[2]) / base_res[2] - mfs->texture_offset) /
+ mfs->texture_size;
+ }
+ else if (mloopuv) {
+ const float *uv[3];
+ uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
+ uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
+ uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
+
+ interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
+
+ /* Map texure coord between -1.0f and 1.0f. */
+ tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+ tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+ tex_co[2] = mfs->texture_offset;
+ }
+ texres.nor = NULL;
+ BKE_texture_get_value(NULL, mfs->noise_texture, tex_co, &texres, false);
+ emission_strength *= texres.tin;
}
- texres.nor = NULL;
- BKE_texture_get_value(NULL, mfs->noise_texture, tex_co, &texres, false);
- sample_str *= texres.tin;
}
}
- /* multiply initial velocity by emitter influence */
- if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) {
- mul_v3_fl(&velocity_map[index * 3], sample_str);
- }
-
- /* apply final influence based on volume factor */
- influence_map[index] = MAX2(volume_factor, sample_str);
+ /* Apply final influence value but also consider volume initialization factor. */
+ influence_map[index] = MAX2(volume_factor, emission_strength);
}
typedef struct EmitFromDMData {
@@ -1900,9 +1705,6 @@ typedef struct EmitFromDMData {
int defgrp_index;
BVHTreeFromMesh *tree;
- int hires_multiplier;
- float hr;
-
EmissionMap *em;
bool has_velocity;
float *vert_vel;
@@ -1917,23 +1719,17 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
{
EmitFromDMData *data = userdata;
EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
for (int x = data->min[0]; x < data->max[0]; x++) {
for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 ||
- !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = manta_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* Emission for smoke and fire. Result in em->influence. Also, calculate invels */
+ const int index = manta_get_index(
+ x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
+ const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f};
+
+ /* Compute emission only for flow objects that produce fluid (i.e. skip outflow objects).
+ * Result in em->influence. Also computes initial velocities. Result in em->velocity. */
+ if ((data->mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) ||
+ (data->mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW)) {
sample_mesh(data->mfs,
data->mvert,
data->mloop,
@@ -1950,59 +1746,18 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
data->has_velocity,
data->defgrp_index,
data->dvert,
- (float)lx,
- (float)ly,
- (float)lz);
-
- /* Calculate levelset from meshes. Result in em->distances */
- update_mesh_distances(index,
- em->distances,
- data->tree,
- ray_start,
- data->mfs->surface_distance,
- data->mfs->flags & FLUID_FLOW_USE_PLANE_INIT);
+ (float)x,
+ (float)y,
+ (float)z);
}
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = manta_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {
- lx + 0.5f * data->hr,
- ly + 0.5f * data->hr,
- lz + 0.5f * data->hr,
- };
-
- /* Emission for smoke and fire high. Result in em->influence_high */
- if (data->mfs->type == FLUID_FLOW_TYPE_SMOKE || data->mfs->type == FLUID_FLOW_TYPE_FIRE ||
- data->mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) {
- sample_mesh(data->mfs,
- data->mvert,
- data->mloop,
- data->mlooptri,
- data->mloopuv,
- em->influence_high,
- NULL,
- index,
- data->mds->base_res,
- data->flow_center,
- data->tree,
- ray_start,
- data->vert_vel,
- data->has_velocity,
- data->defgrp_index,
- data->dvert,
- /* x,y,z needs to be always lowres */
- lx,
- ly,
- lz);
- }
- }
+ /* Calculate levelset values from meshes. Result in em->distances. */
+ update_mesh_distances(index,
+ em->distances,
+ data->tree,
+ ray_start,
+ data->mfs->surface_distance,
+ data->mfs->flags & FLUID_FLOW_USE_PLANE_INIT);
}
}
}
@@ -2026,11 +1781,9 @@ static void emit_from_mesh(
int defgrp_index = mfs->vgroup_density - 1;
float flow_center[3] = {0};
int min[3], max[3], res[3];
- int hires_multiplier = 1;
- /* copy mesh for thread safety because we modify it,
- * main issue is its VertArray being modified, then replaced and freed
- */
+ /* Copy mesh for thread safety as we modify it.
+ * Main issue is its VertArray being modified, then replaced and freed. */
me = BKE_mesh_copy_for_eval(mfs->mesh, true);
/* Duplicate vertices to modify. */
@@ -2062,23 +1815,22 @@ static void emit_from_mesh(
}
}
- /* Transform mesh vertices to
- * domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups */
for (i = 0; i < numverts; i++) {
float n[3];
- /* vert pos */
+ /* Vertex position. */
mul_m4_v3(flow_ob->obmat, mvert[i].co);
manta_pos_to_cell(mds, mvert[i].co);
- /* vert normal */
+ /* Vertex normal. */
normal_short_to_float_v3(n, mvert[i].no);
mul_mat3_m4_v3(flow_ob->obmat, n);
mul_mat3_m4_v3(mds->imat, n);
normalize_v3(n);
normal_float_to_short_v3(mvert[i].no, n);
- /* vert velocity */
+ /* Vertex velocity. */
if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
float co[3];
add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift);
@@ -2089,31 +1841,26 @@ static void emit_from_mesh(
copy_v3_v3(&mfs->verts_old[i * 3], co);
}
- /* calculate emission map bounds */
+ /* Calculate emission map bounds. */
em_boundInsert(em, mvert[i].co);
}
mul_m4_v3(flow_ob->obmat, flow_center);
manta_pos_to_cell(mds, flow_center);
- /* check need for high resolution map */
- if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = mds->noise_scale;
- }
-
- /* set emission map */
- clamp_bounds_in_domain(
- mds, em->min, em->max, NULL, NULL, (int)ceil(mfs->surface_distance), dt);
- em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier);
+ /* Set emission map.
+ * Use 3 cell diagonals as margin (3 * 1.732 = 5.196). */
+ int bounds_margin = (int)ceil(5.196);
+ clamp_bounds_in_domain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt);
+ em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY);
- /* setup loop bounds */
+ /* Setup loop bounds. */
for (i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
+ min[i] = em->min[i];
+ max[i] = em->max[i];
+ res[i] = em->res[i];
}
if (BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
- const float hr = 1.0f / ((float)hires_multiplier);
EmitFromDMData data = {
.mds = mds,
@@ -2125,8 +1872,6 @@ static void emit_from_mesh(
.dvert = dvert,
.defgrp_index = defgrp_index,
.tree = &tree_data,
- .hires_multiplier = hires_multiplier,
- .hr = hr,
.em = em,
.has_velocity = has_velocity,
.vert_vel = vert_vel,
@@ -2141,7 +1886,7 @@ static void emit_from_mesh(
settings.min_iter_per_thread = 2;
BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
}
- /* free bvh tree */
+ /* Free bvh tree. */
free_bvhtree_from_mesh(&tree_data);
if (vert_vel) {
@@ -2457,60 +2202,55 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
float *phi_in,
float *emission_in)
{
- /* add inflow */
+ /* Set levelset value for liquid inflow.
+ * Ensure that distance value is "joined" into the levelset. */
if (phi_in) {
- phi_in[index] = distance_value;
+ phi_in[index] = MIN2(distance_value, phi_in[index]);
}
- /* save emission value for manta inflow */
+ /* Set emission value for smoke inflow.
+ * Ensure that emission value is "maximised". */
if (emission_in) {
- emission_in[index] = emission_value;
+ emission_in[index] = MAX2(emission_value, emission_in[index]);
}
- /* add smoke inflow */
+ /* Set inflow for smoke from here on. */
int absolute_flow = (mfs->flags & FLUID_FLOW_ABSOLUTE);
float dens_old = (density) ? density[index] : 0.0;
// float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
float dens_flow = (mfs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * mfs->density;
float fuel_flow = (fuel) ? emission_value * mfs->fuel_amount : 0.0f;
- /* add heat */
+ /* Set heat inflow. */
if (heat && heat_in) {
if (emission_value > 0.0f) {
heat_in[index] = ADD_IF_LOWER(heat[index], mfs->temperature);
- /* Scale inflow by dt/frame-length.
- * This is to ensure that adaptive steps don't apply too much emission. */
- }
- else {
- heat_in[index] = heat[index];
}
}
- /* set density and fuel - absolute mode */
+ /* Set density and fuel - absolute mode. */
if (absolute_flow) {
if (density && density_in) {
- density_in[index] = density[index];
if (mfs->type != FLUID_FLOW_TYPE_FIRE && dens_flow > density[index]) {
- density_in[index] = dens_flow;
+ /* Use MAX2 to preserve values from other emitters at this cell. */
+ density_in[index] = MAX2(dens_flow, density_in[index]);
}
}
if (fuel && fuel_in) {
- fuel_in[index] = fuel[index];
if (mfs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow && fuel_flow > fuel[index]) {
- fuel_in[index] = fuel_flow;
+ /* Use MAX2 to preserve values from other emitters at this cell. */
+ fuel_in[index] = MAX2(fuel_flow, fuel_in[index]);
}
}
}
- /* set density and fuel - additive mode */
+ /* Set density and fuel - additive mode. */
else {
if (density && density_in) {
- density_in[index] = density[index];
if (mfs->type != FLUID_FLOW_TYPE_FIRE) {
density_in[index] += dens_flow;
CLAMP(density_in[index], 0.0f, 1.0f);
}
}
if (fuel && fuel_in) {
- fuel_in[index] = fuel[index];
if (mfs->type != FLUID_FLOW_TYPE_SMOKE && mfs->fuel_amount) {
fuel_in[index] += fuel_flow;
CLAMP(fuel_in[index], 0.0f, 10.0f);
@@ -2518,12 +2258,8 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
}
}
- /* set color */
+ /* Set color. */
if (color_r && color_r_in) {
- color_r_in[index] = color_r[index];
- color_g_in[index] = color_g[index];
- color_b_in[index] = color_b[index];
-
if (dens_flow) {
float total_dens = density[index] / (dens_old + dens_flow);
color_r_in[index] = (color_r[index] + mfs->color[0] * dens_flow) * total_dens;
@@ -2532,7 +2268,7 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
}
}
- /* set fire reaction coordinate */
+ /* Set fire reaction coordinate. */
if (fuel && fuel_in) {
/* Instead of using 1.0 for all new fuel add slight falloff to reduce flow blocky-ness. */
float value = 1.0f - pow2f(1.0f - emission_value);
@@ -2542,9 +2278,6 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
react_in[index] = value * f + (1.0f - f) * react[index];
CLAMP(react_in[index], 0.0f, value);
}
- else {
- react_in[index] = react[index];
- }
}
}
@@ -2666,37 +2399,49 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
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 all flow related flags and ensure that corresponding grids get initialized. */
update_flowsflags(mds, flowobjs, numflowobj);
- /* init emission maps for each flow */
+ /* Initialize emission maps for each flow. */
emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "manta_flow_maps");
- /* Prepare flow emission maps */
+ /* Prepare flow emission maps. */
for (flow_index = 0; flow_index < numflowobj; flow_index++) {
Object *flowobj = flowobjs[flow_index];
FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
eModifierType_Fluid);
- /* Check for initialized smoke object */
+ /* Check for initialized smoke object. */
if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
FluidFlowSettings *mfs = mmd2->flow;
int subframes = mfs->subframes;
EmissionMap *em = &emaps[flow_index];
+ /* 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) {
+ 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);
- /* Further splitting because of emission subframe: If no subframes present, sample_size is 1
- */
+ /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
float sample_size = 1.0f / (float)(subframes + 1);
- int hires_multiplier = 1;
/* First frame cannot have any subframes because there is (obviously) no previous frame from
- * where subframes could come from */
+ * where subframes could come from. */
if (is_first_frame) {
subframes = 0;
}
@@ -2707,7 +2452,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
/* Emission loop. When not using subframes this will loop only once. */
for (subframe = subframes; subframe >= 0; subframe--) {
- /* Temporary emission map used when subframes are enabled, i.e. at least one subframe */
+ /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
EmissionMap em_temp = {NULL};
/* Set scene time */
@@ -2718,22 +2463,22 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
scene->r.cfra = frame - 1;
}
/* Last frame in this loop (subframe == suframes). Can be real end frame or in between
- * frames (adaptive frame) */
+ * frames (adaptive frame). */
else {
/* Handle adaptive subframe (ie has subframe fraction). Need to set according scene
- * subframe parameter */
+ * 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 */
+ * parameter to 0 and advance current scene frame. */
else {
scene->r.subframe = 0.0f;
scene->r.cfra = frame;
}
}
- /* Sanity check: subframe portion must be between 0 and 1 */
+ /* Sanity check: subframe portion must be between 0 and 1. */
CLAMP(scene->r.subframe, 0.0f, 1.0f);
# ifdef DEBUG_PRINT
/* Debugging: Print subframe information. */
@@ -2748,11 +2493,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
/* Update frame time, this is considering current subframe fraction
* BLI_mutex_lock() called in manta_step(), so safe to update subframe here
* TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph)
- * as subframes don't work with the latter yet */
+ * as subframes don't work with the latter yet. */
BKE_object_modifier_update_subframe(
depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid);
- /* Emission from particles */
+ /* Emission from particles. */
if (mfs->source == FLUID_FLOW_SOURCE_PARTICLES) {
if (subframes) {
emit_from_particles(flowobj, mds, mfs, &em_temp, depsgraph, scene, subframe_dt);
@@ -2760,12 +2505,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
else {
emit_from_particles(flowobj, mds, mfs, em, depsgraph, scene, subframe_dt);
}
-
- if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) {
- hires_multiplier = 1;
- }
}
- /* Emission from mesh */
+ /* Emission from mesh. */
else if (mfs->source == FLUID_FLOW_SOURCE_MESH) {
if (subframes) {
emit_from_mesh(flowobj, mds, mfs, &em_temp, subframe_dt);
@@ -2779,11 +2520,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
}
/* If this we emitted with temp emission map in this loop (subframe emission), we combine
- * the temp map with the original emission map */
+ * the temp map with the original emission map. */
if (subframes) {
- /* Combine emission maps */
- em_combineMaps(
- em, &em_temp, hires_multiplier, !(mfs->flags & FLUID_FLOW_ABSOLUTE), sample_size);
+ /* Combine emission maps. */
+ em_combineMaps(em, &em_temp, !(mfs->flags & FLUID_FLOW_ABSOLUTE), sample_size);
em_freeData(&em_temp);
}
}
@@ -2798,7 +2538,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
dt);
# endif
- /* Adjust domain size if needed. Only do this once for every 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, emaps, numflowobj, dt);
}
@@ -2827,28 +2567,29 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
float *velz_initial = manta_get_in_velocity_z(mds->fluid);
uint z;
- /* Grid reset before writing again */
+ /* Grid reset before writing again. */
for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
if (phi_in) {
- phi_in[z] = FLT_MAX;
+ phi_in[z] = PHI_MAX;
}
if (phiout_in) {
- phiout_in[z] = FLT_MAX;
+ phiout_in[z] = PHI_MAX;
}
+ /* Sync smoke inflow grids with their counterparts (simulation grids). */
if (density_in) {
- density_in[z] = 0.0f;
+ density_in[z] = density[z];
}
if (heat_in) {
- heat_in[z] = 0.0f;
+ heat_in[z] = heat[z];
}
if (color_r_in) {
- color_r_in[z] = 0.0f;
- color_g_in[z] = 0.0f;
- color_b_in[z] = 0.0f;
+ color_r_in[z] = color_r[z];
+ color_g_in[z] = color_b[z];
+ color_b_in[z] = color_g[z];
}
if (fuel_in) {
- fuel_in[z] = 0.0f;
- react_in[z] = 0.0f;
+ fuel_in[z] = fuel[z];
+ react_in[z] = react[z];
}
if (emission_in) {
emission_in[z] = 0.0f;
@@ -2860,13 +2601,13 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
}
}
- /* Apply emission data */
+ /* Apply emission data for every flow object. */
for (flow_index = 0; flow_index < numflowobj; flow_index++) {
Object *flowobj = flowobjs[flow_index];
FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
eModifierType_Fluid);
- // check for initialized flow object
+ /* Check for initialized flow object. */
if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
FluidFlowSettings *mfs = mmd2->flow;
EmissionMap *em = &emaps[flow_index];
@@ -2877,28 +2618,29 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
int gx, gy, gz, ex, ey, ez, dx, dy, dz;
size_t e_index, d_index;
- // loop through every emission map cell
+ /* Loop through every emission map cell. */
for (gx = em->min[0]; gx < em->max[0]; gx++) {
for (gy = em->min[1]; gy < em->max[1]; gy++) {
for (gz = em->min[2]; gz < em->max[2]; gz++) {
- /* get emission map index */
+ /* Compute emission map index. */
ex = gx - em->min[0];
ey = gy - em->min[1];
ez = gz - em->min[2];
e_index = manta_get_index(ex, em->res[0], ey, em->res[1], ez);
- /* get domain index */
+ /* Get domain index. */
dx = gx - mds->res_min[0];
dy = gy - mds->res_min[1];
dz = gz - mds->res_min[2];
d_index = manta_get_index(dx, mds->res[0], dy, mds->res[1], dz);
- /* make sure emission cell is inside the new domain boundary */
+ /* Make sure emission cell is inside the new domain boundary. */
if (dx < 0 || dy < 0 || dz < 0 || dx >= mds->res[0] || dy >= mds->res[1] ||
dz >= mds->res[2]) {
continue;
}
- if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { // outflow
+ /* Delete fluid in outflow regions. */
+ if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) {
apply_outflow_fields(d_index,
distance_map[e_index],
density_in,
@@ -2910,10 +2652,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
color_b_in,
phiout_in);
}
- else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && mmd2->time > 2) {
+ /* Do not apply inflow after the first frame when in geometry mode. */
+ else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && !is_first_frame) {
apply_inflow_fields(mfs,
0.0f,
- FLT_MAX,
+ PHI_MAX,
d_index,
density_in,
density,
@@ -2932,8 +2675,9 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
phi_in,
emission_in);
}
+ /* Main inflow application. */
else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW ||
- mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) { // inflow
+ mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) {
/* only apply inflow if enabled */
if (mfs->flags & FLUID_FLOW_USE_INFLOW) {
apply_inflow_fields(mfs,
@@ -2956,7 +2700,6 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
color_b,
phi_in,
emission_in);
- /* initial velocity */
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];
@@ -2964,14 +2707,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
}
}
}
- } // low res loop
+ }
}
- }
-
- // free emission maps
+ } /* End of flow emission map loop. */
em_freeData(em);
-
- } // end emission
+ } /* End of flow object loop. */
}
BKE_collision_objects_free(flowobjs);
@@ -3161,7 +2901,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj
// if reading raw data directly from manta, normalize now, otherwise omit this, ie when reading
// from files
- {
+ if (!manta_liquid_mesh_from_file(mds->fluid)) {
// normalize to unit cube around 0
mverts->co[0] -= ((float)mds->res[0] * mds->mesh_scale) * 0.5f;
mverts->co[1] -= ((float)mds->res[1] * mds->mesh_scale) * 0.5f;
@@ -3715,12 +3455,14 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Read mesh cache. */
if (with_liquid && with_mesh) {
- has_mesh = manta_read_mesh(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) {
- has_particles = manta_read_particles(mds->fluid, mmd, particles_frame);
+ /* Update particle data from file is faster than via Python (manta_read_particles()). */
+ has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame);
}
/* Read guide cache. */
@@ -3758,12 +3500,23 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
/* Read data cache only */
else {
- /* Read config and realloc fluid object if needed. */
- if (manta_read_config(mds->fluid, mmd, data_frame) && manta_needs_realloc(mds->fluid, mmd)) {
- BKE_fluid_reallocate_fluid(mds, mds->res, 1);
+ 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)) {
+ BKE_fluid_reallocate_fluid(mds, mds->res, 1);
+ }
+ /* Read data cache */
+ has_data = manta_read_data(mds->fluid, mmd, data_frame);
+ }
+ if (with_liquid) {
+ if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) {
+ has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame);
+ }
+ else {
+ has_data = manta_read_data(mds->fluid, mmd, data_frame);
+ }
}
- /* Read data cache */
- has_data = manta_read_data(mds->fluid, mmd, data_frame);
}
}
@@ -3857,15 +3610,47 @@ struct Mesh *BKE_fluid_modifier_do(
BLI_rw_mutex_unlock(mmd->domain->fluid_mutex);
}
+ /* Optimization: Do not update viewport during bakes (except in replay mode)
+ * Reason: UI is locked and updated liquid / smoke geometry is not visible anyways. */
+ bool needs_viewport_update = false;
+ if (mmd->domain) {
+ FluidDomainSettings *mds = mmd->domain;
+
+ /* Always update viewport in cache replay mode. */
+ if (mds->cache_type == FLUID_DOMAIN_CACHE_REPLAY ||
+ mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ needs_viewport_update = true;
+ }
+ /* In other cache modes, only update the viewport when no bake is going on. */
+ else {
+ bool with_mesh;
+ with_mesh = mds->flags & FLUID_DOMAIN_USE_MESH;
+ 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;
+
+ if (with_mesh && !baking_data && !baking_noise && !baking_mesh && !baking_particles &&
+ !baking_guide) {
+ needs_viewport_update = true;
+ }
+ }
+ }
+
Mesh *result = NULL;
if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) {
- /* Return generated geometry depending on domain type. */
- if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
- result = create_liquid_geometry(mmd->domain, me, ob);
- }
- if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
- result = create_smoke_geometry(mmd->domain, me, ob);
+ if (needs_viewport_update) {
+ /* Return generated geometry depending on domain type. */
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ result = create_liquid_geometry(mmd->domain, me, ob);
+ }
+ if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
+ result = create_smoke_geometry(mmd->domain, me, ob);
+ }
}
+
/* Clear flag outside of locked block (above). */
mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
@@ -4190,7 +3975,7 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
part->type = psys_type;
part->totpart = 0;
- part->draw_size = 0.01f; // make fluid particles more subtle in viewport
+ part->draw_size = 0.01f; /* Make fluid particles more subtle in viewport. */
part->draw_col = PART_DRAW_COL_VEL;
psys->part = part;
psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
@@ -4212,7 +3997,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
for (psys = ob->particlesystem.first; psys; psys = next_psys) {
next_psys = psys->next;
- if (psys->part->type & particle_type) {
+ if (psys->part->type == particle_type) {
/* clear modifier */
pmmd = psys_get_modifier(ob, psys);
BLI_remlink(&ob->modifiers, pmmd);
@@ -4319,7 +4104,6 @@ void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, in
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_LEFT, 0);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_TOP, 0);
BKE_fluid_collisionextents_set(settings, FLUID_DOMAIN_BORDER_BOTTOM, 0);
- BKE_fluid_particles_set(settings, FLUID_DOMAIN_PARTICLE_FLIP, 0);
object->dt = OB_SOLID;
}
@@ -4565,7 +4349,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
mmd->domain->particle_number = 2;
mmd->domain->particle_minimum = 8;
mmd->domain->particle_maximum = 16;
- mmd->domain->particle_radius = 1.5f;
+ mmd->domain->particle_radius = 1.0f;
mmd->domain->particle_band_width = 3.0f;
mmd->domain->fractions_threshold = 0.05f;
@@ -4624,9 +4408,9 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
mmd->domain->cache_flag = 0;
mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR;
mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT;
- mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_UNI;
- mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_UNI;
- mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_UNI;
+ mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_OPENVDB;
+ mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_OPENVDB;
+ mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_OPENVDB;
modifier_path_init(mmd->domain->cache_directory,
sizeof(mmd->domain->cache_directory),
FLUID_DOMAIN_DIR_DEFAULT);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index f72bb4b4cd4..8eb5cca1ad0 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -494,7 +494,7 @@ bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, s
gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
/* initialize triangle memory to dummy data */
- gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->triangles = NULL;
gps->flag |= GP_STROKE_RECALC_GEOMETRY;
gps->tot_triangles = 0;
@@ -939,9 +939,15 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M
gpl->actframe = gpf;
}
else {
- /* unresolved errogenous situation! */
- CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame");
- /* gpl->actframe should still be NULL */
+ /* If delete first frame, need to find one. */
+ if (gpl->frames.first != NULL) {
+ gpl->actframe = gpl->frames.first;
+ }
+ else {
+ /* unresolved errogenous situation! */
+ CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame");
+ /* gpl->actframe should still be NULL */
+ }
}
}
else {
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index fe087256d25..bc0c54ed96e 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -862,6 +862,14 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ /* Clear any previous evaluated data. */
+ if (ob->runtime.gpencil_tot_layers > 0) {
+ for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) {
+ bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i];
+ BKE_gpencil_free_frame_runtime_data(gpf_eval);
+ }
+ }
+
/* Create array of evaluated frames equal to number of layers. */
ob->runtime.gpencil_tot_layers = BLI_listbase_count(&gpd->layers);
CLAMP_MIN(ob->runtime.gpencil_tot_layers, 1);
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 1125047be32..e3b27236616 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -461,6 +461,21 @@ static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
return newp;
}
+void IDP_AssignID(IDProperty *prop, ID *id, const int flag)
+{
+ BLI_assert(prop->type == IDP_ID);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && IDP_Id(prop) != NULL) {
+ id_us_min(IDP_Id(prop));
+ }
+
+ prop->data.pointer = id;
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(IDP_Id(prop));
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 6d6e5166e1c..be354b04157 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -441,10 +441,9 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s
BLI_listbase_clear(&ima_dst->anims);
BLI_duplicatelist(&ima_dst->tiles, &ima_src->tiles);
- LISTBASE_FOREACH (ImageTile *, tile, &ima_dst->tiles) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- tile->gputexture[i] = NULL;
- }
+
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ ima_dst->gputexture[i] = NULL;
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
@@ -510,11 +509,9 @@ bool BKE_image_scale(Image *image, int width, int height)
bool BKE_image_has_opengl_texture(Image *ima)
{
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (tile->gputexture[i] != NULL) {
- return true;
- }
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (ima->gputexture[i] != NULL) {
+ return true;
}
}
return false;
@@ -1348,6 +1345,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
/* bw */
switch (imtype) {
+ case R_IMF_IMTYPE_BMP:
case R_IMF_IMTYPE_PNG:
case R_IMF_IMTYPE_JPEG90:
case R_IMF_IMTYPE_TARGA:
@@ -3293,9 +3291,16 @@ void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
static void image_free_tile(Image *ima, ImageTile *tile)
{
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (tile->gputexture[i] != NULL) {
- GPU_texture_free(tile->gputexture[i]);
- tile->gputexture[i] = NULL;
+ /* Only two textures depends on all tiles, so if this is a secondary tile we can keep the other
+ * two. */
+ if (tile != ima->tiles.first &&
+ !(ELEM(i, TEXTARGET_TEXTURE_2D_ARRAY, TEXTARGET_TEXTURE_TILE_MAPPING))) {
+ continue;
+ }
+
+ if (ima->gputexture[i] != NULL) {
+ GPU_texture_free(ima->gputexture[i]);
+ ima->gputexture[i] = NULL;
}
}
@@ -3560,6 +3565,16 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
BLI_strncpy(tile->label, label, sizeof(tile->label));
}
+ /* Reallocate GPU tile array. */
+ if (ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY]);
+ ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY] = NULL;
+ }
+ if (ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING] != NULL) {
+ GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING]);
+ ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING] = NULL;
+ }
+
return tile;
}
@@ -3877,7 +3892,12 @@ static void image_initialize_after_load(Image *ima, ImageUser *iuser, ImBuf *UNU
BKE_image_tag_time(ima);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- tile->ok = IMA_OK_LOADED;
+ /* Images should never get loaded if the corresponding tile does not exist,
+ * but we should at least not crash if it happens due to a bug elsewhere. */
+ BLI_assert(tile != NULL);
+ if (tile != NULL) {
+ tile->ok = IMA_OK_LOADED;
+ }
}
static int imbuf_alpha_flags_for_image(Image *ima)
@@ -4750,14 +4770,14 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
return false;
}
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
-
if (iuser) {
if (iuser->ok == 0) {
return false;
}
}
- else if (tile == NULL) {
+
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+ if (tile == NULL) {
return false;
}
else if (tile->ok == 0) {
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index bda1cac80e4..12a90906d1f 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -340,6 +340,23 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas
FOREACH_FINALIZE_VOID;
}
+/* 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)
+{
+ 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);
+ }
+ for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ FOREACH_CALLBACK_INVOKE(data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_ID_as_subdata_link(ID **id_pp,
LibraryIDLinkCallback callback,
void *user_data,
@@ -484,14 +501,7 @@ static void library_foreach_ID_link(Main *bmain,
SEQ_END;
}
- for (CollectionObject *cob = scene->master_collection->gobject.first; cob;
- cob = cob->next) {
- CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
- }
- for (CollectionChild *child = scene->master_collection->children.first; child;
- child = child->next) {
- CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
- }
+ library_foreach_collection(&data, scene->master_collection);
if (scene->master_collection->lanpr) {
CALLBACK_INVOKE(scene->master_collection->lanpr->target, IDWALK_CB_USER);
@@ -804,15 +814,7 @@ static void library_foreach_ID_link(Main *bmain,
case ID_GR: {
Collection *collection = (Collection *)id;
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
- }
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- CALLBACK_INVOKE(child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
- }
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
- CALLBACK_INVOKE(parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK);
- }
+ library_foreach_collection(&data, collection);
break;
}
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 06f1ee5050b..3cba3aa9611 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -41,6 +41,30 @@ void BKE_lightprobe_init(LightProbe *probe)
MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id);
}
+void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type)
+{
+ probe->type = lightprobe_type;
+
+ switch (probe->type) {
+ case LIGHTPROBE_TYPE_GRID:
+ probe->distinf = 0.3f;
+ probe->falloff = 1.0f;
+ probe->clipsta = 0.01f;
+ break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ probe->distinf = 0.1f;
+ probe->falloff = 0.5f;
+ probe->clipsta = 0.001f;
+ break;
+ case LIGHTPROBE_TYPE_CUBE:
+ probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID;
+ break;
+ default:
+ BLI_assert(!"LightProbe type not configured.");
+ break;
+ }
+}
+
void *BKE_lightprobe_add(Main *bmain, const char *name)
{
LightProbe *probe;
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 2ade368284c..fba84aaad42 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -522,7 +522,6 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob,
Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
{
- Curve *cu = ob->data;
Mesh *mesh;
MVert *allvert;
MEdge *alledge;
@@ -530,7 +529,6 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
MPoly *allpoly;
MLoopUV *alluv = NULL;
int totvert, totedge, totloop, totpoly;
- bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
if (BKE_mesh_nurbs_displist_to_mdata(ob,
dispbase,
@@ -540,7 +538,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
&totedge,
&allloop,
&allpoly,
- (use_orco_uv) ? &alluv : NULL,
+ &alluv,
&totloop,
&totpoly) != 0) {
/* Error initializing mdata. This often happens when curve is empty */
@@ -580,12 +578,8 @@ Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
}
/* this may fail replacing ob->data, be sure to check ob->type */
-void BKE_mesh_from_nurbs_displist(Main *bmain,
- Object *ob,
- ListBase *dispbase,
- const bool use_orco_uv,
- const char *obdata_name,
- bool temporary)
+void BKE_mesh_from_nurbs_displist(
+ Main *bmain, Object *ob, ListBase *dispbase, const char *obdata_name, bool temporary)
{
Object *ob1;
Mesh *me_eval = ob->runtime.mesh_eval;
@@ -609,7 +603,7 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
&totedge,
&allloop,
&allpoly,
- (use_orco_uv) ? &alluv : NULL,
+ &alluv,
&totloop,
&totpoly) != 0) {
/* Error initializing */
@@ -706,14 +700,13 @@ void BKE_mesh_from_nurbs_displist(Main *bmain,
void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
{
Curve *cu = (Curve *)ob->data;
- bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
ListBase disp = {NULL, NULL};
if (ob->runtime.curve_cache) {
disp = ob->runtime.curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
+ BKE_mesh_from_nurbs_displist(bmain, ob, &disp, cu->id.name, false);
}
typedef struct EdgeLink {
@@ -1023,8 +1016,6 @@ static void curve_to_mesh_eval_ensure(Object *object)
static Mesh *mesh_new_from_curve_type_object(Object *object)
{
Curve *curve = object->data;
- const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0;
-
Object *temp_object = object_for_curve_to_mesh_create(object);
Curve *temp_curve = (Curve *)temp_object->data;
@@ -1039,12 +1030,8 @@ static Mesh *mesh_new_from_curve_type_object(Object *object)
temp_curve->editnurb = NULL;
/* Convert to mesh. */
- BKE_mesh_from_nurbs_displist(NULL,
- temp_object,
- &temp_object->runtime.curve_cache->disp,
- uv_from_orco,
- curve->id.name + 2,
- true);
+ BKE_mesh_from_nurbs_displist(
+ NULL, temp_object, &temp_object->runtime.curve_cache->disp, curve->id.name + 2, true);
/* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did
* not have any segments or otherwise would have generated an empty mesh. */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index fa03aec3e08..4aa5bfa04ab 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -866,7 +866,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
tot_elem = mesh->totedge;
break;
case ME_FSEL:
- tot_elem = mesh->totface;
+ tot_elem = mesh->totpoly;
break;
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index a539aa45cf6..23fa8dd60d5 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -1289,13 +1289,9 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
int i, j, numGrids, highGridSize, lowGridSize;
const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
- /* create subsurf DM from original mesh at high level */
- if (ob->derivedDeform) {
- cddm = CDDM_copy(ob->derivedDeform);
- }
- else {
- cddm = CDDM_from_mesh(me);
- }
+ /* Create subsurf DM from original mesh at high level. */
+ /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */
+ cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
highdm = subsurf_dm_create_local(scene,
@@ -1369,12 +1365,8 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
DerivedMesh *cddm, *subdm;
const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
- if (ob->derivedDeform) {
- cddm = CDDM_copy(ob->derivedDeform);
- }
- else {
- cddm = CDDM_from_mesh(me);
- }
+ /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */
+ cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
subdm = subsurf_dm_create_local(scene,
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 09581debd99..7aa8837d139 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1499,6 +1499,10 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
fcu->bezt->vec[1][0] = strip->start;
fcu->bezt->vec[1][1] = strip->influence;
+
+ /* Respect User Preferences for default interpolation and handles. */
+ fcu->bezt->h1 = fcu->bezt->h2 = U.keyhandles_new;
+ fcu->bezt->ipo = U.ipo_new;
}
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index be28ca26459..75e0d044c7c 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1089,7 +1089,11 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
/* keep socket listorder identical, for copying links */
/* ntree is the target tree */
-bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag)
+/* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */
+bNode *BKE_node_copy_ex(bNodeTree *ntree,
+ const bNode *node_src,
+ const int flag,
+ const bool unique_name)
{
bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node");
bNodeSocket *sock_dst, *sock_src;
@@ -1098,7 +1102,9 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag)
*node_dst = *node_src;
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
- nodeUniqueName(ntree, node_dst);
+ if (unique_name) {
+ nodeUniqueName(ntree, node_dst);
+ }
BLI_addtail(&ntree->nodes, node_dst);
}
@@ -1186,7 +1192,7 @@ static void node_set_new_pointers(bNode *node_src, bNode *new_node)
bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag)
{
- bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag);
+ bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true);
node_set_new_pointers(node_src, new_node);
return new_node;
}
@@ -1516,7 +1522,7 @@ void BKE_node_tree_copy_data(Main *UNUSED(bmain),
GHash *new_pointers = BLI_ghash_ptr_new("BKE_node_tree_copy_data");
for (const bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) {
- bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata);
+ 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. */
bNodeSocket *new_input_sock = new_node->inputs.first;
@@ -1595,7 +1601,7 @@ void BKE_node_tree_copy_data(Main *UNUSED(bmain),
bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
bNodeTree *ntree_copy;
- const int flag = do_id_user ? LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN : 0;
+ const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN;
BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, flag);
return ntree_copy;
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 10553e73d8d..90205286a72 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -430,7 +430,6 @@ void BKE_object_free_derived_caches(Object *ob)
MEM_SAFE_FREE(ob->runtime.bb);
object_update_from_subsurf_ccg(ob);
- BKE_object_free_derived_mesh_caches(ob);
/* Restore initial pointer. */
if (ob->runtime.mesh_orig != NULL) {
@@ -457,20 +456,6 @@ void BKE_object_free_derived_caches(Object *ob)
DRW_gpencil_freecache(ob);
}
-void BKE_object_free_derived_mesh_caches(struct Object *ob)
-{
- if (ob->derivedFinal) {
- ob->derivedFinal->needsFree = 1;
- ob->derivedFinal->release(ob->derivedFinal);
- ob->derivedFinal = NULL;
- }
- if (ob->derivedDeform) {
- ob->derivedDeform->needsFree = 1;
- ob->derivedDeform->release(ob->derivedDeform);
- ob->derivedDeform = NULL;
- }
-}
-
void BKE_object_free_caches(Object *object)
{
ModifierData *md;
@@ -804,6 +789,8 @@ static const char *get_obdata_defname(int type)
return DATA_("Empty");
case OB_GPENCIL:
return DATA_("GPencil");
+ case OB_LIGHTPROBE:
+ return DATA_("LightProbe");
default:
CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
return DATA_("Empty");
@@ -1323,7 +1310,7 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
{
copy_v3_v3(ob_tar->loc, ob_src->loc);
copy_v3_v3(ob_tar->rot, ob_src->rot);
- copy_v3_v3(ob_tar->quat, ob_src->quat);
+ copy_v4_v4(ob_tar->quat, ob_src->quat);
copy_v3_v3(ob_tar->rotAxis, ob_src->rotAxis);
ob_tar->rotAngle = ob_src->rotAngle;
ob_tar->rotmode = ob_src->rotmode;
@@ -1425,9 +1412,6 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata);
- ob_dst->derivedDeform = NULL;
- ob_dst->derivedFinal = NULL;
-
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
@@ -2330,40 +2314,38 @@ static void give_parvert(Object *par, int nr, float vec[3])
int count = 0;
const int numVerts = me_eval->totvert;
- if (nr < numVerts) {
- if (em && me_eval->runtime.is_original) {
- if (em->bm->elem_table_dirty & BM_VERT) {
+ if (em && me_eval->runtime.is_original) {
+ if (em->bm->elem_table_dirty & BM_VERT) {
#ifdef VPARENT_THREADING_HACK
- BLI_mutex_lock(&vparent_lock);
- if (em->bm->elem_table_dirty & BM_VERT) {
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- }
- BLI_mutex_unlock(&vparent_lock);
-#else
- BLI_assert(!"Not safe for threading");
+ BLI_mutex_lock(&vparent_lock);
+ if (em->bm->elem_table_dirty & BM_VERT) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
-#endif
}
+ BLI_mutex_unlock(&vparent_lock);
+#else
+ BLI_assert(!"Not safe for threading");
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+#endif
}
+ }
- if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) &&
- !(em && me_eval->runtime.is_original)) {
- const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
- /* Get the average of all verts with (original index == nr). */
- for (int i = 0; i < numVerts; i++) {
- if (index[i] == nr) {
- add_v3_v3(vec, me_eval->mvert[i].co);
- count++;
- }
- }
- }
- else {
- if (nr < numVerts) {
- add_v3_v3(vec, me_eval->mvert[nr].co);
+ if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) &&
+ !(em && me_eval->runtime.is_original)) {
+ const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
+ /* Get the average of all verts with (original index == nr). */
+ for (int i = 0; i < numVerts; i++) {
+ if (index[i] == nr) {
+ add_v3_v3(vec, me_eval->mvert[i].co);
count++;
}
}
}
+ else {
+ if (nr < numVerts) {
+ add_v3_v3(vec, me_eval->mvert[nr].co);
+ count++;
+ }
+ }
if (count == 0) {
/* keep as 0, 0, 0 */
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 21ca5e6d6a6..366fd0950fa 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -163,9 +163,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
#else
BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_mesh : NULL;
- if (em && em->ob != ob) {
- em = NULL;
- }
#endif
CustomData_MeshMasks cddata_masks = scene->customdata_mask;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 584f1ab1b0c..46c2f735761 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -79,7 +79,7 @@ const char PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255};
const char PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255};
const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
-static eOverlayControlFlags overlay_flags = 0;
+static ePaintOverlayControlFlags overlay_flags = 0;
void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex)
{
@@ -120,7 +120,7 @@ void BKE_paint_invalidate_overlay_all(void)
PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY | PAINT_OVERLAY_INVALID_CURVE);
}
-eOverlayControlFlags BKE_paint_get_overlay_flags(void)
+ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void)
{
return overlay_flags;
}
@@ -143,7 +143,7 @@ void BKE_paint_set_overlay_override(eOverlayFlags flags)
}
}
-void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag)
+void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag)
{
overlay_flags &= ~(flag);
}
@@ -1019,15 +1019,12 @@ static void sculptsession_free_pbvh(Object *object)
ss->pbvh = NULL;
}
- if (ss->pmap) {
- MEM_freeN(ss->pmap);
- ss->pmap = NULL;
- }
+ MEM_SAFE_FREE(ss->pmap);
- if (ss->pmap_mem) {
- MEM_freeN(ss->pmap_mem);
- ss->pmap_mem = NULL;
- }
+ MEM_SAFE_FREE(ss->pmap_mem);
+
+ MEM_SAFE_FREE(ss->preview_vert_index_list);
+ ss->preview_vert_index_count = 0;
}
void BKE_sculptsession_bm_to_me_for_render(Object *object)
@@ -1096,6 +1093,14 @@ void BKE_sculptsession_free(Object *ob)
MEM_freeN(ss->preview_vert_index_list);
}
+ if (ss->pose_ik_chain_preview) {
+ for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
+ MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments[i].weights);
+ }
+ MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments);
+ MEM_SAFE_FREE(ss->pose_ik_chain_preview);
+ }
+
BKE_sculptsession_free_vwpaint_data(ob->sculpt);
MEM_freeN(ss);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index ded38cf562f..97fcef4fd27 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3246,22 +3246,24 @@ static void psys_cache_edit_paths_iter(void *__restrict iter_data_v,
}
}
else {
+ /* HACK(fclem): Instead of setting the color we pass the select state in the red channel.
+ * This is then picked up in DRW and the gpu shader will do the color interpolation. */
if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- copy_v3_v3(ca->col, iter_data->sel_col);
+ ca->col[0] = 1.0f;
}
else {
keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime);
+ ca->col[0] = 1.0f - keytime;
}
}
else {
if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
+ ca->col[0] = keytime;
}
else {
- copy_v3_v3(ca->col, iter_data->nosel_col);
+ ca->col[0] = 0.0f;
}
}
}
@@ -3565,7 +3567,9 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
psys->totpart = 0;
psys->flag = PSYS_CURRENT;
- psys->cfra = BKE_scene_frame_to_ctime(scene, CFRA + 1);
+ if (scene != NULL) {
+ psys->cfra = BKE_scene_frame_to_ctime(scene, CFRA + 1);
+ }
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -3582,14 +3586,47 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
return;
}
- /* clear all other appearances of this pointer (like on manta flow modifier) */
+ /* Clear particle system in fluid modifier. */
if ((md = modifiers_findByType(ob, eModifierType_Fluid))) {
FluidModifierData *mmd = (FluidModifierData *)md;
+
+ /* Clear particle system pointer in flow settings. */
if ((mmd->type == MOD_FLUID_TYPE_FLOW) && mmd->flow && mmd->flow->psys) {
if (mmd->flow->psys == psys) {
mmd->flow->psys = NULL;
}
}
+ /* Clear particle flag in domain settings when removing particle system manually. */
+ if (mmd->type == MOD_FLUID_TYPE_DOMAIN) {
+ if (psys->part->type == PART_FLUID_FLIP) {
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
+ }
+ if (psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_SPRAYFOAM ||
+ psys->part->type == PART_FLUID_SPRAYBUBBLE ||
+ psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY;
+ }
+ if (psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_SPRAYFOAM ||
+ psys->part->type == PART_FLUID_FOAMBUBBLE ||
+ psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM;
+ }
+ if (psys->part->type == PART_FLUID_BUBBLE || psys->part->type == PART_FLUID_FOAMBUBBLE ||
+ psys->part->type == PART_FLUID_SPRAYBUBBLE ||
+ psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE;
+ }
+ if (psys->part->type == PART_FLUID_TRACER) {
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER;
+ }
+
+ /* Disable combined export if combined particle system was deleted. */
+ if (psys->part->type == PART_FLUID_SPRAYFOAM || psys->part->type == PART_FLUID_SPRAYBUBBLE ||
+ psys->part->type == PART_FLUID_FOAMBUBBLE ||
+ psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ mmd->domain->sndparticle_combined_export = SNDPARTICLE_COMBINED_EXPORT_OFF;
+ }
+ }
}
if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) {
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 34f2aa73817..172940760f9 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -4137,6 +4137,34 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_
}
}
+static bool particles_has_flip(short parttype)
+{
+ return (parttype == PART_FLUID_FLIP);
+}
+
+static bool particles_has_tracer(short parttype)
+{
+ return (parttype == PART_FLUID_TRACER);
+}
+
+static bool particles_has_spray(short parttype)
+{
+ return ((parttype == PART_FLUID_SPRAY) || (parttype == PART_FLUID_SPRAYFOAM) ||
+ (parttype == PART_FLUID_SPRAYFOAMBUBBLE));
+}
+
+static bool particles_has_bubble(short parttype)
+{
+ return ((parttype == PART_FLUID_BUBBLE) || (parttype == PART_FLUID_FOAMBUBBLE) ||
+ (parttype == PART_FLUID_SPRAYFOAMBUBBLE));
+}
+
+static bool particles_has_foam(short parttype)
+{
+ return ((parttype == PART_FLUID_FOAM) || (parttype == PART_FLUID_SPRAYFOAM) ||
+ (parttype == PART_FLUID_SPRAYFOAMBUBBLE));
+}
+
static void particles_fluid_step(ParticleSimulationData *sim,
int cfra,
const bool use_render_params)
@@ -4173,15 +4201,15 @@ static void particles_fluid_step(ParticleSimulationData *sim,
float min[3], max[3], size[3], cell_size_scaled[3], max_size;
/* Sanity check: parts also enabled in fluid domain? */
- if ((part->type == PART_FLUID_FLIP &&
+ if ((particles_has_flip(part->type) &&
(mds->particle_type & FLUID_DOMAIN_PARTICLE_FLIP) == 0) ||
- (part->type == PART_FLUID_SPRAY &&
+ (particles_has_spray(part->type) &&
(mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) == 0) ||
- (part->type == PART_FLUID_BUBBLE &&
+ (particles_has_bubble(part->type) &&
(mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) == 0) ||
- (part->type == PART_FLUID_FOAM &&
+ (particles_has_foam(part->type) &&
(mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) == 0) ||
- (part->type == PART_FLUID_TRACER &&
+ (particles_has_tracer(part->type) &&
(mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) == 0)) {
BLI_snprintf(debugStrBuffer,
sizeof(debugStrBuffer),
@@ -4194,23 +4222,23 @@ static void particles_fluid_step(ParticleSimulationData *sim,
if (part->type == PART_FLUID_FLIP) {
tottypepart = totpart = manta_liquid_get_num_flip_particles(mds->fluid);
}
- if ((part->type == PART_FLUID_SPRAY) || (part->type == PART_FLUID_BUBBLE) ||
- (part->type == PART_FLUID_FOAM) || (part->type == PART_FLUID_TRACER)) {
+ if (particles_has_spray(part->type) || particles_has_bubble(part->type) ||
+ particles_has_foam(part->type) || particles_has_tracer(part->type)) {
totpart = manta_liquid_get_num_snd_particles(mds->fluid);
/* tottypepart is the amount of particles of a snd particle type. */
for (p = 0; p < totpart; p++) {
flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p);
- if ((part->type & PART_FLUID_SPRAY) && (flagActivePart & PARTICLE_TYPE_SPRAY)) {
+ if (particles_has_spray(part->type) && (flagActivePart & PARTICLE_TYPE_SPRAY)) {
tottypepart++;
}
- if ((part->type & PART_FLUID_BUBBLE) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) {
+ if (particles_has_bubble(part->type) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) {
tottypepart++;
}
- if ((part->type & PART_FLUID_FOAM) && (flagActivePart & PARTICLE_TYPE_FOAM)) {
+ if (particles_has_foam(part->type) && (flagActivePart & PARTICLE_TYPE_FOAM)) {
tottypepart++;
}
- if ((part->type & PART_FLUID_TRACER) && (flagActivePart & PARTICLE_TYPE_TRACER)) {
+ if (particles_has_tracer(part->type) && (flagActivePart & PARTICLE_TYPE_TRACER)) {
tottypepart++;
}
}
@@ -4261,8 +4289,8 @@ static void particles_fluid_step(ParticleSimulationData *sim,
velY = manta_liquid_get_flip_particle_velocity_y_at(mds->fluid, p);
velZ = manta_liquid_get_flip_particle_velocity_z_at(mds->fluid, p);
}
- else if ((part->type == PART_FLUID_SPRAY) || (part->type == PART_FLUID_BUBBLE) ||
- (part->type == PART_FLUID_FOAM) || (part->type == PART_FLUID_TRACER)) {
+ else if (particles_has_spray(part->type) || particles_has_bubble(part->type) ||
+ particles_has_foam(part->type) || particles_has_tracer(part->type)) {
flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p);
resX = (float)manta_liquid_get_particle_res_x(mds->fluid);
@@ -4292,16 +4320,16 @@ static void particles_fluid_step(ParticleSimulationData *sim,
/* Type of particle must match current particle system type
* (only important for snd particles). */
- if ((flagActivePart & PARTICLE_TYPE_SPRAY) && (part->type & PART_FLUID_SPRAY) == 0) {
+ if ((flagActivePart & PARTICLE_TYPE_SPRAY) && !particles_has_spray(part->type)) {
continue;
}
- if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && (part->type & PART_FLUID_BUBBLE) == 0) {
+ if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && !particles_has_bubble(part->type)) {
continue;
}
- if ((flagActivePart & PARTICLE_TYPE_FOAM) && (part->type & PART_FLUID_FOAM) == 0) {
+ if ((flagActivePart & PARTICLE_TYPE_FOAM) && !particles_has_foam(part->type)) {
continue;
}
- if ((flagActivePart & PARTICLE_TYPE_TRACER) && (part->type & PART_FLUID_TRACER) == 0) {
+ if ((flagActivePart & PARTICLE_TYPE_TRACER) && !particles_has_tracer(part->type)) {
continue;
}
# if 0
@@ -4844,9 +4872,9 @@ void particle_system_update(struct Depsgraph *depsgraph,
hair_step(&sim, cfra, use_render_params);
}
}
- else if ((part->type == PART_FLUID_FLIP) || (part->type == PART_FLUID_SPRAY) ||
- (part->type == PART_FLUID_BUBBLE) || (part->type == PART_FLUID_FOAM) ||
- (part->type == PART_FLUID_TRACER)) {
+ else if (particles_has_flip(part->type) || particles_has_spray(part->type) ||
+ particles_has_bubble(part->type) || particles_has_foam(part->type) ||
+ particles_has_tracer(part->type)) {
particles_fluid_step(&sim, (int)cfra, use_render_params);
}
else {
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 01612ded396..ec520e188f1 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1120,7 +1120,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_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
{
if (vd.mask && *vd.mask < 1.0f) {
has_unmasked = true;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index bfaea9d438b..75b9f558e90 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -374,6 +374,13 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
sce_dst->preview = NULL;
}
+ BKE_scene_copy_data_eevee(sce_dst, sce_src);
+}
+
+void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src)
+{
+ /* Copy eevee data between scenes. */
+ sce_dst->eevee = sce_src->eevee;
sce_dst->eevee.light_cache = NULL;
sce_dst->eevee.light_cache_info[0] = '\0';
/* TODO Copy the cache. */
@@ -401,9 +408,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
sce_copy->unit = sce->unit;
sce_copy->physics_settings = sce->physics_settings;
sce_copy->audio = sce->audio;
- sce_copy->eevee = sce->eevee;
- sce_copy->eevee.light_cache = NULL;
- sce_copy->eevee.light_cache_info[0] = '\0';
+ BKE_scene_copy_data_eevee(sce_copy, sce);
if (sce->id.properties) {
sce_copy->id.properties = IDP_CopyProperty(sce->id.properties);
@@ -1412,6 +1417,19 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
if (run_callbacks) {
BKE_callback_exec_id_depsgraph(
bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
+
+ /* It is possible that the custom callback modified scene and removed some IDs from the main
+ * database. In this case DEG_ids_clear_recalc() will crash because it iterates over all IDs
+ * which depsgraph was built for.
+ *
+ * The solution is to update relations prior to this call, avoiding access to freed IDs.
+ * Should be safe because relations update is supposed to preserve flags of all IDs which are
+ * still a part of the dependency graph. If an ID is kicked out of the dependency graph it
+ * should also be fine because when/if it's added to another dependency graph it will need to
+ * be tagged for an update anyway.
+ *
+ * If there are no relations changed by the callback this call will do nothing. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
}
/* Inform editors about possible changes. */
DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
@@ -1477,6 +1495,10 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
/* Notify editors and python about recalc. */
if (pass == 0) {
BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
+
+ /* NOTE: Similar to this case in scene_graph_update_tagged(). Need to ensure that
+ * DEG_ids_clear_recalc() doesn't access freed memory of possibly removed ID. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
}
/* Inform editors about possible changes. */
@@ -2253,7 +2275,16 @@ void BKE_scene_cursor_mat3_to_rot(View3DCursor *cursor, const float mat[3][3], b
switch (cursor->rotation_mode) {
case ROT_MODE_QUAT: {
- mat3_normalized_to_quat(cursor->rotation_quaternion, mat);
+ float quat[4];
+ mat3_normalized_to_quat(quat, mat);
+ if (use_compat) {
+ float quat_orig[4];
+ copy_v4_v4(quat_orig, cursor->rotation_quaternion);
+ quat_to_compatible_quat(cursor->rotation_quaternion, quat, quat_orig);
+ }
+ else {
+ copy_v4_v4(cursor->rotation_quaternion, quat);
+ }
break;
}
case ROT_MODE_AXISANGLE: {
@@ -2279,7 +2310,14 @@ void BKE_scene_cursor_quat_to_rot(View3DCursor *cursor, const float quat[4], boo
switch (cursor->rotation_mode) {
case ROT_MODE_QUAT: {
- copy_qt_qt(cursor->rotation_quaternion, quat);
+ if (use_compat) {
+ float quat_orig[4];
+ copy_v4_v4(quat_orig, cursor->rotation_quaternion);
+ quat_to_compatible_quat(cursor->rotation_quaternion, quat, quat_orig);
+ }
+ else {
+ copy_qt_qt(cursor->rotation_quaternion, quat);
+ }
break;
}
case ROT_MODE_AXISANGLE: {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 236fb43e89c..8dfe01ae1fd 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -3888,7 +3888,7 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
int font = blf_mono_font_render;
int line_height;
int y_ofs, x, y;
- float proxy_size_comp;
+ double proxy_size_comp;
if (data->text_blf_id == SEQ_FONT_NOT_LOADED) {
data->text_blf_id = -1;
@@ -3906,15 +3906,11 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
display = IMB_colormanagement_display_get_named(display_device);
/* Compensate text size for preview render size. */
- if (ELEM(
- context->preview_render_size, SEQ_PROXY_RENDER_SIZE_SCENE, SEQ_PROXY_RENDER_SIZE_FULL)) {
- proxy_size_comp = context->scene->r.size / 100.0f;
- }
- else if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_100) {
- proxy_size_comp = 1.0f;
+ if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
+ proxy_size_comp = context->scene->r.size / 100.0;
}
else {
- proxy_size_comp = context->preview_render_size / 100.0f;
+ 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 6dd1c47407f..8c9097e1d4e 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -416,9 +416,7 @@ static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra)
pfjob->stop = false;
pfjob->running = true;
- if (&pfjob->threads) {
- BLI_threadpool_remove(&pfjob->threads, pfjob);
- }
+ BLI_threadpool_remove(&pfjob->threads, pfjob);
BLI_threadpool_insert(&pfjob->threads, pfjob);
return pfjob;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index b05724ca6af..747ce18cada 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -38,6 +38,7 @@
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
#include "BLI_math.h"
#include "BLI_fileops.h"
@@ -1587,35 +1588,32 @@ typedef struct SeqIndexBuildContext {
#define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE)
-static IMB_Proxy_Size seq_rendersize_to_proxysize(int size)
+static IMB_Proxy_Size seq_rendersize_to_proxysize(int render_size)
{
- if (size >= 100) {
- return IMB_PROXY_NONE;
+ switch (render_size) {
+ case SEQ_PROXY_RENDER_SIZE_25:
+ return IMB_PROXY_25;
+ case SEQ_PROXY_RENDER_SIZE_50:
+ return IMB_PROXY_50;
+ case SEQ_PROXY_RENDER_SIZE_75:
+ return IMB_PROXY_75;
+ case SEQ_PROXY_RENDER_SIZE_100:
+ return IMB_PROXY_100;
}
- if (size >= 99) {
- return IMB_PROXY_100;
- }
- if (size >= 75) {
- return IMB_PROXY_75;
- }
- if (size >= 50) {
- return IMB_PROXY_50;
- }
- return IMB_PROXY_25;
+ return IMB_PROXY_NONE;
}
-static double seq_rendersize_to_scale_factor(int size)
+double BKE_sequencer_rendersize_to_scale_factor(int render_size)
{
- if (size >= 99) {
- return 1.0;
- }
- if (size >= 75) {
- return 0.75;
+ switch (render_size) {
+ case SEQ_PROXY_RENDER_SIZE_25:
+ return 0.25;
+ case SEQ_PROXY_RENDER_SIZE_50:
+ return 0.50;
+ case SEQ_PROXY_RENDER_SIZE_75:
+ return 0.75;
}
- if (size >= 50) {
- return 0.50;
- }
- return 0.25;
+ return 1.0;
}
/* the number of files will vary according to the stereo format */
@@ -1773,8 +1771,12 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
}
-static bool seq_proxy_get_fname(
- Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const int view_id)
+static bool seq_proxy_get_fname(Editing *ed,
+ Sequence *seq,
+ int cfra,
+ eSpaceSeq_Proxy_RenderSize render_size,
+ char *name,
+ const int view_id)
{
int frameno;
char dir[PROXY_MAXFILE];
@@ -1868,19 +1870,21 @@ static bool seq_proxy_get_fname(
/* generate a separate proxy directory for each preview size */
+ int proxy_size_number = BKE_sequencer_rendersize_to_scale_factor(render_size) * 100;
+
if (seq->type == SEQ_TYPE_IMAGE) {
BLI_snprintf(name,
PROXY_MAXFILE,
"%s/images/%d/%s_proxy%s",
dir,
- render_size,
+ proxy_size_number,
BKE_sequencer_give_stripelem(seq, cfra)->name,
suffix);
frameno = 1;
}
else {
frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix);
}
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
@@ -1896,7 +1900,6 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
char name[PROXY_MAXFILE];
IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
int size_flags;
- int render_size = context->preview_render_size;
StripProxy *proxy = seq->strip->proxy;
Editing *ed = context->scene->ed;
StripAnim *sanim;
@@ -1905,22 +1908,17 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
return NULL;
}
- /* dirty hack to distinguish 100% render size from PROXY_100 */
- if (render_size == 99) {
- render_size = 100;
- }
-
size_flags = proxy->build_size_flags;
/* only use proxies, if they are enabled (even if present!) */
- if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) {
+ if (psize == IMB_PROXY_NONE || (size_flags & psize) == 0) {
return NULL;
}
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
if (proxy->anim == NULL) {
- if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
+ if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
return NULL;
}
@@ -1939,7 +1937,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
- if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
+ if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
return NULL;
}
@@ -2700,10 +2698,10 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
int sx, sy, dx, dy;
if (is_proxy_image) {
- double f = seq_rendersize_to_scale_factor(context->preview_render_size);
+ double f = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
if (f != 1.0) {
- IMB_scalefastImBuf(ibuf, ibuf->x / f, ibuf->y / f);
+ IMB_scalefastImBuf(ibuf, ibuf->x * f, ibuf->y * f);
}
}
@@ -3151,12 +3149,11 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
(context->scene->r.scemode & R_MULTIVIEW) != 0;
- IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
if ((seq->flag & SEQ_USE_PROXY) == 0) {
- proxy_size = IMB_PROXY_NONE;
+ psize = IMB_PROXY_NONE;
}
-
/* load all the videos */
seq_open_anim_file(context->scene, seq, false);
@@ -3181,10 +3178,10 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
nr + seq->anim_startofs,
seq->strip->proxy ? seq->strip->proxy->tc :
IMB_TC_RECORD_RUN,
- proxy_size);
+ psize);
/* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) {
+ 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 :
@@ -3250,10 +3247,10 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
ibuf = IMB_anim_absolute(sanim->anim,
nr + seq->anim_startofs,
seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
+ psize);
/* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf && proxy_size != IMB_PROXY_NONE) {
+ if (!ibuf && psize != IMB_PROXY_NONE) {
ibuf = IMB_anim_absolute(sanim->anim,
nr + seq->anim_startofs,
seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
@@ -3280,6 +3277,7 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence
ImBuf *ibuf = NULL;
MovieClipUser user;
float tloc[2], tscale, tangle;
+ IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
if (!seq->clip) {
return NULL;
@@ -3292,7 +3290,7 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence
user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- switch (seq_rendersize_to_proxysize(context->preview_render_size)) {
+ switch (psize) {
case IMB_PROXY_NONE:
user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
break;
@@ -3876,7 +3874,8 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
if (ibuf) {
if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
- is_proxy_image = (context->preview_render_size != 100);
+ is_proxy_image = seq_rendersize_to_proxysize(context->preview_render_size) !=
+ IMB_PROXY_NONE;
}
}
}
@@ -4920,7 +4919,10 @@ static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir)
return tot_ofs;
}
-bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, Scene *evil_scene)
+bool BKE_sequence_base_shuffle_time(ListBase *seqbasep,
+ Scene *evil_scene,
+ ListBase *markers,
+ const bool use_sync_markers)
{
/* note: seq->tmp is used to tag strips to move */
@@ -4937,6 +4939,16 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, Scene *evil_scene)
seq->flag &= ~SEQ_OVERLAP;
}
}
+
+ if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
+ TimeMarker *marker;
+ /* affect selected markers - it's unlikely that we will want to affect all in this way? */
+ for (marker = markers->first; marker; marker = marker->next) {
+ if (marker->flag & SELECT) {
+ marker->frame += offset;
+ }
+ }
+ }
}
return offset ? false : true;
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index c6cac2057d6..49a295c6a9e 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -794,54 +794,59 @@ static bool target_project_tri_correct(void *UNUSED(userdata),
float x_next[3])
{
/* Insignificant correction threshold */
- const float epsilon = 1e-6f;
- const float dir_epsilon = 0.05f;
+ const float epsilon = 1e-5f;
+ /* Dot product threshold for checking if step is 'clearly' pointing outside. */
+ const float dir_epsilon = 0.5f;
bool fixed = false, locked = false;
- /* Weight 0 and 1 boundary check. */
- for (int i = 0; i < 2; i++) {
- if (step[i] > x[i]) {
- if (step[i] > dir_epsilon * fabsf(step[1 - i])) {
- /* Abort if the solution is clearly outside the domain. */
- if (x[i] < epsilon) {
- return false;
- }
+ /* The barycentric coordinate domain is a triangle bounded by
+ * the X and Y axes, plus the x+y=1 diagonal. First, clamp the
+ * movement against the diagonal. Note that step is subtracted. */
+ float sum = x[0] + x[1];
+ float sstep = -(step[0] + step[1]);
- /* Scale a significant step down to arrive at the boundary. */
- mul_v3_fl(step, x[i] / step[i]);
- fixed = true;
- }
- else {
- /* Reset precision errors to stay at the boundary. */
- step[i] = x[i];
- fixed = locked = true;
- }
- }
- }
+ if (sum + sstep > 1.0f) {
+ float ldist = 1.0f - sum;
- /* Weight 2 boundary check. */
- float sum = x[0] + x[1];
- float sstep = step[0] + step[1];
+ /* If already at the boundary, slide along it. */
+ if (ldist < epsilon * (float)M_SQRT2) {
+ float step_len = len_v2(step);
- if (sum - sstep > 1.0f) {
- if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) {
/* Abort if the solution is clearly outside the domain. */
- if (sum > 1.0f - epsilon) {
+ if (step_len > epsilon && sstep > step_len * dir_epsilon * (float)M_SQRT2) {
return false;
}
+ /* Project the new position onto the diagonal. */
+ add_v2_fl(step, (sum + sstep - 1.0f) * 0.5f);
+ fixed = locked = true;
+ }
+ else {
/* Scale a significant step down to arrive at the boundary. */
- mul_v3_fl(step, (1.0f - sum) / -sstep);
+ mul_v3_fl(step, ldist / sstep);
fixed = true;
}
- else {
- /* Reset precision errors to stay at the boundary. */
- if (locked) {
- step[0] = step[1] = 0.0f;
+ }
+
+ /* Weight 0 and 1 boundary checks - along axis. */
+ for (int i = 0; i < 2; i++) {
+ if (step[i] > x[i]) {
+ /* If already at the boundary, slide along it. */
+ if (x[i] < epsilon) {
+ float step_len = len_v2(step);
+
+ /* Abort if the solution is clearly outside the domain. */
+ if (step_len > epsilon && (locked || step[i] > step_len * dir_epsilon)) {
+ return false;
+ }
+
+ /* Reset precision errors to stay at the boundary. */
+ step[i] = x[i];
+ fixed = true;
}
else {
- step[0] -= 0.5f * sstep;
- step[1] = -step[0];
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, x[i] / step[i]);
fixed = true;
}
}
@@ -1506,7 +1511,7 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
struct Scene *sce = CTX_data_scene(C);
- ShrinkwrapModifierData ssmd = {0};
+ ShrinkwrapModifierData ssmd = {{0}};
ModifierEvalContext ctx = {depsgraph, ob_source, 0};
int totvert;
@@ -1527,7 +1532,7 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
{
- ShrinkwrapModifierData ssmd = {0};
+ ShrinkwrapModifierData ssmd = {{0}};
int totvert;
ssmd.target = ob_target;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index b56403dfb6d..3bbd909800b 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -3132,8 +3132,10 @@ SoftBody *sbNew(Scene *scene)
sb->inpush = 0.5f;
sb->interval = 10;
- sb->sfra = scene->r.sfra;
- sb->efra = scene->r.efra;
+ if (scene != NULL) {
+ sb->sfra = scene->r.sfra;
+ sb->efra = scene->r.efra;
+ }
sb->colball = 0.49f;
sb->balldamp = 0.50f;
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index d42436ecb40..84d135c7f32 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -411,7 +411,7 @@ void BKE_sound_delete_cache(bSound *sound)
}
}
-static void sound_load_audio(Main *bmain, bSound *sound)
+static void sound_load_audio(Main *bmain, bSound *sound, bool free_waveform)
{
if (sound->cache) {
@@ -425,7 +425,9 @@ static void sound_load_audio(Main *bmain, bSound *sound)
sound->playback_handle = NULL;
}
- BKE_sound_free_waveform(sound);
+ if (free_waveform) {
+ BKE_sound_free_waveform(sound);
+ }
/* XXX unused currently */
# if 0
@@ -488,7 +490,7 @@ static void sound_load_audio(Main *bmain, bSound *sound)
void BKE_sound_load(Main *bmain, bSound *sound)
{
sound_verify_evaluated_id(&sound->id);
- sound_load_audio(bmain, sound);
+ sound_load_audio(bmain, sound, true);
}
AUD_Device *BKE_sound_mixdown(Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
@@ -902,7 +904,7 @@ void BKE_sound_read_waveform(Main *bmain, bSound *sound, short *stop)
bool need_close_audio_handles = false;
if (sound->playback_handle == NULL) {
/* TODO(sergey): Make it fully independent audio handle. */
- sound_load_audio(bmain, sound);
+ sound_load_audio(bmain, sound, true);
need_close_audio_handles = true;
}
@@ -1096,7 +1098,9 @@ bool BKE_sound_info_get(struct Main *main, struct bSound *sound, SoundInfo *soun
return sound_info_from_playback_handle(sound->playback_handle, sound_info);
}
/* TODO(sergey): Make it fully independent audio handle. */
- sound_load_audio(main, sound);
+ /* Don't free waveforms during non-destructive queries.
+ * This causes unnecessary recalculation - see T69921 */
+ sound_load_audio(main, sound, false);
const bool result = sound_info_from_playback_handle(sound->playback_handle, sound_info);
sound_free_audio(sound);
return result;
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index a02ff98a38a..9008348ed3b 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -1668,7 +1668,8 @@ StudioLight *BKE_studiolight_create(const char *path,
const float light_ambient[3])
{
StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_USER_DEFINED |
- STUDIOLIGHT_TYPE_STUDIO);
+ STUDIOLIGHT_TYPE_STUDIO |
+ STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS);
char filename[FILE_MAXFILE];
BLI_split_file_part(path, filename, FILE_MAXFILE);
@@ -1688,7 +1689,7 @@ StudioLight *BKE_studiolight_create(const char *path,
StudioLight *BKE_studiolight_studio_edit_get(void)
{
static StudioLight sl = {0};
- sl.flag = STUDIOLIGHT_TYPE_STUDIO;
+ sl.flag = STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS;
memcpy(sl.light, U.light_param, sizeof(*sl.light) * 4);
memcpy(sl.light_ambient, U.light_ambient, sizeof(*sl.light_ambient) * 3);
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 11d2314ace3..33a9875151a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2519,7 +2519,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
- struct Scene *scene,
+ const struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags)
{
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 3e449fa6b25..f58c20a7d72 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -247,8 +247,12 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout)
{
- id_us_min(&layout->screen->id);
- BKE_id_free(bmain, layout->screen);
+ /* Screen should usually be set, but we call this from file reading to get rid of invalid
+ * layouts. */
+ if (layout->screen) {
+ id_us_min(&layout->screen->id);
+ BKE_id_free(bmain, layout->screen);
+ }
BLI_freelinkN(&workspace->layouts, layout);
}
diff --git a/source/blender/blenlib/BLI_boxpack_2d.h b/source/blender/blenlib/BLI_boxpack_2d.h
index 626a00b50fd..b519a920a77 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -24,6 +24,8 @@
* \ingroup bli
*/
+struct ListBase;
+
/* Box Packer */
typedef struct BoxPack {
@@ -44,4 +46,15 @@ void BLI_box_pack_2d(BoxPack *boxarray,
float *tot_width,
float *tot_height);
+typedef struct FixedSizeBoxPack {
+ struct FixedSizeBoxPack *next, *prev;
+ int x, y;
+ int w, h;
+} FixedSizeBoxPack;
+
+void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
+ int width,
+ int height,
+ struct ListBase *packed);
+
#endif /* __BLI_BOXPACK_2D_H__ */
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
index b8bf88dd85b..1db91ea4205 100644
--- a/source/blender/blenlib/BLI_expr_pylike_eval.h
+++ b/source/blender/blenlib/BLI_expr_pylike_eval.h
@@ -45,6 +45,7 @@ typedef enum eExprPyLike_EvalStatus {
void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
+bool BLI_expr_pylike_is_using_param(struct ExprPyLike_Parsed *expr, int index);
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len);
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index b8a87e9d9fa..dffb2a165ee 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -24,6 +24,10 @@
* \ingroup bli
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct _GSQueue GSQueue;
GSQueue *BLI_gsqueue_new(const size_t elem_size);
@@ -33,4 +37,8 @@ void BLI_gsqueue_pop(GSQueue *gq, void *r_item);
void BLI_gsqueue_push(GSQueue *gq, const void *item);
void BLI_gsqueue_free(GSQueue *gq);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BLI_GSQUEUE_H__ */
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 814b13fa47f..ac0f5f44c74 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -205,6 +205,8 @@ void mul_transposed_m3_v3(const float M[3][3], float r[3]);
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_m3_v3_double(const float M[3][3], double r[3]);
+void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
+
void mul_m3_fl(float R[3][3], float f);
void mul_m4_fl(float R[4][4], float f);
void mul_mat3_m4_fl(float R[4][4], float f);
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index d2f651609f1..75d5cb286ac 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -81,12 +81,6 @@ bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) AT
int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen);
void BLI_stringenc(
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
-void BLI_stringenc_path(char *string,
- const char *dir,
- const char *head,
- const char *tail,
- unsigned short numlen,
- int pic);
/* removes trailing slash */
void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2);
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index e3cd70f7413..2b11213d351 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -39,6 +39,10 @@ bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+bool BLI_rctf_is_valid(const struct rctf *rect);
+bool BLI_rcti_is_valid(const struct rcti *rect);
+void BLI_rctf_sanitize(struct rctf *rect);
+void BLI_rcti_sanitize(struct rcti *rect);
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size);
void BLI_rcti_init_minmax(struct rcti *rect);
@@ -79,6 +83,10 @@ bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, cons
bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b);
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest);
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest);
+bool BLI_rctf_isect_rect_x(const struct rctf *src1, const struct rctf *src2, float range_x[2]);
+bool BLI_rctf_isect_rect_y(const struct rctf *src1, const struct rctf *src2, float range_y[2]);
+bool BLI_rcti_isect_rect_x(const struct rcti *src1, const struct rcti *src2, int range_x[2]);
+bool BLI_rcti_isect_rect_y(const struct rcti *src1, const struct rcti *src2, int range_y[2]);
bool BLI_rcti_isect_x(const rcti *rect, const int x);
bool BLI_rcti_isect_y(const rcti *rect, const int y);
bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y);
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 24346454a3f..83bcdff214d 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -45,11 +45,6 @@ struct BLI_mempool;
typedef struct TaskScheduler TaskScheduler;
-enum {
- TASK_SCHEDULER_AUTO_THREADS = 0,
- TASK_SCHEDULER_SINGLE_THREAD = 1,
-};
-
TaskScheduler *BLI_task_scheduler_create(int num_threads);
void BLI_task_scheduler_free(TaskScheduler *scheduler);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index f3740b5d39f..d22b1cd0ddb 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -261,6 +261,8 @@ set(LIB
bf_intern_guardedalloc
bf_intern_numaapi
extern_wcwidth
+
+ ${FREETYPE_LIBRARY}
)
if(WITH_MEM_VALGRIND)
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 71f276bc68f..50381f2fb18 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1128,7 +1128,7 @@ static void tree_overlap_traverse(BVHOverlapData_Thread *data_thread,
}
}
else {
- for (j = 0; j < data->tree2->tree_type; j++) {
+ for (j = 0; j < data->tree1->tree_type; j++) {
if (node1->children[j]) {
tree_overlap_traverse(data_thread, node1->children[j], node2);
}
@@ -1175,7 +1175,7 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
}
}
else {
- for (j = 0; j < data->tree2->tree_type; j++) {
+ for (j = 0; j < data->tree1->tree_type; j++) {
if (node1->children[j]) {
tree_overlap_traverse_cb(data_thread, node1->children[j], node2);
}
@@ -1187,9 +1187,9 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
/**
* a version of #tree_overlap_traverse_cb that that break on first true return.
*/
-static bool tree_overlap_num_recursive(BVHOverlapData_Thread *data_thread,
- const BVHNode *node1,
- const BVHNode *node2)
+static bool tree_overlap_traverse_num(BVHOverlapData_Thread *data_thread,
+ const BVHNode *node1,
+ const BVHNode *node2)
{
BVHOverlapData_Shared *data = data_thread->shared;
int j;
@@ -1219,7 +1219,7 @@ static bool tree_overlap_num_recursive(BVHOverlapData_Thread *data_thread,
}
else {
for (j = 0; j < node2->totnode; j++) {
- if (tree_overlap_num_recursive(data_thread, node1, node2->children[j])) {
+ if (tree_overlap_traverse_num(data_thread, node1, node2->children[j])) {
return true;
}
}
@@ -1228,7 +1228,7 @@ static bool tree_overlap_num_recursive(BVHOverlapData_Thread *data_thread,
else {
const uint max_interactions = data_thread->max_interactions;
for (j = 0; j < node1->totnode; j++) {
- if (tree_overlap_num_recursive(data_thread, node1->children[j], node2)) {
+ if (tree_overlap_traverse_num(data_thread, node1->children[j], node2)) {
data_thread->max_interactions = max_interactions;
}
}
@@ -1254,7 +1254,12 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
BVHOverlapData_Shared *data_shared = data->shared;
- if (data_shared->callback) {
+ if (data->max_interactions) {
+ tree_overlap_traverse_num(data,
+ data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+ }
+ else if (data_shared->callback) {
tree_overlap_traverse_cb(data,
data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
data_shared->tree2->nodes[data_shared->tree2->totleaf]);
@@ -1266,18 +1271,6 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
}
}
-static void bvhtree_overlap_num_task_cb(void *__restrict userdata,
- const int j,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
- BVHOverlapData_Shared *data_shared = data->shared;
-
- tree_overlap_num_recursive(data,
- data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
- data_shared->tree2->nodes[data_shared->tree2->totleaf]);
-}
-
BVHTreeOverlap *BLI_bvhtree_overlap_ex(
const BVHTree *tree1,
const BVHTree *tree2,
@@ -1288,13 +1281,15 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
const uint max_interactions,
const int flag)
{
- bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0;
bool overlap_pairs = (flag & BVH_OVERLAP_RETURN_PAIRS) != 0;
+ bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0 &&
+ (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
/* `RETURN_PAIRS` was not implemented without `max_interations`. */
BLI_assert(overlap_pairs || max_interactions);
- const int thread_num = BLI_bvhtree_overlap_thread_num(tree1);
+ const int root_node_len = BLI_bvhtree_overlap_thread_num(tree1);
+ const int thread_num = use_threading ? root_node_len : 1;
int j;
size_t total = 0;
BVHTreeOverlap *overlap = NULL, *to = NULL;
@@ -1309,12 +1304,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
return NULL;
}
+ const BVHNode *root1 = tree1->nodes[tree1->totleaf];
+ const BVHNode *root2 = tree2->nodes[tree2->totleaf];
+
start_axis = min_axis(tree1->start_axis, tree2->start_axis);
stop_axis = min_axis(tree1->stop_axis, tree2->stop_axis);
/* fast check root nodes for collision before doing big splitting + traversal */
- if (!tree_overlap_test(
- tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], start_axis, stop_axis)) {
+ if (!tree_overlap_test(root1, root2, start_axis, stop_axis)) {
return NULL;
}
@@ -1337,14 +1334,23 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
data[j].thread = j;
}
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading && (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
- BLI_task_parallel_range(0,
- thread_num,
- data,
- max_interactions ? bvhtree_overlap_num_task_cb : bvhtree_overlap_task_cb,
- &settings);
+ if (use_threading) {
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1;
+ BLI_task_parallel_range(0, root_node_len, data, bvhtree_overlap_task_cb, &settings);
+ }
+ else {
+ if (max_interactions) {
+ tree_overlap_traverse_num(data, root1, root2);
+ }
+ else if (callback) {
+ tree_overlap_traverse_cb(data, root1, root2);
+ }
+ else {
+ tree_overlap_traverse(data, root1, root2);
+ }
+ }
if (overlap_pairs) {
for (j = 0; j < thread_num; j++) {
@@ -1813,11 +1819,16 @@ static void bvhtree_ray_cast_data_precalc(BVHRayCastData *data, int flag)
for (i = 0; i < 3; i++) {
data->ray_dot_axis[i] = dot_v3v3(data->ray.direction, bvhtree_kdop_axes[i]);
- data->idot_axis[i] = 1.0f / data->ray_dot_axis[i];
if (fabsf(data->ray_dot_axis[i]) < FLT_EPSILON) {
- data->ray_dot_axis[i] = 0.0;
+ data->ray_dot_axis[i] = 0.0f;
+ /* Sign is not important in this case, `data->index` is adjusted anyway. */
+ data->idot_axis[i] = FLT_MAX;
}
+ else {
+ data->idot_axis[i] = 1.0f / data->ray_dot_axis[i];
+ }
+
data->index[2 * i] = data->idot_axis[i] < 0.0f ? 1 : 0;
data->index[2 * i + 1] = 1 - data->index[2 * i];
data->index[2 * i] += 2 * i;
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index ddc7f9ee4c7..8a2427a32a8 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BLI_boxpack_2d.h" /* own include */
#include "BLI_sort.h" /* qsort_r */
@@ -673,3 +674,110 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
MEM_freeN(vertex_pack_indices);
MEM_freeN(vs_ctx.vertarray);
}
+
+/* Packs boxes into a fixed area.
+ * boxes and packed are linked lists containing structs that can be cast to
+ * FixedSizeBoxPack (i.e. contains a FixedSizeBoxPack as its first element).
+ * Boxes that were packed successfully are placed into *packed and removed from *boxes.
+ *
+ * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
+ * Better ones could be used, but for the current use case (packing Image tiles into GPU
+ * textures) this is fine.
+ *
+ * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
+ * larger boxes should come first, though how exactly size is best defined (e.g. area,
+ * perimeter) depends on the particular application. */
+void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
+{
+ ListBase spaces = {NULL};
+ FixedSizeBoxPack *full_rect = MEM_callocN(sizeof(FixedSizeBoxPack), __func__);
+ full_rect->w = width;
+ full_rect->h = height;
+
+ BLI_addhead(&spaces, full_rect);
+
+ /* The basic idea of the algorithm is to keep a list of free spaces in the packing area.
+ * Then, for each box to be packed, we try to find a space that can contain it.
+ * The found space is then split into the area that is occupied by the box and the
+ * remaining area, which is reinserted into the free space list.
+ * By inserting the smaller remaining spaces first, the algorithm tries to use these
+ * smaller spaces first instead of "wasting" a large space. */
+ 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) {
+ continue;
+ }
+
+ /* Pack this box into this space. */
+ box->x = space->x;
+ box->y = space->y;
+ BLI_remlink(boxes, box);
+ BLI_addtail(packed, box);
+
+ if (box->w == space->w && box->h == space->h) {
+ /* Box exactly fills space, so just remove the space. */
+ BLI_remlink(&spaces, space);
+ MEM_freeN(space);
+ }
+ else if (box->w == space->w) {
+ /* Box fills the entire width, so we can just contract the box
+ * to the upper part that remains. */
+ space->y += box->h;
+ space->h -= box->h;
+ }
+ else if (box->h == space->h) {
+ /* Box fills the entire height, so we can just contract the box
+ * to the right part that remains. */
+ space->x += box->w;
+ space->w -= box->w;
+ }
+ else {
+ /* Split the remaining L-shaped space into two spaces.
+ * There are two ways to do so, we pick the one that produces the biggest
+ * remaining space:
+ *
+ * Horizontal Split Vertical Split
+ * ################### ###################
+ * # # # - #
+ * # Large # # Small - #
+ * # # # - #
+ * #********---------# #******** Large #
+ * # Box * Small # # Box * #
+ * # * # # * #
+ * ################### ###################
+ *
+ */
+ int area_hsplit_large = space->w * (space->h - box->h);
+ int area_vsplit_large = (space->w - box->w) * space->h;
+
+ /* Perform split. This space becomes the larger space,
+ * while the new smaller space is inserted _before_ it. */
+ FixedSizeBoxPack *new_space = MEM_callocN(sizeof(FixedSizeBoxPack), __func__);
+ if (area_hsplit_large > area_vsplit_large) {
+ new_space->x = space->x + box->w;
+ new_space->y = space->y;
+ new_space->w = space->w - box->w;
+ new_space->h = box->h;
+
+ space->y += box->h;
+ space->h -= box->h;
+ }
+ else {
+ new_space->x = space->x;
+ new_space->y = space->y + box->h;
+ new_space->w = box->w;
+ new_space->h = space->h - box->h;
+
+ space->x += box->w;
+ space->w -= box->w;
+ }
+ BLI_addhead(&spaces, new_space);
+ }
+
+ break;
+ }
+ }
+
+ BLI_freelistN(&spaces);
+} \ No newline at end of file
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 4faaf1605e0..118949d1c46 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -17,8 +17,7 @@
/** \file
* \ingroup bli
*
- * Dynamic Constrained Delaunay Triangulation.
- * See paper by Marcelo Kallmann, Hanspeter Bieri, and Daniel Thalmann
+ * Constrained 2d Delaunay Triangulation.
*/
#include "MEM_guardedalloc.h"
@@ -29,12 +28,11 @@
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
-#include "BLI_rand.h"
#include "BLI_delaunay_2d.h"
/* Uncomment this define to get helpful debugging functions etc. defined. */
-// #define DEBUG_CDT
+#define DEBUG_CDT
struct CDTEdge;
struct CDTFace;
@@ -53,20 +51,21 @@ typedef struct CDTVert {
SymEdge *symedge; /* Some edge attached to it. */
LinkNode *input_ids; /* List of corresponding vertex input ids. */
int index; /* Index into array that cdt keeps. */
- int visit_index; /* Which visit epoch has this been seen. */
+ int merge_to_index; /* Index of a CDTVert that this has merged to. -1 if no merge. */
} CDTVert;
typedef struct CDTEdge {
LinkNode *input_ids; /* List of input edge ids that this is part of. */
SymEdge symedges[2]; /* The directed edges for this edge. */
+ bool in_queue; /* Used in flipping algorithm. */
} CDTEdge;
typedef struct CDTFace {
- double centroid[2]; /* Average of vertex coords. */
SymEdge *symedge; /* A symedge in face; only used during output. */
LinkNode *input_ids; /* List of input face ids that this is part of. */
int visit_index; /* Which visit epoch has this been seen. */
bool deleted; /* Marks this face no longer used. */
+ bool in_queue; /* Used in remove_small_features algorithm. */
} CDTFace;
typedef struct CDT_state {
@@ -76,6 +75,7 @@ typedef struct CDT_state {
CDTVert **vert_array;
int vert_array_len;
int vert_array_len_alloc;
+ int input_vert_tot;
double minx;
double miny;
double maxx;
@@ -83,19 +83,13 @@ typedef struct CDT_state {
double margin;
int visit_count;
int face_edge_offset;
- RNG *rng;
MemArena *arena;
BLI_mempool *listpool;
double epsilon;
+ double epsilon_squared;
bool output_prepared;
} CDT_state;
-typedef struct LocateResult {
- enum { OnVert, OnEdge, InFace } loc_kind;
- SymEdge *se;
- double edge_lambda;
-} LocateResult;
-
#define DLNY_ARENASIZE 1 << 14
/**
@@ -105,60 +99,57 @@ typedef struct LocateResult {
#define DLNY_MARGIN_PCT 2000.0
#ifdef DEBUG_CDT
+# ifdef __GNUC__
+# define ATTU __attribute__((unused))
+# else
+# define ATTU
+# endif
# define F2(p) p[0], p[1]
-static void dump_se(const SymEdge *se, const char *lab);
-static void dump_v(const CDTVert *v, const char *lab);
-static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit);
-static void dump_id_list(const LinkNode *id_list, const char *lab);
-static void dump_cdt(const CDT_state *cdt, const char *lab);
-static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab);
-static void cdt_draw(CDT_state *cdt, const char *lab);
-static void write_cdt_input_to_file(const CDT_input *inp);
-static void validate_face_centroid(SymEdge *se);
-static void validate_cdt(CDT_state *cdt, bool check_all_tris);
+# define F3(p) p[0], p[1], p[2]
+ATTU static void dump_se(const SymEdge *se, const char *lab);
+ATTU static void dump_v(const CDTVert *v, const char *lab);
+ATTU static void dump_se_cycle(const SymEdge *se, const char *lab, const int limit);
+ATTU static void dump_id_list(const LinkNode *id_list, const char *lab);
+ATTU static void dump_cdt(const CDT_state *cdt, const char *lab);
+ATTU static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab);
+ATTU static void cdt_draw(CDT_state *cdt, const char *lab);
+ATTU static void cdt_draw_vertex_region(CDT_state *cdt, int v, double dist, const char *lab);
+ATTU static void write_cdt_input_to_file(const CDT_input *inp);
+ATTU static void validate_cdt(CDT_state *cdt,
+ bool check_all_tris,
+ bool check_delaunay,
+ bool check_visibility);
#endif
-/**
- * Return 1 if a,b,c forms CCW angle, -1 if a CW angle, 0 if straight.
- * For straight test, allow b to be withing eps of line.
- */
-static int CCW_test(const double a[2], const double b[2], const double c[2], const double eps)
+static void exactinit(void);
+static double orient2d(const double *pa, const double *pb, const double *pc);
+static double incircle(const double *pa, const double *pb, const double *pc, const double *pd);
+
+/** Return other #SymEdge for same #CDTEdge as se. */
+BLI_INLINE SymEdge *sym(const SymEdge *se)
{
- double det;
- double ab;
+ return se->next->rot;
+}
- /* This is twice the signed area of triangle abc. */
- det = (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
- if (eps == 0.0) {
- if (det > 0) {
- return 1;
- }
- else if (det < 0) {
- return -1;
- }
- else {
- return 0;
- }
- }
- ab = len_v2v2_db(a, b);
- if (ab <= eps) {
- return 0;
- }
- det /= ab;
- if (det > eps) {
- return 1;
- }
- else if (det < -eps) {
- return -1;
- }
- return 0;
+/** Return SymEdge whose next is se. */
+BLI_INLINE SymEdge *prev(const SymEdge *se)
+{
+ return se->rot->next->rot;
}
-/** return true if a -- b -- c are in that order, assuming they are on a straight line according to
- * CCW_test. */
-static bool in_line(const double a[2], const double b[2], const double c[2], double eps)
+/** Return true if a -- b -- c are in that order, assuming they are on a straight line according to
+ * orient2d and we know the order is either abc or bac.
+ * This means ab . ac and bc . ac must both be non-negative. */
+static bool in_line(const double a[2], const double b[2], const double c[2])
{
- return fabs(len_v2v2_db(a, c) - (len_v2v2_db(a, b) + len_v2v2_db(b, c))) <= eps;
+ double ab[2], bc[2], ac[2];
+ sub_v2_v2v2_db(ab, b, a);
+ sub_v2_v2v2_db(bc, c, b);
+ sub_v2_v2v2_db(ac, c, a);
+ if (dot_v2v2_db(ab, ac) < 0.0) {
+ return false;
+ }
+ return dot_v2v2_db(bc, ac) >= 0.0;
}
#ifndef NDEBUG
@@ -176,21 +167,6 @@ static bool reachable(SymEdge *s1, SymEdge *s2, int limit)
}
#endif
-static void calc_face_centroid(SymEdge *se)
-{
- SymEdge *senext;
- double *centroidp = se->face->centroid;
- int count;
- copy_v2_v2_db(centroidp, se->vert->co);
- count = 1;
- for (senext = se->next; senext != se; senext = senext->next) {
- add_v2_v2_db(centroidp, senext->vert->co);
- count++;
- }
- centroidp[0] /= count;
- centroidp[1] /= count;
-}
-
/** Using array to store these instead of linked list so can make a random selection from them. */
static CDTVert *add_cdtvert(CDT_state *cdt, double x, double y)
{
@@ -208,7 +184,7 @@ static CDTVert *add_cdtvert(CDT_state *cdt, double x, double y)
}
BLI_assert(cdt->vert_array_len < cdt->vert_array_len_alloc);
v->index = cdt->vert_array_len;
- v->visit_index = 0;
+ v->merge_to_index = -1;
cdt->vert_array[cdt->vert_array_len++] = v;
return v;
}
@@ -220,6 +196,7 @@ static CDTEdge *add_cdtedge(
SymEdge *se = &e->symedges[0];
SymEdge *sesym = &e->symedges[1];
e->input_ids = NULL;
+ e->in_queue = false;
BLI_linklist_prepend_arena(&cdt->edges, (void *)e, cdt->arena);
se->edge = sesym->edge = e;
se->face = fleft;
@@ -243,6 +220,7 @@ static CDTFace *add_cdtface(CDT_state *cdt)
f->deleted = false;
f->symedge = NULL;
f->input_ids = NULL;
+ f->in_queue = false;
BLI_linklist_prepend_arena(&cdt->faces, (void *)f, cdt->arena);
return f;
}
@@ -290,37 +268,24 @@ static void add_list_to_input_ids(LinkNode **dst, const LinkNode *src, CDT_state
}
}
-/** Return other #SymEdge for same #CDTEdge as se. */
-static inline SymEdge *sym(const SymEdge *se)
-{
- return se->next->rot;
-}
-
-/** Return SymEdge whose next is se. */
-static inline SymEdge *prev(const SymEdge *se)
-{
- return se->rot->next->rot;
-}
-
-static inline bool is_border_edge(const CDTEdge *e, const CDT_state *cdt)
+BLI_INLINE bool is_border_edge(const CDTEdge *e, const CDT_state *cdt)
{
return e->symedges[0].face == cdt->outer_face || e->symedges[1].face == cdt->outer_face;
}
-/** Does one edge of this edge touch the frame? */
-static bool edge_touches_frame(const CDTEdge *e)
+BLI_INLINE bool is_constrained_edge(const CDTEdge *e)
{
- return e->symedges[0].vert->index < 4 || e->symedges[1].vert->index < 4;
+ return e->input_ids != NULL;
}
-static inline bool is_constrained_edge(const CDTEdge *e)
+BLI_INLINE bool is_deleted_edge(const CDTEdge *e)
{
- return e->input_ids != NULL;
+ return e->symedges[0].next == NULL;
}
-static inline bool is_deleted_edge(const CDTEdge *e)
+BLI_INLINE bool is_original_vert(const CDTVert *v, CDT_state *cdt)
{
- return e->symedges[0].next == NULL;
+ return (v->index < cdt->input_vert_tot);
}
/** Is there already an edge between a and b? */
@@ -357,7 +322,6 @@ static bool vert_touches_face(const CDTVert *v, const CDTFace *f)
* Add an edge from s1->v to s2->v, splitting the face in two.
* The original face will continue to be associated with the subface
* that has s1, and a new face will be made for s2's new face.
- * The centroids of both faces are recalculated.
* Return the new diagonal's CDTEdge *.
*/
static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2)
@@ -366,8 +330,8 @@ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2)
CDTFace *fold, *fnew;
SymEdge *sdiag, *sdiagsym;
SymEdge *s1prev, *s1prevsym, *s2prev, *s2prevsym, *se;
- BLI_assert(reachable(s1, s2, 2000));
- BLI_assert(reachable(s2, s1, 2000));
+ BLI_assert(reachable(s1, s2, 20000));
+ BLI_assert(reachable(s2, s1, 20000));
fold = s1->face;
fnew = add_cdtface(cdt);
s1prev = prev(s1);
@@ -392,12 +356,61 @@ static CDTEdge *add_diagonal(CDT_state *cdt, SymEdge *s1, SymEdge *s2)
se->face = fnew;
}
add_list_to_input_ids(&fnew->input_ids, fold->input_ids, cdt);
- calc_face_centroid(sdiag);
- calc_face_centroid(sdiagsym);
return ediag;
}
/**
+ * Add a dangling edge from an isolated v to the vert at se in the same face as se->face.
+ */
+static CDTEdge *add_vert_to_symedge_edge(CDT_state *cdt, CDTVert *v, SymEdge *se)
+{
+ CDTEdge *e;
+ SymEdge *se_rot, *se_rotsym, *new_se, *new_se_sym;
+
+ se_rot = se->rot;
+ se_rotsym = sym(se_rot);
+ e = add_cdtedge(cdt, v, se->vert, se->face, se->face);
+ new_se = &e->symedges[0];
+ new_se_sym = &e->symedges[1];
+ new_se->next = se;
+ new_se_sym->next = new_se;
+ new_se->rot = new_se;
+ new_se_sym->rot = se_rot;
+ se->rot = new_se_sym;
+ se_rotsym->next = new_se_sym;
+ return e;
+}
+
+/* Connect the verts of se1 and se2, assuming that currently those two SymEdges are on
+ * the outer boundary (have face == outer_face) of two components that are isolated from
+ * each other.
+ */
+static CDTEdge *connect_separate_parts(CDT_state *cdt, SymEdge *se1, SymEdge *se2)
+{
+ CDTEdge *e;
+ SymEdge *se1_rot, *se1_rotsym, *se2_rot, *se2_rotsym, *new_se, *new_se_sym;
+ ;
+
+ BLI_assert(se1->face == cdt->outer_face && se2->face == cdt->outer_face);
+ se1_rot = se1->rot;
+ se1_rotsym = sym(se1_rot);
+ se2_rot = se2->rot;
+ se2_rotsym = sym(se2_rot);
+ e = add_cdtedge(cdt, se1->vert, se2->vert, cdt->outer_face, cdt->outer_face);
+ new_se = &e->symedges[0];
+ new_se_sym = &e->symedges[1];
+ new_se->next = se2;
+ new_se_sym->next = se1;
+ new_se->rot = se1_rot;
+ new_se_sym->rot = se2_rot;
+ se1->rot = new_se;
+ se2->rot = new_se_sym;
+ se1_rotsym->next = new_se;
+ se2_rotsym->next = new_se_sym;
+ return e;
+}
+
+/**
* Split \a se at fraction \a lambda,
* and return the new #CDTEdge that is the new second half.
* Copy the edge input_ids into the new one.
@@ -435,14 +448,12 @@ static CDTEdge *split_edge(CDT_state *cdt, SymEdge *se, double lambda)
newsesym->vert->symedge = newsesym;
}
add_list_to_input_ids(&e->input_ids, se->edge->input_ids, cdt);
- calc_face_centroid(se);
- calc_face_centroid(sesym);
return e;
}
/**
* Delete an edge from the structure. The new combined face on either side of
- * the deleted edge will be the one that was e's face; the centroid is updated.
+ * the deleted edge will be the one that was e's face.
* There will be now an unused face, marked by setting its deleted flag,
* and an unused #CDTEdge, marked by setting the next and rot pointers of
* its SymEdges to NULL.
@@ -519,820 +530,486 @@ static void delete_edge(CDT_state *cdt, SymEdge *e)
cdt->outer_face = aface;
}
}
- if (aface != cdt->outer_face) {
- calc_face_centroid(f);
- }
}
-/**
- * The initial structure will be the rectangle with opposite corners (minx,miny)
- * and (maxx,maxy), and a diagonal going between those two corners.
- * We keep track of the outer face (surrounding the entire structure; its boundary
- * is the clockwise traversal of the bounding box rectangle initially) in cdt->outer_face.
- *
- * The vertices are kept as pointers in an array (which may need to be reallocated from
- * time to time); the edges and faces are kept in lists. Sometimes edges and faces are deleted,
- * marked by setting all pointers to NULL (for edges), or setting the deleted flag to true (for
- * faces).
- *
- * A #MemArena is allocated to do all allocations from except for link list nodes; a listpool
- * is created for link list node allocations.
- *
- * The epsilon argument is stored and used in "near enough" distance calculations.
- *
- * When done, caller must call BLI_constrained_delaunay_free to free
- * the memory used by the returned #CDT_state.
- */
-static CDT_state *cdt_init(double minx, double maxx, double miny, double maxy, double epsilon)
+static CDT_state *new_cdt_init(const CDT_input *in)
{
- double x0, x1, y0, y1;
- double margin;
- CDTVert *v[4];
- CDTEdge *e[4];
- CDTFace *f0, *fouter;
- int i, inext, iprev;
+ int i;
MemArena *arena = BLI_memarena_new(DLNY_ARENASIZE, __func__);
- CDT_state *cdt = BLI_memarena_alloc(arena, sizeof(CDT_state));
- cdt->edges = NULL;
- cdt->faces = NULL;
- cdt->vert_array_len = 0;
- cdt->vert_array_len_alloc = 32;
+ CDT_state *cdt = BLI_memarena_calloc(arena, sizeof(CDT_state));
+
+ cdt->epsilon = (double)in->epsilon;
+ cdt->epsilon_squared = cdt->epsilon * cdt->epsilon;
+ cdt->arena = arena;
+ cdt->input_vert_tot = in->verts_len;
+ cdt->vert_array_len_alloc = 2 * in->verts_len;
cdt->vert_array = BLI_memarena_alloc(arena,
cdt->vert_array_len_alloc * sizeof(*cdt->vert_array));
- cdt->minx = minx;
- cdt->miny = miny;
- cdt->maxx = maxx;
- cdt->maxy = maxy;
- cdt->arena = arena;
- cdt->listpool = BLI_mempool_create(sizeof(LinkNode), 128, 128, 0);
- cdt->rng = BLI_rng_new(0);
- cdt->epsilon = epsilon;
-
- /* Expand bounding box a bit and make initial CDT from it. */
- margin = DLNY_MARGIN_PCT * max_dd(maxx - minx, maxy - miny) / 100.0;
- if (margin <= 0.0) {
- margin = 1.0;
- }
- if (margin < epsilon) {
- margin = 4 * epsilon; /* Make sure constraint verts don't merge with border verts. */
- }
- cdt->margin = margin;
- x0 = minx - margin;
- y0 = miny - margin;
- x1 = maxx + margin;
- y1 = maxy + margin;
-
- /* Make a quad, then split it with a diagonal. */
- v[0] = add_cdtvert(cdt, x0, y0);
- v[1] = add_cdtvert(cdt, x1, y0);
- v[2] = add_cdtvert(cdt, x1, y1);
- v[3] = add_cdtvert(cdt, x0, y1);
- cdt->outer_face = fouter = add_cdtface(cdt);
- f0 = add_cdtface(cdt);
- for (i = 0; i < 4; i++) {
- e[i] = add_cdtedge(cdt, v[i], v[(i + 1) % 4], f0, fouter);
- }
- for (i = 0; i < 4; i++) {
- inext = (i + 1) % 4;
- iprev = (i + 3) % 4;
- e[i]->symedges[0].next = &e[inext]->symedges[0];
- e[inext]->symedges[1].next = &e[i]->symedges[1];
- e[i]->symedges[0].rot = &e[iprev]->symedges[1];
- e[iprev]->symedges[1].rot = &e[i]->symedges[0];
- }
- calc_face_centroid(&e[0]->symedges[0]);
- add_diagonal(cdt, &e[0]->symedges[0], &e[2]->symedges[0]);
- fouter->centroid[0] = fouter->centroid[1] = 0.0;
-
- cdt->visit_count = 0;
- cdt->output_prepared = false;
- cdt->face_edge_offset = 0;
+ cdt->listpool = BLI_mempool_create(
+ sizeof(LinkNode), 128 + 4 * in->verts_len, 128 + in->verts_len, 0);
+
+ for (i = 0; i < in->verts_len; i++) {
+ add_cdtvert(cdt, (double)(in->vert_coords[i][0]), (double)(in->vert_coords[i][1]));
+ }
+ cdt->outer_face = add_cdtface(cdt);
return cdt;
}
-static void cdt_free(CDT_state *cdt)
+static void new_cdt_free(CDT_state *cdt)
{
- BLI_rng_free(cdt->rng);
BLI_mempool_destroy(cdt->listpool);
BLI_memarena_free(cdt->arena);
}
-static bool locate_point_final(const double p[2],
- SymEdge *tri_se,
- bool try_neighbors,
- const double epsilon,
- LocateResult *r_lr)
-{
- /* 'p' should be in or on our just outside of 'cur_tri'. */
- double dist_inside[3];
- int i;
- SymEdge *se;
- const double *a, *b;
- double lambda, close[2];
- bool done = false;
-#ifdef DEBUG_CDT
- int dbg_level = 0;
-
- if (dbg_level > 0) {
- fprintf(stderr, "locate_point_final %d\n", try_neighbors);
- dump_se(tri_se, "tri_se");
- fprintf(stderr, "\n");
- }
-#endif
- se = tri_se;
- i = 0;
- do {
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "%d: ", i);
- dump_se(se, "search se");
- }
-#endif
- a = se->vert->co;
- b = se->next->vert->co;
- lambda = closest_to_line_v2_db(close, p, a, b);
- double len_close_p = len_v2v2_db(close, p);
- if (len_close_p < epsilon) {
- if (len_v2v2_db(p, a) < epsilon) {
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "OnVert case a (%.2f,%.2f)\n", F2(a));
- }
-#endif
- r_lr->loc_kind = OnVert;
- r_lr->se = se;
- r_lr->edge_lambda = 0.0;
- done = true;
- }
- else if (len_v2v2_db(p, b) < epsilon) {
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "OnVert case b (%.2f,%.2f)\n", F2(b));
- }
-#endif
- r_lr->loc_kind = OnVert;
- r_lr->se = se->next;
- r_lr->edge_lambda = 0.0;
- done = true;
- }
- else if (lambda > 0.0 && lambda < 1.0) {
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "OnEdge case, lambda=%f\n", lambda);
- dump_se(se, "se");
- }
-#endif
- r_lr->loc_kind = OnEdge;
- r_lr->se = se;
- r_lr->edge_lambda = lambda;
- done = true;
- }
- }
- else {
- dist_inside[i] = len_close_p;
- dist_inside[i] = CCW_test(a, b, p, epsilon) >= 0 ? len_close_p : -len_close_p;
- }
- i++;
- se = se->next;
- } while (se != tri_se && !done);
- if (!done) {
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr,
- "not done, dist_inside=%f %f %f\n",
- dist_inside[0],
- dist_inside[1],
- dist_inside[2]);
- }
-#endif
- if (dist_inside[0] >= 0.0 && dist_inside[1] >= 0.0 && dist_inside[2] >= 0.0) {
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "InFace case\n");
- dump_se_cycle(tri_se, "tri", 10);
- }
-#endif
- r_lr->loc_kind = InFace;
- r_lr->se = tri_se;
- r_lr->edge_lambda = 0.0;
- done = true;
- }
- else if (try_neighbors) {
- for (se = tri_se->next; se != tri_se; se = se->next) {
- if (locate_point_final(p, se, false, epsilon, r_lr)) {
- done = true;
- break;
- }
- }
- if (!done) {
- /* Shouldn't happen desperation mode: pick something. */
- se = NULL;
- if (dist_inside[0] > 0) {
- se = tri_se;
- }
- if (dist_inside[1] > 0 && (se == NULL || dist_inside[1] < dist_inside[i])) {
- se = tri_se->next;
- }
- if (se == NULL) {
- se = tri_se->next->next;
- }
- a = se->vert->co;
- b = se->next->vert->co;
- lambda = closest_to_line_v2_db(close, p, a, b);
- if (lambda <= 0.0) {
- r_lr->loc_kind = OnVert;
- r_lr->se = se;
- r_lr->edge_lambda = 0.0;
- }
- else if (lambda >= 1.0) {
- r_lr->loc_kind = OnVert;
- r_lr->se = se->next;
- r_lr->edge_lambda = 0.0;
- }
- else {
- r_lr->loc_kind = OnEdge;
- r_lr->se = se->next;
- r_lr->edge_lambda = lambda;
- }
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(
- stderr, "desperation case kind=%u lambda=%f\n", r_lr->loc_kind, r_lr->edge_lambda);
- dump_se(r_lr->se, "se");
- BLI_assert(0); /* While developing, catch these "should not happens" */
- }
-#endif
- fprintf(stderr, "desperation! point=(%g,%g)\n", p[0], p[1]); // TODO: remove
- return true;
- }
- }
- }
- return done;
-}
+typedef struct SiteInfo {
+ CDTVert *v;
+ int orig_index;
+} SiteInfo;
-static LocateResult locate_point(CDT_state *cdt, const double p[2])
+static int site_lexicographic_cmp(const void *a, const void *b)
{
- LocateResult lr;
- SymEdge *cur_se, *next_se, *next_se_sym;
- CDTFace *cur_tri;
- bool done;
- int sample_n, i, k;
- CDTVert *v, *best_start_vert;
- double dist_squared, best_dist_squared;
- double *a, *b, *c;
- const double epsilon = cdt->epsilon;
- int visit = ++cdt->visit_count;
- int loop_count = 0;
-#ifdef DEBUG_CDT
- int dbg_level = 0;
+ const SiteInfo *s1 = a;
+ const SiteInfo *s2 = b;
+ const double *co1 = s1->v->co;
+ const double *co2 = s2->v->co;
- if (dbg_level > 0) {
- fprintf(stderr, "locate_point (%.2f,%.2f), visit_index=%d\n", F2(p), visit);
- }
-#endif
- /* Starting point determined by closest to p in an n ** (1/3) sized sample of current points. */
- BLI_assert(cdt->vert_array_len > 0);
- sample_n = (int)round(pow((double)cdt->vert_array_len, 0.33333));
- if (sample_n < 1) {
- sample_n = 1;
+ if (co1[0] < co2[0]) {
+ return -1;
}
- best_start_vert = NULL;
- best_dist_squared = DBL_MAX;
- for (k = 0; k < sample_n; k++) {
- /* Yes, this may try some i's more than once,
- * but will still get about an n ** (1/3) size sample. */
- i = (int)(BLI_rng_get_uint(cdt->rng) % cdt->vert_array_len);
- v = cdt->vert_array[i];
- dist_squared = len_squared_v2v2_db(p, v->co);
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "try start vert %d, dist_squared=%f\n", i, dist_squared);
- dump_v(v, "v");
- }
-#endif
- if (dist_squared < best_dist_squared) {
- best_dist_squared = dist_squared;
- best_start_vert = v;
- }
+ else if (co1[0] > co2[0]) {
+ return 1;
}
- cur_se = &best_start_vert->symedge[0];
- if (cur_se->face == cdt->outer_face) {
- cur_se = cur_se->rot;
- BLI_assert(cur_se->face != cdt->outer_face);
+ else if (co1[1] < co2[1]) {
+ return -1;
}
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se(cur_se, "start vert edge");
+ else if (co1[1] > co2[1]) {
+ return 1;
}
-#endif
- done = false;
- while (!done) {
- /* Find edge of cur_tri that separates p and t's centroid,
- * and where other tri over the edge is unvisited. */
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se_cycle(cur_se, "cur search face", 5);
- }
-#endif
- cur_tri = cur_se->face;
- BLI_assert(cur_tri != cdt->outer_face);
- cur_tri->visit_index = visit;
- /* Is p in or on current triangle? */
- a = cur_se->vert->co;
- b = cur_se->next->vert->co;
- c = cur_se->next->next->vert->co;
- if (CCW_test(a, b, p, 0.0) >= 0 && CCW_test(b, c, p, 0.0) >= 0 &&
- CCW_test(c, a, p, 0.0) >= 0) {
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "p in current triangle\n");
- }
-#endif
- done = locate_point_final(p, cur_se, false, epsilon, &lr);
- BLI_assert(done == true);
- break;
- }
- bool found_next = false;
- next_se = cur_se;
- do {
- a = next_se->vert->co;
- b = next_se->next->vert->co;
- c = next_se->next->next->vert->co;
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- dump_se(next_se, "search edge");
- fprintf(stderr, "tri centroid=(%.3f,%.3f)\n", F2(cur_tri->centroid));
- validate_face_centroid(next_se);
- }
-#endif
- next_se_sym = sym(next_se);
- if (CCW_test(a, b, p, 0.0) <= 0 && next_se->face != cdt->outer_face) {
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "CCW_test(a, b, p) <= 0\n");
- }
-#endif
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se(next_se_sym, "next_se_sym");
- fprintf(stderr, "next_se_sym face visit=%d\n", next_se_sym->face->visit_index);
- }
-#endif
- if (next_se_sym->face->visit_index != visit) {
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "found edge to cross\n");
- }
-#endif
- found_next = true;
- cur_se = next_se_sym;
- break;
- }
- }
- next_se = next_se->next;
- } while (next_se != cur_se);
- if (!found_next) {
- done = locate_point_final(p, cur_se, true, epsilon, &lr);
- BLI_assert(done = true);
- done = true;
- }
- if (++loop_count > 1000000) {
- fprintf(stderr, "infinite search loop?\n");
- done = locate_point_final(p, cur_se, true, epsilon, &lr);
- }
+ else if (s1->orig_index < s2->orig_index) {
+ return -1;
}
-
- return lr;
-}
-
-/**
- * Return true if circumcircle(v1, v2, v3) does not contain p.
- * To avoid possible infinite flip loops, we will say true even if p is inside the circle
- * but less than epsilon from the boundary; or if v1, v2, v3, form a straight line.
- */
-static bool delaunay_check(CDTVert *v1, CDTVert *v2, CDTVert *v3, CDTVert *p, const double epsilon)
-{
- double x1, y1, x2, y2, den, cenx, ceny, rad, pc, a, b, w, z, q, s;
-
- /* Find center and radius of circum-circle of v1,v2,v3.
- * Transform coords so v3 is at origin to help reduce floating point error
- * when coordinates are far from (0,0) but close together.
- */
- x1 = v1->co[0] - v3->co[0];
- y1 = v1->co[1] - v3->co[1];
- x2 = v2->co[0] - v3->co[0];
- y2 = v2->co[1] - v3->co[1];
- den = 2.0 * (x1 * y2 - x2 * y1);
- if (UNLIKELY(den == 0.0)) {
- /* v1, v2, v3 are in a line. */
- return true;
+ else if (s1->orig_index > s2->orig_index) {
+ return 1;
}
- /* cen[0] = det(x1**2 + y1**2, y1, x2**2 + y2**2, y2) / den
- * cen[1] = det(x1, x1**2 + y1**2, x2, x2**2 + y2**2) / den
- * den = 2 * det(x1, y1, x2, y2)
- */
- a = x1 * x1 + y1 * y1;
- b = x2 * x2 + y2 * y2;
- cenx = (a * y2 - b * y1) / den;
- ceny = (x1 * b - x2 * a) / den;
- w = x1 - cenx;
- z = y1 - ceny;
- rad = sqrt(w * w + z * z);
- q = p->co[0] - v3->co[0] - cenx;
- s = p->co[1] - v3->co[1] - ceny;
- pc = sqrt(q * q + s * s);
- return (pc >= rad - epsilon);
-}
-
-/* Return true if we can flip edge v1-v3 to edge v2-v4 inside quad v1v2v3v4 (in CCW order).
- * We can do this if angles v4-v1-v2 and v2-v3-v4 are both CCW or straight.
- */
-static inline bool can_flip(CDTVert *v1, CDTVert *v2, CDTVert *v3, CDTVert *v4)
-{
- return CCW_test(v4->co, v1->co, v2->co, 0.0) >= 0 && CCW_test(v2->co, v3->co, v4->co, 0.0) >= 0;
+ return 0;
}
-/** Use LinkNode linked list as stack of SymEdges, allocating from cdt->listpool. */
-typedef LinkNode *Stack;
-
-static inline void push(Stack *stack, SymEdge *se, CDT_state *cdt)
+BLI_INLINE bool vert_left_of_symedge(CDTVert *v, SymEdge *se)
{
- BLI_linklist_prepend_pool(stack, se, cdt->listpool);
+ return orient2d(v->co, se->vert->co, se->next->vert->co) > 0.0;
}
-static inline SymEdge *pop(Stack *stack, CDT_state *cdt)
+BLI_INLINE bool vert_right_of_symedge(CDTVert *v, SymEdge *se)
{
- return (SymEdge *)BLI_linklist_pop_pool(stack, cdt->listpool);
+ return orient2d(v->co, se->next->vert->co, se->vert->co) > 0.0;
}
-static inline bool is_empty(Stack *stack)
+/* Is se above basel? */
+BLI_INLINE bool dc_tri_valid(SymEdge *se, SymEdge *basel, SymEdge *basel_sym)
{
- return *stack == NULL;
+ return orient2d(se->next->vert->co, basel_sym->vert->co, basel->vert->co) > 0.0;
}
-/**
- * <pre>
- * /\ /\
- * /a|\ / \
- * / | sesym / \
- * / | \ / \
- * . b | d . -> . se______
- * \ se| / \ /
- * \ |c/ \ /
- * \ |/ \ /
- * </pre>
+/* Delaunay triangulate sites[start} to sites[end-1].
+ * Assume sites are lexicographically sorted by coordinate.
+ * Return SymEdge of ccw convex hull at left-most point in *r_le
+ * and that of right-most point of cw convex null in *r_re.
*/
-static void flip(SymEdge *se, CDT_state *cdt)
+static void dc_tri(
+ CDT_state *cdt, SiteInfo *sites, int start, int end, SymEdge **r_le, SymEdge **r_re)
{
- SymEdge *a, *b, *c, *d;
- SymEdge *sesym, *asym, *bsym, *csym, *dsym;
- CDTFace *t1, *t2;
- CDTVert *v1, *v2;
+ int n = end - start;
+ int n2;
+ CDTVert *v1, *v2, *v3;
+ CDTEdge *ea, *eb, *ebasel;
+ SymEdge *ldo, *ldi, *rdi, *rdo, *basel, *basel_sym, *lcand, *rcand, *t;
+ double orient;
+ bool valid_lcand, valid_rcand;
#ifdef DEBUG_CDT
- const int dbg_level = 0;
-#endif
+ char label_buf[100];
+ int dbg_level = 0;
- sesym = sym(se);
-#ifdef DEBUG_CDT
if (dbg_level > 0) {
- fprintf(stderr, "flip\n");
- dump_se(se, "se");
- dump_se(sesym, "sesym");
- }
-#endif
- a = se->next;
- b = a->next;
- c = sesym->next;
- d = c->next;
- asym = sym(a);
- bsym = sym(b);
- csym = sym(c);
- dsym = sym(d);
-#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- dump_se(a, "a");
- dump_se(b, "b");
- dump_se(c, "c");
- dump_se(d, "d");
+ fprintf(stderr, "DC_TRI start=%d end=%d\n", start, end);
}
#endif
- v1 = se->vert;
- v2 = sesym->vert;
- t1 = a->face;
- t2 = c->face;
-
- se->vert = b->vert;
- sesym->vert = d->vert;
-
- a->next = se;
- se->next = d;
- d->next = a;
-
- sesym->next = b;
- b->next = c;
- c->next = sesym;
- a->rot = dsym;
- b->rot = se;
- se->rot = asym;
-
- c->rot = bsym;
- d->rot = sesym;
- sesym->rot = csym;
-
- a->face = se->face = d->face = t1;
- sesym->face = b->face = c->face = t2;
-
- if (v1->symedge == se) {
- v1->symedge = c;
+ BLI_assert(r_le != NULL && r_re != NULL);
+ if (n <= 1) {
+ *r_le = NULL;
+ *r_re = NULL;
+ return;
}
- if (v2->symedge == sesym) {
- v2->symedge = a;
+ if (n <= 3) {
+ v1 = sites[start].v;
+ v2 = sites[start + 1].v;
+ ea = add_cdtedge(cdt, v1, v2, cdt->outer_face, cdt->outer_face);
+ ea->symedges[0].next = &ea->symedges[1];
+ ea->symedges[1].next = &ea->symedges[0];
+ ea->symedges[0].rot = &ea->symedges[0];
+ ea->symedges[1].rot = &ea->symedges[1];
+ if (n == 2) {
+ *r_le = &ea->symedges[0];
+ *r_re = &ea->symedges[1];
+ return;
+ }
+ v3 = sites[start + 2].v;
+ eb = add_vert_to_symedge_edge(cdt, v3, &ea->symedges[1]);
+ orient = orient2d(v1->co, v2->co, v3->co);
+ if (orient > 0.0) {
+ add_diagonal(cdt, &eb->symedges[0], &ea->symedges[0]);
+ *r_le = &ea->symedges[0];
+ *r_re = &eb->symedges[0];
+ }
+ else if (orient < 0.0) {
+ add_diagonal(cdt, &ea->symedges[0], &eb->symedges[0]);
+ *r_le = ea->symedges[0].rot;
+ *r_re = eb->symedges[0].rot;
+ }
+ else {
+ /* Collinear points. Just return a line. */
+ *r_le = &ea->symedges[0];
+ *r_re = &eb->symedges[0];
+ }
+ return;
}
+ /* Here: n >= 4. Divide and conquer. */
+ n2 = n / 2;
+ BLI_assert(n2 >= 2 && end - (start + n2) >= 2);
- calc_face_centroid(a);
- calc_face_centroid(sesym);
-
+ /* Delaunay triangulate two halves, L and R. */
+ dc_tri(cdt, sites, start, start + n2, &ldo, &ldi);
+ dc_tri(cdt, sites, start + n2, end, &rdi, &rdo);
#ifdef DEBUG_CDT
if (dbg_level > 0) {
- fprintf(stderr, "after flip\n");
- dump_se_cycle(a, "a cycle", 5);
- dump_se_cycle(sesym, "sesym cycle", 5);
+ fprintf(stderr, "\nDC_TRI merge step for start=%d, end=%d\n", start, end);
+ dump_se(ldo, "ldo");
+ dump_se(ldi, "ldi");
+ dump_se(rdi, "rdi");
+ dump_se(rdo, "rdo");
+ if (dbg_level > 1) {
+ sprintf(label_buf, "dc_tri(%d,%d)(%d,%d)", start, start + n2, start + n2, end);
+ /* dump_cdt(cdt, label_buf); */
+ cdt_draw(cdt, label_buf);
+ }
}
#endif
- if (cdt) {
- /* Pass. */
- }
-}
-static void flip_edges(CDTVert *v, Stack *stack, CDT_state *cdt)
-{
- SymEdge *se, *sesym;
- CDTVert *a, *b, *c, *d;
- SymEdge *tri_without_p;
- bool is_delaunay;
- const double epsilon = cdt->epsilon;
- int count = 3;
+ /* Find lower common tangent of L and R. */
+ for (;;) {
+ if (vert_left_of_symedge(rdi->vert, ldi)) {
+ ldi = ldi->next;
+ }
+ else if (vert_right_of_symedge(ldi->vert, rdi)) {
+ rdi = sym(rdi)->rot; /* Previous edge to rdi with same right face. */
+ }
+ else {
+ break;
+ }
+ }
#ifdef DEBUG_CDT
- const int dbg_level = 0;
if (dbg_level > 0) {
- fprintf(stderr, "flip_edges, v=(%.2f,%.2f)\n", F2(v->co));
+ fprintf(stderr, "common lower tangent is between\n");
+ dump_se(rdi, "rdi");
+ dump_se(ldi, "ldi");
}
#endif
- while (!is_empty(stack)) {
- if (++count > 10000) {
- fprintf(stderr, "infinite flip loop?\n");
- return;
- }
- se = pop(stack, cdt);
+ ebasel = connect_separate_parts(cdt, sym(rdi)->next, ldi);
+ basel = &ebasel->symedges[0];
+ basel_sym = &ebasel->symedges[1];
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se(se, "flip_edges popped");
- }
+ if (dbg_level > 1) {
+ dump_se(basel, "basel");
+ cdt_draw(cdt, "after basel made");
+ }
#endif
- if (!is_constrained_edge(se->edge)) {
- /* Edge is not constrained; is it Delaunay? */
+ if (ldi->vert == ldo->vert) {
+ ldo = basel_sym;
+ }
+ if (rdi->vert == rdo->vert) {
+ rdo = basel;
+ }
+
+ /* Merge loop. */
+ for (;;) {
+ /* Locate the first point lcand->next->vert encountered by rising bubble,
+ * and delete L edges out of basel->next->vert that fail the circle test. */
+ lcand = basel_sym->rot;
+ rcand = basel_sym->next;
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- dump_se_cycle(se, "unconstrained edge", 5);
- }
- else if (dbg_level > 0) {
- fprintf(stderr, "unconstrained edge\n");
- }
+ if (dbg_level > 1) {
+ fprintf(stderr, "\ntop of merge loop\n");
+ dump_se(lcand, "lcand");
+ dump_se(rcand, "rcand");
+ dump_se(basel, "basel");
+ }
#endif
- a = se->vert;
- b = se->next->vert;
- c = se->next->next->vert;
- sesym = sym(se);
- d = sesym->next->next->vert;
+ if (dc_tri_valid(lcand, basel, basel_sym)) {
#ifdef DEBUG_CDT
if (dbg_level > 1) {
- fprintf(stderr, "a=(%.3f,%.3f) b=(%.3f,%.3f)\n", F2(a->co), F2(b->co));
- fprintf(stderr, "c=(%.3f,%.3f) d=(%.3f,%.3f)\n", F2(c->co), F2(d->co));
+ fprintf(stderr, "found valid lcand\n");
+ dump_se(lcand, " lcand");
}
#endif
- if (v == c) {
- tri_without_p = sesym;
- is_delaunay = delaunay_check(a, b, c, d, epsilon);
+ while (incircle(basel_sym->vert->co,
+ basel->vert->co,
+ lcand->next->vert->co,
+ lcand->rot->next->vert->co) > 0.0) {
#ifdef DEBUG_CDT
if (dbg_level > 1) {
- fprintf(stderr, "v==c, delaunay(a,b,c,d)=%d\n", is_delaunay);
+ fprintf(stderr, "incircle says to remove lcand\n");
+ dump_se(lcand, " lcand");
}
#endif
+ t = lcand->rot;
+ delete_edge(cdt, sym(lcand));
+ lcand = t;
}
- else {
- tri_without_p = se;
- BLI_assert(d == v);
- is_delaunay = delaunay_check(b, a, d, c, epsilon);
+ }
+ /* Symmetrically, locate first R point to be hit and delete R edges. */
+ if (dc_tri_valid(rcand, basel, basel_sym)) {
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "v!=c, delaunay(b,a,d,c)=%d\n", is_delaunay);
- }
-#endif
+ if (dbg_level > 1) {
+ fprintf(stderr, "found valid rcand\n");
+ dump_se(rcand, " rcand");
}
- if (!is_delaunay && can_flip(a, d, b, c)) {
- /* Push two edges of tri without p that aren't se. */
+#endif
+ while (incircle(basel_sym->vert->co,
+ basel->vert->co,
+ rcand->next->vert->co,
+ sym(rcand)->next->next->vert->co) > 0.0) {
#ifdef DEBUG_CDT
if (dbg_level > 0) {
- fprintf(stderr, "maybe pushing more edges\n");
+ fprintf(stderr, "incircle says to remove rcand\n");
+ dump_se(lcand, " rcand");
}
#endif
- if (!is_border_edge(tri_without_p->next->edge, cdt)) {
+ t = sym(rcand)->next;
+ delete_edge(cdt, rcand);
+ rcand = t;
+ }
+ }
+ /* If both lcand and rcand are invalid, then basel is the common upper tangent. */
+ valid_lcand = dc_tri_valid(lcand, basel, basel_sym);
+ valid_rcand = dc_tri_valid(rcand, basel, basel_sym);
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se(tri_without_p->next, "push1");
- }
+ if (dbg_level > 0) {
+ fprintf(
+ stderr, "after bubbling up, valid_lcand=%d, valid_rcand=%d\n", valid_lcand, valid_rcand);
+ dump_se(lcand, "lcand");
+ dump_se(rcand, "rcand");
+ }
#endif
- push(stack, tri_without_p->next, cdt);
- }
- if (!is_border_edge(tri_without_p->next->next->edge, cdt)) {
+ if (!valid_lcand && !valid_rcand) {
+ break;
+ }
+ /* The next cross edge to be connected is to either lcand->next->vert or rcand->next->vert;
+ * if both are valid, choose the appropriate one using the incircle test.
+ */
+ if (!valid_lcand ||
+ (valid_rcand &&
+ incircle(lcand->next->vert->co, lcand->vert->co, rcand->vert->co, rcand->next->vert->co) >
+ 0.0)) {
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- dump_se(tri_without_p->next->next, "\npush2");
- }
+ if (dbg_level > 0) {
+ fprintf(stderr, "connecting rcand\n");
+ dump_se(basel_sym, " se1=basel_sym");
+ dump_se(rcand->next, " se2=rcand->next");
+ }
#endif
- push(stack, tri_without_p->next->next, cdt);
- }
- flip(se, cdt);
+ ebasel = add_diagonal(cdt, rcand->next, basel_sym);
+ }
+ else {
#ifdef DEBUG_CDT
- if (dbg_level > 2) {
- dump_cdt(cdt, "after flip");
- cdt_draw(cdt, "afer flip");
- validate_cdt(cdt, true);
- }
-#endif
+ if (dbg_level > 0) {
+ fprintf(stderr, "connecting lcand\n");
+ dump_se(sym(lcand), " se1=sym(lcand)");
+ dump_se(basel_sym->next, " se2=basel_sym->next");
}
+#endif
+ ebasel = add_diagonal(cdt, basel_sym->next, sym(lcand));
}
+ basel = &ebasel->symedges[0];
+ basel_sym = &ebasel->symedges[1];
+ BLI_assert(basel_sym->face == cdt->outer_face);
+#ifdef DEBUG_CDT
+ if (dbg_level > 2) {
+ cdt_draw(cdt, "after adding new crossedge");
+ // dump_cdt(cdt, "after adding new crossedge");
+ }
+#endif
}
+ *r_le = ldo;
+ *r_re = rdo;
+ BLI_assert(sym(ldo)->face == cdt->outer_face && rdo->face == cdt->outer_face);
}
-/**
- * Splits e at lambda and returns a #SymEdge with new vert as its vert.
- * The two opposite triangle vertices to e are connect to new point.
- * <pre>
- * /\ /\
- * /f|\ / |\
- * / |j\ / | \
- * / | i\ / k| \
- * . | . -> . l_ p m_.
- * \g | / \ | /
- * \ |h/ \ | /
- * \e|/ \ e|/
- *
- * t1 = {e, f, g}; t2 = {h, i, j};
- * t1' = {e, l.sym, g}; t2' = {h, m.sym, e'.sym}
- * t3 = {k, f, l}; t4 = {m, i, j}
- * </pre>
- */
-static CDTVert *insert_point_in_edge(CDT_state *cdt, SymEdge *e, double lambda)
+/* Guibas-Stolfi Divide-and_Conquer algorithm. */
+static void dc_triangulate(CDT_state *cdt, SiteInfo *sites, int nsites)
{
- SymEdge *f, *g, *h, *i, *j, *k;
- CDTEdge *ke;
- CDTVert *p;
- Stack stack;
- /* Split e at lambda. */
-
- f = e->next;
- g = f->next;
- BLI_assert(g->next == e);
- j = sym(e);
- h = j->next;
- i = h->next;
- BLI_assert(i->next == j);
-
- ke = split_edge(cdt, e, lambda);
- k = &ke->symedges[0];
- p = k->vert;
+ int i, j, n;
+ SymEdge *le, *re;
- add_diagonal(cdt, g, k);
- add_diagonal(cdt, sym(e), i);
-
- stack = NULL;
- if (!is_border_edge(f->edge, cdt)) {
- push(&stack, f, cdt);
- }
- if (!is_border_edge(g->edge, cdt)) {
- push(&stack, g, cdt);
- }
- if (!is_border_edge(h->edge, cdt)) {
- push(&stack, h, cdt);
+ /* Compress sites in place to eliminated verts that merge to others. */
+ i = 0;
+ j = 0;
+ while (j < nsites) {
+ /* Invariante: sites[0..i-1] have non-merged verts from 0..(j-1) in them. */
+ sites[i] = sites[j++];
+ if (sites[i].v->merge_to_index < 0) {
+ i++;
+ }
}
- if (!is_border_edge(i->edge, cdt)) {
- push(&stack, i, cdt);
+ n = i;
+ if (n == 0) {
+ return;
}
- flip_edges(k->vert, &stack, cdt);
- return p;
+ dc_tri(cdt, sites, 0, n, &le, &re);
}
/**
- * Inserts p inside e's triangle and connects the three cornders
- * of the triangle to the new point. Returns a SymEdge that has
- * new point as its point.
- * <pre>
- * * *
- * *g * * .j*
- * * * * . *
- * * p * -> * 1. p . 3*
- * * * * . . *
- * * e f* * . h 2 i . *
- * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * </pre>
+ * Do a Delaunay Triangulation of the points in cdt->vert_array.
+ * This is only a first step in the Constrained Delaunay triangulation,
+ * because it doesn't yet deal with the segment constraints.
+ * The algorithm used is the Divide & Conquer algorithm from the
+ * Guibas-Stolfi "Primitives for the Manipulation of General Subdivision
+ * and the Computation of Voronoi Diagrams" paper.
+ * The data structure here is similar to but not exactly the same as
+ * the quad-edge structure described in that paper.
+ * The incircle and ccw tests are done using Shewchuk's exact
+ * primitives (see below), so that this routine is robust.
+ *
+ * As a preprocessing step, we want to merge all vertices that are
+ * within cdt->epsilon of each other. This is accomplished by lexicographically
+ * sorting the coordinates first (which is needed anyway for the D&C algorithm).
+ * The CDTVerts with merge_to_index not equal to -1 are after this regarded
+ * as having been merged into the vertex with the corresponding index.
*/
-static CDTVert *insert_point_in_face(CDT_state *cdt, SymEdge *e, const double p[2])
+static void initial_triangulation(CDT_state *cdt)
{
- SymEdge *f, *g, *h, *i, *j;
- SymEdge *esym, *fsym, *gsym, *hsym, *isym, *jsym;
- CDTVert *v;
- CDTEdge *he, *ie, *je;
- CDTFace *t1, *t2, *t3;
- Stack stack;
+ int i, j, n;
+ SiteInfo *sites;
+ double *ico, *jco;
+ double xend, yend, xcur;
+ double epsilon = cdt->epsilon;
+ double epsilon_squared = cdt->epsilon_squared;
+#ifdef SJF_WAY
+ CDTEdge *e;
+ CDTVert *va, *vb;
+#endif
#ifdef DEBUG_CDT
int dbg_level = 0;
if (dbg_level > 0) {
- fprintf(stderr, "insert point in face, p=(%.3f,%.3f)\n", F2(p));
- dump_se_cycle(e, "insert face", 20);
+ fprintf(stderr, "\nINITIAL TRIANGULATION\n\n");
}
#endif
- f = e->next;
- g = f->next;
- esym = sym(e);
- fsym = sym(f);
- gsym = sym(g);
- t1 = e->face;
- t2 = add_cdtface(cdt);
- t3 = add_cdtface(cdt);
-
- v = add_cdtvert(cdt, p[0], p[1]);
- he = add_cdtedge(cdt, e->vert, v, t1, t2);
- h = &he->symedges[0];
- hsym = &he->symedges[1];
- ie = add_cdtedge(cdt, f->vert, v, t2, t3);
- i = &ie->symedges[0];
- isym = &ie->symedges[1];
- je = add_cdtedge(cdt, g->vert, v, t3, t1);
- j = &je->symedges[0];
- jsym = &je->symedges[1];
-
- e->next = i;
- i->next = hsym;
- hsym->next = e;
- e->face = t2;
-
- f->next = j;
- j->next = isym;
- isym->next = f;
- f->face = t3;
-
- g->next = h;
- h->next = jsym;
- jsym->next = g;
- g->face = t1;
-
- e->rot = h;
- i->rot = esym;
- hsym->rot = isym;
-
- f->rot = i;
- j->rot = fsym;
- isym->rot = jsym;
-
- g->rot = j;
- h->rot = gsym;
- jsym->rot = hsym;
-
- calc_face_centroid(e);
- calc_face_centroid(f);
- calc_face_centroid(g);
-
+ /* First sort the vertices by lexicographic order of their
+ * coordinates, breaking ties by putting earlier original-index
+ * vertices first.
+ */
+ n = cdt->vert_array_len;
+ if (n <= 1) {
+ return;
+ }
+ sites = MEM_malloc_arrayN(n, sizeof(SiteInfo), __func__);
+ for (i = 0; i < n; i++) {
+ sites[i].v = cdt->vert_array[i];
+ sites[i].orig_index = i;
+ }
+ qsort(sites, n, sizeof(SiteInfo), site_lexicographic_cmp);
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
- fprintf(stderr, "after initial insert:\n");
- dump_se_cycle(e, "e", 20);
- dump_se_cycle(f, "f", 20);
- dump_se_cycle(g, "g", 20);
- if (dbg_level > 2) {
- dump_cdt(cdt, "after initial insert, before flip");
- cdt_draw(cdt, "after initial insert, before flip");
- validate_cdt(cdt, true);
+ if (dbg_level > 0) {
+ fprintf(stderr, "after sorting\n");
+ for (i = 0; i < n; i++) {
+ fprintf(stderr, "%d: orig index: %d, (%f,%f)\n", i, sites[i].orig_index, F2(sites[i].v->co));
}
}
#endif
- stack = NULL;
- if (!is_border_edge(e->edge, cdt)) {
- push(&stack, e, cdt);
- }
- if (!is_border_edge(f->edge, cdt)) {
- push(&stack, f, cdt);
- }
- if (!is_border_edge(g->edge, cdt)) {
- push(&stack, g, cdt);
+ /* Now dedup according to user-defined epsilon.
+ * We will merge a vertex into an earlier-indexed vertex
+ * that is within epsilon (Euclidean distance).
+ * Merges may cascade. So we may end up merging two things
+ * that are farther than epsilon by transitive merging. Oh well.
+ * Assume that merges are rare, so use simple searches in the
+ * lexicographic ordering - likely we will soon hit y's with
+ * the same x that are farther away than epsilon, and then
+ * skipping ahead to the next biggest x, are likely to soon
+ * find one of those farther away than epsilon.
+ */
+ for (i = 0; i < n - 1; i++) {
+ ico = sites[i].v->co;
+ /* Start j at next place that has both x and y coords within epsilon. */
+ xend = ico[0] + epsilon;
+ yend = ico[1] + epsilon;
+ j = i + 1;
+ while (j < n) {
+ jco = sites[j].v->co;
+ if (jco[0] > xend) {
+ break; /* No more j's to process. */
+ }
+ else if (jco[1] > yend) {
+ /* Get past any string of v's with the same x and too-big y. */
+ xcur = jco[0];
+ while (++j < n) {
+ if (sites[j].v->co[0] > xcur) {
+ break;
+ }
+ }
+ BLI_assert(j == n || sites[j].v->co[0] > xcur);
+ if (j == n) {
+ break;
+ }
+ jco = sites[j].v->co;
+ if (jco[0] > xend || jco[1] > yend) {
+ break;
+ }
+ }
+ /* When here, vertex i and j are within epsilon by box test.
+ * The Euclidean distance test is stricter, so need to do it too, now.
+ */
+ BLI_assert(j < n && jco[0] <= xend && jco[1] <= yend);
+ if (len_squared_v2v2_db(ico, jco) <= epsilon_squared) {
+ sites[j].v->merge_to_index = (sites[i].v->merge_to_index == -1) ?
+ sites[i].orig_index :
+ sites[i].v->merge_to_index;
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr,
+ "merged orig vert %d to %d\n",
+ sites[j].orig_index,
+ sites[j].v->merge_to_index);
+ }
+#endif
+ }
+ j++;
+ }
}
- flip_edges(v, &stack, cdt);
- return v;
+ /* Now add non-dup vertices into triangulation in lexicographic order. */
+
+ dc_triangulate(cdt, sites, n);
+ MEM_freeN(sites);
+}
+
+/** Use LinkNode linked list as stack of SymEdges, allocating from cdt->listpool. */
+typedef LinkNode *Stack;
+
+BLI_INLINE void push(Stack *stack, SymEdge *se, CDT_state *cdt)
+{
+ BLI_linklist_prepend_pool(stack, se, cdt->listpool);
+}
+
+BLI_INLINE SymEdge *pop(Stack *stack, CDT_state *cdt)
+{
+ return (SymEdge *)BLI_linklist_pop_pool(stack, cdt->listpool);
+}
+
+BLI_INLINE bool is_empty(Stack *stack)
+{
+ return *stack == NULL;
}
/**
@@ -1347,12 +1024,16 @@ static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se)
SymEdge *ss, *first, *cse;
CDTVert *a, *b, *c, *v;
CDTEdge *ebc, *eca;
- const double epsilon = cdt->epsilon;
int count;
#ifdef DEBUG_CDT
SymEdge *last;
const int dbg_level = 0;
+#endif
+ if (se->face == cdt->outer_face || sym(se)->face == cdt->outer_face) {
+ return;
+ }
+#ifdef DEBUG_CDT
if (dbg_level > 0) {
fprintf(stderr, "retriangulate");
dump_se_cycle(se, "poly ", 1000);
@@ -1391,7 +1072,7 @@ static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se)
#endif
for (ss = first->next; ss != se; ss = ss->next) {
v = ss->vert;
- if (!delaunay_check(a, b, c, v, epsilon)) {
+ if (incircle(a->co, b->co, c->co, v->co) > 0.0) {
c = v;
cse = ss;
#ifdef DEBUG_CDT
@@ -1440,50 +1121,6 @@ static void re_delaunay_triangulate(CDT_state *cdt, SymEdge *se)
}
/**
- * Add a constrained point to cdt structure, and return the corresponding CDTVert*.
- * May not be at exact coords given, because it can be merged with an existing vertex
- * or moved to an existing edge (which could be a triangulation edge, not just a constraint one)
- * if the point is within cdt->epsilon of those other elements.
- *
- * input_id will be added to the list of input_ids for the returned CDTVert (don't use -1 for id).
- *
- * Assumes cdt has been initialized, with min/max bounds that contain coords.
- * Assumes that #BLI_constrained_delaunay_get_output has not been called yet.
- */
-static CDTVert *add_point_constraint(CDT_state *cdt, const double coords[2], int input_id)
-{
- LocateResult lr;
- CDTVert *v;
-#ifdef DEBUG_CDT
- const int dbg_level = 0;
-#endif
-
- BLI_assert(!cdt->output_prepared);
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "add point constraint (%.3f,%.3f), id=%d\n", F2(coords), input_id);
- }
-#endif
- lr = locate_point(cdt, coords);
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, " locate result has loc_kind %u\n", lr.loc_kind);
- }
-#endif
- if (lr.loc_kind == OnVert) {
- v = lr.se->vert;
- }
- else if (lr.loc_kind == OnEdge) {
- v = insert_point_in_edge(cdt, lr.se, lr.edge_lambda);
- }
- else {
- v = insert_point_in_face(cdt, lr.se, coords);
- }
- add_to_input_ids(&v->input_ids, input_id, cdt);
- return v;
-}
-
-/**
* Add a constrained edge between v1 and v2 to cdt structure.
* This may result in a number of #CDTEdges created, due to intersections
* and partial overlaps with existing cdt vertices and edges.
@@ -1505,11 +1142,11 @@ static void add_edge_constraint(
SymEdge *t, *tstart, *tout, *tnext;
SymEdge *se;
CDTEdge *edge;
- int ccw1, ccw2, isect;
- int i, search_count, visit;
+ int isect;
+ double orient1, orient2;
+ int i, search_count;
double curco[2];
double lambda;
- const double epsilon = cdt->epsilon;
bool done, state_through_vert;
LinkNodePair edge_list = {NULL, NULL};
typedef struct CrossData {
@@ -1523,7 +1160,7 @@ static void add_edge_constraint(
CrossData *cd;
BLI_array_staticdeclare(crossings, 128);
#ifdef DEBUG_CDT
- const int dbg_level = 0;
+ int dbg_level = 0;
#endif
/* Find path through structure from v1 to v2 and record how we got there in crossings.
@@ -1564,6 +1201,10 @@ static void add_edge_constraint(
#ifdef DEBUG_CDT
if (dbg_level > 0) {
vse2 = v2->symedge;
+ if (dbg_level > 2) {
+ // dump_cdt(cdt, "before insert_segment");
+ cdt_draw(cdt, "before insert segment");
+ }
fprintf(stderr, "\ninsert_segment %d\n", input_id);
dump_v(v1, " 1");
dump_v(v2, " 2");
@@ -1571,9 +1212,6 @@ static void add_edge_constraint(
dump_se(vse1, " se1");
dump_se(vse2, " se2");
}
- if (dbg_level > 2) {
- dump_cdt(cdt, "before insert_segment");
- }
}
#endif
if (v1 == v2) {
@@ -1600,7 +1238,7 @@ static void add_edge_constraint(
cdata.vert = v2;
BLI_array_append(crossings, cdata);
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
+ if (dbg_level > 0) {
fprintf(stderr, "special one segment case\n");
dump_se(t, " ");
}
@@ -1611,10 +1249,6 @@ static void add_edge_constraint(
t = t->rot;
} while (t != tstart);
if (!done) {
- /* To prevent infinite loop in the face of epsilon tests that might lead us back to
- * an already-visited (vertex, face) pair, use visit indices.
- */
- visit = ++cdt->visit_count;
state_through_vert = true;
done = false;
t = vse1;
@@ -1636,9 +1270,6 @@ static void add_edge_constraint(
dump_se_cycle(t, "current t ", 4);
}
#endif
- BLI_assert(t->vert->visit_index != visit || t->face->visit_index != visit);
- t->vert->visit_index = visit;
- t->face->visit_index = visit;
if (state_through_vert) {
/* Invariant: ray vcur--v2 contains t->vert. */
cdata.in = (BLI_array_len(crossings) == 0) ? NULL : t;
@@ -1648,7 +1279,7 @@ static void add_edge_constraint(
BLI_array_append(crossings, cdata);
if (t->vert == v2) {
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
+ if (dbg_level > 1) {
fprintf(stderr, "found v2, so done\n");
}
#endif
@@ -1661,20 +1292,18 @@ static void add_edge_constraint(
do {
va = t->next->vert;
vb = t->next->next->vert;
- ccw1 = CCW_test(t->vert->co, va->co, v2->co, epsilon);
- ccw2 = CCW_test(t->vert->co, vb->co, v2->co, epsilon);
+ orient1 = orient2d(t->vert->co, va->co, v2->co);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "non-final through vert case\n");
dump_v(va, " va");
dump_v(vb, " vb");
- fprintf(stderr, "ccw1=%d, ccw2=%d\n", ccw1, ccw2);
+ fprintf(stderr, "orient1=%g\n", orient1);
}
#endif
- if (ccw1 == 0 && in_line(t->vert->co, va->co, v2->co, epsilon) &&
- va->visit_index != visit) {
+ if (orient1 == 0.0 && in_line(t->vert->co, va->co, v2->co)) {
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
+ if (dbg_level > 1) {
fprintf(stderr, "ray goes through va\n");
}
#endif
@@ -1683,30 +1312,35 @@ static void add_edge_constraint(
t = t->next;
break;
}
- else if (ccw2 == 0 && in_line(t->vert->co, vb->co, v2->co, epsilon) &&
- vb->visit_index != visit) {
+ else if (t->face != cdt->outer_face) {
+ orient2 = orient2d(t->vert->co, vb->co, v2->co);
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "ray goes through vb\n");
+ if (dbg_level > 1) {
+ fprintf(stderr, "orient2=%g\n", orient2);
}
#endif
- state_through_vert = true;
- t = t->next->next;
- tout = sym(t);
- break;
- }
- else if (ccw1 > 0 && ccw2 < 0 &&
- (t->next->vert->visit_index != visit ||
- t->next->face->visit_index != visit)) {
+ if (orient2 == 0.0 && in_line(t->vert->co, vb->co, v2->co)) {
#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "segment intersects\n");
+ if (dbg_level > 1) {
+ fprintf(stderr, "ray goes through vb\n");
+ }
+#endif
+ state_through_vert = true;
+ t = t->next->next;
+ tout = sym(t);
+ break;
}
+ else if (orient1 > 0.0 && orient2 < 0.0) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 1) {
+ fprintf(stderr, "segment intersects\n");
+ }
#endif
- state_through_vert = false;
- tout = t;
- t = t->next;
- break;
+ state_through_vert = false;
+ tout = t;
+ t = t->next;
+ break;
+ }
}
t = t->rot;
#ifdef DEBUG_CDT
@@ -1715,57 +1349,13 @@ static void add_edge_constraint(
}
#endif
} while (t != tstart);
- if (tout == NULL) {
- /* With exact arithmetic this shouldn't happen, but maybe the epsilon tests made it so
- * that we want to go back to a previous vertex.
- * As desperation measure, pick unvisited vertex that is closest in line with
- * destination.
- */
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "add_edge_constraint desperation search\n");
- }
-#endif
- SymEdge *bestt = NULL;
- double dot, bestdot = -2.0;
- double dir_tv_v2[2], dir_tvnext_v2[2];
- sub_v2_v2v2_db(dir_tv_v2, v2->co, t->vert->co);
- do {
- if (t->next->vert->visit_index != visit) {
- sub_v2_v2v2_db(dir_tvnext_v2, v2->co, t->next->vert->co);
- dot = dot_v2v2_db(dir_tv_v2, dir_tvnext_v2);
- if (dot > bestdot) {
- bestdot = dot;
- bestt = t->next;
- }
- }
- t = t->rot;
- } while (t != tstart);
- if (bestt == NULL) {
- /* No unvisited place to go! Give up on adding this edge constraint. */
-#ifdef DEBUG_CDT
- fprintf(stderr, "could not add edge constraint\n");
-#endif
- return;
- }
- else {
-#ifdef DEBUG_CDT
- if (dbg_level > 0) {
- fprintf(stderr, "add_edge_constraint desperation search chose to go through\n");
- dump_v(bestt->vert, "desperation vert");
- }
-#endif
- tout = bestt;
- t = t->next;
- }
- }
+ BLI_assert(tout != NULL);
crossings[BLI_array_len(crossings) - 1].out = tout;
}
}
else { /* State is "through edge", not "through vert" */
/* Invariant: ray v1--v2 intersects segment t->edge, not at either end.
* and t->face is the face we have just passed through.
- * Whatever we make t next should not have both vert and face visited.
*/
va = t->vert;
vb = t->next->vert;
@@ -1784,19 +1374,41 @@ static void add_edge_constraint(
}
#endif
isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, curco, v2->co, &lambda, NULL);
- if (isect != ISECT_LINE_LINE_CROSS) {
- /* Shouldn't happen. Just pick something. */
+ if (isect == ISECT_LINE_LINE_NONE || isect == ISECT_LINE_LINE_EXACT) {
+ /* The orient tests say that there is an intersection between
+ * va and vb, but the inexect isect routine has either put the
+ * intersection exactly on one of the endpoints or just outside
+ * one of them.
+ * Or this is an exact intersection at one of the curco / v2 ends.
+ * If lambda is outside of range, move the intersection to somewhere
+ * just inside the segment.
+ * Could also snap to an endpoint and redo this as a "through vert"
+ * case, but the short edge will be cleaned up later and this seems
+ * less risky to get into "impossible" cases.
+ */
+ if (lambda <= 0.0) {
+ lambda = 4.0 * (double)FLT_EPSILON;
+ }
+ else if (lambda >= 1.0) {
+ lambda = 1.0 - 4.0 * (double)FLT_EPSILON;
+ }
+ }
+ if (isect == ISECT_LINE_LINE_COLINEAR) {
#ifdef DEBUG_CDT
if (dbg_level > 1) {
- fprintf(stderr, "add_edge_constraint no intersect found, using lambda = 0.5\n");
+ fprintf(stderr, "intersect is collinear, treating as through vert\n");
}
+ dump_v(va, "va");
#endif
- lambda = 0.5;
+ state_through_vert = true;
+ continue;
}
#ifdef DEBUG_CDT
+ interp_v2_v2v2_db(curco, va->co, vb->co, lambda);
if (dbg_level > 0) {
- fprintf(stderr, "intersect point at %f along va--vb\n", lambda);
- if (dbg_level == 1) {
+ fprintf(stderr, "intersect point at lambda=%.17g along va--vb\n", lambda);
+ fprintf(stderr, "which is (%g,%g)\n", F2(curco));
+ if (dbg_level > 1) {
dump_v(va, " va");
dump_v(vb, " vb");
}
@@ -1817,15 +1429,15 @@ static void add_edge_constraint(
/* 'tout' is 'symedge' from 'va' to third vertex, 'vc'. */
BLI_assert(tout->vert == va);
vc = tout->next->vert;
- ccw1 = CCW_test(curco, v2->co, vc->co, epsilon);
+ orient1 = orient2d(curco, v2->co, vc->co);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "now searching with third vertex ");
dump_v(vc, "vc");
- fprintf(stderr, "ccw(vcur, v2, vc) = %d\n", ccw1);
+ fprintf(stderr, "orient2d(vcur, v2, vc) = %g\n", orient1);
}
#endif
- if (ccw1 == -1 && (vc->visit_index != visit || tout->next->face->visit_index != visit)) {
+ if (orient1 < 0.0) {
/* vcur--v2 should intersect vb--vc. */
#ifdef DEBUG_CDT
if (dbg_level > 1) {
@@ -1835,7 +1447,7 @@ static void add_edge_constraint(
t = tout->next;
state_through_vert = false;
}
- else if (ccw1 == 1 && tout->face->visit_index != visit) {
+ else if (orient1 > 0.0) {
/* vcur--v2 should intersect va--vc. */
#ifdef DEBUG_CDT
if (dbg_level > 1) {
@@ -1845,7 +1457,7 @@ static void add_edge_constraint(
t = tout;
state_through_vert = false;
}
- else if (ccw1 == 0 && vc->visit_index != visit) {
+ else if (orient1 == 0.0) {
#ifdef DEBUG_CDT
if (dbg_level > 1) {
fprintf(stderr, "ccw==0 case, so going through or to vc\n");
@@ -1856,16 +1468,11 @@ static void add_edge_constraint(
}
else {
#ifdef DEBUG_CDT
- fprintf(stderr, "add_edge_constraint desperation search 2\n");
+ fprintf(stderr, "add_edge_constraint desperation search needed\n");
#endif
- if (tout->face->visit_index != visit) {
- /* Treat as if an intersection of va-vc. */
- t = tout;
- state_through_vert = false;
- }
}
}
- if (++search_count > 10000) {
+ if (++search_count > 1000000) {
fprintf(stderr, "infinite loop? bailing out\n");
BLI_assert(0); /* Catch these while developing. */
break;
@@ -2091,6 +1698,304 @@ static void dissolve_symedge(CDT_state *cdt, SymEdge *se)
delete_edge(cdt, se);
}
+/* Return true if we can merge se's vert into se->next's vert
+ * without making the area of any new triangle formed by doing
+ * that into a zero or negative area triangle.*/
+static bool can_collapse(const SymEdge *se)
+{
+ SymEdge *loop_se;
+ const double *co = se->next->vert->co;
+
+ for (loop_se = se->rot; loop_se != se && loop_se->rot != se; loop_se = loop_se->rot) {
+ if (orient2d(co, loop_se->next->vert->co, loop_se->rot->next->vert->co) <= 0.0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Merge one end of e onto the other, fixing up surrounding faces.
+ *
+ * General situation looks something like:
+ *
+ * c-----e
+ * / \ / \
+ * / \ / \
+ * a------b-----f
+ * \ / \ /
+ * \ / \ /
+ * d-----g
+ *
+ * where ab is the tiny edge. We want to merge a and b and delete edge ab.
+ * We don't want to change the coordinates of input vertices [We could revisit this
+ * in the future, as API def doesn't prohibit this, but callers will appreciate if they
+ * don't change.]
+ * Sometimes the collapse shouldn't happen because the triangles formed by the changed
+ * edges may end up with zero or negative area (see can_collapse, above).
+ * So don't choose a collapse direction that is not allowed or one that has an original vertex
+ * as origin and a non-original vertex as destination.
+ * If both collapse directions are allowed by that rule, picke the one with the lower original
+ * index.
+ *
+ * After merging, the faces abc and adb disappear (if they are not the outer face).
+ * Suppose we merge b onto a.
+ * Then edges cb and db are deleted. Face cbe becomes cae and face bdg becomes adg.
+ * Any other faces attached to b now have a in their place.
+ * We can do this by rotating edges round b, replacing their vert references with a.
+ * Similar statements can be made about what happens when a merges into b;
+ * in code below we'll swap a and b to make above lettering work for a b->a merge.
+ * Return the vert at the collapsed edge, if a collapse happens.
+ */
+static CDTVert *collapse_tiny_edge(CDT_state *cdt, CDTEdge *e)
+{
+ CDTVert *va, *vb;
+ SymEdge *ab_se, *ba_se, *bd_se, *bc_se, *ad_se, *ac_se;
+ SymEdge *bg_se, *be_se, *se, *gb_se, *ca_se;
+ bool can_collapse_a_to_b, can_collapse_b_to_a;
+#ifdef DEBUG_CDT
+ int dbg_level = 0;
+#endif
+
+ ab_se = &e->symedges[0];
+ ba_se = &e->symedges[1];
+ va = ab_se->vert;
+ vb = ba_se->vert;
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "\ncollapse_tiny_edge\n");
+ dump_se(&e->symedges[0], "tiny edge");
+ fprintf(stderr, "a = [%d], b = [%d]\n", va->index, vb->index);
+ validate_cdt(cdt, true, false, true);
+ }
+#endif
+ can_collapse_a_to_b = can_collapse(ab_se);
+ can_collapse_b_to_a = can_collapse(ba_se);
+ /* Now swap a and b if necessary and possible, so that from this point on we are collapsing b to
+ * a. */
+ if (va->index > vb->index || !can_collapse_b_to_a) {
+ if (can_collapse_a_to_b && !(is_original_vert(va, cdt) && !is_original_vert(vb, cdt))) {
+ SWAP(CDTVert *, va, vb);
+ ab_se = &e->symedges[1];
+ ba_se = &e->symedges[0];
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "swapped a and b\n");
+ }
+#endif
+ }
+ else {
+ /* Neither collapse direction is OK. */
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "neither collapse direction ok\n");
+ }
+#endif
+ return NULL;
+ }
+ }
+ bc_se = ab_se->next;
+ bd_se = ba_se->rot;
+ if (bd_se == ba_se) {
+ /* Shouldn't happen. Wire edge in outer face. */
+ fprintf(stderr, "unexpected wire edge\n");
+ return NULL;
+ }
+ vb->merge_to_index = va->merge_to_index == -1 ? va->index : va->merge_to_index;
+ vb->symedge = NULL;
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr,
+ "vb = v[%d] merges to va = v[%d], vb->merge_to_index=%d\n",
+ vb->index,
+ va->index,
+ vb->merge_to_index);
+ }
+#endif
+ /* First fix the vertex of intermediate triangles, like bgf. */
+ for (se = bd_se->rot; se != bc_se; se = se->rot) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ dump_se(se, "intermediate tri edge, setting vert to va");
+ }
+#endif
+ se->vert = va;
+ }
+ ad_se = sym(sym(bd_se)->rot);
+ ca_se = bc_se->next;
+ ac_se = sym(ca_se);
+ if (bd_se->rot != bc_se) {
+ bg_se = bd_se->rot;
+ be_se = sym(bc_se)->next;
+ gb_se = sym(bg_se);
+ }
+ else {
+ bg_se = NULL;
+ be_se = NULL;
+ }
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "delete bd, inputs to ad\n");
+ dump_se(bd_se, " bd");
+ dump_se(ad_se, " ad");
+ fprintf(stderr, "delete bc, inputs to ac\n");
+ dump_se(bc_se, " bc");
+ dump_se(ac_se, " ac");
+ fprintf(stderr, "delete ab\n");
+ dump_se(ab_se, " ab");
+ if (bg_se != NULL) {
+ fprintf(stderr, "fix up bg, be\n");
+ dump_se(bg_se, " bg");
+ dump_se(be_se, " be");
+ }
+ }
+#endif
+ add_list_to_input_ids(&ad_se->edge->input_ids, bd_se->edge->input_ids, cdt);
+ delete_edge(cdt, bd_se);
+ add_list_to_input_ids(&ac_se->edge->input_ids, bc_se->edge->input_ids, cdt);
+ delete_edge(cdt, sym(bc_se));
+ /* At this point we have this:
+ *
+ * c-----e
+ * / / \
+ * / / \
+ * a------b-----f
+ * \ \ /
+ * \ \ /
+ * d-----g
+ *
+ * Or, if there is not bg_se and be_se, like this:
+ *
+ * c
+ * /
+ * /
+ * a------b
+ * \
+ * \
+ * d
+ *
+ * (But we've already changed the vert field for bg, bf, ..., be to be va.)
+ */
+ if (bg_se != NULL) {
+ gb_se->next = ad_se;
+ ad_se->rot = bg_se;
+ ca_se->next = be_se;
+ be_se->rot = ac_se;
+ bg_se->vert = va;
+ be_se->vert = va;
+ }
+ else {
+ ca_se->next = ad_se;
+ ad_se->rot = ac_se;
+ }
+ /* Don't use delete_edge as it changes too much. */
+ ab_se->next = ab_se->rot = NULL;
+ ba_se->next = ba_se->rot = NULL;
+ if (va->symedge == ab_se) {
+ va->symedge = ac_se;
+ }
+ return va;
+}
+
+/*
+ * Check to see if e is tiny (length <= epsilon) and queue it if so.
+ */
+static void maybe_enqueue_small_feature(CDT_state *cdt, CDTEdge *e, LinkNodePair *tiny_edge_queue)
+{
+ SymEdge *se, *sesym;
+#ifdef DEBUG_CDT
+ int dbg_level = 0;
+
+ if (dbg_level > 0) {
+ fprintf(stderr, "\nmaybe_enqueue_small_features\n");
+ dump_se(&e->symedges[0], " se0");
+ }
+#endif
+
+ if (is_deleted_edge(e) || e->in_queue) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "returning because of e conditions\n");
+ }
+#endif
+ return;
+ }
+ se = &e->symedges[0];
+ sesym = &e->symedges[1];
+ if (len_squared_v2v2_db(se->vert->co, sesym->vert->co) <= cdt->epsilon_squared) {
+ BLI_linklist_append_pool(tiny_edge_queue, e, cdt->listpool);
+ e->in_queue = true;
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "Queue tiny edge\n");
+ }
+#endif
+ }
+}
+
+/* Consider all edges in rot ring around v for possible enqueing as small features .*/
+static void maybe_enqueue_small_features(CDT_state *cdt, CDTVert *v, LinkNodePair *tiny_edge_queue)
+{
+ SymEdge *se, *se_start;
+
+ se = se_start = v->symedge;
+ if (!se_start) {
+ return;
+ }
+ do {
+ maybe_enqueue_small_feature(cdt, se->edge, tiny_edge_queue);
+ } while ((se = se->rot) != se_start);
+}
+
+/* Collapse small edges (length <= epsilon) until no more exist.
+ */
+static void remove_small_features(CDT_state *cdt)
+{
+ double epsilon = cdt->epsilon;
+ LinkNodePair tiny_edge_queue = {NULL, NULL};
+ BLI_mempool *pool = cdt->listpool;
+ LinkNode *ln;
+ CDTEdge *e;
+ CDTVert *v_change;
+#ifdef DEBUG_CDT
+ int dbg_level = 0;
+
+ if (dbg_level > 0) {
+ fprintf(stderr, "\nREMOVE_SMALL_FEATURES, epsilon=%g\n", epsilon);
+ }
+#endif
+
+ if (epsilon == 0.0) {
+ return;
+ }
+
+ for (ln = cdt->edges; ln; ln = ln->next) {
+ e = (CDTEdge *)ln->link;
+ maybe_enqueue_small_feature(cdt, e, &tiny_edge_queue);
+ }
+
+ while (tiny_edge_queue.list != NULL) {
+ e = (CDTEdge *)BLI_linklist_pop_pool(&tiny_edge_queue.list, pool);
+ if (tiny_edge_queue.list == NULL) {
+ tiny_edge_queue.last_node = NULL;
+ }
+ e->in_queue = false;
+ if (is_deleted_edge(e)) {
+ continue;
+ }
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "collapse tiny edge\n");
+ dump_se(&e->symedges[0], "");
+ }
+#endif
+ v_change = collapse_tiny_edge(cdt, e);
+ if (v_change) {
+ maybe_enqueue_small_features(cdt, v_change, &tiny_edge_queue);
+ }
+ }
+}
+
/* Remove all non-constraint edges. */
static void remove_non_constraint_edges(CDT_state *cdt)
{
@@ -2176,7 +2081,7 @@ static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt)
e = sorted_edges[i].e;
se = &e->symedges[0];
dissolve = true;
- if (!edge_touches_frame(e)) {
+ if (true /*!edge_touches_frame(e)*/) {
fleft = se->face;
fright = sym(se)->face;
if (fleft != cdt->outer_face && fright != cdt->outer_face &&
@@ -2197,7 +2102,7 @@ static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt)
}
}
-static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constraints)
+static void remove_outer_edges_until_constraints(CDT_state *cdt)
{
LinkNode *fstack = NULL;
SymEdge *se, *se_start;
@@ -2207,27 +2112,28 @@ static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constrain
int dbg_level = 0;
if (dbg_level > 0) {
- fprintf(stderr, "remove_outer_edges, until_constraints=%d\n", remove_until_constraints);
+ fprintf(stderr, "remove_outer_edges_until_constraints\n");
}
#endif
cdt->outer_face->visit_index = visit;
-
- /* Find an f, not outer face, but touching outer face. */
- f = NULL;
- se_start = se = cdt->vert_array[0]->symedge;
+ /* Walk around outer face, adding faces on other side of dissolvable edges to stack. */
+ se_start = se = cdt->outer_face->symedge;
do {
- if (se->face != cdt->outer_face) {
- f = se->face;
- break;
+ if (!is_constrained_edge(se->edge)) {
+ fsym = sym(se)->face;
+ if (fsym->visit_index != visit) {
+#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr, "pushing f=%p from symedge ", fsym);
+ dump_se(se, "an outer edge");
+ }
+#endif
+ BLI_linklist_prepend_pool(&fstack, fsym, cdt->listpool);
+ }
}
- se = se->rot;
- } while (se != se_start);
- BLI_assert(f != NULL && f->symedge != NULL);
- if (f == NULL) {
- return;
- }
- BLI_linklist_prepend_pool(&fstack, f, cdt->listpool);
+ } while ((se = se->next) != se_start);
+
while (fstack != NULL) {
LinkNode *to_dissolve = NULL;
bool dissolvable;
@@ -2245,18 +2151,16 @@ static void remove_outer_edges(CDT_state *cdt, const bool remove_until_constrain
if (dbg_level > 0) {
fprintf(stderr, "top of loop, f=%p\n", f);
dump_se_cycle(f->symedge, "visit", 10000);
- dump_cdt(cdt, "cdt at top of loop");
+ if (dbg_level > 1) {
+ dump_cdt(cdt, "cdt at top of loop");
+ cdt_draw(cdt, "top of dissolve loop");
+ }
}
#endif
f->visit_index = visit;
se_start = se = f->symedge;
do {
- if (remove_until_constraints) {
- dissolvable = !is_constrained_edge(se->edge);
- }
- else {
- dissolvable = edge_touches_frame(se->edge);
- }
+ dissolvable = !is_constrained_edge(se->edge);
#ifdef DEBUG_CDT
if (dbg_level > 1) {
dump_se(se, "edge in f");
@@ -2306,15 +2210,20 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_
LinkNode *ln;
cdt->output_prepared = true;
+ if (cdt->edges == NULL) {
+ return;
+ }
/* Make sure all non-deleted faces have a symedge. */
for (ln = cdt->edges; ln; ln = ln->next) {
e = (CDTEdge *)ln->link;
- if (e->symedges[0].face->symedge == NULL) {
- e->symedges[0].face->symedge = &e->symedges[0];
- }
- if (e->symedges[1].face->symedge == NULL) {
- e->symedges[1].face->symedge = &e->symedges[1];
+ if (!is_deleted_edge(e)) {
+ if (e->symedges[0].face->symedge == NULL) {
+ e->symedges[0].face->symedge = &e->symedges[0];
+ }
+ if (e->symedges[1].face->symedge == NULL) {
+ e->symedges[1].face->symedge = &e->symedges[1];
+ }
}
}
#ifdef DEBUG_CDT
@@ -2335,19 +2244,20 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_
else if (output_type == CDT_CONSTRAINTS_VALID_BMESH) {
remove_non_constraint_edges_leave_valid_bmesh(cdt);
}
- else if (output_type == CDT_FULL || output_type == CDT_INSIDE) {
- remove_outer_edges(cdt, output_type == CDT_INSIDE);
+ else if (output_type == CDT_INSIDE) {
+ remove_outer_edges_until_constraints(cdt);
}
}
-#define NUM_BOUND_VERTS 4
-#define VERT_OUT_INDEX(v) ((v)->index - NUM_BOUND_VERTS)
-
-static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_type)
+static CDT_result *cdt_get_output(CDT_state *cdt,
+ const CDT_input *input,
+ const CDT_output_type output_type)
{
int i, j, nv, ne, nf, faces_len_total;
int orig_map_size, orig_map_index;
+ int *vert_to_output_map;
CDT_result *result;
+ CDTVert *v;
LinkNode *lne, *lnf, *ln;
SymEdge *se, *se_start;
CDTEdge *e;
@@ -2356,35 +2266,70 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t
prepare_cdt_for_output(cdt, output_type);
result = (CDT_result *)MEM_callocN(sizeof(*result), __func__);
+ if (cdt->vert_array_len == 0) {
+ return result;
+ }
- /* All verts except first NUM_BOUND_VERTS will be output. */
- nv = cdt->vert_array_len - NUM_BOUND_VERTS;
+ /* All verts without a merge_to_index will be output.
+ * vert_to_output_map[i] will hold the output vertex index
+ * corresponding to the vert in position i in cdt->vert_array.
+ * Since merging picked the leftmost-lowermost representative,
+ * that is not necessarily the same as the vertex with the lowest original
+ * index (i.e., index in cdt->vert_array), so we need two passes:
+ * one to get the non-merged-to vertices in vert_to_output_map,
+ * and a second to put in the merge targets for merged-to vertices.
+ */
+ vert_to_output_map = BLI_memarena_alloc(cdt->arena, (size_t)cdt->vert_array_len * sizeof(int *));
+ nv = 0;
+ for (i = 0; i < cdt->vert_array_len; i++) {
+ v = cdt->vert_array[i];
+ if (v->merge_to_index == -1) {
+ vert_to_output_map[i] = nv;
+ nv++;
+ }
+ }
if (nv <= 0) {
return result;
}
+ if (nv < cdt->vert_array_len) {
+ for (i = 0; i < input->verts_len; i++) {
+ v = cdt->vert_array[i];
+ if (v->merge_to_index != -1) {
+ add_to_input_ids(&cdt->vert_array[v->merge_to_index]->input_ids, i, cdt);
+ vert_to_output_map[i] = vert_to_output_map[v->merge_to_index];
+ }
+ }
+ }
result->verts_len = nv;
result->vert_coords = MEM_malloc_arrayN(nv, sizeof(result->vert_coords[0]), __func__);
/* Make the vertex "orig" map arrays, mapping output verts to lists of input ones. */
orig_map_size = 0;
- for (i = 0; i < nv; i++) {
- orig_map_size += BLI_linklist_count(cdt->vert_array[i + 4]->input_ids);
+ for (i = 0; i < cdt->vert_array_len; i++) {
+ if (cdt->vert_array[i]->merge_to_index == -1) {
+ orig_map_size += 1 + BLI_linklist_count(cdt->vert_array[i]->input_ids);
+ }
}
result->verts_orig_len_table = MEM_malloc_arrayN(nv, sizeof(int), __func__);
result->verts_orig_start_table = MEM_malloc_arrayN(nv, sizeof(int), __func__);
result->verts_orig = MEM_malloc_arrayN(orig_map_size, sizeof(int), __func__);
orig_map_index = 0;
- for (i = 0; i < nv; i++) {
- j = i + NUM_BOUND_VERTS;
- result->vert_coords[i][0] = (float)cdt->vert_array[j]->co[0];
- result->vert_coords[i][1] = (float)cdt->vert_array[j]->co[1];
- result->verts_orig_start_table[i] = orig_map_index;
- for (ln = cdt->vert_array[j]->input_ids; ln; ln = ln->next) {
- result->verts_orig[orig_map_index++] = POINTER_AS_INT(ln->link);
+ i = 0;
+ for (j = 0; j < cdt->vert_array_len; j++) {
+ v = cdt->vert_array[j];
+ if (v->merge_to_index == -1) {
+ result->vert_coords[i][0] = (float)v->co[0];
+ result->vert_coords[i][1] = (float)v->co[1];
+ result->verts_orig_start_table[i] = orig_map_index;
+ result->verts_orig[orig_map_index++] = j;
+ for (ln = v->input_ids; ln; ln = ln->next) {
+ result->verts_orig[orig_map_index++] = POINTER_AS_INT(ln->link);
+ }
+ result->verts_orig_len_table[i] = orig_map_index - result->verts_orig_start_table[i];
+ i++;
}
- result->verts_orig_len_table[i] = orig_map_index - result->verts_orig_start_table[i];
}
ne = 0;
@@ -2412,8 +2357,8 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t
for (lne = cdt->edges; lne; lne = lne->next) {
e = (CDTEdge *)lne->link;
if (!is_deleted_edge(e)) {
- result->edges[i][0] = VERT_OUT_INDEX(e->symedges[0].vert);
- result->edges[i][1] = VERT_OUT_INDEX(e->symedges[1].vert);
+ result->edges[i][0] = vert_to_output_map[e->symedges[0].vert->index];
+ result->edges[i][1] = vert_to_output_map[e->symedges[1].vert->index];
result->edges_orig_start_table[i] = orig_map_index;
for (ln = e->input_ids; ln; ln = ln->next) {
result->edges_orig[orig_map_index++] = POINTER_AS_INT(ln->link);
@@ -2462,7 +2407,7 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t
result->faces_start_table[i] = j;
se = se_start = f->symedge;
do {
- result->faces[j++] = VERT_OUT_INDEX(se->vert);
+ result->faces[j++] = se->vert->index;
se = se->next;
} while (se != se_start);
result->faces_len_table[i] = j - result->faces_start_table[i];
@@ -2478,28 +2423,72 @@ static CDT_result *cdt_get_output(CDT_state *cdt, const CDT_output_type output_t
return result;
}
+/**
+ * Calculate the Constrained Delaunay Triangulation of the 2d elements given in \a input.
+ *
+ * A Delaunay triangulation of a set of vertices is a triangulation where no triangle in the
+ * triangulation has a circumcircle that strictly contains another vertex. Delaunay triangulations
+ * are avoid long skinny triangles: they maximize the minimum angle of all triangles in the
+ * triangulation.
+ *
+ * A Constrained Delaunay Triangulation adds the requirement that user-provided line segments must
+ * appear as edges in the output (perhaps divided into several sub-segments). It is not required
+ * that the input edges be non-intersecting: this routine will calculate the intersections. This
+ * means that besides triangulating, this routine is also useful for general and robust 2d edge and
+ * face intersection.
+ *
+ * This routine also takes an epsilon parameter in the \a input. Input vertices closer than epsilon
+ * will be merged, and we collapse tiny edges (less than epsilon length) and skinny triangles
+ * (having an altitude of less than epsilon).
+ *
+ * The current initial Deluanay triangulation algorithm is the Guibas-Stolfi Divide and Conquer
+ * algorithm (see "Primitives for the Manipulation of General Subdivisions and the Computation of
+ * Voronoi Diagrams"). and uses Shewchuk's exact predicates to issues where numeric errors cause
+ * inconsistent geometric judgements. This is followed by inserting edge constraints (including the
+ * edges implied by faces) using the algorithms discussed in "Fully Dynamic Constrained Delaunay
+ * Triangulations" by Kallmann, Bieri, and Thalmann.
+ *
+ * \param input: points to a CDT_input struct which contains the vertices, edges, and faces to be
+ * triangulated. \param output_type: specifies which edges to remove after doing the triangulation.
+ * \return A pointer to an allocated CDT_result struct, which describes the triangulation in terms
+ * of vertices, edges, and faces, and also has tables to map output elements back to input
+ * elements. The caller must use BLI_delaunay_2d_cdt_free() on the result when done with it.
+ *
+ * See the header file BLI_delaunay_2d.h for details of the CDT_input and CDT_result structs and
+ * the CDT_output_type enum.
+ */
CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_type output_type)
{
int nv = input->verts_len;
int ne = input->edges_len;
int nf = input->faces_len;
- double epsilon = (double)input->epsilon;
- int i, f, v1, v2;
- int fedge_start, fedge_end;
- double minx, maxx, miny, maxy;
- float *xy;
- double vert_co[2];
+ int i, iv1, iv2, f, fedge_start, fedge_end;
CDT_state *cdt;
- CDT_result *result;
- CDTVert **verts;
- LinkNode *edge_list;
+ CDTVert *v1, *v2;
CDTEdge *face_edge;
SymEdge *face_symedge;
+ LinkNode *edge_list;
+ CDT_result *result;
+ static bool called_exactinit = false;
#ifdef DEBUG_CDT
int dbg_level = 0;
#endif
+ /* The exact orientation and incircle primitives need a one-time initialization of certain
+ * constants. */
+ if (!called_exactinit) {
+ exactinit();
+ called_exactinit = true;
+ }
#ifdef DEBUG_CDT
+ if (dbg_level > 0) {
+ fprintf(stderr,
+ "\n\nCDT CALC, nv=%d, ne=%d, nf=%d, eps=%g\n",
+ input->verts_len,
+ input->edges_len,
+ input->faces_len,
+ input->epsilon);
+ }
if (dbg_level == -1) {
write_cdt_input_to_file(input);
}
@@ -2514,77 +2503,43 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
return NULL;
}
- if (nv > 0) {
- minx = miny = DBL_MAX;
- maxx = maxy = -DBL_MAX;
- for (i = 0; i < nv; i++) {
- xy = input->vert_coords[i];
- if (xy[0] < minx) {
- minx = xy[0];
- }
- if (xy[0] > maxx) {
- maxx = xy[0];
- }
- if (xy[1] < miny) {
- miny = xy[1];
- }
- if (xy[1] > maxy) {
- maxy = xy[1];
- }
- }
- verts = (CDTVert **)MEM_mallocN(nv * sizeof(CDTVert *), "constrained delaunay");
- }
- else {
- minx = miny = maxx = maxy = 0;
- verts = NULL;
- }
-
- if (epsilon == 0.0) {
- epsilon = 1e-8;
- }
- cdt = cdt_init(minx, maxx, miny, maxy, epsilon);
- /* TODO: use a random permutation for order of adding the vertices. */
- for (i = 0; i < nv; i++) {
- vert_co[0] = (double)input->vert_coords[i][0];
- vert_co[1] = (double)input->vert_coords[i][1];
- verts[i] = add_point_constraint(cdt, vert_co, i);
+ cdt = new_cdt_init(input);
+ initial_triangulation(cdt);
#ifdef DEBUG_CDT
- if (dbg_level > 3) {
- char namebuf[60];
- sprintf(namebuf, "after point %d = (%f,%f)\n", i, vert_co[0], vert_co[1]);
- cdt_draw(cdt, namebuf);
- dump_cdt(cdt, namebuf);
- validate_cdt(cdt, true);
- }
-#endif
+ if (dbg_level > 0) {
+ validate_cdt(cdt, true, false, false);
}
+#endif
+
for (i = 0; i < ne; i++) {
- v1 = input->edges[i][0];
- v2 = input->edges[i][1];
- if (v1 < 0 || v1 >= nv || v2 < 0 || v2 >= nv) {
+ iv1 = input->edges[i][0];
+ iv2 = input->edges[i][1];
+ if (iv1 < 0 || iv1 >= nv || iv2 < 0 || iv2 >= nv) {
#ifdef DEBUG_CDT
- fprintf(stderr, "edge indices not valid: v1=%d, v2=%d, nv=%d\n", v1, v2, nv);
+ fprintf(stderr, "edge indices for e%d not valid: v1=%d, v2=%d, nv=%d\n", i, iv1, iv2, nv);
#endif
continue;
}
- add_edge_constraint(cdt, verts[v1], verts[v2], i, NULL);
+ v1 = cdt->vert_array[iv1];
+ v2 = cdt->vert_array[iv2];
+ if (v1->merge_to_index != -1) {
+ v1 = cdt->vert_array[v1->merge_to_index];
+ }
+ if (v2->merge_to_index != -1) {
+ v2 = cdt->vert_array[v2->merge_to_index];
+ }
+ add_edge_constraint(cdt, v1, v2, i, NULL);
#ifdef DEBUG_CDT
if (dbg_level > 3) {
char namebuf[60];
- sprintf(namebuf, "after edge constraint %d = (%d,%d)\n", i, v1, v2);
+ sprintf(namebuf, "after edge constraint %d = (%d,%d)\n", i, iv1, iv2);
cdt_draw(cdt, namebuf);
- dump_cdt(cdt, namebuf);
- validate_cdt(cdt, true);
+ // dump_cdt(cdt, namebuf);
+ validate_cdt(cdt, true, true, false);
}
#endif
}
-#ifdef DEBUG_CDT
- if (dbg_level > 2) {
- cdt_draw(cdt, "after edge constraints");
- dump_cdt(cdt, "after edge constraints");
- validate_cdt(cdt, true);
- }
-#endif
+
cdt->face_edge_offset = ne;
for (f = 0; f < nf; f++) {
int flen = input->faces_len_table[f];
@@ -2597,17 +2552,25 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
}
for (i = 0; i < flen; i++) {
int face_edge_id = cdt->face_edge_offset + fstart + i;
- v1 = input->faces[fstart + i];
- v2 = input->faces[fstart + ((i + 1) % flen)];
- if (v1 < 0 || v1 >= nv || v2 < 0 || v2 >= nv) {
+ iv1 = input->faces[fstart + i];
+ iv2 = input->faces[fstart + ((i + 1) % flen)];
+ if (iv1 < 0 || iv1 >= nv || iv2 < 0 || iv2 >= nv) {
#ifdef DEBUG_CDT
- fprintf(stderr, "face indices not valid: f=%d, v1=%d, v2=%d, nv=%d\n", f, v1, v2, nv);
+ fprintf(stderr, "face indices not valid: f=%d, iv1=%d, iv2=%d, nv=%d\n", f, iv1, iv2, nv);
#endif
continue;
}
- add_edge_constraint(cdt, verts[v1], verts[v2], face_edge_id, &edge_list);
+ v1 = cdt->vert_array[iv1];
+ v2 = cdt->vert_array[iv2];
+ if (v1->merge_to_index != -1) {
+ v1 = cdt->vert_array[v1->merge_to_index];
+ }
+ if (v2->merge_to_index != -1) {
+ v2 = cdt->vert_array[v2->merge_to_index];
+ }
+ add_edge_constraint(cdt, v1, v2, face_edge_id, &edge_list);
#ifdef DEBUG_CDT
- if (dbg_level > 1) {
+ if (dbg_level > 2) {
fprintf(stderr, "edges for edge %d:\n", i);
for (LinkNode *ln = edge_list; ln; ln = ln->next) {
CDTEdge *cdt_e = (CDTEdge *)ln->link;
@@ -2619,16 +2582,18 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
}
if (dbg_level > 2) {
cdt_draw(cdt, "after a face edge");
- dump_cdt(cdt, "after a face edge");
- validate_cdt(cdt, true);
+ if (dbg_level > 3) {
+ dump_cdt(cdt, "after a face edge");
+ }
+ validate_cdt(cdt, true, true, false);
}
#endif
if (i == 0) {
face_edge = (CDTEdge *)edge_list->link;
face_symedge = &face_edge->symedges[0];
- if (face_symedge->vert != verts[v1]) {
+ if (face_symedge->vert != v1) {
face_symedge = &face_edge->symedges[1];
- BLI_assert(face_symedge->vert == verts[v1]);
+ BLI_assert(face_symedge->vert == v1);
}
}
BLI_linklist_free_pool(edge_list, NULL, cdt->listpool);
@@ -2639,22 +2604,36 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty
}
#ifdef DEBUG_CDT
if (dbg_level > 0) {
- validate_cdt(cdt, true);
+ validate_cdt(cdt, true, true, false);
}
if (dbg_level > 1) {
- cdt_draw(cdt, "before cdt_get_output");
+ cdt_draw(cdt, "after adding edges and faces");
+ if (dbg_level > 2) {
+ dump_cdt(cdt, "after adding edges and faces");
+ }
}
#endif
- result = cdt_get_output(cdt, output_type);
+
+ if (cdt->epsilon > 0.0) {
+ remove_small_features(cdt);
+#ifdef DEBUG_CDT
+ if (dbg_level > 2) {
+ cdt_draw(cdt, "after collapse skinny triangles\n");
+ if (dbg_level > 3) {
+ dump_cdt(cdt, "after collapse skinny triangles\n");
+ }
+ }
+#endif
+ }
+
+ result = cdt_get_output(cdt, input, output_type);
#ifdef DEBUG_CDT
if (dbg_level > 0) {
cdt_draw(cdt, "final");
}
#endif
- if (verts) {
- MEM_freeN(verts);
- }
- cdt_free(cdt);
+
+ new_cdt_free(cdt);
return result;
}
@@ -2710,19 +2689,22 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result)
#ifdef DEBUG_CDT
-static const char *vertname(const CDTVert *v)
+ATTU static const char *vertname(const CDTVert *v)
{
static char vertnamebuf[20];
- if (v->index < 4) {
- sprintf(vertnamebuf, "[%c]", "ABCD"[v->index]);
- }
- else {
- sprintf(vertnamebuf, "[%d]", v->index - 4);
- }
+ sprintf(vertnamebuf, "[%d]", v->index);
return vertnamebuf;
}
+ATTU static const char *sename(const SymEdge *se)
+{
+ static char senamebuf[20];
+
+ sprintf(senamebuf, "{%x}", (POINTER_AS_UINT(se)) & 0xFFFF);
+ return senamebuf;
+}
+
static void dump_v(const CDTVert *v, const char *lab)
{
fprintf(stderr, "%s%s(%.3f,%.3f)\n", lab, vertname(v), F2(v->co));
@@ -2732,11 +2714,12 @@ static void dump_se(const SymEdge *se, const char *lab)
{
if (se->next) {
fprintf(stderr,
- "%s%s((%.3f,%.3f)->(%.3f,%.3f))\n",
+ "%s%s((%.3f,%.3f)->(%.3f,%.3f))",
lab,
vertname(se->vert),
F2(se->vert->co),
F2(se->next->vert->co));
+ fprintf(stderr, "%s\n", vertname(se->next->vert));
}
else {
fprintf(stderr, "%s%s((%.3f,%.3f)->NULL)\n", lab, vertname(se->vert), F2(se->vert->co));
@@ -2791,13 +2774,28 @@ static void dump_cdt_filtered(const CDT_state *cdt,
continue;
}
v = cdt->vert_array[i];
- fprintf(stderr, "%s %x: (%f,%f) symedge=%x\n", vertname(v), PL(v), F2(v->co), PL(v->symedge));
+ fprintf(stderr, "%s %x: (%f,%f) symedge=%x", vertname(v), PL(v), F2(v->co), PL(v->symedge));
+ if (v->merge_to_index == -1) {
+ fprintf(stderr, "\n");
+ }
+ else {
+ fprintf(stderr, " merge to %s\n", vertname(cdt->vert_array[v->merge_to_index]));
+ continue;
+ }
dump_id_list(v->input_ids, " ");
se = v->symedge;
cnt = 0;
if (se) {
fprintf(stderr, " edges out:\n");
do {
+ if (se->next == NULL) {
+ fprintf(stderr, " [NULL next/rot symedge, se=%x\n", PL(se));
+ break;
+ }
+ if (se->next->next == NULL) {
+ fprintf(stderr, " [NULL next-next/rot symedge, se=%x\n", PL(se));
+ break;
+ }
vother = sym(se)->vert;
fprintf(stderr, " %s (e=%x, se=%x)\n", vertname(vother), PL(se->edge), PL(se));
se = se->rot;
@@ -2839,15 +2837,13 @@ static void dump_cdt_filtered(const CDT_state *cdt,
continue;
}
if (f == cdt->outer_face) {
- fprintf(stderr, "outer");
- }
- else {
- fprintf(stderr, "%x: centroid (%f,%f)", PL(f), F2(f->centroid));
+ fprintf(stderr, "%x: outer", PL(f));
}
fprintf(stderr, " symedge=%x\n", PL(f->symedge));
dump_id_list(f->input_ids, " ");
}
fprintf(stderr, "\nOTHER\n");
+ fprintf(stderr, "outer_face=%x\n", PL(cdt->outer_face));
fprintf(
stderr, "minx=%f, maxx=%f, miny=%f, maxy=%f\n", cdt->minx, cdt->maxx, cdt->miny, cdt->maxy);
fprintf(stderr, "margin=%f\n", cdt->margin);
@@ -2895,6 +2891,37 @@ static bool reachable_filter(const CDT_state *cdt, int v_index, void *filter_dat
return false;
}
+static void set_min_max(CDT_state *cdt)
+{
+ int i;
+ double minx, maxx, miny, maxy;
+ double *co;
+
+ minx = miny = DBL_MAX;
+ maxx = maxy = -DBL_MAX;
+ for (i = 0; i < cdt->vert_array_len; i++) {
+ co = cdt->vert_array[i]->co;
+ if (co[0] < minx) {
+ minx = co[0];
+ }
+ if (co[0] > maxx) {
+ maxx = co[0];
+ }
+ if (co[1] < miny) {
+ miny = co[1];
+ }
+ if (co[1] > maxy) {
+ maxy = co[1];
+ }
+ }
+ if (minx != DBL_MAX) {
+ cdt->minx = minx;
+ cdt->miny = miny;
+ cdt->maxx = maxx;
+ cdt->maxy = maxy;
+ }
+}
+
static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const char *lab)
{
ReachableFilterData rfd;
@@ -2903,7 +2930,7 @@ static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const
dump_cdt_filtered(cdt, reachable_filter, &rfd, lab);
}
-/**
+/*
* Make an html file with svg in it to display the argument cdt.
* Mouse-overs will reveal the coordinates of vertices and edges.
* Constraint edges are drawn thicker than non-constraint edges.
@@ -2916,24 +2943,20 @@ static void dump_cdt_vert_neighborhood(CDT_state *cdt, int v, int maxdist, const
# define THICK_LINE 3
# define VERT_RADIUS 3
# define DRAW_VERT_LABELS 1
-static void cdt_draw(CDT_state *cdt, const char *lab)
+# define DRAW_EDGE_LABELS 0
+
+static void cdt_draw_region(
+ CDT_state *cdt, const char *lab, double minx, double miny, double maxx, double maxy)
{
static bool append = false;
FILE *f = fopen(DRAWFILE, append ? "a" : "w");
- double draw_margin = (cdt->maxx - cdt->minx + cdt->maxy - cdt->miny + 1) * 0.05;
- double minx = cdt->minx - draw_margin;
- double maxx = cdt->maxx + draw_margin;
- double miny = cdt->miny - draw_margin;
- double maxy = cdt->maxy + draw_margin;
- double width, height, aspect;
int view_width, view_height;
- double scale;
+ double width, height, aspect, scale;
LinkNode *ln;
CDTVert *v, *u;
CDTEdge *e;
int i, strokew;
- /* Note: to debug a small area: assign custom min's/max's here. */
width = maxx - minx;
height = maxy - miny;
aspect = height / width;
@@ -2979,10 +3002,23 @@ static void cdt_draw(CDT_state *cdt, const char *lab)
fprintf(f, " <title>%s", vertname(u));
fprintf(f, "%s</title>\n", vertname(v));
fprintf(f, "</line>\n");
+# if DRAW_EDGE_LABELS
+ fprintf(f,
+ "<text x=\"%f\" y=\"%f\" font-size=\"small\">",
+ SX(0.5 * (u->co[0] + v->co[0])),
+ SY(0.5 * (u->co[1] + v->co[1])));
+ fprintf(f, "%s", vertname(u));
+ fprintf(f, "%s", vertname(v));
+ fprintf(f, "%s", sename(&e->symedges[0]));
+ fprintf(f, "%s</text>\n", sename(&e->symedges[1]));
+# endif
}
- i = cdt->output_prepared ? NUM_BOUND_VERTS : 0;
+ i = 0;
for (; i < cdt->vert_array_len; i++) {
v = cdt->vert_array[i];
+ if (v->merge_to_index != -1) {
+ continue;
+ }
fprintf(f,
"<circle fill=\"black\" cx=\"%f\" cy=\"%f\" r=\"%d\">\n",
SX(v->co[0]),
@@ -3006,6 +3042,25 @@ static void cdt_draw(CDT_state *cdt, const char *lab)
# undef SY
}
+static void cdt_draw(CDT_state *cdt, const char *lab)
+{
+ double draw_margin, minx, maxx, miny, maxy;
+
+ set_min_max(cdt);
+ draw_margin = (cdt->maxx - cdt->minx + cdt->maxy - cdt->miny + 1) * 0.05;
+ minx = cdt->minx - draw_margin;
+ maxx = cdt->maxx + draw_margin;
+ miny = cdt->miny - draw_margin;
+ maxy = cdt->maxy + draw_margin;
+ cdt_draw_region(cdt, lab, minx, miny, maxx, maxy);
+}
+
+static void cdt_draw_vertex_region(CDT_state *cdt, int v, double dist, const char *lab)
+{
+ const double *co = cdt->vert_array[v]->co;
+ cdt_draw_region(cdt, lab, co[0] - dist, co[1] - dist, co[0] + dist, co[1] + dist);
+}
+
# define CDTFILE "/tmp/cdtinput.txt"
static void write_cdt_input_to_file(const CDT_input *inp)
{
@@ -3029,16 +3084,18 @@ static void write_cdt_input_to_file(const CDT_input *inp)
}
# ifndef NDEBUG /* Only used in assert. */
-/**
+/*
* Is a visible from b: i.e., ab crosses no edge of cdt?
* If constrained is true, consider only constrained edges as possible crossers.
* In any case, don't count an edge ab itself.
+ * Note: this is an expensive test if there are a lot of edges.
*/
static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, const CDT_state *cdt)
{
const LinkNode *ln;
const CDTEdge *e;
const SymEdge *se, *senext;
+ double lambda, mu;
int ikind;
for (ln = cdt->edges; ln; ln = ln->next) {
@@ -3055,13 +3112,17 @@ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, con
continue;
}
ikind = isect_seg_seg_v2_lambda_mu_db(
- a->co, b->co, se->vert->co, senext->vert->co, NULL, NULL);
+ a->co, b->co, se->vert->co, senext->vert->co, &lambda, &mu);
if (ikind != ISECT_LINE_LINE_NONE) {
if (ikind == ISECT_LINE_LINE_COLINEAR) {
/* TODO: special test here for overlap. */
continue;
}
- return false;
+ /* Allow an intersection very near or at ends, to allow for numerical error. */
+ if (lambda > FLT_EPSILON && (1.0 - lambda) > FLT_EPSILON && mu > FLT_EPSILON &&
+ (1.0 - mu) > FLT_EPSILON) {
+ return false;
+ }
}
}
return true;
@@ -3069,7 +3130,7 @@ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, con
# endif
# ifndef NDEBUG /* Only used in assert. */
-/**
+/*
* Check that edge ab satisfies constrained delaunay condition:
* That is, for all non-constraint, non-border edges ab,
* (1) ab is visible in the constraint graph; and
@@ -3078,7 +3139,7 @@ static bool is_visible(const CDTVert *a, const CDTVert *b, bool constrained, con
* The argument 'se' specifies ab by: a is se's vert and b is se->next's vert.
* Return true if check is OK.
*/
-static bool is_delaunay_edge(const SymEdge *se, const double epsilon)
+static bool is_delaunay_edge(const SymEdge *se)
{
int i;
CDTVert *a, *b, *c;
@@ -3099,7 +3160,7 @@ static bool is_delaunay_edge(const SymEdge *se, const double epsilon)
b = curse->next->vert;
c = curse->next->next->vert;
for (ss = curse->rot; ss != curse; ss = ss->rot) {
- ok[i] |= delaunay_check(a, b, c, ss->next->vert, epsilon);
+ ok[i] |= incircle(a->co, b->co, c->co, ss->next->vert->co) <= 0.0;
}
}
return ok[0] || ok[1];
@@ -3113,48 +3174,29 @@ static bool plausible_non_null_ptr(void *p)
}
# endif
-static void validate_face_centroid(SymEdge *se)
-{
- SymEdge *senext;
-# ifndef NDEBUG
- double *centroidp = se->face->centroid;
-# endif
- double c[2];
- int count;
- copy_v2_v2_db(c, se->vert->co);
- BLI_assert(reachable(se->next, se, 100));
- count = 1;
- for (senext = se->next; senext != se; senext = senext->next) {
- add_v2_v2_db(c, senext->vert->co);
- count++;
- }
- c[0] /= count;
- c[1] /= count;
- BLI_assert(fabs(c[0] - centroidp[0]) < 1e-8 && fabs(c[1] - centroidp[1]) < 1e-8);
-}
-
-static void validate_cdt(CDT_state *cdt, bool check_all_tris)
+static void validate_cdt(CDT_state *cdt,
+ bool check_all_tris,
+ bool check_delaunay,
+ bool check_visibility)
{
- LinkNode *ln, *lne;
- int totedges, totfaces, totverts, totborderedges;
+ LinkNode *ln;
+ int totedges, totfaces, totverts;
CDTEdge *e;
SymEdge *se, *sesym, *s;
CDTVert *v, *v1, *v2, *v3;
CDTFace *f;
- double *p;
- double margin;
int i, limit;
bool isborder;
if (cdt->output_prepared) {
return;
}
+ if (cdt->edges == NULL || cdt->edges->next == NULL) {
+ return;
+ }
BLI_assert(cdt != NULL);
- BLI_assert(cdt->maxx >= cdt->minx);
- BLI_assert(cdt->maxy >= cdt->miny);
totedges = 0;
- totborderedges = 0;
for (ln = cdt->edges; ln; ln = ln->next) {
e = (CDTEdge *)ln->link;
se = &e->symedges[0];
@@ -3165,13 +3207,6 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris)
}
totedges++;
isborder = is_border_edge(e, cdt);
- if (isborder) {
- totborderedges++;
- BLI_assert((se->face == cdt->outer_face && sesym->face != cdt->outer_face) ||
- (se->face != cdt->outer_face && sesym->face == cdt->outer_face));
- }
- /* BLI_assert(se->face != sesym->face);
- * Not required because faces can have intruding wire edges. */
BLI_assert(se->vert != sesym->vert);
BLI_assert(se->edge == sesym->edge && se->edge == e);
BLI_assert(sym(se) == sesym && sym(sesym) == se);
@@ -3179,8 +3214,6 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris)
se = &e->symedges[i];
v = se->vert;
f = se->face;
- p = v->co;
- UNUSED_VARS_NDEBUG(p);
BLI_assert(plausible_non_null_ptr(v));
if (f != NULL) {
BLI_assert(plausible_non_null_ptr(f));
@@ -3198,9 +3231,9 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris)
v1 = se->vert;
v2 = se->next->vert;
v3 = se->next->next->vert;
- BLI_assert(CCW_test(v1->co, v2->co, v3->co, 0.0));
- BLI_assert(CCW_test(v2->co, v3->co, v1->co, 0.0));
- BLI_assert(CCW_test(v3->co, v1->co, v2->co, 0.0));
+ BLI_assert(orient2d(v1->co, v2->co, v3->co) >= 0.0);
+ BLI_assert(orient2d(v2->co, v3->co, v1->co) >= 0.0);
+ BLI_assert(orient2d(v3->co, v1->co, v2->co) >= 0.0);
}
UNUSED_VARS_NDEBUG(limit);
BLI_assert(se->next->next != se);
@@ -3211,19 +3244,23 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris)
s = s->next;
} while (s != se);
}
- BLI_assert(isborder || is_visible(se->vert, se->next->vert, false, cdt));
- BLI_assert(isborder || is_delaunay_edge(se, cdt->epsilon));
+ if (check_visibility) {
+ BLI_assert(isborder || is_visible(se->vert, se->next->vert, false, cdt));
+ }
+ if (!isborder && check_delaunay) {
+ BLI_assert(is_delaunay_edge(se));
+ }
}
totverts = 0;
- margin = cdt->margin;
for (i = 0; i < cdt->vert_array_len; i++) {
- totverts++;
v = cdt->vert_array[i];
BLI_assert(plausible_non_null_ptr(v));
- p = v->co;
- BLI_assert(p[0] >= cdt->minx - margin && p[0] <= cdt->maxx + margin);
- UNUSED_VARS_NDEBUG(margin);
- BLI_assert(v->symedge->vert == v);
+ if (v->merge_to_index != -1) {
+ BLI_assert(v->merge_to_index >= 0 && v->merge_to_index < cdt->vert_array_len);
+ continue;
+ }
+ totverts++;
+ BLI_assert(cdt->vert_array_len <= 1 || v->symedge->vert == v);
}
totfaces = 0;
for (ln = cdt->faces; ln; ln = ln->next) {
@@ -3236,23 +3273,1111 @@ static void validate_cdt(CDT_state *cdt, bool check_all_tris)
if (f == cdt->outer_face) {
continue;
}
- for (lne = cdt->edges; lne; lne = lne->next) {
- e = (CDTEdge *)lne->link;
- if (!is_deleted_edge(e)) {
- for (i = 0; i < 2; i++) {
- if (e->symedges[i].face == f) {
- validate_face_centroid(&e->symedges[i]);
- }
- }
- }
- }
- p = f->centroid;
- BLI_assert(p[0] >= cdt->minx - margin && p[0] <= cdt->maxx + margin);
- BLI_assert(p[1] >= cdt->miny - margin && p[1] <= cdt->maxy + margin);
}
/* Euler's formula for planar graphs. */
- if (check_all_tris) {
+ if (check_all_tris && totfaces > 1) {
BLI_assert(totverts - totedges + totfaces == 2);
}
}
#endif
+
+/* Jonathan Shewchuk's adaptive predicates, trimmed to those needed here.
+ * Permission obtained by private communication from Jonathan to include this code in Blender.
+ */
+
+/*
+ * Routines for Arbitrary Precision Floating-point Arithmetic
+ * and Fast Robust Geometric Predicates
+ * (predicates.c)
+ *
+ * May 18, 1996
+ *
+ * Placed in the public domain by
+ * Jonathan Richard Shewchuk
+ * School of Computer Science
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, Pennsylvania 15213-3891
+ * jrs@cs.cmu.edu
+ *
+ * This file contains C implementation of algorithms for exact addition
+ * and multiplication of floating-point numbers, and predicates for
+ * robustly performing the orientation and incircle tests used in
+ * computational geometry. The algorithms and underlying theory are
+ * described in Jonathan Richard Shewchuk. "Adaptive Precision Floating-
+ * Point Arithmetic and Fast Robust Geometric Predicates." Technical
+ * Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon
+ * University, Pittsburgh, Pennsylvania, May 1996. (Submitted to
+ * Discrete & Computational Geometry.)
+ *
+ * This file, the paper listed above, and other information are available
+ * from the Web page http://www.cs.cmu.edu/~quake/robust.html .
+ *
+ * Using this code:
+ *
+ * First, read the short or long version of the paper (from the Web page
+ * above).
+ *
+ * Be sure to call exactinit() once, before calling any of the arithmetic
+ * functions or geometric predicates. Also be sure to turn on the
+ * optimizer when compiling this file.
+ *
+ * On some machines, the exact arithmetic routines might be defeated by the
+ * use of internal extended precision floating-point registers. Sometimes
+ * this problem can be fixed by defining certain values to be volatile,
+ * thus forcing them to be stored to memory and rounded off. This isn't
+ * a great solution, though, as it slows the arithmetic down.
+ *
+ * To try this out, write "#define INEXACT volatile" below. Normally,
+ * however, INEXACT should be defined to be nothing. ("#define INEXACT".)
+ */
+
+#define INEXACT /* Nothing */
+/* #define INEXACT volatile */
+
+/* Which of the following two methods of finding the absolute values is
+ * fastest is compiler-dependent. A few compilers can inline and optimize
+ * the fabs() call; but most will incur the overhead of a function call,
+ * which is disastrously slow. A faster way on IEEE machines might be to
+ * mask the appropriate bit, but that's difficult to do in C.
+ */
+
+#define Absolute(a) ((a) >= 0.0 ? (a) : -(a))
+/* #define Absolute(a) fabs(a) */
+
+/* Many of the operations are broken up into two pieces, a main part that
+ * performs an approximate operation, and a "tail" that computes the
+ * roundoff error of that operation.
+ *
+ * The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(),
+ * Split(), and Two_Product() are all implemented as described in the
+ * reference. Each of these macros requires certain variables to be
+ * defined in the calling routine. The variables `bvirt', `c', `abig',
+ * `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because
+ * they store the result of an operation that may incur roundoff error.
+ * The input parameter `x' (or the highest numbered `x_' parameter) must
+ * also be declared `INEXACT'.
+ */
+
+#define Fast_Two_Sum_Tail(a, b, x, y) \
+ bvirt = x - a; \
+ y = b - bvirt
+
+#define Fast_Two_Sum(a, b, x, y) \
+ x = (double)(a + b); \
+ Fast_Two_Sum_Tail(a, b, x, y)
+
+#define Fast_Two_Diff_Tail(a, b, x, y) \
+ bvirt = a - x; \
+ y = bvirt - b
+
+#define Fast_Two_Diff(a, b, x, y) \
+ x = (double)(a - b); \
+ Fast_Two_Diff_Tail(a, b, x, y)
+
+#define Two_Sum_Tail(a, b, x, y) \
+ bvirt = (double)(x - a); \
+ avirt = x - bvirt; \
+ bround = b - bvirt; \
+ around = a - avirt; \
+ y = around + bround
+
+#define Two_Sum(a, b, x, y) \
+ x = (double)(a + b); \
+ Two_Sum_Tail(a, b, x, y)
+
+#define Two_Diff_Tail(a, b, x, y) \
+ bvirt = (double)(a - x); \
+ avirt = x + bvirt; \
+ bround = bvirt - b; \
+ around = a - avirt; \
+ y = around + bround
+
+#define Two_Diff(a, b, x, y) \
+ x = (double)(a - b); \
+ Two_Diff_Tail(a, b, x, y)
+
+#define Split(a, ahi, alo) \
+ c = (double)(splitter * a); \
+ abig = (double)(c - a); \
+ ahi = c - abig; \
+ alo = a - ahi
+
+#define Two_Product_Tail(a, b, x, y) \
+ Split(a, ahi, alo); \
+ Split(b, bhi, blo); \
+ err1 = x - (ahi * bhi); \
+ err2 = err1 - (alo * bhi); \
+ err3 = err2 - (ahi * blo); \
+ y = (alo * blo) - err3
+
+#define Two_Product(a, b, x, y) \
+ x = (double)(a * b); \
+ Two_Product_Tail(a, b, x, y)
+
+#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
+ x = (double)(a * b); \
+ Split(a, ahi, alo); \
+ err1 = x - (ahi * bhi); \
+ err2 = err1 - (alo * bhi); \
+ err3 = err2 - (ahi * blo); \
+ y = (alo * blo) - err3
+
+#define Square_Tail(a, x, y) \
+ Split(a, ahi, alo); \
+ err1 = x - (ahi * ahi); \
+ err3 = err1 - ((ahi + ahi) * alo); \
+ y = (alo * alo) - err3
+
+#define Square(a, x, y) \
+ x = (double)(a * a); \
+ Square_Tail(a, x, y)
+
+#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
+ Two_Sum(a0, b, _i, x0); \
+ Two_Sum(a1, _i, x2, x1)
+
+#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
+ Two_Diff(a0, b, _i, x0); \
+ Two_Sum(a1, _i, x2, x1)
+
+#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
+ Two_One_Sum(a1, a0, b0, _j, _0, x0); \
+ Two_One_Sum(_j, _0, b1, x3, x2, x1)
+
+#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
+ Two_One_Diff(a1, a0, b0, _j, _0, x0); \
+ Two_One_Diff(_j, _0, b1, x3, x2, x1)
+
+static double splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */
+static double m_epsilon; /* = 2^(-p). Used to estimate roundoff errors. */
+/* A set of coefficients used to calculate maximum roundoff errors. */
+static double resulterrbound;
+static double ccwerrboundA, ccwerrboundB, ccwerrboundC;
+static double o3derrboundA, o3derrboundB, o3derrboundC;
+static double iccerrboundA, iccerrboundB, iccerrboundC;
+static double isperrboundA, isperrboundB, isperrboundC;
+
+/* exactinit() Initialize the variables used for exact arithmetic.
+ *
+ * `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in
+ * floating-point arithmetic. `epsilon' bounds the relative roundoff
+ * error. It is used for floating-point error analysis.
+ *
+ * `splitter' is used to split floating-point numbers into two half-
+ * length significands for exact multiplication.
+ *
+ * I imagine that a highly optimizing compiler might be too smart for its
+ * own good, and somehow cause this routine to fail, if it pretends that
+ * floating-point arithmetic is too much like real arithmetic.
+ *
+ * Don't change this routine unless you fully understand it.
+ */
+
+static void exactinit(void)
+{
+ double half;
+ double check, lastcheck;
+ int every_other;
+
+ every_other = 1;
+ half = 0.5;
+ m_epsilon = 1.0;
+ splitter = 1.0;
+ check = 1.0;
+ /* Repeatedly divide `epsilon' by two until it is too small to add to
+ * one without causing roundoff. (Also check if the sum is equal to
+ * the previous sum, for machines that round up instead of using exact
+ * rounding. Not that this library will work on such machines anyway.
+ */
+ do {
+ lastcheck = check;
+ m_epsilon *= half;
+ if (every_other) {
+ splitter *= 2.0;
+ }
+ every_other = !every_other;
+ check = 1.0 + m_epsilon;
+ } while ((check != 1.0) && (check != lastcheck));
+ splitter += 1.0;
+
+ /* Error bounds for orientation and incircle tests. */
+ resulterrbound = (3.0 + 8.0 * m_epsilon) * m_epsilon;
+ ccwerrboundA = (3.0 + 16.0 * m_epsilon) * m_epsilon;
+ ccwerrboundB = (2.0 + 12.0 * m_epsilon) * m_epsilon;
+ ccwerrboundC = (9.0 + 64.0 * m_epsilon) * m_epsilon * m_epsilon;
+ o3derrboundA = (7.0 + 56.0 * m_epsilon) * m_epsilon;
+ o3derrboundB = (3.0 + 28.0 * m_epsilon) * m_epsilon;
+ o3derrboundC = (26.0 + 288.0 * m_epsilon) * m_epsilon * m_epsilon;
+ iccerrboundA = (10.0 + 96.0 * m_epsilon) * m_epsilon;
+ iccerrboundB = (4.0 + 48.0 * m_epsilon) * m_epsilon;
+ iccerrboundC = (44.0 + 576.0 * m_epsilon) * m_epsilon * m_epsilon;
+ isperrboundA = (16.0 + 224.0 * m_epsilon) * m_epsilon;
+ isperrboundB = (5.0 + 72.0 * m_epsilon) * m_epsilon;
+ isperrboundC = (71.0 + 1408.0 * m_epsilon) * m_epsilon * m_epsilon;
+}
+
+/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero
+ * components from the output expansion.
+ *
+ * Sets h = e + f. See the long version of my paper for details.
+ *
+ * If round-to-even is used (as with IEEE 754), maintains the strongly
+ * nonoverlapping property. (That is, if e is strongly nonoverlapping, h
+ * will be also.) Does NOT maintain the nonoverlapping or nonadjacent
+ * properties.
+ */
+
+static int fast_expansion_sum_zeroelim(
+ int elen, double *e, int flen, double *f, double *h) /* h cannot be e or f. */
+{
+ double Q;
+ INEXACT double Qnew;
+ INEXACT double hh;
+ INEXACT double bvirt;
+ double avirt, bround, around;
+ int eindex, findex, hindex;
+ double enow, fnow;
+
+ enow = e[0];
+ fnow = f[0];
+ eindex = findex = 0;
+ if ((fnow > enow) == (fnow > -enow)) {
+ Q = enow;
+ enow = e[++eindex];
+ }
+ else {
+ Q = fnow;
+ fnow = f[++findex];
+ }
+ hindex = 0;
+ if ((eindex < elen) && (findex < flen)) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ Fast_Two_Sum(enow, Q, Qnew, hh);
+ enow = e[++eindex];
+ }
+ else {
+ Fast_Two_Sum(fnow, Q, Qnew, hh);
+ fnow = f[++findex];
+ }
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ while ((eindex < elen) && (findex < flen)) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ Two_Sum(Q, enow, Qnew, hh);
+ enow = e[++eindex];
+ }
+ else {
+ Two_Sum(Q, fnow, Qnew, hh);
+ fnow = f[++findex];
+ }
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ }
+ while (eindex < elen) {
+ Two_Sum(Q, enow, Qnew, hh);
+ enow = e[++eindex];
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ while (findex < flen) {
+ Two_Sum(Q, fnow, Qnew, hh);
+ fnow = f[++findex];
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ if ((Q != 0.0) || (hindex == 0)) {
+ h[hindex++] = Q;
+ }
+ return hindex;
+}
+
+/* scale_expansion_zeroelim() Multiply an expansion by a scalar,
+ * eliminating zero components from the
+ * output expansion.
+ *
+ * Sets h = be. See either version of my paper for details.
+ *
+ * Maintains the nonoverlapping property. If round-to-even is used (as
+ * with IEEE 754), maintains the strongly nonoverlapping and nonadjacent
+ * properties as well. (That is, if e has one of these properties, so
+ * will h.)
+ */
+
+static int scale_expansion_zeroelim(int elen,
+ double *e,
+ double b,
+ double *h) /* e and h cannot be the same. */
+{
+ INEXACT double Q, sum;
+ double hh;
+ INEXACT double product1;
+ double product0;
+ int eindex, hindex;
+ double enow;
+ INEXACT double bvirt;
+ double avirt, bround, around;
+ INEXACT double c;
+ INEXACT double abig;
+ double ahi, alo, bhi, blo;
+ double err1, err2, err3;
+
+ Split(b, bhi, blo);
+ Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
+ hindex = 0;
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ for (eindex = 1; eindex < elen; eindex++) {
+ enow = e[eindex];
+ Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
+ Two_Sum(Q, product0, sum, hh);
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ Fast_Two_Sum(product1, sum, Q, hh);
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ }
+ if ((Q != 0.0) || (hindex == 0)) {
+ h[hindex++] = Q;
+ }
+ return hindex;
+}
+
+/* estimate() Produce a one-word estimate of an expansion's value.
+ *
+ * See either version of my paper for details.
+ */
+
+static double estimate(int elen, double *e)
+{
+ double Q;
+ int eindex;
+
+ Q = e[0];
+ for (eindex = 1; eindex < elen; eindex++) {
+ Q += e[eindex];
+ }
+ return Q;
+}
+
+/* orient2d() Adaptive exact 2D orientation test. Robust.
+ *
+ * Return a positive value if the points pa, pb, and pc occur
+ * in counterclockwise order; a negative value if they occur
+ * in clockwise order; and zero if they are collinear. The
+ * result is also a rough approximation of twice the signed
+ * area of the triangle defined by the three points.
+ *
+ * This uses exact arithmetic to ensure a correct answer. The
+ * result returned is the determinant of a matrix.
+ * This determinant is computed adaptively, in the sense that exact
+ * arithmetic is used only to the degree it is needed to ensure that the
+ * returned value has the correct sign. Hence, orient2d() is usually quite
+ * fast, but will run more slowly when the input points are collinear or
+ * nearly so.
+ */
+
+static double orient2dadapt(const double *pa, const double *pb, const double *pc, double detsum)
+{
+ INEXACT double acx, acy, bcx, bcy;
+ double acxtail, acytail, bcxtail, bcytail;
+ INEXACT double detleft, detright;
+ double detlefttail, detrighttail;
+ double det, errbound;
+ double B[4], C1[8], C2[12], D[16];
+ INEXACT double B3;
+ int C1length, C2length, Dlength;
+ double u[4];
+ INEXACT double u3;
+ INEXACT double s1, t1;
+ double s0, t0;
+
+ INEXACT double bvirt;
+ double avirt, bround, around;
+ INEXACT double c;
+ INEXACT double abig;
+ double ahi, alo, bhi, blo;
+ double err1, err2, err3;
+ INEXACT double _i, _j;
+ double _0;
+
+ acx = (double)(pa[0] - pc[0]);
+ bcx = (double)(pb[0] - pc[0]);
+ acy = (double)(pa[1] - pc[1]);
+ bcy = (double)(pb[1] - pc[1]);
+
+ Two_Product(acx, bcy, detleft, detlefttail);
+ Two_Product(acy, bcx, detright, detrighttail);
+
+ Two_Two_Diff(detleft, detlefttail, detright, detrighttail, B3, B[2], B[1], B[0]);
+ B[3] = B3;
+
+ det = estimate(4, B);
+ errbound = ccwerrboundB * detsum;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pc[0], acx, acxtail);
+ Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail);
+ Two_Diff_Tail(pa[1], pc[1], acy, acytail);
+ Two_Diff_Tail(pb[1], pc[1], bcy, bcytail);
+
+ if ((acxtail == 0.0) && (acytail == 0.0) && (bcxtail == 0.0) && (bcytail == 0.0)) {
+ return det;
+ }
+
+ errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det);
+ det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Product(acxtail, bcy, s1, s0);
+ Two_Product(acytail, bcx, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);
+
+ Two_Product(acx, bcytail, s1, s0);
+ Two_Product(acy, bcxtail, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);
+
+ Two_Product(acxtail, bcytail, s1, s0);
+ Two_Product(acytail, bcxtail, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);
+
+ return (D[Dlength - 1]);
+}
+
+static double orient2d(const double *pa, const double *pb, const double *pc)
+{
+ double detleft, detright, det;
+ double detsum, errbound;
+
+ detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
+ detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
+ det = detleft - detright;
+
+ if (detleft > 0.0) {
+ if (detright <= 0.0) {
+ return det;
+ }
+ else {
+ detsum = detleft + detright;
+ }
+ }
+ else if (detleft < 0.0) {
+ if (detright >= 0.0) {
+ return det;
+ }
+ else {
+ detsum = -detleft - detright;
+ }
+ }
+ else {
+ return det;
+ }
+
+ errbound = ccwerrboundA * detsum;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ return orient2dadapt(pa, pb, pc, detsum);
+}
+
+/* incircle() Adaptive exact 2D incircle test. Robust.
+ *
+ * Return a positive value if the point pd lies inside the
+ * circle passing through pa, pb, and pc; a negative value if
+ * it lies outside; and zero if the four points are cocircular.
+ * The points pa, pb, and pc must be in counterclockwise
+ * order, or the sign of the result will be reversed.
+ *
+ * This uses exact arithmetic to ensure a correct answer.
+ * The result returned is the determinant of a matrix.
+ * This determinant is computed adaptively, in the sense that exact
+ * arithmetic is used only to the degree it is needed to ensure that the
+ * returned value has the correct sign. Hence, incircle() is usually quite
+ * fast, but will run more slowly when the input points are cocircular or
+ * nearly so.
+ */
+
+static double incircleadapt(
+ const double *pa, const double *pb, const double *pc, const double *pd, double permanent)
+{
+ INEXACT double adx, bdx, cdx, ady, bdy, cdy;
+ double det, errbound;
+
+ INEXACT double bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+ double bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+ double bc[4], ca[4], ab[4];
+ INEXACT double bc3, ca3, ab3;
+ double axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32];
+ int axbclen, axxbclen, aybclen, ayybclen, alen;
+ double bxca[8], bxxca[16], byca[8], byyca[16], bdet[32];
+ int bxcalen, bxxcalen, bycalen, byycalen, blen;
+ double cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32];
+ int cxablen, cxxablen, cyablen, cyyablen, clen;
+ double abdet[64];
+ int ablen;
+ double fin1[1152], fin2[1152];
+ double *finnow, *finother, *finswap;
+ int finlength;
+
+ double adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail;
+ INEXACT double adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1;
+ double adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0;
+ double aa[4], bb[4], cc[4];
+ INEXACT double aa3, bb3, cc3;
+ INEXACT double ti1, tj1;
+ double ti0, tj0;
+ double u[4], v[4];
+ INEXACT double u3, v3;
+ double temp8[8], temp16a[16], temp16b[16], temp16c[16];
+ double temp32a[32], temp32b[32], temp48[48], temp64[64];
+ int temp8len, temp16alen, temp16blen, temp16clen;
+ int temp32alen, temp32blen, temp48len, temp64len;
+ double axtbb[8], axtcc[8], aytbb[8], aytcc[8];
+ int axtbblen, axtcclen, aytbblen, aytcclen;
+ double bxtaa[8], bxtcc[8], bytaa[8], bytcc[8];
+ int bxtaalen, bxtcclen, bytaalen, bytcclen;
+ double cxtaa[8], cxtbb[8], cytaa[8], cytbb[8];
+ int cxtaalen, cxtbblen, cytaalen, cytbblen;
+ double axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8];
+ int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen;
+ double axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16];
+ int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen;
+ double axtbctt[8], aytbctt[8], bxtcatt[8];
+ double bytcatt[8], cxtabtt[8], cytabtt[8];
+ int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen;
+ double abt[8], bct[8], cat[8];
+ int abtlen, bctlen, catlen;
+ double abtt[4], bctt[4], catt[4];
+ int abttlen, bcttlen, cattlen;
+ INEXACT double abtt3, bctt3, catt3;
+ double negate;
+
+ INEXACT double bvirt;
+ double avirt, bround, around;
+ INEXACT double c;
+ INEXACT double abig;
+ double ahi, alo, bhi, blo;
+ double err1, err2, err3;
+ INEXACT double _i, _j;
+ double _0;
+
+ adx = (double)(pa[0] - pd[0]);
+ bdx = (double)(pb[0] - pd[0]);
+ cdx = (double)(pc[0] - pd[0]);
+ ady = (double)(pa[1] - pd[1]);
+ bdy = (double)(pb[1] - pd[1]);
+ cdy = (double)(pc[1] - pd[1]);
+
+ Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+ Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+ Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+ bc[3] = bc3;
+ axbclen = scale_expansion_zeroelim(4, bc, adx, axbc);
+ axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc);
+ aybclen = scale_expansion_zeroelim(4, bc, ady, aybc);
+ ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc);
+ alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet);
+
+ Two_Product(cdx, ady, cdxady1, cdxady0);
+ Two_Product(adx, cdy, adxcdy1, adxcdy0);
+ Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+ ca[3] = ca3;
+ bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca);
+ bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca);
+ bycalen = scale_expansion_zeroelim(4, ca, bdy, byca);
+ byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca);
+ blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet);
+
+ Two_Product(adx, bdy, adxbdy1, adxbdy0);
+ Two_Product(bdx, ady, bdxady1, bdxady0);
+ Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+ ab[3] = ab3;
+ cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab);
+ cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab);
+ cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab);
+ cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab);
+ clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet);
+
+ ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+ finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+ det = estimate(finlength, fin1);
+ errbound = iccerrboundB * permanent;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+ Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+ Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+ Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+ Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+ Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+ if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0) &&
+ (bdytail == 0.0) && (cdytail == 0.0)) {
+ return det;
+ }
+
+ errbound = iccerrboundC * permanent + resulterrbound * Absolute(det);
+ det += ((adx * adx + ady * ady) *
+ ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) +
+ 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) +
+ ((bdx * bdx + bdy * bdy) *
+ ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) +
+ 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) +
+ ((cdx * cdx + cdy * cdy) *
+ ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) +
+ 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx));
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ finnow = fin1;
+ finother = fin2;
+
+ if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) {
+ Square(adx, adxadx1, adxadx0);
+ Square(ady, adyady1, adyady0);
+ Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]);
+ aa[3] = aa3;
+ }
+ if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) {
+ Square(bdx, bdxbdx1, bdxbdx0);
+ Square(bdy, bdybdy1, bdybdy0);
+ Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]);
+ bb[3] = bb3;
+ }
+ if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) {
+ Square(cdx, cdxcdx1, cdxcdx0);
+ Square(cdy, cdycdy1, cdycdy0);
+ Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]);
+ cc[3] = cc3;
+ }
+
+ if (adxtail != 0.0) {
+ axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc);
+ temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, temp16a);
+
+ axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc);
+ temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b);
+
+ axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb);
+ temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc);
+ temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, temp16a);
+
+ aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb);
+ temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b);
+
+ aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc);
+ temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdxtail != 0.0) {
+ bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca);
+ temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, temp16a);
+
+ bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa);
+ temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b);
+
+ bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc);
+ temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca);
+ temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, temp16a);
+
+ bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc);
+ temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b);
+
+ bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa);
+ temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdxtail != 0.0) {
+ cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab);
+ temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, temp16a);
+
+ cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb);
+ temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b);
+
+ cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa);
+ temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab);
+ temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, temp16a);
+
+ cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa);
+ temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b);
+
+ cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb);
+ temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ if ((adxtail != 0.0) || (adytail != 0.0)) {
+ if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) {
+ Two_Product(bdxtail, cdy, ti1, ti0);
+ Two_Product(bdx, cdytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -bdy;
+ Two_Product(cdxtail, negate, ti1, ti0);
+ negate = -bdytail;
+ Two_Product(cdx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct);
+
+ Two_Product(bdxtail, cdytail, ti1, ti0);
+ Two_Product(cdxtail, bdytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]);
+ bctt[3] = bctt3;
+ bcttlen = 4;
+ }
+ else {
+ bct[0] = 0.0;
+ bctlen = 1;
+ bctt[0] = 0.0;
+ bcttlen = 1;
+ }
+
+ if (adxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a);
+ axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct);
+ temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, temp32a);
+ axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt);
+ temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, temp16a);
+ temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a);
+ aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct);
+ temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, temp32a);
+ aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt);
+ temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, temp16a);
+ temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if ((bdxtail != 0.0) || (bdytail != 0.0)) {
+ if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) {
+ Two_Product(cdxtail, ady, ti1, ti0);
+ Two_Product(cdx, adytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -cdy;
+ Two_Product(adxtail, negate, ti1, ti0);
+ negate = -cdytail;
+ Two_Product(adx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat);
+
+ Two_Product(cdxtail, adytail, ti1, ti0);
+ Two_Product(adxtail, cdytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]);
+ catt[3] = catt3;
+ cattlen = 4;
+ }
+ else {
+ cat[0] = 0.0;
+ catlen = 1;
+ catt[0] = 0.0;
+ cattlen = 1;
+ }
+
+ if (bdxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a);
+ bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat);
+ temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, temp32a);
+ bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt);
+ temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, temp16a);
+ temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a);
+ bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat);
+ temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, temp32a);
+ bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt);
+ temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, temp16a);
+ temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if ((cdxtail != 0.0) || (cdytail != 0.0)) {
+ if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) {
+ Two_Product(adxtail, bdy, ti1, ti0);
+ Two_Product(adx, bdytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -ady;
+ Two_Product(bdxtail, negate, ti1, ti0);
+ negate = -adytail;
+ Two_Product(bdx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt);
+
+ Two_Product(adxtail, bdytail, ti1, ti0);
+ Two_Product(bdxtail, adytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]);
+ abtt[3] = abtt3;
+ abttlen = 4;
+ }
+ else {
+ abt[0] = 0.0;
+ abtlen = 1;
+ abtt[0] = 0.0;
+ abttlen = 1;
+ }
+
+ if (cdxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a);
+ cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt);
+ temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, temp32a);
+ cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt);
+ temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, temp16a);
+ temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a);
+ cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt);
+ temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, temp32a);
+ cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt);
+ temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, temp16a);
+ temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+
+ return finnow[finlength - 1];
+}
+
+static double incircle(const double *pa, const double *pb, const double *pc, const double *pd)
+{
+ double adx, bdx, cdx, ady, bdy, cdy;
+ double bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+ double alift, blift, clift;
+ double det;
+ double permanent, errbound;
+
+ adx = pa[0] - pd[0];
+ bdx = pb[0] - pd[0];
+ cdx = pc[0] - pd[0];
+ ady = pa[1] - pd[1];
+ bdy = pb[1] - pd[1];
+ cdy = pc[1] - pd[1];
+
+ bdxcdy = bdx * cdy;
+ cdxbdy = cdx * bdy;
+ alift = adx * adx + ady * ady;
+
+ cdxady = cdx * ady;
+ adxcdy = adx * cdy;
+ blift = bdx * bdx + bdy * bdy;
+
+ adxbdy = adx * bdy;
+ bdxady = bdx * ady;
+ clift = cdx * cdx + cdy * cdy;
+
+ det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady);
+
+ permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift +
+ (Absolute(cdxady) + Absolute(adxcdy)) * blift +
+ (Absolute(adxbdy) + Absolute(bdxady)) * clift;
+ errbound = iccerrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+ return det;
+ }
+
+ return incircleadapt(pa, pb, pc, pd, permanent);
+}
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index 43923ce8c98..6020dc41a62 100644
--- a/source/blender/blenlib/intern/expr_pylike_eval.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -140,6 +140,24 @@ bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
}
+/** Check if the parsed expression uses the parameter with the given index. */
+bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
+{
+ int i;
+
+ if (expr == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < expr->ops_count; i++) {
+ if (expr->ops[i].opcode == OPCODE_PARAMETER && expr->ops[i].arg.ival == index) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 5118d8a698e..4d8a2f72eca 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1235,6 +1235,27 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#endif
}
+/**
+ * Combines transformations, handling scale separately in a manner equivalent
+ * to the Aligned Inherit Scale mode, in order to avoid creating shear.
+ * If A scale is uniform, the result is equivalent to ordinary multiplication.
+ */
+void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
+{
+ float loc_a[3], rot_a[3][3], size_a[3];
+ float loc_b[3], rot_b[3][3], size_b[3];
+ float loc_r[3], rot_r[3][3], size_r[3];
+
+ mat4_to_loc_rot_size(loc_a, rot_a, size_a, A);
+ mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
+
+ mul_v3_m4v3(loc_r, A, loc_b);
+ mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
+ mul_v3_v3v3(size_r, size_a, size_b);
+
+ loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
+}
+
/****************************** Linear Algebra *******************************/
void transpose_m3(float mat[3][3])
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 67bc5c2fa50..caa38c9cf08 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -169,6 +169,12 @@ MINLINE void copy_v4_v4_short(short r[4], const short a[4])
}
/* int */
+MINLINE void zero_v2_int(int r[2])
+{
+ r[0] = 0;
+ r[1] = 0;
+}
+
MINLINE void zero_v3_int(int r[3])
{
r[0] = 0;
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index cd1a0e2c328..dff1f77c1ab 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -157,20 +157,6 @@ void BLI_stringenc(
sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
-/**
- * Returns in area pointed to by string a string of the form "<dir><head><pic><tail>", where pic
- * is formatted as numlen digits with leading zeroes.
- */
-void BLI_stringenc_path(char *string,
- const char *dir,
- const char *head,
- const char *tail,
- unsigned short numlen,
- int pic)
-{
- sprintf(string, "%s%s%.*d%s", dir, head, numlen, MAX2(0, pic), tail);
-}
-
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
/* ******************** string encoding ***************** */
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index ecff2ebffef..2ed7d7d7345 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -439,42 +439,66 @@ void BLI_rcti_union(rcti *rct1, const rcti *rct2)
void BLI_rctf_init(rctf *rect, float xmin, float xmax, float ymin, float ymax)
{
- if (xmin <= xmax) {
- rect->xmin = xmin;
- rect->xmax = xmax;
- }
- else {
- rect->xmax = xmin;
- rect->xmin = xmax;
- }
- if (ymin <= ymax) {
- rect->ymin = ymin;
- rect->ymax = ymax;
- }
- else {
- rect->ymax = ymin;
- rect->ymin = ymax;
- }
+ rect->xmin = xmin;
+ rect->xmax = xmax;
+ rect->ymin = ymin;
+ rect->ymax = ymax;
+
+ BLI_rctf_sanitize(rect);
}
void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
{
- if (xmin <= xmax) {
- rect->xmin = xmin;
- rect->xmax = xmax;
+ rect->xmin = xmin;
+ rect->xmax = xmax;
+ rect->ymin = ymin;
+ rect->ymax = ymax;
+
+ BLI_rcti_sanitize(rect);
+}
+
+/**
+ * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ * If this returns false, #BLI_rctf_sanitize() can be called to address this.
+ *
+ * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
+ * have max < min. Usually this is what you'd want though.
+ */
+bool BLI_rctf_is_valid(const rctf *rect)
+{
+ return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
+}
+
+bool BLI_rcti_is_valid(const rcti *rect)
+{
+ return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
+}
+
+/**
+ * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ */
+void BLI_rctf_sanitize(rctf *rect)
+{
+ if (rect->xmin > rect->xmax) {
+ SWAP(float, rect->xmin, rect->xmax);
}
- else {
- rect->xmax = xmin;
- rect->xmin = xmax;
+ if (rect->ymin > rect->ymax) {
+ SWAP(float, rect->ymin, rect->ymax);
}
- if (ymin <= ymax) {
- rect->ymin = ymin;
- rect->ymax = ymax;
+
+ BLI_assert(BLI_rctf_is_valid(rect));
+}
+
+void BLI_rcti_sanitize(rcti *rect)
+{
+ if (rect->xmin > rect->xmax) {
+ SWAP(int, rect->xmin, rect->xmax);
}
- else {
- rect->ymax = ymin;
- rect->ymin = ymax;
+ if (rect->ymin > rect->ymax) {
+ SWAP(int, rect->ymin, rect->ymax);
}
+
+ BLI_assert(BLI_rcti_is_valid(rect));
}
void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size)
@@ -899,6 +923,90 @@ bool BLI_rcti_isect(const rcti *src1, const rcti *src2, rcti *dest)
}
}
+bool BLI_rctf_isect_rect_x(const rctf *src1, const rctf *src2, float range_x[2])
+{
+ const float xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
+ const float xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
+
+ if (xmax >= xmin) {
+ if (range_x) {
+ range_x[0] = xmin;
+ range_x[1] = xmax;
+ }
+ return true;
+ }
+ else {
+ if (range_x) {
+ range_x[0] = 0;
+ range_x[1] = 0;
+ }
+ return false;
+ }
+}
+
+bool BLI_rctf_isect_rect_y(const rctf *src1, const rctf *src2, float range_y[2])
+{
+ const float ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
+ const float ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
+
+ if (ymax >= ymin) {
+ if (range_y) {
+ range_y[0] = ymin;
+ range_y[1] = ymax;
+ }
+ return true;
+ }
+ else {
+ if (range_y) {
+ range_y[0] = 0;
+ range_y[1] = 0;
+ }
+ return false;
+ }
+}
+
+bool BLI_rcti_isect_rect_x(const rcti *src1, const rcti *src2, int range_x[2])
+{
+ const int xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
+ const int xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
+
+ if (xmax >= xmin) {
+ if (range_x) {
+ range_x[0] = xmin;
+ range_x[1] = xmax;
+ }
+ return true;
+ }
+ else {
+ if (range_x) {
+ range_x[0] = 0;
+ range_x[1] = 0;
+ }
+ return false;
+ }
+}
+
+bool BLI_rcti_isect_rect_y(const rcti *src1, const rcti *src2, int range_y[2])
+{
+ const int ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
+ const int ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
+
+ if (ymax >= ymin) {
+ if (range_y) {
+ range_y[0] = ymin;
+ range_y[1] = ymax;
+ }
+ return true;
+ }
+ else {
+ if (range_y) {
+ range_y[0] = 0;
+ range_y[1] = 0;
+ }
+ return false;
+ }
+}
+
void BLI_rcti_rctf_copy(rcti *dst, const rctf *src)
{
dst->xmin = floorf(src->xmin + 0.5f);
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 0b8ec44cbcd..1eed59e568e 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -685,6 +685,7 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2)
return numcompare;
}
+ /* Some wasted work here, left_number_strcmp already consumes at least some digits. */
d1++;
while (isdigit(s1[d1])) {
d1++;
@@ -695,14 +696,22 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2)
}
}
+ /* Test for end of strings first so that shorter strings are ordered in front. */
+ if (ELEM(0, s1[d1], s2[d2])) {
+ break;
+ }
+
c1 = tolower(s1[d1]);
c2 = tolower(s2[d2]);
- /* first check for '.' so "foo.bar" comes before "foo 1.bar" */
- if (c1 == '.' && c2 != '.') {
+ if (c1 == c2) {
+ /* Continue iteration */
+ }
+ /* Check for '.' so "foo.bar" comes before "foo 1.bar". */
+ else if (c1 == '.') {
return -1;
}
- if (c1 != '.' && c2 == '.') {
+ else if (c2 == '.') {
return 1;
}
else if (c1 < c2) {
@@ -711,9 +720,7 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2)
else if (c1 > c2) {
return 1;
}
- else if (c1 == 0) {
- break;
- }
+
d1++;
d2++;
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 597cd0adabc..ebe0c27331e 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1911,11 +1911,9 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
if (ima->cache) {
oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
}
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (a = 0; a < TEXTARGET_COUNT; a++) {
- if (tile->gputexture[a] != NULL) {
- oldnewmap_insert(fd->imamap, tile->gputexture[a], tile->gputexture[a], 0);
- }
+ for (a = 0; a < TEXTARGET_COUNT; a++) {
+ if (ima->gputexture[a] != NULL) {
+ oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0);
}
}
if (ima->rr) {
@@ -1959,10 +1957,8 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
if (ima->cache == NULL) {
ima->gpuflag = 0;
ima->gpuframenr = INT_MAX;
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (i = 0; i < TEXTARGET_COUNT; i++) {
- tile->gputexture[i] = NULL;
- }
+ for (i = 0; i < TEXTARGET_COUNT; i++) {
+ ima->gputexture[i] = NULL;
}
ima->rr = NULL;
}
@@ -1970,10 +1966,8 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
slot->render = newimaadr(fd, slot->render);
}
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (i = 0; i < TEXTARGET_COUNT; i++) {
- tile->gputexture[i] = newimaadr(fd, tile->gputexture[i]);
- }
+ for (i = 0; i < TEXTARGET_COUNT; i++) {
+ ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
}
ima->rr = newimaadr(fd, ima->rr);
}
@@ -3378,6 +3372,11 @@ static void lib_link_workspaces(FileData *fd, Main *bmain)
}
}
}
+ else {
+ /* If we're reading a layout without screen stored, it's useless and we shouldn't keep it
+ * around. */
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
}
id->tag &= ~LIB_TAG_NEED_LINK;
@@ -3876,7 +3875,7 @@ static void direct_link_bones(FileData *fd, Bone *bone)
bone->bbone_next = newdataadr(fd, bone->bbone_next);
bone->bbone_prev = newdataadr(fd, bone->bbone_prev);
- bone->flag &= ~BONE_DRAW_ACTIVE;
+ bone->flag &= ~(BONE_DRAW_ACTIVE | BONE_DRAW_LOCKED_WEIGHT);
link_list(fd, &bone->childbase);
@@ -4270,18 +4269,14 @@ static void direct_link_image(FileData *fd, Image *ima)
if (!ima->cache) {
ima->gpuflag = 0;
ima->gpuframenr = INT_MAX;
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- tile->gputexture[i] = NULL;
- }
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ ima->gputexture[i] = NULL;
}
ima->rr = NULL;
}
else {
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- tile->gputexture[i] = newimaadr(fd, tile->gputexture[i]);
- }
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
}
ima->rr = newimaadr(fd, ima->rr);
}
@@ -6226,8 +6221,6 @@ static void direct_link_object(FileData *fd, Object *ob)
BKE_object_empty_draw_type_set(ob, ob->empty_drawtype);
}
- ob->derivedDeform = NULL;
- ob->derivedFinal = NULL;
BKE_object_runtime_reset(ob);
link_list(fd, &ob->pc_ids);
@@ -9343,6 +9336,9 @@ static BHead *read_libblock(FileData *fd,
ID *id;
ListBase *lb;
const char *allocname;
+
+ /* XXX Very weakly handled currently, see comment at the end of this function 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
@@ -9598,7 +9594,14 @@ static BHead *read_libblock(FileData *fd,
oldnewmap_clear(fd->datamap);
if (wrong_id) {
+ /* 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...
+ * This should be properly solved at some point. */
BKE_id_free(main, id);
+ if (r_id != NULL) {
+ *r_id = NULL;
+ }
}
return (bhead);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index dc8e5e9f97e..3c4b153d2ed 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -636,6 +636,29 @@ static ARegion *do_versions_add_region(int regiontype, const char *name)
return ar;
}
+static void do_versions_area_ensure_tool_region(Main *bmain,
+ const short space_type,
+ 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) {
+ if (sl->spacetype == space_type) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
+ if (!ar) {
+ ARegion *header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ar = do_versions_add_region(RGN_TYPE_TOOLS, "tools region");
+ BLI_insertlinkafter(regionbase, header, ar);
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar->flag = region_flag;
+ }
+ }
+ }
+ }
+ }
+}
+
static void do_version_bones_split_bbone_scale(ListBase *lb)
{
for (Bone *bone = lb->first; bone; bone = bone->next) {
@@ -1034,7 +1057,7 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
/* Free Style */
LISTBASE_FOREACH (struct FreestyleLineStyle *, linestyle, &bmain->linestyles) {
- LISTBASE_FOREACH (LineStyleModifier *, m, &linestyle->thickness_modifiers) {
+ LISTBASE_FOREACH (LineStyleModifier *, m, &linestyle->alpha_modifiers) {
switch (m->type) {
case LS_MODIFIER_ALONG_STROKE:
callback(((LineStyleAlphaModifier_AlongStroke *)m)->curve);
@@ -1091,6 +1114,18 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
}
}
+static void do_version_fcurve_hide_viewport_fix(struct ID *UNUSED(id),
+ struct FCurve *fcu,
+ void *UNUSED(user_data))
+{
+ if (strcmp(fcu->rna_path, "hide")) {
+ return;
+ }
+
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = BLI_strdupn("hide_viewport", 13);
+}
+
void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
{
bool use_collection_compat_28 = true;
@@ -1524,6 +1559,25 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
}
+
+ /**
+ * 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. */
+
+ /* During development of Blender 2.80 the "Object.hide" property was
+ * removed, and reintroduced in 5e968a996a53 as "Object.hide_viewport". */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ BKE_fcurves_id_cb(&ob->id, do_version_fcurve_hide_viewport_fix, NULL);
+ }
+ }
}
/* NOTE: This version patch is intended for versions < 2.52.2,
@@ -2797,6 +2851,35 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ /* Files stored pre 2.5 (possibly re-saved with newer versions) may have non-visible
+ * spaces without a header (visible/active ones are properly versioned).
+ * Multiple version patches below assume there's always a header though. So inserting this
+ * patch in-between older ones to add a header when needed.
+ *
+ * From here on it should be fine to assume there always is a header.
+ */
+ 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);
+
+ if (!ar_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. */
+ BLI_assert(!do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER));
+
+ ARegion *ar = do_versions_add_region(RGN_TYPE_HEADER, "header 2.83.1 versioning");
+ ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ BLI_addhead(regionbase, ar);
+ }
+ }
+ }
+ }
+ }
+
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) {
@@ -3678,7 +3761,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
/* All spaces that use tools must be eventually added. */
ARegion *ar = NULL;
- if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE) &&
+ if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ) &&
((ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)) == NULL)) {
/* Add tool header. */
ar = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header");
@@ -4291,6 +4374,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Keep this block, even when empty. */
+ /* 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) {
@@ -4330,5 +4416,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Brush cursor alpha */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ br->add_col[3] = 0.9f;
+ br->sub_col[3] = 0.9f;
+ }
+
+ /* Pose brush IK segments. */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->pose_ik_segments == 0) {
+ br->pose_ik_segments = 1;
+ }
+ }
}
} \ No newline at end of file
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index a4ad954254a..466dd02b3b3 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -1219,7 +1219,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
bNodeSocket *sockDistortion = nodeFindSocket(node, SOCK_IN, "Distortion");
float *distortion = cycles_node_socket_float_value(sockDistortion);
- if (socket_is_used(sockDistortion)) {
+ if (socket_is_used(sockDistortion) && sockDistortion->link != NULL) {
bNode *distortionInputNode = sockDistortion->link->fromnode;
bNodeSocket *distortionInputSock = sockDistortion->link->fromsock;
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index bc43d9605e2..8c7a0c4f7b2 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -207,13 +207,20 @@ static void blo_update_defaults_screen(bScreen *screen,
}
}
- /* Show top-bar by default. */
+ /* 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;
+
for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
- ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
+ if ((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) {
+ ar->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index b1f70848bdc..94ee8d46675 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -164,6 +164,17 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_view3d.face_front);
}
+ if (!USER_VERSION_ATLEAST(283, 1)) {
+ FROM_DEFAULT_V4_UCHAR(space_view3d.bone_locked_weight);
+ }
+
+ if (!USER_VERSION_ATLEAST(283, 2)) {
+ FROM_DEFAULT_V4_UCHAR(space_info.info_property);
+ FROM_DEFAULT_V4_UCHAR(space_info.info_property_text);
+ FROM_DEFAULT_V4_UCHAR(space_info.info_operator);
+ FROM_DEFAULT_V4_UCHAR(space_info.info_operator_text);
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 2ad9ec9cae3..74258aeaa7a 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2067,9 +2067,7 @@ static void write_customdata(WriteData *wd,
int count,
CustomData *data,
CustomDataLayer *layers,
- CustomDataMask cddata_mask,
- int partial_type,
- int partial_count)
+ CustomDataMask cddata_mask)
{
int i;
@@ -2106,16 +2104,7 @@ static void write_customdata(WriteData *wd,
else {
CustomData_file_write_info(layer->type, &structname, &structnum);
if (structnum) {
- /* when using partial visibility, the MEdge and MFace layers
- * are smaller than the original, so their type and count is
- * passed to make this work */
- if (layer->type != partial_type) {
- datasize = structnum * count;
- }
- else {
- datasize = structnum * partial_count;
- }
-
+ datasize = structnum * count;
writestruct_id(wd, DATA, structname, datasize, layer->data);
}
else {
@@ -2134,85 +2123,70 @@ static void write_customdata(WriteData *wd,
static void write_mesh(WriteData *wd, Mesh *mesh)
{
- CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
-
if (mesh->id.us > 0 || wd->use_memfile) {
- /* write LibData */
- {
- /* write a copy of the mesh, don't modify in place because it is
- * not thread safe for threaded renders that are reading this */
- 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));
-
- /**
- * Those calls:
- * - Reduce mesh->xdata.totlayer to number of layers to write.
- * - Fill xlayers with those layers to be written.
- * Note that mesh->xdata is from now on invalid for Blender,
- * but this is why the whole mesh is a temp local copy!
- */
- CustomData_file_write_prepare(
- &mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_file_write_prepare(
- &mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
- flayers = flayers_buff;
- 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);
- write_iddata(wd, &mesh->id);
-
- /* direct data */
- if (mesh->adt) {
- write_animdata(wd, mesh->adt);
- }
+ /* 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));
+
+ /* Reduce xdata layers, fill xlayers with layers to be written.
+ * This makes xdata invalid for Blender, which is why we made a
+ * temporary local copy. */
+ CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
+
+ CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ flayers = flayers_buff;
+ 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);
+ write_iddata(wd, &mesh->id);
- writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
- writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
+ /* direct data */
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- write_customdata(
- wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, CD_MASK_MESH.vmask, -1, 0);
- write_customdata(
- wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, CD_MASK_MESH.emask, -1, 0);
- /* fdata is really a dummy - written so slots align */
- write_customdata(
- wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, CD_MASK_MESH.fmask, -1, 0);
- write_customdata(
- wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, CD_MASK_MESH.lmask, -1, 0);
- write_customdata(
- wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, CD_MASK_MESH.pmask, -1, 0);
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
+ writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
- /* restore pointer */
- mesh = old_mesh;
- }
- }
+ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, CD_MASK_MESH.vmask);
+ write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, CD_MASK_MESH.emask);
+ /* fdata is really a dummy - written so slots align */
+ write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, CD_MASK_MESH.fmask);
+ 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);
- if (vlayers && vlayers != vlayers_buff) {
- MEM_freeN(vlayers);
- }
- if (elayers && elayers != elayers_buff) {
- MEM_freeN(elayers);
- }
- if (flayers && flayers != flayers_buff) {
- MEM_freeN(flayers);
- }
- if (llayers && llayers != llayers_buff) {
- MEM_freeN(llayers);
- }
- if (players && players != players_buff) {
- MEM_freeN(players);
+ /* restore pointer */
+ mesh = old_mesh;
+
+ /* free temporary data */
+ if (vlayers && vlayers != vlayers_buff) {
+ MEM_freeN(vlayers);
+ }
+ if (elayers && elayers != elayers_buff) {
+ MEM_freeN(elayers);
+ }
+ if (flayers && flayers != flayers_buff) {
+ MEM_freeN(flayers);
+ }
+ if (llayers && llayers != llayers_buff) {
+ MEM_freeN(llayers);
+ }
+ if (players && players != players_buff) {
+ MEM_freeN(players);
+ }
}
}
diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
index 0361137f5b1..147c375aa6e 100644
--- a/source/blender/blentranslation/msgfmt/CMakeLists.txt
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -30,6 +30,7 @@ set(SRC
msgfmt.c
)
+setup_libdirs()
add_cc_flags_custom_test(msgfmt)
if(APPLE)
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 00954eb400c..35c33837d64 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -183,6 +183,8 @@ if(WITH_BULLET)
)
list(APPEND LIB
extern_bullet
+
+ ${BULLET_LIBRARIES}
)
add_definitions(-DWITH_BULLET)
endif()
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 74d01dca66a..4fa7bf64834 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -102,6 +102,16 @@ static BMO_FlagSet bmo_enum_axis_xyz[] = {
{0, NULL},
};
+static BMO_FlagSet bmo_enum_axis_neg_xyz_and_xyz[] = {
+ {0, "-X"},
+ {1, "-Y"},
+ {2, "-Z"},
+ {3, "X"},
+ {4, "Y"},
+ {5, "Z"},
+ {0, NULL},
+};
+
static BMO_FlagSet bmo_enum_falloff_type[] = {
{SUBD_FALLOFF_SMOOTH, "SMOOTH"},
{SUBD_FALLOFF_SPHERE, "SPHERE"},
@@ -2046,7 +2056,7 @@ static BMOpDefine bmo_symmetrize_def = {
"symmetrize",
/* slots_in */
{{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
- {"direction", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_axis_xyz}, /* axis to use */
+ {"direction", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_axis_neg_xyz_and_xyz}, /* axis to use */
{"dist", BMO_OP_SLOT_FLT}, /* minimum distance */
{{'\0'}},
},
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index a121bd3b9f4..a9b0d4d3918 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -2477,39 +2477,53 @@ bool BM_face_is_normal_valid(const BMFace *f)
return len_squared_v3v3(no, f->no) < (eps * eps);
}
-static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol)
+/**
+ * Use to accumulate volume calculation for faces with consistent winding.
+ *
+ * Use double precision since this is prone to float precision error, see T73295.
+ */
+static double bm_mesh_calc_volume_face(const BMFace *f)
{
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
uint(*index)[3] = BLI_array_alloca(index, tottri);
- int j;
+ double vol = 0.0;
BM_face_calc_tessellation(f, false, loops, index);
- for (j = 0; j < tottri; j++) {
+ for (int j = 0; j < tottri; j++) {
const float *p1 = loops[index[j][0]]->v->co;
const float *p2 = loops[index[j][1]]->v->co;
const float *p3 = loops[index[j][2]]->v->co;
+ double p1_db[3];
+ double p2_db[3];
+ double p3_db[3];
+
+ copy_v3db_v3fl(p1_db, p1);
+ copy_v3db_v3fl(p2_db, p2);
+ copy_v3db_v3fl(p3_db, p3);
+
/* co1.dot(co2.cross(co3)) / 6.0 */
- float cross[3];
- cross_v3_v3v3(cross, p2, p3);
- *r_vol += (1.0f / 6.0f) * dot_v3v3(p1, cross);
+ double cross[3];
+ cross_v3_v3v3_db(cross, p2_db, p3_db);
+ vol += dot_v3v3_db(p1_db, cross);
}
+ return (1.0 / 6.0) * vol;
}
-float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
+double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
{
/* warning, calls own tessellation function, may be slow */
- float vol = 0.0f;
+ double vol = 0.0;
BMFace *f;
BMIter fiter;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- bm_mesh_calc_volume_face(f, &vol);
+ vol += bm_mesh_calc_volume_face(f);
}
if (is_signed == false) {
- vol = fabsf(vol);
+ vol = fabs(vol);
}
return vol;
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 134e0b99691..fb646b11076 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -233,7 +233,7 @@ bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_
bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+double BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index d9a7aa626e4..65b70f62b58 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -543,9 +543,14 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op)
BMO_op_initf(bm,
&extop,
op->flag,
- "extrude_face_region geom=%S use_normal_flip=%b use_normal_from_adjacent=%b",
+ "extrude_face_region "
+ "geom=%S "
+ "use_keep_orig=%b "
+ "use_normal_flip=%b "
+ "use_normal_from_adjacent=%b",
op,
"geom_last.out",
+ use_merge,
use_normal_flip && (a == 0),
(a != 0));
BMO_op_exec(bm, &extop);
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index f93d33bb05f..b9d5548f5d4 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -828,6 +828,11 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts)
for (i = 0; i < cuts; i++) {
/* no chance of double */
BM_face_split(bm, l_new->f, l_new->prev, l_new->next->next, &l_new, NULL, false);
+ if (l_new == NULL) {
+ /* This happens when l_new->prev and l_new->next->next are adjacent. Since
+ * this sets l_new to NULL, we cannot continue this for-loop. */
+ break;
+ }
if (l_new->f->len < l_new->radial_next->f->len) {
l_new = l_new->radial_next;
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 9cc645f7a3a..d3b3541a539 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -60,16 +60,7 @@
#define BEVEL_MATCH_SPEC_WEIGHT 0.2
//#define DEBUG_CUSTOM_PROFILE_CUTOFF
-//#define DEBUG_CUSTOM_PROFILE_SAMPLE
-
-#if defined(DEBUG_PROFILE_ORIENTATION_DRAW) || defined(DEBUG_CUSTOM_PROFILE_PIPE)
-static float debug_color_red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
-static float debug_color_blue[4] = {0.0f, 0.0f, 1.0f, 1.0f};
-extern void DRW_debug_sphere(const float center[3], const float radius, const float color[4]);
-extern void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]);
-#endif
-
-/* happens far too often, uncomment for development */
+/* Happens far too often, uncomment for development. */
// #define BEVEL_ASSERT_PROJECT
/* for testing */
@@ -155,6 +146,8 @@ typedef struct Profile {
float *prof_co;
/** Like prof_co, but for seg power of 2 >= seg */
float *prof_co_2;
+ /** Mark a special case so the these parameters aren't reset with others. */
+ bool special_params;
} Profile;
#define PRO_SQUARE_R 1e4f
#define PRO_CIRCLE_R 2.0f
@@ -266,7 +259,7 @@ typedef struct BevVert {
VMesh *vmesh;
} BevVert;
-/* face classification: note depend on F_RECON > F_EDGE > F_VERT */
+/* Face classification. Note: depends on F_RECON > F_EDGE > F_VERT */
typedef enum {
/** Used when there is no face at all */
F_NONE,
@@ -290,10 +283,6 @@ enum {
ANGLE_LARGER = 1,
};
-#if 0
-static const char* fkind_names[] = {"F_NONE", "F_ORIG", "F_VERT", "F_EDGE", "F_RECON"}; /* DEBUG */
-#endif
-
/** Bevel parameters and state */
typedef struct BevelParams {
/** Records BevVerts made: key BMVert*, value BevVert* */
@@ -359,12 +348,8 @@ typedef struct BevelParams {
// #pragma GCC diagnostic ignored "-Wpadded"
-/* Some flags to re-enable old behavior for a while,
- * in case fixes broke things not caught by regression tests. */
-static int bev_debug_flags = 0;
-#define DEBUG_OLD_PLANE_SPECIAL (bev_debug_flags & 1)
-#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
-#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+/* Only for debugging, shouldn't be in blender repo. */
+// #include "bevdebug.c"
/* use the unused _BM_ELEM_TAG_ALT flag to flag the 'long' loops (parallel to beveled edge)
* of edge-polygons. */
@@ -994,23 +979,31 @@ static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1,
return (ang11 - ang1co > -BEVEL_EPSILON_ANG);
}
-/*
+/**
* Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco.
* e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of
* the bevel vertex, e1 precedes e2 in CCW order.
- * Except: if edges_between 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.
* Offset edge is on right of both edges, where e1 enters v and e2 leave it.
* When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2),
- * but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may
- * lead to different offsets) then meeting point can be found be intersecting offset lines.
+ * but if the offsets are not equal (we allow for because the bevel modifier has edge weights that
+ * may lead to different offsets) then the meeting point can be found by intersecting offset lines.
* If making the meeting point significantly changes the left or right offset from the user spec,
* 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
+ * 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,
+ * 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, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3])
+static void offset_meet(EdgeHalf *e1,
+ EdgeHalf *e2,
+ BMVert *v,
+ BMFace *f,
+ bool edges_between,
+ float meetco[3],
+ const EdgeHalf *e_in_plane)
{
float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3];
float norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3];
@@ -1018,10 +1011,10 @@ static void offset_meet(
float ang, d;
BMVert *closer_v;
EdgeHalf *e, *e1next, *e2prev;
- BMFace *ff;
+ BMFace *fnext;
int isect_kind;
- /* get direction vectors for two offset lines */
+ /* Get direction vectors for two offset lines. */
sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
@@ -1032,20 +1025,20 @@ static void offset_meet(
sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
}
else {
- /* shup up 'maybe unused' warnings */
+ /* Shut up 'maybe unused' warnings. */
zero_v3(dir1n);
zero_v3(dir2p);
}
ang = angle_v3v3(dir1, dir2);
if (ang < BEVEL_EPSILON_ANG) {
- /* special case: e1 and e2 are parallel; put offset point perp to both, from v.
+ /* Special case: e1 and e2 are parallel; put offset point perp to both, from v.
* need to find a suitable plane.
- * this code used to just use offset and dir1, but that makes for visible errors
+ * This code used to just use offset and dir1, but that makes for visible errors
* on a circle with > 200 sides, which trips this "nearly perp" code (see T61214).
* so use the average of the two, and the offset formula for angle bisector.
- * if offsets are different, we're out of luck:
- * use the max of the two (so get consistent looking results if the same situation
+ * If offsets are different, we're out of luck:
+ * Use the max of the two (so get consistent looking results if the same situation
* arises elsewhere in the object but with opposite roles for e1 and e2 */
if (f) {
copy_v3_v3(norm_v, f->no);
@@ -1063,23 +1056,21 @@ static void offset_meet(
copy_v3_v3(meetco, off1a);
}
else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) {
- /* special case e1 and e2 are antiparallel, so bevel is into
- * a zero-area face. Just make the offset point on the
- * common line, at offset distance from v. */
+ /* Special case: e1 and e2 are antiparallel, so bevel is into a zero-area face.
+ * Just make the offset point on the common line, at offset distance from v. */
d = max_ff(e1->offset_r, e2->offset_l);
slide_dist(e2, v, d, meetco);
}
else {
- /* Get normal to plane where meet point should be,
- * using cross product instead of f->no in case f is non-planar.
- * Except: sometimes locally there can be a small angle
- * between dir1 and dir2 that leads to a normal that is actually almost
- * perpendicular to the face normal; in this case it looks wrong to use
- * the local (cross-product) normal, so use the face normal if the angle
- * between dir1 and dir2 is smallish.
+ /* Get normal to plane where meet point should be, using cross product instead of f->no
+ * in case f is non-planar.
+ * Except: sometimes locally there can be a small angle between dir1 and dir2 that leads
+ * to a normal that is actually almost perpendicular to the face normal;
+ * in this case it looks wrong to use the local (cross-product) normal,
+ * so use the face normal if the angle between dir1 and dir2 is smallish.
* If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip.
- * Use f->no to figure out which side to look at angle from, as even if
- * f is non-planar, will be more accurate than vertex normal */
+ * Use f->no to figure out which side to look at angle from, as even if f is non-planar,
+ * will be more accurate than vertex normal. */
if (f && ang < BEVEL_SMALL_ANG) {
copy_v3_v3(norm_v1, f->no);
copy_v3_v3(norm_v2, f->no);
@@ -1093,7 +1084,7 @@ static void offset_meet(
copy_v3_v3(norm_v2, norm_v1);
}
else {
- /* separate faces; get face norms at corners for each separately */
+ /* Separate faces; get face norms at corners for each separately. */
cross_v3_v3v3(norm_v1, dir1n, dir1);
normalize_v3(norm_v1);
f = e1->fnext;
@@ -1108,13 +1099,13 @@ static void offset_meet(
}
}
- /* get vectors perp to each edge, perp to norm_v, and pointing into face */
+ /* Get vectors perp to each edge, perp to norm_v, and pointing into face. */
cross_v3_v3v3(norm_perp1, dir1, norm_v1);
cross_v3_v3v3(norm_perp2, dir2, norm_v2);
normalize_v3(norm_perp1);
normalize_v3(norm_perp2);
- /* get points that are offset distances from each line, then another point on each line */
+ /* Get points that are offset distances from each line, then another point on each line. */
copy_v3_v3(off1a, v->co);
madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
add_v3_v3v3(off1b, off1a, dir1);
@@ -1122,18 +1113,17 @@ static void offset_meet(
madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
add_v3_v3v3(off2b, off2a, dir2);
- /* intersect the lines */
+ /* Intersect the offset lines. */
isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
if (isect_kind == 0) {
- /* lines are collinear: we already tested for this, but this used a different epsilon */
- copy_v3_v3(meetco, off1a); /* just to do something */
+ /* Lines are collinear: we already tested for this, but this used a different epsilon. */
+ copy_v3_v3(meetco, off1a); /* Just to do something. */
}
else {
/* The lines intersect, but is it at a reasonable place?
- * One problem to check: if one of the offsets is 0, then don't
- * want an intersection that is outside that edge itself.
- * This can happen if angle between them is > 180 degrees,
- * or if the offset amount is > the edge length*/
+ * One problem to check: if one of the offsets is 0, then don't want an intersection
+ * that is outside that edge itself. This can happen if angle between them is > 180 degrees,
+ * or if the offset amount is > the edge length. */
if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) {
copy_v3_v3(meetco, closer_v->co);
}
@@ -1141,19 +1131,26 @@ static void offset_meet(
copy_v3_v3(meetco, closer_v->co);
}
if (edges_between && e1->offset_r > 0.0f && e2->offset_l > 0.0f) {
- /* Try to drop meetco to a face between e1 and e2 */
+ /* Try to drop meetco to a face between e1 and e2. */
if (isect_kind == 2) {
- /* lines didn't meet in 3d: get average of meetco and isect2 */
+ /* Lines didn't meet in 3d: get average of meetco and isect2. */
mid_v3_v3v3(meetco, meetco, isect2);
}
for (e = e1; e != e2; e = e->next) {
- ff = e->fnext;
- if (!ff) {
+ fnext = e->fnext;
+ if (!fnext) {
continue;
}
- plane_from_point_normal_v3(plane, v->co, ff->no);
+ plane_from_point_normal_v3(plane, v->co, fnext->no);
closest_to_plane_normalized_v3(dropco, plane, meetco);
- if (point_between_edges(dropco, v, ff, e, e->next)) {
+ /* Don't drop to the faces next to the in plane edge. */
+ if (e_in_plane) {
+ ang = angle_v3v3(fnext->no, e_in_plane->fnext->no);
+ if ((fabsf(ang) < BEVEL_SMALL_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_SMALL_ANG)) {
+ continue;
+ }
+ }
+ if (point_between_edges(dropco, v, fnext, e, e->next)) {
copy_v3_v3(meetco, dropco);
break;
}
@@ -1163,8 +1160,7 @@ static void offset_meet(
}
}
-/* Chosen so that 1/sin(BEVEL_GOOD_ANGLE) is about 4,
- * giving that expansion factor to bevel width. */
+/* Chosen so 1/sin(BEVEL_GOOD_ANGLE) is about 4, giving that expansion factor to bevel width. */
#define BEVEL_GOOD_ANGLE 0.25f
/* Calculate the meeting point between e1 and e2 (one of which should have zero offsets),
@@ -1182,7 +1178,7 @@ static bool offset_meet_edge(
normalize_v3(dir1);
normalize_v3(dir2);
- /* find angle from dir1 to dir2 as viewed from vertex normal side */
+ /* Find angle from dir1 to dir2 as viewed from vertex normal side. */
ang = angle_normalized_v3v3(dir1, dir2);
if (fabsf(ang) < BEVEL_GOOD_ANGLE) {
if (r_angle) {
@@ -1192,7 +1188,7 @@ static bool offset_meet_edge(
}
cross_v3_v3v3(fno, dir1, dir2);
if (dot_v3v3(fno, v->no) < 0.0f) {
- ang = 2.0f * (float)M_PI - ang; /* angle is reflex */
+ ang = 2.0f * (float)M_PI - ang; /* Angle is reflex. */
if (r_angle) {
*r_angle = ang;
}
@@ -1219,7 +1215,7 @@ static bool offset_meet_edge(
}
/* Return true if it will look good to put the meeting point where offset_on_edge_between
- * would put it. This means that neither side sees a reflex angle */
+ * would put it. This means that neither side sees a reflex angle. */
static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v)
{
float ang;
@@ -1248,7 +1244,7 @@ static bool offset_on_edge_between(
if (ok1 && ok2) {
mid_v3_v3v3(meetco, meet1, meet2);
if (r_sinratio) {
- /* ang1 should not be 0, but be paranoid */
+ /* ang1 should not be 0, but be paranoid. */
*r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1);
}
retval = true;
@@ -1261,7 +1257,7 @@ static bool offset_on_edge_between(
}
else {
/* Neither offset line met emid.
- * This should only happen if all three lines are on top of each other */
+ * This should only happen if all three lines are on top of each other. */
slide_dist(emid, v, e1->offset_r, meetco);
}
@@ -1269,8 +1265,7 @@ static bool offset_on_edge_between(
}
/* Offset by e->offset in plane with normal plane_no, on left if left==true,
- * else on right. If no is NULL, choose an arbitrary plane different
- * from eh's direction. */
+ * else on right. If no is NULL, choose an arbitrary plane different from eh's direction. */
static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, float r[3])
{
float dir[3], no[3], fdir[3];
@@ -1303,8 +1298,11 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, flo
madd_v3_v3fl(r, fdir, left ? e->offset_l : e->offset_r);
}
-/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */
-static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3])
+/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco. */
+static void project_to_edge(const BMEdge *e,
+ const float co_a[3],
+ const float co_b[3],
+ float projco[3])
{
float otherco[3];
@@ -1317,56 +1315,37 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3],
}
/* If there is a bndv->ebev edge, find the mid control point if necessary.
- * It is the closest point on the beveled edge to the line segment between
- * bndv and bndv->next. */
+ * It is the closest point on the beveled edge to the line segment between bndv and bndv->next. */
static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
{
- EdgeHalf *e;
- Profile *pro;
- float co1[3], co2[3], co3[3], d1[3], d2[3];
- bool do_linear_interp;
+ float start[3], end[3], co3[3], d1[3], d2[3];
+ bool do_linear_interp = true;
+ EdgeHalf *e = bndv->ebev;
+ Profile *pro = &bndv->profile;
- copy_v3_v3(co1, bndv->nv.co);
- copy_v3_v3(co2, bndv->next->nv.co);
- pro = &bndv->profile;
- e = bndv->ebev;
- do_linear_interp = true;
+ copy_v3_v3(start, bndv->nv.co);
+ copy_v3_v3(end, bndv->next->nv.co);
if (e) {
do_linear_interp = false;
pro->super_r = bp->pro_super_r;
- /* projection direction is direction of the edge */
+ /* projection direction is direction of the edge. */
sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
if (e->is_rev) {
negate_v3(pro->proj_dir);
}
normalize_v3(pro->proj_dir);
- project_to_edge(e->e, co1, co2, pro->middle);
- if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
- /* put arc endpoints on plane with normal proj_dir, containing middle */
- add_v3_v3v3(co3, co1, pro->proj_dir);
- if (!isect_line_plane_v3(pro->start, co1, co3, pro->middle, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->start, co1);
- }
- add_v3_v3v3(co3, co2, pro->proj_dir);
- if (!isect_line_plane_v3(pro->end, co2, co3, pro->middle, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->end, co2);
- }
- }
- else {
- copy_v3_v3(pro->start, co1);
- copy_v3_v3(pro->end, co2);
- }
- /* default plane to project onto is the one with triangle co1 - middle - co2 in it */
- sub_v3_v3v3(d1, pro->middle, co1);
- sub_v3_v3v3(d2, pro->middle, co2);
+ project_to_edge(e->e, start, end, pro->middle);
+ copy_v3_v3(pro->start, start);
+ copy_v3_v3(pro->end, end);
+ /* Default plane to project onto is the one with triangle start - middle - end in it. */
+ sub_v3_v3v3(d1, pro->middle, start);
+ sub_v3_v3v3(d2, pro->middle, end);
normalize_v3(d1);
normalize_v3(d2);
cross_v3_v3v3(pro->plane_no, d1, d2);
normalize_v3(pro->plane_no);
if (nearly_parallel(d1, d2)) {
- /* co1 - middle -co2 are collinear.
+ /* Start - middle - end are collinear.
* Should be case that beveled edge is coplanar with two boundary verts.
* We want to move the profile to that common plane, if possible.
* That makes the multi-segment bevels curve nicely in that plane, as users expect.
@@ -1375,94 +1354,91 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
* If the profile is going to lead into unbeveled edges on each side
* (that is, both BoundVerts are "on-edge" points on non-beveled edges)
*/
- if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) {
- do_linear_interp = true;
- }
- else {
- if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
- copy_v3_v3(pro->start, co1);
- copy_v3_v3(pro->end, co2);
- }
- if (DEBUG_OLD_FLAT_MID) {
- copy_v3_v3(pro->middle, bv->v->co);
- }
- else {
- copy_v3_v3(pro->middle, bv->v->co);
- if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
- /* want mid at the meet point of next and prev offset edges */
- float d3[3], d4[3], co4[3], meetco[3], isect2[3];
- int isect_kind;
-
- sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
- sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
- normalize_v3(d3);
- normalize_v3(d4);
- if (nearly_parallel(d3, d4)) {
- /* offset lines are collinear - want linear interpolation */
- mid_v3_v3v3(pro->middle, co1, co2);
- do_linear_interp = true;
- }
- else {
- add_v3_v3v3(co3, co1, d3);
- add_v3_v3v3(co4, co2, d4);
- isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
- if (isect_kind != 0) {
- copy_v3_v3(pro->middle, meetco);
- }
- else {
- /* offset lines don't intersect - want linear interpolation */
- mid_v3_v3v3(pro->middle, co1, co2);
- do_linear_interp = true;
- }
- }
- }
- }
- copy_v3_v3(pro->end, co2);
- sub_v3_v3v3(d1, pro->middle, co1);
- normalize_v3(d1);
- sub_v3_v3v3(d2, pro->middle, co2);
- normalize_v3(d2);
- cross_v3_v3v3(pro->plane_no, d1, d2);
- normalize_v3(pro->plane_no);
- if (nearly_parallel(d1, d2)) {
- /* whole profile is collinear with edge: just interpolate */
+ copy_v3_v3(pro->middle, bv->v->co);
+ if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
+ /* Want mid at the meet point of next and prev offset edges. */
+ float d3[3], d4[3], co4[3], meetco[3], isect2[3];
+ int isect_kind;
+
+ sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
+ sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
+ normalize_v3(d3);
+ normalize_v3(d4);
+ if (nearly_parallel(d3, d4)) {
+ /* Offset lines are collinear - want linear interpolation. */
+ mid_v3_v3v3(pro->middle, start, end);
do_linear_interp = true;
}
else {
- copy_v3_v3(pro->plane_co, bv->v->co);
- copy_v3_v3(pro->proj_dir, pro->plane_no);
+ add_v3_v3v3(co3, start, d3);
+ add_v3_v3v3(co4, end, d4);
+ isect_kind = isect_line_line_v3(start, co3, end, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->middle, meetco);
+ }
+ else {
+ /* Offset lines don't intersect - want linear interpolation. */
+ mid_v3_v3v3(pro->middle, start, end);
+ do_linear_interp = true;
+ }
}
}
+ copy_v3_v3(pro->end, end);
+ sub_v3_v3v3(d1, pro->middle, start);
+ normalize_v3(d1);
+ sub_v3_v3v3(d2, pro->middle, end);
+ normalize_v3(d2);
+ cross_v3_v3v3(pro->plane_no, d1, d2);
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
+ /* Whole profile is collinear with edge: just interpolate. */
+ do_linear_interp = true;
+ }
+ else {
+ copy_v3_v3(pro->plane_co, bv->v->co);
+ copy_v3_v3(pro->proj_dir, pro->plane_no);
+ }
}
- copy_v3_v3(pro->plane_co, co1);
+ copy_v3_v3(pro->plane_co, start);
}
else if (bndv->is_arc_start) {
- /* assume pro->middle was alredy set */
- copy_v3_v3(pro->start, co1);
- copy_v3_v3(pro->end, co2);
+ /* Assume pro->middle was already set. */
+ copy_v3_v3(pro->start, start);
+ copy_v3_v3(pro->end, end);
pro->super_r = PRO_CIRCLE_R;
zero_v3(pro->plane_co);
zero_v3(pro->plane_no);
zero_v3(pro->proj_dir);
do_linear_interp = false;
}
+ else if (bp->vertex_only) {
+ copy_v3_v3(pro->start, start);
+ copy_v3_v3(pro->middle, bv->v->co);
+ copy_v3_v3(pro->end, end);
+ pro->super_r = bp->pro_super_r;
+ zero_v3(pro->plane_co);
+ zero_v3(pro->plane_no);
+ zero_v3(pro->proj_dir);
+ do_linear_interp = false;
+ }
+
if (do_linear_interp) {
pro->super_r = PRO_LINE_R;
- copy_v3_v3(pro->start, co1);
- copy_v3_v3(pro->end, co2);
- mid_v3_v3v3(pro->middle, co1, co2);
- /* won't use projection for this line profile */
+ copy_v3_v3(pro->start, start);
+ copy_v3_v3(pro->end, end);
+ mid_v3_v3v3(pro->middle, start, end);
+ /* Won't use projection for this line profile. */
zero_v3(pro->plane_co);
zero_v3(pro->plane_no);
zero_v3(pro->proj_dir);
}
}
-/* Maybe move the profile plane for bndv->ebev to the plane its profile's start, and the
+/* Maybe move the profile plane for bndv->ebev to the plane its profile's start, and the
* original beveled vert, bmv. This will usually be the plane containing its adjacent
* non-beveled edges, but sometimes the start and the end are not on those edges.
*
- * Currently just used in build boundary terminal edge */
+ * Currently just used in #build_boundary_terminal_edge */
static void move_profile_plane(BoundVert *bndv, BMVert *bmvert)
{
float d1[3], d2[3], no[3], no2[3], no3[3], dot2, dot3;
@@ -1487,6 +1463,9 @@ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert)
copy_v3_v3(bndv->profile.plane_no, no);
}
}
+
+ /* We've changed the parameters from their defaults, so don't recalculate them later. */
+ pro->special_params = true;
}
/* Move the profile plane for the two BoundVerts involved in a weld.
@@ -1522,6 +1501,10 @@ static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *b
copy_v3_v3(bndv2->profile.plane_no, no);
}
}
+
+ /* We've changed the parameters from their defaults, so don't recalculate them later. */
+ bndv1->profile.special_params = true;
+ bndv2->profile.special_params = true;
}
/* return 1 if a and b are in CCW order on the normal side of f,
@@ -1739,6 +1722,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b
else {
map_ok = make_unit_square_map(pro->start, pro->middle, pro->end, map);
}
+
if (bp->vmesh_method == BEVEL_VMESH_CUTOFF && map_ok) {
/* Calculate the "height" of the profile by putting the (0,0) and (1,1) corners of the
* un-transformed profile throughout the 2D->3D map and calculating the distance between them.
@@ -1750,6 +1734,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b
mul_v3_m4v3(top_corner, map, p);
pro->height = len_v3v3(bottom_corner, top_corner);
}
+
/* The first iteration is the nseg case, the second is the seg_2 case (if it's needed) */
for (i = 0; i < 2; i++) {
if (i == 0) {
@@ -2295,14 +2280,14 @@ static int count_bound_vert_seams(BevVert *bv)
return ans;
}
-/* Is e between two planes where angle between is 180? */
+/* Is e between two faces with a 180 degree angle between their normals? */
static bool eh_on_plane(EdgeHalf *e)
{
float dot;
if (e->fprev && e->fnext) {
dot = dot_v3v3(e->fprev->no, e->fnext->no);
- if (fabsf(dot) <= BEVEL_EPSILON_BIG || fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG) {
+ if (fabsf(dot + 1.0f) <= BEVEL_EPSILON_BIG || fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG) {
return true;
}
}
@@ -2312,15 +2297,20 @@ static bool eh_on_plane(EdgeHalf *e)
/* Calculate the profiles for all the BoundVerts of VMesh vm */
static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm)
{
- BoundVert *bndv;
-
- bndv = vm->boundstart;
+ BoundVert *bndv = vm->boundstart;
do {
- set_profile_params(bp, bv, bndv);
- /* Use the miter profile spacing struct if the default is filled with the custom profile. */
- bool miter_profile = bp->use_custom_profile && (bndv->is_arc_start || bndv->is_patch_start);
- /* Don't bother reversing the profile if it's a miter profile */
- bool reverse_profile = !bndv->is_profile_start && !miter_profile;
+ /* In special cases the params will have already been set. */
+ if (!bndv->profile.special_params) {
+ set_profile_params(bp, bv, bndv);
+ }
+ bool miter_profile = false;
+ bool reverse_profile = false;
+ if (bp->use_custom_profile) {
+ /* Use the miter profile spacing struct if the default is filled with the custom profile. */
+ miter_profile = (bndv->is_arc_start || bndv->is_patch_start);
+ /* Don't bother reversing the profile if it's a miter profile */
+ reverse_profile = !bndv->is_profile_start && !miter_profile;
+ }
calculate_profile(bp, bndv, reverse_profile, miter_profile);
} while ((bndv = bndv->next) != vm->boundstart);
}
@@ -2348,8 +2338,6 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
}
} while ((e = e->next) != efirst);
- calculate_vm_profiles(bp, bv, vm);
-
if (construct) {
set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2) {
@@ -2422,7 +2410,7 @@ static void build_boundary_terminal_edge(BevelParams *bp,
* and join with the beveled edge to make a poly or adj mesh,
* Because e->prev has offset 0, offset_meet will put co on that edge. */
/* TODO: should do something else if angle between e and e->prev > 180 */
- offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL);
if (construct) {
bndv = add_new_bound_vert(mem_arena, vm, co);
bndv->efirst = e->prev;
@@ -2434,7 +2422,7 @@ static void build_boundary_terminal_edge(BevelParams *bp,
adjust_bound_vert(e->leftv, co);
}
e = e->next;
- offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL);
if (construct) {
bndv = add_new_bound_vert(mem_arena, vm, co);
bndv->efirst = e->prev;
@@ -2462,15 +2450,13 @@ static void build_boundary_terminal_edge(BevelParams *bp,
}
}
}
- calculate_vm_profiles(bp, bv, vm);
if (bv->edgecount >= 3) {
/* Special case: snap profile to plane of adjacent two edges. */
bndv = vm->boundstart;
BLI_assert(bndv->ebev != NULL);
+ set_profile_params(bp, bv, bndv);
move_profile_plane(bndv, bv->v);
- /* This step happens before the profile orientation pass so don't reverse the profile. */
- calculate_profile(bp, bndv, false, false);
}
if (construct) {
@@ -2497,17 +2483,6 @@ static void build_boundary_terminal_edge(BevelParams *bp,
vm->mesh_kind = M_POLY;
}
}
-#ifdef DEBUG_CUSTOM_PROFILE_WELD
- if (bp->seg > 1) {
- printf("Terminal Edge Profile Coordinates:\n");
- for (int k = 0; k < bp->seg; k++) {
- printf("%0.4f, %0.4f, %0.4f\n",
- (double)vm->boundstart->profile.prof_co[3 * k],
- (double)vm->boundstart->profile.prof_co[3 * k + 1],
- (double)vm->boundstart->profile.prof_co[3 * k + 2]);
- }
- }
-#endif
}
/* Helper for build_boundary to handle special miters */
@@ -2592,18 +2567,20 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em
} while (v != vstart);
}
-/* Make a circular list of BoundVerts for bv, each of which has the coordinates
- * of a vertex on the boundary of the beveled vertex bv->v.
- * This may adjust some EdgeHalf widths, and there might have to be
- * a subsequent pass to make the widths as consistent as possible.
- * The first time through, construct will be true and we are making the BoundVerts
- * and setting up the BoundVert and EdgeHalf pointers appropriately.
- * For a width consistency path, 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.
- * Also, if construct, decide on the mesh pattern that will be used inside the boundary.
- * Doesn't make the actual BMVerts */
+/**
+ * Make a circular list of BoundVerts for bv, each of which has the coordinates of a vertex on the
+ * boundary of the beveled vertex bv->v. This may adjust some EdgeHalf widths, and there might have
+ * 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
+ * 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.
+ */
static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
{
MemArena *mem_arena = bp->mem_arena;
@@ -2614,7 +2591,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
int in_plane, not_in_plane, miter_outer, miter_inner;
int ang_kind;
- /* Current bevel does nothing if only one edge into a vertex */
+ /* Current bevel does nothing if only one edge into a vertex. */
if (bv->edgecount <= 1) {
return;
}
@@ -2626,21 +2603,21 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
vm = bv->vmesh;
- /* Find a beveled edge to be efirst */
+ /* Find a beveled edge to be efirst. */
e = efirst = next_bev(bv, NULL);
BLI_assert(e->is_bev);
if (bv->selcount == 1) {
- /* Special case: only one beveled edge in */
+ /* Special case: only one beveled edge in. */
build_boundary_terminal_edge(bp, bv, efirst, construct);
return;
}
- /* Special miters outside only for 3 or more beveled edges */
+ /* Special miters outside only for 3 or more beveled edges. */
miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP;
miter_inner = bp->miter_inner;
- /* keep track of the first beveled edge of an outside miter (there can be at most 1 per bv */
+ /* Keep track of the first beveled edge of an outside miter (there can be at most 1 per bv). */
emiter = NULL;
/* There is more than one beveled edge.
@@ -2650,14 +2627,13 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
do {
BLI_assert(e->is_bev);
eon = NULL;
- /* Make the BoundVert for the right side of e; other side will be made
- * when the beveled edge to the left of e is handled.
- * Analyze edges until next beveled edge.
- * They are either "in plane" (preceding and subsequent faces are coplanar) or not.
- * The "non-in-plane" edges affect the silhouette and we prefer to slide along one of those if
- * possible. */
- in_plane = not_in_plane = 0; /* Counts of in-plane / not-in-plane */
- enip = eip = NULL; /* representatives of each */
+ /* Make the BoundVert for the right side of e; the other side will be made when the beveled
+ * edge to the left of e is handled.
+ * Analyze edges until next beveled edge: They are either "in plane" (preceding and subsequent
+ * faces are coplanar) or not. The "non-in-plane" edges affect the silhouette and we prefer to
+ * slide along one of those if possible. */
+ in_plane = not_in_plane = 0; /* Counts of in-plane / not-in-plane. */
+ enip = eip = NULL; /* Representatives of each type. */
for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
if (eh_on_plane(e2)) {
in_plane++;
@@ -2668,8 +2644,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
enip = e2;
}
}
+
if (in_plane == 0 && not_in_plane == 0) {
- offset_meet(e, e2, bv->v, e->fnext, false, co);
+ offset_meet(e, e2, bv->v, e->fnext, false, co, NULL);
}
else if (not_in_plane > 0) {
if (bp->loop_slide && not_in_plane == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
@@ -2678,7 +2655,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
else {
- offset_meet(e, e2, bv->v, NULL, true, co);
+ offset_meet(e, e2, bv->v, NULL, true, co, eip);
}
}
else {
@@ -2689,9 +2666,10 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
else {
- offset_meet(e, e2, bv->v, e->fnext, true, co);
+ offset_meet(e, e2, bv->v, e->fnext, true, co, eip);
}
}
+
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e;
@@ -2819,8 +2797,6 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
adjust_miter_coords(bp, bv, emiter);
}
- calculate_vm_profiles(bp, bv, vm);
-
if (construct) {
set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
@@ -3173,53 +3149,6 @@ static void regularize_profile_orientation(BevelParams *bp, BMEdge *bme)
}
}
-#ifdef DEBUG_PROFILE_ORIENTATION_DRAW
-/**
- * Draws markers on beveled edges showing the side that the profile starts on. A sphere shows
- * the start side of the profile where it starts, and the lines connected to the sphere show which
- * edge the orientation corresponds to.
- * \note Only drawn while bevel is calculating, the debug geometry is not persistent.
- */
-static void debug_draw_profile_orientation(BevelParams *bp, BMesh *bm)
-{
- BMIter iter;
- BMEdge *bmedge;
- float middle[3];
-
- BM_ITER_MESH (bmedge, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(bmedge, BM_ELEM_TAG)) {
- mid_v3_v3v3(middle, bmedge->v1->co, bmedge->v2->co);
-
- /* Draw the orientation for the first side of the edge. */
- EdgeHalf *edge_half = find_edge_half(find_bevvert(bp, bmedge->v1), bmedge);
- if (edge_half->leftv->is_profile_start) { /* The left boundvert defines the profiles. */
- DRW_debug_sphere(edge_half->leftv->nv.co, 0.04f, debug_color_red);
- DRW_debug_line_v3v3(middle, edge_half->leftv->nv.co, debug_color_red);
- DRW_debug_line_v3v3(bmedge->v1->co, edge_half->leftv->nv.co, debug_color_red);
- }
- else {
- DRW_debug_sphere(edge_half->rightv->nv.co, 0.04f, debug_color_red);
- DRW_debug_line_v3v3(middle, edge_half->rightv->nv.co, debug_color_red);
- DRW_debug_line_v3v3(bmedge->v1->co, edge_half->rightv->nv.co, debug_color_red);
- }
-
- /* Draw the orientation for the second side of the edge. */
- edge_half = find_edge_half(find_bevvert(bp, bmedge->v2), bmedge);
- if (edge_half->leftv->is_profile_start) {
- DRW_debug_sphere(edge_half->leftv->nv.co, 0.05f, debug_color_blue);
- DRW_debug_line_v3v3(middle, edge_half->leftv->nv.co, debug_color_blue);
- DRW_debug_line_v3v3(bmedge->v2->co, edge_half->leftv->nv.co, debug_color_blue);
- }
- else {
- DRW_debug_sphere(edge_half->rightv->nv.co, 0.05f, debug_color_blue);
- DRW_debug_line_v3v3(middle, edge_half->rightv->nv.co, debug_color_blue);
- DRW_debug_line_v3v3(bmedge->v2->co, edge_half->rightv->nv.co, debug_color_blue);
- }
- }
- }
-}
-#endif
-
/* Adjust the offsets for a single cycle or chain.
* For chains and some cycles, a fast solution exists.
* Otherwise, we set up and solve a linear least squares problem
@@ -3631,9 +3560,6 @@ static void vmesh_copy_equiv_verts(VMesh *vm)
/* Calculate and return in r_cent the centroid of the center poly */
static void vmesh_center(VMesh *vm, float r_cent[3])
{
-#ifdef DEBUG_CUSTOM_PROFILE_ADJ
- printf("VMESH CENTER\n");
-#endif
int n, ns2, i;
n = vm->count;
@@ -4145,9 +4071,8 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
copy_v3_v3(bndv->profile.plane_co, bndv->profile.start);
cross_v3_v3v3(bndv->profile.plane_no, bndv->profile.start, bndv->profile.end);
copy_v3_v3(bndv->profile.proj_dir, bndv->profile.plane_no);
- /* No need to reverse the profile or use the miter profile spacing struct because this case
- * isn't used with custom profiles. */
- calculate_profile(bp, bndv, false, false);
+ /* Calculate profiles again because we started over with new boundverts. */
+ calculate_profile(bp, bndv, false, false); /* No custom profiles in this case. */
/* Just building the boundaries here, so sample the profile halfway through */
get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co);
@@ -4347,6 +4272,10 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3])
copy_v3_v3(va, pro->start);
copy_v3_v3(vb, pro->end);
+ if (compare_v3v3(va, vb, BEVEL_EPSILON_D)) {
+ copy_v3_v3(co, va);
+ return;
+ }
/* Get a plane with the normal pointing along the beveled edge */
sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
@@ -4355,13 +4284,8 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3])
closest_to_plane_v3(va0, plane, va);
closest_to_plane_v3(vb0, plane, vb);
closest_to_plane_v3(vmid0, plane, pro->middle);
- if (make_unit_square_map(va0, vmid0, vb0, m)) {
+ if (make_unit_square_map(va0, vmid0, vb0, m) && invert_m4_m4(minv, m)) {
/* Transform co and project it onto superellipse */
- if (!invert_m4_m4(minv, m)) {
- /* shouldn't happen */
- BLI_assert(!"failed inverse during pipe profile snap");
- return;
- }
mul_v3_m4v3(p, minv, co);
snap_to_superellipsoid(p, pro->super_r, midline);
@@ -4382,14 +4306,6 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3])
*/
static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
{
-#ifdef DEBUG_CUSTOM_PROFILE_PIPE
- printf("PIPE ADJ VMESH\n");
- float green[4] = {0.0f, 1.0f, 0.0f, 1.0f};
- float blue[4] = {0.0f, 0.0f, 1.0f, 1.0f};
- float red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
- float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- float *color;
-#endif
int i, j, k, n_bndv, ns, half_ns, ipipe1, ipipe2, ring;
VMesh *vm;
bool even, midline;
@@ -4406,11 +4322,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
ipipe1 = vpipe->index;
ipipe2 = vpipe->next->next->index;
-#ifdef DEBUG_CUSTOM_PROFILE_PIPE
- printf("ipipe1: %d\n", ipipe1);
- printf("ipipe2: %d\n", ipipe2);
-#endif
-
for (i = 0; i < n_bndv; i++) {
for (j = 1; j <= half_ns; j++) {
for (k = 0; k <= half_ns; k++) {
@@ -4444,18 +4355,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
/* Place the vertex by interpolatin between the two profile points using the factor. */
interp_v3_v3v3(mesh_vert(vm, i, j, k)->co, profile_point_pipe1, profile_point_pipe2, f);
-#ifdef DEBUG_CUSTOM_PROFILE_PIPE
- printf("(%d, %d, %d)\n", i, j, k);
- printf("f: %.3f\n", f);
- printf("point 1: (%.3f, %.3f, %.3f)\n",
- profile_point_pipe1[0],
- profile_point_pipe1[1],
- profile_point_pipe1[2]);
- printf("point 2: (%.3f, %.3f, %.3f)\n",
- profile_point_pipe2[0],
- profile_point_pipe2[1],
- profile_point_pipe2[2]);
-#endif
}
else {
/* A tricky case is for the 'square' profiles and an even nseg: we want certain
@@ -4467,33 +4366,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
}
}
}
-#ifdef DEBUG_CUSTOM_PROFILE_PIPE
- /* Draw the locations of all the vertices after the "snapping" process */
- for (i = 0; i < n_bndv; i++) {
- for (j = 1; j <= half_ns; j++) {
- for (k = 1; k <= ns; k++) {
- if (!is_canon(vm, i, j, k)) {
- continue;
- }
- switch (i) {
- case 0:
- color = red;
- break;
- case 1:
- color = green;
- break;
- case 2:
- color = blue;
- break;
- case 3:
- color = white;
- break;
- }
- DRW_debug_sphere(mesh_vert(vm, i, j, k)->co, 0.01f, color);
- }
- }
- }
-#endif
return vm;
}
@@ -4910,20 +4782,6 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert
odd = ns % 2;
BLI_assert(n_bndv >= 3 && ns > 1);
- /* Add support for profiles in vertex only in-plane bevels. */
- if (bp->vertex_only) {
- bndv = bv->vmesh->boundstart;
- do {
- Profile *pro = &bndv->profile;
- copy_v3_v3(pro->middle, bv->v->co);
- pro->super_r = bp->pro_super_r;
- bool miter_profile = bp->use_custom_profile && (bndv->is_arc_start || bndv->is_patch_start);
- /* Orientation doesn't matter when only beveling vertices */
- calculate_profile(bp, bndv, false, miter_profile);
- bndv = bndv->next;
- } while (bndv != bv->vmesh->boundstart);
- }
-
if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd && !bp->use_custom_profile) {
vm1 = square_out_adj_vmesh(bp, bv);
}
@@ -5093,6 +4951,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
{
#ifdef DEBUG_CUSTOM_PROFILE_CUTOFF
printf("BEVEL BUILD CUTOFF\n");
+# define F3(v) (v)[0], (v)[1], (v)[2]
int j;
#endif
int i;
@@ -5131,10 +4990,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
#ifdef DEBUG_CUSTOM_PROFILE_CUTOFF
printf("Corner vertices:\n");
for (j = 0; j < n_bndv; j++) {
- printf(" (%.3f, %.3f, %.3f)\n",
- (double)mesh_vert(bv->vmesh, j, 1, 0)->co[0],
- (double)mesh_vert(bv->vmesh, j, 1, 0)->co[1],
- (double)mesh_vert(bv->vmesh, j, 1, 0)->co[2]);
+ printf(" (%.3f, %.3f, %.3f)\n", F3(mesh_vert(bv->vmesh, j, 1, 0)->co));
}
#endif
@@ -5192,21 +5048,14 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
if (bndv->is_patch_start || bndv->is_arc_start) {
printf(" Miter profile\n");
}
- printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n",
- (double)mesh_vert(bv->vmesh, i, 1, 0)->co[0],
- (double)mesh_vert(bv->vmesh, i, 1, 0)->co[1],
- (double)mesh_vert(bv->vmesh, i, 1, 0)->co[2]);
+ printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 0)->co));
#endif
/* Add profile point vertices to the face, including the last one. */
for (int k = 0; k < bp->seg + 1; k++) {
face_bmverts[k + 1] = mesh_vert(bv->vmesh, i, 0, k)->v; /* Leave room for first vert. */
#ifdef DEBUG_CUSTOM_PROFILE_CUTOFF
- printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n",
- k,
- (double)mesh_vert(bv->vmesh, i, 0, k)->co[0],
- (double)mesh_vert(bv->vmesh, i, 0, k)->co[1],
- (double)mesh_vert(bv->vmesh, i, 0, k)->co[2]);
+ printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n", k, F3(mesh_vert(bv->vmesh, i, 0, k)->co));
#endif
}
@@ -5214,10 +5063,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv)
if (build_center_face) {
face_bmverts[bp->seg + 2] = mesh_vert(bv->vmesh, i, 1, 1)->v;
#ifdef DEBUG_CUSTOM_PROFILE_CUTOFF
- printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n",
- (double)mesh_vert(bv->vmesh, i, 1, 1)->co[0],
- (double)mesh_vert(bv->vmesh, i, 1, 1)->co[1],
- (double)mesh_vert(bv->vmesh, i, 1, 1)->co[2]);
+ printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 1)->co));
#endif
}
@@ -5416,7 +5262,6 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
* we have to make it here. */
static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
{
-
VMesh *vm = bv->vmesh;
BMVert *v1, *v2;
BMEdge *e_eg, *bme;
@@ -5443,8 +5288,6 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
zero_v3(pro->plane_co);
zero_v3(pro->plane_no);
zero_v3(pro->proj_dir);
- /* there's no orientation chain to continue so the orientation of the bevel doesn't matter. */
- calculate_profile(bp, bndv, false, false);
for (k = 1; k < ns; k++) {
get_profile_point(bp, pro, k, ns, co);
@@ -5507,15 +5350,17 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
}
else { /* Get the last of the two BoundVerts. */
weld2 = bndv;
+ set_profile_params(bp, bv, weld1);
+ set_profile_params(bp, bv, weld2);
move_weld_profile_planes(bv, weld1, weld2);
- if (!bp->use_custom_profile) { /* Else profile recalculated in next loop. */
- calculate_profile(bp, weld1, !weld1->is_profile_start, false);
- calculate_profile(bp, weld2, !weld2->is_profile_start, false);
- }
}
}
} while ((bndv = bndv->next) != vm->boundstart);
+ /* It's simpler to calculate all profiles only once at a single moment, so keep just a single
+ * profile calculation here, the last point before actual mesh verts are created. */
+ calculate_vm_profiles(bp, bv, vm);
+
/* Create new vertices and place them based on the profiles. */
/* Copy other ends to (i, 0, ns) for all i, and fill in profiles for edges. */
bndv = vm->boundstart;
@@ -5524,10 +5369,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
/* bndv's last vert along the boundary arc is the first of the next BoundVert's arc. */
copy_mesh_vert(vm, i, 0, ns, bndv->next->index, 0, 0);
- /* Fix the profile orientations if it's not a miter profile. */
- if (bp->use_custom_profile && !bndv->is_arc_start && !bndv->is_patch_start) {
- calculate_profile(bp, bndv, !bndv->is_profile_start, false);
- }
if (vm->mesh_kind != M_ADJ) {
for (k = 1; k < ns; k++) {
if (bndv->ebev) {
@@ -5577,24 +5418,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
copy_mesh_vert(bv->vmesh, weld2->index, 0, ns - k, weld1->index, 0, k);
}
}
-#ifdef DEBUG_CUSTOM_PROFILE_WELD
- if (weld && ns > 1) {
- printf("Weld1 profile coordinates:\n");
- for (k = 0; k < ns; k++) {
- printf("%0.4f, %0.4f, %0.4f\n",
- (double)weld1->profile.prof_co[3 * k],
- (double)weld1->profile.prof_co[3 * k + 1],
- (double)weld1->profile.prof_co[3 * k + 2]);
- }
- printf("Weld2 profile coordinates\n");
- for (k = 0; k < ns; k++) {
- printf("%0.4f, %0.4f, %0.4f\n",
- (double)weld2->profile.prof_co[3 * k],
- (double)weld2->profile.prof_co[3 * k + 1],
- (double)weld2->profile.prof_co[3 * k + 2]);
- }
- }
-#endif
/* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff options. */
vpipe = NULL;
@@ -7411,7 +7234,7 @@ void BM_mesh_bevel(BMesh *bm,
adjust_offsets(&bp, bm);
}
- /* Maintain consistent orientations for the unsymmetrical custom profiles. */
+ /* Maintain consistent orientations for the asymmetrical custom profiles. */
if (bp.use_custom_profile) {
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
@@ -7419,11 +7242,6 @@ void BM_mesh_bevel(BMesh *bm,
}
}
}
-#ifdef DEBUG_PROFILE_ORIENTATION_DRAW
- if (bp.use_custom_profile) {
- debug_draw_profile_orientation(&bp, bm);
- }
-#endif
/* Build the meshes around vertices, now that positions are final */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -7499,22 +7317,6 @@ void BM_mesh_bevel(BMesh *bm,
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_elem_flag_disable(l, BM_ELEM_LONG_TAG);
}
-
-#ifdef DEBUG_CUSTOM_PROFILE_SAMPLE
- printf("Profile spacing:\n");
- printf("Seg values:\n");
- if (bp.pro_spacing.xvals != NULL) {
- for (int i = 0; i < bp.seg; i++) {
- printf("(%.3f, %.3f)\n", bp.pro_spacing.xvals[i], bp.pro_spacing.yvals[i]);
- }
- }
- if (bp.pro_spacing.seg_2 != bp.seg && bp.pro_spacing.seg_2 != 0) {
- printf("Seg_2 values:\n");
- for (int i = 0; i < bp.pro_spacing.seg_2; i++) {
- printf("(%0.2f, %0.2f)\n", bp.pro_spacing.xvals_2[i], bp.pro_spacing.yvals_2[i]);
- }
- }
-#endif
}
/* primary free */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 9a3cade85db..df88dcf3006 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -1082,7 +1082,15 @@ bool BM_mesh_intersect(BMesh *bm,
tree_b = tree_a;
}
- overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot, NULL, NULL);
+ int flag = BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS;
+# if DEBUG
+ /* The overlap result must match that obtained in Release to succeed
+ * in the `bmesh_boolean` test. */
+ if (looptris_tot < 1024) {
+ flag &= ~BVH_OVERLAP_USE_THREADING;
+ }
+# endif
+ overlap = BLI_bvhtree_overlap_ex(tree_b, tree_a, &tree_overlap_tot, NULL, NULL, 0, flag);
if (overlap) {
uint i;
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index 82e2151dc01..ce40256221e 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -29,11 +29,17 @@
#include "BKE_bvhutils.h"
+#include "atomic_ops.h"
+
#include "bmesh.h"
#include "bmesh_intersect_edges.h" /* own include */
+//#define INTERSECT_EDGES_DEBUG
+
+#define KDOP_TREE_TYPE 4
#define KDOP_AXIS_LEN 14
+#define BLI_STACK_PAIR_LEN 2 * KDOP_TREE_TYPE
/* -------------------------------------------------------------------- */
/** \name Weld Linked Wire Edges into Linked Faces
@@ -51,7 +57,7 @@ struct EDBMSplitBestFaceData {
* Track the range of vertices in edgenet along the faces normal,
* find the lowest since it's most likely to be most co-planar with the face.
*/
- float best_face_range_on_normal_axis;
+ float best_edgenet_range_on_face_normal;
BMFace *r_best_face;
};
@@ -70,11 +76,14 @@ static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f,
SWAP(float, min, max);
}
- BMVert *v_test = l_b->v;
BMEdge **e_iter = &data->edgenet[0];
+ BMEdge *e_next = data->edgenet[1];
+ BMVert *v_test = ELEM((*e_iter)->v1, e_next->v1, e_next->v2) ? (*e_iter)->v2 : (*e_iter)->v1;
+
int verts_len = data->edgenet_len - 1;
for (int i = verts_len; i--; e_iter++) {
v_test = BM_edge_other_vert(*e_iter, v_test);
+ BLI_assert(v_test != NULL);
if (!BM_face_point_inside_test(f, v_test->co)) {
return false;
}
@@ -87,9 +96,9 @@ static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f,
}
}
- const float test_face_range_on_normal_axis = max - min;
- if (test_face_range_on_normal_axis < data->best_face_range_on_normal_axis) {
- data->best_face_range_on_normal_axis = test_face_range_on_normal_axis;
+ const float test_edgenet_range_on_face_normal = max - min;
+ if (test_edgenet_range_on_face_normal < data->best_edgenet_range_on_face_normal) {
+ data->best_edgenet_range_on_face_normal = test_edgenet_range_on_face_normal;
data->r_best_face = f;
}
@@ -105,114 +114,79 @@ static bool bm_vert_pair_share_splittable_face_cb(BMFace *UNUSED(f),
float(*data)[3] = userdata;
float *v_a_co = data[0];
float *v_a_b_dir = data[1];
+ const float range_min = -FLT_EPSILON;
+ const float range_max = 1.0f + FLT_EPSILON;
+
+ float co[3];
+ float dir[3];
+ float lambda_b;
- float lambda;
- if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_a->prev->v->co, l_a->next->v->co, &lambda)) {
- if (IN_RANGE(lambda, 0.0f, 1.0f)) {
+ copy_v3_v3(co, l_a->prev->v->co);
+ sub_v3_v3v3(dir, l_a->next->v->co, co);
+ if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, NULL, &lambda_b)) {
+ if (IN_RANGE(lambda_b, range_min, range_max)) {
return true;
}
- else if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_b->prev->v->co, l_b->next->v->co, &lambda)) {
- return IN_RANGE(lambda, 0.0f, 1.0f);
+ else {
+ copy_v3_v3(co, l_b->prev->v->co);
+ sub_v3_v3v3(dir, l_b->next->v->co, co);
+ if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, NULL, &lambda_b)) {
+ return IN_RANGE(lambda_b, range_min, range_max);
+ }
}
}
return false;
}
-void BM_vert_weld_linked_wire_edges_into_linked_faces(
- BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len)
+static BMFace *bm_vert_pair_best_face_get(
+ BMVert *v_a, BMVert *v_b, BMEdge **edgenet, const int edgenet_len, const float epsilon)
{
- BMEdge **edgenet = *r_edgenet;
- int edgenet_alloc_len = *r_edgenet_alloc_len;
-
- BMIter iter;
- BMEdge *e;
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- int edgenet_len = 0;
- BMVert *v_other = v;
- while (BM_edge_is_wire(e)) {
- 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;
- v_other = BM_edge_other_vert(e, v_other);
- if (v_other == v) {
- /* Endless loop. */
- break;
- }
-
- BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other);
- if (e_next == e) {
- /* Vert is wire_endpoint. */
- edgenet_len = 0;
- break;
- }
-
- BMEdge *e_test = e_next;
- while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != e) {
- if (e_test->l) {
- /* Vert is linked to a face. */
- goto l_break;
- }
- }
-
- e = e_next;
- }
+ BMFace *r_best_face = NULL;
- BMLoop *dummy;
- BMFace *best_face;
+ BLI_assert(v_a != v_b);
- l_break:
- if (edgenet_len == 0) {
- /* Nothing to do. */
- continue;
- }
- if (edgenet_len == 1) {
- float data[2][3];
- copy_v3_v3(data[0], v_other->co);
- sub_v3_v3v3(data[1], v->co, data[0]);
- best_face = BM_vert_pair_shared_face_cb(
- v_other, v, true, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
- }
- else {
- struct EDBMSplitBestFaceData data = {
- .edgenet = edgenet,
- .edgenet_len = edgenet_len,
- .best_face_range_on_normal_axis = FLT_MAX,
- .r_best_face = NULL,
- };
- BM_vert_pair_shared_face_cb(
- v_other, v, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
-
- if (data.r_best_face) {
- float no[3], min = FLT_MAX, max = -FLT_MAX;
- copy_v3_v3(no, data.r_best_face->no);
- BMVert *v_test;
- BMIter f_iter;
- BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) {
- float dot = dot_v3v3(v_test->co, no);
- if (dot < min) {
- min = dot;
- }
- if (dot > max) {
- max = dot;
- }
+ BMLoop *dummy;
+ if (edgenet_len == 1) {
+ float data[2][3];
+ copy_v3_v3(data[0], v_b->co);
+ 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);
+ }
+ else {
+ struct EDBMSplitBestFaceData data = {
+ .edgenet = edgenet,
+ .edgenet_len = edgenet_len,
+ .best_edgenet_range_on_face_normal = FLT_MAX,
+ .r_best_face = NULL,
+ };
+ BM_vert_pair_shared_face_cb(
+ v_a, v_b, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
+
+ if (data.r_best_face) {
+ /* Check if the edgenet's range is smaller than the face's range. */
+ float no[3], min = FLT_MAX, max = -FLT_MAX;
+ copy_v3_v3(no, data.r_best_face->no);
+ BMVert *v_test;
+ BMIter f_iter;
+ BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) {
+ float dot = dot_v3v3(v_test->co, no);
+ if (dot < min) {
+ min = dot;
}
- float range = max - min + 2 * epsilon;
- if (range < data.best_face_range_on_normal_axis) {
- data.r_best_face = NULL;
+ if (dot > max) {
+ max = dot;
}
}
- best_face = data.r_best_face;
- }
-
- if (best_face) {
- BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL);
+ float face_range_on_normal = max - min + 2 * epsilon;
+ if (face_range_on_normal < data.best_edgenet_range_on_face_normal) {
+ data.r_best_face = NULL;
+ }
}
+ r_best_face = data.r_best_face;
}
- *r_edgenet = edgenet;
- *r_edgenet_alloc_len = edgenet_alloc_len;
+ return r_best_face;
}
/** \} */
@@ -239,21 +213,16 @@ struct EDBMSplitElem {
struct EDBMSplitData {
BMesh *bm;
- BLI_Stack *pair_stack;
- int cut_edges_a_len;
- int cut_edges_b_len;
+ BLI_Stack **pair_stack;
+ int cut_edges_len;
float dist_sq;
float dist_sq_sq;
};
/* Utils */
-static void bm_vert_pair_elem_setup_ex(BMVert *v,
- float edge_index,
- struct EDBMSplitElem *r_pair_elem)
+static void bm_vert_pair_elem_setup_ex(BMVert *v, struct EDBMSplitElem *r_pair_elem)
{
- BLI_assert(v->head.index == -1);
- v->head.index = edge_index;
r_pair_elem->vert = v;
}
@@ -265,30 +234,34 @@ static void bm_edge_pair_elem_setup(BMEdge *e,
r_pair_elem->edge = e;
r_pair_elem->lambda = lambda;
- e->head.index++;
- /* Obs: Check Multithread. */
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- (*r_data_cut_edges_len)++;
+ /* Even though we have multiple atomic operations, this is fine here, since
+ * there is no dependency on order.
+ * The `e->head.index` check + atomic increment will ever be true once, as
+ * expected. We don't care which instance of the code actually ends up
+ * incrementing `r_data_cut_edge_len`, so there is no race condition here. */
+ if (atomic_fetch_and_add_int32(&e->head.index, 1) == 0) {
+ atomic_fetch_and_add_int32(r_data_cut_edges_len, 1);
}
}
/* Util for Vert x Edge and Edge x Edge callbacks */
-static bool bm_vertxedge_isect_impl_ex(BMVert *v,
- BMEdge *e,
- int edge_index,
- const float co[3],
- const float dir[3],
- float lambda,
- float data_dist_sq,
- int *data_cut_edges_len,
- struct EDBMSplitElem r_pair[2])
+static bool bm_edgexvert_isect_impl(BMVert *v,
+ BMEdge *e,
+ const float co[3],
+ const float dir[3],
+ float lambda,
+ float data_dist_sq,
+ int *data_cut_edges_len,
+ struct EDBMSplitElem r_pair[2])
{
- BLI_assert(v->head.index == -1);
-
BMVert *e_v;
float dist_sq_vert_factor;
+ if (!IN_RANGE_INCL(lambda, 0.0f, 1.0f)) {
+ /* Vert x Vert is already handled elsewhere. */
+ return false;
+ }
+
if (lambda < 0.5f) {
e_v = e->v1;
dist_sq_vert_factor = lambda;
@@ -299,27 +272,19 @@ static bool bm_vertxedge_isect_impl_ex(BMVert *v,
}
if (v != e_v) {
- CLAMP(lambda, 0.0f, 1.0f);
+ float dist_sq_vert = SQUARE(dist_sq_vert_factor) * len_squared_v3(dir);
+ if (dist_sq_vert < data_dist_sq) {
+ /* Vert x Vert is already handled elsewhere. */
+ return false;
+ }
- float near[3];
- madd_v3_v3v3fl(near, co, dir, lambda);
+ float closest[3];
+ madd_v3_v3v3fl(closest, co, dir, lambda);
- float dist_sq = len_squared_v3v3(v->co, near);
+ float dist_sq = len_squared_v3v3(v->co, closest);
if (dist_sq < data_dist_sq) {
- float dist_sq_vert = SQUARE(dist_sq_vert_factor) * len_squared_v3(dir);
- if (dist_sq_vert < data_dist_sq) {
- if (e_v->head.index != -1) {
- /* Vertex already has an intersection. */
- return false;
- }
-
- bm_vert_pair_elem_setup_ex(e_v, -2, &r_pair[1]);
- }
- else {
- bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[1]);
- }
-
- bm_vert_pair_elem_setup_ex(v, edge_index, &r_pair[0]);
+ bm_edge_pair_elem_setup(e, lambda, data_cut_edges_len, &r_pair[0]);
+ bm_vert_pair_elem_setup_ex(v, &r_pair[1]);
return true;
}
}
@@ -329,86 +294,56 @@ static bool bm_vertxedge_isect_impl_ex(BMVert *v,
/* Vertex x Vertex Callback */
-static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+static bool bm_vertxvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
{
struct EDBMSplitData *data = userdata;
BMVert *v_a = BM_vert_at_index(data->bm, index_a);
BMVert *v_b = BM_vert_at_index(data->bm, index_b);
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
-
- BLI_assert(v_a->head.index == -1);
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack[thread]);
- /* Set index -2 for sure that it will not repeat keys in `targetmap`. */
- bm_vert_pair_elem_setup_ex(v_a, -2, &pair[0]);
- bm_vert_pair_elem_setup_ex(v_b, -1, &pair[1]);
+ bm_vert_pair_elem_setup_ex(v_a, &pair[0]);
+ bm_vert_pair_elem_setup_ex(v_b, &pair[1]);
return true;
}
+static bool bm_vertxvert_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
+{
+ if (index_a < index_b) {
+ return bm_vertxvert_isect_cb(userdata, index_a, index_b, thread);
+ }
+ return false;
+}
+
/* Vertex x Edge and Edge x Vertex Callbacks */
-static int bm_vertxedge_isect_impl(BMesh *bm,
- int vert_index,
- int edge_index,
- float data_dist_sq,
- int *data_cut_edges_len,
- struct EDBMSplitElem r_pair[2])
+static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int thread)
{
- BMVert *v = BM_vert_at_index(bm, vert_index);
- BMEdge *e = BM_edge_at_index(bm, edge_index);
-
- if (v->head.index != -1) {
- /* Only one vertex per edge. */
- return false;
- }
+ struct EDBMSplitData *data = userdata;
+ BMEdge *e = BM_edge_at_index(data->bm, index_a);
+ BMVert *v = BM_vert_at_index(data->bm, index_b);
float co[3], dir[3], lambda;
copy_v3_v3(co, e->v1->co);
sub_v3_v3v3(dir, e->v2->co, co);
lambda = ray_point_factor_v3_ex(v->co, co, dir, 0.0f, -1.0f);
- return bm_vertxedge_isect_impl_ex(
- v, e, edge_index, co, dir, lambda, data_dist_sq, data_cut_edges_len, r_pair);
-}
-
-static bool bm_vertxedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
-{
- struct EDBMSplitData *data = userdata;
struct EDBMSplitElem pair_tmp[2];
- if (bm_vertxedge_isect_impl(
- data->bm, index_a, index_b, data->dist_sq, &data->cut_edges_b_len, pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
+ if (bm_edgexvert_isect_impl(
+ v, e, co, dir, lambda, data->dist_sq, &data->cut_edges_len, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack[thread]);
pair[0] = pair_tmp[0];
pair[1] = pair_tmp[1];
-
- return true;
- }
-
- return false;
-}
-
-static bool bm_edgexvert_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
-{
- struct EDBMSplitData *data = userdata;
- struct EDBMSplitElem pair_tmp[2];
- if (bm_vertxedge_isect_impl(
- data->bm, index_b, index_a, data->dist_sq, &data->cut_edges_a_len, pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[1];
- pair[1] = pair_tmp[0];
-
- return true;
}
+ /* Always return false with edges. */
return false;
}
/* Edge x Edge Callbacks */
-static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
- int index_a,
- int index_b,
+static bool bm_edgexedge_isect_impl(struct EDBMSplitData *data,
BMEdge *e_a,
BMEdge *e_b,
const float co_a[3],
@@ -416,7 +351,8 @@ static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
const float co_b[3],
const float dir_b[3],
float lambda_a,
- float lambda_b)
+ float lambda_b,
+ struct EDBMSplitElem r_pair[2])
{
float dist_sq_va_factor, dist_sq_vb_factor;
BMVert *e_a_v, *e_b_v;
@@ -439,8 +375,18 @@ static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
}
if (e_a_v != e_b_v) {
- CLAMP(lambda_a, 0.0f, 1.0f);
- CLAMP(lambda_b, 0.0f, 1.0f);
+ if (!IN_RANGE_INCL(lambda_a, 0.0f, 1.0f) || !IN_RANGE_INCL(lambda_b, 0.0f, 1.0f)) {
+ /* Vert x Edge is already handled elsewhere. */
+ return false;
+ }
+
+ float dist_sq_va = SQUARE(dist_sq_va_factor) * len_squared_v3(dir_a);
+ float dist_sq_vb = SQUARE(dist_sq_vb_factor) * len_squared_v3(dir_b);
+
+ if (dist_sq_va < data->dist_sq || dist_sq_vb < data->dist_sq) {
+ /* Vert x Edge is already handled elsewhere. */
+ return false;
+ }
float near_a[3], near_b[3];
madd_v3_v3v3fl(near_a, co_a, dir_a, lambda_a);
@@ -448,49 +394,25 @@ static void bm_edgexedge_isect_impl(struct EDBMSplitData *data,
float dist_sq = len_squared_v3v3(near_a, near_b);
if (dist_sq < data->dist_sq) {
- struct EDBMSplitElem pair_tmp[2];
-
- float dist_sq_va = SQUARE(dist_sq_va_factor) * len_squared_v3(dir_a);
- float dist_sq_vb = SQUARE(dist_sq_vb_factor) * len_squared_v3(dir_b);
-
- if (dist_sq_va < data->dist_sq) {
- if (e_a_v->head.index != -1) {
- /* Only one vertex per edge. */
- return;
- }
- bm_vert_pair_elem_setup_ex(e_a_v, index_b, &pair_tmp[0]);
- }
-
- if (dist_sq_vb < data->dist_sq) {
- if (e_b_v->head.index != -1) {
- /* Only one vertex per edge. */
- return;
- }
- bm_vert_pair_elem_setup_ex(e_b_v, index_a, &pair_tmp[1]);
- }
- else {
- bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_b_len, &pair_tmp[1]);
- }
-
- /* Don't setup edges before a return. */
- if (dist_sq_va >= data->dist_sq) {
- bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_a_len, &pair_tmp[0]);
- }
-
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[0];
- pair[1] = pair_tmp[1];
+ bm_edge_pair_elem_setup(e_a, lambda_a, &data->cut_edges_len, &r_pair[0]);
+ bm_edge_pair_elem_setup(e_b, lambda_b, &data->cut_edges_len, &r_pair[1]);
+ return true;
}
}
+ return false;
}
-static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int thread)
{
- bool ret = false;
struct EDBMSplitData *data = userdata;
BMEdge *e_a = BM_edge_at_index(data->bm, index_a);
BMEdge *e_b = BM_edge_at_index(data->bm, index_b);
+ if (BM_edge_share_vert_check(e_a, e_b)) {
+ /* The other vertices may intersect but Vert x Edge is already handled elsewhere. */
+ return false;
+ }
+
float co_a[3], dir_a[3], co_b[3], dir_b[3];
copy_v3_v3(co_a, e_a->v1->co);
sub_v3_v3v3(dir_a, e_a->v2->co, co_a);
@@ -501,136 +423,56 @@ static bool bm_edgexedge_isect_cb(void *userdata, int index_a, int index_b, int
float lambda_a, lambda_b;
/* Using with dist^4 as `epsilon` is not the best solution, but it fits in most cases. */
if (isect_ray_ray_epsilon_v3(co_a, dir_a, co_b, dir_b, data->dist_sq_sq, &lambda_a, &lambda_b)) {
- if (ELEM(index_b, e_a->v1->head.index, e_a->v2->head.index) ||
- ELEM(index_a, e_b->v1->head.index, e_b->v2->head.index)) {
- return ret;
- }
-
- /* Edge x Edge returns always false. */
- bm_edgexedge_isect_impl(
- data, index_a, index_b, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b);
- }
- else {
- /* Parallel */
struct EDBMSplitElem pair_tmp[2];
- float vec[3], len_sq_a, len_sq_b, lambda;
- sub_v3_v3v3(vec, co_b, co_a);
- len_sq_a = len_squared_v3(dir_a);
- len_sq_b = len_squared_v3(dir_b);
-
- if (!ELEM(e_b->v1, e_a->v1, e_a->v2) && e_b->v1->head.index == -1) {
- lambda = dot_v3v3(vec, dir_a) / len_sq_a;
- if (bm_vertxedge_isect_impl_ex(e_b->v1,
- e_a,
- index_a,
- co_a,
- dir_a,
- lambda,
- data->dist_sq,
- &data->cut_edges_a_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[1];
- pair[1] = pair_tmp[0];
- ret |= true;
- }
- }
-
- if (!ELEM(e_a->v1, e_b->v1, e_b->v2) && e_a->v1->head.index == -1) {
- lambda = -dot_v3v3(vec, dir_b) / len_sq_b;
- if (bm_vertxedge_isect_impl_ex(e_a->v1,
- e_b,
- index_b,
- co_b,
- dir_b,
- lambda,
- data->dist_sq,
- &data->cut_edges_b_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[0];
- pair[1] = pair_tmp[1];
- ret |= true;
- }
+ if (bm_edgexedge_isect_impl(
+ data, e_a, e_b, co_a, dir_a, co_b, dir_b, lambda_a, lambda_b, pair_tmp)) {
+ struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack[thread]);
+ pair[0] = pair_tmp[0];
+ pair[1] = pair_tmp[1];
}
+ }
- add_v3_v3(vec, dir_b);
- if (!ELEM(e_b->v2, e_a->v1, e_a->v2) && e_b->v2->head.index == -1) {
- lambda = dot_v3v3(vec, dir_a) / len_sq_a;
- if (bm_vertxedge_isect_impl_ex(e_b->v2,
- e_a,
- index_a,
- co_a,
- dir_a,
- lambda,
- data->dist_sq,
- &data->cut_edges_a_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[1];
- pair[1] = pair_tmp[0];
- ret |= true;
- }
- }
+ /* Edge x Edge returns always false. */
+ return false;
+}
- sub_v3_v3(vec, dir_a);
- if (!ELEM(e_a->v2, e_b->v1, e_b->v2) && e_a->v2->head.index == -1) {
- lambda = 1.0f - dot_v3v3(vec, dir_b) / len_sq_b;
- if (bm_vertxedge_isect_impl_ex(e_a->v2,
- e_b,
- index_b,
- co_b,
- dir_b,
- lambda,
- data->dist_sq,
- &data->cut_edges_b_len,
- pair_tmp)) {
- struct EDBMSplitElem *pair = BLI_stack_push_r(data->pair_stack);
- pair[0] = pair_tmp[0];
- pair[1] = pair_tmp[1];
- ret |= true;
- }
- }
+static bool bm_edgexedge_self_isect_cb(void *userdata, int index_a, int index_b, int thread)
+{
+ if (index_a < index_b) {
+ return bm_edgexedge_isect_cb(userdata, index_a, index_b, thread);
}
-
- return ret;
+ return false;
}
/* -------------------------------------------------------------------- */
/* BVHTree Overlap Function */
-static void bvhtree_overlap_thread_safe(const BVHTree *tree1,
- const BVHTree *tree2,
- BVHTree_OverlapCallback callback,
- void *userdata)
+static void bm_elemxelem_bvhtree_overlap(const BVHTree *tree1,
+ const BVHTree *tree2,
+ BVHTree_OverlapCallback callback,
+ struct EDBMSplitData *data,
+ BLI_Stack **pair_stack)
{
- BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, 1, 0);
+ int parallel_tasks_num = BLI_bvhtree_overlap_thread_num(tree1);
+ for (int i = 0; i < parallel_tasks_num; i++) {
+ if (pair_stack[i] == NULL) {
+ pair_stack[i] = BLI_stack_new(sizeof(struct EDBMSplitElem[2]), __func__);
+ }
+ }
+ data->pair_stack = pair_stack;
+ BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, data, 1, BVH_OVERLAP_USE_THREADING);
}
/* -------------------------------------------------------------------- */
/* Callbacks for `BLI_qsort_r` */
-static int sort_cmp_by_lambda_a_cb(const void *index1_v, const void *index2_v, void *keys_v)
+static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, void *keys_v)
{
- const struct EDBMSplitElem(*pair_array)[2] = keys_v;
+ const struct EDBMSplitElem *pair_flat = keys_v;
const int index1 = *(int *)index1_v;
const int index2 = *(int *)index2_v;
- if (pair_array[index1][0].lambda > pair_array[index2][0].lambda) {
- return 1;
- }
- else {
- return -1;
- }
-}
-
-static int sort_cmp_by_lambda_b_cb(const void *index1_v, const void *index2_v, void *keys_v)
-{
- const struct EDBMSplitElem(*pair_array)[2] = keys_v;
- const int index1 = *(int *)index1_v;
- const int index2 = *(int *)index2_v;
-
- if (pair_array[index1][1].lambda > pair_array[index2][1].lambda) {
+ if (pair_flat[index1].lambda > pair_flat[index2].lambda) {
return 1;
}
else {
@@ -641,7 +483,10 @@ static int sort_cmp_by_lambda_b_cb(const void *index1_v, const void *index2_v, v
/* -------------------------------------------------------------------- */
/* Main API */
-bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap)
+#define INTERSECT_EDGES
+
+bool BM_mesh_intersect_edges(
+ BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap)
{
bool ok = false;
@@ -650,157 +495,236 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
BMEdge *e;
int i;
- BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
-
/* Store all intersections in this array. */
struct EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = NULL;
- BLI_Stack *pair_stack = BLI_stack_new(sizeof(*pair_array), __func__);
int pair_len = 0;
- float dist_sq = SQUARE(dist);
+ BLI_Stack *pair_stack[BLI_STACK_PAIR_LEN] = {NULL};
+ BLI_Stack **pair_stack_vertxvert = pair_stack;
+ BLI_Stack **pair_stack_edgexelem = &pair_stack[KDOP_TREE_TYPE];
+
+ const float dist_sq = SQUARE(dist);
+ const float dist_half = dist / 2;
+
struct EDBMSplitData data = {
.bm = bm,
.pair_stack = pair_stack,
- .cut_edges_a_len = 0,
- .cut_edges_b_len = 0,
+ .cut_edges_len = 0,
.dist_sq = dist_sq,
.dist_sq_sq = SQUARE(dist_sq),
};
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE);
+
/* tag and count the verts to be tested. */
int verts_act_len = 0, verts_remain_len = 0;
- int loose_verts_act_len = 0, loose_verts_remain_len = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, hflag)) {
BM_elem_flag_enable(v, BM_ELEM_TAG);
- v->head.index = -1;
verts_act_len++;
- if (!v->e) {
- loose_verts_act_len++;
- }
}
else {
BM_elem_flag_disable(v, BM_ELEM_TAG);
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- v->head.index = -1;
verts_remain_len++;
- if (!v->e) {
- loose_verts_remain_len++;
- }
}
}
+
+ /* The index will indicate which cut in pair_array this vertex belongs to. */
+ BM_elem_index_set(v, -1);
}
bm->elem_index_dirty |= BM_VERT;
/* Start the creation of BVHTrees. */
- BVHTree *tree_loose_verts_act = NULL, *tree_loose_verts_remain = NULL;
- if (loose_verts_act_len) {
- tree_loose_verts_act = BLI_bvhtree_new(loose_verts_act_len, dist, 2, KDOP_AXIS_LEN);
+ BVHTree *tree_verts_act = NULL, *tree_verts_remain = NULL;
+ if (verts_act_len) {
+ tree_verts_act = BLI_bvhtree_new(verts_act_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
}
- if (loose_verts_remain_len) {
- tree_loose_verts_remain = BLI_bvhtree_new(loose_verts_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
+ if (verts_remain_len) {
+ tree_verts_remain = BLI_bvhtree_new(
+ verts_remain_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
}
- if (tree_loose_verts_act || tree_loose_verts_remain) {
+ if (tree_verts_act || tree_verts_remain) {
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- if (tree_loose_verts_act && !v->e) {
- BLI_bvhtree_insert(tree_loose_verts_act, i, v->co, 1);
+ if (tree_verts_act) {
+ BLI_bvhtree_insert(tree_verts_act, i, v->co, 1);
}
}
- else if (tree_loose_verts_remain && !v->e && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- BLI_bvhtree_insert(tree_loose_verts_remain, i, v->co, 1);
+ else if (tree_verts_remain && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ BLI_bvhtree_insert(tree_verts_remain, i, v->co, 1);
}
}
- if (tree_loose_verts_act) {
- BLI_bvhtree_balance(tree_loose_verts_act);
+
+ if (tree_verts_act) {
+ BLI_bvhtree_balance(tree_verts_act);
+ /* First pair search. */
+ bm_elemxelem_bvhtree_overlap(
+ tree_verts_act, tree_verts_act, bm_vertxvert_self_isect_cb, &data, pair_stack_vertxvert);
+ }
+
+ if (tree_verts_remain) {
+ BLI_bvhtree_balance(tree_verts_remain);
}
- if (tree_loose_verts_remain) {
- BLI_bvhtree_balance(tree_loose_verts_remain);
+ if (tree_verts_act && tree_verts_remain) {
+ bm_elemxelem_bvhtree_overlap(
+ tree_verts_remain, tree_verts_act, bm_vertxvert_isect_cb, &data, pair_stack_vertxvert);
}
+ }
- if (tree_loose_verts_act && tree_loose_verts_remain) {
- /* First pair search. */
- bvhtree_overlap_thread_safe(
- tree_loose_verts_act, tree_loose_verts_remain, bm_vertxvert_isect_cb, &data);
+ for (i = KDOP_TREE_TYPE; i--;) {
+ if (pair_stack_vertxvert[i]) {
+ pair_len += BLI_stack_count(pair_stack_vertxvert[i]);
}
}
+#ifdef INTERSECT_EDGES
+ uint vertxvert_pair_len = pair_len;
+
+# define EDGE_ACT_TO_TEST 1
+# define EDGE_REMAIN_TO_TEST 2
/* Tag and count the edges. */
int edges_act_len = 0, edges_remain_len = 0;
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) ||
+ (len_squared_v3v3(e->v1->co, e->v2->co) < dist_sq)) {
+ /* Don't test hidden edges or smaller than the minimum distance.
+ * These have already been handled in the vertices overlap. */
+ BM_elem_index_set(e, 0);
+ if (split_faces) {
+ /* Tag to be ignored. */
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ continue;
+ }
+
if (BM_elem_flag_test(e->v1, BM_ELEM_TAG) || BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
+ BM_elem_index_set(e, EDGE_ACT_TO_TEST);
edges_act_len++;
}
else {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- edges_remain_len++;
+ BM_elem_index_set(e, EDGE_REMAIN_TO_TEST);
+ edges_remain_len++;
+ if (split_faces) {
+ /* Tag to be ignored. */
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
}
}
}
- if (edges_remain_len) {
- BVHTree *tree_edges_act = NULL, *tree_edges_remain = NULL;
- tree_edges_remain = BLI_bvhtree_new(edges_remain_len, 0.0f, 2, KDOP_AXIS_LEN);
- if (edges_act_len) {
- tree_edges_act = BLI_bvhtree_new(edges_act_len, dist, 2, KDOP_AXIS_LEN);
- }
+ BVHTree *tree_edges_act = NULL, *tree_edges_remain = NULL;
+ if (edges_act_len) {
+ tree_edges_act = BLI_bvhtree_new(edges_act_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
+ }
+
+ if (edges_remain_len && (tree_edges_act || tree_verts_act)) {
+ tree_edges_remain = BLI_bvhtree_new(
+ edges_remain_len, dist_half, KDOP_TREE_TYPE, KDOP_AXIS_LEN);
+ }
+ if (tree_edges_act || tree_edges_remain) {
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ int edge_test = BM_elem_index_get(e);
float co[2][3];
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- if (tree_edges_act) {
- e->head.index = 0;
- copy_v3_v3(co[0], e->v1->co);
- copy_v3_v3(co[1], e->v2->co);
- BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
- }
+ if (edge_test == EDGE_ACT_TO_TEST) {
+ BLI_assert(tree_edges_act);
+ e->head.index = 0;
+ copy_v3_v3(co[0], e->v1->co);
+ copy_v3_v3(co[1], e->v2->co);
+ BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
}
- else if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- /* Tag used in the overlap callbacks. */
- BM_elem_flag_enable(e, BM_ELEM_TAG);
+ else if (edge_test == EDGE_REMAIN_TO_TEST) {
+ BLI_assert(tree_edges_remain);
e->head.index = 0;
copy_v3_v3(co[0], e->v1->co);
copy_v3_v3(co[1], e->v2->co);
BLI_bvhtree_insert(tree_edges_remain, i, co[0], 2);
}
+# ifdef INTERSECT_EDGES_DEBUG
+ else {
+ e->head.index = 0;
+ }
+# endif
+ /* Tag used when converting pairs to vert x vert. */
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
}
+# undef EDGE_ACT_TO_TEST
+# undef EDGE_REMAIN_TO_TEST
+
/* Use `e->head.index` to count intersections. */
bm->elem_index_dirty |= BM_EDGE;
- BLI_bvhtree_balance(tree_edges_remain);
if (tree_edges_act) {
BLI_bvhtree_balance(tree_edges_act);
}
+ if (tree_edges_remain) {
+ BLI_bvhtree_balance(tree_edges_remain);
+ }
+
+ int edgexedge_pair_len = 0;
if (tree_edges_act) {
/* Edge x Edge */
- bvhtree_overlap_thread_safe(tree_edges_act, tree_edges_remain, bm_edgexedge_isect_cb, &data);
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_act, tree_edges_act, bm_edgexedge_self_isect_cb, &data, pair_stack_edgexelem);
+
+ if (tree_edges_remain) {
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_remain, tree_edges_act, bm_edgexedge_isect_cb, &data, pair_stack_edgexelem);
+ }
+
+ for (i = KDOP_TREE_TYPE; i--;) {
+ if (pair_stack_edgexelem[i]) {
+ edgexedge_pair_len += BLI_stack_count(pair_stack_edgexelem[i]);
+ }
+ }
- if (tree_loose_verts_remain) {
- /* Edge x Vert */
- bvhtree_overlap_thread_safe(
- tree_edges_act, tree_loose_verts_remain, bm_edgexvert_isect_cb, &data);
+ if (tree_verts_act) {
+ /* Edge v Vert */
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_act, tree_verts_act, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
+ }
+
+ if (tree_verts_remain) {
+ /* Edge v Vert */
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_act, tree_verts_remain, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
}
BLI_bvhtree_free(tree_edges_act);
}
- if (tree_loose_verts_act) {
- /* Vert x Edge */
- bvhtree_overlap_thread_safe(
- tree_loose_verts_act, tree_edges_remain, bm_vertxedge_isect_cb, &data);
+ if (tree_verts_act && tree_edges_remain) {
+ /* Edge v Vert */
+ bm_elemxelem_bvhtree_overlap(
+ tree_edges_remain, tree_verts_act, bm_edgexvert_isect_cb, &data, pair_stack_edgexelem);
}
BLI_bvhtree_free(tree_edges_remain);
- pair_len = BLI_stack_count(pair_stack);
- if (pair_len) {
+ int edgexelem_pair_len = 0;
+ for (i = KDOP_TREE_TYPE; i--;) {
+ if (pair_stack_edgexelem[i]) {
+ edgexelem_pair_len += BLI_stack_count(pair_stack_edgexelem[i]);
+ }
+ }
+
+ pair_len += edgexelem_pair_len;
+ int edgexvert_pair_len = edgexelem_pair_len - edgexedge_pair_len;
+
+ if (edgexelem_pair_len) {
pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
- BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+
+ pair_iter = pair_array;
+ for (i = 0; i < BLI_STACK_PAIR_LEN; i++) {
+ if (pair_stack[i]) {
+ uint count = (uint)BLI_stack_count(pair_stack[i]);
+ BLI_stack_pop_n_reverse(pair_stack[i], pair_iter, count);
+ pair_iter += count;
+ }
+ }
/* Map intersections per edge. */
union {
@@ -811,96 +735,263 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
int as_int[0];
} * e_map_iter, *e_map;
- size_t e_map_size = (max_ii(data.cut_edges_a_len, data.cut_edges_b_len) * sizeof(*e_map)) +
- (pair_len * sizeof(*(e_map->cuts_index)));
+# ifdef INTERSECT_EDGES_DEBUG
+ int cut_edges_len = 0;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (e->head.index != 0) {
+ cut_edges_len++;
+ }
+ }
+ BLI_assert(cut_edges_len == data.cut_edges_len);
+# endif
+
+ size_t e_map_size = (data.cut_edges_len * sizeof(*e_map)) +
+ (((size_t)2 * edgexedge_pair_len + edgexvert_pair_len) *
+ sizeof(*(e_map->cuts_index)));
e_map = MEM_mallocN(e_map_size, __func__);
+ int map_len = 0;
/* Convert every pair to Vert x Vert. */
- for (int pair = 0; pair < 2; pair++) {
- int map_len = 0;
- pair_iter = &pair_array[0];
- for (i = 0; i < pair_len; i++, pair_iter++) {
- if ((*pair_iter)[pair].elem->head.htype != BM_EDGE) {
- /* Take the opportunity to set all vert indices to -1 again. */
- (*pair_iter)[pair].elem->head.index = -1;
- continue;
- }
- e = (*pair_iter)[pair].edge;
- if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- int e_cuts_len = e->head.index;
-
- e_map_iter = (void *)&e_map->as_int[map_len];
- e_map_iter->cuts_len = e_cuts_len;
- e_map_iter->cuts_index[0] = i;
-
- /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
- e->head.index = map_len + 1;
- map_len += 1 + e_cuts_len;
- }
- else {
- e_map->as_int[++e->head.index] = i;
- }
+
+ /* The list of pairs starts with [vert x vert] followed by [edge x edge]
+ * and finally [edge x vert].
+ * Ignore the [vert x vert] pairs */
+ struct EDBMSplitElem *pair_flat, *pair_flat_iter;
+ pair_flat = (struct EDBMSplitElem *)&pair_array[vertxvert_pair_len];
+ pair_flat_iter = &pair_flat[0];
+ uint pair_flat_len = 2 * edgexelem_pair_len;
+ for (i = 0; i < pair_flat_len; i++, pair_flat_iter++) {
+ if (pair_flat_iter->elem->head.htype != BM_EDGE) {
+ continue;
+ }
+
+ e = pair_flat_iter->edge;
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ int e_cuts_len = e->head.index;
+
+ e_map_iter = (void *)&e_map->as_int[map_len];
+ e_map_iter->cuts_len = e_cuts_len;
+ e_map_iter->cuts_index[0] = i;
+
+ /* Use `e->head.index` to indicate which slot to fill with the `cut` index. */
+ e->head.index = map_len + 1;
+ map_len += 1 + e_cuts_len;
+ }
+ else {
+ e_map->as_int[++e->head.index] = i;
}
+ }
- /* Split Edges A to set all Vert x Edge. */
- for (i = 0; i < map_len;
- e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
-
- /* sort by lambda. */
- BLI_qsort_r(e_map_iter->cuts_index,
- e_map_iter->cuts_len,
- sizeof(*(e_map->cuts_index)),
- pair == 0 ? sort_cmp_by_lambda_a_cb : sort_cmp_by_lambda_b_cb,
- pair_array);
-
- float lambda, lambda_prev = 0.0f;
- for (int j = 0; j < e_map_iter->cuts_len; j++) {
- struct EDBMSplitElem *pair_elem = &pair_array[e_map_iter->cuts_index[j]][pair];
- lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
- lambda_prev = pair_elem->lambda;
- e = pair_elem->edge;
-
- BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
- v_new->head.index = -1;
- pair_elem->vert = v_new;
+ /* Split Edges A to set all Vert x Edge. */
+ for (i = 0; i < map_len;
+ e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
+
+ /* sort by lambda. */
+ BLI_qsort_r(e_map_iter->cuts_index,
+ e_map_iter->cuts_len,
+ sizeof(*(e_map->cuts_index)),
+ sort_cmp_by_lambda_cb,
+ pair_flat);
+
+ float lambda, lambda_prev = 0.0f;
+ for (int j = 0; j < e_map_iter->cuts_len; j++) {
+ uint index = e_map_iter->cuts_index[j];
+
+ struct EDBMSplitElem *pair_elem = &pair_flat[index];
+ lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev);
+ lambda_prev = pair_elem->lambda;
+ e = pair_elem->edge;
+ if (split_faces) {
+ /* Tagged edges are ignored when split faces.
+ * Un-tag these. */
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
}
+
+ BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
+ pair_elem->vert = v_new;
}
}
MEM_freeN(e_map);
}
}
+#endif
- BLI_bvhtree_free(tree_loose_verts_act);
- BLI_bvhtree_free(tree_loose_verts_remain);
+ BLI_bvhtree_free(tree_verts_act);
+ BLI_bvhtree_free(tree_verts_remain);
if (r_targetmap) {
- if (pair_array == NULL) {
- pair_len = BLI_stack_count(pair_stack);
- if (pair_len) {
- pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
- BLI_stack_pop_n_reverse(pair_stack, pair_array, pair_len);
+ if (pair_len && pair_array == NULL) {
+ pair_array = MEM_mallocN(sizeof(*pair_array) * pair_len, __func__);
+ pair_iter = pair_array;
+ for (i = 0; i < BLI_STACK_PAIR_LEN; i++) {
+ if (pair_stack[i]) {
+ uint count = (uint)BLI_stack_count(pair_stack[i]);
+ BLI_stack_pop_n_reverse(pair_stack[i], pair_iter, count);
+ pair_iter += count;
+ }
}
}
if (pair_array) {
- /* Organize the vertices in the order they will be merged. */
pair_iter = &pair_array[0];
for (i = 0; i < pair_len; i++, pair_iter++) {
BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT);
BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT);
BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem);
-
- BLI_ghash_insert(r_targetmap, (*pair_iter)[0].vert, (*pair_iter)[1].vert);
+ BMVert *v_key, *v_val;
+ v_key = (*pair_iter)[0].vert;
+ v_val = (*pair_iter)[1].vert;
+ BLI_ghash_insert(r_targetmap, v_key, v_val);
+ if (split_faces) {
+ BM_elem_index_set(v_key, i * 2);
+ BM_elem_index_set(v_val, i * 2 + 1);
+ }
}
+ if (split_faces) {
+ BMEdge **edgenet = NULL;
+ int edgenet_alloc_len = 0;
+
+ 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)) {
+ continue;
+ }
+
+ BMVert *va, *vb, *va_dest = NULL;
+ va = e->v1;
+ vb = e->v2;
+
+ int v_cut = BM_elem_index_get(va);
+ 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. */
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ continue;
+ }
+
+ /* Tag to avoid testing again. */
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+
+ if (v_cut == -1) {
+ SWAP(BMVert *, va, vb);
+ v_cut = v_cut_other;
+ v_cut_other = -1;
+ }
+
+ v_cut += v_cut % 2 ? -1 : 1;
+ va_dest = pair_flat[v_cut].vert;
+
+ BMFace *best_face = NULL;
+ int edgenet_len = 0;
+ BMVert *v_other_dest, *v_other = vb;
+ BMEdge *e_net = e;
+ 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;
+ }
+ else {
+ v_other_dest = v_other;
+ }
+
+ if (BM_edge_exists(va_dest, v_other_dest)) {
+ /* No need to detect face. (Optimization). */
+ break;
+ }
+
+ best_face = bm_vert_pair_best_face_get(
+ va_dest, v_other_dest, edgenet, edgenet_len, dist);
+
+ if (best_face) {
+ if (va_dest != va) {
+ e_net = edgenet[0];
+ if (edgenet_len > 1) {
+ vb = BM_edge_other_vert(e_net, va);
+ }
+ else {
+ vb = v_other_dest;
+ }
+ edgenet[0] = BM_edge_create(bm, va_dest, vb, e_net, BM_CREATE_NOP);
+ }
+ if ((edgenet_len > 1) && (v_other_dest != v_other)) {
+ 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);
+ }
+ break;
+ }
+
+ BMEdge *e_test = e_net, *e_next = NULL;
+ while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != (e_net)) {
+ if (!BM_edge_is_wire(e_test)) {
+ if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
+ continue;
+ }
+ if (!BM_elem_flag_test(e_test->v1, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(e_test->v2, BM_ELEM_TAG)) {
+ continue;
+ }
+ }
+ else if (!BM_edge_is_wire(e_net)) {
+ continue;
+ }
+ e_next = e_test;
+ break;
+ }
+
+ if (e_next == NULL) {
+ break;
+ }
+
+ e_net = e_next;
+ v_other = BM_edge_other_vert(e_net, v_other);
+ if (v_other == va) {
+ /* Endless loop. */
+ break;
+ }
+ v_cut_other = BM_elem_index_get(v_other);
+ }
+
+ if (best_face) {
+ BMFace **face_arr = NULL;
+ int face_arr_len = 0;
+ BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, &face_arr, &face_arr_len);
+ if (face_arr) {
+ /* Update the new faces normal.
+ * Normal is necessary to obtain the best face for edgenet */
+ while (face_arr_len--) {
+ BM_face_normal_update(face_arr[face_arr_len]);
+ }
+ MEM_freeN(face_arr);
+ }
+ }
+ }
+
+ if (edgenet) {
+ MEM_freeN(edgenet);
+ }
+ }
ok = true;
}
}
- BLI_stack_free(pair_stack);
+ for (i = BLI_STACK_PAIR_LEN; i--;) {
+ if (pair_stack[i]) {
+ BLI_stack_free(pair_stack[i]);
+ }
+ }
if (pair_array) {
MEM_freeN(pair_array);
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h
index a22a1ca1e1d..7e2252250d6 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.h
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.h
@@ -21,9 +21,7 @@
#ifndef __BMESH_INTERSECT_EDGES_H__
#define __BMESH_INTERSECT_EDGES_H__
-void BM_vert_weld_linked_wire_edges_into_linked_faces(
- BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len);
-
-bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap);
+bool BM_mesh_intersect_edges(
+ BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap);
#endif /* __BMESH_INTERSECT_EDGES_H__ */
diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h
index 4651290ea0f..7b523ac53ca 100644
--- a/source/blender/collada/BCAnimationCurve.h
+++ b/source/blender/collada/BCAnimationCurve.h
@@ -23,8 +23,9 @@
#include "collada_utils.h"
#include "BCSampleData.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+
+extern "C" {
#include "BKE_fcurve.h"
#include "BKE_armature.h"
#include "BKE_material.h"
diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt
index 40762db759e..a88fd05a18f 100644
--- a/source/blender/collada/CMakeLists.txt
+++ b/source/blender/collada/CMakeLists.txt
@@ -126,6 +126,9 @@ set(SRC
)
set(LIB
+ ${OPENCOLLADA_LIBRARIES}
+ ${PCRE_LIBRARIES}
+ ${XML2_LIBRARIES}
)
if(WITH_BUILDINFO)
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index 0ebcd6d0919..24a960ab287 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -56,6 +56,8 @@
#include "COLLADASWInstanceNode.h"
#include "COLLADASWBaseInputElement.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -99,8 +101,6 @@ extern char build_commit_time[];
extern char build_hash[];
#endif
-#include "MEM_guardedalloc.h"
-
#include "RNA_access.h"
}
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 30e41a8d720..f2c52b125a4 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -43,6 +43,8 @@
#include "COLLADASaxFWLLoader.h"
#include "COLLADASaxFWLIExtraDataCallbackHandler.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -68,8 +70,6 @@ extern "C" {
#include "RNA_access.h"
-#include "MEM_guardedalloc.h"
-
#include "WM_api.h"
#include "WM_types.h"
}
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 80f84738f6e..2d69fae035f 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -112,26 +112,22 @@ void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *m
void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
ep.setDiffuse(cot, false, "diffuse");
}
void EffectsExporter::set_ambient(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_ambient(ma);
ep.setAmbient(cot, false, "ambient");
}
void EffectsExporter::set_specular(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_specular(ma);
ep.setSpecular(cot, false, "specular");
}
void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma)
{
- // get diffuse color
COLLADASW::ColorOrTexture cot = bc_get_reflective(ma);
ep.setReflective(cot, false, "reflective");
}
diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp
index 3b2c68ef95e..06f54884668 100644
--- a/source/blender/collada/Materials.cpp
+++ b/source/blender/collada/Materials.cpp
@@ -202,6 +202,7 @@ void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
+ material->a = alpha;
}
else if (cot.isTexture()) {
int locy = -300 * (node_map.size() - 2);
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 64031e10d77..8ed30a0dc81 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -31,6 +31,8 @@
#include "COLLADAFWMeshVertexData.h"
#include "COLLADAFWPolygons.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BKE_customdata.h"
#include "BKE_displist.h"
@@ -44,8 +46,6 @@ extern "C" {
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_edgehash.h"
-
-#include "MEM_guardedalloc.h"
}
#include "ArmatureImporter.h"
@@ -1014,12 +1014,12 @@ void MeshImporter::optimize_material_assignements()
++it) {
Object *ob = (*it);
Mesh *me = (Mesh *)ob->data;
- if (me->id.us == 1) {
+ if (ID_REAL_USERS(&me->id) == 1) {
bc_copy_materials_to_data(ob, me);
bc_remove_materials_from_object(ob, me);
bc_remove_mark(ob);
}
- else if (me->id.us > 1) {
+ else if (ID_REAL_USERS(&me->id) > 1) {
bool can_move = true;
std::vector<Object *> mesh_users = get_all_users_of(me);
if (mesh_users.size() > 1) {
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index b688840cb09..63dad6b7ac0 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -27,6 +27,9 @@
#include <set>
#include <string>
+
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_customdata_types.h"
@@ -62,8 +65,6 @@ extern "C" {
#include "ED_node.h"
#include "ED_object.h"
-#include "MEM_guardedalloc.h"
-
#include "WM_api.h" /* XXX hrm, see if we can do without this */
#include "WM_types.h"
@@ -1321,10 +1322,11 @@ void bc_add_default_shader(bContext *C, Material *ma)
COLLADASW::ColorOrTexture bc_get_base_color(Material *ma)
{
- Color default_color = {0.8, 0.8, 0.8, 1.0};
+ /* for alpha see bc_get_alpha() */
+ Color default_color = {ma->r, ma->g, ma->b, 1.0};
bNode *shader = bc_get_master_shader(ma);
if (ma->use_nodes && shader) {
- return bc_get_cot_from_shader(shader, "Base Color", default_color);
+ return bc_get_cot_from_shader(shader, "Base Color", default_color, false);
}
else {
return bc_get_cot(default_color);
@@ -1414,16 +1416,17 @@ double bc_get_float_from_shader(bNode *shader, double &val, std::string nodeid)
COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader,
std::string nodeid,
- Color &default_color)
+ Color &default_color,
+ bool with_alpha)
{
bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, nodeid.c_str());
if (socket) {
bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value;
float *col = dcol->value;
- return bc_get_cot(col);
+ return bc_get_cot(col, with_alpha);
}
else {
- return bc_get_cot(default_color); /* default black */
+ return bc_get_cot(default_color, with_alpha);
}
}
@@ -1447,9 +1450,9 @@ COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a)
return cot;
}
-COLLADASW::ColorOrTexture bc_get_cot(Color col)
+COLLADASW::ColorOrTexture bc_get_cot(Color col, bool with_alpha)
{
- COLLADASW::Color color(col[0], col[1], col[2], col[3]);
+ COLLADASW::Color color(col[0], col[1], col[2], (with_alpha) ? col[3] : 1.0);
COLLADASW::ColorOrTexture cot(color);
return cot;
}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index c0425e59d1a..b313fcd6e66 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -397,9 +397,10 @@ double bc_get_shininess(Material *ma);
double bc_get_float_from_shader(bNode *shader, double &ior, std::string nodeid);
COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader,
std::string nodeid,
- Color &default_color);
+ Color &default_color,
+ bool with_alpha = true);
COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a);
-COLLADASW::ColorOrTexture bc_get_cot(Color col);
+COLLADASW::ColorOrTexture bc_get_cot(Color col, bool with_alpha = true);
#endif
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index ed14397f73c..8d609d545f8 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -568,6 +568,10 @@ if(WITH_OPENIMAGEDENOISE)
${OPENIMAGEDENOISE_INCLUDE_DIRS}
${TBB_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${OPENIMAGEDENOISE_LIBRARIES}
+ ${TBB_LIBRARIES}
+ )
endif()
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index 1b2e3b2821e..24c68ddbec7 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -44,20 +44,22 @@ void BlurBaseOperation::initExecution()
this->m_data.image_in_width = this->getWidth();
this->m_data.image_in_height = this->getHeight();
if (this->m_data.relative) {
+ int sizex, sizey;
switch (this->m_data.aspect) {
- case CMP_NODE_BLUR_ASPECT_NONE:
- this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width);
- this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height);
- break;
case CMP_NODE_BLUR_ASPECT_Y:
- this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width);
- this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_width);
+ sizex = sizey = this->m_data.image_in_width;
break;
case CMP_NODE_BLUR_ASPECT_X:
- this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_height);
- this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height);
+ sizex = sizey = this->m_data.image_in_height;
+ break;
+ default:
+ BLI_assert(this->m_data.aspect == CMP_NODE_BLUR_ASPECT_NONE);
+ sizex = this->m_data.image_in_width;
+ sizey = this->m_data.image_in_height;
break;
}
+ this->m_data.sizex = round_fl_to_int(this->m_data.percentx * 0.01f * sizex);
+ this->m_data.sizey = round_fl_to_int(this->m_data.percenty * 0.01f * sizey);
}
QualityStepHelper::initExecution(COM_QH_MULTIPLY);
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index 5bd466658c0..ff9fc7dbcbc 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -17,6 +17,7 @@
*/
#include "COM_CompositorOperation.h"
+#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -26,7 +27,6 @@ extern "C" {
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
#include "RE_render_ext.h"
-#include "MEM_guardedalloc.h"
#include "render_types.h"
}
#include "PIL_time.h"
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h
index e03173dca8d..6237d336c74 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.h
+++ b/source/blender/compositor/operations/COM_ImageOperation.h
@@ -20,13 +20,13 @@
#define __COM_IMAGEOPERATION_H__
#include "COM_NodeOperation.h"
+#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BKE_image.h"
extern "C" {
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
#include "RE_render_ext.h"
-#include "MEM_guardedalloc.h"
}
/**
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index c06994d7cdb..334eab6ef95 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -30,9 +30,9 @@
#include "BKE_scene.h"
#include "DNA_color_types.h"
+#include "MEM_guardedalloc.h"
extern "C" {
-#include "MEM_guardedalloc.h"
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cpp
index cd2bb3b2928..b91c3324f87 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cpp
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cpp
@@ -26,8 +26,8 @@
#include "BLI_math_color.h"
#include "COM_defines.h"
#include "BLI_math.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index 5aa7e879760..ca7c18a0586 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -20,12 +20,12 @@
#define __COM_RENDERLAYERSPROG_H__
#include "COM_NodeOperation.h"
+#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
#include "BLI_listbase.h"
#include "BKE_image.h"
extern "C" {
#include "RE_pipeline.h"
-#include "MEM_guardedalloc.h"
}
/**
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cpp
index 24978acc8f3..437b20d14d4 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cpp
+++ b/source/blender/compositor/operations/COM_SplitOperation.cpp
@@ -22,9 +22,9 @@
#include "BLI_utildefines.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
+#include "MEM_guardedalloc.h"
extern "C" {
-#include "MEM_guardedalloc.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
}
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 934b6f8683f..6b44c11f423 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -22,11 +22,11 @@
#include "COM_NodeOperation.h"
#include "DNA_texture_types.h"
#include "BLI_listbase.h"
+#include "MEM_guardedalloc.h"
extern "C" {
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
#include "RE_render_ext.h"
-#include "MEM_guardedalloc.h"
}
/**
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp
index b6caf52a9f7..50b508dafb1 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp
@@ -26,9 +26,9 @@
#include "BLI_utildefines.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
+#include "MEM_guardedalloc.h"
extern "C" {
-#include "MEM_guardedalloc.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 4abeec19645..fad8bc22e08 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
intern/eval/deg_eval_copy_on_write.cc
intern/eval/deg_eval_flush.cc
intern/eval/deg_eval_runtime_backup.cc
+ intern/eval/deg_eval_runtime_backup_animation.cc
intern/eval/deg_eval_runtime_backup_modifier.cc
intern/eval/deg_eval_runtime_backup_movieclip.cc
intern/eval/deg_eval_runtime_backup_object.cc
@@ -82,6 +83,7 @@ set(SRC
intern/depsgraph_query.cc
intern/depsgraph_query_foreach.cc
intern/depsgraph_query_iter.cc
+ intern/depsgraph_relation.cc
intern/depsgraph_registry.cc
intern/depsgraph_tag.cc
intern/depsgraph_type.cc
@@ -104,10 +106,12 @@ set(SRC
intern/builder/deg_builder_rna.h
intern/builder/deg_builder_transitive.h
intern/debug/deg_debug.h
+ intern/debug/deg_time_average.h
intern/eval/deg_eval.h
intern/eval/deg_eval_copy_on_write.h
intern/eval/deg_eval_flush.h
intern/eval/deg_eval_runtime_backup.h
+ intern/eval/deg_eval_runtime_backup_animation.h
intern/eval/deg_eval_runtime_backup_modifier.h
intern/eval/deg_eval_runtime_backup_movieclip.h
intern/eval/deg_eval_runtime_backup_object.h
@@ -127,6 +131,7 @@ set(SRC
intern/depsgraph.h
intern/depsgraph_physics.h
intern/depsgraph_registry.h
+ intern/depsgraph_relation.h
intern/depsgraph_tag.h
intern/depsgraph_type.h
intern/depsgraph_update.h
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 4ca7240abd1..7eca04112e7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -42,6 +42,7 @@ extern "C" {
}
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_tag.h"
#include "intern/depsgraph_type.h"
#include "intern/builder/deg_builder_cache.h"
@@ -55,11 +56,17 @@ extern "C" {
namespace DEG {
+bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig)
+{
+ IDNode *id_node = graph->find_id_node(id_orig);
+ return id_node != nullptr;
+}
+
bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base)
{
Object *object_orig = base->base_orig->object;
IDNode *id_node = graph->find_id_node(&object_orig->id);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
return false;
}
return id_node->has_base;
@@ -107,7 +114,7 @@ bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel *pchan)
{
BLI_assert(object->type == OB_ARMATURE);
- if (pchan == NULL || pchan->bone == NULL) {
+ if (pchan == nullptr || pchan->bone == nullptr) {
return false;
}
/* We don't really care whether segments are higher than 1 due to static user input (as in,
@@ -127,7 +134,7 @@ bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel
bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan)
{
/* Proxies don't have BONE_SEGMENTS */
- if (ID_IS_LINKED(object) && object->proxy_from != NULL) {
+ if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
return false;
}
return check_pchan_has_bbone(object, pchan);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 97e12e9ceb2..2db861b6fca 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -24,6 +24,7 @@
#pragma once
struct Base;
+struct ID;
struct Main;
struct Object;
struct bPoseChannel;
@@ -53,6 +54,7 @@ class DepsgraphBuilder {
DepsgraphBuilderCache *cache_;
};
+bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig);
bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base);
void deg_graph_build_finalize(Main *bmain, Depsgraph *graph);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
index 3cfb4f95e5e..fe1886c67e8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
@@ -37,7 +37,7 @@ namespace DEG {
/* Animated property storage. */
-AnimatedPropertyID::AnimatedPropertyID() : data(NULL), property_rna(NULL)
+AnimatedPropertyID::AnimatedPropertyID() : data(nullptr), property_rna(nullptr)
{
}
@@ -89,13 +89,13 @@ struct AnimatedPropertyCallbackData {
void animated_property_cb(ID * /*id*/, FCurve *fcurve, void *data_v)
{
- if (fcurve->rna_path == NULL || fcurve->rna_path[0] == '\0') {
+ if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') {
return;
}
AnimatedPropertyCallbackData *data = static_cast<AnimatedPropertyCallbackData *>(data_v);
/* Resolve property. */
PointerRNA pointer_rna;
- PropertyRNA *property_rna = NULL;
+ PropertyRNA *property_rna = nullptr;
if (!RNA_path_resolve_property(
&data->pointer_rna, fcurve->rna_path, &pointer_rna, &property_rna)) {
return;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index bea59eceea2..e0d162a49c5 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -35,6 +35,7 @@
#include "intern/node/deg_node_operation.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
namespace DEG {
@@ -99,8 +100,8 @@ void schedule_node_to_stack(CyclesSolverState *state, OperationNode *node)
{
StackEntry entry;
entry.node = node;
- entry.from = NULL;
- entry.via_relation = NULL;
+ entry.from = nullptr;
+ entry.via_relation = nullptr;
BLI_stack_push(state->traversal_stack, &entry);
set_node_visited_state(node, NODE_IN_STACK);
}
@@ -186,7 +187,7 @@ void solve_cycles(CyclesSolverState *state)
node->full_identifier() + " via '" + rel->name + "'\n";
StackEntry *current = entry;
while (current->node != to) {
- BLI_assert(current != NULL);
+ BLI_assert(current != nullptr);
cycle_str += " " + current->from->node->full_identifier() + " via '" +
current->via_relation->name + "'\n";
current = current->from;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index d0e40d49527..6382772c8db 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -47,6 +47,7 @@ extern "C" {
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_light_types.h"
+#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
@@ -121,7 +122,7 @@ 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 != NULL) {
+ if (id_info->id_cow != nullptr) {
deg_free_copy_on_write_datablock(id_info->id_cow);
MEM_freeN(id_info->id_cow);
}
@@ -139,37 +140,37 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain,
Depsgraph *graph,
DepsgraphBuilderCache *cache)
: DepsgraphBuilder(bmain, graph, cache),
- scene_(NULL),
- view_layer_(NULL),
+ scene_(nullptr),
+ view_layer_(nullptr),
view_layer_index_(-1),
- collection_(NULL),
+ collection_(nullptr),
is_parent_collection_visible_(true),
- id_info_hash_(NULL)
+ id_info_hash_(nullptr)
{
}
DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
{
- if (id_info_hash_ != NULL) {
- BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock);
+ if (id_info_hash_ != nullptr) {
+ BLI_ghash_free(id_info_hash_, nullptr, free_copy_on_write_datablock);
}
}
IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
{
- IDNode *id_node = NULL;
- ID *id_cow = NULL;
+ IDNode *id_node = nullptr;
+ ID *id_cow = nullptr;
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);
- if (id_info != NULL) {
+ if (id_info != nullptr) {
id_cow = id_info->id_cow;
previously_visible_components_mask = id_info->previously_visible_components_mask;
previous_eval_flags = id_info->previous_eval_flags;
previous_customdata_masks = id_info->previous_customdata_masks;
/* Tag ID info to not free the CoW ID pointer. */
- id_info->id_cow = NULL;
+ id_info->id_cow = nullptr;
}
id_node = graph_->add_id_node(id, id_cow);
id_node->previously_visible_components_mask = previously_visible_components_mask;
@@ -217,7 +218,7 @@ OperationNode *DepsgraphNodeBuilder::add_operation_node(ComponentNode *comp_node
int name_tag)
{
OperationNode *op_node = comp_node->find_operation(opcode, name, name_tag);
- if (op_node == NULL) {
+ if (op_node == nullptr) {
op_node = comp_node->add_operation(op, opcode, name, name_tag);
graph_->operations.push_back(op_node);
}
@@ -262,7 +263,7 @@ OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id,
int name_tag)
{
OperationNode *operation = find_operation_node(id, comp_type, opcode, name, name_tag);
- if (operation != NULL) {
+ if (operation != nullptr) {
return operation;
}
return add_operation_node(id, comp_type, opcode, op, name, name_tag);
@@ -275,7 +276,7 @@ bool DepsgraphNodeBuilder::has_operation_node(ID *id,
const char *name,
int name_tag)
{
- return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != NULL;
+ return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != nullptr;
}
OperationNode *DepsgraphNodeBuilder::find_operation_node(ID *id,
@@ -323,13 +324,13 @@ void DepsgraphNodeBuilder::begin_build()
id_info->id_cow = id_node->id_cow;
}
else {
- id_info->id_cow = NULL;
+ id_info->id_cow = nullptr;
}
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_node->id_cow = NULL;
+ id_node->id_cow = nullptr;
}
GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) {
@@ -349,23 +350,23 @@ void DepsgraphNodeBuilder::begin_build()
/* Make sure graph has no nodes left from previous state. */
graph_->clear_all_nodes();
graph_->operations.clear();
- BLI_gset_clear(graph_->entry_tags, NULL);
+ BLI_gset_clear(graph_->entry_tags, nullptr);
}
void DepsgraphNodeBuilder::end_build()
{
for (const SavedEntryTag &entry_tag : saved_entry_tags_) {
IDNode *id_node = find_id_node(entry_tag.id_orig);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
continue;
}
ComponentNode *comp_node = id_node->find_component(entry_tag.component_type);
- if (comp_node == NULL) {
+ if (comp_node == nullptr) {
continue;
}
OperationNode *op_node = comp_node->find_operation(
entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag);
- if (op_node == NULL) {
+ if (op_node == nullptr) {
continue;
}
/* Since the tag is coming from a saved copy of entry tags, this means
@@ -376,7 +377,7 @@ void DepsgraphNodeBuilder::end_build()
void DepsgraphNodeBuilder::build_id(ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
switch (GS(id->name)) {
@@ -390,7 +391,7 @@ void DepsgraphNodeBuilder::build_id(ID *id)
build_camera((Camera *)id);
break;
case ID_GR:
- build_collection(NULL, (Collection *)id);
+ build_collection(nullptr, (Collection *)id);
break;
case ID_OB:
/* TODO(sergey): Get visibility from a "parent" somehow.
@@ -432,6 +433,9 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_MSK:
build_mask((Mask *)id);
break;
+ case ID_LS:
+ build_freestyle_linestyle((FreestyleLineStyle *)id);
+ break;
case ID_MC:
build_movieclip((MovieClip *)id);
break;
@@ -483,7 +487,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
* objects are poked with the new visibility flag, since they
* might become visible too. */
}
- else if (from_layer_collection == NULL && !id_node->is_collection_fully_expanded) {
+ 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. */
@@ -497,7 +501,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
id_node = add_id_node(&collection->id);
id_node->is_directly_visible = is_collection_visible;
}
- if (from_layer_collection != NULL) {
+ if (from_layer_collection != nullptr) {
/* If we came from layer collection we don't go deeper, view layer
* builder takes care of going deeper. */
return;
@@ -514,7 +518,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
}
/* Build child collections. */
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- build_collection(NULL, child->collection);
+ build_collection(nullptr, child->collection);
}
/* Restore state. */
collection_ = current_state_collection;
@@ -527,7 +531,7 @@ void DepsgraphNodeBuilder::build_object(int base_index,
eDepsNode_LinkedState_Type linked_state,
bool is_visible)
{
- if (object->proxy != NULL) {
+ if (object->proxy != nullptr) {
object->proxy->proxy_from = object;
}
const bool has_object = built_map_.checkIsBuiltAndTag(object);
@@ -550,10 +554,10 @@ void DepsgraphNodeBuilder::build_object(int base_index,
IDNode *id_node = add_id_node(&object->id);
Object *object_cow = get_cow_datablock(object);
id_node->linked_state = linked_state;
- /* NOTE: Scene is NULL when building dependency graph for render pipeline.
- * Probably need to assign that to something non-NULL, but then the logic here will still be
+ /* NOTE: Scene is nullptr when building dependency graph for render pipeline.
+ * Probably need to assign that to something non-nullptr, but then the logic here will still be
* somewhat weird. */
- if (scene_ != NULL && object == scene_->camera) {
+ if (scene_ != nullptr && object == scene_->camera) {
id_node->is_directly_visible = true;
}
else {
@@ -565,32 +569,32 @@ void DepsgraphNodeBuilder::build_object(int base_index,
/* Transform. */
build_object_transform(object);
/* Parent. */
- if (object->parent != NULL) {
+ if (object->parent != nullptr) {
build_object(-1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible);
}
/* Modifiers. */
- if (object->modifiers.first != NULL) {
+ if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
data.is_parent_visible = is_visible;
modifiers_foreachIDLink(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
- if (object->greasepencil_modifiers.first != NULL) {
+ 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);
}
/* Shader FX. */
- if (object->shader_fx.first != NULL) {
+ if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
data.is_parent_visible = is_visible;
BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
}
/* Constraints. */
- if (object->constraints.first != NULL) {
+ if (object->constraints.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
data.is_parent_visible = is_visible;
@@ -608,17 +612,17 @@ void DepsgraphNodeBuilder::build_object(int base_index,
* pose for proxy. */
build_animdata(&object->id);
/* Particle systems. */
- if (object->particlesystem.first != NULL) {
+ if (object->particlesystem.first != nullptr) {
build_particle_systems(object, is_visible);
}
/* Proxy object to copy from. */
build_object_proxy_from(object, is_visible);
build_object_proxy_group(object, is_visible);
/* Object dupligroup. */
- if (object->instance_collection != NULL) {
+ if (object->instance_collection != nullptr) {
const bool is_current_parent_collection_visible = is_parent_collection_visible_;
is_parent_collection_visible_ = is_visible;
- build_collection(NULL, object->instance_collection);
+ build_collection(nullptr, object->instance_collection);
is_parent_collection_visible_ = is_current_parent_collection_visible;
add_operation_node(&object->id, NodeType::DUPLI, OperationCode::DUPLI);
}
@@ -654,7 +658,7 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index,
void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visible)
{
- if (object->proxy_from == NULL) {
+ if (object->proxy_from == nullptr) {
return;
}
build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
@@ -662,7 +666,7 @@ void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visib
void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visible)
{
- if (object->proxy_group == NULL) {
+ if (object->proxy_group == nullptr) {
return;
}
build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
@@ -670,7 +674,7 @@ void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visi
void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
{
- if (object->data == NULL) {
+ if (object->data == nullptr) {
return;
}
/* type-specific data. */
@@ -685,7 +689,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi
build_object_data_geometry(object, is_object_visible);
break;
case OB_ARMATURE:
- if (ID_IS_LINKED(object) && object->proxy_from != NULL) {
+ if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
build_proxy_rig(object);
}
else {
@@ -714,7 +718,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi
}
/* Materials. */
Material ***materials_ptr = give_matarar(object);
- if (materials_ptr != NULL) {
+ if (materials_ptr != nullptr) {
short *num_materials_ptr = give_totcolp(object);
build_materials(*materials_ptr, *num_materials_ptr);
}
@@ -759,14 +763,14 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object)
OperationCode::TRANSFORM_LOCAL,
function_bind(BKE_object_eval_local_transform, _1, ob_cow));
/* Object parent. */
- if (object->parent != NULL) {
+ if (object->parent != nullptr) {
add_operation_node(&object->id,
NodeType::TRANSFORM,
OperationCode::TRANSFORM_PARENT,
function_bind(BKE_object_eval_parent, _1, ob_cow));
}
/* Object constraints. */
- if (object->constraints.first != NULL) {
+ if (object->constraints.first != nullptr) {
build_object_constraints(object);
}
/* Rest of transformation update. */
@@ -836,16 +840,16 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
build_animation_images(id);
/* Regular animation. */
AnimData *adt = BKE_animdata_from_id(id);
- if (adt == NULL) {
+ if (adt == nullptr) {
return;
}
- if (adt->action != NULL) {
+ if (adt->action != nullptr) {
build_action(adt->action);
}
/* Make sure ID node exists. */
(void)add_id_node(id);
ID *id_cow = get_cow_id(id);
- if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks)) {
+ if (adt->action != nullptr || !BLI_listbase_is_empty(&adt->nla_tracks)) {
OperationNode *operation_node;
/* Explicit entry operation. */
operation_node = add_operation_node(id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY);
@@ -874,10 +878,10 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
{
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
- if (strip->act != NULL) {
+ if (strip->act != nullptr) {
build_action(strip->act);
}
- else if (strip->strips.first != NULL) {
+ else if (strip->strips.first != nullptr) {
build_animdata_nlastrip_targets(&strip->strips);
}
}
@@ -934,13 +938,13 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve)
build_driver_id_property(id, fcurve->rna_path);
LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) {
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- if (dtar->id == NULL) {
+ if (dtar->id == nullptr) {
continue;
}
build_id(dtar->id);
build_driver_id_property(dtar->id, dtar->rna_path);
/* Corresponds to dtar_id_ensure_proxy_from(). */
- if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) {
+ if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != nullptr)) {
Object *proxy_from = ((Object *)dtar->id)->proxy_from;
build_id(&proxy_from->id);
build_driver_id_property(&proxy_from->id, dtar->rna_path);
@@ -952,7 +956,7 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve)
void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path)
{
- if (id == NULL || rna_path == NULL) {
+ if (id == nullptr || rna_path == nullptr) {
return;
}
PointerRNA id_ptr, ptr;
@@ -962,7 +966,7 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path
if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) {
return;
}
- if (prop == NULL) {
+ if (prop == nullptr) {
return;
}
if (!RNA_property_is_idprop(prop)) {
@@ -970,7 +974,7 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
ensure_operation_node(
- id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, NULL, prop_identifier);
+ id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
}
void DepsgraphNodeBuilder::build_parameters(ID *id)
@@ -1049,8 +1053,8 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
sim_node->set_as_exit();
sim_node->owner->entry_operation = sim_node;
/* Objects - simulation participants. */
- if (rbw->group != NULL) {
- build_collection(NULL, rbw->group);
+ if (rbw->group != nullptr) {
+ build_collection(nullptr, rbw->group);
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
if (object->type != OB_MESH) {
continue;
@@ -1068,11 +1072,11 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* Constraints. */
- if (rbw->constraints != NULL) {
+ if (rbw->constraints != nullptr) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) {
RigidBodyCon *rbc = object->rigidbody_constraint;
- if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) {
- /* When either ob1 or ob2 is NULL, the constraint doesn't work. */
+ if (rbc == nullptr || rbc->ob1 == nullptr || rbc->ob2 == nullptr) {
+ /* When either ob1 or ob2 is nullptr, the constraint doesn't work. */
continue;
}
/* Make sure indirectly linked objects are fully built. */
@@ -1116,11 +1120,11 @@ void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object
* NOTE: The call itself ensures settings are only build once. */
build_particle_settings(part);
/* Particle system evaluation. */
- add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, NULL, psys->name);
+ add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, nullptr, psys->name);
/* Keyed particle targets. */
if (part->phystype == PART_PHYS_KEYED) {
LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) {
- if (particle_target->ob == NULL || particle_target->ob == object) {
+ if (particle_target->ob == nullptr || particle_target->ob == object) {
continue;
}
build_object(-1, particle_target->ob, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
@@ -1129,13 +1133,13 @@ void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object
/* Visualization of particle system. */
switch (part->ren_as) {
case PART_DRAW_OB:
- if (part->instance_object != NULL) {
+ if (part->instance_object != nullptr) {
build_object(-1, part->instance_object, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
}
break;
case PART_DRAW_GR:
- if (part->instance_collection != NULL) {
- build_collection(NULL, part->instance_collection);
+ if (part->instance_collection != nullptr) {
+ build_collection(nullptr, part->instance_collection);
}
break;
}
@@ -1170,7 +1174,7 @@ void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_se
/* Texture slots. */
for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) {
MTex *mtex = particle_settings->mtex[mtex_index];
- if (mtex == NULL || mtex->tex == NULL) {
+ if (mtex == nullptr || mtex->tex == nullptr) {
continue;
}
build_texture(mtex->tex);
@@ -1192,7 +1196,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
* drivers evaluation. */
LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) {
add_operation_node(
- &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, key_block->name);
+ &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, key_block->name);
}
}
@@ -1270,13 +1274,13 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
/* Make sure objects used for bevel.taper are in the graph.
* NOTE: This objects might be not linked to the scene. */
Curve *cu = (Curve *)obdata;
- if (cu->bevobj != NULL) {
+ if (cu->bevobj != nullptr) {
build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
}
- if (cu->taperobj != NULL) {
+ if (cu->taperobj != nullptr) {
build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
}
- if (cu->textoncurve != NULL) {
+ if (cu->textoncurve != nullptr) {
build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
}
break;
@@ -1334,7 +1338,7 @@ void DepsgraphNodeBuilder::build_camera(Camera *camera)
}
build_animdata(&camera->id);
build_parameters(&camera->id);
- if (camera->dof.focus_object != NULL) {
+ if (camera->dof.focus_object != nullptr) {
build_object(-1, camera->dof.focus_object, DEG_ID_LINKED_INDIRECTLY, false);
}
}
@@ -1352,7 +1356,7 @@ void DepsgraphNodeBuilder::build_light(Light *lamp)
void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
{
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
if (built_map_.checkIsBuiltAndTag(ntree)) {
@@ -1376,7 +1380,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
- if (id == NULL) {
+ if (id == nullptr) {
continue;
}
ID_Type id_type = GS(id->name);
@@ -1400,7 +1404,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
*
* On the one hand it's annoying to always pull it in, but on another hand it's also annoying
* to have hardcoded node-type exception here. */
- if (node_scene->camera != NULL) {
+ if (node_scene->camera != nullptr) {
/* TODO(sergey): Use visibility of owner of the node tree. */
build_object(-1, node_scene->camera, DEG_ID_LINKED_INDIRECTLY, true);
}
@@ -1450,7 +1454,7 @@ void DepsgraphNodeBuilder::build_material(Material *material)
void DepsgraphNodeBuilder::build_materials(Material **materials, int num_materials)
{
for (int i = 0; i < num_materials; i++) {
- if (materials[i] == NULL) {
+ if (materials[i] == nullptr) {
continue;
}
build_material(materials[i]);
@@ -1470,7 +1474,7 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture)
build_nodetree(texture->nodetree);
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
- if (texture->ima != NULL) {
+ if (texture->ima != nullptr) {
build_image(texture->ima);
}
}
@@ -1548,7 +1552,7 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask)
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskParent *parent = &point->parent;
- if (parent == NULL || parent->id == NULL) {
+ if (parent == nullptr || parent->id == nullptr) {
continue;
}
build_id(parent->id);
@@ -1557,6 +1561,18 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask)
}
}
+void DepsgraphNodeBuilder::build_freestyle_linestyle(FreestyleLineStyle *linestyle)
+{
+ if (built_map_.checkIsBuiltAndTag(linestyle)) {
+ return;
+ }
+
+ ID *linestyle_id = &linestyle->id;
+ build_parameters(linestyle_id);
+ build_animdata(linestyle_id);
+ build_nodetree(linestyle->nodetree);
+}
+
void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
{
if (built_map_.checkIsBuiltAndTag(clip)) {
@@ -1599,7 +1615,7 @@ void DepsgraphNodeBuilder::build_speaker(Speaker *speaker)
add_operation_node(&speaker->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
- if (speaker->sound != NULL) {
+ if (speaker->sound != nullptr) {
build_sound(speaker->sound);
}
}
@@ -1621,7 +1637,7 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound)
void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
{
- if (scene->ed == NULL) {
+ if (scene->ed == nullptr) {
return;
}
build_scene_audio(scene);
@@ -1633,13 +1649,13 @@ void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
/* Make sure data for sequences is in the graph. */
Sequence *seq;
SEQ_BEGIN (scene->ed, seq) {
- if (seq->sound != NULL) {
+ if (seq->sound != nullptr) {
build_sound(seq->sound);
}
- if (seq->scene != NULL) {
+ if (seq->scene != nullptr) {
build_scene_parameters(seq->scene);
}
- if (seq->type == SEQ_TYPE_SCENE && seq->scene != NULL) {
+ if (seq->type == SEQ_TYPE_SCENE && seq->scene != nullptr) {
if (seq->flag & SEQ_SCENE_STRIPS) {
build_scene_sequencer(seq->scene);
}
@@ -1680,7 +1696,7 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data,
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
ID *id = *idpoin;
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
switch (GS(id->name)) {
@@ -1703,7 +1719,7 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
ID *id = *idpoin;
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
switch (GS(id->name)) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 865f60432c1..54a4768d12a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -35,6 +35,8 @@ struct CacheFile;
struct Camera;
struct Collection;
struct FCurve;
+struct FreestyleLineSet;
+struct FreestyleLineStyle;
struct GHash;
struct ID;
struct Image;
@@ -104,27 +106,27 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
OperationNode *add_operation_node(ComponentNode *comp_node,
OperationCode opcode,
- const DepsEvalOperationCb &op = NULL,
+ const DepsEvalOperationCb &op = nullptr,
const char *name = "",
int name_tag = -1);
OperationNode *add_operation_node(ID *id,
NodeType comp_type,
const char *comp_name,
OperationCode opcode,
- const DepsEvalOperationCb &op = NULL,
+ const DepsEvalOperationCb &op = nullptr,
const char *name = "",
int name_tag = -1);
OperationNode *add_operation_node(ID *id,
NodeType comp_type,
OperationCode opcode,
- const DepsEvalOperationCb &op = NULL,
+ const DepsEvalOperationCb &op = nullptr,
const char *name = "",
int name_tag = -1);
OperationNode *ensure_operation_node(ID *id,
NodeType comp_type,
OperationCode opcode,
- const DepsEvalOperationCb &op = NULL,
+ const DepsEvalOperationCb &op = nullptr,
const char *name = "",
int name_tag = -1);
@@ -201,6 +203,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_nodetree(bNodeTree *ntree);
virtual void build_material(Material *ma);
virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_freestyle_lineset(FreestyleLineSet *fls);
+ virtual void build_freestyle_linestyle(FreestyleLineStyle *linestyle);
virtual void build_texture(Tex *tex);
virtual void build_image(Image *image);
virtual void build_world(World *world);
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 979e1a02e71..07010a5cbef 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -87,7 +87,7 @@ void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bC
/* Find the chain's root. */
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
- if (rootchan == NULL) {
+ if (rootchan == nullptr) {
return;
}
@@ -154,12 +154,12 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
/* Armature. */
build_armature(armature);
/* Rebuild pose if not up to date. */
- if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) {
- /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */
- BKE_pose_rebuild(NULL, object, armature, true);
+ if (object->pose == nullptr || (object->pose->flag & POSE_RECALC)) {
+ /* By definition, no need to tag depsgraph as dirty from here, so we can pass nullptr bmain. */
+ BKE_pose_rebuild(nullptr, object, armature, true);
}
/* Speed optimization for animation lookups. */
- if (object->pose != NULL) {
+ if (object->pose != nullptr) {
BKE_pose_channels_hash_make(object->pose);
if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(object->pose);
@@ -243,12 +243,12 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
op_node->set_as_exit();
/* Custom properties. */
- if (pchan->prop != NULL) {
+ if (pchan->prop != nullptr) {
add_operation_node(
- &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name);
+ &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
}
/* Build constraints. */
- if (pchan->constraints.first != NULL) {
+ if (pchan->constraints.first != nullptr) {
build_pose_constraints(object, pchan, pchan_index, is_object_visible);
}
/**
@@ -277,7 +277,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
}
/* Custom shape. */
- if (pchan->custom != NULL) {
+ if (pchan->custom != nullptr) {
/* TODO(sergey): Use own visibility. */
build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
}
@@ -291,7 +291,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
OperationNode *op_node;
Object *object_cow = get_cow_datablock(object);
/* Sanity check. */
- BLI_assert(object->pose != NULL);
+ BLI_assert(object->pose != nullptr);
/* Armature. */
build_armature(armature);
/* speed optimization for animation lookups */
@@ -322,9 +322,9 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
op_node->set_as_exit();
/* Custom properties. */
- if (pchan->prop != NULL) {
+ if (pchan->prop != nullptr) {
add_operation_node(
- &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name);
+ &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
}
pchan_index++;
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 777512acf89..1edf9826208 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
@@ -46,7 +46,7 @@ void DepsgraphNodeBuilder::build_scene_render(Scene *scene, ViewLayer *view_laye
build_scene_sequencer(scene);
build_scene_speakers(scene, view_layer);
}
- if (scene->camera != NULL) {
+ if (scene->camera != nullptr) {
build_object(-1, scene->camera, DEG_ID_LINKED_DIRECTLY, true);
}
}
@@ -76,7 +76,7 @@ void DepsgraphNodeBuilder::build_scene_compositor(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_COMPOSITOR)) {
return;
}
- if (scene->nodetree == NULL) {
+ if (scene->nodetree == nullptr) {
return;
}
build_nodetree(scene->nodetree);
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 88ebf1c9b50..d5e9c024812 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
@@ -37,6 +37,7 @@
extern "C" {
#include "DNA_freestyle_types.h"
#include "DNA_layer_types.h"
+#include "DNA_linestyle_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -74,6 +75,16 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb)
}
}
+void DepsgraphNodeBuilder::build_freestyle_lineset(FreestyleLineSet *fls)
+{
+ if (fls->group != nullptr) {
+ build_collection(nullptr, fls->group);
+ }
+ if (fls->linestyle != nullptr) {
+ build_freestyle_linestyle(fls->linestyle);
+ }
+}
+
void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state)
@@ -109,19 +120,19 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
}
}
build_layer_collections(&view_layer->layer_collections);
- if (scene->camera != NULL) {
+ if (scene->camera != nullptr) {
build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true);
}
/* Rigidbody. */
- if (scene->rigidbody_world != NULL) {
+ if (scene->rigidbody_world != nullptr) {
build_rigidbody(scene);
}
/* Scene's animation and drivers. */
- if (scene->adt != NULL) {
+ if (scene->adt != nullptr) {
build_animdata(&scene->id);
}
/* World. */
- if (scene->world != NULL) {
+ if (scene->world != nullptr) {
build_world(scene->world);
}
/* Cache file. */
@@ -137,14 +148,12 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
build_movieclip(clip);
}
/* Material override. */
- if (view_layer->mat_override != NULL) {
+ if (view_layer->mat_override != nullptr) {
build_material(view_layer->mat_override);
}
- /* Freestyle collections. */
+ /* Freestyle linesets. */
LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
- if (fls->group != NULL) {
- build_collection(NULL, fls->group);
- }
+ build_freestyle_lineset(fls);
}
/* Sequencer. */
if (linked_state == DEG_ID_LINKED_DIRECTLY) {
@@ -161,7 +170,7 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
build_scene_compositor(scene);
build_scene_parameters(scene);
/* Build all set scenes. */
- if (scene->set != NULL) {
+ if (scene->set != nullptr) {
ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set);
build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 95c50c4f44e..5483ff9c030 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -35,7 +35,7 @@ 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, NULL);
+ BLI_gset_free(values, nullptr);
}
RootPChanMap::RootPChanMap()
@@ -47,7 +47,7 @@ RootPChanMap::RootPChanMap()
RootPChanMap::~RootPChanMap()
{
/* Free the map, and all the value sets. */
- BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset);
+ BLI_ghash_free(map_, nullptr, free_rootpchanmap_valueset);
}
/* Debug contents of map */
@@ -91,7 +91,7 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
}
/* Check if there's a common root bone between two bones. */
-bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
+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) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 0c1d22f9345..1442f547b08 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -39,7 +39,7 @@ struct RootPChanMap {
void add_bone(const char *bone, const char *root);
/* Check if there's a common root bone between two bones. */
- bool has_common_root(const char *bone1, const char *bone2);
+ bool has_common_root(const char *bone1, const char *bone2) const;
protected:
/* The actual map:
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 3e0ab9684da..5214fdbd246 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -47,6 +47,7 @@ extern "C" {
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_light_types.h"
+#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
@@ -113,6 +114,7 @@ extern "C" {
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
+#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_type.h"
namespace DEG {
@@ -122,32 +124,10 @@ namespace DEG {
namespace {
-/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
- * time dependencies nor special exceptions in the depsgraph evaluation. */
-
-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;
-}
-
bool driver_target_depends_on_time(const DriverTarget *target)
{
if (target->idtype == ID_SCE &&
- (target->rna_path != NULL && STREQ(target->rna_path, "frame_current"))) {
+ (target->rna_path != nullptr && STREQ(target->rna_path, "frame_current"))) {
return true;
}
return false;
@@ -175,10 +155,8 @@ bool driver_variables_depends_on_time(const ListBase *variables)
bool driver_depends_on_time(ChannelDriver *driver)
{
- if (driver->type == DRIVER_TYPE_PYTHON) {
- if (python_driver_exression_depends_on_time(driver->expression)) {
- return true;
- }
+ if (BKE_driver_expression_depends_on_time(driver)) {
+ return true;
}
if (driver_variables_depends_on_time(&driver->variables)) {
return true;
@@ -217,10 +195,19 @@ bool object_particles_depends_on_time(Object *object)
bool check_id_has_anim_component(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
- if (adt == NULL) {
+ if (adt == nullptr) {
return false;
}
- return (adt->action != NULL) || (!BLI_listbase_is_empty(&adt->nla_tracks));
+ return (adt->action != nullptr) || (!BLI_listbase_is_empty(&adt->nla_tracks));
+}
+
+bool check_id_has_driver_component(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == nullptr) {
+ return false;
+ }
+ return !BLI_listbase_is_empty(&adt->drivers);
}
OperationCode bone_target_opcode(ID *target,
@@ -254,7 +241,7 @@ bool object_have_geometry_component(const Object *object)
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
Depsgraph *graph,
DepsgraphBuilderCache *cache)
- : DepsgraphBuilder(bmain, graph, cache), scene_(NULL), rna_node_query_(graph, this)
+ : DepsgraphBuilder(bmain, graph, cache), scene_(nullptr), rna_node_query_(graph, this)
{
}
@@ -262,7 +249,7 @@ TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey &key) con
{
if (key.id) {
/* XXX TODO */
- return NULL;
+ return nullptr;
}
else {
return graph_->time_source;
@@ -275,8 +262,8 @@ ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const
if (!id_node) {
fprintf(stderr,
"find_node component: Could not find ID %s\n",
- (key.id != NULL) ? key.id->name : "<null>");
- return NULL;
+ (key.id != nullptr) ? key.id->name : "<null>");
+ return nullptr;
}
ComponentNode *node = id_node->find_component(key.type, key.name);
@@ -286,7 +273,7 @@ ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const
OperationNode *DepsgraphRelationBuilder::get_node(const OperationKey &key) const
{
OperationNode *op_node = find_node(key);
- if (op_node == NULL) {
+ if (op_node == nullptr) {
fprintf(stderr,
"find_node_operation: Failed for (%s, '%s')\n",
operationCodeAsString(key.opcode),
@@ -304,18 +291,18 @@ OperationNode *DepsgraphRelationBuilder::find_node(const OperationKey &key) cons
{
IDNode *id_node = graph_->find_id_node(key.id);
if (!id_node) {
- return NULL;
+ return nullptr;
}
ComponentNode *comp_node = id_node->find_component(key.component_type, key.component_name);
if (!comp_node) {
- return NULL;
+ return nullptr;
}
return comp_node->find_operation(key.opcode, key.name, key.name_tag);
}
bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const
{
- return find_node(key) != NULL;
+ return find_node(key) != nullptr;
}
void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNodeHandle *handle,
@@ -331,10 +318,11 @@ void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNode
void DepsgraphRelationBuilder::add_customdata_mask(Object *object,
const DEGCustomDataMeshMasks &customdata_masks)
{
- if (customdata_masks != DEGCustomDataMeshMasks() && object != NULL && object->type == OB_MESH) {
+ if (customdata_masks != DEGCustomDataMeshMasks() && object != nullptr &&
+ object->type == OB_MESH) {
DEG::IDNode *id_node = graph_->find_id_node(&object->id);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
BLI_assert(!"ID should always be valid");
}
else {
@@ -346,7 +334,7 @@ void DepsgraphRelationBuilder::add_customdata_mask(Object *object,
void DepsgraphRelationBuilder::add_special_eval_flag(ID *id, uint32_t flag)
{
DEG::IDNode *id_node = graph_->find_id_node(id);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
BLI_assert(!"ID should always be valid");
}
else {
@@ -372,7 +360,7 @@ Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc,
(node_to) ? node_to->identifier().c_str() : "<None>",
description);
}
- return NULL;
+ return nullptr;
}
Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from,
@@ -393,7 +381,7 @@ Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_f
(node_to) ? node_to->identifier().c_str() : "<None>",
description);
}
- return NULL;
+ return nullptr;
}
void DepsgraphRelationBuilder::add_particle_collision_relations(const OperationKey &key,
@@ -453,7 +441,7 @@ void DepsgraphRelationBuilder::add_particle_forcefield_relations(const Operation
/* Absorption forces need collision relation. */
if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
- add_particle_collision_relations(key, object, NULL, "Force Absorption");
+ add_particle_collision_relations(key, object, nullptr, "Force Absorption");
}
}
@@ -490,7 +478,7 @@ void DepsgraphRelationBuilder::begin_build()
void DepsgraphRelationBuilder::build_id(ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
switch (GS(id->name)) {
@@ -504,10 +492,10 @@ void DepsgraphRelationBuilder::build_id(ID *id)
build_camera((Camera *)id);
break;
case ID_GR:
- build_collection(NULL, NULL, (Collection *)id);
+ build_collection(nullptr, nullptr, (Collection *)id);
break;
case ID_OB:
- build_object(NULL, (Object *)id);
+ build_object(nullptr, (Object *)id);
break;
case ID_KE:
build_shapekeys((Key *)id);
@@ -536,6 +524,9 @@ void DepsgraphRelationBuilder::build_id(ID *id)
case ID_MSK:
build_mask((Mask *)id);
break;
+ case ID_LS:
+ build_freestyle_linestyle((FreestyleLineStyle *)id);
+ break;
case ID_MC:
build_movieclip((MovieClip *)id);
break;
@@ -571,7 +562,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
Object *object,
Collection *collection)
{
- if (from_layer_collection != NULL) {
+ if (from_layer_collection != nullptr) {
/* If we came from layer collection we don't go deeper, view layer
* builder takes care of going deeper.
*
@@ -581,18 +572,19 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
return;
}
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
- OperationKey object_transform_final_key(
- object != NULL ? &object->id : NULL, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL);
- ComponentKey duplicator_key(object != NULL ? &object->id : NULL, NodeType::DUPLI);
+ OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr,
+ NodeType::TRANSFORM,
+ OperationCode::TRANSFORM_FINAL);
+ ComponentKey duplicator_key(object != nullptr ? &object->id : nullptr, NodeType::DUPLI);
if (!group_done) {
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- build_object(NULL, cob->ob);
+ build_object(nullptr, cob->ob);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- build_collection(NULL, NULL, child->collection);
+ build_collection(nullptr, nullptr, child->collection);
}
}
- if (object != NULL) {
+ if (object != nullptr) {
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, ob, graph_->mode) {
ComponentKey dupli_transform_key(&ob->id, NodeType::TRANSFORM);
add_relation(dupli_transform_key, object_transform_final_key, "Dupligroup");
@@ -612,7 +604,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
{
if (built_map_.checkIsBuiltAndTag(object)) {
- if (base != NULL) {
+ if (base != nullptr) {
build_object_flags(base, object);
}
return;
@@ -634,34 +626,34 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
/* Various flags, flushing from bases/collections. */
build_object_flags(base, object);
/* Parenting. */
- if (object->parent != NULL) {
+ if (object->parent != nullptr) {
/* Make sure parent object's relations are built. */
- build_object(NULL, object->parent);
+ build_object(nullptr, object->parent);
/* Parent relationship. */
build_object_parent(object);
/* Local -> parent. */
add_relation(local_transform_key, parent_transform_key, "ObLocal -> ObParent");
}
/* Modifiers. */
- if (object->modifiers.first != NULL) {
+ if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
modifiers_foreachIDLink(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
- if (object->greasepencil_modifiers.first != NULL) {
+ if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
}
/* Shader FX. */
- if (object->shader_fx.first != NULL) {
+ if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
}
/* Constraints. */
- if (object->constraints.first != NULL) {
+ if (object->constraints.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_constraints_id_loop(&object->constraints, constraint_walk, &data);
@@ -669,11 +661,11 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
/* Object constraints. */
OperationKey object_transform_simulation_init_key(
&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT);
- if (object->constraints.first != NULL) {
+ if (object->constraints.first != nullptr) {
OperationKey constraint_key(
&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_CONSTRAINTS);
/* Constraint relations. */
- build_constraints(&object->id, NodeType::TRANSFORM, "", &object->constraints, NULL);
+ build_constraints(&object->id, NodeType::TRANSFORM, "", &object->constraints, nullptr);
/* operation order */
add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack");
add_relation(constraint_key, final_transform_key, "ObConstraints -> Done");
@@ -697,15 +689,15 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
/* Object data. */
build_object_data(object);
/* Particle systems. */
- if (object->particlesystem.first != NULL) {
+ if (object->particlesystem.first != nullptr) {
build_particle_systems(object);
}
/* Proxy object to copy from. */
build_object_proxy_from(object);
build_object_proxy_group(object);
/* Object dupligroup. */
- if (object->instance_collection != NULL) {
- build_collection(NULL, object, object->instance_collection);
+ if (object->instance_collection != nullptr) {
+ build_collection(nullptr, object, object->instance_collection);
}
/* Point caches. */
build_object_pointcache(object);
@@ -719,11 +711,11 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
void DepsgraphRelationBuilder::build_object_proxy_from(Object *object)
{
- if (object->proxy_from == NULL) {
+ if (object->proxy_from == nullptr) {
return;
}
/* Object is linked here (comes from the library). */
- build_object(NULL, object->proxy_from);
+ build_object(nullptr, object->proxy_from);
ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
@@ -731,11 +723,11 @@ void DepsgraphRelationBuilder::build_object_proxy_from(Object *object)
void DepsgraphRelationBuilder::build_object_proxy_group(Object *object)
{
- if (object->proxy_group == NULL || object->proxy_group == object->proxy) {
+ if (object->proxy_group == nullptr || object->proxy_group == object->proxy) {
return;
}
/* Object is local here (local in .blend file, users interacts with it). */
- build_object(NULL, object->proxy_group);
+ build_object(nullptr, object->proxy_group);
OperationKey proxy_group_eval_key(
&object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
@@ -744,7 +736,7 @@ void DepsgraphRelationBuilder::build_object_proxy_group(Object *object)
void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object)
{
- if (base == NULL) {
+ if (base == nullptr) {
return;
}
OperationKey view_layer_done_key(
@@ -760,7 +752,7 @@ void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object)
void DepsgraphRelationBuilder::build_object_data(Object *object)
{
- if (object->data == NULL) {
+ if (object->data == nullptr) {
return;
}
ID *obdata_id = (ID *)object->data;
@@ -789,7 +781,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
break;
}
case OB_ARMATURE:
- if (ID_IS_LINKED(object) && object->proxy_from != NULL) {
+ if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
build_proxy_rig(object);
}
else {
@@ -810,7 +802,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
break;
}
Key *key = BKE_key_from_object(object);
- if (key != NULL) {
+ if (key != nullptr) {
ComponentKey geometry_key((ID *)object->data, NodeType::GEOMETRY);
ComponentKey key_key(&key->id, NodeType::GEOMETRY);
add_relation(key_key, geometry_key, "Shapekeys");
@@ -818,7 +810,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
}
/* Materials. */
Material ***materials_ptr = give_matarar(object);
- if (materials_ptr != NULL) {
+ if (materials_ptr != nullptr) {
short *num_materials_ptr = give_totcolp(object);
build_materials(*materials_ptr, *num_materials_ptr);
}
@@ -1040,7 +1032,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
/* Invalid constraint type. */
- if (cti == NULL) {
+ if (cti == nullptr) {
continue;
}
/* Special case for camera tracking -- it doesn't use targets to
@@ -1067,7 +1059,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
depends_on_camera = true;
}
- if (depends_on_camera && scene_->camera != NULL) {
+ if (depends_on_camera && scene_->camera != nullptr) {
ComponentKey camera_key(&scene_->camera->id, NodeType::TRANSFORM);
add_relation(camera_key, constraint_op_key, cti->name);
}
@@ -1088,10 +1080,10 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
}
}
else if (cti->get_constraint_targets) {
- ListBase targets = {NULL, NULL};
+ ListBase targets = {nullptr, nullptr};
cti->get_constraint_targets(con, &targets);
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
- if (ct->tar == NULL) {
+ if (ct->tar == nullptr) {
continue;
}
if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
@@ -1219,13 +1211,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
- if (adt == NULL) {
+ if (adt == nullptr) {
return;
}
- if (adt->action != NULL) {
+ if (adt->action != nullptr) {
build_action(adt->action);
}
- if (adt->action == NULL && BLI_listbase_is_empty(&adt->nla_tracks)) {
+ if (adt->action == nullptr && BLI_listbase_is_empty(&adt->nla_tracks)) {
return;
}
/* Ensure evaluation order from entry to exit. */
@@ -1237,20 +1229,20 @@ void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
/* Wire up dependency from action. */
ComponentKey adt_key(id, NodeType::ANIMATION);
/* Relation from action itself. */
- if (adt->action != NULL) {
+ if (adt->action != nullptr) {
ComponentKey action_key(&adt->action->id, NodeType::ANIMATION);
add_relation(action_key, adt_key, "Action -> Animation");
}
/* Get source operations. */
Node *node_from = get_node(adt_key);
- BLI_assert(node_from != NULL);
- if (node_from == NULL) {
+ BLI_assert(node_from != nullptr);
+ if (node_from == nullptr) {
return;
}
OperationNode *operation_from = node_from->get_exit_operation();
- BLI_assert(operation_from != NULL);
+ BLI_assert(operation_from != nullptr);
/* Build relations from animation operation to properties it changes. */
- if (adt->action != NULL) {
+ if (adt->action != nullptr) {
build_animdata_curves_targets(id, adt_key, operation_from, &adt->action->curves);
}
LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
@@ -1274,7 +1266,7 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id,
continue;
}
Node *node_to = rna_node_query_.find_node(&ptr, prop, RNAPointerSource::ENTRY);
- if (node_to == NULL) {
+ if (node_to == nullptr) {
continue;
}
OperationNode *operation_to = node_to->get_entry_operation();
@@ -1308,7 +1300,7 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id,
ListBase *strips)
{
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
- if (strip->act != NULL) {
+ if (strip->act != nullptr) {
build_action(strip->act);
ComponentKey action_key(&strip->act->id, NodeType::ANIMATION);
@@ -1316,7 +1308,7 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id,
build_animdata_curves_targets(id, adt_key, operation_from, &strip->act->curves);
}
- else if (strip->strips.first != NULL) {
+ else if (strip->strips.first != nullptr) {
build_animdata_nlastrip_targets(id, adt_key, operation_from, &strip->strips);
}
}
@@ -1325,7 +1317,7 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id,
void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
- if (adt == NULL) {
+ if (adt == nullptr) {
return;
}
ComponentKey adt_key(id, NodeType::ANIMATION);
@@ -1350,7 +1342,7 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
*
* TODO(sergey): Avoid liner lookup somehow. */
if (fcu->array_index > 0) {
- FCurve *fcu_prev = NULL;
+ FCurve *fcu_prev = nullptr;
LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
/* Writing to different RNA paths is */
const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
@@ -1362,11 +1354,11 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
continue;
}
/* Choose fcurve with highest possible array index. */
- if (fcu_prev == NULL || fcu_candidate->array_index > fcu_prev->array_index) {
+ if (fcu_prev == nullptr || fcu_candidate->array_index > fcu_prev->array_index) {
fcu_prev = fcu_candidate;
}
}
- if (fcu_prev != NULL) {
+ if (fcu_prev != nullptr) {
OperationKey prev_driver_key(id,
NodeType::PARAMETERS,
OperationCode::DRIVER,
@@ -1393,6 +1385,8 @@ void DepsgraphRelationBuilder::build_animation_images(ID *id)
/* TODO: can we check for existence of node for performance? */
if (BKE_image_user_id_has_animation(id)) {
OperationKey image_animation_key(id, NodeType::ANIMATION, OperationCode::IMAGE_ANIMATION);
+ ComponentKey cow_key(id, NodeType::COPY_ON_WRITE);
+ add_relation(cow_key, image_animation_key, "CoW -> Image Animation");
TimeSourceKey time_src_key;
add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation");
}
@@ -1436,7 +1430,7 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
{
/* Validate the RNA path pointer just in case. */
const char *rna_path = fcu->rna_path;
- if (rna_path == NULL || rna_path[0] == '\0') {
+ if (rna_path == nullptr || rna_path[0] == '\0') {
return;
}
/* Parse the RNA path to find the target property pointer. */
@@ -1466,16 +1460,16 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
/* Drivers on armature-level bone settings (i.e. bbone stuff),
* which will affect the evaluation of corresponding pose bones. */
Bone *bone = (Bone *)property_entry_key.ptr.data;
- if (bone != NULL) {
+ if (bone != nullptr) {
/* Find objects which use this, and make their eval callbacks
* depend on this. */
for (IDNode *to_node : graph_->id_nodes) {
if (GS(to_node->id_orig->name) == ID_OB) {
Object *object = (Object *)to_node->id_orig;
/* We only care about objects with pose data which use this. */
- if (object->data == id_ptr && object->pose != NULL) {
+ if (object->data == id_ptr && object->pose != nullptr) {
bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone->name);
- if (pchan != NULL) {
+ if (pchan != nullptr) {
OperationKey bone_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone");
@@ -1503,14 +1497,14 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
PointerRNA id_ptr;
PointerRNA ptr;
RNA_id_pointer_create(id, &id_ptr);
- if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) {
+ if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, nullptr, nullptr)) {
if (id_ptr.owner_id != ptr.owner_id) {
ComponentKey cow_key(ptr.owner_id, NodeType::COPY_ON_WRITE);
add_relation(cow_key, driver_key, "Driven CoW -> Driver", RELATION_CHECK_BEFORE_ADD);
}
}
}
- if (property_entry_key.prop != NULL && RNA_property_is_idprop(property_entry_key.prop)) {
+ if (property_entry_key.prop != nullptr && RNA_property_is_idprop(property_entry_key.prop)) {
RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT);
OperationKey parameters_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL);
add_relation(property_exit_key, parameters_key, "Driven Property -> Properties");
@@ -1532,16 +1526,16 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
/* Only used targets. */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
ID *target_id = dtar->id;
- if (target_id == NULL) {
+ if (target_id == nullptr) {
continue;
}
build_id(target_id);
build_driver_id_property(target_id, dtar->rna_path);
/* Look up the proxy - matches dtar_id_ensure_proxy_from during evaluation. */
- Object *object = NULL;
+ Object *object = nullptr;
if (GS(target_id->name) == ID_OB) {
object = (Object *)target_id;
- if (object->proxy_from != NULL) {
+ if (object->proxy_from != nullptr) {
/* Redirect the target to the proxy, like in evaluation. */
object = object->proxy_from;
target_id = &object->id;
@@ -1554,7 +1548,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (object && object->type == OB_ARMATURE) &&
(dtar->pchan_name[0])) {
bPoseChannel *target_pchan = BKE_pose_channel_find_name(object->pose, dtar->pchan_name);
- if (target_pchan == NULL) {
+ if (target_pchan == nullptr) {
continue;
}
OperationKey variable_key(
@@ -1575,7 +1569,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
OperationKey target_key(target_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL);
add_relation(target_key, driver_key, "Target -> Driver");
}
- else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') {
+ else if (dtar->rna_path != nullptr && dtar->rna_path[0] != '\0') {
RNAPathKey variable_exit_key(target_id, dtar->rna_path, RNAPointerSource::EXIT);
if (RNA_pointer_is_null(&variable_exit_key.ptr)) {
continue;
@@ -1587,7 +1581,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
}
else {
- /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this
+ /* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this
* is an incomplete target reference, so nothing to do here. */
}
}
@@ -1597,7 +1591,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_path)
{
- if (id == NULL || rna_path == NULL) {
+ if (id == nullptr || rna_path == nullptr) {
return;
}
PointerRNA id_ptr, ptr;
@@ -1607,7 +1601,7 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_
if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) {
return;
}
- if (prop == NULL) {
+ if (prop == nullptr) {
return;
}
if (!RNA_property_is_idprop(prop)) {
@@ -1639,7 +1633,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
build_animdata(&world->id);
build_parameters(&world->id);
/* world's nodetree */
- if (world->nodetree != NULL) {
+ if (world->nodetree != nullptr) {
build_nodetree(world->nodetree);
OperationKey ntree_key(
&world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
@@ -1669,7 +1663,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
LISTBASE_FOREACH (EffectorRelation *, effector_relation, effector_relations) {
ComponentKey effector_transform_key(&effector_relation->ob->id, NodeType::TRANSFORM);
add_relation(effector_transform_key, rb_init_key, "RigidBody Field");
- if (effector_relation->pd != NULL) {
+ if (effector_relation->pd != nullptr) {
const short shape = effector_relation->pd->shape;
if (ELEM(shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS)) {
ComponentKey effector_geometry_key(&effector_relation->ob->id, NodeType::GEOMETRY);
@@ -1678,8 +1672,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
}
}
/* Objects. */
- if (rbw->group != NULL) {
- build_collection(NULL, NULL, rbw->group);
+ if (rbw->group != nullptr) {
+ build_collection(nullptr, nullptr, rbw->group);
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
if (object->type != OB_MESH) {
continue;
@@ -1699,7 +1693,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* Geometry must be known to create the rigid body. RBO_MESH_BASE
* uses the non-evaluated mesh, so then the evaluation is
* unnecessary. */
- if (object->rigidbody_object != NULL &&
+ if (object->rigidbody_object != nullptr &&
object->rigidbody_object->mesh_source != RBO_MESH_BASE) {
/* NOTE: We prefer this relation to be never killed, to avoid
* access partially evaluated mesh from solver. */
@@ -1718,18 +1712,18 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* Constraints. */
- if (rbw->constraints != NULL) {
+ if (rbw->constraints != nullptr) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) {
RigidBodyCon *rbc = object->rigidbody_constraint;
- if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) {
- /* When either ob1 or ob2 is NULL, the constraint doesn't
+ if (rbc == nullptr || rbc->ob1 == nullptr || rbc->ob2 == nullptr) {
+ /* When either ob1 or ob2 is nullptr, the constraint doesn't
* work. */
continue;
}
/* Make sure indirectly linked objects are fully built. */
- build_object(NULL, object);
- build_object(NULL, rbc->ob1);
- build_object(NULL, rbc->ob2);
+ build_object(nullptr, object);
+ build_object(nullptr, rbc->ob1);
+ build_object(nullptr, rbc->ob2);
/* final result of the constraint object's transform controls how
* the constraint affects the physics sim for these objects. */
ComponentKey trans_key(&object->id, NodeType::TRANSFORM);
@@ -1785,8 +1779,8 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object)
add_particle_collision_relations(
psys_key, object, part->collision_group, "Particle Collision");
}
- else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd != NULL &&
- psys->clmd->coll_parms != NULL) {
+ else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd != nullptr &&
+ psys->clmd->coll_parms != nullptr) {
add_particle_collision_relations(
psys_key, object, psys->clmd->coll_parms->group, "Hair Collision");
}
@@ -1794,17 +1788,17 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object)
add_particle_forcefield_relations(
psys_key, object, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field");
/* Boids .*/
- if (part->boids != NULL) {
+ if (part->boids != nullptr) {
LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
- Object *ruleob = NULL;
+ Object *ruleob = nullptr;
if (rule->type == eBoidRuleType_Avoid) {
ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
}
else if (rule->type == eBoidRuleType_FollowLeader) {
ruleob = ((BoidRuleFollowLeader *)rule)->ob;
}
- if (ruleob != NULL) {
+ if (ruleob != nullptr) {
ComponentKey ruleob_key(&ruleob->id, NodeType::TRANSFORM);
add_relation(ruleob_key, psys_key, "Boid Rule");
}
@@ -1814,11 +1808,11 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object)
/* Keyed particle targets. */
if (part->phystype == PART_PHYS_KEYED) {
LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) {
- if (particle_target->ob == NULL || particle_target->ob == object) {
+ if (particle_target->ob == nullptr || particle_target->ob == object) {
continue;
}
/* Make sure target object is pulled into the graph. */
- build_object(NULL, particle_target->ob);
+ build_object(nullptr, particle_target->ob);
/* Use geometry component, since that's where particles are
* actually evaluated. */
ComponentKey target_key(&particle_target->ob->id, NodeType::GEOMETRY);
@@ -1828,16 +1822,16 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object)
/* Visualization. */
switch (part->ren_as) {
case PART_DRAW_OB:
- if (part->instance_object != NULL) {
+ if (part->instance_object != nullptr) {
/* Make sure object's relations are all built. */
- build_object(NULL, part->instance_object);
+ build_object(nullptr, part->instance_object);
/* Build relation for the particle visualization. */
build_particle_system_visualization_object(object, psys, part->instance_object);
}
break;
case PART_DRAW_GR:
- if (part->instance_collection != NULL) {
- build_collection(NULL, NULL, part->instance_collection);
+ if (part->instance_collection != nullptr) {
+ build_collection(nullptr, nullptr, part->instance_collection);
LISTBASE_FOREACH (CollectionObject *, go, &part->instance_collection->gobject) {
build_particle_system_visualization_object(object, psys, go->ob);
}
@@ -1870,7 +1864,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
/* Texture slots. */
for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) {
MTex *mtex = part->mtex[mtex_index];
- if (mtex == NULL || mtex->tex == NULL) {
+ if (mtex == nullptr || mtex->tex == nullptr) {
continue;
}
build_texture(mtex->tex);
@@ -1881,7 +1875,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
RELATION_FLAG_FLUSH_USER_EDIT_ONLY);
/* TODO(sergey): Consider moving texture space handling to an own
* function. */
- if (mtex->texco == TEXCO_OBJECT && mtex->object != NULL) {
+ if (mtex->texco == TEXCO_OBJECT && mtex->object != nullptr) {
ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM);
add_relation(object_key, particle_settings_eval_key, "Particle Texture Space");
}
@@ -1965,7 +1959,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
rel->flag |= RELATION_FLAG_NO_FLUSH;
/* Modifiers */
- if (object->modifiers.first != NULL) {
+ if (object->modifiers.first != nullptr) {
ModifierUpdateDepsgraphContext ctx = {};
ctx.scene = scene_;
ctx.object = object;
@@ -1983,7 +1977,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
}
}
/* Grease Pencil Modifiers. */
- if (object->greasepencil_modifiers.first != NULL) {
+ if (object->greasepencil_modifiers.first != nullptr) {
ModifierUpdateDepsgraphContext ctx = {};
ctx.scene = scene_;
ctx.object = object;
@@ -2002,7 +1996,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
}
}
/* Shader FX. */
- if (object->shader_fx.first != NULL) {
+ if (object->shader_fx.first != nullptr) {
ModifierUpdateDepsgraphContext ctx = {};
ctx.scene = scene_;
ctx.object = object;
@@ -2062,8 +2056,8 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
/* Object data data-block. */
build_object_data_geometry_datablock((ID *)object->data);
Key *key = BKE_key_from_object(object);
- if (key != NULL) {
- if (key->adt != NULL) {
+ if (key != nullptr) {
+ if (key->adt != nullptr) {
if (key->adt->action || key->adt->nla_tracks.first) {
ComponentKey obdata_key((ID *)object->data, NodeType::GEOMETRY);
ComponentKey adt_key(&key->id, NodeType::ANIMATION);
@@ -2096,7 +2090,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
build_parameters(obdata);
/* ShapeKeys. */
Key *key = BKE_key_from_id(obdata);
- if (key != NULL) {
+ if (key != nullptr) {
build_shapekeys(key);
}
/* Link object data evaluation node to exit operation. */
@@ -2112,22 +2106,22 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
break;
case ID_CU: {
Curve *cu = (Curve *)obdata;
- if (cu->bevobj != NULL) {
+ if (cu->bevobj != nullptr) {
ComponentKey bevob_geom_key(&cu->bevobj->id, NodeType::GEOMETRY);
add_relation(bevob_geom_key, obdata_geom_eval_key, "Curve Bevel Geometry");
ComponentKey bevob_key(&cu->bevobj->id, NodeType::TRANSFORM);
add_relation(bevob_key, obdata_geom_eval_key, "Curve Bevel Transform");
- build_object(NULL, cu->bevobj);
+ build_object(nullptr, cu->bevobj);
}
- if (cu->taperobj != NULL) {
+ if (cu->taperobj != nullptr) {
ComponentKey taperob_key(&cu->taperobj->id, NodeType::GEOMETRY);
add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper");
- build_object(NULL, cu->taperobj);
+ build_object(nullptr, cu->taperobj);
}
- if (cu->textoncurve != NULL) {
+ if (cu->textoncurve != nullptr) {
ComponentKey textoncurve_key(&cu->textoncurve->id, NodeType::GEOMETRY);
add_relation(textoncurve_key, obdata_geom_eval_key, "Text on Curve");
- build_object(NULL, cu->textoncurve);
+ build_object(nullptr, cu->textoncurve);
}
break;
}
@@ -2150,7 +2144,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
* we need to rebuild the bGPDstroke->triangles caches). */
for (int i = 0; i < gpd->totcol; i++) {
Material *ma = gpd->mat[i];
- if ((ma != NULL) && (ma->gp_style != NULL)) {
+ if ((ma != nullptr) && (ma->gp_style != nullptr)) {
OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
add_relation(material_key, geometry_key, "Material -> GP Data");
}
@@ -2179,8 +2173,8 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
}
build_animdata(&camera->id);
build_parameters(&camera->id);
- if (camera->dof.focus_object != NULL) {
- build_object(NULL, camera->dof.focus_object);
+ if (camera->dof.focus_object != nullptr) {
+ build_object(nullptr, camera->dof.focus_object);
ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS);
ComponentKey dof_ob_key(&camera->dof.focus_object->id, NodeType::TRANSFORM);
add_relation(dof_ob_key, camera_parameters_key, "Camera DOF");
@@ -2196,7 +2190,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
build_animdata(&lamp->id);
build_parameters(&lamp->id);
/* light's nodetree */
- if (lamp->nodetree != NULL) {
+ if (lamp->nodetree != nullptr) {
build_nodetree(lamp->nodetree);
ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING);
@@ -2207,7 +2201,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
{
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
if (built_map_.checkIsBuiltAndTag(ntree)) {
@@ -2219,7 +2213,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
- if (id == NULL) {
+ if (id == nullptr) {
continue;
}
ID_Type id_type = GS(id->name);
@@ -2239,7 +2233,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
add_relation(image_key, shading_key, "Image -> Node");
}
else if (id_type == ID_OB) {
- build_object(NULL, (Object *)id);
+ build_object(nullptr, (Object *)id);
ComponentKey object_transform_key(id, NodeType::TRANSFORM);
add_relation(object_transform_key, shading_key, "Object Transform -> Node");
if (object_have_geometry_component(reinterpret_cast<Object *>(id))) {
@@ -2254,8 +2248,8 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
*
* On the one hand it's annoying to always pull it in, but on another hand it's also annoying
* to have hardcoded node-type exception here. */
- if (node_scene->camera != NULL) {
- build_object(NULL, node_scene->camera);
+ if (node_scene->camera != nullptr) {
+ build_object(nullptr, node_scene->camera);
}
}
else if (id_type == ID_TXT) {
@@ -2305,7 +2299,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
build_animdata(&material->id);
build_parameters(&material->id);
/* material's nodetree */
- if (material->nodetree != NULL) {
+ if (material->nodetree != nullptr) {
build_nodetree(material->nodetree);
OperationKey ntree_key(
&material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
@@ -2318,7 +2312,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
void DepsgraphRelationBuilder::build_materials(Material **materials, int num_materials)
{
for (int i = 0; i < num_materials; i++) {
- if (materials[i] == NULL) {
+ if (materials[i] == nullptr) {
continue;
}
build_material(materials[i]);
@@ -2338,7 +2332,7 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
build_nodetree(texture->nodetree);
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
- if (texture->ima != NULL) {
+ if (texture->ima != nullptr) {
build_image(texture->ima);
}
}
@@ -2383,6 +2377,11 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
ComponentKey datablock_key(&cache_file->id, NodeType::CACHE);
add_relation(animation_key, datablock_key, "Datablock Animation");
}
+ if (check_id_has_driver_component(&cache_file->id)) {
+ ComponentKey animation_key(&cache_file->id, NodeType::PARAMETERS);
+ ComponentKey datablock_key(&cache_file->id, NodeType::CACHE);
+ add_relation(animation_key, datablock_key, "Drivers -> Cache Eval");
+ }
/* Cache file updates */
if (cache_file->is_sequence) {
@@ -2415,7 +2414,7 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskParent *parent = &point->parent;
- if (parent == NULL || parent->id == NULL) {
+ if (parent == nullptr || parent->id == nullptr) {
continue;
}
build_id(parent->id);
@@ -2429,6 +2428,18 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
}
}
+void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *linestyle)
+{
+ if (built_map_.checkIsBuiltAndTag(linestyle)) {
+ return;
+ }
+
+ ID *linestyle_id = &linestyle->id;
+ build_parameters(linestyle_id);
+ build_animdata(linestyle_id);
+ build_nodetree(linestyle->nodetree);
+}
+
void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
{
if (built_map_.checkIsBuiltAndTag(clip)) {
@@ -2455,7 +2466,7 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
}
build_animdata(&speaker->id);
build_parameters(&speaker->id);
- if (speaker->sound != NULL) {
+ if (speaker->sound != nullptr) {
build_sound(speaker->sound);
ComponentKey speaker_key(&speaker->id, NodeType::AUDIO);
ComponentKey sound_key(&speaker->sound->id, NodeType::AUDIO);
@@ -2474,7 +2485,7 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
{
- if (scene->ed == NULL) {
+ if (scene->ed == nullptr) {
return;
}
build_scene_audio(scene);
@@ -2484,18 +2495,18 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
Sequence *seq;
bool has_audio_strips = false;
SEQ_BEGIN (scene->ed, seq) {
- if (seq->sound != NULL) {
+ if (seq->sound != nullptr) {
build_sound(seq->sound);
ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO);
add_relation(sound_key, sequencer_key, "Sound -> Sequencer");
has_audio_strips = true;
}
- if (seq->scene != NULL) {
+ if (seq->scene != nullptr) {
build_scene_parameters(seq->scene);
/* This is to support 3D audio. */
has_audio_strips = true;
}
- if (seq->type == SEQ_TYPE_SCENE && seq->scene != NULL) {
+ if (seq->type == SEQ_TYPE_SCENE && seq->scene != nullptr) {
if (seq->flag & SEQ_SCENE_STRIPS) {
build_scene_sequencer(seq->scene);
ComponentKey sequence_scene_audio_key(&seq->scene->id, NodeType::AUDIO);
@@ -2525,7 +2536,7 @@ void DepsgraphRelationBuilder::build_scene_speakers(Scene * /*scene*/, ViewLayer
if (object->type != OB_SPEAKER || !need_pull_base_into_graph(base)) {
continue;
}
- build_object(NULL, base->object);
+ build_object(nullptr, base->object);
}
}
@@ -2551,7 +2562,7 @@ void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id)
void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree)
{
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
build_nested_datablock(owner, &ntree->id);
@@ -2559,7 +2570,7 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree
void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
{
- if (key == NULL) {
+ if (key == nullptr) {
return;
}
build_nested_datablock(owner, &key->id);
@@ -2616,7 +2627,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
/* All entry operations of each component should wait for a proper
* copy of ID. */
OperationNode *op_entry = comp_node->get_entry_operation();
- if (op_entry != NULL) {
+ if (op_entry != nullptr) {
Relation *rel = graph_->add_new_relation(op_cow, op_entry, "CoW Dependency");
rel->flag |= rel_flag;
}
@@ -2662,7 +2673,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
if (GS(id_orig->name) == ID_OB) {
Object *object = (Object *)id_orig;
ID *object_data_id = (ID *)object->data;
- if (object_data_id != NULL) {
+ if (object_data_id != nullptr) {
if (deg_copy_on_write_is_needed(object_data_id)) {
OperationKey data_copy_on_write_key(
object_data_id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
@@ -2674,6 +2685,26 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
BLI_assert(object->type == OB_EMPTY);
}
}
+
+#if 0
+ /* NOTE: Relation is disabled since AnimationBackup() is disabled.
+ * See comment in AnimationBackup:init_from_id(). */
+
+ /* Copy-on-write of write will iterate over f-curves to store current values corresponding
+ * to their RNA path. This means that action must be copied prior to the ID's copy-on-write,
+ * otherwise depsgraph might try to access freed data. */
+ AnimData *animation_data = BKE_animdata_from_id(id_orig);
+ if (animation_data != nullptr) {
+ if (animation_data->action != nullptr) {
+ OperationKey action_copy_on_write_key(
+ &animation_data->action->id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
+ add_relation(action_copy_on_write_key,
+ copy_on_write_key,
+ "Eval Order",
+ RELATION_FLAG_GODMODE | RELATION_FLAG_NO_FLUSH);
+ }
+ }
+#endif
}
/* **** ID traversal callbacks functions **** */
@@ -2685,7 +2716,7 @@ void DepsgraphRelationBuilder::modifier_walk(void *user_data,
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
ID *id = *idpoin;
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
data->builder->build_id(id);
@@ -2698,7 +2729,7 @@ void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/,
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
ID *id = *idpoin;
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
data->builder->build_id(id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index c6a0014577f..11eb31c68f6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -51,6 +51,8 @@ struct Camera;
struct Collection;
struct EffectorWeights;
struct FCurve;
+struct FreestyleLineSet;
+struct FreestyleLineStyle;
struct ID;
struct Image;
struct Key;
@@ -255,6 +257,10 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
bPoseChannel *pchan,
bConstraint *con,
RootPChanMap *root_map);
+ virtual void build_inter_ik_chains(Object *object,
+ const OperationKey &solver_key,
+ const bPoseChannel *rootchan,
+ const RootPChanMap *root_map);
virtual void build_rig(Object *object);
virtual void build_proxy_rig(Object *object);
virtual void build_shapekeys(Key *key);
@@ -264,6 +270,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_nodetree(bNodeTree *ntree);
virtual void build_material(Material *ma);
virtual void build_materials(Material **materials, int num_materials);
+ virtual void build_freestyle_lineset(FreestyleLineSet *fls);
+ virtual void build_freestyle_linestyle(FreestyleLineStyle *linestyle);
virtual void build_texture(Tex *tex);
virtual void build_image(Image *image);
virtual void build_gpencil(bGPdata *gpd);
@@ -360,7 +368,7 @@ struct DepsNodeHandle {
const char *default_name = "")
: builder(builder), node(node), default_name(default_name)
{
- BLI_assert(node != NULL);
+ BLI_assert(node != nullptr);
}
DepsgraphRelationBuilder *builder;
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 4412fa3fca3..eeeb58100b0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -36,7 +36,7 @@ template<typename KeyType>
OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType &key)
{
Node *node = get_node(key);
- return node != NULL ? node->get_exit_operation() : NULL;
+ return node != nullptr ? node->get_exit_operation() : nullptr;
}
template<typename KeyFrom, typename KeyTo>
@@ -47,8 +47,8 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
{
Node *node_from = get_node(key_from);
Node *node_to = get_node(key_to);
- OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
- OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr;
+ OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr;
if (op_from && op_to) {
return add_operation_relation(op_from, op_to, description, flags);
}
@@ -80,7 +80,7 @@ Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
key_to.identifier().c_str());
}
}
- return NULL;
+ return nullptr;
}
template<typename KeyTo>
@@ -91,11 +91,11 @@ Relation *DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
{
TimeSourceNode *time_from = get_node(key_from);
Node *node_to = get_node(key_to);
- OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
- if (time_from != NULL && op_to != NULL) {
+ OperationNode *op_to = node_to ? node_to->get_entry_operation() : nullptr;
+ if (time_from != nullptr && op_to != nullptr) {
return add_time_relation(time_from, op_to, description, flags);
}
- return NULL;
+ return nullptr;
}
template<typename KeyType>
@@ -105,9 +105,9 @@ Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_
int flags)
{
Node *node_from = get_node(key_from);
- OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationNode *op_from = node_from ? node_from->get_exit_operation() : nullptr;
OperationNode *op_to = handle->node->get_entry_operation();
- if (op_from != NULL && op_to != NULL) {
+ if (op_from != nullptr && op_to != nullptr) {
return add_operation_relation(op_from, op_to, description, flags);
}
else {
@@ -124,7 +124,7 @@ Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_
key_from.identifier().c_str());
}
}
- return NULL;
+ return nullptr;
}
template<typename KeyTo>
@@ -135,7 +135,7 @@ Relation *DepsgraphRelationBuilder::add_depends_on_transform_relation(ID *id,
{
if (GS(id->name) == ID_OB) {
Object *object = reinterpret_cast<Object *>(id);
- if (object->rigidbody_object != NULL) {
+ if (object->rigidbody_object != nullptr) {
OperationKey transform_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
return add_relation(transform_key, key_to, description, flags);
}
@@ -162,12 +162,12 @@ bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom &key_from,
/* Get operations for requested keys. */
Node *node_from = get_node(key_from);
Node *node_to = get_node(key_to);
- if (node_from == NULL || node_to == NULL) {
+ if (node_from == nullptr || node_to == nullptr) {
return false;
}
OperationNode *op_from = node_from->get_exit_operation();
OperationNode *op_to = node_to->get_entry_operation();
- if (op_from == NULL || op_to == NULL) {
+ if (op_from == nullptr || op_to == nullptr) {
return false;
}
/* Different armatures, bone can't be the same. */
@@ -193,12 +193,12 @@ bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(const KeyFrom &k
/* Get operations for requested keys. */
Node *node_from = get_node(key_from);
Node *node_to = get_node(key_to);
- if (node_from == NULL || node_to == NULL) {
+ if (node_from == nullptr || node_to == nullptr) {
return false;
}
OperationNode *op_from = node_from->get_exit_operation();
OperationNode *op_to = node_to->get_entry_operation();
- if (op_from == NULL || op_to == NULL) {
+ if (op_from == nullptr || op_to == nullptr) {
return false;
}
/* Check if this is actually a node tree. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
index 35af968d46e..6c449900f03 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
@@ -30,7 +30,7 @@ namespace DEG {
////////////////////////////////////////////////////////////////////////////////
// Time source.
-TimeSourceKey::TimeSourceKey() : id(NULL)
+TimeSourceKey::TimeSourceKey() : id(nullptr)
{
}
@@ -46,7 +46,7 @@ string TimeSourceKey::identifier() const
////////////////////////////////////////////////////////////////////////////////
// Component.
-ComponentKey::ComponentKey() : id(NULL), type(NodeType::UNDEFINED), name("")
+ComponentKey::ComponentKey() : id(nullptr), type(NodeType::UNDEFINED), name("")
{
}
@@ -72,7 +72,7 @@ string ComponentKey::identifier() const
// Operation.
OperationKey::OperationKey()
- : id(NULL),
+ : id(nullptr),
component_type(NodeType::UNDEFINED),
component_name(""),
opcode(OperationCode::OPERATION),
@@ -176,7 +176,7 @@ RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) : id(i
int index;
if (!RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) {
ptr = PointerRNA_NULL;
- prop = NULL;
+ prop = nullptr;
}
}
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 e254f8df0d2..12cd6936a13 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -58,6 +58,7 @@ extern "C" {
#include "intern/node/deg_node_operation.h"
#include "intern/depsgraph_type.h"
+#include "intern/depsgraph_relation.h"
namespace DEG {
@@ -70,7 +71,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
/* Attach owner to IK Solver to. */
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
- if (rootchan == NULL) {
+ if (rootchan == nullptr) {
return;
}
OperationKey pchan_local_key(
@@ -90,7 +91,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key;
/* IK target */
/* TODO(sergey): This should get handled as part of the constraint code. */
- if (data->tar != NULL) {
+ if (data->tar != nullptr) {
/* Different object - requires its transform. */
if (data->tar != object) {
ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM);
@@ -119,7 +120,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
}
/* Pole Target. */
/* TODO(sergey): This should get handled as part of the constraint code. */
- if (data->poletar != NULL) {
+ if (data->poletar != nullptr) {
/* Different object - requires its transform. */
if (data->poletar != object) {
ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM);
@@ -146,7 +147,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
"\nStarting IK Build: pchan = %s, target = (%s, %s), "
"segcount = %d\n",
pchan->name,
- data->tar ? data->tar->id.name : "NULL",
+ data->tar ? data->tar->id.name : "nullptr",
data->subtarget,
data->rootbone);
bPoseChannel *parchan = pchan;
@@ -160,7 +161,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
add_relation(parchan_transforms_key, solver_key, "IK Solver Owner");
/* Walk to the chain's root. */
int segcount = 0;
- while (parchan != NULL) {
+ while (parchan != nullptr) {
/* Make IK-solver dependent on this bone's result, since it can only run
* after the standard results of the bone are know. Validate links step
* on the bone will ensure that users of this bone only grab the result
@@ -192,6 +193,9 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
}
OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
+
+ /* Add relation when the root of this IK chain is influenced by another IK chain. */
+ build_inter_ik_chains(object, solver_key, rootchan, root_map);
}
/* Spline IK Eval Steps */
@@ -214,7 +218,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
/* Attach owner to IK Solver. */
add_relation(transforms_key, solver_key, "Spline IK Solver Owner", RELATION_FLAG_GODMODE);
/* Attach path dependency to solver. */
- if (data->tar != NULL) {
+ if (data->tar != nullptr) {
ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY);
add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK");
ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM);
@@ -228,7 +232,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
root_map->add_bone(pchan->name, rootchan->name);
/* Walk to the chain's root/ */
int segcount = 1;
- for (bPoseChannel *parchan = pchan->parent; parchan != NULL && segcount < data->chainlen;
+ for (bPoseChannel *parchan = pchan->parent; parchan != nullptr && segcount < data->chainlen;
parchan = parchan->parent, segcount++) {
/* Make Spline IK solver dependent on this bone's result, since it can
* only run after the standard results of the bone are know. Validate
@@ -244,6 +248,33 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
}
OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
+
+ /* Add relation when the root of this IK chain is influenced by another IK chain. */
+ build_inter_ik_chains(object, solver_key, rootchan, root_map);
+}
+
+void DepsgraphRelationBuilder::build_inter_ik_chains(Object *object,
+ const OperationKey &solver_key,
+ const bPoseChannel *rootchan,
+ const RootPChanMap *root_map)
+{
+ bPoseChannel *deepest_root = nullptr;
+ const char *root_name = rootchan->name;
+
+ /* Find shared IK chain root. */
+ for (bPoseChannel *parchan = rootchan->parent; parchan; parchan = parchan->parent) {
+ if (!root_map->has_common_root(root_name, parchan->name)) {
+ break;
+ }
+ deepest_root = parchan;
+ }
+ if (deepest_root == nullptr) {
+ return;
+ }
+
+ OperationKey other_bone_key(
+ &object->id, NodeType::BONE, deepest_root->name, OperationCode::BONE_DONE);
+ add_relation(other_bone_key, solver_key, "IK Chain Overlap");
}
/* Pose/Armature Bones Graph */
@@ -332,7 +363,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* Local to pose parenting operation. */
add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose");
/* Parent relation. */
- if (pchan->parent != NULL) {
+ if (pchan->parent != nullptr) {
OperationCode parent_key_opcode;
/* NOTE: this difference in handling allows us to prevent lockups
* while ensuring correct poses for separate chains. */
@@ -347,7 +378,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone");
}
/* Build constraints. */
- if (pchan->constraints.first != NULL) {
+ if (pchan->constraints.first != nullptr) {
/* Build relations for indirectly linked objects. */
BuilderWalkUserData data;
data.builder = this;
@@ -412,8 +443,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
add_relation(bone_ready_key, pose_cleanup_key, "Ready -> Cleanup");
}
/* Custom shape. */
- if (pchan->custom != NULL) {
- build_object(NULL, pchan->custom);
+ if (pchan->custom != nullptr) {
+ build_object(nullptr, pchan->custom);
}
}
}
@@ -456,13 +487,13 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
* the parent bone, some users expect the parent to be ready if the
* bone itself is (e.g. for computing the local space matrix).
*/
- if (pchan->parent != NULL) {
+ if (pchan->parent != nullptr) {
OperationKey parent_key(
&object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE);
add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone");
}
- if (pchan->prop != NULL) {
+ if (pchan->prop != nullptr) {
OperationKey bone_parameters(
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
OperationKey from_bone_parameters(
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 4e0c2cbba0c..08191bcecc8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -42,8 +42,8 @@ void DepsgraphRelationBuilder::build_scene_render(Scene *scene, ViewLayer *view_
build_scene_sequencer(scene);
build_scene_speakers(scene, view_layer);
}
- if (scene->camera != NULL) {
- build_object(NULL, scene->camera);
+ if (scene->camera != nullptr) {
+ build_object(nullptr, scene->camera);
}
}
@@ -64,7 +64,7 @@ void DepsgraphRelationBuilder::build_scene_compositor(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_COMPOSITOR)) {
return;
}
- if (scene->nodetree == NULL) {
+ if (scene->nodetree == nullptr) {
return;
}
build_nodetree(scene->nodetree);
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 4c55e4a137a..41e91ba7286 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
@@ -35,6 +35,7 @@
#include "BLI_blenlib.h"
extern "C" {
+#include "DNA_linestyle_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -69,12 +70,22 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
continue;
}
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
- build_collection(lc, NULL, lc->collection);
+ build_collection(lc, nullptr, lc->collection);
}
build_layer_collections(&lc->layer_collections);
}
}
+void DepsgraphRelationBuilder::build_freestyle_lineset(FreestyleLineSet *fls)
+{
+ if (fls->group != nullptr) {
+ build_collection(nullptr, nullptr, fls->group);
+ }
+ if (fls->linestyle != nullptr) {
+ build_freestyle_linestyle(fls->linestyle);
+ }
+}
+
void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state)
@@ -84,7 +95,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
/* Scene objects. */
/* NOTE: Nodes builder requires us to pass CoW base because it's being
* passed to the evaluation functions. During relations builder we only
- * do NULL-pointer check of the base, so it's fine to pass original one. */
+ * do nullptr-pointer check of the base, so it's fine to pass original one. */
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (need_pull_base_into_graph(base)) {
build_object(base, base->object);
@@ -93,19 +104,19 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
build_layer_collections(&view_layer->layer_collections);
- if (scene->camera != NULL) {
- build_object(NULL, scene->camera);
+ if (scene->camera != nullptr) {
+ build_object(nullptr, scene->camera);
}
/* Rigidbody. */
- if (scene->rigidbody_world != NULL) {
+ if (scene->rigidbody_world != nullptr) {
build_rigidbody(scene);
}
/* Scene's animation and drivers. */
- if (scene->adt != NULL) {
+ if (scene->adt != nullptr) {
build_animdata(&scene->id);
}
/* World. */
- if (scene->world != NULL) {
+ if (scene->world != nullptr) {
build_world(scene->world);
}
/* Masks. */
@@ -117,14 +128,12 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
build_movieclip(clip);
}
/* Material override. */
- if (view_layer->mat_override != NULL) {
+ if (view_layer->mat_override != nullptr) {
build_material(view_layer->mat_override);
}
- /* Freestyle collections. */
+ /* Freestyle linesets. */
LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
- if (fls->group != NULL) {
- build_collection(NULL, NULL, fls->group);
- }
+ build_freestyle_lineset(fls);
}
/* Scene parameters, compositor and such. */
build_scene_compositor(scene);
@@ -140,7 +149,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
build_scene_sequencer(scene);
}
/* Build all set scenes. */
- if (scene->set != NULL) {
+ if (scene->set != nullptr) {
ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set);
build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 180499519f6..853f8995d68 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -57,14 +57,14 @@ namespace DEG {
class RNANodeQueryIDData {
public:
- explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(NULL)
+ explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(nullptr)
{
}
~RNANodeQueryIDData()
{
- if (contraint_to_pchan_map_ != NULL) {
- BLI_ghash_free(contraint_to_pchan_map_, NULL, NULL);
+ if (contraint_to_pchan_map_ != nullptr) {
+ BLI_ghash_free(contraint_to_pchan_map_, nullptr, nullptr);
}
}
@@ -76,13 +76,13 @@ class RNANodeQueryIDData {
void ensure_constraint_to_pchan_map()
{
- if (contraint_to_pchan_map_ != NULL) {
+ if (contraint_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");
- if (object->pose != NULL) {
+ 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_,
@@ -105,7 +105,7 @@ class RNANodeQueryIDData {
/* ***************************** Node Identifier **************************** */
RNANodeIdentifier::RNANodeIdentifier()
- : id(NULL),
+ : id(nullptr),
type(NodeType::UNDEFINED),
component_name(""),
operation_code(OperationCode::OPERATION),
@@ -116,7 +116,7 @@ RNANodeIdentifier::RNANodeIdentifier()
bool RNANodeIdentifier::is_valid() const
{
- return id != NULL && type != NodeType::UNDEFINED;
+ return id != nullptr && type != NodeType::UNDEFINED;
}
/* ********************************** Query ********************************* */
@@ -140,7 +140,7 @@ RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder)
RNANodeQuery::~RNANodeQuery()
{
- BLI_ghash_free(id_data_map_, NULL, ghash_id_data_free_func);
+ BLI_ghash_free(id_data_map_, nullptr, ghash_id_data_free_func);
}
Node *RNANodeQuery::find_node(const PointerRNA *ptr,
@@ -149,16 +149,16 @@ Node *RNANodeQuery::find_node(const PointerRNA *ptr,
{
const RNANodeIdentifier node_identifier = construct_node_identifier(ptr, prop, source);
if (!node_identifier.is_valid()) {
- return NULL;
+ return nullptr;
}
IDNode *id_node = depsgraph_->find_id_node(node_identifier.id);
- if (id_node == NULL) {
- return NULL;
+ if (id_node == nullptr) {
+ return nullptr;
}
ComponentNode *comp_node = id_node->find_component(node_identifier.type,
node_identifier.component_name);
- if (comp_node == NULL) {
- return NULL;
+ if (comp_node == nullptr) {
+ return nullptr;
}
if (node_identifier.operation_code == OperationCode::OPERATION) {
return comp_node;
@@ -173,7 +173,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
RNAPointerSource source)
{
RNANodeIdentifier node_identifier;
- if (ptr->type == NULL) {
+ if (ptr->type == nullptr) {
return node_identifier;
}
/* Set default values for returns. */
@@ -183,44 +183,42 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.operation_name = "";
node_identifier.operation_name_tag = -1;
/* Handling of commonly known scenarios. */
- if (ptr->type == &RNA_PoseBone) {
+ if (prop != nullptr && RNA_property_is_idprop(prop)) {
+ node_identifier.type = NodeType::PARAMETERS;
+ node_identifier.operation_code = OperationCode::ID_PROPERTY;
+ node_identifier.operation_name = RNA_property_identifier(
+ reinterpret_cast<const PropertyRNA *>(prop));
+ return node_identifier;
+ }
+ else if (ptr->type == &RNA_PoseBone) {
const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr->data);
- if (prop != NULL && RNA_property_is_idprop(prop)) {
- node_identifier.type = NodeType::PARAMETERS;
- node_identifier.operation_code = OperationCode::ID_PROPERTY;
- node_identifier.operation_name = RNA_property_identifier(
- reinterpret_cast<const PropertyRNA *>(prop));
- node_identifier.operation_name_tag = -1;
- }
- else {
- /* Bone - generally, we just want the bone component. */
- node_identifier.type = NodeType::BONE;
- node_identifier.component_name = pchan->name;
- /* However check property name for special handling. */
- if (prop != NULL) {
- Object *object = reinterpret_cast<Object *>(node_identifier.id);
- const char *prop_name = RNA_property_identifier(prop);
- /* B-Bone properties should connect to the final operation. */
- if (STRPREFIX(prop_name, "bbone_")) {
- if (builder_->check_pchan_has_bbone_segments(object, pchan)) {
- node_identifier.operation_code = OperationCode::BONE_SEGMENTS;
- }
- else {
- node_identifier.operation_code = OperationCode::BONE_DONE;
- }
+ /* Bone - generally, we just want the bone component. */
+ node_identifier.type = NodeType::BONE;
+ node_identifier.component_name = pchan->name;
+ /* However check property name for special handling. */
+ if (prop != nullptr) {
+ Object *object = reinterpret_cast<Object *>(node_identifier.id);
+ const char *prop_name = RNA_property_identifier(prop);
+ /* B-Bone properties should connect to the final operation. */
+ if (STRPREFIX(prop_name, "bbone_")) {
+ if (builder_->check_pchan_has_bbone_segments(object, pchan)) {
+ node_identifier.operation_code = OperationCode::BONE_SEGMENTS;
}
- /* Final transform properties go to the Done node for the exit. */
- else if (STREQ(prop_name, "head") || STREQ(prop_name, "tail") ||
- STREQ(prop_name, "length") || STRPREFIX(prop_name, "matrix")) {
- if (source == RNAPointerSource::EXIT) {
- node_identifier.operation_code = OperationCode::BONE_DONE;
- }
- }
- /* And other properties can always go to the entry operation. */
else {
- node_identifier.operation_code = OperationCode::BONE_LOCAL;
+ node_identifier.operation_code = OperationCode::BONE_DONE;
+ }
+ }
+ /* Final transform properties go to the Done node for the exit. */
+ else if (STREQ(prop_name, "head") || STREQ(prop_name, "tail") ||
+ STREQ(prop_name, "length") || STRPREFIX(prop_name, "matrix")) {
+ if (source == RNAPointerSource::EXIT) {
+ node_identifier.operation_code = OperationCode::BONE_DONE;
}
}
+ /* And other properties can always go to the entry operation. */
+ else {
+ node_identifier.operation_code = OperationCode::BONE_LOCAL;
+ }
}
return node_identifier;
}
@@ -247,7 +245,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
* at a given constraint, but for rigging one might use constraint
* influence to be used to drive some corrective shape keys or so. */
const bPoseChannel *pchan = id_data->get_pchan_for_constraint(constraint);
- if (pchan == NULL) {
+ if (pchan == nullptr) {
node_identifier.type = NodeType::TRANSFORM;
node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL;
}
@@ -262,10 +260,10 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
Object *object = reinterpret_cast<Object *>(ptr->owner_id);
bConstraintTarget *tgt = (bConstraintTarget *)ptr->data;
/* Check whether is object or bone constraint. */
- bPoseChannel *pchan = NULL;
+ bPoseChannel *pchan = nullptr;
bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan);
- if (con != NULL) {
- if (pchan != NULL) {
+ if (con != nullptr) {
+ if (pchan != nullptr) {
node_identifier.type = NodeType::BONE;
node_identifier.operation_code = OperationCode::BONE_LOCAL;
node_identifier.component_name = pchan->name;
@@ -301,7 +299,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
}
else if (ptr->type == &RNA_Object) {
/* Transforms props? */
- if (prop != NULL) {
+ if (prop != nullptr) {
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
/* TODO(sergey): How to optimize this? */
if (strstr(prop_identifier, "location") || strstr(prop_identifier, "rotation") ||
@@ -372,20 +370,12 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.type = NodeType::GEOMETRY;
return node_identifier;
}
- if (prop != NULL) {
+ if (prop != nullptr) {
/* All unknown data effectively falls under "parameter evaluation". */
- if (RNA_property_is_idprop(prop)) {
- node_identifier.type = NodeType::PARAMETERS;
- node_identifier.operation_code = OperationCode::ID_PROPERTY;
- node_identifier.operation_name = RNA_property_identifier((PropertyRNA *)prop);
- node_identifier.operation_name_tag = -1;
- }
- else {
- node_identifier.type = NodeType::PARAMETERS;
- node_identifier.operation_code = OperationCode::PARAMETERS_EVAL;
- node_identifier.operation_name = "";
- node_identifier.operation_name_tag = -1;
- }
+ node_identifier.type = NodeType::PARAMETERS;
+ node_identifier.operation_code = OperationCode::PARAMETERS_EVAL;
+ node_identifier.operation_name = "";
+ node_identifier.operation_name_tag = -1;
return node_identifier;
}
return node_identifier;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 13cf8e63832..fc7c546e294 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -30,6 +30,7 @@
#include "intern/node/deg_node_operation.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
#include "intern/debug/deg_debug.h"
namespace DEG {
diff --git a/source/blender/depsgraph/intern/debug/deg_debug.cc b/source/blender/depsgraph/intern/debug/deg_debug.cc
index b811f11f721..74a042989db 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug.cc
@@ -28,10 +28,50 @@
#include "BLI_hash.h"
#include "BLI_string.h"
+#include "PIL_time_utildefines.h"
+
#include "BKE_global.h"
namespace DEG {
+DepsgraphDebug::DepsgraphDebug()
+ : flags(G.debug), is_ever_evaluated(false), graph_evaluation_start_time_(0)
+{
+}
+
+bool DepsgraphDebug::do_time_debug() const
+{
+ return ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
+}
+
+void DepsgraphDebug::begin_graph_evaluation()
+{
+ if (!do_time_debug()) {
+ return;
+ }
+
+ const double current_time = PIL_check_seconds_timer();
+
+ if (is_ever_evaluated) {
+ fps_samples_.add_sample(current_time - graph_evaluation_start_time_);
+ }
+
+ graph_evaluation_start_time_ = current_time;
+}
+
+void DepsgraphDebug::end_graph_evaluation()
+{
+ if (!do_time_debug()) {
+ return;
+ }
+
+ const double graph_eval_end_time = PIL_check_seconds_timer();
+ printf("Depsgraph updated in %f seconds.\n", graph_eval_end_time - graph_evaluation_start_time_);
+ printf("Depsgraph evaluation FPS: %f\n", 1.0f / fps_samples_.get_averaged());
+
+ is_ever_evaluated = true;
+}
+
bool terminal_do_color(void)
{
return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0;
diff --git a/source/blender/depsgraph/intern/debug/deg_debug.h b/source/blender/depsgraph/intern/debug/deg_debug.h
index 3e4da644641..21a802828dc 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug.h
+++ b/source/blender/depsgraph/intern/debug/deg_debug.h
@@ -24,6 +24,7 @@
#pragma once
#include "intern/depsgraph_type.h"
+#include "intern/debug/deg_time_average.h"
#include "BKE_global.h"
@@ -31,6 +32,38 @@
namespace DEG {
+class DepsgraphDebug {
+ public:
+ DepsgraphDebug();
+
+ bool do_time_debug() const;
+
+ void begin_graph_evaluation();
+ void end_graph_evaluation();
+
+ /* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */
+ int flags;
+
+ /* Name of this dependency graph (is used for debug prints, helping to distinguish graphs
+ * created for different view layer). */
+ string name;
+
+ /* Is true when dependency graph was evaluated at least once.
+ * This is NOT an indication that depsgraph is at its evaluated state. */
+ bool is_ever_evaluated;
+
+ protected:
+ /* Maximum number of counters used to calculate frame rate of depsgraph update. */
+ static const constexpr int MAX_FPS_COUNTERS = 64;
+
+ /* Point in time when last graph evaluation began.
+ * Is initialized from begin_graph_evaluation() when time debug is enabled.
+ */
+ double graph_evaluation_start_time_;
+
+ AveragedTimeSampler<MAX_FPS_COUNTERS> fps_samples_;
+};
+
#define DEG_DEBUG_PRINTF(depsgraph, type, ...) \
do { \
if (DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_##type) { \
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 ee3959a0861..b2f2359a954 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -36,6 +36,8 @@ extern "C" {
#include "DEG_depsgraph_debug.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
+
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
@@ -553,7 +555,7 @@ static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgr
deg_debug_graphviz_node(ctx, node);
}
TimeSourceNode *time_source = graph->find_time_source();
- if (time_source != NULL) {
+ if (time_source != nullptr) {
deg_debug_graphviz_node(ctx, time_source);
}
}
@@ -570,7 +572,7 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const De
}
TimeSourceNode *time_source = graph->find_time_source();
- if (time_source != NULL) {
+ if (time_source != nullptr) {
deg_debug_graphviz_node_relations(ctx, 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 4a668e817fe..c37188bc3ca 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
@@ -156,7 +156,7 @@ void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph,
const char *label,
const char *output_filename)
{
- if (depsgraph == NULL) {
+ if (depsgraph == nullptr) {
return;
}
DEG::DebugContext ctx;
diff --git a/source/blender/depsgraph/intern/debug/deg_time_average.h b/source/blender/depsgraph/intern/debug/deg_time_average.h
new file mode 100644
index 00000000000..9794e9a88c3
--- /dev/null
+++ b/source/blender/depsgraph/intern/debug/deg_time_average.h
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+namespace DEG {
+
+// Utility class which takes care of calculating average of time series, such as
+// FPS counters.
+template<int MaxSamples> class AveragedTimeSampler {
+ public:
+ AveragedTimeSampler() : num_samples_(0), next_sample_index_(0)
+ {
+ }
+
+ void add_sample(double value)
+ {
+ samples_[next_sample_index_] = value;
+
+ // Move to the next index, keeping wrapping at the end of array into account.
+ ++next_sample_index_;
+ if (next_sample_index_ == MaxSamples) {
+ next_sample_index_ = 0;
+ }
+
+ // Update number of stored samples.
+ if (num_samples_ != MaxSamples) {
+ ++num_samples_;
+ }
+ }
+
+ double get_averaged() const
+ {
+ double sum = 0.0;
+ for (int i = 0; i < num_samples_; ++i) {
+ sum += samples_[i];
+ }
+ return sum / num_samples_;
+ }
+
+ protected:
+ double samples_[MaxSamples];
+
+ // Number of samples which are actually stored in the array.
+ int num_samples_;
+
+ // Index in the samples_ array under which next sample will be stored.
+ int next_sample_index_;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 292c3b361d8..ce6797939b5 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -46,6 +46,7 @@ extern "C" {
#include "intern/depsgraph_update.h"
#include "intern/depsgraph_physics.h"
+#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_registry.h"
#include "intern/eval/deg_eval_copy_on_write.h"
@@ -66,7 +67,7 @@ template<typename T> static void remove_from_vector(vector<T> *vector, const T &
}
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
- : time_source(NULL),
+ : time_source(nullptr),
need_update(true),
need_update_time(false),
bmain(bmain),
@@ -74,7 +75,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
view_layer(view_layer),
mode(mode),
ctime(BKE_scene_frame_get(scene)),
- scene_cow(NULL),
+ scene_cow(nullptr),
is_active(false),
is_evaluating(false),
is_render_pipeline_depsgraph(false)
@@ -82,7 +83,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
BLI_spin_init(&lock);
id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
- debug_flags = G.debug;
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,9 +91,9 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
Depsgraph::~Depsgraph()
{
clear_id_nodes();
- BLI_ghash_free(id_hash, NULL, NULL);
- BLI_gset_free(entry_tags, NULL);
- if (time_source != NULL) {
+ BLI_ghash_free(id_hash, nullptr, nullptr);
+ BLI_gset_free(entry_tags, nullptr);
+ if (time_source != nullptr) {
OBJECT_GUARDED_DELETE(time_source, TimeSourceNode);
}
BLI_spin_end(&lock);
@@ -103,9 +103,9 @@ Depsgraph::~Depsgraph()
TimeSourceNode *Depsgraph::add_time_source()
{
- if (time_source == NULL) {
+ if (time_source == nullptr) {
DepsNodeFactory *factory = type_get_factory(NodeType::TIMESOURCE);
- time_source = (TimeSourceNode *)factory->create_node(NULL, "", "Time Source");
+ time_source = (TimeSourceNode *)factory->create_node(nullptr, "", "Time Source");
}
return time_source;
}
@@ -143,7 +143,7 @@ IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
void Depsgraph::clear_id_nodes_conditional(const std::function<bool(ID_Type id_type)> &filter)
{
for (IDNode *id_node : id_nodes) {
- if (id_node->id_cow == NULL) {
+ if (id_node->id_cow == nullptr) {
/* This means builder "stole" ownership of the copy-on-written
* datablock for her own dirty needs. */
continue;
@@ -170,7 +170,7 @@ void Depsgraph::clear_id_nodes()
OBJECT_GUARDED_DELETE(id_node, IDNode);
}
/* Clear containers. */
- BLI_ghash_clear(id_hash, NULL, NULL);
+ BLI_ghash_clear(id_hash, nullptr, nullptr);
id_nodes.clear();
/* Clear physics relation caches. */
clear_physics_relations(this);
@@ -179,11 +179,11 @@ void Depsgraph::clear_id_nodes()
/* Add new relation between two nodes */
Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags)
{
- Relation *rel = NULL;
+ Relation *rel = nullptr;
if (flags & RELATION_CHECK_BEFORE_ADD) {
rel = check_nodes_connected(from, to, description);
}
- if (rel != NULL) {
+ if (rel != nullptr) {
rel->flag |= flags;
return rel;
}
@@ -212,49 +212,12 @@ Relation *Depsgraph::check_nodes_connected(const Node *from,
if (rel->to != to) {
continue;
}
- if (description != NULL && !STREQ(rel->name, description)) {
+ if (description != nullptr && !STREQ(rel->name, description)) {
continue;
}
return rel;
}
- return NULL;
-}
-
-/* ************************ */
-/* Relationships Management */
-
-Relation::Relation(Node *from, Node *to, const char *description)
- : from(from), to(to), name(description), flag(0)
-{
- /* Hook it up to the nodes which use it.
- *
- * NOTE: We register relation in the nodes which this link connects to here
- * in constructor but we don't unregister it in the destructor.
- *
- * Reasoning:
- *
- * - Destructor is currently used on global graph destruction, so there's no
- * real need in avoiding dangling pointers, all the memory is to be freed
- * anyway.
- *
- * - Unregistering 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);
-}
-
-Relation::~Relation()
-{
- /* Sanity check. */
- BLI_assert(from != NULL && to != NULL);
-}
-
-void Relation::unlink()
-{
- /* Sanity check. */
- BLI_assert(from != NULL && to != NULL);
- remove_from_vector(&from->outlinks, this);
- remove_from_vector(&to->inlinks, this);
+ return nullptr;
}
/* Low level tagging -------------------------------------- */
@@ -263,7 +226,7 @@ void Relation::unlink()
void Depsgraph::add_entry_tag(OperationNode *node)
{
/* Sanity check. */
- if (node == NULL) {
+ if (node == nullptr) {
return;
}
/* Add to graph-level set of directly modified nodes to start searching
@@ -276,16 +239,16 @@ void Depsgraph::add_entry_tag(OperationNode *node)
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
- if (time_source != NULL) {
+ if (time_source != nullptr) {
OBJECT_GUARDED_DELETE(time_source, TimeSourceNode);
- time_source = NULL;
+ time_source = nullptr;
}
}
ID *Depsgraph::get_cow_id(const ID *id_orig) const
{
IDNode *id_node = find_id_node(id_orig);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
/* This function is used from places where we expect ID to be either
* already a copy-on-write version or have a corresponding copy-on-write
* version.
@@ -325,7 +288,7 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
- if (graph == NULL) {
+ if (graph == nullptr) {
return;
}
using DEG::Depsgraph;
@@ -342,10 +305,10 @@ bool DEG_is_evaluating(struct Depsgraph *depsgraph)
bool DEG_is_active(const struct Depsgraph *depsgraph)
{
- if (depsgraph == NULL) {
+ if (depsgraph == nullptr) {
/* Happens for such cases as work object in what_does_obaction(),
* and sine render pipeline parts. Shouldn't really be accepting
- * NULL depsgraph, but is quite hard to get proper one in those
+ * nullptr depsgraph, but is quite hard to get proper one in those
* cases. */
return false;
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 43829f4e045..7801f95e008 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -40,6 +40,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_physics.h"
+#include "intern/debug/deg_debug.h"
#include "intern/depsgraph_type.h"
struct GHash;
@@ -53,47 +54,9 @@ namespace DEG {
struct IDNode;
struct Node;
struct OperationNode;
+struct Relation;
struct TimeSourceNode;
-/* *************************** */
-/* Relationships Between Nodes */
-
-/* Settings/Tags on Relationship.
- * NOTE: Is a bitmask, allowing accumulation. */
-enum RelationFlag {
- /* "cyclic" link - when detecting cycles, this relationship was the one
- * which triggers a cyclic relationship to exist in the graph. */
- RELATION_FLAG_CYCLIC = (1 << 0),
- /* Update flush will not go through this relation. */
- RELATION_FLAG_NO_FLUSH = (1 << 1),
- /* Only flush along the relation is update comes from a node which was
- * affected by user input. */
- RELATION_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2),
- /* The relation can not be killed by the cyclic dependencies solver. */
- RELATION_FLAG_GODMODE = (1 << 4),
- /* Relation will check existence before being added. */
- RELATION_CHECK_BEFORE_ADD = (1 << 5),
-};
-
-/* B depends on A (A -> B) */
-struct Relation {
- Relation(Node *from, Node *to, const char *description);
- ~Relation();
-
- void unlink();
-
- /* the nodes in the relationship (since this is shared between the nodes) */
- Node *from; /* A */
- Node *to; /* B */
-
- /* relationship attributes */
- const char *name; /* label for debugging */
- int flag; /* Bitmask of RelationFlag) */
-};
-
-/* ********* */
-/* Depsgraph */
-
/* Dependency Graph object */
struct Depsgraph {
// TODO(sergey): Go away from C++ container and use some native BLI.
@@ -107,7 +70,7 @@ struct Depsgraph {
TimeSourceNode *find_time_source() const;
IDNode *find_id_node(const ID *id) const;
- IDNode *add_id_node(ID *id, ID *id_cow_hint = NULL);
+ IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr);
void clear_id_nodes();
void clear_id_nodes_conditional(const std::function<bool(ID_Type id_type)> &filter);
@@ -115,7 +78,7 @@ struct Depsgraph {
Relation *add_new_relation(Node *from, Node *to, const char *description, int flags = 0);
/* Check whether two nodes are connected by relation with given
- * description. Description might be NULL to check ANY relation between
+ * description. Description might be nullptr to check ANY relation between
* given nodes. */
Relation *check_nodes_connected(const Node *from, const Node *to, const char *description);
@@ -194,9 +157,7 @@ struct Depsgraph {
* to read stuff from. */
bool is_active;
- /* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */
- int debug_flags;
- string debug_name;
+ DepsgraphDebug debug;
bool is_evaluating;
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index f67ab381c79..a570e042c26 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -59,6 +59,7 @@ extern "C" {
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
+#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_registry.h"
#include "intern/depsgraph_type.h"
@@ -143,7 +144,7 @@ void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle,
ID *id = DEG_get_id_from_handle(node_handle);
DEG::ComponentKey point_cache_key(id, DEG::NodeType::POINT_CACHE);
DEG::Relation *rel = relation_builder->add_relation(comp_key, point_cache_key, "Point Cache");
- if (rel != NULL) {
+ if (rel != nullptr) {
rel->flag |= DEG::RELATION_FLAG_FLUSH_USER_EDIT_ONLY;
}
else {
@@ -345,7 +346,7 @@ class DepsgraphFromIDsFilter {
DepsgraphFromIDsFilter(ID **ids, const int num_ids)
{
for (int i = 0; i < num_ids; ++i) {
- ids_.insert(ids[0]);
+ ids_.insert(ids[i]);
}
}
@@ -376,7 +377,7 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder {
virtual void build_object_proxy_group(Object *object, bool is_visible) override
{
- if (object->proxy_group == NULL) {
+ if (object->proxy_group == nullptr) {
return;
}
if (!filter_.contains(&object->proxy_group->id)) {
@@ -407,7 +408,7 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder {
virtual void build_object_proxy_group(Object *object) override
{
- if (object->proxy_group == NULL) {
+ if (object->proxy_group == nullptr) {
return;
}
if (!filter_.contains(&object->proxy_group->id)) {
@@ -478,7 +479,7 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
* TODO(sergey): Try to make it so we don't flush updates
* to the whole depsgraph. */
DEG::IDNode *id_node = deg_graph->find_id_node(&deg_graph->scene->id);
- if (id_node != NULL) {
+ if (id_node != nullptr) {
id_node->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_RELATIONS);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index bb60db5209c..25f7e9117d1 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -38,6 +38,7 @@ extern "C" {
#include "DEG_depsgraph_query.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_type.h"
#include "intern/debug/deg_debug.h"
#include "intern/node/deg_node_component.h"
@@ -47,31 +48,31 @@ extern "C" {
void DEG_debug_flags_set(Depsgraph *depsgraph, int flags)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
- deg_graph->debug_flags = flags;
+ deg_graph->debug.flags = flags;
}
int DEG_debug_flags_get(const Depsgraph *depsgraph)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
- return deg_graph->debug_flags;
+ return deg_graph->debug.flags;
}
void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
- deg_graph->debug_name = name;
+ deg_graph->debug.name = name;
}
const char *DEG_debug_name_get(struct Depsgraph *depsgraph)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
- return deg_graph->debug_name.c_str();
+ return deg_graph->debug.name.c_str();
}
bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2)
{
- BLI_assert(graph1 != NULL);
- BLI_assert(graph2 != NULL);
+ BLI_assert(graph1 != nullptr);
+ BLI_assert(graph2 != nullptr);
const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1);
const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2);
if (deg_graph1->operations.size() != deg_graph2->operations.size()) {
@@ -233,7 +234,7 @@ void DEG_stats_simple(const Depsgraph *graph,
}
DEG::TimeSourceNode *time_source = deg_graph->find_time_source();
- if (time_source != NULL) {
+ if (time_source != nullptr) {
tot_rels += time_source->inlinks.size();
}
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc
index f47081cd54e..cabb95fe732 100644
--- a/source/blender/depsgraph/intern/depsgraph_physics.cc
+++ b/source/blender/depsgraph/intern/depsgraph_physics.cc
@@ -67,8 +67,8 @@ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type
ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collection)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
- if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == NULL) {
- return NULL;
+ if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == nullptr) {
+ return nullptr;
}
ID *collection_orig = DEG_get_original_id(&collection->id);
@@ -82,8 +82,8 @@ ListBase *DEG_get_collision_relations(const Depsgraph *graph,
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
- if (deg_graph->physics_relations[type] == NULL) {
- return NULL;
+ if (deg_graph->physics_relations[type] == nullptr) {
+ return nullptr;
}
ID *collection_orig = DEG_get_original_id(&collection->id);
return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[type], collection_orig);
@@ -106,7 +106,7 @@ void DEG_add_collision_relations(DepsNodeHandle *handle,
if (ob1 == object) {
continue;
}
- if (filter_function == NULL ||
+ if (filter_function == nullptr ||
filter_function(ob1, modifiers_findByType(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,7 +144,7 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle,
}
/* Smoke flow relations. */
- if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source != NULL) {
+ if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source != nullptr) {
DEG_add_object_pointcache_relation(
handle, relation->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain");
DEG_add_object_pointcache_relation(
@@ -154,7 +154,7 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle,
/* Absorption forces need collision relation. */
if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
DEG_add_collision_relations(
- handle, object, NULL, eModifierType_Collision, NULL, "Force Absorption");
+ handle, object, nullptr, eModifierType_Collision, nullptr, "Force Absorption");
}
}
}
@@ -166,13 +166,13 @@ namespace DEG {
ListBase *build_effector_relations(Depsgraph *graph, Collection *collection)
{
GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
- if (hash == NULL) {
+ if (hash == nullptr) {
graph->physics_relations[DEG_PHYSICS_EFFECTOR] = BLI_ghash_ptr_new(
"Depsgraph physics relations hash");
hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
}
ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection));
- if (relations == NULL) {
+ if (relations == nullptr) {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection);
BLI_ghash_insert(hash, &collection->id, relations);
@@ -186,12 +186,12 @@ ListBase *build_collision_relations(Depsgraph *graph,
{
const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
GHash *hash = graph->physics_relations[type];
- if (hash == NULL) {
+ if (hash == nullptr) {
graph->physics_relations[type] = BLI_ghash_ptr_new("Depsgraph physics relations hash");
hash = graph->physics_relations[type];
}
ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection));
- if (relations == NULL) {
+ if (relations == nullptr) {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
relations = BKE_collision_relations_create(depsgraph, collection, modifier_type);
BLI_ghash_insert(hash, &collection->id, relations);
@@ -221,17 +221,17 @@ void clear_physics_relations(Depsgraph *graph)
switch (type) {
case DEG_PHYSICS_EFFECTOR:
- BLI_ghash_free(graph->physics_relations[i], NULL, free_effector_relations);
+ BLI_ghash_free(graph->physics_relations[i], nullptr, free_effector_relations);
break;
case DEG_PHYSICS_COLLISION:
case DEG_PHYSICS_SMOKE_COLLISION:
case DEG_PHYSICS_DYNAMIC_BRUSH:
- BLI_ghash_free(graph->physics_relations[i], NULL, free_collision_relations);
+ BLI_ghash_free(graph->physics_relations[i], nullptr, free_collision_relations);
break;
case DEG_PHYSICS_RELATIONS_NUM:
break;
}
- graph->physics_relations[i] = NULL;
+ graph->physics_relations[i] = nullptr;
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 3b0f49e0150..4205f79b9c0 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -103,7 +103,7 @@ bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type)
uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
{
- if (graph == NULL) {
+ if (graph == nullptr) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
*
@@ -114,7 +114,7 @@ uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id));
- if (id_node == NULL) {
+ if (id_node == nullptr) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
}
@@ -126,7 +126,7 @@ void DEG_get_customdata_mask_for_object(const Depsgraph *graph,
Object *ob,
CustomData_MeshMasks *r_mask)
{
- if (graph == NULL) {
+ if (graph == nullptr) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
*
@@ -137,7 +137,7 @@ void DEG_get_customdata_mask_for_object(const Depsgraph *graph,
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(&ob->id));
- if (id_node == NULL) {
+ if (id_node == nullptr) {
/* TODO(sergey): Does it mean we need to check set scene? */
return;
}
@@ -155,7 +155,7 @@ Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
Scene *scene_cow = deg_graph->scene_cow;
/* TODO(sergey): Shall we expand data-block here? Or is it OK to assume
* that caller is OK with just a pointer in case scene is not updated yet? */
- BLI_assert(scene_cow != NULL && DEG::deg_copy_on_write_is_expanded(&scene_cow->id));
+ BLI_assert(scene_cow != nullptr && DEG::deg_copy_on_write_is_expanded(&scene_cow->id));
return scene_cow;
}
@@ -163,15 +163,15 @@ ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
Scene *scene_cow = DEG_get_evaluated_scene(graph);
- if (scene_cow == NULL) {
- return NULL; /* Happens with new, not-yet-built/evaluated graphes. */
+ if (scene_cow == nullptr) {
+ return nullptr; /* Happens with new, not-yet-built/evaluated graphes. */
}
/* Do name-based lookup. */
/* TODO(sergey): Can this be optimized? */
ViewLayer *view_layer_orig = deg_graph->view_layer;
ViewLayer *view_layer_cow = (ViewLayer *)BLI_findstring(
&scene_cow->view_layers, view_layer_orig->name, offsetof(ViewLayer, name));
- BLI_assert(view_layer_cow != NULL);
+ BLI_assert(view_layer_cow != nullptr);
return view_layer_cow;
}
@@ -182,15 +182,15 @@ Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
{
- if (id == NULL) {
- return NULL;
+ if (id == nullptr) {
+ return nullptr;
}
/* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
* but here we never do assert, since we don't know nature of the
* incoming ID data-block. */
const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph;
const DEG::IDNode *id_node = deg_graph->find_id_node(id);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
return id;
}
return id_node->id_cow;
@@ -201,7 +201,7 @@ void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
PointerRNA *ptr,
PointerRNA *r_ptr_eval)
{
- if ((ptr == NULL) || (r_ptr_eval == NULL)) {
+ if ((ptr == nullptr) || (r_ptr_eval == nullptr)) {
return;
}
ID *orig_id = ptr->owner_id;
@@ -233,7 +233,7 @@ void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
if (path) {
PointerRNA cow_id_ptr;
RNA_id_pointer_create(cow_id, &cow_id_ptr);
- if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, NULL)) {
+ if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, nullptr)) {
/* Couldn't find COW copy of data */
fprintf(stderr,
"%s: Couldn't resolve RNA path ('%s') relative to COW ID (%p) for '%s'\n",
@@ -261,10 +261,10 @@ Object *DEG_get_original_object(Object *object)
ID *DEG_get_original_id(ID *id)
{
- if (id == NULL) {
- return NULL;
+ if (id == nullptr) {
+ return nullptr;
}
- if (id->orig_id == NULL) {
+ if (id->orig_id == nullptr) {
return id;
}
BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0);
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index b7a40fb69bd..0a28e379ef5 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -40,6 +40,7 @@ extern "C" {
#include "DEG_depsgraph_query.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_id.h"
@@ -87,7 +88,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
{
/* Start with getting ID node from the graph. */
IDNode *target_id_node = graph->find_id_node(id);
- if (target_id_node == NULL) {
+ if (target_id_node == nullptr) {
/* TODO(sergey): Shall we inform or assert here about attempt to start
* iterating over non-existing ID? */
return;
@@ -210,7 +211,7 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
{
/* Start with getting ID node from the graph. */
IDNode *target_id_node = graph->find_id_node(id);
- if (target_id_node == NULL) {
+ if (target_id_node == nullptr) {
/* TODO(sergey): Shall we inform or assert here about attempt to start
* iterating over non-existing ID? */
return;
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index db469612f76..90ab7565f4a 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -67,7 +67,7 @@ namespace {
void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
{
#ifdef INVALIDATE_WORK_DATA
- BLI_assert(data != NULL);
+ BLI_assert(data != nullptr);
memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
#else
(void)data;
@@ -76,14 +76,14 @@ void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
void verify_id_properties_freed(DEGObjectIterData *data)
{
- if (data->dupli_object_current == NULL) {
+ if (data->dupli_object_current == nullptr) {
// We didn't enter duplication yet, so we can't have any dangling
// pointers.
return;
}
const Object *dupli_object = data->dupli_object_current->ob;
Object *temp_dupli_object = &data->temp_dupli_object;
- if (temp_dupli_object->id.properties == NULL) {
+ if (temp_dupli_object->id.properties == nullptr) {
// No ID properties in temp datablock -- no leak is possible.
return;
}
@@ -94,7 +94,7 @@ void verify_id_properties_freed(DEGObjectIterData *data)
// Free memory which is owned by temporary storage which is about to
// get overwritten.
IDP_FreeProperty(temp_dupli_object->id.properties);
- temp_dupli_object->id.properties = NULL;
+ temp_dupli_object->id.properties = nullptr;
}
static bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject *dob)
@@ -120,7 +120,7 @@ static bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, Dupl
bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
{
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
- while (data->dupli_object_next != NULL) {
+ while (data->dupli_object_next != nullptr) {
DupliObject *dob = data->dupli_object_next;
Object *obd = dob->ob;
@@ -215,7 +215,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, NULL)) {
+ if (deg_object_hide_original(data->eval_mode, object, nullptr)) {
return;
}
}
@@ -249,10 +249,10 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
return;
}
- data->dupli_parent = NULL;
- data->dupli_list = NULL;
- data->dupli_object_next = NULL;
- data->dupli_object_current = NULL;
+ data->dupli_parent = nullptr;
+ data->dupli_list = nullptr;
+ data->dupli_object_next = nullptr;
+ data->dupli_object_current = nullptr;
data->scene = DEG_get_evaluated_scene(depsgraph);
data->id_node_index = 0;
data->num_id_nodes = num_id_nodes;
@@ -281,10 +281,10 @@ void DEG_iterator_objects_next(BLI_Iterator *iter)
else {
verify_id_properties_freed(data);
free_object_duplilist(data->dupli_list);
- data->dupli_parent = NULL;
- data->dupli_list = NULL;
- data->dupli_object_next = NULL;
- data->dupli_object_current = NULL;
+ data->dupli_parent = nullptr;
+ data->dupli_list = nullptr;
+ data->dupli_object_next = nullptr;
+ data->dupli_object_current = nullptr;
deg_invalidate_iterator_work_data(data);
}
}
@@ -303,7 +303,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter)
void DEG_iterator_objects_end(BLI_Iterator *iter)
{
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
- if (data != NULL) {
+ if (data != nullptr) {
/* Force crash in case the iterator data is referenced and accessed down
* the line. (T51718) */
deg_invalidate_iterator_work_data(data);
diff --git a/source/blender/depsgraph/intern/depsgraph_relation.cc b/source/blender/depsgraph/intern/depsgraph_relation.cc
new file mode 100644
index 00000000000..1b2de2cc807
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_relation.cc
@@ -0,0 +1,73 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/depsgraph_relation.h" /* own include */
+
+#include "BLI_utildefines.h"
+
+#include "intern/depsgraph_type.h"
+#include "intern/node/deg_node.h"
+
+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)
+{
+ /* Hook it up to the nodes which use it.
+ *
+ * NOTE: We register relation in the nodes which this link connects to here
+ * in constructor but we don't unregister it in the destructor.
+ *
+ * Reasoning:
+ *
+ * - Destructor is currently used on global graph destruction, so there's no
+ * real need in avoiding dangling pointers, all the memory is to be freed
+ * anyway.
+ *
+ * - Unregistering 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);
+}
+
+Relation::~Relation()
+{
+ /* Sanity check. */
+ BLI_assert(from != nullptr && to != nullptr);
+}
+
+void Relation::unlink()
+{
+ /* Sanity check. */
+ BLI_assert(from != nullptr && to != nullptr);
+ remove_from_vector(&from->outlinks, this);
+ remove_from_vector(&to->inlinks, this);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_relation.h b/source/blender/depsgraph/intern/depsgraph_relation.h
new file mode 100644
index 00000000000..2f9f0249b1f
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_relation.h
@@ -0,0 +1,63 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+namespace DEG {
+
+struct Node;
+
+/* Settings/Tags on Relationship.
+ * NOTE: Is a bitmask, allowing accumulation. */
+enum RelationFlag {
+ /* "cyclic" link - when detecting cycles, this relationship was the one
+ * which triggers a cyclic relationship to exist in the graph. */
+ RELATION_FLAG_CYCLIC = (1 << 0),
+ /* Update flush will not go through this relation. */
+ RELATION_FLAG_NO_FLUSH = (1 << 1),
+ /* Only flush along the relation is update comes from a node which was
+ * affected by user input. */
+ RELATION_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2),
+ /* The relation can not be killed by the cyclic dependencies solver. */
+ RELATION_FLAG_GODMODE = (1 << 4),
+ /* Relation will check existence before being added. */
+ RELATION_CHECK_BEFORE_ADD = (1 << 5),
+};
+
+/* B depends on A (A -> B) */
+struct Relation {
+ Relation(Node *from, Node *to, const char *description);
+ ~Relation();
+
+ void unlink();
+
+ /* the nodes in the relationship (since this is shared between the nodes) */
+ Node *from; /* A */
+ Node *to; /* B */
+
+ /* relationship attributes */
+ const char *name; /* label for debugging */
+ int flag; /* Bitmask of RelationFlag) */
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index ce5917110d6..b019c079dab 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -246,7 +246,7 @@ void id_tag_update_ntree_special(
Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source)
{
bNodeTree *ntree = ntreeFromID(id);
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
graph_id_tag_update(bmain, graph, &ntree->id, flag, update_source);
@@ -257,7 +257,7 @@ void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id)
/* NOTE: We handle this immediately, without delaying anything, to be
* sure we don't cause threading issues with OpenGL. */
/* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */
- DEGEditorUpdateContext update_ctx = {NULL};
+ DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
update_ctx.depsgraph = (::Depsgraph *)graph;
update_ctx.scene = graph->scene;
@@ -281,7 +281,7 @@ void depsgraph_tag_component(Depsgraph *graph,
/* NOTE: Animation component might not be existing yet (which happens when adding new driver or
* adding a new keyframe), so the required copy-on-write tag needs to be taken care explicitly
* here. */
- if (component_node == NULL) {
+ if (component_node == nullptr) {
if (component_type == NodeType::ANIMATION) {
depsgraph_id_tag_copy_on_write(graph, id_node, update_source);
}
@@ -292,7 +292,7 @@ void depsgraph_tag_component(Depsgraph *graph,
}
else {
OperationNode *operation_node = component_node->find_operation(operation_code);
- if (operation_node != NULL) {
+ if (operation_node != nullptr) {
operation_node->tag_update(graph, update_source);
}
}
@@ -315,7 +315,7 @@ void deg_graph_id_tag_legacy_compat(
case ID_OB: {
Object *object = (Object *)id;
ID *data_id = (ID *)object->data;
- if (data_id != NULL) {
+ if (data_id != nullptr) {
graph_id_tag_update(bmain, depsgraph, data_id, 0, update_source);
}
break;
@@ -325,9 +325,9 @@ void deg_graph_id_tag_legacy_compat(
* tagging here. */
case ID_ME: {
Mesh *mesh = (Mesh *)id;
- if (mesh->key != NULL) {
+ if (mesh->key != nullptr) {
ID *key_id = &mesh->key->id;
- if (key_id != NULL) {
+ if (key_id != nullptr) {
graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source);
}
}
@@ -335,9 +335,9 @@ void deg_graph_id_tag_legacy_compat(
}
case ID_LT: {
Lattice *lattice = (Lattice *)id;
- if (lattice->key != NULL) {
+ if (lattice->key != nullptr) {
ID *key_id = &lattice->key->id;
- if (key_id != NULL) {
+ if (key_id != nullptr) {
graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source);
}
}
@@ -345,9 +345,9 @@ void deg_graph_id_tag_legacy_compat(
}
case ID_CU: {
Curve *curve = (Curve *)id;
- if (curve->key != NULL) {
+ if (curve->key != nullptr) {
ID *key_id = &curve->key->id;
- if (key_id != NULL) {
+ if (key_id != nullptr) {
graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source);
}
}
@@ -367,13 +367,13 @@ static void graph_id_tag_update_single_flag(Main *bmain,
eUpdateSource update_source)
{
if (tag == ID_RECALC_EDITORS) {
- if (graph != NULL && graph->is_active) {
+ if (graph != nullptr && graph->is_active) {
depsgraph_update_editors_tag(bmain, graph, id);
}
return;
}
else if (tag == ID_RECALC_TIME) {
- if (graph != NULL) {
+ if (graph != nullptr) {
graph->need_update_time = true;
}
return;
@@ -389,14 +389,14 @@ static void graph_id_tag_update_single_flag(Main *bmain,
return;
}
/* Some sanity checks before moving forward. */
- if (id_node == NULL) {
+ if (id_node == nullptr) {
/* Happens when object is tagged for update and not yet in the
* dependency graph (but will be after relations update). */
return;
}
/* Tag ID recalc flag. */
DepsNodeFactory *factory = type_get_factory(component_type);
- BLI_assert(factory != NULL);
+ BLI_assert(factory != nullptr);
id_node->id_cow->recalc |= factory->id_recalc_tag();
/* Tag corresponding dependency graph operation for update. */
if (component_type == NodeType::ID_REF) {
@@ -413,7 +413,7 @@ static void graph_id_tag_update_single_flag(Main *bmain,
string stringify_append_bit(const string &str, IDRecalcFlag tag)
{
const char *tag_name = DEG_update_tag_as_string(tag);
- if (tag_name == NULL) {
+ if (tag_name == nullptr) {
return str;
}
string result = str;
@@ -468,7 +468,7 @@ int deg_recalc_flags_for_legacy_zero()
int deg_recalc_flags_effective(Depsgraph *graph, int flags)
{
- if (graph != NULL) {
+ if (graph != nullptr) {
if (!graph->is_active) {
return 0;
}
@@ -489,7 +489,7 @@ void deg_graph_node_tag_zero(Main *bmain,
IDNode *id_node,
eUpdateSource update_source)
{
- if (id_node == NULL) {
+ if (id_node == nullptr) {
return;
}
ID *id = id_node->id_orig;
@@ -514,7 +514,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti
const ID_Type id_type = GS(id_node->id_orig->name);
if (id_type == ID_OB) {
Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig);
- if (object_orig->proxy != NULL) {
+ if (object_orig->proxy != nullptr) {
object_orig->proxy->proxy_from = object_orig;
}
}
@@ -528,7 +528,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti
if (!DEG::deg_copy_on_write_is_expanded(id_node->id_cow)) {
flag |= ID_RECALC_COPY_ON_WRITE;
if (do_time) {
- if (BKE_animdata_from_id(id_node->id_orig) != NULL) {
+ if (BKE_animdata_from_id(id_node->id_orig) != nullptr) {
flag |= ID_RECALC_ANIMATION;
}
}
@@ -612,7 +612,7 @@ NodeType geometry_tag_to_component(const ID *id)
void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source)
{
- graph_id_tag_update(bmain, NULL, id, flag, update_source);
+ graph_id_tag_update(bmain, nullptr, id, flag, update_source);
for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
graph_id_tag_update(bmain, depsgraph, id, flag, update_source);
}
@@ -621,8 +621,8 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source)
void graph_id_tag_update(
Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source)
{
- const int debug_flags = (graph != NULL) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug;
- if (graph != NULL && graph->is_evaluating) {
+ const int debug_flags = (graph != nullptr) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug;
+ if (graph != nullptr && graph->is_evaluating) {
if (debug_flags & G_DEBUG_DEPSGRAPH) {
printf("ID tagged for update during dependency graph evaluation.");
}
@@ -635,8 +635,8 @@ void graph_id_tag_update(
stringify_update_bitfield(flag).c_str(),
update_source_as_string(update_source));
}
- IDNode *id_node = (graph != NULL) ? graph->find_id_node(id) : NULL;
- if (graph != NULL) {
+ IDNode *id_node = (graph != nullptr) ? graph->find_id_node(id) : nullptr;
+ if (graph != nullptr) {
DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(graph), GS(id->name));
}
if (flag == 0) {
@@ -644,7 +644,7 @@ void graph_id_tag_update(
}
/* Store original flag in the ID.
* Allows to have more granularity than a node-factory based flags. */
- if (id_node != NULL) {
+ if (id_node != nullptr) {
id_node->id_cow->recalc |= flag;
}
/* When ID is tagged for update based on an user edits store the recalc flags in the original ID.
@@ -730,7 +730,7 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
case ID_RECALC_ALL:
return "ALL";
}
- return NULL;
+ return nullptr;
}
/* Data-Based Tagging */
@@ -743,7 +743,7 @@ void DEG_id_tag_update(ID *id, int flag)
void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag)
{
- if (id == NULL) {
+ if (id == nullptr) {
/* Ideally should not happen, but old depsgraph allowed this. */
return;
}
@@ -804,7 +804,7 @@ void DEG_ids_check_recalc(
{
bool updated = time || DEG_id_type_any_updated(depsgraph);
- DEGEditorUpdateContext update_ctx = {NULL};
+ DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
update_ctx.depsgraph = depsgraph;
update_ctx.scene = scene;
diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc
index ed4ec592fc7..d10bfaaace8 100644
--- a/source/blender/depsgraph/intern/depsgraph_update.cc
+++ b/source/blender/depsgraph/intern/depsgraph_update.cc
@@ -29,19 +29,19 @@
namespace DEG {
-static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
-static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
+static DEG_EditorUpdateIDCb deg_editor_update_id_cb = nullptr;
+static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = nullptr;
void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id)
{
- if (deg_editor_update_id_cb != NULL) {
+ if (deg_editor_update_id_cb != nullptr) {
deg_editor_update_id_cb(update_ctx, id);
}
}
void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated)
{
- if (deg_editor_update_scene_cb != NULL) {
+ if (deg_editor_update_scene_cb != nullptr) {
deg_editor_update_scene_cb(update_ctx, updated);
}
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index d6b3c54a149..df61a1416bd 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
#include "BKE_global.h"
@@ -51,47 +52,86 @@
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
namespace DEG {
-/* ********************** */
-/* Evaluation Entrypoints */
+namespace {
-/* Forward declarations. */
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationNode *node,
- const int thread_id);
+struct DepsgraphEvalState;
+
+void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id);
+
+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)
+{
+ BLI_task_pool_push_from_thread(
+ pool, deg_task_run_func, node, false, TASK_PRIORITY_HIGH, thread_id);
+}
+
+/* Denotes which part of dependency graph is being evaluated. */
+enum class EvaluationStage {
+ /* Stage 1: Only Copy-on-Write operations are to be evaluated, prior to anything else.
+ * This allows other operations to access its dependencies when there is a dependency cycle
+ * involved. */
+ COPY_ON_WRITE,
+
+ /* Threaded evaluation of all possible operations. */
+ THREADED_EVALUATION,
+
+ /* Workaround for areas which can not be evaluated in threads.
+ *
+ * For example, metaballs, which are iterating over all bases and are requesting dupli-lists
+ * to see whether there are metaballs inside. */
+ SINGLE_THREADED_WORKAROUND,
+};
struct DepsgraphEvalState {
Depsgraph *graph;
bool do_stats;
- bool is_cow_stage;
+ EvaluationStage stage;
+ bool need_single_thread_pass;
};
-static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
+void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_node)
{
- void *userdata_v = BLI_task_pool_userdata(pool);
- DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v;
- OperationNode *node = (OperationNode *)taskdata;
+ ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(state->graph);
+
/* Sanity checks. */
- BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
+ BLI_assert(!operation_node->is_noop() && "NOOP nodes should not actually be scheduled");
/* Perform operation. */
if (state->do_stats) {
const double start_time = PIL_check_seconds_timer();
- node->evaluate((::Depsgraph *)state->graph);
- node->stats.current_time += PIL_check_seconds_timer() - start_time;
+ operation_node->evaluate(depsgraph);
+ operation_node->stats.current_time += PIL_check_seconds_timer() - start_time;
}
else {
- node->evaluate((::Depsgraph *)state->graph);
+ operation_node->evaluate(depsgraph);
}
+}
+
+void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
+{
+ void *userdata_v = BLI_task_pool_userdata(pool);
+ DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v;
+
+ /* Evaluate node. */
+ OperationNode *operation_node = reinterpret_cast<OperationNode *>(taskdata);
+ evaluate_node(state, operation_node);
+
/* Schedule children. */
BLI_task_pool_delayed_push_begin(pool, thread_id);
- schedule_children(pool, state->graph, node, thread_id);
+ schedule_children(state, operation_node, thread_id, schedule_node_to_pool, pool);
BLI_task_pool_delayed_push_end(pool, thread_id);
}
-static bool check_operation_node_visible(OperationNode *op_node)
+bool check_operation_node_visible(OperationNode *op_node)
{
const ComponentNode *comp_node = op_node->owner;
/* Special exception, copy on write component is to be always evaluated,
@@ -102,7 +142,7 @@ static bool check_operation_node_visible(OperationNode *op_node)
return comp_node->affects_directly_visible;
}
-static void calculate_pending_parents_for_node(OperationNode *node)
+void calculate_pending_parents_for_node(OperationNode *node)
{
/* Update counters, applies for both visible and invisible IDs. */
node->num_links_pending = 0;
@@ -134,14 +174,14 @@ static void calculate_pending_parents_for_node(OperationNode *node)
}
}
-static void calculate_pending_parents(Depsgraph *graph)
+void calculate_pending_parents(Depsgraph *graph)
{
for (OperationNode *node : graph->operations) {
calculate_pending_parents_for_node(node);
}
}
-static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
+void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
{
const bool do_stats = state->do_stats;
calculate_pending_parents(graph);
@@ -153,12 +193,54 @@ static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
}
}
+bool is_metaball_object_operation(const OperationNode *operation_node)
+{
+ const ComponentNode *component_node = operation_node->owner;
+ const IDNode *id_node = component_node->owner;
+ if (GS(id_node->id_cow->name) != ID_OB) {
+ return false;
+ }
+ const Object *object = reinterpret_cast<const Object *>(id_node->id_cow);
+ return object->type == OB_MBALL;
+}
+
+bool need_evaluate_operation_at_stage(DepsgraphEvalState *state,
+ const OperationNode *operation_node)
+{
+ const ComponentNode *component_node = operation_node->owner;
+ switch (state->stage) {
+ case EvaluationStage::COPY_ON_WRITE:
+ return (component_node->type == NodeType::COPY_ON_WRITE);
+
+ case EvaluationStage::THREADED_EVALUATION:
+ /* Sanity check: copy-on-write node should be evaluated already. This will be indicated by
+ * scheduled flag (we assume that scheduled operations have been actually handled by previous
+ * stage). */
+ BLI_assert(operation_node->scheduled || component_node->type != NodeType::COPY_ON_WRITE);
+ if (is_metaball_object_operation(operation_node)) {
+ state->need_single_thread_pass = true;
+ return false;
+ }
+ return true;
+
+ case EvaluationStage::SINGLE_THREADED_WORKAROUND:
+ return true;
+ }
+ BLI_assert(!"Unhandled evaluation stage, should never happen.");
+ return false;
+}
+
/* Schedule a node if it needs evaluation.
* dec_parents: Decrement pending parents count, true when child nodes are
* scheduled after a task has been completed.
*/
-static void schedule_node(
- TaskPool *pool, Depsgraph *graph, OperationNode *node, bool dec_parents, const int thread_id)
+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)
{
/* No need to schedule nodes of invisible ID. */
if (!check_operation_node_visible(node)) {
@@ -181,41 +263,39 @@ static void schedule_node(
return;
}
/* During the COW stage only schedule COW nodes. */
- DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
- if (state->is_cow_stage) {
- if (node->owner->type != NodeType::COPY_ON_WRITE) {
- return;
- }
- }
- else {
- BLI_assert(node->scheduled || node->owner->type != NodeType::COPY_ON_WRITE);
+ if (!need_evaluate_operation_at_stage(state, node)) {
+ return;
}
/* Actually schedule the node. */
bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t) true);
if (!is_scheduled) {
if (node->is_noop()) {
/* skip NOOP node, schedule children right away */
- schedule_children(pool, graph, node, thread_id);
+ schedule_children(state, node, thread_id, schedule_function, schedule_function_args...);
}
else {
/* children are scheduled once this task is completed */
- BLI_task_pool_push_from_thread(
- pool, deg_task_run_func, node, false, TASK_PRIORITY_HIGH, thread_id);
+ schedule_function(node, thread_id, schedule_function_args...);
}
}
}
-static void schedule_graph(TaskPool *pool, Depsgraph *graph)
+template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
+void schedule_graph(DepsgraphEvalState *state,
+ ScheduleFunction *schedule_function,
+ ScheduleFunctionArgs... schedule_function_args)
{
- for (OperationNode *node : graph->operations) {
- schedule_node(pool, graph, node, false, -1);
+ for (OperationNode *node : state->graph->operations) {
+ schedule_node(state, node, false, -1, schedule_function, schedule_function_args...);
}
}
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationNode *node,
- const int thread_id)
+template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
+void schedule_children(DepsgraphEvalState *state,
+ OperationNode *node,
+ const int thread_id,
+ ScheduleFunction *schedule_function,
+ ScheduleFunctionArgs... schedule_function_args)
{
for (Relation *rel : node->outlinks) {
OperationNode *child = (OperationNode *)rel->to;
@@ -224,11 +304,39 @@ static void schedule_children(TaskPool *pool,
/* Happens when having cyclic dependencies. */
continue;
}
- schedule_node(pool, graph, child, (rel->flag & RELATION_FLAG_CYCLIC) == 0, thread_id);
+ schedule_node(state,
+ child,
+ (rel->flag & RELATION_FLAG_CYCLIC) == 0,
+ thread_id,
+ schedule_function,
+ schedule_function_args...);
+ }
+}
+
+void schedule_node_to_queue(OperationNode *node,
+ const int /*thread_id*/,
+ GSQueue *evaluation_queue)
+{
+ BLI_gsqueue_push(evaluation_queue, &node);
+}
+
+void evaluate_graph_single_threaded(DepsgraphEvalState *state)
+{
+ GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *));
+ schedule_graph(state, schedule_node_to_queue, evaluation_queue);
+
+ while (!BLI_gsqueue_is_empty(evaluation_queue)) {
+ OperationNode *operation_node;
+ BLI_gsqueue_pop(evaluation_queue, &operation_node);
+
+ evaluate_node(state, operation_node);
+ schedule_children(state, operation_node, 0, schedule_node_to_queue, evaluation_queue);
}
+
+ BLI_gsqueue_free(evaluation_queue);
}
-static void depsgraph_ensure_view_layer(Depsgraph *graph)
+void depsgraph_ensure_view_layer(Depsgraph *graph)
{
/* We update copy-on-write scene in the following cases:
* - It was not expanded yet.
@@ -242,6 +350,8 @@ static void depsgraph_ensure_view_layer(Depsgraph *graph)
}
}
+} // namespace
+
/**
* Evaluate all nodes tagged for updating,
* \warning This is usually done as part of main loop, but may also be
@@ -255,14 +365,16 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
if (BLI_gset_len(graph->entry_tags) == 0) {
return;
}
- const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
- const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0;
+
+ graph->debug.begin_graph_evaluation();
+
graph->is_evaluating = true;
depsgraph_ensure_view_layer(graph);
/* Set up evaluation state. */
DepsgraphEvalState state;
state.graph = graph;
- state.do_stats = do_time_debug;
+ 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;
@@ -277,16 +389,25 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
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.is_cow_stage = true;
- schedule_graph(task_pool, graph);
+ state.stage = EvaluationStage::COPY_ON_WRITE;
+ schedule_graph(&state, schedule_node_to_pool, task_pool);
BLI_task_pool_work_wait_and_reset(task_pool);
+
/* After that, process all other nodes. */
- state.is_cow_stage = false;
- schedule_graph(task_pool, graph);
+ state.stage = EvaluationStage::THREADED_EVALUATION;
+ schedule_graph(&state, schedule_node_to_pool, task_pool);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
+
+ if (state.need_single_thread_pass) {
+ state.stage = EvaluationStage::SINGLE_THREADED_WORKAROUND;
+ evaluate_graph_single_threaded(&state);
+ }
+
/* Finalize statistics gathering. This is because we only gather single
* operation timing here, without aggregating anything to avoid any extra
* synchronization. */
@@ -299,9 +420,8 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
BLI_task_scheduler_free(task_scheduler);
}
graph->is_evaluating = false;
- if (do_time_debug) {
- printf("Depsgraph updated in %f seconds.\n", PIL_check_seconds_timer() - start_time);
- }
+
+ graph->debug.end_graph_evaluation();
}
} // namespace DEG
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 3a2cf35f4d5..b74e5715e14 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
@@ -120,13 +120,13 @@ union NestedIDHackTempStorage {
World world;
};
-/* Set nested owned ID pointers to NULL. */
+/* Set nested owned ID pointers to nullptr. */
void nested_id_hack_discard_pointers(ID *id_cow)
{
switch (GS(id_cow->name)) {
# define SPECIAL_CASE(id_type, dna_type, field) \
case id_type: { \
- ((dna_type *)id_cow)->field = NULL; \
+ ((dna_type *)id_cow)->field = nullptr; \
break; \
}
@@ -144,9 +144,9 @@ void nested_id_hack_discard_pointers(ID *id_cow)
Scene *scene_cow = (Scene *)id_cow;
/* Node trees always have their own ID node in the graph, and are
* being copied as part of their copy-on-write process. */
- scene_cow->nodetree = NULL;
+ scene_cow->nodetree = nullptr;
/* Tool settings pointer is shared with the original scene. */
- scene_cow->toolsettings = NULL;
+ scene_cow->toolsettings = nullptr;
break;
}
@@ -154,7 +154,7 @@ void nested_id_hack_discard_pointers(ID *id_cow)
/* Clear the ParticleSettings pointer to prevent doubly-freeing it. */
Object *ob = (Object *)id_cow;
LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
- psys->part = NULL;
+ psys->part = nullptr;
}
break;
}
@@ -165,7 +165,7 @@ void nested_id_hack_discard_pointers(ID *id_cow)
}
}
-/* Set ID pointer of nested owned IDs (nodetree, key) to NULL.
+/* Set ID pointer of nested owned IDs (nodetree, key) to nullptr.
*
* Return pointer to a new ID to be used. */
const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage, const ID *id)
@@ -174,7 +174,7 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage
# define SPECIAL_CASE(id_type, dna_type, field, variable) \
case id_type: { \
storage->variable = *(dna_type *)id; \
- storage->variable.field = NULL; \
+ storage->variable.field = nullptr; \
return &storage->variable.id; \
}
@@ -190,8 +190,8 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage
case ID_SCE: {
storage->scene = *(Scene *)id;
- storage->scene.toolsettings = NULL;
- storage->scene.nodetree = NULL;
+ storage->scene.toolsettings = nullptr;
+ storage->scene.nodetree = nullptr;
return &storage->scene.id;
}
@@ -206,7 +206,7 @@ const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage
/* Set ID pointer of nested owned IDs (nodetree, key) to the original value. */
void nested_id_hack_restore_pointers(const ID *old_id, ID *new_id)
{
- if (new_id == NULL) {
+ if (new_id == nullptr) {
return;
}
switch (GS(old_id->name)) {
@@ -240,9 +240,9 @@ void ntree_hack_remap_pointers(const Depsgraph *depsgraph, ID *id_cow)
# define SPECIAL_CASE(id_type, dna_type, field, field_type) \
case id_type: { \
dna_type *data = (dna_type *)id_cow; \
- if (data->field != NULL) { \
+ if (data->field != nullptr) { \
ID *ntree_id_cow = depsgraph->get_cow_id(&data->field->id); \
- if (ntree_id_cow != NULL) { \
+ if (ntree_id_cow != nullptr) { \
DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n", \
data->field->id.name, \
data->field, \
@@ -287,7 +287,7 @@ bool id_copy_inplace_no_main(const ID *id, ID *newid)
#endif
bool result = BKE_id_copy_ex(
- NULL, (ID *)id_for_copy, &newid, (LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE));
+ nullptr, (ID *)id_for_copy, &newid, (LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE));
#ifdef NESTED_ID_NASTY_WORKAROUND
if (result) {
@@ -310,7 +310,7 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
#endif
bool result = BKE_id_copy_ex(
- NULL, id_for_copy, (ID **)&new_scene, LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE);
+ nullptr, id_for_copy, (ID **)&new_scene, LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE);
#ifdef NESTED_ID_NASTY_WORKAROUND
if (result) {
@@ -339,7 +339,7 @@ ViewLayer *get_original_view_layer(const Depsgraph *depsgraph, const IDNode *id_
* properly fixed.
*
* TODO(sergey): Support indirectly linked scene. */
- return NULL;
+ return nullptr;
}
/* Remove all view layers but the one which corresponds to an input one. */
@@ -359,27 +359,27 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph,
* NOTE: Need to keep view layers for all scenes, even indirect ones. This is because of
* render layer node possibly pointing to another scene. */
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene_cow->view_layers) {
- view_layer->basact = NULL;
+ view_layer->basact = nullptr;
}
return;
}
else if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) {
/* Indirectly linked scenes means it's not an input scene and not a set scene, and is pulled
* via some driver. Such scenes should not have view layers after copy. */
- view_layer_input = NULL;
+ view_layer_input = nullptr;
}
else {
view_layer_input = get_original_view_layer(depsgraph, id_node);
}
- ViewLayer *view_layer_eval = NULL;
+ ViewLayer *view_layer_eval = nullptr;
/* Find evaluated view layer. At the same time we free memory used by
* all other of the view layers. */
for (ViewLayer *view_layer_cow = reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first),
*view_layer_next;
- view_layer_cow != NULL;
+ view_layer_cow != nullptr;
view_layer_cow = view_layer_next) {
view_layer_next = view_layer_cow->next;
- if (view_layer_input != NULL && STREQ(view_layer_input->name, view_layer_cow->name)) {
+ if (view_layer_input != nullptr && STREQ(view_layer_input->name, view_layer_cow->name)) {
view_layer_eval = view_layer_cow;
}
else {
@@ -387,8 +387,8 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph,
}
}
/* Make evaluated view layer the only one in the evaluated scene (if it exists). */
- if (view_layer_eval != NULL) {
- view_layer_eval->prev = view_layer_eval->next = NULL;
+ if (view_layer_eval != nullptr) {
+ view_layer_eval->prev = view_layer_eval->next = nullptr;
}
scene_cow->view_layers.first = view_layer_eval;
scene_cow->view_layers.last = view_layer_eval;
@@ -405,10 +405,10 @@ void scene_remove_all_bases(Scene *scene_cow)
* objects. */
void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *view_layer)
{
- if (view_layer == NULL) {
+ if (view_layer == nullptr) {
return;
}
- ListBase enabled_bases = {NULL, NULL};
+ ListBase enabled_bases = {nullptr, nullptr};
LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) {
/* TODO(sergey): Would be cool to optimize this somehow, or make it so
* builder tags bases.
@@ -427,7 +427,7 @@ void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *vie
}
else {
if (base == view_layer->basact) {
- view_layer->basact = NULL;
+ view_layer->basact = nullptr;
}
MEM_freeN(base);
}
@@ -438,7 +438,7 @@ void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *vie
void view_layer_update_orig_base_pointers(const ViewLayer *view_layer_orig,
ViewLayer *view_layer_eval)
{
- if (view_layer_orig == NULL || view_layer_eval == NULL) {
+ if (view_layer_orig == nullptr || view_layer_eval == nullptr) {
/* Happens when scene is only used for parameters or compositor/sequencer. */
return;
}
@@ -478,7 +478,7 @@ void update_sequence_orig_pointers(const ListBase *sequences_orig, ListBase *seq
{
Sequence *sequence_orig = reinterpret_cast<Sequence *>(sequences_orig->first);
Sequence *sequence_cow = reinterpret_cast<Sequence *>(sequences_cow->first);
- while (sequence_orig != NULL) {
+ while (sequence_orig != nullptr) {
update_sequence_orig_pointers(&sequence_orig->seqbase, &sequence_cow->seqbase);
sequence_cow->orig_sequence = sequence_orig;
sequence_cow = sequence_cow->next;
@@ -488,7 +488,7 @@ void update_sequence_orig_pointers(const ListBase *sequences_orig, ListBase *seq
void update_scene_orig_pointers(const Scene *scene_orig, Scene *scene_cow)
{
- if (scene_orig->ed != NULL) {
+ if (scene_orig->ed != nullptr) {
update_sequence_orig_pointers(&scene_orig->ed->seqbase, &scene_cow->ed->seqbase);
}
}
@@ -499,21 +499,6 @@ BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
return (id_cow->name[0] != '\0');
}
-/* Those are data-blocks which are not covered by dependency graph and hence
- * does not need any remapping or anything.
- *
- * TODO(sergey): How to make it more robust for the future, so we don't have
- * to maintain exception lists all over the code? */
-bool check_datablocks_copy_on_writable(const ID *id_orig)
-{
- const ID_Type id_type = GS(id_orig->name);
- /* We shouldn't bother if copied ID is same as original one. */
- if (!deg_copy_on_write_is_needed(id_orig)) {
- return false;
- }
- return !ELEM(id_type, ID_BR, ID_LS, ID_PAL);
-}
-
/* Callback for BKE_library_foreach_ID_link which remaps original ID pointer
* with the one created by CoW system. */
@@ -530,13 +515,13 @@ struct RemapCallbackUserData {
int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, int /*cb_flag*/)
{
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
RemapCallbackUserData *user_data = (RemapCallbackUserData *)user_data_v;
const Depsgraph *depsgraph = user_data->depsgraph;
ID *id_orig = *id_p;
- if (check_datablocks_copy_on_writable(id_orig)) {
+ if (deg_copy_on_write_is_needed(id_orig)) {
ID *id_cow;
if (user_data->create_placeholders) {
/* Special workaround to stop creating temp datablocks for
@@ -550,7 +535,7 @@ int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, i
const ID_Type id_type_self = GS(id_self->name);
if (id_type == ID_OB && id_type_self == ID_SCE) {
IDNode *id_node = depsgraph->find_id_node(id_orig);
- if (id_node == NULL) {
+ if (id_node == nullptr) {
id_cow = id_orig;
}
else {
@@ -564,7 +549,7 @@ int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, i
else {
id_cow = depsgraph->get_cow_id(id_orig);
}
- BLI_assert(id_cow != NULL);
+ BLI_assert(id_cow != nullptr);
DEG_COW_PRINT(
" Remapping datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
*id_p = id_cow;
@@ -610,7 +595,7 @@ void update_lattice_edit_mode_pointers(const Depsgraph * /*depsgraph*/,
lt_cow->editlatt = lt_orig->editlatt;
}
-void update_mesh_edit_mode_pointers(const Depsgraph *depsgraph, const ID *id_orig, ID *id_cow)
+void update_mesh_edit_mode_pointers(const ID *id_orig, ID *id_cow)
{
/* For meshes we need to update edit_mesh to make it to point
* to the CoW version of object.
@@ -620,13 +605,12 @@ void update_mesh_edit_mode_pointers(const Depsgraph *depsgraph, const ID *id_ori
* edit_mesh to object. */
const Mesh *mesh_orig = (const Mesh *)id_orig;
Mesh *mesh_cow = (Mesh *)id_cow;
- if (mesh_orig->edit_mesh == NULL) {
+ if (mesh_orig->edit_mesh == nullptr) {
return;
}
mesh_cow->edit_mesh = (BMEditMesh *)MEM_dupallocN(mesh_orig->edit_mesh);
- mesh_cow->edit_mesh->ob = (Object *)depsgraph->get_cow_id(&mesh_orig->edit_mesh->ob->id);
- mesh_cow->edit_mesh->mesh_eval_cage = NULL;
- mesh_cow->edit_mesh->mesh_eval_final = NULL;
+ mesh_cow->edit_mesh->mesh_eval_cage = nullptr;
+ mesh_cow->edit_mesh->mesh_eval_final = nullptr;
}
/* Edit data is stored and owned by original datablocks, copied ones
@@ -639,7 +623,7 @@ void update_edit_mode_pointers(const Depsgraph *depsgraph, const ID *id_orig, ID
update_armature_edit_mode_pointers(depsgraph, id_orig, id_cow);
break;
case ID_ME:
- update_mesh_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ update_mesh_edit_mode_pointers(id_orig, id_cow);
break;
case ID_CU:
update_curve_edit_mode_pointers(depsgraph, id_orig, id_cow);
@@ -662,7 +646,7 @@ void update_list_orig_pointers(const ListBase *listbase_orig,
{
T *element_orig = reinterpret_cast<T *>(listbase_orig->first);
T *element_cow = reinterpret_cast<T *>(listbase->first);
- while (element_orig != NULL) {
+ while (element_orig != nullptr) {
element_cow->*orig_field = element_orig;
element_cow = element_cow->next;
element_orig = element_orig->next;
@@ -695,9 +679,9 @@ void reset_particle_system_edit_eval(const Depsgraph *depsgraph, Object *object_
}
LISTBASE_FOREACH (ParticleSystem *, psys, &object_cow->particlesystem) {
ParticleSystem *orig_psys = psys->orig_psys;
- if (orig_psys->edit != NULL) {
- orig_psys->edit->psys_eval = NULL;
- orig_psys->edit->psmd_eval = NULL;
+ if (orig_psys->edit != nullptr) {
+ orig_psys->edit->psys_eval = nullptr;
+ orig_psys->edit->psmd_eval = nullptr;
}
}
}
@@ -726,7 +710,7 @@ void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *stri
{
NlaStrip *strip_orig = reinterpret_cast<NlaStrip *>(strips_orig->first);
NlaStrip *strip_cow = reinterpret_cast<NlaStrip *>(strips_cow->first);
- while (strip_orig != NULL) {
+ while (strip_orig != nullptr) {
strip_cow->orig_strip = strip_orig;
update_nla_strips_orig_pointers(&strip_orig->strips, &strip_cow->strips);
strip_cow = strip_cow->next;
@@ -738,7 +722,7 @@ void update_nla_tracks_orig_pointers(const ListBase *tracks_orig, ListBase *trac
{
NlaTrack *track_orig = reinterpret_cast<NlaTrack *>(tracks_orig->first);
NlaTrack *track_cow = reinterpret_cast<NlaTrack *>(tracks_cow->first);
- while (track_orig != NULL) {
+ while (track_orig != nullptr) {
update_nla_strips_orig_pointers(&track_orig->strips, &track_cow->strips);
track_cow = track_cow->next;
track_orig = track_orig->next;
@@ -748,29 +732,29 @@ void update_nla_tracks_orig_pointers(const ListBase *tracks_orig, ListBase *trac
void update_animation_data_after_copy(const ID *id_orig, ID *id_cow)
{
const AnimData *anim_data_orig = BKE_animdata_from_id(const_cast<ID *>(id_orig));
- if (anim_data_orig == NULL) {
+ if (anim_data_orig == nullptr) {
return;
}
AnimData *anim_data_cow = BKE_animdata_from_id(id_cow);
- BLI_assert(anim_data_cow != NULL);
+ BLI_assert(anim_data_cow != nullptr);
update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks);
}
/* Some builders (like motion path one) will ignore proxies from being built. This code makes it so
* proxy and proxy_group pointers never point to an original objects, preventing evaluation code
* from assign evaluated pointer to an original proxy->proxy_from. */
-void update_proxy_pointers_after_copy(const Depsgraph * /*depsgraph*/,
- const Object * /*object_orig*/,
+void update_proxy_pointers_after_copy(const Depsgraph *depsgraph,
+ const Object *object_orig,
Object *object_cow)
{
- if (object_cow->proxy != NULL) {
- if ((object_cow->proxy->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
- object_cow->proxy = NULL;
+ if (object_cow->proxy != nullptr) {
+ if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy->id)) {
+ object_cow->proxy = nullptr;
}
}
- if (object_cow->proxy_group != NULL) {
- if ((object_cow->proxy_group->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
- object_cow->proxy_group = NULL;
+ if (object_cow->proxy_group != nullptr) {
+ if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy_group->id)) {
+ object_cow->proxy_group = nullptr;
}
}
}
@@ -801,7 +785,7 @@ void update_id_after_copy(const Depsgraph *depsgraph,
const bArmature *armature_orig = (bArmature *)object_orig->data;
bArmature *armature_cow = (bArmature *)object_cow->data;
BKE_pose_remap_bone_pointers(armature_cow, object_cow->pose);
- if (armature_orig->edbo == NULL) {
+ if (armature_orig->edbo == nullptr) {
update_pose_orig_pointers(object_orig->pose, object_cow->pose);
}
BKE_pose_pchan_index_rebuild(object_cow->pose);
@@ -835,7 +819,7 @@ int foreach_libblock_validate_callback(void *user_data,
int /*cb_flag*/)
{
ValidateData *data = (ValidateData *)user_data;
- if (*id_p != NULL) {
+ if (*id_p != nullptr) {
if (!check_datablock_expanded(*id_p)) {
data->is_valid = false;
/* TODO(sergey): Store which is not valid? */
@@ -922,12 +906,12 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
* is not to be remapped again. */
deg_tag_copy_on_write_id(id_cow, id_orig);
/* Perform remapping of the nodes. */
- RemapCallbackUserData user_data = {NULL};
+ RemapCallbackUserData user_data = {nullptr};
user_data.depsgraph = depsgraph;
user_data.node_builder = node_builder;
user_data.create_placeholders = create_placeholders;
BKE_library_foreach_ID_link(
- NULL, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP);
+ nullptr, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP);
/* Correct or tweak some pointers which are not taken care by foreach
* from above. */
update_id_after_copy(depsgraph, id_node, id_orig, id_cow);
@@ -942,7 +926,7 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
bool create_placeholders)
{
DEG::IDNode *id_node = depsgraph->find_id_node(id_orig);
- BLI_assert(id_node != NULL);
+ BLI_assert(id_node != nullptr);
return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders);
}
@@ -966,7 +950,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig)
{
DEG::IDNode *id_node = depsgraph->find_id_node(id_orig);
- BLI_assert(id_node != NULL);
+ BLI_assert(id_node != nullptr);
return deg_update_copy_on_write_datablock(depsgraph, id_node);
}
@@ -975,47 +959,47 @@ namespace {
void discard_armature_edit_mode_pointers(ID *id_cow)
{
bArmature *armature_cow = (bArmature *)id_cow;
- armature_cow->edbo = NULL;
+ armature_cow->edbo = nullptr;
}
void discard_curve_edit_mode_pointers(ID *id_cow)
{
Curve *curve_cow = (Curve *)id_cow;
- curve_cow->editnurb = NULL;
- curve_cow->editfont = NULL;
+ curve_cow->editnurb = nullptr;
+ curve_cow->editfont = nullptr;
}
void discard_mball_edit_mode_pointers(ID *id_cow)
{
MetaBall *mball_cow = (MetaBall *)id_cow;
- mball_cow->editelems = NULL;
+ mball_cow->editelems = nullptr;
}
void discard_lattice_edit_mode_pointers(ID *id_cow)
{
Lattice *lt_cow = (Lattice *)id_cow;
- lt_cow->editlatt = NULL;
+ lt_cow->editlatt = nullptr;
}
void discard_mesh_edit_mode_pointers(ID *id_cow)
{
Mesh *mesh_cow = (Mesh *)id_cow;
- if (mesh_cow->edit_mesh == NULL) {
+ if (mesh_cow->edit_mesh == nullptr) {
return;
}
BKE_editmesh_free_derivedmesh(mesh_cow->edit_mesh);
MEM_freeN(mesh_cow->edit_mesh);
- mesh_cow->edit_mesh = NULL;
+ mesh_cow->edit_mesh = nullptr;
}
void discard_scene_pointers(ID *id_cow)
{
Scene *scene_cow = (Scene *)id_cow;
- scene_cow->toolsettings = NULL;
- scene_cow->eevee.light_cache = NULL;
+ scene_cow->toolsettings = nullptr;
+ scene_cow->eevee.light_cache = nullptr;
}
-/* NULL-ify all edit mode pointers which points to data from
+/* nullptr-ify all edit mode pointers which points to data from
* original object. */
void discard_edit_mode_pointers(ID *id_cow)
{
@@ -1069,8 +1053,8 @@ void deg_free_copy_on_write_datablock(ID *id_cow)
* caches from modifying object->data. This is currently happening
* due to mesh/curve datablock boundbox tagging dirty. */
Object *ob_cow = (Object *)id_cow;
- ob_cow->data = NULL;
- ob_cow->sculpt = NULL;
+ ob_cow->data = nullptr;
+ ob_cow->sculpt = nullptr;
break;
}
default:
@@ -1097,12 +1081,13 @@ void deg_evaluate_copy_on_write(struct ::Depsgraph *graph, const IDNode *id_node
bool deg_validate_copy_on_write_datablock(ID *id_cow)
{
- if (id_cow == NULL) {
+ if (id_cow == nullptr) {
return false;
}
ValidateData data;
data.is_valid = true;
- BKE_library_foreach_ID_link(NULL, id_cow, foreach_libblock_validate_callback, &data, IDWALK_NOP);
+ BKE_library_foreach_ID_link(
+ nullptr, id_cow, foreach_libblock_validate_callback, &data, IDWALK_NOP);
return data.is_valid;
}
@@ -1124,7 +1109,7 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow)
bool deg_copy_on_write_is_needed(const ID *id_orig)
{
const ID_Type id_type = GS(id_orig->name);
- return !ELEM(id_type, ID_IM);
+ return ID_TYPE_IS_COW(id_type);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
index 2f83c2f54b9..1992c80e036 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -52,11 +52,11 @@ struct IDNode;
*/
ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
const IDNode *id_node,
- DepsgraphNodeBuilder *node_builder = NULL,
+ DepsgraphNodeBuilder *node_builder = nullptr,
bool create_placeholders = false);
ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
struct ID *id_orig,
- DepsgraphNodeBuilder *node_builder = NULL,
+ DepsgraphNodeBuilder *node_builder = nullptr,
bool create_placeholders = false);
/* Makes sure given CoW data-block is brought back to state of the original
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 96e2974a7ab..d99f6cccc69 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -49,6 +49,7 @@ extern "C" {
#include "intern/debug/deg_debug.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
#include "intern/depsgraph_update.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
@@ -156,7 +157,7 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node,
* whole IK solver, otherwise result might be unpredictable. */
if (comp_node->type == NodeType::BONE) {
ComponentNode *pose_comp = id_node->find_component(NodeType::EVAL_POSE);
- BLI_assert(pose_comp != NULL);
+ BLI_assert(pose_comp != nullptr);
if (pose_comp->custom_flags == COMPONENT_STATE_NONE) {
queue->push_front(pose_comp->get_entry_operation());
pose_comp->custom_flags = COMPONENT_STATE_SCHEDULED;
@@ -172,7 +173,7 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node,
*/
BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQueue *queue)
{
- OperationNode *result = NULL;
+ OperationNode *result = nullptr;
for (Relation *rel : op_node->outlinks) {
/* Flush is forbidden, completely. */
if (rel->flag & RELATION_FLAG_NO_FLUSH) {
@@ -196,7 +197,7 @@ BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQ
if (to_node->scheduled) {
continue;
}
- if (result != NULL) {
+ if (result != nullptr) {
queue->push_front(to_node);
}
else {
@@ -210,7 +211,7 @@ BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQ
void flush_engine_data_update(ID *id)
{
DrawDataList *draw_data_list = DRW_drawdatalist_from_id(id);
- if (draw_data_list == NULL) {
+ if (draw_data_list == nullptr) {
return;
}
LISTBASE_FOREACH (DrawData *, draw_data, draw_data_list) {
@@ -235,7 +236,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd
continue;
}
DepsNodeFactory *factory = type_get_factory(comp_node->type);
- BLI_assert(factory != NULL);
+ BLI_assert(factory != nullptr);
id_cow->recalc |= factory->id_recalc_tag();
}
GHASH_FOREACH_END();
@@ -336,8 +337,8 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
{
/* Sanity checks. */
- BLI_assert(bmain != NULL);
- BLI_assert(graph != NULL);
+ BLI_assert(bmain != nullptr);
+ BLI_assert(graph != nullptr);
/* Nothing to update, early out. */
if (graph->need_update_time) {
const Scene *scene_orig = graph->scene;
@@ -364,7 +365,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
while (!queue.empty()) {
OperationNode *op_node = queue.front();
queue.pop_front();
- while (op_node != NULL) {
+ while (op_node != nullptr) {
/* Tag operation as required for update. */
op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
/* Inform corresponding ID and component nodes about the change. */
@@ -392,7 +393,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, NULL);
+ BLI_gset_clear(graph->entry_tags, nullptr);
}
} // 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 88390ab412f..40a17666880 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
@@ -32,13 +32,14 @@
namespace DEG {
RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph)
- : scene_backup(depsgraph),
+ : animation_backup(depsgraph),
+ scene_backup(depsgraph),
sound_backup(depsgraph),
object_backup(depsgraph),
- drawdata_ptr(NULL),
+ drawdata_ptr(nullptr),
movieclip_backup(depsgraph)
{
- drawdata_backup.first = drawdata_backup.last = NULL;
+ drawdata_backup.first = drawdata_backup.last = nullptr;
}
void RuntimeBackup::init_from_id(ID *id)
@@ -47,6 +48,8 @@ void RuntimeBackup::init_from_id(ID *id)
return;
}
+ animation_backup.init_from_id(id);
+
const ID_Type id_type = GS(id->name);
switch (id_type) {
case ID_OB:
@@ -68,14 +71,16 @@ void RuntimeBackup::init_from_id(ID *id)
/* Note that we never free GPU draw data from here since that's not
* safe for threading and draw data is likely to be re-used. */
drawdata_ptr = DRW_drawdatalist_from_id(id);
- if (drawdata_ptr != NULL) {
+ if (drawdata_ptr != nullptr) {
drawdata_backup = *drawdata_ptr;
- drawdata_ptr->first = drawdata_ptr->last = NULL;
+ drawdata_ptr->first = drawdata_ptr->last = nullptr;
}
}
void RuntimeBackup::restore_to_id(ID *id)
{
+ animation_backup.restore_to_id(id);
+
const ID_Type id_type = GS(id->name);
switch (id_type) {
case ID_OB:
@@ -93,7 +98,7 @@ void RuntimeBackup::restore_to_id(ID *id)
default:
break;
}
- if (drawdata_ptr != NULL) {
+ if (drawdata_ptr != nullptr) {
*drawdata_ptr = drawdata_backup;
}
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
index 31ae3164e37..cc8c6ae0d5b 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
@@ -25,6 +25,7 @@
#include "DNA_ID.h"
+#include "intern/eval/deg_eval_runtime_backup_animation.h"
#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
#include "intern/eval/deg_eval_runtime_backup_object.h"
#include "intern/eval/deg_eval_runtime_backup_scene.h"
@@ -38,12 +39,13 @@ class RuntimeBackup {
public:
explicit RuntimeBackup(const Depsgraph *depsgraph);
- /* NOTE: Will reset all runtime fields which has been backed up to NULL. */
+ /* NOTE: Will reset all runtime fields which has been backed up to nullptr. */
void init_from_id(ID *id);
/* Restore fields to the given ID. */
void restore_to_id(ID *id);
+ AnimationBackup animation_backup;
SceneBackup scene_backup;
SoundBackup sound_backup;
ObjectRuntimeBackup object_backup;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc
new file mode 100644
index 00000000000..e3beeb52ab1
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc
@@ -0,0 +1,144 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_animation.h"
+
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "intern/depsgraph.h"
+
+namespace DEG {
+
+namespace {
+
+struct AnimatedPropertyStoreCalbackData {
+ AnimationBackup *backup;
+
+ /* ID which needs to be stored.
+ * Is used to check possibly nested IDs which f-curves are pointing to. */
+ ID *id;
+
+ PointerRNA id_pointer_rna;
+};
+
+void animated_property_store_cb(ID *id, FCurve *fcurve, void *data_v)
+{
+ AnimatedPropertyStoreCalbackData *data = reinterpret_cast<AnimatedPropertyStoreCalbackData *>(
+ data_v);
+ if (fcurve->rna_path == nullptr || fcurve->rna_path[0] == '\0') {
+ return;
+ }
+ if (id != data->id) {
+ return;
+ }
+
+ /* Resolve path to the property. */
+ PathResolvedRNA resolved_rna;
+ if (!BKE_animsys_store_rna_setting(
+ &data->id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna)) {
+ return;
+ }
+
+ /* Read property value. */
+ float value;
+ if (!BKE_animsys_read_rna_setting(&resolved_rna, &value)) {
+ return;
+ }
+
+ data->backup->values_backup.emplace_back(fcurve->rna_path, fcurve->array_index, value);
+}
+
+} // namespace
+
+AnimationValueBackup::AnimationValueBackup()
+{
+}
+
+AnimationValueBackup::AnimationValueBackup(const string &rna_path, int array_index, float value)
+ : rna_path(rna_path), array_index(array_index), value(value)
+{
+}
+
+AnimationValueBackup::~AnimationValueBackup()
+{
+}
+
+AnimationBackup::AnimationBackup(const Depsgraph *depsgraph)
+{
+ meed_value_backup = !depsgraph->is_active;
+ reset();
+}
+
+void AnimationBackup::reset()
+{
+}
+
+void AnimationBackup::init_from_id(ID *id)
+{
+ /* NOTE: This animation backup nicely preserves values which are animated and
+ * are not touched by frame/depsgraph post_update handler.
+ *
+ * But it makes it impossible to have user edits to animated properties: for
+ * example, translation of object with animated location will not work with
+ * the current version of backup. */
+ return;
+
+ AnimatedPropertyStoreCalbackData data;
+ data.backup = this;
+ data.id = id;
+ RNA_id_pointer_create(id, &data.id_pointer_rna);
+ BKE_fcurves_id_cb(id, animated_property_store_cb, &data);
+}
+
+void AnimationBackup::restore_to_id(ID *id)
+{
+ return;
+
+ PointerRNA id_pointer_rna;
+ RNA_id_pointer_create(id, &id_pointer_rna);
+ for (const AnimationValueBackup &value_backup : values_backup) {
+ /* Resolve path to the property.
+ *
+ * NOTE: Do it again (after storing), since the sub-data pointers might be
+ * changed after copy-on-write. */
+ PathResolvedRNA resolved_rna;
+ if (!BKE_animsys_store_rna_setting(&id_pointer_rna,
+ value_backup.rna_path.c_str(),
+ value_backup.array_index,
+ &resolved_rna)) {
+ return;
+ }
+
+ /* Write property value. */
+ if (!BKE_animsys_write_rna_setting(&resolved_rna, value_backup.value)) {
+ return;
+ }
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
new file mode 100644
index 00000000000..d97ee2b0556
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
@@ -0,0 +1,65 @@
+/*
+ * 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) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "BKE_modifier.h"
+
+#include "intern/depsgraph_type.h"
+
+namespace DEG {
+
+struct Depsgraph;
+
+class AnimationValueBackup {
+ public:
+ AnimationValueBackup();
+ AnimationValueBackup(const string &rna_path, int array_index, float value);
+ ~AnimationValueBackup();
+
+ AnimationValueBackup(const AnimationValueBackup &other) = default;
+ AnimationValueBackup(AnimationValueBackup &&other) noexcept = default;
+
+ AnimationValueBackup &operator=(const AnimationValueBackup &other) = default;
+ AnimationValueBackup &operator=(AnimationValueBackup &&other) = default;
+
+ string rna_path;
+ int array_index;
+ float value;
+};
+
+/* Backup of animated properties values. */
+class AnimationBackup {
+ public:
+ AnimationBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_id(ID *id);
+ void restore_to_id(ID *id);
+
+ bool meed_value_backup;
+ vector<AnimationValueBackup> values_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
index c5744533083..3361c26a077 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
@@ -26,7 +26,7 @@
namespace DEG {
ModifierDataBackupID::ModifierDataBackupID(const Depsgraph * /*depsgraph*/)
- : ModifierDataBackupID(NULL, eModifierType_None)
+ : ModifierDataBackupID(nullptr, eModifierType_None)
{
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
index 54838475bbf..d552c8da99a 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
@@ -36,8 +36,8 @@ MovieClipBackup::MovieClipBackup(const Depsgraph * /*depsgraph*/)
void MovieClipBackup::reset()
{
- anim = NULL;
- cache = NULL;
+ anim = nullptr;
+ cache = nullptr;
}
void MovieClipBackup::init_from_movieclip(MovieClip *movieclip)
@@ -46,8 +46,8 @@ void MovieClipBackup::init_from_movieclip(MovieClip *movieclip)
cache = movieclip->cache;
/* Clear pointers stored in the movie clip, so they are not freed when copied-on-written
* datablock is freed for re-allocation. */
- movieclip->anim = NULL;
- movieclip->cache = NULL;
+ movieclip->anim = nullptr;
+ movieclip->cache = nullptr;
}
void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip)
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 a6a042f3e7b..df7338e1076 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
@@ -52,7 +52,7 @@ void ObjectRuntimeBackup::init_from_object(Object *object)
/* Object update will override actual object->data to an evaluated version.
* Need to make sure we don't have data set to evaluated one before free
* anything. */
- if (mesh_eval != NULL && object->data == mesh_eval) {
+ if (mesh_eval != nullptr && object->data == mesh_eval) {
object->data = runtime.mesh_orig;
}
/* Make a backup of base flags. */
@@ -73,22 +73,22 @@ inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier
void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
{
LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
- if (modifier_data->runtime == NULL) {
+ if (modifier_data->runtime == nullptr) {
continue;
}
- BLI_assert(modifier_data->orig_modifier_data != NULL);
+ BLI_assert(modifier_data->orig_modifier_data != nullptr);
ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime));
- modifier_data->runtime = NULL;
+ modifier_data->runtime = nullptr;
}
}
void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object)
{
- if (object->pose != NULL) {
+ if (object->pose != nullptr) {
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- /* This is NULL in Edit mode. */
- if (pchan->orig_pchan != NULL) {
+ /* This is nullptr in Edit mode. */
+ if (pchan->orig_pchan != nullptr) {
pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime;
BKE_pose_channel_runtime_reset(&pchan->runtime);
}
@@ -103,7 +103,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object)
object->runtime = runtime;
object->runtime.mesh_orig = mesh_orig;
object->runtime.bb = bb;
- if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
+ if (object->type == OB_MESH && object->runtime.mesh_eval != nullptr) {
if (object->id.recalc & ID_RECALC_GEOMETRY) {
/* If geometry is tagged for update it means, that part of
* evaluated mesh are not valid anymore. In this case we can not
@@ -138,33 +138,33 @@ void ObjectRuntimeBackup::restore_to_object(Object *object)
void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
{
LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
- BLI_assert(modifier_data->orig_modifier_data != NULL);
+ BLI_assert(modifier_data->orig_modifier_data != nullptr);
ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find(
modifier_data_id);
if (runtime_data_iterator != modifier_runtime_data.end()) {
modifier_data->runtime = runtime_data_iterator->second;
- runtime_data_iterator->second = NULL;
+ runtime_data_iterator->second = nullptr;
}
}
for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) {
const ModifierDataBackupID modifier_data_id = value.first;
void *runtime = value.second;
- if (value.second == NULL) {
+ if (value.second == nullptr) {
continue;
}
const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type);
- BLI_assert(modifier_type_info != NULL);
+ BLI_assert(modifier_type_info != nullptr);
modifier_type_info->freeRuntimeData(runtime);
}
}
void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object)
{
- if (object->pose != NULL) {
+ if (object->pose != nullptr) {
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- /* This is NULL in Edit mode. */
- if (pchan->orig_pchan != NULL) {
+ /* This is nullptr in Edit mode. */
+ if (pchan->orig_pchan != nullptr) {
PoseChannelRuntimeDataBackup::iterator runtime_data_iterator =
pose_channel_runtime_data.find(pchan->orig_pchan);
if (runtime_data_iterator != pose_channel_runtime_data.end()) {
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 a288fb6ab92..a1d6961cf5d 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
@@ -35,10 +35,10 @@ SceneBackup::SceneBackup(const Depsgraph *depsgraph) : sequencer_backup(depsgrap
void SceneBackup::reset()
{
- sound_scene = NULL;
- playback_handle = NULL;
- sound_scrub_handle = NULL;
- speaker_handles = NULL;
+ sound_scene = nullptr;
+ playback_handle = nullptr;
+ sound_scrub_handle = nullptr;
+ speaker_handles = nullptr;
rigidbody_last_time = -1;
}
@@ -49,16 +49,16 @@ void SceneBackup::init_from_scene(Scene *scene)
sound_scrub_handle = scene->sound_scrub_handle;
speaker_handles = scene->speaker_handles;
- if (scene->rigidbody_world != NULL) {
+ if (scene->rigidbody_world != nullptr) {
rigidbody_last_time = scene->rigidbody_world->ltime;
}
/* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock
* is freed for re-allocation. */
- scene->sound_scene = NULL;
- scene->playback_handle = NULL;
- scene->sound_scrub_handle = NULL;
- scene->speaker_handles = NULL;
+ scene->sound_scene = nullptr;
+ scene->playback_handle = nullptr;
+ scene->sound_scrub_handle = nullptr;
+ scene->speaker_handles = nullptr;
sequencer_backup.init_from_scene(scene);
}
@@ -70,7 +70,7 @@ void SceneBackup::restore_to_scene(Scene *scene)
scene->sound_scrub_handle = sound_scrub_handle;
scene->speaker_handles = speaker_handles;
- if (scene->rigidbody_world != NULL) {
+ if (scene->rigidbody_world != nullptr) {
scene->rigidbody_world->ltime = rigidbody_last_time;
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
index 0150281a4ef..f26d78d3138 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
@@ -34,14 +34,14 @@ SequenceBackup::SequenceBackup(const Depsgraph * /*depsgraph*/)
void SequenceBackup::reset()
{
- scene_sound = NULL;
+ scene_sound = nullptr;
}
void SequenceBackup::init_from_sequence(Sequence *sequence)
{
scene_sound = sequence->scene_sound;
- sequence->scene_sound = NULL;
+ sequence->scene_sound = nullptr;
}
void SequenceBackup::restore_to_sequence(Sequence *sequence)
@@ -52,7 +52,7 @@ void SequenceBackup::restore_to_sequence(Sequence *sequence)
bool SequenceBackup::isEmpty() const
{
- return (scene_sound == NULL);
+ return (scene_sound == nullptr);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
index 08c2697aab3..adc7fd570e8 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
@@ -63,7 +63,7 @@ void SequencerBackup::restore_to_scene(Scene *scene)
/* Cleanup audio while the scene is still known. */
for (SequencesBackupMap::value_type &it : sequences_backup) {
SequenceBackup &sequence_backup = it.second;
- if (sequence_backup.scene_sound != NULL) {
+ if (sequence_backup.scene_sound != nullptr) {
BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound);
}
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
index 0c54032e32c..f427d57a8ef 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
@@ -36,9 +36,9 @@ SoundBackup::SoundBackup(const Depsgraph * /*depsgraph*/)
void SoundBackup::reset()
{
- cache = NULL;
- waveform = NULL;
- playback_handle = NULL;
+ cache = nullptr;
+ waveform = nullptr;
+ playback_handle = nullptr;
}
void SoundBackup::init_from_sound(bSound *sound)
@@ -47,9 +47,9 @@ void SoundBackup::init_from_sound(bSound *sound)
waveform = sound->waveform;
playback_handle = sound->playback_handle;
- sound->cache = NULL;
- sound->waveform = NULL;
- sound->playback_handle = NULL;
+ sound->cache = nullptr;
+ sound->waveform = nullptr;
+ sound->playback_handle = nullptr;
}
void SoundBackup::restore_to_sound(bSound *sound)
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 16c934e72fe..5002f2890ae 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -28,6 +28,7 @@
#include "BLI_utildefines.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_factory.h"
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index acfc8d19bc7..3878362d936 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -191,11 +191,11 @@ struct Node {
virtual OperationNode *get_entry_operation()
{
- return NULL;
+ return nullptr;
}
virtual OperationNode *get_exit_operation()
{
- return NULL;
+ return nullptr;
}
virtual NodeClass get_class() const;
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index 830c53cfc76..334f55c0942 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -104,7 +104,7 @@ static void comp_node_hash_value_free(void *value_v)
}
ComponentNode::ComponentNode()
- : entry_operation(NULL), exit_operation(NULL), affects_directly_visible(false)
+ : 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");
}
@@ -120,7 +120,7 @@ void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/)
ComponentNode::~ComponentNode()
{
clear_operations();
- if (operations_map != NULL) {
+ if (operations_map != nullptr) {
BLI_ghash_free(operations_map, comp_node_hash_key_free, comp_node_hash_value_free);
}
}
@@ -135,8 +135,8 @@ string ComponentNode::identifier() const
OperationNode *ComponentNode::find_operation(OperationIDKey key) const
{
- OperationNode *node = NULL;
- if (operations_map != NULL) {
+ OperationNode *node = nullptr;
+ if (operations_map != nullptr) {
node = (OperationNode *)BLI_ghash_lookup(operations_map, &key);
}
else {
@@ -162,13 +162,13 @@ OperationNode *ComponentNode::find_operation(OperationCode opcode,
OperationNode *ComponentNode::get_operation(OperationIDKey key) const
{
OperationNode *node = find_operation(key);
- if (node == NULL) {
+ if (node == nullptr) {
fprintf(stderr,
"%s: find_operation(%s) failed\n",
this->identifier().c_str(),
key.identifier().c_str());
BLI_assert(!"Request for non-existing operation, should not happen");
- return NULL;
+ return nullptr;
}
return node;
}
@@ -183,7 +183,7 @@ OperationNode *ComponentNode::get_operation(OperationCode opcode,
bool ComponentNode::has_operation(OperationIDKey key) const
{
- return find_operation(key) != NULL;
+ return find_operation(key) != nullptr;
}
bool ComponentNode::has_operation(OperationCode opcode, const char *name, int name_tag) const
@@ -229,19 +229,19 @@ OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb &op,
void ComponentNode::set_entry_operation(OperationNode *op_node)
{
- BLI_assert(entry_operation == NULL);
+ BLI_assert(entry_operation == nullptr);
entry_operation = op_node;
}
void ComponentNode::set_exit_operation(OperationNode *op_node)
{
- BLI_assert(exit_operation == NULL);
+ BLI_assert(exit_operation == nullptr);
exit_operation = op_node;
}
void ComponentNode::clear_operations()
{
- if (operations_map != NULL) {
+ if (operations_map != nullptr) {
BLI_ghash_clear(operations_map, comp_node_hash_key_free, comp_node_hash_value_free);
}
for (OperationNode *op_node : operations) {
@@ -253,14 +253,14 @@ void ComponentNode::clear_operations()
void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source)
{
OperationNode *entry_op = get_entry_operation();
- if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ if (entry_op != nullptr && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
for (OperationNode *op_node : operations) {
op_node->tag_update(graph, source);
}
// It is possible that tag happens before finalization.
- if (operations_map != NULL) {
+ if (operations_map != nullptr) {
GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) {
op_node->tag_update(graph, source);
}
@@ -273,8 +273,8 @@ OperationNode *ComponentNode::get_entry_operation()
if (entry_operation) {
return entry_operation;
}
- else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) {
- OperationNode *op_node = NULL;
+ else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) {
+ OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) {
op_node = tmp;
@@ -287,7 +287,7 @@ OperationNode *ComponentNode::get_entry_operation()
else if (operations.size() == 1) {
return operations[0];
}
- return NULL;
+ return nullptr;
}
OperationNode *ComponentNode::get_exit_operation()
@@ -295,8 +295,8 @@ OperationNode *ComponentNode::get_exit_operation()
if (exit_operation) {
return exit_operation;
}
- else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) {
- OperationNode *op_node = NULL;
+ else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) {
+ OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) {
op_node = tmp;
@@ -309,7 +309,7 @@ OperationNode *ComponentNode::get_exit_operation()
else if (operations.size() == 1) {
return operations[0];
}
- return NULL;
+ return nullptr;
}
void ComponentNode::finalize_build(Depsgraph * /*graph*/)
@@ -319,8 +319,8 @@ void ComponentNode::finalize_build(Depsgraph * /*graph*/)
operations.push_back(op_node);
}
GHASH_FOREACH_END();
- BLI_ghash_free(operations_map, comp_node_hash_key_free, NULL);
- operations_map = NULL;
+ BLI_ghash_free(operations_map, comp_node_hash_key_free, nullptr);
+ operations_map = nullptr;
}
/* Bone Component ========================================= */
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 53fbc6e617c..c25f0bbd7aa 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -65,7 +65,7 @@ struct ComponentNode : public Node {
virtual string identifier() const override;
/* Find an existing operation, if requested operation does not exist
- * NULL will be returned. */
+ * nullptr will be returned. */
OperationNode *find_operation(OperationIDKey key) const;
OperationNode *find_operation(OperationCode opcode, const char *name, int name_tag) const;
diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.cc b/source/blender/depsgraph/intern/node/deg_node_factory.cc
index 4a11ed2a4fb..9dfd018b4fd 100644
--- a/source/blender/depsgraph/intern/node/deg_node_factory.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_factory.cc
@@ -26,11 +26,11 @@
namespace DEG {
/* Global type registry */
-static DepsNodeFactory *node_typeinfo_registry[static_cast<int>(NodeType::NUM_TYPES)] = {NULL};
+static DepsNodeFactory *node_typeinfo_registry[static_cast<int>(NodeType::NUM_TYPES)] = {nullptr};
void register_node_typeinfo(DepsNodeFactory *factory)
{
- BLI_assert(factory != NULL);
+ BLI_assert(factory != nullptr);
const int type_as_int = static_cast<int>(factory->type());
node_typeinfo_registry[type_as_int] = factory;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index e14513a1aa2..853198109a2 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -101,7 +101,7 @@ static void id_deps_node_hash_value_free(void *value_v)
/* Initialize 'id' node - from pointer data given. */
void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
/* Store ID-pointer. */
id_orig = (ID *)id;
eval_flags = 0;
@@ -126,7 +126,7 @@ void IDNode::init_copy_on_write(ID *id_cow_hint)
/* Create pointer as early as possible, so we can use it for function
* bindings. Rest of data we'll be copying to the new datablock when
* it is actually needed. */
- if (id_cow_hint != NULL) {
+ if (id_cow_hint != nullptr) {
// BLI_assert(deg_copy_on_write_is_needed(id_orig));
if (deg_copy_on_write_is_needed(id_orig)) {
id_cow = id_cow_hint;
@@ -154,22 +154,22 @@ IDNode::~IDNode()
void IDNode::destroy()
{
- if (id_orig == NULL) {
+ if (id_orig == nullptr) {
return;
}
BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free);
/* Free memory used by this CoW ID. */
- if (id_cow != id_orig && id_cow != NULL) {
+ if (id_cow != id_orig && id_cow != nullptr) {
deg_free_copy_on_write_datablock(id_cow);
MEM_freeN(id_cow);
- id_cow = NULL;
+ id_cow = nullptr;
DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
}
/* Tag that the node is freed. */
- id_orig = NULL;
+ id_orig = nullptr;
}
string IDNode::identifier() const
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 35184253f5c..886c25b5a4e 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -57,7 +57,7 @@ struct IDNode : public Node {
};
virtual void init(const ID *id, const char *subdata) override;
- void init_copy_on_write(ID *id_cow_hint = NULL);
+ void init_copy_on_write(ID *id_cow_hint = nullptr);
~IDNode();
void destroy();
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index 09a761d282f..e313b5ccee7 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -241,13 +241,13 @@ void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source)
void OperationNode::set_as_entry()
{
- BLI_assert(owner != NULL);
+ BLI_assert(owner != nullptr);
owner->set_entry_operation(this);
}
void OperationNode::set_as_exit()
{
- BLI_assert(owner != NULL);
+ BLI_assert(owner != nullptr);
owner->set_exit_operation(this);
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_time.cc b/source/blender/depsgraph/intern/node/deg_node_time.cc
index cae98ef56c0..ff3e950bb44 100644
--- a/source/blender/depsgraph/intern/node/deg_node_time.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_time.cc
@@ -26,6 +26,7 @@
#include "DNA_scene_types.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_relation.h"
namespace DEG {
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index a6ad7d97922..420249ab930 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -229,8 +229,10 @@ static void eevee_draw_background(void *vedata)
/* Copy previous persmat to UBO data */
copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat);
- /* Refresh Probes */
+ /* Refresh Probes
+ * Shadows needs to be updated for correct probes */
DRW_stats_group_start("Probes Refresh");
+ EEVEE_shadows_update(sldata, vedata);
EEVEE_lightprobes_refresh(sldata, vedata);
EEVEE_lightprobes_refresh_planar(sldata, vedata);
DRW_stats_group_end();
@@ -481,6 +483,10 @@ static void eevee_render_to_image(void *vedata,
const DRWContextState *draw_ctx = DRW_context_state_get();
EEVEE_render_init(vedata, engine, draw_ctx->depsgraph);
+ if (RE_engine_test_break(engine)) {
+ return;
+ }
+
DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache);
/* Actually do the rendering. */
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 261b7f00e42..e8e5614e4d4 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -768,6 +768,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb
EEVEE_materials_cache_finish(sldata, vedata);
EEVEE_lights_cache_finish(sldata, vedata);
EEVEE_lightprobes_cache_finish(sldata, vedata);
+ EEVEE_shadows_update(sldata, vedata);
/* Disable volumetrics when baking. */
stl->effects->enabled_effects &= ~EFFECT_VOLUMETRIC;
@@ -830,17 +831,19 @@ static void eevee_lightbake_render_world_sample(void *ved, void *user_data)
EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb);
EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f);
- /* Clear the cache to avoid white values in the grid. */
- GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0);
- GPU_framebuffer_bind(lbake->store_fb);
- /* Clear to 1.0f for visibility. */
- GPU_framebuffer_clear_color(lbake->store_fb, ((float[4]){1.0f, 1.0f, 1.0f, 1.0f}));
- DRW_draw_pass(vedata->psl->probe_grid_fill);
+ if (lcache->flag & LIGHTCACHE_UPDATE_GRID) {
+ /* Clear the cache to avoid white values in the grid. */
+ GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0);
+ GPU_framebuffer_bind(lbake->store_fb);
+ /* Clear to 1.0f for visibility. */
+ GPU_framebuffer_clear_color(lbake->store_fb, ((float[4]){1.0f, 1.0f, 1.0f, 1.0f}));
+ DRW_draw_pass(vedata->psl->probe_grid_fill);
- SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
- /* Make a copy for later. */
- eevee_lightbake_copy_irradiance(lbake, lcache);
+ /* Make a copy for later. */
+ eevee_lightbake_copy_irradiance(lbake, lcache);
+ }
lcache->cube_len = 1;
lcache->grid_len = lbake->grid_len;
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 126ec8d81c4..c6e8bac0949 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -208,13 +208,11 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
linfo->num_light++;
}
-void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
{
EEVEE_LightsInfo *linfo = sldata->lights;
sldata->common_data.la_num_light = linfo->num_light;
DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
-
- EEVEE_shadows_update(sldata, vedata);
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index d0fe7c6637e..2e0afc5d8d7 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -1457,7 +1457,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
- const int materials_len = MAX2(1, ob->totcol);
+ const int materials_len = DRW_cache_object_material_count_get(ob);
struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len);
struct DRWShadingGroup **shgrp_depth_array = BLI_array_alloca(shgrp_depth_array,
@@ -1529,18 +1529,10 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) {
/* Get per-material split surface */
- char *auto_layer_names;
- int *auto_layer_is_srgb;
- int auto_layer_count;
struct GPUBatch **mat_geom = NULL;
if (!use_sculpt_pbvh) {
- mat_geom = DRW_cache_object_surface_material_get(ob,
- gpumat_array,
- materials_len,
- &auto_layer_names,
- &auto_layer_is_srgb,
- &auto_layer_count);
+ mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
}
if (use_sculpt_pbvh) {
@@ -1577,28 +1569,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i], oedata);
ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata);
- char *name = auto_layer_names;
- for (int j = 0; j < auto_layer_count; j++) {
- /* TODO don't add these uniform when not needed (default pass shaders). */
- /* FIXME: This is broken, as it overrides any autolayers srgb bool of the previous mesh
- * that shares the same material. */
- if (shgrp_array[i]) {
- DRW_shgroup_uniform_bool_copy(shgrp_array[i], name, auto_layer_is_srgb[j]);
- }
- if (shgrp_depth_array[i]) {
- DRW_shgroup_uniform_bool_copy(shgrp_depth_array[i], name, auto_layer_is_srgb[j]);
- }
- if (shgrp_depth_clip_array[i]) {
- DRW_shgroup_uniform_bool_copy(
- shgrp_depth_clip_array[i], name, auto_layer_is_srgb[j]);
- }
- /* Go to next layer name. */
- while (*name != '\0') {
- name++;
- }
- name += 1;
- }
-
/* Shadow Pass */
struct GPUMaterial *gpumat;
const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree);
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 670201555bd..fc5af62d45f 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -119,7 +119,7 @@ int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
if (scene_eval->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) {
/* Update Motion Blur Matrices */
- if (camera) {
+ if (camera && (camera->type == OB_CAMERA) && (camera->data != NULL)) {
float persmat[4][4];
float ctime = DEG_get_ctime(draw_ctx->depsgraph);
float delta = scene_eval->eevee.motion_blur_shutter;
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index ba5704f14e5..063510d51e6 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -30,6 +30,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "BKE_global.h"
#include "BKE_object.h"
#include "BLI_rand.h"
@@ -38,6 +39,7 @@
#include "DEG_depsgraph_query.h"
#include "GPU_framebuffer.h"
+#include "GPU_extensions.h"
#include "GPU_state.h"
#include "RE_pipeline.h"
@@ -91,9 +93,24 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
copy_v4_fl4(camtexcofac, 1.0f, 1.0f, 0.0f, 0.0f);
}
+ int final_res[2] = {size_orig[0] + g_data->overscan_pixels * 2.0f,
+ size_orig[1] + g_data->overscan_pixels * 2.0f};
+
+ int max_dim = max_ii(final_res[0], final_res[1]);
+ if (max_dim > GPU_max_texture_size()) {
+ char error_msg[128];
+ BLI_snprintf(error_msg,
+ sizeof(error_msg),
+ "Error: Reported texture size limit (%dpx) is lower than output size (%dpx).",
+ GPU_max_texture_size(),
+ max_dim);
+ RE_engine_set_error_message(engine, error_msg);
+ G.is_break = true;
+ return;
+ }
+
/* XXX overriding viewport size. Simplify things but is not really 100% safe. */
- DRW_render_viewport_size_set((int[2]){size_orig[0] + g_data->overscan_pixels * 2.0f,
- size_orig[1] + g_data->overscan_pixels * 2.0f});
+ DRW_render_viewport_size_set(final_res);
/* TODO 32 bit depth */
DRW_texture_ensure_fullscreen_2d(&dtxl->depth, GPU_DEPTH24_STENCIL8, 0);
@@ -447,12 +464,13 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1);
EEVEE_materials_init(sldata, stl, fbl);
- /* Refresh Probes */
+ /* Refresh Probes
+ * Shadows needs to be updated for correct probes */
+ EEVEE_shadows_update(sldata, vedata);
EEVEE_lightprobes_refresh(sldata, vedata);
EEVEE_lightprobes_refresh_planar(sldata, vedata);
/* Refresh Shadows */
- EEVEE_shadows_update(sldata, vedata);
EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
/* Set matrices. */
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index d32f93432b8..423cc64da36 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -401,6 +401,14 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
return;
}
+ float size[3];
+ mat4_to_size(size, ob->obmat);
+ /* Check if any of the axes have 0 length. (see T69070) */
+ const float epsilon = 1e-8f;
+ if ((size[0] < epsilon) || (size[1] < epsilon) || (size[2] < epsilon)) {
+ return;
+ }
+
struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma);
eGPUMaterialStatus status = GPU_material_status(mat);
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 b9a971570df..c4f815b5dd4 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -5,6 +5,7 @@
#define M_1_PI 0.318309886183790671538 /* 1/pi */
#define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */
#define M_1_PI2 0.101321183642337771443 /* 1/(pi^2) */
+#define FLT_MAX 3.402823e+38
#define LUT_SIZE 64
@@ -934,6 +935,11 @@ void main()
vec3 vol_transmit, vol_scatter;
volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
+ /* Removes part of the volume scattering that have
+ * already been added to the destination pixels.
+ * Since we do that using the blending pipeline we need to account for material transmittance. */
+ vol_scatter -= vol_scatter * cl.transmittance;
+
outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout);
outTransmittance = vec4(cl.transmittance, transmit * holdout);
# else
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 ca4940ceffb..5277bfa32bb 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
@@ -41,6 +41,12 @@ float max_v4(vec4 v)
return max(max(v.x, v.y), max(v.z, v.w));
}
+vec4 safe_color(vec4 c)
+{
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
+}
+
#define THRESHOLD 1.0
#ifdef STEP_DOWNSAMPLE
@@ -57,10 +63,10 @@ void main(void)
ivec4 uvs = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
/* custom downsampling */
- vec4 color1 = texelFetch(colorBuffer, uvs.xy, 0);
- vec4 color2 = texelFetch(colorBuffer, uvs.zw, 0);
- vec4 color3 = texelFetch(colorBuffer, uvs.zy, 0);
- vec4 color4 = texelFetch(colorBuffer, uvs.xw, 0);
+ vec4 color1 = safe_color(texelFetch(colorBuffer, uvs.xy, 0));
+ vec4 color2 = safe_color(texelFetch(colorBuffer, uvs.zw, 0));
+ vec4 color3 = safe_color(texelFetch(colorBuffer, uvs.zy, 0));
+ vec4 color4 = safe_color(texelFetch(colorBuffer, uvs.xw, 0));
/* Leverage SIMD by combining 4 depth samples into a vec4 */
vec4 depth;
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
index 540f2ac4728..65506e5c7b1 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
@@ -9,7 +9,7 @@ flat out int probeIdx;
void main()
{
- gl_Position = ViewProjectionMatrix * probe_mat * vec4(pos, 1.0);
- worldPosition = (probe_mat * vec4(pos, 1.0)).xyz;
+ worldPosition = (probe_mat * vec4(-pos.x, pos.y, 0.0, 1.0)).xyz;
+ gl_Position = ViewProjectionMatrix * vec4(worldPosition, 1.0);
probeIdx = probe_id;
}
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 978ce149be4..8c2619650b9 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,8 @@ void CLOSURE_NAME(vec3 N
out_refr = vec3(0.0);
#endif
-#ifdef SHADOW_SHADER
+#if defined(SHADOW_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/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
index 2cf8501de9b..dbfc7ad5a71 100644
--- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
@@ -47,13 +47,14 @@ vec3 solve_cubic(vec4 coefs)
float D = coefs.x;
/* Compute the Hessian and the discriminant */
- vec3 delta = vec3(-coefs.z * coefs.z + coefs.y,
- -coefs.y * coefs.z + coefs.x,
- dot(vec2(coefs.z, -coefs.y), coefs.xy));
+ vec3 delta = vec3(-coefs.zy * coefs.zz + coefs.yx, dot(vec2(coefs.z, -coefs.y), coefs.xy));
/* Discriminant */
float discr = dot(vec2(4.0 * delta.x, -delta.y), delta.zy);
+ /* Clamping avoid NaN output on some platform. (see T67060) */
+ float sqrt_discr = sqrt(clamp(discr, 0.0, FLT_MAX));
+
vec2 xlc, xsc;
/* Algorithm A */
@@ -63,10 +64,11 @@ vec3 solve_cubic(vec4 coefs)
float D_a = -2.0 * B * delta.x + delta.y;
/* Take the cubic root of a normalized complex number */
- float theta = atan(sqrt(discr), -D_a) / 3.0;
+ float theta = atan(sqrt_discr, -D_a) / 3.0;
- float x_1a = 2.0 * sqrt(-C_a) * cos(theta);
- float x_3a = 2.0 * sqrt(-C_a) * cos(theta + (2.0 / 3.0) * M_PI);
+ float _2_sqrt_C_a = 2.0 * sqrt(-C_a);
+ float x_1a = _2_sqrt_C_a * cos(theta);
+ float x_3a = _2_sqrt_C_a * cos(theta + (2.0 / 3.0) * M_PI);
float xl;
if ((x_1a + x_3a) > 2.0 * B) {
@@ -86,10 +88,11 @@ vec3 solve_cubic(vec4 coefs)
float D_d = -D * delta.y + 2.0 * C * delta.z;
/* Take the cubic root of a normalized complex number */
- float theta = atan(D * sqrt(discr), -D_d) / 3.0;
+ float theta = atan(D * sqrt_discr, -D_d) / 3.0;
- float x_1d = 2.0 * sqrt(-C_d) * cos(theta);
- float x_3d = 2.0 * sqrt(-C_d) * cos(theta + (2.0 / 3.0) * M_PI);
+ float _2_sqrt_C_d = 2.0 * sqrt(-C_d);
+ float x_1d = _2_sqrt_C_d * cos(theta);
+ float x_3d = _2_sqrt_C_d * cos(theta + (2.0 / 3.0) * M_PI);
float xs;
if (x_1d + x_3d < 2.0 * C) {
@@ -269,15 +272,18 @@ float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3])
}
float L = dot(V3, C);
- float x0 = dot(V1, C) / L;
- float y0 = dot(V2, C) / L;
+ float inv_L = 1.0 / L;
+ float x0 = dot(V1, C) * inv_L;
+ float y0 = dot(V2, C) * inv_L;
- a *= L * L;
- b *= L * L;
+ float L_sqr = L * L;
+ a *= L_sqr;
+ b *= L_sqr;
+ float t = 1.0 + x0 * x0;
float c0 = a * b;
- float c1 = a * b * (1.0 + x0 * x0 + y0 * y0) - a - b;
- float c2 = 1.0 - a * (1.0 + x0 * x0) - b * (1.0 + y0 * y0);
+ float c1 = c0 * (t + y0 * y0) - a - b;
+ float c2 = (1.0 - a * t) - b * (1.0 + y0 * y0);
float c3 = 1.0;
vec3 roots = solve_cubic(vec4(c0, c1, c2, c3));
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 704e16b2907..23fa30b5c13 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -82,13 +82,13 @@ typedef struct EXTERNAL_Data {
static struct {
/* Depth Pre Pass */
struct GPUShader *depth_sh;
- bool draw_depth;
} e_data = {NULL}; /* Engine data */
typedef struct EXTERNAL_PrivateData {
DRWShadingGroup *depth_shgrp;
/* Do we need to update the depth or can we reuse the last calculated texture. */
+ bool need_depth;
bool update_depth;
float last_persmat[4][4];
@@ -110,13 +110,15 @@ static void external_engine_init(void *vedata)
if (!stl->g_data) {
/* Alloc transient pointers */
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
- stl->g_data->update_depth = true;
+ stl->g_data->need_depth = true;
}
+ stl->g_data->update_depth = true;
+
/* Progressive render samples are tagged with no rebuild, in that case we
* can skip updating the depth buffer */
- if (!(ar && (ar->do_draw & RGN_DRAW_NO_REBUILD))) {
- stl->g_data->update_depth = true;
+ if (ar && (ar->do_draw & RGN_DRAW_NO_REBUILD)) {
+ stl->g_data->update_depth = false;
}
}
@@ -126,6 +128,8 @@ static void external_cache_init(void *vedata)
EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
EXTERNAL_TextureList *txl = ((EXTERNAL_Data *)vedata)->txl;
EXTERNAL_FramebufferList *fbl = ((EXTERNAL_Data *)vedata)->fbl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
{
DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
@@ -144,14 +148,7 @@ static void external_cache_init(void *vedata)
}
/* Do not draw depth pass when overlays are turned off. */
- e_data.draw_depth = false;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
- if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
- /* mark `update_depth` for when overlays are turned on again. */
- stl->g_data->update_depth = true;
- return;
- }
+ stl->g_data->need_depth = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
}
static void external_cache_populate(void *vedata, Object *ob)
@@ -163,20 +160,16 @@ static void external_cache_populate(void *vedata, Object *ob)
return;
}
- /* Do not draw depth pass when overlays are turned off. */
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
- if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
+ if (ob->type == OB_GPENCIL) {
+ /* Grease Pencil objects need correct depth to do the blending. */
+ stl->g_data->need_depth = true;
return;
}
- if (stl->g_data->update_depth) {
- e_data.draw_depth = true;
- struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
- if (geom) {
- /* Depth Prepass */
- DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
- }
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ /* Depth Prepass */
+ DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
}
}
@@ -246,16 +239,14 @@ static void external_draw_scene(void *vedata)
external_draw_scene_do(vedata);
}
- if (e_data.draw_depth) {
+ if (stl->g_data->update_depth && stl->g_data->need_depth) {
DRW_draw_pass(psl->depth_pass);
- // copy result to tmp buffer
+ /* Copy main depth buffer to cached framebuffer. */
GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT);
- stl->g_data->update_depth = false;
- }
- else {
- // copy tmp buffer to default
- GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
}
+
+ /* Copy cached depth buffer to main framebuffer. */
+ GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
}
static void external_engine_free(void)
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index f9df1342bf8..f21d96a304c 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -349,7 +349,6 @@ void DRW_gpencil_freecache(struct Object *ob)
for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) {
bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i];
BKE_gpencil_free_frame_runtime_data(gpf_eval);
- gpf_eval = NULL;
}
ob->runtime.gpencil_tot_layers = 0;
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 4c6ce896ebc..2c6b1315ad4 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -522,7 +522,7 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
BKE_image_release_ibuf(image, ibuf, NULL);
}
else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D);
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, ibuf, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "myTexture", texture);
DRW_shgroup_uniform_bool_copy(
grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
@@ -705,7 +705,7 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
BKE_image_release_ibuf(image, ibuf, NULL);
}
else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D);
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, ibuf, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "myTexture", texture);
DRW_shgroup_uniform_bool_copy(
grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
@@ -878,7 +878,7 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
BKE_image_release_ibuf(image, ibuf, NULL);
}
else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D);
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, ibuf, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "myTexture", texture);
DRW_shgroup_uniform_bool_copy(
grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index a1a1f7cc389..f4baf2c7837 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -439,7 +439,7 @@ void GPENCIL_cache_init(void *vedata)
stl->storage->is_main_onion = false;
}
/* save render state */
- stl->storage->is_render = DRW_state_is_image_render();
+ stl->storage->is_render = DRW_state_is_scene_render();
stl->storage->is_mat_preview = (bool)stl->storage->is_render &&
STREQ(scene->id.name + 2, "preview");
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 0b77fcad265..416283e321b 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -35,6 +35,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_modifier.h"
@@ -974,6 +975,15 @@ static bool set_pchan_color(const ArmatureDrawContext *ctx,
/** \name Drawing Color Helpers
* \{ */
+static void bone_locked_color_shade(float color[4])
+{
+ float locked_color[4];
+
+ UI_GetThemeColor4fv(TH_BONE_LOCKED_WEIGHT, locked_color);
+
+ interp_v3_v3v3(color, color, locked_color, locked_color[3]);
+}
+
static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
const EditBone *UNUSED(eBone),
const bPoseChannel *pchan,
@@ -989,6 +999,11 @@ static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
static float disp_color[4];
copy_v4_v4(disp_color, pchan->draw_data->solid_color);
set_pchan_color(ctx, PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+
+ if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
+ bone_locked_color_shade(disp_color);
+ }
+
return disp_color;
}
@@ -1009,7 +1024,7 @@ static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext *
const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
static float consts_color[4];
- if ((arm->flag & ARM_POSEMODE) &&
+ if ((arm->flag & ARM_POSEMODE) && !(boneflag & BONE_DRAW_LOCKED_WEIGHT) &&
set_pchan_color(ctx, PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
}
@@ -1065,6 +1080,10 @@ static const float *get_bone_wire_color(const ArmatureDrawContext *ctx,
else if (arm->flag & ARM_POSEMODE) {
copy_v4_v4(disp_color, pchan->draw_data->wire_color);
set_pchan_color(ctx, PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+
+ if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
+ bone_locked_color_shade(disp_color);
+ }
}
else {
copy_v3_v3(disp_color, ctx->color.vertex);
@@ -1518,7 +1537,7 @@ static void draw_bone_custom_shape(ArmatureDrawContext *ctx,
drw_shgroup_bone_custom_empty(ctx, disp_mat, col_wire, pchan->custom);
}
}
- if ((boneflag & BONE_DRAWWIRE) == 0) {
+ if ((boneflag & BONE_DRAWWIRE) == 0 && (boneflag & BONE_DRAW_LOCKED_WEIGHT) == 0) {
drw_shgroup_bone_custom_solid(ctx, disp_mat, col_solid, col_hint, col_wire, pchan->custom);
}
else {
@@ -2010,6 +2029,8 @@ static void draw_armature_edit(ArmatureDrawContext *ctx)
boneflag |= BONE_DRAW_ACTIVE;
}
+ boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
+
draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
if (arm->drawtype == ARM_ENVELOPE) {
@@ -2054,6 +2075,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
bPoseChannel *pchan;
int index = -1;
const bool show_text = DRW_state_show_text();
+ bool draw_locked_weights = false;
/* We can't safely draw non-updated pose, might contain NULL bone pointers... */
if (ob->pose->flag & POSE_RECALC) {
@@ -2089,6 +2111,28 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
}
}
+ /* In weight paint mode retrieve the vertex group lock status. */
+ if ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) &&
+ (draw_ctx->obact != NULL)) {
+ draw_locked_weights = true;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT;
+ }
+
+ const Object *obact_orig = DEG_get_original_object(draw_ctx->obact);
+
+ LISTBASE_FOREACH (bDeformGroup *, dg, &obact_orig->defbase) {
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
+
+ if (pchan) {
+ pchan->bone->flag |= BONE_DRAW_LOCKED_WEIGHT;
+ }
+ }
+ }
+ }
+
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) {
Bone *bone = pchan->bone;
const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0;
@@ -2120,6 +2164,10 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
boneflag |= BONE_DRAW_ACTIVE;
}
+ if (!draw_locked_weights) {
+ boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
+ }
+
draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
index 56fbc3cca01..6a65be0b84c 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -204,6 +204,7 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_bool_copy(grp, "selectEdges", pd->edit_mesh.do_edges || select_edge);
/* Verts */
+ state |= DRW_STATE_WRITE_DEPTH;
DRW_PASS_CREATE(psl->edit_mesh_verts_ps[i], state | pd->clipping_state);
if (select_vert) {
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index fe39b8580e3..59a03d10fbe 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -177,6 +177,30 @@ BLI_INLINE OVERLAY_DupliData *OVERLAY_duplidata_get(Object *ob, void *vedata, bo
return NULL;
}
+static bool overlay_object_is_edit_mode(const OVERLAY_PrivateData *pd, const Object *ob)
+{
+ if ((ob->mode & OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) {
+ /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */
+ switch (ob->type) {
+ case OB_MESH:
+ return pd->ctx_mode == CTX_MODE_EDIT_MESH;
+ case OB_ARMATURE:
+ return pd->ctx_mode == CTX_MODE_EDIT_ARMATURE;
+ case OB_CURVE:
+ return pd->ctx_mode == CTX_MODE_EDIT_CURVE;
+ case OB_SURF:
+ return pd->ctx_mode == CTX_MODE_EDIT_SURFACE;
+ case OB_LATTICE:
+ return pd->ctx_mode == CTX_MODE_EDIT_LATTICE;
+ case OB_MBALL:
+ return pd->ctx_mode == CTX_MODE_EDIT_METABALL;
+ case OB_FONT:
+ return pd->ctx_mode == CTX_MODE_EDIT_TEXT;
+ }
+ }
+ return false;
+}
+
static void OVERLAY_cache_populate(void *vedata, Object *ob)
{
OVERLAY_Data *data = vedata;
@@ -185,7 +209,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
const bool is_select = DRW_state_is_select();
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 = BKE_object_is_in_editmode(ob);
+ 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_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
@@ -378,6 +402,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_image_draw(vedata);
OVERLAY_facing_draw(vedata);
+ OVERLAY_extra_blend_draw(vedata);
if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(fbl->overlay_line_fb);
@@ -412,6 +437,11 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_motion_path_draw(vedata);
OVERLAY_extra_centers_draw(vedata);
+ if (DRW_state_is_select()) {
+ /* Edit modes have their own selection code. */
+ return;
+ }
+
/* Functions after this point can change FBO freely. */
switch (pd->ctx_mode) {
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 90ddb9f7476..fc52efb0174 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -140,7 +140,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
cb->light_point = BUF_INSTANCE(grp_sub, format, DRW_cache_light_point_lines_get());
cb->light_spot = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_lines_get());
cb->light_sun = BUF_INSTANCE(grp_sub, format, DRW_cache_light_sun_lines_get());
- cb->probe_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+ cb->probe_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_cube_get());
cb->probe_grid = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_grid_get());
cb->probe_planar = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
cb->solid_quad = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_get());
@@ -157,13 +157,13 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
grp_sub = DRW_shgroup_create_sub(grp);
- DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_BACK);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
cb->camera_volume = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_get());
cb->camera_volume_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_wire_get());
cb->light_spot_cone_back = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
grp_sub = DRW_shgroup_create_sub(grp);
- DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_FRONT);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT);
cb->light_spot_cone_front = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
}
{
@@ -623,8 +623,9 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
copy_m4_m4(instdata.mat, ob->obmat);
/* FIXME / TODO: clipend has no meaning nowadays.
* In EEVEE, Only clipsta is used shadowmaping.
- * Clip end is computed automatically based on light power. */
- instdata.clip_end = la->clipend;
+ * Clip end is computed automatically based on light power.
+ * For now, always use the custom distance as clipend. */
+ instdata.clip_end = la->att_dist;
instdata.clip_sta = la->clipsta;
DRW_buffer_add_entry(cb->groundline, instdata.pos);
@@ -637,6 +638,9 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
DRW_buffer_add_entry(cb->light_sun, color, &instdata);
}
else if (la->type == LA_SPOT) {
+ /* Previous implementation was using the clipend distance as cone size.
+ * We cannot do this anymore so we use a fixed size of 10. (see T72871) */
+ rescale_m4(instdata.mat, (float[3]){10.0f, 10.0f, 10.0f});
/* For cycles and eevee the spot attenuation is
* y = (1/(1 + x^2) - a)/((1 - a) b)
* We solve the case where spot attenuation y = 1 and y = 0
@@ -704,7 +708,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob)
case LIGHTPROBE_TYPE_CUBE:
instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
instdata.clip_end = show_clipping ? prb->clipend : -1.0;
- DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+ DRW_buffer_add_entry(cb->probe_cube, color_p, &instdata);
DRW_buffer_add_entry(cb->groundline, instdata.pos);
if (show_influence) {
@@ -1015,6 +1019,11 @@ static void camera_stereoscopy_extra(OVERLAY_ExtraCallBuffers *cb,
const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) != 0;
const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME) != 0;
+ if (!is_stereo3d_cameras) {
+ /* Draw single camera. */
+ DRW_buffer_add_entry_struct(cb->camera_frame, instdata);
+ }
+
for (int eye = 0; eye < 2; eye++) {
ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[eye], stereodata.mat);
@@ -1497,7 +1506,7 @@ static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb,
OVERLAY_PrivateData *pd,
ViewLayer *view_layer)
{
- const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
+ const bool is_library = ID_REAL_USERS(&ob->id) > 1 || ID_IS_LINKED(ob);
if (ob == OBACT(view_layer)) {
DRW_buffer_add_entry(cb->center_active, ob->obmat[3]);
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
index cda55fcfb5e..cf90c12b357 100644
--- a/source/blender/draw/engines/overlay/overlay_image.c
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -134,6 +134,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
float *r_aspect,
bool *r_use_alpha_premult)
{
+ void *lock;
Image *image = bgpic->ima;
ImageUser *iuser = &bgpic->iuser;
MovieClip *clip = NULL;
@@ -160,12 +161,19 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser);
}
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ iuser->scene = draw_ctx->scene;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
if (ibuf == NULL) {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ iuser->scene = NULL;
return NULL;
}
+ width = ibuf->x;
+ height = ibuf->y;
+ tex = GPU_texture_from_blender(image, iuser, ibuf, GL_TEXTURE_2D);
+ BKE_image_release_ibuf(image, ibuf, lock);
+ iuser->scene = NULL;
- tex = GPU_texture_from_blender(image, iuser, GL_TEXTURE_2D);
if (tex == NULL) {
return NULL;
}
@@ -173,10 +181,6 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp
aspect_x = bgpic->ima->aspx;
aspect_y = bgpic->ima->aspy;
- width = ibuf->x;
- height = ibuf->y;
-
- BKE_image_release_ibuf(image, ibuf, NULL);
break;
case CAM_BGIMG_SOURCE_MOVIE:
@@ -376,7 +380,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
* see: T59347 */
int size[2] = {0};
if (ima != NULL) {
- tex = GPU_texture_from_blender(ima, ob->iuser, GL_TEXTURE_2D);
+ tex = GPU_texture_from_blender(ima, ob->iuser, NULL, GL_TEXTURE_2D);
if (tex) {
size[0] = GPU_texture_orig_width(tex);
size[1] = GPU_texture_orig_height(tex);
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
index 047659fbeee..e88a69b695e 100644
--- a/source/blender/draw/engines/overlay/overlay_paint.c
+++ b/source/blender/draw/engines/overlay/overlay_paint.c
@@ -85,7 +85,7 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
- GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D);
+ GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, NULL, GL_TEXTURE_2D);
const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index b52434fa6c6..d3c513e5963 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -167,9 +167,10 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
/* Don't do that in edit Mesh mode, unless there is a modifier preview. */
if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
+ const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != NULL);
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
- const bool use_coloring = (use_wire && !is_edit_mode && !use_sculpt_pbvh &&
+ const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode &&
!has_edit_mesh_cage);
DRWShadingGroup *shgrp = NULL;
struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob);
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
index 4784d420e1d..0d01f67c6ea 100644
--- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
@@ -144,6 +144,8 @@ void main()
vec4 lines = vec4(neightbor_line0.z, neightbor_line1.z, neightbor_line2.z, neightbor_line3.z);
/* Count number of line neighbors. */
float blend = dot(vec4(0.25), step(0.001, lines));
+ /* Only do blend if there is more than 2 neighbor. This avoid loosing too much AA. */
+ blend = clamp(blend * 2.0 - 1.0, 0.0, 1.0);
fragColor = mix(fragColor, fragColor / fragColor.a, blend);
}
#endif
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index f5a3aa2c332..c77c89396af 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -57,6 +57,34 @@ bvec4 gather_edges(vec2 uv, uint ref)
return notEqual(ids, uvec4(ref));
}
+/* Clockwise */
+vec2 rotate_90(vec2 v)
+{
+ return vec2(v.y, -v.x);
+}
+vec2 rotate_180(vec2 v)
+{
+ return vec2(-v.x, -v.y);
+}
+vec2 rotate_270(vec2 v)
+{
+ return vec2(-v.y, v.x);
+}
+
+/* Counter-Clockwise */
+bvec4 rotate_90(bvec4 v)
+{
+ return v.yzwx;
+}
+bvec4 rotate_180(bvec4 v)
+{
+ return v.zwxy;
+}
+bvec4 rotate_270(bvec4 v)
+{
+ return v.wxyz;
+}
+
/* Apply offset to line endpoint based on surrounding edges infos. */
bool line_offset(bvec2 edges, vec2 ofs, inout vec2 line_point)
{
@@ -79,6 +107,7 @@ bool line_offset(bvec2 edges, vec2 ofs, inout vec2 line_point)
/* Use surrounding edges to approximate the outline direction to create smooth lines. */
void straight_line_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end)
{
+ /* Y_POS as reference. Other cases are rotated to match reference. */
line_end = vec2(1.5, 0.5 + PROXIMITY_OFS);
line_start = vec2(-line_end.x, line_end.y);
@@ -92,53 +121,50 @@ void straight_line_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2
}
}
-/* Compute line direction vector from the bottom left corner. */
-void diag_dir(bvec4 edges, out vec2 line_start, out vec2 line_end)
+vec2 diag_offset(bvec4 edges)
{
- /* TODO Improve diagonal antialiasing. */
+ /* X_NEG | Y_POS as reference. Other cases are rotated to match reference.
+ * So the line is comming from bottom left. */
if (all(edges.wz)) {
- line_start = vec2(-3.0, -0.5 + PROXIMITY_OFS);
- line_end = vec2(3.0, 0.5 + PROXIMITY_OFS);
+ /* Horizontal line. */
+ return vec2(2.5, 0.5);
}
else if (all(not(edges.xw))) {
- line_start = vec2(-0.5 - PROXIMITY_OFS, -3.0);
- line_end = vec2(0.5 - PROXIMITY_OFS, 3.0);
+ /* Vertical line. */
+ return vec2(0.5, 2.5);
}
else if (edges.w) {
- line_start = vec2(-1.0, -0.5 - PROXIMITY_OFS);
- line_end = vec2(2.0, 0.5 - PROXIMITY_OFS);
+ /* Less horizontal Line. */
+ return vec2(2.5, 0.5);
}
else {
- line_start = vec2(-0.6, -0.5 + PROXIMITY_OFS);
- line_end = vec2(0.6 - PROXIMITY_OFS, 0.5);
+ /* Less vertical Line. */
+ return vec2(0.5, 2.5);
}
}
-/* Clockwise */
-vec2 rotate_90(vec2 v)
-{
- return vec2(v.y, -v.x);
-}
-vec2 rotate_180(vec2 v)
-{
- return vec2(-v.x, -v.y);
-}
-vec2 rotate_270(vec2 v)
-{
- return vec2(-v.y, v.x);
-}
-/* Counter-Clockwise */
-bvec4 rotate_90(bvec4 v)
-{
- return v.yzwx;
-}
-bvec4 rotate_180(bvec4 v)
-{
- return v.zwxy;
-}
-bvec4 rotate_270(bvec4 v)
+/* Compute line direction vector from the bottom left corner. */
+void diag_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end)
{
- return v.wxyz;
+ /* Negate instead of rotating back the result of diag_offset. */
+ edges2 = not(edges2);
+ edges2 = rotate_180(edges2);
+ line_end = diag_offset(edges1);
+ line_end += diag_offset(edges2);
+
+ if (line_end.x == line_end.y) {
+ /* Perfect diagonal line. Push line start towards edge. */
+ line_start = vec2(-1.0, 1.0) * PROXIMITY_OFS * 0.4;
+ }
+ else if (line_end.x > line_end.y) {
+ /* Horizontal Line. Lower line start. */
+ line_start = vec2(0.0, PROXIMITY_OFS);
+ }
+ else {
+ /* Vertical Line. Push line start to the right. */
+ line_start = -vec2(PROXIMITY_OFS, 0.0);
+ }
+ line_end += line_start;
}
void main()
@@ -292,26 +318,33 @@ void main()
/* Diagonal */
case DIAG_XNEG_YPOS:
extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5), ref);
- diag_dir(extra_edges, line_start, line_end);
+ extra_edges2 = gather_edges(uvs + ofs.xy * vec2(-1.5), ref);
+ diag_dir(extra_edges, extra_edges2, line_start, line_end);
break;
case DIAG_XPOS_YNEG:
extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5), ref);
+ extra_edges2 = gather_edges(uvs - ofs.xy * vec2(-1.5), ref);
extra_edges = rotate_180(extra_edges);
- diag_dir(extra_edges, line_start, line_end);
+ extra_edges2 = rotate_180(extra_edges2);
+ diag_dir(extra_edges, extra_edges2, line_start, line_end);
line_start = rotate_180(line_start);
line_end = rotate_180(line_end);
break;
case DIAG_XPOS_YPOS:
extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5, -1.5), ref);
+ extra_edges2 = gather_edges(uvs - ofs.xy * vec2(1.5, -1.5), ref);
extra_edges = rotate_90(extra_edges);
- diag_dir(extra_edges, line_start, line_end);
+ extra_edges2 = rotate_90(extra_edges2);
+ diag_dir(extra_edges, extra_edges2, line_start, line_end);
line_start = rotate_90(line_start);
line_end = rotate_90(line_end);
break;
case DIAG_XNEG_YNEG:
extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5, -1.5), ref);
+ extra_edges2 = gather_edges(uvs + ofs.xy * vec2(1.5, -1.5), ref);
extra_edges = rotate_270(extra_edges);
- diag_dir(extra_edges, line_start, line_end);
+ extra_edges2 = rotate_270(extra_edges2);
+ diag_dir(extra_edges, extra_edges2, line_start, line_end);
line_start = rotate_270(line_start);
line_end = rotate_270(line_end);
break;
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
index 8ef89b89eb3..f6e3724eb51 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
@@ -1,10 +1,10 @@
-flat in int objectId;
+flat in uint objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
void main()
{
- outId = uint(objectId);
+ outId = objectId;
}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
index b32913dcd60..282799e1660 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
@@ -3,9 +3,9 @@ layout(lines_adjacency) in;
layout(line_strip, max_vertices = 2) out;
in vec3 vPos[];
-in int objectId_g[];
+in uint objectId_g[];
-flat out int objectId;
+flat out uint objectId;
void vert_from_gl_in(int v)
{
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
index 8b9854b2d3e..984e55b0c46 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
@@ -5,14 +5,14 @@ in vec3 pos;
#ifdef USE_GEOM
out vec3 vPos;
-out int objectId_g;
+out uint objectId_g;
# define objectId objectId_g
#else
-flat out int objectId;
+flat out uint objectId;
#endif
-int outline_colorid_get(void)
+uint outline_colorid_get(void)
{
int flag = int(abs(ObjectInfo.w));
bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0;
@@ -20,24 +20,24 @@ int outline_colorid_get(void)
if (is_from_dupli) {
if (isTransform) {
- return 0; /* colorTransform */
+ return 0u; /* colorTransform */
}
else {
- return 2; /* colorDupliSelect */
+ return 2u; /* colorDupliSelect */
}
}
if (isTransform) {
- return 0; /* colorTransform */
+ return 0u; /* colorTransform */
}
else if (is_active) {
- return 3; /* colorActive */
+ return 3u; /* colorActive */
}
else {
- return 1; /* colorSelect */
+ return 1u; /* colorSelect */
}
- return 0;
+ return 0u;
}
/* Replace top 2 bits (of the 16bit output) by outlineId.
@@ -56,13 +56,13 @@ void main()
gl_Position.z -= 1e-3;
/* ID 0 is nothing (background) */
- objectId = resource_handle + 1;
+ objectId = uint(resource_handle + 1);
/* Should be 2 bits only [0..3]. */
- int outline_id = outline_colorid_get();
+ uint outline_id = outline_colorid_get();
/* Combine for 16bit uint target. */
- objectId = (outline_id << 14) | ((objectId << SHIFT) >> SHIFT);
+ objectId = (outline_id << 14u) | ((objectId << SHIFT) >> SHIFT);
#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 21f8bcf1791..a2fa82d151e 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -105,7 +105,7 @@ void main()
vec3 wnor = normalize(normal_object_to_world(nor));
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
- vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrix[2].xyz;
+ vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz;
float facing = dot(wnor, V);
float facing_ratio = clamp(1.0 - facing * facing, 0.0, 1.0);
@@ -120,7 +120,7 @@ void main()
gl_Position.xy += wofs.xy * sizeViewportInv.xy * gl_Position.w;
/* Push the vertex towards the camera. Helps a bit. */
- gl_Position.z -= facing_ratio * curvature * 1e-4;
+ gl_Position.z -= facing_ratio * curvature * 4.0e-5;
/* Convert to screen position [0..sizeVp]. */
edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 23399056582..4701e544a04 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -156,9 +156,10 @@ static void select_cache_init(void *vedata)
{
SELECTID_PassList *psl = ((SELECTID_Data *)vedata)->psl;
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
+ SELECTID_PrivateData *pd = stl->g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
- SELECTID_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ SELECTID_Shaders *sh = &e_data.sh_data[draw_ctx->sh_cfg];
if (e_data.context.select_mode == -1) {
e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene,
@@ -166,57 +167,32 @@ static void select_cache_init(void *vedata)
BLI_assert(e_data.context.select_mode != 0);
}
- {
- psl->depth_only_pass = DRW_pass_create("Depth Only Pass", DRW_STATE_DEFAULT);
- stl->g_data->shgrp_depth_only = DRW_shgroup_create(sh_data->select_id_uniform,
- psl->depth_only_pass);
-
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->shgrp_depth_only, DRW_STATE_CLIP_PLANES);
- }
+ DRWState state = DRW_STATE_DEFAULT;
+ state |= RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d) ? DRW_STATE_CLIP_PLANES : 0;
- psl->select_id_face_pass = DRW_pass_create("Face Pass", DRW_STATE_DEFAULT);
+ {
+ DRW_PASS_CREATE(psl->depth_only_pass, state);
+ pd->shgrp_depth_only = DRW_shgroup_create(sh->select_id_uniform, psl->depth_only_pass);
+ DRW_PASS_CREATE(psl->select_id_face_pass, state);
if (e_data.context.select_mode & SCE_SELECT_FACE) {
- stl->g_data->shgrp_face_flat = DRW_shgroup_create(sh_data->select_id_flat,
- psl->select_id_face_pass);
-
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->shgrp_face_flat, DRW_STATE_CLIP_PLANES);
- }
+ pd->shgrp_face_flat = DRW_shgroup_create(sh->select_id_flat, psl->select_id_face_pass);
}
else {
- stl->g_data->shgrp_face_unif = DRW_shgroup_create(sh_data->select_id_uniform,
- psl->select_id_face_pass);
- DRW_shgroup_uniform_int_copy(stl->g_data->shgrp_face_unif, "id", 0);
-
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->shgrp_face_unif, DRW_STATE_CLIP_PLANES);
- }
+ pd->shgrp_face_unif = DRW_shgroup_create(sh->select_id_uniform, psl->select_id_face_pass);
+ DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "id", 0);
}
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
- psl->select_id_edge_pass = DRW_pass_create(
- "Edge Pass", DRW_STATE_DEFAULT | DRW_STATE_FIRST_VERTEX_CONVENTION);
-
- stl->g_data->shgrp_edge = DRW_shgroup_create(sh_data->select_id_flat,
- psl->select_id_edge_pass);
+ DRW_PASS_CREATE(psl->select_id_edge_pass, state | DRW_STATE_FIRST_VERTEX_CONVENTION);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->shgrp_edge, DRW_STATE_CLIP_PLANES);
- }
+ pd->shgrp_edge = DRW_shgroup_create(sh->select_id_flat, psl->select_id_edge_pass);
}
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
- psl->select_id_vert_pass = DRW_pass_create("Vert Pass", DRW_STATE_DEFAULT);
- stl->g_data->shgrp_vert = DRW_shgroup_create(sh_data->select_id_flat,
- psl->select_id_vert_pass);
- DRW_shgroup_uniform_float_copy(
- stl->g_data->shgrp_vert, "sizeVertex", G_draw.block.sizeVertex);
-
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->shgrp_vert, DRW_STATE_CLIP_PLANES);
- }
+ DRW_PASS_CREATE(psl->select_id_vert_pass, state);
+ pd->shgrp_vert = DRW_shgroup_create(sh->select_id_flat, psl->select_id_vert_pass);
+ DRW_shgroup_uniform_float_copy(pd->shgrp_vert, "sizeVertex", G_draw.block.sizeVertex);
}
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
index 59a463f49c3..c0d7719180b 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -140,6 +140,28 @@ vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
return matcap_uv * 0.496 + 0.5;
}
+bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
+{
+ vec2 tile_pos = floor(co.xy);
+
+ if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
+ return false;
+
+ float tile = 10.0 * tile_pos.y + tile_pos.x;
+ if (tile >= textureSize(map, 0).x)
+ return false;
+
+ /* Fetch tile information. */
+ float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
+ if (tile_layer < 0.0)
+ return false;
+
+ vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
+
+ co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
+ return true;
+}
+
vec4 workbench_sample_texture(sampler2D image,
vec2 coord,
bool nearest_sampling,
@@ -158,3 +180,28 @@ vec4 workbench_sample_texture(sampler2D image,
return color;
}
+
+vec4 workbench_sample_texture_array(sampler2DArray tile_array,
+ sampler1DArray tile_data,
+ vec2 coord,
+ bool nearest_sampling,
+ bool premultiplied)
+{
+ vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
+
+ vec3 uv = vec3(coord, 0);
+ if (!node_tex_tile_lookup(uv, tile_array, tile_data))
+ return vec4(1.0, 0.0, 1.0, 1.0);
+
+ /* 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;
+ vec4 color = texture(tile_array, uv);
+
+ /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
+ if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
+ color.rgb = color.rgb / color.a;
+ }
+
+ return color;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index f799ce41cb2..559dc07c107 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -1,6 +1,11 @@
uniform float ImageTransparencyCutoff = 0.1;
+#ifdef TEXTURE_IMAGE_ARRAY
+uniform sampler2DArray image_tile_array;
+uniform sampler1DArray image_tile_data;
+#else
uniform sampler2D image;
+#endif
uniform bool imageNearest;
uniform bool imagePremultiplied;
@@ -44,7 +49,12 @@ void main()
vec4 base_color;
#if defined(V3D_SHADING_TEXTURE_COLOR)
+# ifdef TEXTURE_IMAGE_ARRAY
+ base_color = workbench_sample_texture_array(
+ image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
+# else
base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
+# endif
if (base_color.a < ImageTransparencyCutoff) {
discard;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index b5f95f2dcf8..94e41b4bcd4 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -2,7 +2,12 @@
uniform vec4 materialColorAndMetal;
uniform float materialRoughness;
+#ifdef TEXTURE_IMAGE_ARRAY
+uniform sampler2DArray image_tile_array;
+uniform sampler1DArray image_tile_data;
+#else
uniform sampler2D image;
+#endif
uniform float ImageTransparencyCutoff = 0.1;
uniform bool imageNearest;
uniform bool imagePremultiplied;
@@ -39,7 +44,12 @@ void main()
vec4 color;
# if defined(V3D_SHADING_TEXTURE_COLOR)
+# ifdef TEXTURE_IMAGE_ARRAY
+ color = workbench_sample_texture_array(
+ image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
+# else
color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
+# endif
if (color.a < ImageTransparencyCutoff) {
discard;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 04dd9ab85bb..0a3252f0b9b 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -4,13 +4,18 @@ in vec3 pos;
in vec3 nor;
in vec2 au; /* active texture layer */
# ifdef V3D_SHADING_VERTEX_COLOR
-in vec3 ac; /* active color */
+in vec4 ac; /* active color */
# endif
# define uv au
#else /* HAIR_SHADER */
+
# ifdef V3D_SHADING_TEXTURE_COLOR
uniform samplerBuffer au; /* active texture layer */
# endif
+# ifdef V3D_SHADING_VERTEX_COLOR
+uniform samplerBuffer ac; /* active color layer */
+# endif
+
flat out float hair_rand;
#endif /* HAIR_SHADER */
@@ -37,16 +42,6 @@ float integer_noise(int n)
return (float(nn) / 1073741824.0);
}
-#ifdef V3D_SHADING_VERTEX_COLOR
-vec3 srgb_to_linear_attr(vec3 c)
-{
- c = max(c, vec3(0.0));
- vec3 c1 = c * (1.0 / 12.92);
- vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
- return mix(c1, c2, step(vec3(0.04045), c));
-}
-#endif
-
vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand)
{
/* To "simulate" anisotropic shading, randomize hair normal per strand. */
@@ -90,7 +85,9 @@ void main()
#ifdef V3D_SHADING_VERTEX_COLOR
# ifndef HAIR_SHADER
- vertexColor = srgb_to_linear_attr(ac);
+ vertexColor = ac.rgb;
+# else
+ vertexColor = hair_get_customdata_vec4(ac).rgb;
# endif
#endif
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 02a3af7fa73..26402e66318 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -214,16 +214,17 @@ static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature)
static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override,
eGPUShaderConfig sh_cfg)
{
WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg];
int index = workbench_material_get_prepass_shader_index(
- wpd, is_uniform_color, is_hair, color_override);
+ wpd, is_uniform_color, is_hair, is_tiled, color_override);
if (sh_data->prepass_sh_cache[index] == NULL) {
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, color_override);
+ wpd, is_uniform_color, is_hair, is_tiled, color_override);
char *prepass_vert = workbench_build_prepass_vert(is_hair);
char *prepass_frag = workbench_build_prepass_frag();
sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({
@@ -243,7 +244,7 @@ static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd)
int index = workbench_material_get_composite_shader_index(wpd);
if (e_data.composite_sh_cache[index] == NULL) {
char *defines = workbench_material_build_defines(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *composite_frag = workbench_build_composite_frag(wpd);
e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
MEM_freeN(composite_frag);
@@ -271,17 +272,19 @@ static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd)
static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
{
wpd->prepass_sh = ensure_deferred_prepass_shader(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->prepass_hair_sh = ensure_deferred_prepass_shader(
- wpd, false, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->prepass_uniform_sh = ensure_deferred_prepass_shader(
- wpd, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader(
- wpd, true, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->prepass_textured_sh = ensure_deferred_prepass_shader(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
+ wpd->prepass_textured_array_sh = ensure_deferred_prepass_shader(
+ wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
wpd->prepass_vertex_sh = ensure_deferred_prepass_shader(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
wpd->composite_sh = ensure_deferred_composite_shader(wpd);
wpd->background_sh = ensure_background_shader(wpd);
}
@@ -873,8 +876,9 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
/* select the correct prepass shader */
GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh :
wpd->prepass_uniform_sh;
+ const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- shader = wpd->prepass_textured_sh;
+ shader = is_tiled ? wpd->prepass_textured_array_sh : wpd->prepass_textured_sh;
}
if (color_type == V3D_SHADING_VERTEX_COLOR) {
shader = wpd->prepass_vertex_sh;
@@ -883,7 +887,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat
shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
workbench_material_copy(material, &material_template);
DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, interp);
+ workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, is_tiled, interp);
BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
}
return material;
@@ -926,7 +930,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
(ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
shader);
DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, false, interp);
}
}
}
@@ -958,7 +962,7 @@ static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata,
}
else {
/* IMAGEPAINT_MODE_MATERIAL */
- const int materials_len = MAX2(1, ob->totcol);
+ const int materials_len = DRW_cache_object_material_count_get(ob);
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
if (geom_array != NULL && geom_array[i] != NULL) {
@@ -1027,9 +1031,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
WORKBENCH_MaterialData *material;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
const bool is_active = (ob == draw_ctx->obact);
- const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
- const int materials_len = MAX2(1, ob->totcol);
+ const int materials_len = DRW_cache_object_material_count_get(ob);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
bool has_transp_mat = false;
const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
@@ -1133,8 +1138,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
- geoms = DRW_cache_object_surface_material_get(
- ob, gpumat_array, materials_len, NULL, NULL, NULL);
+ geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
for (int i = 0; i < materials_len; i++) {
if (geoms != NULL && geoms[i] != NULL) {
Material *mat = give_current_material(ob, i + 1);
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 44f43fc7d09..97bea58f31b 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -172,8 +172,10 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
GPUShader *shader = (wpd->shading.color_type == color_type) ?
wpd->transparent_accum_sh :
wpd->transparent_accum_uniform_sh;
+ const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
- shader = wpd->transparent_accum_textured_sh;
+ shader = is_tiled ? wpd->transparent_accum_textured_array_sh :
+ wpd->transparent_accum_textured_sh;
}
grp = DRW_shgroup_create(shader, psl->transparent_accum_pass);
@@ -201,14 +203,15 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
}
- workbench_material_shgroup_uniform(wpd, grp, material, ob, false, interp);
+ workbench_material_shgroup_uniform(wpd, grp, material, ob, false, is_tiled, interp);
material->shgrp = grp;
/* Depth */
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh,
psl->object_outline_pass);
- GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
+ GPUTexture *tex = GPU_texture_from_blender(
+ material->ima, material->iuser, NULL, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
}
else {
@@ -226,16 +229,17 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override,
eGPUShaderConfig sh_cfg)
{
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
int index = workbench_material_get_accum_shader_index(
- wpd, is_uniform_color, is_hair, color_override);
+ wpd, is_uniform_color, is_hair, is_tiled, color_override);
if (sh_data->transparent_accum_sh_cache[index] == NULL) {
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
char *defines = workbench_material_build_defines(
- wpd, is_uniform_color, is_hair, color_override);
+ wpd, is_uniform_color, is_hair, is_tiled, color_override);
char *transparent_accum_vert = workbench_build_forward_vert(is_hair);
char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag();
sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({
@@ -255,7 +259,7 @@ static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd)
int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
if (e_data.composite_sh_cache[index] == NULL) {
char *defines = workbench_material_build_defines(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *composite_frag = workbench_build_forward_composite_frag();
e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
MEM_freeN(composite_frag);
@@ -268,17 +272,19 @@ void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConf
{
wpd->composite_sh = ensure_forward_composite_shaders(wpd);
wpd->transparent_accum_sh = ensure_forward_accum_shaders(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(
- wpd, false, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(
- wpd, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(
- wpd, true, true, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
+ wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
+ wpd->transparent_accum_textured_array_sh = ensure_forward_accum_shaders(
+ wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
}
void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
@@ -288,11 +294,11 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh
if (sh_data->object_outline_sh == NULL) {
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
char *defines = workbench_material_build_defines(
- wpd, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
+ wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *defines_texture = workbench_material_build_defines(
- wpd, true, false, WORKBENCH_COLOR_OVERRIDE_OFF);
+ wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *defines_hair = workbench_material_build_defines(
- wpd, false, true, WORKBENCH_COLOR_OVERRIDE_OFF);
+ wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF);
char *forward_vert = workbench_build_forward_vert(false);
char *forward_frag = workbench_build_forward_outline_frag();
char *forward_hair_vert = workbench_build_forward_vert(true);
@@ -533,7 +539,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
ob, psys, md, psl->transparent_accum_pass, shader);
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
- workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, interp);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
/* Hairs have lots of layer and can rapidly become the most prominent surface.
* So lower their alpha artificially. */
@@ -589,7 +595,7 @@ static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *
}
else {
/* IMAGEPAINT_MODE_MATERIAL */
- const int materials_len = MAX2(1, ob->totcol);
+ const int materials_len = DRW_cache_object_material_count_get(ob);
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
if (geom_array != NULL && geom_array[i] != NULL) {
@@ -663,7 +669,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
- const int materials_len = MAX2(1, ob->totcol);
+ const int materials_len = DRW_cache_object_material_count_get(ob);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
@@ -751,7 +757,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
- ob, gpumat_array, materials_len, NULL, NULL, NULL);
+ ob, gpumat_array, materials_len);
if (mat_geom) {
for (int i = 0; i < materials_len; i++) {
if (mat_geom[i] == NULL) {
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 16fcda54253..fc054b11d55 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -85,6 +85,7 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override)
{
char *str = NULL;
@@ -102,6 +103,7 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
use_textures = false;
use_vertex_colors = true;
is_hair = false;
+ is_tiled = false;
break;
case WORKBENCH_COLOR_OVERRIDE_OFF:
break;
@@ -151,6 +153,9 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
if (is_hair) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
+ if (use_textures && is_tiled) {
+ BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
+ }
str = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -211,6 +216,7 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override)
{
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
@@ -225,6 +231,7 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
case WORKBENCH_COLOR_OVERRIDE_VERTEX:
use_textures = false;
use_vertex_colors = true;
+ is_tiled = false;
break;
case WORKBENCH_COLOR_OVERRIDE_OFF:
break;
@@ -239,6 +246,7 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4);
SET_FLAG_FROM_TEST(index, use_textures, 1 << 5);
SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 6);
+ SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
BLI_assert(index < MAX_PREPASS_SHADERS);
return index;
}
@@ -246,6 +254,7 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override)
{
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
@@ -262,6 +271,7 @@ int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
use_textures = false;
use_vertex_colors = true;
is_hair = false;
+ is_tiled = false;
break;
case WORKBENCH_COLOR_OVERRIDE_OFF:
break;
@@ -277,6 +287,7 @@ int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
/* 1 bits SHADOWS (only facing factor) */
SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5);
SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
+ SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
BLI_assert(index < MAX_ACCUM_SHADERS);
return index;
}
@@ -352,6 +363,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
WORKBENCH_MaterialData *material,
Object *ob,
const bool deferred,
+ const bool is_tiled,
const int interp)
{
if (deferred && !workbench_is_matdata_pass_enabled(wpd)) {
@@ -362,8 +374,19 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
wpd, material->ima, ob, false));
if (use_texture) {
- GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "image", tex);
+ if (is_tiled) {
+ GPUTexture *array_tex = GPU_texture_from_blender(
+ material->ima, material->iuser, NULL, GL_TEXTURE_2D_ARRAY);
+ GPUTexture *data_tex = GPU_texture_from_blender(
+ material->ima, material->iuser, NULL, GL_TEXTURE_1D_ARRAY);
+ DRW_shgroup_uniform_texture(grp, "image_tile_array", array_tex);
+ DRW_shgroup_uniform_texture(grp, "image_tile_data", data_tex);
+ }
+ else {
+ GPUTexture *tex = GPU_texture_from_blender(
+ material->ima, material->iuser, NULL, GL_TEXTURE_2D);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ }
DRW_shgroup_uniform_bool_copy(
grp, "imagePremultiplied", (material->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_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 7c774ca7490..e100f6e875c 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -37,8 +37,8 @@
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
#define M_GOLDEN_RATION_CONJUGATE 0.618033988749895
#define MAX_COMPOSITE_SHADERS (1 << 7)
-#define MAX_PREPASS_SHADERS (1 << 7)
-#define MAX_ACCUM_SHADERS (1 << 7)
+#define MAX_PREPASS_SHADERS (1 << 8)
+#define MAX_ACCUM_SHADERS (1 << 8)
#define MAX_CAVITY_SHADERS (1 << 3)
#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR)
@@ -207,6 +207,7 @@ typedef struct WORKBENCH_PrivateData {
struct GPUShader *prepass_uniform_sh;
struct GPUShader *prepass_uniform_hair_sh;
struct GPUShader *prepass_textured_sh;
+ struct GPUShader *prepass_textured_array_sh;
struct GPUShader *prepass_vertex_sh;
struct GPUShader *composite_sh;
struct GPUShader *background_sh;
@@ -215,6 +216,7 @@ typedef struct WORKBENCH_PrivateData {
struct GPUShader *transparent_accum_uniform_sh;
struct GPUShader *transparent_accum_uniform_hair_sh;
struct GPUShader *transparent_accum_textured_sh;
+ struct GPUShader *transparent_accum_textured_array_sh;
struct GPUShader *transparent_accum_vertex_sh;
View3DShading shading;
StudioLight *studio_light;
@@ -516,6 +518,7 @@ void workbench_material_get_image_and_mat(
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override);
void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
Object *ob,
@@ -527,16 +530,19 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd);
int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override);
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
bool is_uniform_color,
bool is_hair,
+ bool is_tiled,
const WORKBENCH_ColorOverride color_override);
void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
Object *ob,
const bool deferred,
+ const bool is_tiled,
const int interp);
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
const WORKBENCH_MaterialData *source_material);
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 69135f8ade3..6bb58bf8795 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -824,27 +824,33 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
}
}
-GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
- struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count)
+int DRW_cache_object_material_count_get(struct Object *ob)
{
- if (auto_layer_names != NULL) {
- *auto_layer_names = NULL;
- *auto_layer_is_srgb = NULL;
- *auto_layer_count = 0;
+ Mesh *me = (ob->runtime.mesh_eval != NULL) ? ob->runtime.mesh_eval : (Mesh *)ob->data;
+ short type = (ob->runtime.mesh_eval != NULL) ? OB_MESH : ob->type;
+
+ switch (type) {
+ case OB_MESH:
+ return DRW_mesh_material_count_get(me);
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ return DRW_curve_material_count_get(ob->data);
+ case OB_MBALL:
+ return DRW_metaball_material_count_get(ob->data);
+ default:
+ BLI_assert(0);
+ return 0;
}
+}
+GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
+ struct GPUMaterial **gpumat_array,
+ uint gpumat_array_len)
+{
switch (ob->type) {
case OB_MESH:
- return DRW_cache_mesh_surface_shaded_get(ob,
- gpumat_array,
- gpumat_array_len,
- auto_layer_names,
- auto_layer_is_srgb,
- auto_layer_count);
+ return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
case OB_CURVE:
return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
case OB_SURF:
@@ -1222,10 +1228,11 @@ GPUBatch *DRW_cache_field_curve_get(void)
GPUBatch *DRW_cache_field_tube_limit_get(void)
{
#define CIRCLE_RESOL 32
+#define SIDE_STIPPLE 32
if (!SHC.drw_field_tube_limit) {
GPUVertFormat format = extra_vert_format();
- int v_len = 2 * (CIRCLE_RESOL * 2 + 4);
+ int v_len = 2 * (CIRCLE_RESOL * 2 + 4 * SIDE_STIPPLE / 2);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
@@ -1233,14 +1240,14 @@ GPUBatch *DRW_cache_field_tube_limit_get(void)
int flag = VCLASS_EMPTY_SIZE;
/* Caps */
for (int i = 0; i < 2; i++) {
- float z = (float)i * 2.0f - 1.0f;
- circle_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
+ float z = i * 2.0f - 1.0f;
+ circle_dashed_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
}
/* Side Edges */
for (int a = 0; a < 4; a++) {
- for (int i = 0; i < 2; i++) {
- float z = (float)i * 2.0f - 1.0f;
- float angle = (2.0f * M_PI * a) / 4.0f;
+ float angle = (2.0f * M_PI * a) / 4.0f;
+ for (int i = 0; i < SIDE_STIPPLE; i++) {
+ float z = (i / (float)SIDE_STIPPLE) * 2.0f - 1.0f;
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{sinf(angle), cosf(angle), z}, flag});
}
}
@@ -1248,16 +1255,18 @@ GPUBatch *DRW_cache_field_tube_limit_get(void)
SHC.drw_field_tube_limit = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_field_tube_limit;
+#undef SIDE_STIPPLE
#undef CIRCLE_RESOL
}
GPUBatch *DRW_cache_field_cone_limit_get(void)
{
#define CIRCLE_RESOL 32
+#define SIDE_STIPPLE 32
if (!SHC.drw_field_cone_limit) {
GPUVertFormat format = extra_vert_format();
- int v_len = 2 * (CIRCLE_RESOL * 2 + 4);
+ int v_len = 2 * (CIRCLE_RESOL * 2 + 4 * SIDE_STIPPLE / 2);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, v_len);
@@ -1265,14 +1274,14 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
int flag = VCLASS_EMPTY_SIZE;
/* Caps */
for (int i = 0; i < 2; i++) {
- float z = (float)i * 2.0f - 1.0f;
- circle_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
+ float z = i * 2.0f - 1.0f;
+ circle_dashed_verts(vbo, &v, CIRCLE_RESOL, 1.0f, z, flag);
}
/* Side Edges */
for (int a = 0; a < 4; a++) {
- for (int i = 0; i < 2; i++) {
- float z = (float)i * 2.0f - 1.0f;
- float angle = (2.0f * M_PI * a) / 4.0f;
+ float angle = (2.0f * M_PI * a) / 4.0f;
+ for (int i = 0; i < SIDE_STIPPLE; i++) {
+ float z = (i / (float)SIDE_STIPPLE) * 2.0f - 1.0f;
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{sinf(angle) * z, cosf(angle) * z, z}, flag});
}
}
@@ -1280,6 +1289,7 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
SHC.drw_field_cone_limit = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_field_cone_limit;
+#undef SIDE_STIPPLE
#undef CIRCLE_RESOL
}
@@ -1636,45 +1646,52 @@ GPUBatch *DRW_cache_speaker_get(void)
GPUBatch *DRW_cache_lightprobe_cube_get(void)
{
if (!SHC.drw_lightprobe_cube) {
- int v_idx = 0;
+ GPUVertFormat format = extra_vert_format();
+
+ int v_len = (6 + 3 + (1 + 2 * DIAMOND_NSEGMENTS) * 6) * 2;
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, v_len);
+
+ const float r = 14.0f;
+ int v = 0;
+ int flag = VCLASS_SCREENSPACE;
+ /* Icon */
const float sin_pi_3 = 0.86602540378f;
const float cos_pi_3 = 0.5f;
- const float v[7][3] = {
- {0.0f, 1.0f, 0.0f},
- {sin_pi_3, cos_pi_3, 0.0f},
- {sin_pi_3, -cos_pi_3, 0.0f},
- {0.0f, -1.0f, 0.0f},
- {-sin_pi_3, -cos_pi_3, 0.0f},
- {-sin_pi_3, cos_pi_3, 0.0f},
- {0.0f, 0.0f, 0.0f},
+ const float p[7][2] = {
+ {0.0f, 1.0f},
+ {sin_pi_3, cos_pi_3},
+ {sin_pi_3, -cos_pi_3},
+ {0.0f, -1.0f},
+ {-sin_pi_3, -cos_pi_3},
+ {-sin_pi_3, cos_pi_3},
+ {0.0f, 0.0f},
};
-
- /* Position Only 3D format */
- static GPUVertFormat format = {0};
- static struct {
- uint pos;
- } attr_id;
- if (format.attr_len == 0) {
- attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ for (int i = 0; i < 6; i++) {
+ float t1[2], t2[2];
+ copy_v2_v2(t1, p[i]);
+ copy_v2_v2(t2, p[(i + 1) % 6]);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{t1[0] * r, t1[1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{t2[0] * r, t2[1] * r, 0.0f}, flag});
}
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, (6 + 3) * 2);
-
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[1][0] * r, p[1][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[6][0] * r, p[6][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[5][0] * r, p[5][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[6][0] * r, p[6][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[3][0] * r, p[3][1] * r, 0.0f}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{p[6][0] * r, p[6][1] * r, 0.0f}, flag});
+ /* Direction Lines */
+ flag = VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE;
for (int i = 0; i < 6; i++) {
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
+ char axes[] = "zZyYxX";
+ float zsta = light_distance_z_get(axes[i], true);
+ float zend = light_distance_z_get(axes[i], false);
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, zsta}, flag});
+ GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0f, 0.0f, zend}, flag});
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zsta, flag);
+ circle_verts(vbo, &v, DIAMOND_NSEGMENTS, 1.2f, zend, flag);
}
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
-
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
- GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
-
SHC.drw_lightprobe_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
}
return SHC.drw_lightprobe_cube;
@@ -2726,18 +2743,10 @@ GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count)
+ uint gpumat_array_len)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_shaded(ob->data,
- gpumat_array,
- gpumat_array_len,
- auto_layer_names,
- auto_layer_is_srgb,
- auto_layer_count);
+ return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len);
}
/* Return list of batches with length equal to max(1, totcol). */
@@ -2888,8 +2897,7 @@ GPUBatch **DRW_cache_curve_surface_shaded_get(Object *ob,
struct Curve *cu = ob->data;
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(
- mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
+ return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
else {
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
@@ -3029,8 +3037,7 @@ GPUBatch **DRW_cache_text_surface_shaded_get(Object *ob,
return NULL;
}
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(
- mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
+ return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
else {
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
@@ -3124,8 +3131,7 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
struct Curve *cu = ob->data;
struct Mesh *mesh_eval = ob->runtime.mesh_eval;
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(
- mesh_eval, gpumat_array, gpumat_array_len, NULL, NULL, NULL);
+ return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
else {
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 11564464546..508a6f2c46d 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -54,11 +54,9 @@ struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob);
struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count);
+ uint gpumat_array_len);
struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob);
+int DRW_cache_object_material_count_get(struct Object *ob);
/* Empties */
struct GPUBatch *DRW_cache_plain_axes_get(void);
@@ -127,10 +125,7 @@ struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_edges_get(struct Object *ob);
struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count);
+ uint gpumat_array_len);
struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob);
@@ -138,8 +133,6 @@ struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob);
-void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob);
-
/* Curve */
struct GPUBatch *DRW_cache_curve_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_curve_surface_shaded_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 7ee02c3c556..9228147af44 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -213,12 +213,6 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
- /* arrays of bool uniform names (and value) that will be use to
- * set srgb conversion for auto attributes.*/
- char *auto_layer_names;
- int *auto_layer_is_srgb;
- int auto_layer_len;
-
DRWBatchFlag batch_requested;
DRWBatchFlag batch_ready;
@@ -253,6 +247,8 @@ typedef struct MeshBatchCache {
void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
MeshBufferCache mbc,
Mesh *me,
+ const bool is_editmode,
+ const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
const bool use_subsurf_fdots,
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index 4bd0aac1ecc..ee0597c6b21 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -95,6 +95,9 @@ typedef struct MeshRenderData {
bool use_subsurf_fdots;
bool use_final_mesh;
+ /** Use for #MeshStatVis calculation which use world-space coords. */
+ float obmat[4][4];
+
const ToolSettings *toolsettings;
/* HACK not supposed to be there but it's needed. */
struct MeshBatchCache *cache;
@@ -125,6 +128,8 @@ typedef struct MeshRenderData {
} MeshRenderData;
static MeshRenderData *mesh_render_data_create(Mesh *me,
+ const bool is_editmode,
+ const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
const eMRIterType iter_type,
@@ -136,10 +141,12 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
mr->toolsettings = ts;
mr->mat_len = mesh_render_mat_len_get(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 (me->edit_mesh) {
+ 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;
@@ -678,6 +685,18 @@ static void extract_lines_loose_ledge_mesh(const MeshRenderData *UNUSED(mr),
* `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))
@@ -696,7 +715,7 @@ static const MeshExtract extract_lines_loose = {
NULL,
NULL,
NULL,
- NULL,
+ extract_lines_loose_ledge_bmesh,
extract_lines_loose_ledge_mesh,
NULL,
NULL,
@@ -1909,7 +1928,7 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
GPU_vertformat_alias_add(&format, "c");
@@ -1929,12 +1948,20 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- MLoopCol *vcol_data = (MLoopCol *)vbo->data;
+ typedef struct gpuMeshVcol {
+ ushort r, g, b, a;
+ } gpuMeshVcol;
+
+ gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data;
for (int i = 0; i < 8; i++) {
if (vcol_layers & (1 << i)) {
- void *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
- memcpy(vcol_data, layer_data, sizeof(*vcol_data) * mr->loop_len);
- vcol_data += mr->loop_len;
+ 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));
+ }
}
}
return NULL;
@@ -2652,6 +2679,7 @@ static void extract_edituv_data_loop_bmesh(const MeshRenderData *mr,
EditLoopData *eldata = data->vbo_data + l;
memset(eldata, 0x0, sizeof(*eldata));
mesh_render_data_loop_flag(mr, loop, data->cd_ofs, eldata);
+ mesh_render_data_face_flag(mr, loop->f, data->cd_ofs, eldata);
mesh_render_data_loop_edge_flag(mr, loop, data->cd_ofs, eldata);
}
@@ -3090,11 +3118,9 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
axis_from_enum_v3(dir, axis);
- if (em && LIKELY(em->ob)) {
- /* now convert into global space */
- mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
- normalize_v3(dir);
- }
+ /* now convert into global space */
+ mul_transposed_mat3_m4_v3(mr->obmat, dir);
+ normalize_v3(dir);
if (mr->extract_type == MR_EXTRACT_BMESH) {
int l = 0;
@@ -3152,7 +3178,7 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
/* cheating to avoid another allocation */
float *face_dists = r_thickness + (mr->loop_len - mr->poly_len);
BMEditMesh *em = mr->edit_bmesh;
- const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
+ const float scale = 1.0f / mat4_to_scale(mr->obmat);
const MeshStatVis *statvis = &mr->toolsettings->statvis;
const float min = statvis->thickness_min * scale;
const float max = statvis->thickness_max * scale;
@@ -4362,6 +4388,8 @@ static void extract_task_create(TaskPool *task_pool,
void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
MeshBufferCache mbc,
Mesh *me,
+ const bool is_editmode,
+ const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
const bool use_subsurf_fdots,
@@ -4422,7 +4450,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
#endif
MeshRenderData *mr = mesh_render_data_create(
- me, do_final, do_uvedit, iter_flag, data_flag, cd_layer_used, ts);
+ me, is_editmode, obmat, do_final, do_uvedit, iter_flag, data_flag, cd_layer_used, ts);
mr->cache = cache; /* HACK */
mr->use_hide = use_hide;
mr->use_subsurf_fdots = use_subsurf_fdots;
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 8cb318bd0bb..755f794d201 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -69,6 +69,8 @@ void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
/* Curve */
void DRW_curve_batch_cache_create_requested(struct Object *ob);
+int DRW_curve_material_count_get(struct Curve *cu);
+
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);
@@ -80,7 +82,10 @@ struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
struct GPUBatch *DRW_curve_batch_cache_get_wireframes_face(struct Curve *cu);
+
/* Metaball */
+int DRW_metaball_material_count_get(struct MetaBall *mb);
+
struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
struct GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(struct Object *ob,
struct MetaBall *mb,
@@ -93,9 +98,10 @@ struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
/* DispList */
void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb, struct GPUVertBuf *vbo);
void DRW_displist_vertbuf_create_wiredata(struct ListBase *lb, struct GPUVertBuf *vbo);
-void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(struct ListBase *lb,
- struct GPUVertBuf *vbo_pos_nor,
- struct GPUVertBuf *vbo_uv);
+void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(struct ListBase *lb,
+ struct GPUVertBuf *vbo_pos_nor,
+ struct GPUVertBuf *vbo_uv,
+ struct GPUVertBuf *vbo_tan);
void DRW_displist_indexbuf_create_lines_in_order(struct ListBase *lb, struct GPUIndexBuf *ibo);
void DRW_displist_indexbuf_create_triangles_in_order(struct ListBase *lb, struct GPUIndexBuf *ibo);
void DRW_displist_indexbuf_create_triangles_loop_split_by_material(struct ListBase *lb,
@@ -127,10 +133,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Mesh *me);
struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count);
+ uint gpumat_array_len);
struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me);
@@ -163,6 +166,8 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me);
+int DRW_mesh_material_count_get(struct Mesh *me);
+
/* Edit mesh bitflags (is this the right place?) */
enum {
VFLAG_VERT_ACTIVE = 1 << 0,
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c
index ab800e42cc0..85340fae35d 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.c
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -333,8 +333,7 @@ static void curve_cd_calc_used_gpu_layers(int *cd_layers,
*cd_layers |= CD_MLOOPUV;
break;
case CD_TANGENT:
- /* Currently unsupported */
- // *cd_layers |= CD_TANGENT;
+ *cd_layers |= CD_TANGENT;
break;
case CD_MCOL:
/* Curve object don't have Color data. */
@@ -358,6 +357,7 @@ typedef struct CurveBatchCache {
GPUVertBuf *loop_pos_nor;
GPUVertBuf *loop_uv;
+ GPUVertBuf *loop_tan;
} ordered;
struct {
@@ -414,7 +414,7 @@ static bool curve_batch_cache_valid(Curve *cu)
return false;
}
- if (cache->mat_len != max_ii(1, cu->totcol)) {
+ if (cache->mat_len != DRW_curve_material_count_get(cu)) {
return false;
}
@@ -914,6 +914,11 @@ GPUBatch *DRW_curve_batch_cache_get_edge_detection(Curve *cu, bool *r_is_manifol
return DRW_batch_request(&cache->batch.edge_detection);
}
+int DRW_curve_material_count_get(Curve *cu)
+{
+ return max_ii(1, cu->totcol);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -987,6 +992,9 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
if (cache->cd_used & CD_MLOOPUV) {
DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_uv);
}
+ if (cache->cd_used & CD_TANGENT) {
+ DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_tan);
+ }
DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_pos_nor);
}
}
@@ -1002,6 +1010,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE);
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_pos_nor, CU_DATATYPE_SURFACE);
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_uv, CU_DATATYPE_SURFACE);
+ DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_tan, CU_DATATYPE_SURFACE);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_tris, CU_DATATYPE_SURFACE);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_lines, CU_DATATYPE_SURFACE);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE);
@@ -1040,8 +1049,8 @@ 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_displist_vertbuf_create_loop_pos_and_nor_and_uv(
- lb, cache->ordered.loop_pos_nor, cache->ordered.loop_uv);
+ 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);
}
if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) {
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
index eef108b1f2f..50979d72189 100644
--- a/source/blender/draw/intern/draw_cache_impl_displist.c
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -33,6 +33,7 @@
#include "DNA_curve_types.h"
#include "BKE_displist.h"
+#include "BKE_displist_tangent.h"
#include "GPU_batch.h"
#include "GPU_extensions.h"
@@ -345,6 +346,8 @@ static void surf_uv_quad(const DispList *dl, const uint quad[4], float r_uv[4][2
}
for (int i = 0; i < 4; i++) {
+ /* Note: For some reason the shading U and V are swapped compared to the
+ * one described in the surface format. */
/* find uv based on vertex index into grid array */
r_uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev;
r_uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu;
@@ -362,12 +365,16 @@ static void surf_uv_quad(const DispList *dl, const uint quad[4], float r_uv[4][2
static void displist_vertbuf_attr_set_tri_pos_nor_uv(GPUVertBufRaw *pos_step,
GPUVertBufRaw *nor_step,
GPUVertBufRaw *uv_step,
+ GPUVertBufRaw *tan_step,
const float v1[3],
const float v2[3],
const float v3[3],
const GPUPackedNormal *n1,
const GPUPackedNormal *n2,
const GPUPackedNormal *n3,
+ const GPUPackedNormal *t1,
+ const GPUPackedNormal *t2,
+ const GPUPackedNormal *t3,
const float uv1[2],
const float uv2[2],
const float uv3[2])
@@ -387,16 +394,72 @@ static void displist_vertbuf_attr_set_tri_pos_nor_uv(GPUVertBufRaw *pos_step,
normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv2);
normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv3);
}
+
+ if (tan_step->size != 0) {
+ *(GPUPackedNormal *)GPU_vertbuf_raw_step(tan_step) = *t1;
+ *(GPUPackedNormal *)GPU_vertbuf_raw_step(tan_step) = *t2;
+ *(GPUPackedNormal *)GPU_vertbuf_raw_step(tan_step) = *t3;
+ }
+}
+
+#define SURFACE_QUAD_ITER_START(dl) \
+ { \
+ uint quad[4]; \
+ int quad_index = 0; \
+ int max_v = (dl->flag & DL_CYCL_V) ? dl->parts : (dl->parts - 1); \
+ int max_u = (dl->flag & DL_CYCL_U) ? dl->nr : (dl->nr - 1); \
+ for (int v = 0; v < max_v; v++) { \
+ quad[3] = dl->nr * v; \
+ quad[0] = quad[3] + 1; \
+ quad[2] = quad[3] + dl->nr; \
+ quad[1] = quad[0] + dl->nr; \
+ /* Cyclic wrap */ \
+ if (v == dl->parts - 1) { \
+ quad[1] -= dl->parts * dl->nr; \
+ quad[2] -= dl->parts * dl->nr; \
+ } \
+ for (int u = 0; u < max_u; u++, quad_index++) { \
+ /* Cyclic wrap */ \
+ if (u == dl->nr - 1) { \
+ quad[0] -= dl->nr; \
+ quad[1] -= dl->nr; \
+ }
+
+#define SURFACE_QUAD_ITER_END \
+ quad[2] = quad[1]; \
+ quad[1]++; \
+ quad[3] = quad[0]; \
+ quad[0]++; \
+ } \
+ } \
+ }
+
+static void displist_surf_fnors_ensure(const DispList *dl, float (**fnors)[3])
+{
+ int u_len = dl->nr - ((dl->flag & DL_CYCL_U) ? 0 : 1);
+ int v_len = dl->parts - ((dl->flag & DL_CYCL_V) ? 0 : 1);
+ const float(*verts)[3] = (float(*)[3])dl->verts;
+ float(*nor_flat)[3] = MEM_mallocN(sizeof(float) * 3 * u_len * v_len, __func__);
+ *fnors = nor_flat;
+
+ SURFACE_QUAD_ITER_START(dl)
+ {
+ normal_quad_v3(*nor_flat, verts[quad[0]], verts[quad[1]], verts[quad[2]], verts[quad[3]]);
+ nor_flat++;
+ }
+ SURFACE_QUAD_ITER_END
}
-void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
- GPUVertBuf *vbo_pos_nor,
- GPUVertBuf *vbo_uv)
+void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb,
+ GPUVertBuf *vbo_pos_nor,
+ GPUVertBuf *vbo_uv,
+ GPUVertBuf *vbo_tan)
{
static GPUVertFormat format_pos_nor = {0};
static GPUVertFormat format_uv = {0};
+ static GPUVertFormat format_tan = {0};
static struct {
- uint pos, nor, uv;
+ uint pos, nor, uv, tan;
} attr_id;
if (format_pos_nor.attr_len == 0) {
/* initialize vertex format */
@@ -404,9 +467,15 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
&format_pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
attr_id.nor = GPU_vertformat_attr_add(
&format_pos_nor, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
/* UVs are in [0..1] range. We can compress them. */
attr_id.uv = GPU_vertformat_attr_add(
&format_uv, "u", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_alias_add(&format_uv, "au");
+
+ attr_id.tan = GPU_vertformat_attr_add(
+ &format_tan, "t", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_alias_add(&format_tan, "at");
}
int vbo_len_capacity = curve_render_surface_tri_len_get(lb) * 3;
@@ -414,6 +483,7 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
GPUVertBufRaw pos_step = {0};
GPUVertBufRaw nor_step = {0};
GPUVertBufRaw uv_step = {0};
+ GPUVertBufRaw tan_step = {0};
if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) {
GPU_vertbuf_init_with_format(vbo_pos_nor, &format_pos_nor);
@@ -426,6 +496,11 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
GPU_vertbuf_data_alloc(vbo_uv, vbo_len_capacity);
GPU_vertbuf_attr_get_raw_data(vbo_uv, attr_id.uv, &uv_step);
}
+ if (DRW_TEST_ASSIGN_VBO(vbo_tan)) {
+ GPU_vertbuf_init_with_format(vbo_tan, &format_tan);
+ GPU_vertbuf_data_alloc(vbo_tan, vbo_len_capacity);
+ GPU_vertbuf_attr_get_raw_data(vbo_tan, attr_id.tan, &tan_step);
+ }
BKE_displist_normals_add(lb);
@@ -440,6 +515,17 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
if (dl->type == DL_INDEX3) {
/* Currently 'DL_INDEX3' is always a flat surface with a single normal. */
const GPUPackedNormal pnor = GPU_normal_convert_i10_v3(dl->nors);
+
+ GPUPackedNormal ptan = {0, 0, 0, 1};
+ if (vbo_tan) {
+ float tan[4];
+ float(*tan_ptr)[4] = &tan;
+ BKE_displist_tangent_calc(dl, NULL, &tan_ptr);
+
+ ptan = GPU_normal_convert_i10_v3(tan);
+ ptan.w = (tan[3] > 0.0) ? 1 : -2;
+ }
+
const float x_max = (float)(dl->nr - 1);
uv[0][1] = uv[1][1] = uv[2][1] = 0.0f;
const int i_end = dl->parts;
@@ -453,97 +539,97 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
&nor_step,
&uv_step,
+ &tan_step,
verts[idx[0]],
verts[idx[2]],
verts[idx[1]],
&pnor,
&pnor,
&pnor,
+ &ptan,
+ &ptan,
+ &ptan,
uv[0],
uv[2],
uv[1]);
}
}
else if (dl->type == DL_SURF) {
- uint quad[4];
- for (int a = 0; a < dl->parts; a++) {
- if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
- break;
+ float(*tangents)[4] = NULL;
+ float(*fnors)[3] = NULL;
+
+ if (!is_smooth) {
+ displist_surf_fnors_ensure(dl, &fnors);
+ }
+
+ if (vbo_tan) {
+ BKE_displist_tangent_calc(dl, fnors, &tangents);
+ }
+
+ SURFACE_QUAD_ITER_START(dl)
+ {
+ if (vbo_uv) {
+ surf_uv_quad(dl, quad, uv);
}
- int b;
- if (dl->flag & DL_CYCL_U) {
- quad[0] = dl->nr * a;
- quad[3] = quad[0] + dl->nr - 1;
- quad[1] = quad[0] + dl->nr;
- quad[2] = quad[3] + dl->nr;
- b = 0;
+ GPUPackedNormal pnors_quad[4];
+ if (is_smooth) {
+ for (int j = 0; j < 4; j++) {
+ pnors_quad[j] = GPU_normal_convert_i10_v3(nors[quad[j]]);
+ }
}
else {
- quad[3] = dl->nr * a;
- quad[0] = quad[3] + 1;
- quad[2] = quad[3] + dl->nr;
- quad[1] = quad[0] + dl->nr;
- b = 1;
+ pnors_quad[0] = GPU_normal_convert_i10_v3(fnors[quad_index]);
+ pnors_quad[1] = pnors_quad[2] = pnors_quad[3] = pnors_quad[0];
}
- if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
- quad[1] -= dl->parts * dl->nr;
- quad[2] -= dl->parts * dl->nr;
- }
-
- for (; b < dl->nr; b++) {
- if (vbo_uv) {
- surf_uv_quad(dl, quad, uv);
- }
- GPUPackedNormal pnors_quad[4];
- if (is_smooth) {
- for (int j = 0; j < 4; j++) {
- pnors_quad[j] = GPU_normal_convert_i10_v3(nors[quad[j]]);
- }
+ GPUPackedNormal ptans_quad[4];
+ if (vbo_tan) {
+ for (int j = 0; j < 4; j++) {
+ float *tan = tangents[quad_index * 4 + j];
+ ptans_quad[j] = GPU_normal_convert_i10_v3(tan);
+ ptans_quad[j].w = (tan[3] > 0.0f) ? 1 : -2;
}
- else {
- float nor_flat[3];
- normal_quad_v3(
- nor_flat, verts[quad[0]], verts[quad[1]], verts[quad[2]], verts[quad[3]]);
- pnors_quad[0] = GPU_normal_convert_i10_v3(nor_flat);
- pnors_quad[1] = pnors_quad[0];
- pnors_quad[2] = pnors_quad[0];
- pnors_quad[3] = pnors_quad[0];
- }
-
- displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
- &nor_step,
- &uv_step,
- verts[quad[2]],
- verts[quad[0]],
- verts[quad[1]],
- &pnors_quad[2],
- &pnors_quad[0],
- &pnors_quad[1],
- uv[2],
- uv[0],
- uv[1]);
+ }
- displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
- &nor_step,
- &uv_step,
- verts[quad[0]],
- verts[quad[2]],
- verts[quad[3]],
- &pnors_quad[0],
- &pnors_quad[2],
- &pnors_quad[3],
- uv[0],
- uv[2],
- uv[3]);
+ displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
+ &nor_step,
+ &uv_step,
+ &tan_step,
+ verts[quad[2]],
+ verts[quad[0]],
+ verts[quad[1]],
+ &pnors_quad[2],
+ &pnors_quad[0],
+ &pnors_quad[1],
+ &ptans_quad[2],
+ &ptans_quad[0],
+ &ptans_quad[1],
+ uv[2],
+ uv[0],
+ uv[1]);
- quad[2] = quad[1];
- quad[1]++;
- quad[3] = quad[0];
- quad[0]++;
- }
+ displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
+ &nor_step,
+ &uv_step,
+ &tan_step,
+ verts[quad[0]],
+ verts[quad[2]],
+ verts[quad[3]],
+ &pnors_quad[0],
+ &pnors_quad[2],
+ &pnors_quad[3],
+ &ptans_quad[0],
+ &ptans_quad[2],
+ &ptans_quad[3],
+ uv[0],
+ uv[2],
+ uv[3]);
}
+ SURFACE_QUAD_ITER_END
+
+ MEM_SAFE_FREE(tangents);
+ MEM_SAFE_FREE(fnors);
}
else {
BLI_assert(dl->type == DL_INDEX4);
@@ -554,6 +640,7 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
for (int i = 0; i < i_end; i++, idx += 4) {
const bool is_tri = idx[2] != idx[3];
+ GPUPackedNormal ptan = {0};
GPUPackedNormal pnors_idx[4];
if (is_smooth) {
int idx_len = is_tri ? 3 : 4;
@@ -570,34 +657,40 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
normal_quad_v3(nor_flat, verts[idx[0]], verts[idx[1]], verts[idx[2]], verts[idx[3]]);
}
pnors_idx[0] = GPU_normal_convert_i10_v3(nor_flat);
- pnors_idx[1] = pnors_idx[0];
- pnors_idx[2] = pnors_idx[0];
- pnors_idx[3] = pnors_idx[0];
+ pnors_idx[1] = pnors_idx[2] = pnors_idx[3] = pnors_idx[0];
}
displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
&nor_step,
&uv_step,
+ &tan_step,
verts[idx[0]],
verts[idx[2]],
verts[idx[1]],
&pnors_idx[0],
&pnors_idx[2],
&pnors_idx[1],
+ &ptan,
+ &ptan,
+ &ptan,
uv[0],
uv[2],
uv[1]);
- if (idx[2] != idx[3]) {
+ if (is_tri) {
displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
&nor_step,
&uv_step,
+ &tan_step,
verts[idx[2]],
verts[idx[0]],
verts[idx[3]],
&pnors_idx[2],
&pnors_idx[0],
&pnors_idx[3],
+ &ptan,
+ &ptan,
+ &ptan,
uv[2],
uv[0],
uv[3]);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 7c7178eae85..87f93bf6fd6 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -230,68 +230,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
return cd_used;
}
-static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me,
- DRW_MeshCDMask cd_used,
- char **r_auto_layers_names,
- int **r_auto_layers_srgb,
- int *r_auto_layers_len)
-{
- const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
- const CustomData *cd_ldata = &me_final->ldata;
-
- int uv_len_used = count_bits_i(cd_used.uv);
- int vcol_len_used = count_bits_i(cd_used.vcol);
- int uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV);
- int vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL);
-
- uint auto_names_len = 32 * (uv_len_used + vcol_len_used);
- uint auto_ofs = 0;
- /* Allocate max, resize later. */
- char *auto_names = MEM_callocN(sizeof(char) * auto_names_len, __func__);
- int *auto_is_srgb = MEM_callocN(sizeof(int) * (uv_len_used + vcol_len_used), __func__);
-
- for (int i = 0; i < uv_len; i++) {
- if ((cd_used.uv & (1 << i)) != 0) {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
- char safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
- GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
- auto_ofs += BLI_snprintf_rlen(
- auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name);
- /* +1 to include '\0' terminator. */
- auto_ofs += 1;
- }
- }
-
- uint auto_is_srgb_ofs = uv_len_used;
- for (int i = 0; i < vcol_len; i++) {
- if ((cd_used.vcol & (1 << i)) != 0) {
- const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
- /* We only do vcols that are not overridden by a uv layer with same name. */
- if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
- char safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
- GPU_vertformat_safe_attrib_name(name, safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
- auto_ofs += BLI_snprintf_rlen(
- auto_names + auto_ofs, auto_names_len - auto_ofs, "ba%s", safe_name);
- /* +1 to include '\0' terminator. */
- auto_ofs += 1;
- auto_is_srgb[auto_is_srgb_ofs] = true;
- auto_is_srgb_ofs++;
- }
- }
- }
-
- auto_names = MEM_reallocN(auto_names, sizeof(char) * auto_ofs);
- auto_is_srgb = MEM_reallocN(auto_is_srgb, sizeof(int) * auto_is_srgb_ofs);
-
- /* WATCH: May have been referenced somewhere before freeing. */
- MEM_SAFE_FREE(*r_auto_layers_names);
- MEM_SAFE_FREE(*r_auto_layers_srgb);
-
- *r_auto_layers_names = auto_names;
- *r_auto_layers_srgb = auto_is_srgb;
- *r_auto_layers_len = auto_is_srgb_ofs;
-}
-
/** \} */
/* ---------------------------------------------------------------------- */
@@ -492,8 +430,6 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
mesh_cd_layers_type_clear(&cache->cd_used);
MEM_SAFE_FREE(cache->surface_per_mat);
- MEM_SAFE_FREE(cache->auto_layer_names);
- MEM_SAFE_FREE(cache->auto_layer_is_srgb);
cache->mat_len = 0;
}
@@ -771,10 +707,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me)
GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
struct GPUMaterial **gpumat_array,
- uint gpumat_array_len,
- char **auto_layer_names,
- int **auto_layer_is_srgb,
- int *auto_layer_count)
+ uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(me, gpumat_array, gpumat_array_len);
@@ -783,21 +716,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
- if (!mesh_cd_layers_type_overlap(cache->cd_used, cd_needed)) {
- mesh_cd_extract_auto_layers_names_and_srgb(me,
- cache->cd_needed,
- &cache->auto_layer_names,
- &cache->auto_layer_is_srgb,
- &cache->auto_layer_len);
- }
-
mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT);
- if (auto_layer_names) {
- *auto_layer_names = cache->auto_layer_names;
- *auto_layer_is_srgb = cache->auto_layer_is_srgb;
- *auto_layer_count = cache->auto_layer_len;
- }
for (int i = 0; i < cache->mat_len; i++) {
DRW_batch_request(&cache->surface_per_mat[i]);
}
@@ -831,6 +751,11 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me)
return DRW_batch_request(&cache->batch.surface);
}
+int DRW_mesh_material_count_get(Mesh *me)
+{
+ return mesh_render_mat_len_get(me);
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -930,6 +855,7 @@ static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
+ mesh_cd_calc_active_uv_layer(me, &cd_needed);
mesh_cd_calc_edit_uv_layer(me, &cd_needed);
BLI_assert(cd_needed.edit_uv != 0 &&
@@ -1055,6 +981,7 @@ void DRW_mesh_batch_cache_create_requested(
ts = scene->toolsettings;
}
MeshBatchCache *cache = mesh_batch_cache_get(me);
+ bool cd_uv_update = false;
/* Early out */
if (cache->batch_requested == 0) {
@@ -1064,6 +991,19 @@ void DRW_mesh_batch_cache_create_requested(
return;
}
+ /* Sanity check. */
+ if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) {
+ BLI_assert(me->edit_mesh->mesh_eval_final != NULL);
+ }
+
+ const bool is_editmode =
+ (me->edit_mesh != NULL) &&
+ (/* Simple case, the object is in edit-mode with an edit-mesh. */
+ (ob->mode & OB_MODE_EDIT) ||
+ /* This is needed so linked duplicates show updates while the user edits the mesh.
+ * While this is not essential, it's useful to see the edit-mode changes everywhere. */
+ (me->edit_mesh->mesh_eval_final != NULL));
+
DRWBatchFlag batch_requested = cache->batch_requested;
cache->batch_requested = 0;
@@ -1125,6 +1065,7 @@ void DRW_mesh_batch_cache_create_requested(
{
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv);
+ cd_uv_update = true;
}
if ((cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan ||
cache->cd_used.tan_orco != cache->cd_needed.tan_orco) {
@@ -1164,29 +1105,27 @@ void DRW_mesh_batch_cache_create_requested(
if (batch_requested & MBC_EDITUV) {
/* Discard UV batches if sync_selection changes */
- if (ts != NULL) {
- const bool is_uvsyncsel = (ts->uv_flag & UV_SYNC_SELECTION);
- if (cache->is_uvsyncsel != is_uvsyncsel) {
- cache->is_uvsyncsel = is_uvsyncsel;
- 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);
- GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines);
- GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_points);
- }
- /* We only clear the batches as they may already have been
- * referenced. */
- GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
- GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_fdots);
- cache->batch_ready &= ~MBC_EDITUV;
+ 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)
+ {
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines);
+ GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_points);
}
+ /* We only clear the batches as they may already have been
+ * referenced. */
+ GPU_BATCH_CLEAR_SAFE(cache->batch.wire_loops_uvs);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_area);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_stretch_angle);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts);
+ GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_fdots);
+ cache->batch_ready &= ~MBC_EDITUV;
}
}
@@ -1200,10 +1139,10 @@ void DRW_mesh_batch_cache_create_requested(
cache->batch_ready |= batch_requested;
- const bool do_cage = (me->edit_mesh &&
+ const bool do_cage = (is_editmode &&
(me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage));
- const bool do_uvcage = me->edit_mesh && !me->edit_mesh->mesh_eval_final->runtime.is_original;
+ const bool do_uvcage = is_editmode && !me->edit_mesh->mesh_eval_final->runtime.is_original;
MeshBufferCache *mbufcache = &cache->final;
@@ -1398,17 +1337,44 @@ void DRW_mesh_batch_cache_create_requested(
const bool use_subsurf_fdots = scene ? modifiers_usesSubsurfFacedots((Scene *)scene, ob) : false;
if (do_uvcage) {
- mesh_buffer_cache_create_requested(
- cache, cache->uv_cage, me, false, true, false, &cache->cd_used, ts, true);
+ mesh_buffer_cache_create_requested(cache,
+ cache->uv_cage,
+ me,
+ is_editmode,
+ ob->obmat,
+ false,
+ true,
+ false,
+ &cache->cd_used,
+ ts,
+ true);
}
if (do_cage) {
- mesh_buffer_cache_create_requested(
- cache, cache->cage, me, false, false, use_subsurf_fdots, &cache->cd_used, ts, true);
- }
-
- mesh_buffer_cache_create_requested(
- cache, cache->final, me, true, false, use_subsurf_fdots, &cache->cd_used, ts, use_hide);
+ mesh_buffer_cache_create_requested(cache,
+ cache->cage,
+ me,
+ is_editmode,
+ ob->obmat,
+ false,
+ false,
+ use_subsurf_fdots,
+ &cache->cd_used,
+ ts,
+ true);
+ }
+
+ mesh_buffer_cache_create_requested(cache,
+ cache->final,
+ me,
+ is_editmode,
+ ob->obmat,
+ true,
+ false,
+ use_subsurf_fdots,
+ &cache->cd_used,
+ ts,
+ use_hide);
#ifdef DEBUG
check:
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index e3bfcbde3ef..c14e66c2b47 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "DNA_meta_types.h"
@@ -206,6 +207,8 @@ GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob,
return NULL;
}
+ BLI_assert(gpumat_array_len == DRW_metaball_material_count_get(mb));
+
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
if (cache->shaded_triangles == NULL) {
cache->mat_len = gpumat_array_len;
@@ -270,3 +273,8 @@ struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
return cache->edge_detection;
}
+
+int DRW_metaball_material_count_get(MetaBall *mb)
+{
+ return max_ii(1, mb->totcol);
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 0a9984762b0..795e7be63b1 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -637,23 +637,6 @@ static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_
}
}
-static float particle_key_select_ratio(const PTCacheEdit *edit, int strand, float t)
-{
- const PTCacheEditPoint *point = &edit->points[strand];
- float edit_key_seg_t = 1.0f / (point->totkey - 1);
- if (t == 1.0) {
- return (point->keys[point->totkey - 1].flag & PEK_SELECT) ? 1.0f : 0.0;
- }
- else {
- float interp = t / edit_key_seg_t;
- int index = (int)interp;
- interp -= floorf(interp); /* Time between 2 edit key */
- float s1 = (point->keys[index].flag & PEK_SELECT) ? 1.0f : 0.0;
- float s2 = (point->keys[index + 1].flag & PEK_SELECT) ? 1.0f : 0.0;
- return s1 + interp * (s2 - s1);
- }
-}
-
static float particle_key_weight(const ParticleData *particle, int strand, float t)
{
const ParticleData *part = particle + strand;
@@ -673,8 +656,8 @@ static float particle_key_weight(const ParticleData *particle, int strand, float
}
static int particle_batch_cache_fill_segments_edit(
- const PTCacheEdit *edit, /* NULL for weight data */
- const ParticleData *particle, /* NULL for select data */
+ const PTCacheEdit *UNUSED(edit), /* NULL for weight data */
+ const ParticleData *particle, /* NULL for select data */
ParticleCacheKey **path_cache,
const int start_index,
const int num_path_keys,
@@ -697,8 +680,8 @@ static int particle_batch_cache_fill_segments_edit(
seg_data->color = (weight < 1.0f) ? weight : 1.0f;
}
else {
- float selected = particle_key_select_ratio(edit, i, strand_t);
- seg_data->color = selected;
+ /* Computed in psys_cache_edit_paths_iter(). */
+ seg_data->color = path[j].col[0];
}
GPU_indexbuf_add_generic_vert(elb, curr_point);
curr_point++;
@@ -894,11 +877,13 @@ 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];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
- uint hash = BLI_ghashutil_strhash_p(name);
+ GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+
int n = 0;
- BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%u", hash);
- BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash);
+ BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%s", attr_safe_name);
+ BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%s", attr_safe_name);
if (i == active_uv) {
BLI_strncpy(cache->uv_layer_names[i][n++], "au", MAX_LAYER_NAME_LEN);
@@ -913,14 +898,16 @@ 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];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
- uint hash = BLI_ghashutil_strhash_p(name);
+ GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+
int n = 0;
- BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%u", hash);
+ BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%s", attr_safe_name);
/* We only do vcols auto name that are not overridden by uvs */
if (CustomData_get_named_layer_index(&psmd->mesh_final->ldata, CD_MLOOPUV, name) == -1) {
- BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash);
+ BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%s", attr_safe_name);
}
if (i == active_col) {
@@ -1176,10 +1163,12 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
col_id = MEM_mallocN(sizeof(*col_id) * num_col_layers, "Col attr format");
for (int i = 0; i < num_uv_layers; i++) {
+
+ char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
- char uuid[32];
+ GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
- BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(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);
if (i == active_uv) {
@@ -1187,12 +1176,13 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
}
}
- for (int i = 0; i < num_uv_layers; i++) {
- const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
- char uuid[32];
+ for (int i = 0; i < num_col_layers; i++) {
+ char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_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);
- BLI_snprintf(uuid, sizeof(uuid), "c%u", BLI_ghashutil_strhash_p(name));
- col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ 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);
if (i == active_col) {
GPU_vertformat_alias_add(&format, "c");
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index 6b05bb07c0f..59c6efe1a61 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -210,6 +210,10 @@ static void drw_debug_draw_spheres(void)
GPU_batch_instbuf_set(draw_batch, inst_vbo, true);
GPU_batch_program_set_builtin(draw_batch, GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
+ float persmat[4][4];
+ DRW_view_persmat_get(NULL, persmat, false);
+ GPU_batch_uniform_mat4(draw_batch, "ViewProjectionMatrix", persmat);
+
GPU_batch_draw(draw_batch);
GPU_batch_discard(draw_batch);
}
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 6eaba7e8811..c03b4822b1b 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 DECIMAL_DIGITS_BOUND(uint) + 2
+#define MAX_LAYER_NAME_LEN GPU_MAX_SAFE_ATTRIB_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 b580ad21652..0c38f929b0b 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1610,6 +1610,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
drw_draw_background_alpha_under();
}
+ drw_debug_draw();
+
/* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */
GPU_flush();
@@ -1634,8 +1636,6 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DRW_state_reset();
}
- drw_debug_draw();
-
GPU_depth_test(false);
drw_engines_draw_text();
GPU_depth_test(true);
@@ -2258,6 +2258,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
FOREACH_OBJECT_IN_MODE_END;
}
else {
+ /* When selecting pose-bones in pose mode, check for visibility not select-ability
+ * as pose-bones have their own selection restriction flag. */
+ const bool use_pose_exception = (DST.draw_ctx.object_pose != NULL);
+
const int object_type_exclude_select = (v3d->object_type_exclude_viewport |
v3d->object_type_exclude_select);
bool filter_exclude = false;
@@ -2265,8 +2269,19 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
}
- if ((ob->base_flag & BASE_SELECTABLE) &&
- (object_type_exclude_select & (1 << ob->type)) == 0) {
+
+ if (use_pose_exception && (ob->mode & OB_MODE_POSE)) {
+ if ((ob->base_flag & BASE_VISIBLE_VIEWLAYER) == 0) {
+ continue;
+ }
+ }
+ else {
+ if ((ob->base_flag & BASE_SELECTABLE) == 0) {
+ continue;
+ }
+ }
+
+ if ((object_type_exclude_select & (1 << ob->type)) == 0) {
if (object_filter_fn != NULL) {
if (ob->base_flag & BASE_FROM_DUPLI) {
/* pass (use previous filter_exclude value) */
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 98474c81209..f9a6b663900 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1214,17 +1214,19 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp,
GPUTexture *tex = NULL;
if (input->ima) {
- /* If there's no specified iuser but we need a different tile, create a temporary one. */
- ImageUser local_iuser;
- BKE_imageuser_default(&local_iuser);
- local_iuser.tile = input->image_tile;
-
- ImageUser *iuser = input->iuser ? input->iuser : &local_iuser;
- iuser->tile = input->image_tile;
-
GPUTexture **tex_ref = BLI_memblock_alloc(DST.vmempool->images);
- *tex_ref = tex = GPU_texture_from_blender(input->ima, iuser, GL_TEXTURE_2D);
+ int textarget;
+ if (input->type == GPU_TEX2D_ARRAY) {
+ textarget = GL_TEXTURE_2D_ARRAY;
+ }
+ else if (input->type == GPU_TEX1D_ARRAY) {
+ textarget = GL_TEXTURE_1D_ARRAY;
+ }
+ else {
+ textarget = GL_TEXTURE_2D;
+ }
+ *tex_ref = tex = GPU_texture_from_blender(input->ima, input->iuser, NULL, textarget);
GPU_texture_ref(tex);
}
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 9d14b77119f..75d5a5c73b9 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -129,6 +129,7 @@ void drw_state_set(DRWState state)
}
else {
glStencilMask(0x00);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
}
}
@@ -1313,7 +1314,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
break;
case DRW_CMD_DRAW:
if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
- cmd->draw.batch->inst) {
+ cmd->draw.batch->inst[0]) {
draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, true);
}
else {
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index 47fafbdcbd8..92095791ef7 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -253,7 +253,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *ar,
BoundBox bb;
const rcti rect = {0, ar->winx, 0, ar->winy};
- ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
+ ED_view3d_clipping_calc(&bb, clip_planes, ar, ob, &rect);
}
if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) {
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index b7ed20d9ec5..e90289de963 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -898,6 +898,23 @@ static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode)
}
}
+/* get rearranging function, given 'rearrange' mode (grease pencil is inverted) */
+static AnimChanRearrangeFp rearrange_gpencil_get_mode_func(eRearrangeAnimChan_Mode mode)
+{
+ switch (mode) {
+ case REARRANGE_ANIMCHAN_TOP:
+ return rearrange_island_bottom;
+ case REARRANGE_ANIMCHAN_UP:
+ return rearrange_island_down;
+ case REARRANGE_ANIMCHAN_DOWN:
+ return rearrange_island_up;
+ case REARRANGE_ANIMCHAN_BOTTOM:
+ return rearrange_island_top;
+ default:
+ return NULL;
+ }
+}
+
/* Rearrange Islands Generics ------------------------------------- */
/* add channel into list of islands */
@@ -1331,7 +1348,7 @@ static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode
int filter;
/* get rearranging function */
- AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+ AnimChanRearrangeFp rearrange_func = rearrange_gpencil_get_mode_func(mode);
if (rearrange_func == NULL) {
return;
@@ -1360,10 +1377,15 @@ static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode
/* free visible layers data */
BLI_freelistN(&anim_data_visible);
+
+ /* Tag to recalc geometry */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
/* free GPD channel data */
ANIM_animdata_freelist(&anim_data);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
/* ------------------- */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index f73c8a5b71a..4c81df8b71d 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -56,6 +56,7 @@
#include "DNA_meta_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
+#include "DNA_object_force_types.h"
#include "DNA_particle_types.h"
#include "DNA_space_types.h"
#include "DNA_sequence_types.h"
@@ -2433,8 +2434,9 @@ static size_t animdata_filter_ds_particles(
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
- /* if no material returned, skip - so that we don't get weird blank entries... */
- if (ELEM(NULL, psys->part, psys->part->adt)) {
+ /* Note that when psys->part->adt is NULL the textures can still be
+ * animated. */
+ if (psys->part == NULL) {
continue;
}
@@ -2732,6 +2734,12 @@ static size_t animdata_filter_dopesheet_ob(
tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode);
}
+ /* particle deflector textures */
+ if (ob->pd != NULL && ob->pd->tex != NULL && !(ads->filterflag & ADS_FILTER_NOTEX)) {
+ tmp_items += animdata_filter_ds_texture(
+ ac, &tmp_data, ads, ob->pd->tex, &ob->id, filter_mode);
+ }
+
/* shape-key */
if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 13358808a23..e0d72ab5198 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -1001,13 +1001,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
mm->evtx = event->x;
fac = ((float)(event->x - mm->firstx) * dx);
- apply_keyb_grid(event->shift,
- event->ctrl,
- &fac,
- 0.0,
- 1.0,
- 0.1,
- 0 /*was: U.flag & USER_AUTOGRABGRID*/);
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
RNA_int_set(op->ptr, "frames", (int)fac);
ed_marker_move_apply(C, op);
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 8203a9131fa..14b1f6523d9 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2964,6 +2964,82 @@ bool ED_autokeyframe_pchan(
}
}
+/**
+ * Use for auto-keyframing from the UI.
+ */
+bool ED_autokeyframe_property(
+ bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
+{
+ Main *bmain = CTX_data_main(C);
+ ID *id;
+ bAction *action;
+ FCurve *fcu;
+ bool driven;
+ bool special;
+ bool changed = false;
+
+ fcu = rna_get_fcurve_context_ui(C, ptr, prop, rnaindex, NULL, &action, &driven, &special);
+
+ if (fcu == NULL) {
+ return changed;
+ }
+
+ if (special) {
+ /* NLA Strip property */
+ if (IS_AUTOKEY_ON(scene)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ changed = insert_keyframe_direct(reports, *ptr, prop, fcu, cfra, ts->keyframe_type, NULL, 0);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ }
+ else if (driven) {
+ /* Driver - Try to insert keyframe using the driver's input as the frame,
+ * making it easier to set up corrective drivers
+ */
+ if (IS_AUTOKEY_ON(scene)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ changed = insert_keyframe_direct(
+ reports, *ptr, prop, fcu, cfra, ts->keyframe_type, NULL, INSERTKEY_DRIVER);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ }
+ else {
+ id = ptr->owner_id;
+
+ /* TODO: this should probably respect the keyingset only option for anim */
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ short flag = ANIM_get_keyframing_flags(scene, 1);
+
+ fcu->flag &= ~FCURVE_SELECTED;
+
+ /* Note: We use rnaindex instead of fcu->array_index,
+ * because a button may control all items of an array at once.
+ * E.g., color wheels (see T42567). */
+ BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ changed = insert_keyframe(bmain,
+ reports,
+ id,
+ action,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ rnaindex,
+ cfra,
+ ts->keyframe_type,
+ NULL,
+ flag) != 0;
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ }
+ return changed;
+}
+
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 70a9b7ba1fa..ae489fb5233 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -179,9 +179,9 @@ void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *ar, bDopeShee
rcti rect;
rect.xmin = 0;
- rect.xmax = ceilf(ar->sizex * UI_DPI_FAC);
- rect.ymin = ar->sizey * UI_DPI_FAC - UI_TIME_SCRUB_MARGIN_Y;
- rect.ymax = ceilf(ar->sizey * UI_DPI_FAC);
+ rect.xmax = ar->winx;
+ rect.ymin = ar->winy - UI_TIME_SCRUB_MARGIN_Y;
+ rect.ymax = ar->winy;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 2b18fc15f63..451148ed936 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -232,11 +232,22 @@ EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[],
void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3])
{
- float delta[3];
+ float delta[3], roll;
/* Find the current bone matrix */
sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, mat);
+ roll = ebone->roll;
+ if (!normalize_v3(delta)) {
+ /* Use the orientation of the parent bone if any. */
+ const EditBone *ebone_parent = ebone->parent;
+ if (ebone_parent) {
+ sub_v3_v3v3(delta, ebone_parent->tail, ebone_parent->head);
+ normalize_v3(delta);
+ roll = ebone_parent->roll;
+ }
+ }
+
+ vec_roll_to_mat3_normalized(delta, roll, mat);
}
void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4])
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 4c4bac6a249..5486d60d5d7 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -460,14 +460,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]);
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- selem->pressure = wmtab->Pressure;
- }
- else {
- selem->pressure = 1.0f;
- }
+ /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
+ selem->pressure = event->tablet.pressure;
bool is_depth_found = stroke_elem_project_fallback_elem(
cdd, cdd->prev.location_world_valid, selem);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 4cc0c865093..62bac643347 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -648,6 +648,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.inflate
brush.sculpt.layer
brush.sculpt.mask
+ brush.sculpt.multiplane_scrape
brush.sculpt.nudge
brush.sculpt.pinch
brush.sculpt.pose
@@ -657,6 +658,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.smooth
brush.sculpt.snake_hook
brush.sculpt.thumb
+ brush.sculpt.topology
brush.uv_sculpt.grab
brush.uv_sculpt.pinch
brush.uv_sculpt.relax
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index 4fbe901c1ca..68a204c04a7 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -45,7 +45,6 @@ set(SRC
geometry/geom_arrow_gizmo.c
geometry/geom_cube_gizmo.c
geometry/geom_dial_gizmo.c
- gizmo_types/arrow2d_gizmo.c
gizmo_types/arrow3d_gizmo.c
gizmo_types/blank3d_gizmo.c
gizmo_types/button2d_gizmo.c
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
deleted file mode 100644
index 1c8c46a2bad..00000000000
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2016 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edgizmolib
- *
- * \name 2D Arrow Gizmo
- *
- * \brief Simple arrow gizmo which is dragged into a certain direction.
- */
-
-#include "BLI_math.h"
-
-#include "DNA_windowmanager_types.h"
-
-#include "BKE_context.h"
-
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_types.h"
-
-#include "ED_screen.h"
-#include "ED_gizmo_library.h"
-
-/* own includes */
-#include "WM_api.h"
-
-#include "../gizmo_library_intern.h"
-
-static void arrow2d_draw_geom(wmGizmo *gz, const float matrix[4][4], const float color[4])
-{
- const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
- const float size = 0.11f;
- const float size_breadth = size / 2.0f;
- const float size_length = size * 1.7f;
- /* Subtract the length so the arrow fits in the hotspot. */
- const float arrow_length = RNA_float_get(gz->ptr, "length") - size_length;
- const float arrow_angle = RNA_float_get(gz->ptr, "angle");
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- GPU_matrix_push();
- GPU_matrix_mul(matrix);
- GPU_matrix_rotate_2d(RAD2DEGF(arrow_angle));
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- immUniformColor4fv(color);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, 0.0f, 0.0f);
- immVertex2f(pos, 0.0f, arrow_length);
- immEnd();
-
- if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) {
- immBegin(GPU_PRIM_TRI_FAN, 4);
- immVertex2f(pos, -size / 2, arrow_length);
- immVertex2f(pos, size / 2, arrow_length);
- immVertex2f(pos, size / 2, arrow_length + size);
- immVertex2f(pos, -size / 2, arrow_length + size);
- immEnd();
- }
- else {
- immBegin(GPU_PRIM_TRIS, 3);
- immVertex2f(pos, size_breadth, arrow_length);
- immVertex2f(pos, -size_breadth, arrow_length);
- immVertex2f(pos, 0.0f, arrow_length + size_length);
- immEnd();
- }
-
- immUnbindProgram();
-
- GPU_matrix_pop();
-}
-
-static void gizmo_arrow2d_draw(const bContext *UNUSED(C), wmGizmo *gz)
-{
- float color[4];
-
- float matrix_final[4][4];
-
- gizmo_color_get(gz, gz->state & WM_GIZMO_STATE_HIGHLIGHT, color);
-
- GPU_line_width(gz->line_width);
-
- WM_gizmo_calc_matrix_final(gz, matrix_final);
-
- GPU_blend(true);
- arrow2d_draw_geom(gz, matrix_final, color);
- GPU_blend(false);
-
- if (gz->interaction_data) {
- GizmoInteraction *inter = gz->interaction_data;
-
- GPU_blend(true);
- arrow2d_draw_geom(gz, inter->init_matrix_final, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
- GPU_blend(false);
- }
-}
-
-static void gizmo_arrow2d_setup(wmGizmo *gz)
-{
- gz->flag |= WM_GIZMO_DRAW_MODAL;
-}
-
-static int gizmo_arrow2d_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *UNUSED(event))
-{
- GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
-
- copy_m4_m4(inter->init_matrix_basis, gz->matrix_basis);
- WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
-
- gz->interaction_data = inter;
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int gizmo_arrow2d_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
-{
- const float mval_fl[2] = {UNPACK2(mval)};
- const float arrow_length = RNA_float_get(gz->ptr, "length");
- const float arrow_angle = RNA_float_get(gz->ptr, "angle");
- const float line_len = arrow_length * gz->scale_final;
- float mval_local[2];
-
- copy_v2_v2(mval_local, mval_fl);
- sub_v2_v2(mval_local, gz->matrix_basis[3]);
-
- float line[2][2];
- line[0][0] = line[0][1] = line[1][0] = 0.0f;
- line[1][1] = line_len;
-
- /* rotate only if needed */
- if (arrow_angle != 0.0f) {
- float rot_point[2];
- copy_v2_v2(rot_point, line[1]);
- rotate_v2_v2fl(line[1], rot_point, arrow_angle);
- }
-
- /* arrow line intersection check */
- float isect_1[2], isect_2[2];
- const int isect = isect_line_sphere_v2(
- line[0], line[1], mval_local, GIZMO_HOTSPOT + gz->line_width * 0.5f, isect_1, isect_2);
-
- if (isect > 0) {
- float line_ext[2][2]; /* extended line for segment check including hotspot */
- copy_v2_v2(line_ext[0], line[0]);
- line_ext[1][0] = line[1][0] + GIZMO_HOTSPOT * ((line[1][0] - line[0][0]) / line_len);
- line_ext[1][1] = line[1][1] + GIZMO_HOTSPOT * ((line[1][1] - line[0][1]) / line_len);
-
- const float lambda_1 = line_point_factor_v2(isect_1, line_ext[0], line_ext[1]);
- if (isect == 1) {
- if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f)) {
- return 0;
- }
- }
- else {
- BLI_assert(isect == 2);
- const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]);
- if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f)) {
- return 0;
- }
- }
- }
-
- return -1;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name 2D Arrow Gizmo API
- *
- * \{ */
-
-static void GIZMO_GT_arrow_2d(wmGizmoType *gzt)
-{
- /* identifiers */
- gzt->idname = "GIZMO_GT_arrow_2d";
-
- /* api callbacks */
- gzt->draw = gizmo_arrow2d_draw;
- gzt->setup = gizmo_arrow2d_setup;
- gzt->invoke = gizmo_arrow2d_invoke;
- gzt->test_select = gizmo_arrow2d_test_select;
-
- gzt->struct_size = sizeof(wmGizmo);
-
- /* rna */
- static EnumPropertyItem rna_enum_draw_style_items[] = {
- {ED_GIZMO_ARROW_STYLE_NORMAL, "NORMAL", 0, "Normal", ""},
- {ED_GIZMO_ARROW_STYLE_BOX, "BOX", 0, "Box", ""},
- {0, NULL, 0, NULL, NULL},
- };
- RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
- RNA_def_float_rotation(gzt->srna,
- "angle",
- 0,
- NULL,
- DEG2RADF(-360.0f),
- DEG2RADF(360.0f),
- "Roll",
- "",
- DEG2RADF(-360.0f),
- DEG2RADF(360.0f));
- RNA_def_enum(gzt->srna,
- "draw_style",
- rna_enum_draw_style_items,
- ED_GIZMO_ARROW_STYLE_NORMAL,
- "Draw Style",
- "");
-}
-
-void ED_gizmotypes_arrow_2d(void)
-{
- WM_gizmotype_append(GIZMO_GT_arrow_2d);
-}
-
-/** \} */
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 6a28c626a81..f1a8bc62cd3 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -22,17 +22,18 @@
*
* \name Arrow Gizmo
*
- * 3D Gizmo
+ * 2D/3D Gizmo
*
* \brief Simple arrow gizmo which is dragged into a certain direction.
* The arrow head can have varying shapes, e.g. cone, box, etc.
*
* - `matrix[0]` is derived from Y and Z.
* - `matrix[1]` is 'up' for gizmo types that have an up.
- * - `matrix[2]` is the arrow direction (for all arrowes).
+ * - `matrix[2]` is the arrow direction (for all arrows).
*/
#include "BLI_math.h"
+#include "BLI_utildefines.h"
#include "DNA_view3d_types.h"
@@ -56,6 +57,8 @@
#include "ED_screen.h"
#include "ED_gizmo_library.h"
+#include "UI_interface.h"
+
/* own includes */
#include "../gizmo_geometry.h"
#include "../gizmo_library_intern.h"
@@ -214,6 +217,50 @@ static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz)
}
/**
+ * Selection for 2D views.
+ */
+static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
+{
+ /* Project into 2D space since it simplifies pixel threshold tests. */
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+ const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
+
+ float matrix_final[4][4];
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ /* Arrow in pixel space. */
+ float arrow_start[2] = {matrix_final[3][0], matrix_final[3][1]};
+ float arrow_end[2];
+ {
+ float co[3] = {0, 0, arrow_length};
+ mul_m4_v3(matrix_final, co);
+ copy_v2_v2(arrow_end, co);
+ }
+
+ const float mval_fl[2] = {UNPACK2(mval)};
+ const float arrow_stem_threshold_px = 5 * UI_DPI_FAC;
+ const float arrow_head_threshold_px = 12 * UI_DPI_FAC;
+
+ /* Distance to arrow head. */
+ if (len_squared_v2v2(mval_fl, arrow_end) < SQUARE(arrow_head_threshold_px)) {
+ return 0;
+ }
+
+ /* Distance to arrow stem. */
+ float co_isect[2];
+ const float lambda = closest_to_line_v2(co_isect, mval_fl, arrow_start, arrow_end);
+ /* Clamp inside the line, to avoid overlapping with other gizmos,
+ * especially around the start of the arrow. */
+ if (lambda >= 0.0 && lambda <= 1.0) {
+ if (len_squared_v2v2(mval_fl, co_isect) < SQUARE(arrow_stem_threshold_px)) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/**
* Calculate arrow offset independent from prop min value,
* meaning the range will not be offset by min value first.
*/
@@ -361,7 +408,14 @@ static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
const bool is_prop_valid = WM_gizmo_target_property_is_valid(gz_prop);
- if (!cancel) {
+ if (cancel) {
+ GizmoInteraction *inter = gz->interaction_data;
+ if (is_prop_valid) {
+ gizmo_property_value_reset(C, gz, inter, gz_prop);
+ }
+ data->offset = inter->init_offset;
+ }
+ else {
/* Assign in case applying the operation needs an updated offset
* edit-mesh bisect needs this. */
if (is_prop_valid) {
@@ -371,14 +425,13 @@ static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
const float value = WM_gizmo_target_property_float_get(gz, gz_prop);
data->offset = gizmo_offset_from_value(data, value, constrained, inverted);
}
- return;
}
- GizmoInteraction *inter = gz->interaction_data;
- if (is_prop_valid) {
- gizmo_property_value_reset(C, gz, inter, gz_prop);
+ if (!cancel) {
+ if (is_prop_valid) {
+ WM_gizmo_target_property_anim_autokey(C, gz, gz_prop);
+ }
}
- data->offset = inter->init_offset;
}
/* -------------------------------------------------------------------- */
@@ -427,6 +480,7 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
/* api callbacks */
gzt->draw = gizmo_arrow_draw;
gzt->draw_select = gizmo_arrow_draw_select;
+ gzt->test_select = gizmo_arrow_test_select;
gzt->matrix_basis_get = gizmo_arrow_matrix_basis_get;
gzt->modal = gizmo_arrow_modal;
gzt->setup = gizmo_arrow_setup;
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 ef4fd23b64d..2e4284d357a 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -56,7 +56,6 @@
/* own includes */
#include "../gizmo_library_intern.h"
-#define GIZMO_RESIZER_SIZE 10.0f
#define GIZMO_MARGIN_OFFSET_SCALE 1.5f
static bool gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[2], float scale[2])
@@ -92,12 +91,7 @@ static bool gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[2], f
static bool gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[2], float margin[2])
{
float handle_size;
- if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- handle_size = 0.15f;
- }
- else {
- handle_size = GIZMO_RESIZER_SIZE;
- }
+ handle_size = 0.15f;
handle_size *= gz->scale_final;
float scale_xy[2];
if (!gizmo_calc_rect_view_scale(gz, dims, scale_xy)) {
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 723be3cfe6b..05b58903e04 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -91,13 +91,7 @@ static void gizmo_calc_rect_view_scale(const wmGizmo *gz, const float dims[3], f
static void gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[3], float margin[3])
{
- float handle_size;
- if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- handle_size = 0.15f;
- }
- else {
- handle_size = GIZMO_RESIZER_SIZE;
- }
+ const float handle_size = 0.15f;
// XXX, the scale isn't taking offset into account, we need to calculate scale per handle!
// handle_size *= gz->scale_final;
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 d3121711e28..6dc81e26bf1 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -235,7 +235,7 @@ static void dial_ghostarc_draw_incremental_angle(const float incremental_angle,
}
static void dial_ghostarc_draw(const float angle_ofs,
- const float angle_delta,
+ float angle_delta,
const float arc_inner_factor,
const float color[4])
{
@@ -244,21 +244,36 @@ static void dial_ghostarc_draw(const float angle_ofs,
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ /* Avoid artifacts by drawing the main arc over the span of one rotation only. */
+ const float pi2 = (float)(M_PI * 2.0);
+ int rotation_count = (int)floorf(fabsf(angle_delta) / pi2);
+ angle_delta = fmod(angle_delta, pi2);
+
+ /* Calculate the remaining angle that can be filled with the background color. */
+ const float angle_background = angle_delta >= 0 ? (pi2 - angle_delta) : -(pi2 + angle_delta);
+
+ float color_background[4] = {0};
if (arc_inner_factor != 0.0) {
- float color_dark[4] = {0};
- color_dark[3] = color[3] / 2;
- immUniformColor4fv(color_dark);
- imm_draw_disk_partial_fill_2d(pos,
- 0,
- 0,
- arc_inner_factor,
- width_inner,
- DIAL_RESOLUTION,
- RAD2DEGF(angle_ofs),
- RAD2DEGF(M_PI * 2));
+ color_background[3] = color[3] / 2.0f;
}
- immUniformColor4fv(color);
+ if (rotation_count != 0) {
+ /* Calculate the background color to visualize the rotation count. */
+ copy_v4_v4(color_background, color);
+ color_background[3] = color[3] * rotation_count;
+ }
+
+ immUniformColor4fv(color_background);
+ imm_draw_disk_partial_fill_2d(pos,
+ 0,
+ 0,
+ arc_inner_factor,
+ width_inner,
+ DIAL_RESOLUTION,
+ RAD2DEGF(angle_ofs + angle_delta),
+ RAD2DEGF(angle_background));
+
+ immUniformColor4f(UNPACK3(color), color[3] * (rotation_count + 1));
imm_draw_disk_partial_fill_2d(pos,
0,
0,
@@ -537,6 +552,13 @@ static void gizmo_dial_exit(bContext *C, wmGizmo *gz, const bool cancel)
WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
}
}
+
+ if (!cancel) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_anim_autokey(C, gz, gz_prop);
+ }
+ }
}
static void gizmo_dial_setup(wmGizmo *gz)
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 5342f8695b2..f040e67ae44 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -335,6 +335,13 @@ static void gizmo_move_exit(bContext *C, wmGizmo *gz, const bool cancel)
ED_transform_snap_object_context_destroy(inter->snap_context_v3d);
inter->snap_context_v3d = NULL;
}
+
+ if (!cancel) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_anim_autokey(C, gz, gz_prop);
+ }
+ }
}
static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 67bf64a2903..6e91be862a9 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -1056,7 +1056,7 @@ void ED_annotation_draw_2dimage(const bContext *C)
int offsx, offsy, sizex, sizey;
int dflag = GP_DRAWDATA_NOSTATUS;
- bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ bGPdata *gpd = ED_annotation_data_get_active(C);
if (gpd == NULL) {
return;
}
@@ -1132,7 +1132,7 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
if (sa == NULL) {
return;
}
- bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ bGPdata *gpd = ED_annotation_data_get_active(C);
if (gpd == NULL) {
return;
}
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 7a10547f35c..5eaf14e361b 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -218,19 +218,9 @@ static void gp_session_validatebuffer(tGPsdata *p);
/* check if context is suitable for drawing */
static bool gpencil_draw_poll(bContext *C)
{
- /* if is inside grease pencil draw mode cannot use annotations */
- Object *obact = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- if ((sa) && (sa->spacetype == SPACE_VIEW3D)) {
- if ((obact) && (obact->type == OB_GPENCIL) && (obact->mode == OB_MODE_PAINT_GPENCIL)) {
- CTX_wm_operator_poll_msg_set(C, "Annotation cannot be used in grease pencil draw mode");
- return false;
- }
- }
-
if (ED_operator_regionactive(C)) {
/* check if current context can support GPencil data */
- if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ if (ED_annotation_data_get_pointers(C, NULL) != NULL) {
/* check if Grease Pencil isn't already running */
if (ED_gpencil_session_active() == 0) {
return true;
@@ -240,7 +230,7 @@ static bool gpencil_draw_poll(bContext *C)
}
}
else {
- CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Annotation data to draw into");
}
}
else {
@@ -1115,7 +1105,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* get gp-data */
- gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
+ gpd_ptr = ED_annotation_data_get_pointers(C, &p->ownerPtr);
if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
p->status = GP_STATUS_ERROR;
if (G.debug & G_DEBUG) {
@@ -1471,12 +1461,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
{
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- return (wmtab->Active == EVT_TABLET_ERASER);
- }
-
- return false;
+ return (event->tablet.active == EVT_TABLET_ERASER);
}
/* ------------------------------- */
@@ -1696,7 +1681,6 @@ static void annotation_draw_apply_event(
tGPsdata *p = op->customdata;
PointerRNA itemptr;
float mousef[2];
- int tablet = 0;
/* convert from window-space to area-space mouse coordinates
* add any x,y override position for fake events
@@ -1730,29 +1714,20 @@ static void annotation_draw_apply_event(
p->curtime = PIL_check_seconds_timer();
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- p->pressure = wmtab->Pressure;
+ /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
+ p->pressure = event->tablet.pressure;
- /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
- * The pen has to float over the tablet surface, resulting in
- * zero pressure (T47101). Ignore pressure values if floating
- * (i.e. "effectively zero" pressure), and only when the "active"
- * end is the stylus (i.e. the default when not eraser)
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
- p->pressure = 1.0f;
- }
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
}
}
- else {
- /* No tablet data -> No pressure info is available */
- p->pressure = 1.0f;
- }
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
@@ -1768,7 +1743,7 @@ static void annotation_draw_apply_event(
/* special exception here for too high pressure values on first touch in
* windows for some tablets, then we just skip first touch...
*/
- if (tablet && (p->pressure >= 0.99f)) {
+ if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) {
return;
}
}
@@ -1886,9 +1861,6 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* start of interactive drawing part of operator */
static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
tGPsdata *p = NULL;
/* support for tablets eraser pen */
@@ -1896,26 +1868,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
}
- /* if try to do annotations with a gp object selected, first
- * unselect the object to avoid conflicts.
- * The solution is not perfect but we can keep running the annotations while
- * found a better solution.
- */
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
- ob->mode = OB_MODE_OBJECT;
- bGPdata *gpd = (bGPdata *)ob->data;
- ED_gpencil_setup_modes(C, gpd, 0);
- DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_view_layer_base_deselect_all(view_layer);
- view_layer->basact = NULL;
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
- }
-
if (G.debug & G_DEBUG) {
printf("GPencil - Starting Drawing\n");
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 4948df606ee..c2f1e9f091a 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -424,7 +424,8 @@ static bool gp_brush_strength_apply(tGP_BrushEditData *gso,
* - We divide the strength, so that users can set "sane" values.
* Otherwise, good default values are in the range of 0.093
*/
- inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
+ inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
+ CLAMP_MIN(inf, 0.01f);
/* apply */
if (gp_brush_invert_check(gso)) {
@@ -435,12 +436,12 @@ static bool gp_brush_strength_apply(tGP_BrushEditData *gso,
/* make line more opaque - increase stroke strength */
pt->strength += inf;
}
- /* smooth the strength */
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
-
/* Strength should stay within [0.0, 1.0] */
CLAMP(pt->strength, 0.0f, 1.0f);
+ /* smooth the strength */
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+
return true;
}
@@ -1976,7 +1977,6 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
PointerRNA itemptr;
float mouse[2];
- int tablet = 0;
mouse[0] = event->mval[0] + 1;
mouse[1] = event->mval[1] + 1;
@@ -1988,24 +1988,14 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven
RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
RNA_boolean_set(&itemptr, "is_start", gso->first);
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- float pressure = wmtab->Pressure;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets: clamp the values to be sane
- */
- if (tablet && (pressure >= 0.99f)) {
- pressure = 1.0f;
- }
- RNA_float_set(&itemptr, "pressure", pressure);
- }
- else {
- RNA_float_set(&itemptr, "pressure", 1.0f);
+ /* handle pressure sensitivity (which is supplied by tablets and otherwise 1.0) */
+ float pressure = event->tablet.pressure;
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets: clamp the values to be sane */
+ if (pressure >= 0.99f) {
+ pressure = 1.0f;
}
+ RNA_float_set(&itemptr, "pressure", pressure);
if (!gso->is_weight_mode) {
if (event->shift) {
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 4a91a90c075..1ce4ffbbd46 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1390,6 +1390,8 @@ static void gp_layer_to_curve(bContext *C,
}
ED_object_base_select(base_new, BA_SELECT);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
/* --- */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 1331cc92d96..fa23dd5e059 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -91,64 +91,43 @@
/* ******************* Add New Data ************************ */
static bool gp_data_add_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
- if (obact && obact->type == OB_GPENCIL) {
- if (obact->mode != OB_MODE_OBJECT) {
- return false;
- }
- }
/* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+ return ED_annotation_data_get_pointers(C, NULL) != NULL;
}
/* add new datablock - wrapper around API */
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
PointerRNA gpd_owner = {NULL};
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
- bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner);
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
return OPERATOR_CANCELLED;
}
- else {
- /* decrement user count and add new datablock */
- /* TODO: if a datablock exists,
- * we should make a copy of it instead of starting fresh (as in other areas) */
- Main *bmain = CTX_data_main(C);
-
- /* decrement user count of old GP datablock */
- if (*gpd_ptr) {
- bGPdata *gpd = (*gpd_ptr);
- id_us_min(&gpd->id);
- }
- /* Add new datablock, with a single layer ready to use
- * (so users don't have to perform an extra step). */
- if (is_annotation) {
- bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
- *gpd_ptr = gpd;
+ /* decrement user count and add new datablock */
+ /* TODO: if a datablock exists,
+ * we should make a copy of it instead of starting fresh (as in other areas) */
+ Main *bmain = CTX_data_main(C);
- /* tag for annotations */
- gpd->flag |= GP_DATA_ANNOTATIONS;
+ /* decrement user count of old GP datablock */
+ if (*gpd_ptr) {
+ bGPdata *gpd = (*gpd_ptr);
+ id_us_min(&gpd->id);
+ }
- /* add new layer (i.e. a "note") */
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
- }
- else {
- /* GP Object Case - This shouldn't happen! */
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+ /* Add new datablock, with a single layer ready to use
+ * (so users don't have to perform an extra step). */
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+ *gpd_ptr = gpd;
- /* add default sets of colors and brushes */
- Object *ob = CTX_data_active_object(C);
- ED_gpencil_add_defaults(C, ob);
+ /* tag for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
- /* add new layer */
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
- }
- }
+ /* add new layer (i.e. a "note") */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -156,12 +135,12 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_data_add(wmOperatorType *ot)
+void GPENCIL_OT_annotation_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Grease Pencil Add New";
- ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil data-block";
+ ot->name = "Annotation Add New";
+ ot->idname = "GPENCIL_OT_annotation_add";
+ ot->description = "Add new Annotation data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
@@ -174,7 +153,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
/* poll callback for adding data/layers - special */
static bool gp_data_unlink_poll(bContext *C)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL);
/* only unlink annotation datablocks */
if ((gpd_ptr != NULL) && (*gpd_ptr != NULL)) {
@@ -190,7 +169,7 @@ static bool gp_data_unlink_poll(bContext *C)
/* unlink datablock - wrapper around API */
static int gp_data_unlink_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL);
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
@@ -231,47 +210,43 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* add new layer - wrapper around API */
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
- PointerRNA gpd_owner = {NULL};
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
- bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
+ const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_add");
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
-
- if (*gpd_ptr == NULL) {
- Main *bmain = CTX_data_main(C);
- if (is_annotation) {
- /* Annotations */
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+ PointerRNA gpd_owner = {NULL};
+ Main *bmain = CTX_data_main(C);
+ bGPdata *gpd = NULL;
- /* mark as annotation */
- (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
+ if (is_annotation) {
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner);
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
}
- else {
- /* GP Object */
- /* NOTE: This shouldn't actually happen in practice */
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
-
- /* add default sets of colors and brushes */
- Object *ob = CTX_data_active_object(C);
- ED_gpencil_add_defaults(C, ob);
+ /* Annotations */
+ if (*gpd_ptr == NULL) {
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
}
- }
- /* add new layer now */
- if (is_annotation) {
+ /* mark as annotation */
+ (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
+ gpd = *gpd_ptr;
}
else {
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ /* GP Object */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
+ gpd = (bGPdata *)ob->data;
+ BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
}
/* notifiers */
- bGPdata *gpd = *gpd_ptr;
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -291,11 +266,32 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
ot->poll = gp_add_poll;
}
+static bool gp_add_annotation_poll(bContext *C)
+{
+ return ED_annotation_data_get_pointers(C, NULL) != NULL;
+}
+
+void GPENCIL_OT_layer_annotation_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Annotation Layer";
+ ot->idname = "GPENCIL_OT_layer_annotation_add";
+ ot->description = "Add new Annotation layer or note for the active data-block";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_add_exec;
+ ot->poll = gp_add_annotation_poll;
+}
/* ******************* Remove Active Layer ************************* */
static int gp_layer_remove_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_remove");
+
+ bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
+ ED_annotation_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* sanity checks */
@@ -343,6 +339,27 @@ void GPENCIL_OT_layer_remove(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
}
+static bool gp_active_layer_annotation_poll(bContext *C)
+{
+ bGPdata *gpd = ED_annotation_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ return (gpl != NULL);
+}
+
+void GPENCIL_OT_layer_annotation_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Annotation Layer";
+ ot->idname = "GPENCIL_OT_layer_annotation_remove";
+ ot->description = "Remove active Annotation layer";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_remove_exec;
+ ot->poll = gp_active_layer_annotation_poll;
+}
/* ******************* Move Layer Up/Down ************************** */
enum {
@@ -352,7 +369,10 @@ enum {
static int gp_layer_move_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_move");
+
+ bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
+ ED_annotation_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
const int direction = RNA_enum_get(op->ptr, "type") * -1;
@@ -394,6 +414,28 @@ void GPENCIL_OT_layer_move(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
}
+void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Annotation Layer";
+ ot->idname = "GPENCIL_OT_layer_annotation_move";
+ ot->description = "Move the active Annotation layer up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gp_layer_move_exec;
+ ot->poll = gp_active_layer_annotation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
/* ********************* Duplicate Layer ************************** */
static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
@@ -995,7 +1037,7 @@ void GPENCIL_OT_lock_all(wmOperatorType *ot)
/* callbacks */
ot->exec = gp_lock_all_exec;
- ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->poll = gp_reveal_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1034,7 +1076,7 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot)
/* callbacks */
ot->exec = gp_unlock_all_exec;
- ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->poll = gp_reveal_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2176,22 +2218,22 @@ static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
if (fcu->driver) {
/* Fix driver references to invalid ID's */
for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
+ /* Only change the used targets, since the others will need fixing manually anyway. */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- /* change the ID's used... */
+ /* Change the ID's used. */
if (dtar->id == src_id) {
dtar->id = dst_id;
- /* also check on the subtarget...
- * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
- * little twists so that we know that it isn't going to clobber the wrong data
+ /* Also check on the subtarget...
+ * We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
*/
if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
GHASH_ITER (gh_iter, afd->names_map) {
const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
- /* only remap if changed */
+ /* Only remap if changed. */
if (!STREQ(old_name, new_name)) {
if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
/* Fix up path */
@@ -2230,7 +2272,6 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
}
/* Ensure all rotations are applied before */
- // XXX: Why don't we apply them here instead of warning?
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
if (ob_iter->type == OB_GPENCIL) {
if ((ob_iter->rot[0] != 0) || (ob_iter->rot[1] != 0) || (ob_iter->rot[2] != 0)) {
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index a87db4543e4..8d0fe73572f 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1650,10 +1650,23 @@ static bool gp_actframe_delete_poll(bContext *C)
return (gpl && gpl->actframe);
}
+static bool gp_annotation_actframe_delete_poll(bContext *C)
+{
+ bGPdata *gpd = ED_annotation_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* only if there's an active layer with an active frame */
+ return (gpl && gpl->actframe);
+}
+
/* delete active frame - wrapper around API calls */
static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_annotation_active_frame_delete");
+
+ bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
+ ED_annotation_data_get_active(C);
+
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
Scene *scene = CTX_data_scene(C);
@@ -1694,6 +1707,19 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->poll = gp_actframe_delete_poll;
}
+void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Active Frame";
+ ot->idname = "GPENCIL_OT_annotation_active_frame_delete";
+ ot->description = "Delete the active frame for the active Annotation Layer";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_actframe_delete_exec;
+ ot->poll = gp_annotation_actframe_delete_poll;
+}
/* **************** Delete All Active Frames ****************** */
static bool gp_actframe_delete_all_poll(bContext *C)
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 1af641e5c84..69ec11685fb 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -428,12 +428,15 @@ void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
/* buttons editing --- */
-void GPENCIL_OT_data_add(struct wmOperatorType *ot);
+void GPENCIL_OT_annotation_add(struct wmOperatorType *ot);
void GPENCIL_OT_data_unlink(struct wmOperatorType *ot);
void GPENCIL_OT_layer_add(struct wmOperatorType *ot);
void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_annotation_add(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_annotation_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_annotation_move(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot);
@@ -449,6 +452,7 @@ void GPENCIL_OT_layer_merge(struct wmOperatorType *ot);
void GPENCIL_OT_blank_frame_add(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_annotation_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_frame_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index ce410f3e52d..7a541cd8f03 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -276,12 +276,15 @@ void ED_operatortypes_gpencil(void)
/* Editing (Buttons) ------------ */
- WM_operatortype_append(GPENCIL_OT_data_add);
+ WM_operatortype_append(GPENCIL_OT_annotation_add);
WM_operatortype_append(GPENCIL_OT_data_unlink);
WM_operatortype_append(GPENCIL_OT_layer_add);
WM_operatortype_append(GPENCIL_OT_layer_remove);
WM_operatortype_append(GPENCIL_OT_layer_move);
+ WM_operatortype_append(GPENCIL_OT_layer_annotation_add);
+ WM_operatortype_append(GPENCIL_OT_layer_annotation_remove);
+ WM_operatortype_append(GPENCIL_OT_layer_annotation_move);
WM_operatortype_append(GPENCIL_OT_layer_duplicate);
WM_operatortype_append(GPENCIL_OT_layer_duplicate_object);
@@ -295,6 +298,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_blank_frame_add);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_annotation_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_frame_duplicate);
WM_operatortype_append(GPENCIL_OT_frame_clean_fill);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 67830d0e501..09ff24f05fc 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1173,7 +1173,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
/* initialize triangle memory to dummy data */
- gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->triangles = NULL;
gps->flag |= GP_STROKE_RECALC_GEOMETRY;
gps->tot_triangles = 0;
/* drawing batch cache is dirty now */
@@ -2553,12 +2553,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
{
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- return (wmtab->Active == EVT_TABLET_ERASER);
- }
-
- return false;
+ return (event->tablet.active == EVT_TABLET_ERASER);
}
/* ------------------------------- */
@@ -3020,7 +3015,6 @@ static void gpencil_draw_apply_event(bContext *C,
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
PointerRNA itemptr;
float mousef[2];
- int tablet = 0;
bool is_speed_guide = ((guide->use_guide) &&
(p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
@@ -3055,29 +3049,20 @@ static void gpencil_draw_apply_event(bContext *C,
p->curtime = PIL_check_seconds_timer();
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
+ /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
+ p->pressure = event->tablet.pressure;
- tablet = (wmtab->Active != EVT_TABLET_NONE);
- p->pressure = wmtab->Pressure;
-
- /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
- * The pen has to float over the tablet surface, resulting in
- * zero pressure (T47101). Ignore pressure values if floating
- * (i.e. "effectively zero" pressure), and only when the "active"
- * end is the stylus (i.e. the default when not eraser)
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
- p->pressure = 1.0f;
- }
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
}
}
- else {
- /* No tablet data -> No pressure info is available */
- p->pressure = 1.0f;
- }
/* special eraser modes */
if (p->paintmode == GP_PAINTMODE_ERASER) {
@@ -3101,7 +3086,7 @@ static void gpencil_draw_apply_event(bContext *C,
/* special exception here for too high pressure values on first touch in
* windows for some tablets, then we just skip first touch...
*/
- if (tablet && (p->pressure >= 0.99f)) {
+ if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) {
return;
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index f0ff38e60b1..6a0006ef04c 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -1386,7 +1386,7 @@ static void gpencil_primitive_edit_event_handling(
case LEFTMOUSE: {
if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
/* set control points and enter edit mode */
- if ((ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ if (ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
gpencil_primitive_add_segment(tgpi);
copy_v2_v2(tgpi->start, tgpi->end);
copy_v2_v2(tgpi->origin, tgpi->start);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 300d7d9e925..9b1551fe2a5 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -92,23 +92,20 @@
* and an RNA-pointer to trace back to whatever owns it,
* when context info is not available.
*/
-bGPdata **ED_gpencil_data_get_pointers_direct(
- ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr)
+bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *sa, 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) {
- SpaceLink *sl = sa->spacedata.first;
-
switch (sa->spacetype) {
- /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
case SPACE_PROPERTIES: /* properties */
- case SPACE_INFO: /* header info (needed after workspaces merge) */
- case SPACE_ACTION: /* Dopesheet header. */
+ case SPACE_INFO: /* header info */
+ case SPACE_TOPBAR: /* Topbar */
+ case SPACE_VIEW3D: /* 3D-View */
{
if (ob && (ob->type == OB_GPENCIL)) {
- /* GP Object */
+ /* GP Object. */
if (r_ptr) {
RNA_id_pointer_create(&ob->id, r_ptr);
}
@@ -120,25 +117,44 @@ bGPdata **ED_gpencil_data_get_pointers_direct(
break;
}
+ default: /* Unsupported space. */
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Get pointer to active Grease Pencil datablock for annotations,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
+bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
+ ScrArea *sa,
+ 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;
+
+ switch (sa->spacetype) {
+ case SPACE_PROPERTIES: /* properties */
+ case SPACE_INFO: /* header info */
+ {
+ return NULL;
+ break;
+ }
- case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */
+ case SPACE_TOPBAR: /* Topbar */
case SPACE_VIEW3D: /* 3D-View */
{
- if (ob && (ob->type == OB_GPENCIL)) {
- /* GP Object */
- if (r_ptr) {
- RNA_id_pointer_create(&ob->id, r_ptr);
- }
- return (bGPdata **)&ob->data;
- }
- else {
- /* Annotations */
- /* XXX: */
- if (r_ptr) {
- RNA_id_pointer_create(&scene->id, r_ptr);
- }
- return &scene->gpd;
+ if (r_ptr) {
+ RNA_id_pointer_create(&scene->id, r_ptr);
}
+ return &scene->gpd;
break;
}
@@ -156,7 +172,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(
return &snode->nodetree->gpd;
}
- /* even when there is no node-tree, don't allow this to flow to scene */
+ /* Even when there is no node-tree, don't allow this to flow to scene. */
return NULL;
}
case SPACE_SEQ: /* Sequencer */
@@ -165,7 +181,6 @@ bGPdata **ED_gpencil_data_get_pointers_direct(
/* For now, Grease Pencil data is associated with the space
* (actually preview region only). */
- /* XXX our convention for everything else is to link to data though... */
if (r_ptr) {
RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
}
@@ -175,8 +190,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(
{
SpaceImage *sima = (SpaceImage *)sl;
- /* for now, Grease Pencil data is associated with the space... */
- /* XXX our convention for everything else is to link to data though... */
+ /* For now, Grease Pencil data is associated with the space... */
if (r_ptr) {
RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
}
@@ -221,34 +235,61 @@ bGPdata **ED_gpencil_data_get_pointers_direct(
* and an RNA-pointer to trace back to whatever owns it. */
bGPdata **ED_gpencil_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);
Object *ob = CTX_data_active_object(C);
- return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr);
+ return ED_gpencil_data_get_pointers_direct(sa, ob, r_ptr);
}
+/* Get pointer to active Grease Pencil datablock,
+ * and an RNA-pointer to trace back to whatever owns it. */
+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);
+
+ return ED_annotation_data_get_pointers_direct(screen_id, sa, scene, r_ptr);
+}
/* -------------------------------------------------------- */
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob)
+bGPdata *ED_gpencil_data_get_active_direct(ScrArea *sa, Object *ob)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(sa, 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 **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, sa, scene, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
/**
* Get the active Grease Pencil datablock
+ */
+bGPdata *ED_gpencil_data_get_active(const bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return NULL;
+ }
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ return gpd;
+}
+
+/* Get the active Grease Pencil datablock
* \note This is the original (bmain) copy of the datablock, stored in files.
* Do not use for reading evaluated copies of GP Objects data
*/
-bGPdata *ED_gpencil_data_get_active(const bContext *C)
+bGPdata *ED_annotation_data_get_active(const bContext *C)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-
/**
* Get the evaluated copy of the active Grease Pencil datablock (where applicable)
* - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP datablock
@@ -259,20 +300,13 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
*/
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
- ID *screen_id = (ID *)CTX_wm_screen(C);
ScrArea *sa = CTX_wm_area(C);
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob = CTX_data_active_object(C);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
-#if 0
- if (ob && ob->type == OB_GPENCIL) {
- BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data));
- }
-#endif
- return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval);
+ return ED_gpencil_data_get_active_direct(sa, ob_eval);
}
/* -------------------------------------------------------- */
@@ -318,14 +352,23 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
/* poll callback for adding data/layers - special */
bool gp_add_poll(bContext *C)
{
- /* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return false;
+ }
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ return (gpd != NULL);
}
/* poll callback for checking if there is an active layer */
bool gp_active_layer_poll(bContext *C)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+ bGPdata *gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
return (gpl != NULL);
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 4d8da1acb4b..e09f101af73 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -26,7 +26,6 @@
#define __ED_GIZMO_LIBRARY_H__
/* initialize gizmos */
-void ED_gizmotypes_arrow_2d(void);
void ED_gizmotypes_arrow_3d(void);
void ED_gizmotypes_button_2d(void);
void ED_gizmotypes_cage_2d(void);
@@ -92,11 +91,6 @@ void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const fl
void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
/* -------------------------------------------------------------------- */
-/* 2D Arrow Gizmo */
-
-/* none */
-
-/* -------------------------------------------------------------------- */
/* Cage Gizmo */
enum {
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index dce0e3931be..23dbf24ed7b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -97,15 +97,21 @@ 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 ID *screen_id,
- struct ScrArea *sa,
- struct Scene *scene,
+struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *sa,
struct Object *ob,
struct PointerRNA *r_ptr);
-struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id,
- struct ScrArea *sa,
- struct Scene *scene,
- struct Object *ob);
+struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *sa, 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 Scene *scene,
+ struct PointerRNA *r_ptr);
+struct bGPdata *ED_annotation_data_get_active_direct(struct ID *screen_id,
+ struct ScrArea *sa,
+ struct Scene *scene);
bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 16b3c9c240a..ac3007afe5d 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -492,6 +492,12 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+bool ED_autokeyframe_property(struct bContext *C,
+ struct Scene *scene,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ float cfra);
/* Names for builtin keying sets so we don't confuse these with labels/text,
* defined in python script: keyingsets_builtins.py */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 4bf43a2034a..95d6d5cab3b 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -104,12 +104,12 @@ bool EDBM_vert_color_check(struct BMEditMesh *em);
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap);
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select);
-void EDBM_update_generic(struct BMEditMesh *em,
- const bool do_tessellation,
- const bool is_destructive);
+void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
- const bool selected,
+ const struct Scene *scene,
+ const bool face_selected,
+ const bool uv_selected,
const bool use_winding,
const bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *vmap);
@@ -142,9 +142,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
/* 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,
- bool split_edges,
- bool split_faces,
- bool update,
+ const bool split_edges,
+ const bool split_faces,
+ const bool update,
const char hflag,
const float dist);
@@ -152,8 +152,12 @@ void EDBM_automerge_and_split(struct Object *ob,
void ED_mesh_undosys_type(struct UndoType *ut);
/* editmesh_select.c */
-void EDBM_select_mirrored(
- struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail);
+void EDBM_select_mirrored(struct BMEditMesh *em,
+ const struct Mesh *me,
+ const int axis,
+ const bool extend,
+ int *r_totmirr,
+ int *r_totfail);
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *r_dist,
@@ -293,6 +297,7 @@ void ED_keymap_mesh(struct wmKeyConfig *keyconf);
void EDBM_project_snap_verts(struct bContext *C,
struct Depsgraph *depsgraph,
struct ARegion *ar,
+ struct Object *obedit,
struct BMEditMesh *em);
/* editface.c */
@@ -329,11 +334,11 @@ typedef struct MirrTopoStore_t {
bool prev_is_editmode;
} MirrTopoStore_t;
-bool ED_mesh_mirrtopo_recalc_check(struct Mesh *me,
- struct Mesh *me_eval,
+bool ED_mesh_mirrtopo_recalc_check(struct BMEditMesh *em,
+ struct Mesh *me,
MirrTopoStore_t *mesh_topo_store);
-void ED_mesh_mirrtopo_init(struct Mesh *me,
- struct Mesh *me_eval,
+void ED_mesh_mirrtopo_init(struct BMEditMesh *em,
+ struct Mesh *me,
MirrTopoStore_t *mesh_topo_store,
const bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 6a801fc9928..9e0272d1402 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -69,7 +69,7 @@ void ED_region_exit(struct bContext *C, struct ARegion *ar);
void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
void ED_region_pixelspace(struct ARegion *ar);
void ED_region_update_rect(struct ARegion *ar);
-void ED_region_init(struct ARegion *ar);
+void ED_region_floating_initialize(struct ARegion *ar);
void ED_region_tag_redraw(struct ARegion *ar);
void ED_region_tag_redraw_partial(struct ARegion *ar, const struct rcti *rct, bool rebuild);
void ED_region_tag_redraw_overlay(struct ARegion *ar);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 29bac9df93a..d53ad7c4229 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -29,6 +29,7 @@
struct Object;
struct bContext;
struct wmKeyConfig;
+struct wmMsgBus;
struct wmOperatorType;
void ED_keymap_transform(struct wmKeyConfig *keyconf);
@@ -165,28 +166,11 @@ void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
/* *** transform_gizmo_extrude_3d.c *** */
void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt);
-/* Transform: Axis/Cage */
-bool ED_widgetgroup_gizmo2d_xform_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
-void ED_widgetgroup_gizmo2d_xform_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_xform_setup_no_cage(const struct bContext *C,
- struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_xform_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_xform_draw_prepare(const struct bContext *C,
- struct wmGizmoGroup *gzgroup);
-
-/* Resize: Axis */
-bool ED_widgetgroup_gizmo2d_resize_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
-void ED_widgetgroup_gizmo2d_resize_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_resize_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_resize_draw_prepare(const struct bContext *C,
- struct wmGizmoGroup *gzgroup);
-
-/* Rotate: Axis */
-bool ED_widgetgroup_gizmo2d_rotate_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
-void ED_widgetgroup_gizmo2d_rotate_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_rotate_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const struct bContext *C,
- struct wmGizmoGroup *gzgroup);
+/* Generic 2D transform gizmo callback assignment. */
+void ED_widgetgroup_gizmo2d_xform_callbacks_set(struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_resize_callbacks_set(struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
#define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 003e84bbf05..8cce8fa973a 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -35,8 +35,14 @@ void ED_editors_init_for_undo(struct Main *bmain);
void ED_editors_init(struct bContext *C);
void ED_editors_exit(struct Main *bmain, bool do_undo_system);
+bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
+ struct Object *ob,
+ bool for_render,
+ bool check_needs_flush);
+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, bool for_render);
+bool ED_editors_flush_edits(struct Main *bmain);
void ED_spacedata_id_remap(struct ScrArea *sa,
struct SpaceLink *sl,
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 1856ad8454b..c912778afd8 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -45,24 +45,38 @@ struct wmKeyConfig;
void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
-bool ED_uvedit_minmax(
- struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
-bool ED_uvedit_center(Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode);
+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(struct Scene *scene,
+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(Scene *scene,
+bool ED_uvedit_center_multi(const struct Scene *scene,
Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_cent[2],
char mode);
+bool ED_uvedit_center_from_pivot_ex(struct SpaceImage *sima,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ float r_center[2],
+ char mode,
+ bool *r_has_select);
+bool ED_uvedit_center_from_pivot(struct SpaceImage *sima,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ float r_center[2],
+ char mode);
+
bool ED_object_get_active_image(struct Object *ob,
int mat_nr,
struct Image **r_ima,
@@ -92,70 +106,76 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_visible_test(struct Scene *scene,
+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_select_test(struct Scene *scene, struct BMFace *efa, const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset);
+bool uvedit_face_select_test(const struct Scene *scene,
+ struct BMFace *efa,
+ const int cd_loop_uv_offset);
+bool uvedit_edge_select_test(const struct Scene *scene,
+ struct BMLoop *l,
+ const int cd_loop_uv_offset);
+bool uvedit_uv_select_test(const struct Scene *scene,
+ struct BMLoop *l,
+ const int cd_loop_uv_offset);
/* uv face */
-bool uvedit_face_select_set(struct Scene *scene,
+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);
-bool uvedit_face_select_enable(struct Scene *scene,
+bool uvedit_face_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const bool do_history,
const int cd_loop_uv_offset);
-bool uvedit_face_select_disable(struct Scene *scene,
+bool uvedit_face_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const int cd_loop_uv_offset);
/* uv edge */
void uvedit_edge_select_set(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool select,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_edge_select_enable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_edge_select_disable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const int cd_loop_uv_offset);
/* uv vert */
void uvedit_uv_select_set(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool select,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_uv_select_enable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const bool do_history,
const int cd_loop_uv_offset);
void uvedit_uv_select_disable(struct BMEditMesh *em,
- struct Scene *scene,
+ const struct Scene *scene,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool ED_uvedit_nearest_uv(struct Scene *scene,
+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(struct Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
struct Image *ima,
struct Object **objects,
const uint objects_len,
@@ -164,20 +184,20 @@ bool ED_uvedit_nearest_uv_multi(struct Scene *scene,
float r_uv[2]);
void ED_uvedit_get_aspect(
- struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
+ const struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
/* uvedit_unwrap_ops.c */
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
-void ED_uvedit_live_unwrap(struct Scene *scene, struct Object **objects, int objects_len);
-void ED_uvedit_add_simple_uvs(struct Main *bmain, struct Scene *scene, struct Object *ob);
+void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len);
+void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob);
/* uvedit_draw.c */
void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]);
void ED_uvedit_draw_main(struct SpaceImage *sima,
- struct Scene *scene,
+ const struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *obedit,
struct Object *obact,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 44c734e264a..fabf6baed23 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -134,7 +134,7 @@ DEF_ICON(RECOVER_LAST)
DEF_ICON(THREE_DOTS)
DEF_ICON(FULLSCREEN_ENTER)
DEF_ICON(FULLSCREEN_EXIT)
-DEF_ICON_BLANK(135)
+DEF_ICON(BRUSHES_ALL)
/* BUTTONS */
DEF_ICON_SHADING(LIGHT)
@@ -452,11 +452,11 @@ DEF_ICON(NODE_INSERT_OFF)
DEF_ICON(NODE_TOP)
DEF_ICON(NODE_SIDE)
DEF_ICON(NODE_CORNER)
-DEF_ICON_BLANK(698)
-DEF_ICON_BLANK(699)
-DEF_ICON_BLANK(700)
-DEF_ICON_BLANK(701)
-DEF_ICON_BLANK(702)
+DEF_ICON(ANCHOR_TOP)
+DEF_ICON(ANCHOR_BOTTOM)
+DEF_ICON(ANCHOR_LEFT)
+DEF_ICON(ANCHOR_RIGHT)
+DEF_ICON(ANCHOR_CENTER)
DEF_ICON_BLANK(703)
DEF_ICON_BLANK(704)
DEF_ICON_BLANK(705)
@@ -793,7 +793,7 @@ DEF_ICON(BOOKMARKS)
DEF_ICON(FONTPREVIEW)
DEF_ICON(FILTER)
DEF_ICON(NEWFOLDER)
-DEF_ICON_BLANK(794)
+DEF_ICON(FOLDER_REDIRECT)
DEF_ICON(FILE_PARENT)
DEF_ICON(FILE_REFRESH)
DEF_ICON_FOLDER(FILE_FOLDER)
@@ -876,11 +876,11 @@ DEF_ICON(IMAGE_RGB) // XXX CHANGE TO STRAIGHT ALPHA, Z ETC
DEF_ICON(IMAGE_RGB_ALPHA)
DEF_ICON(IMAGE_ALPHA)
DEF_ICON(IMAGE_ZDEPTH)
-DEF_ICON_BLANK(877)
-DEF_ICON_BLANK(878)
-DEF_ICON_BLANK(879)
-DEF_ICON_BLANK(880)
-DEF_ICON_BLANK(881)
+DEF_ICON(HANDLE_AUTOCLAMPED)
+DEF_ICON(HANDLE_AUTO)
+DEF_ICON(HANDLE_ALIGNED)
+DEF_ICON(HANDLE_VECTOR)
+DEF_ICON(HANDLE_FREE)
DEF_ICON_BLANK(882)
DEF_ICON_BLANK(883)
DEF_ICON_BLANK(884)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index b81fa4ae483..3089d980f06 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1640,7 +1640,12 @@ struct Panel *UI_panel_begin(struct ScrArea *sa,
struct PanelType *pt,
struct Panel *pa,
bool *r_open);
-void UI_panel_end(uiBlock *block, int width, int height, bool open);
+void UI_panel_end(const struct ScrArea *sa,
+ const struct ARegion *ar,
+ uiBlock *block,
+ int width,
+ int height,
+ bool open);
void UI_panels_scale(struct ARegion *ar, 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);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index bd8eed4e4aa..1e6e46cbe71 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -143,6 +143,7 @@ typedef enum ThemeColorID {
TH_BONE_SOLID,
TH_BONE_POSE,
TH_BONE_POSE_ACTIVE,
+ TH_BONE_LOCKED_WEIGHT,
TH_STRIP,
TH_STRIP_SELECT,
@@ -320,6 +321,10 @@ typedef enum ThemeColorID {
TH_INFO_INFO_TEXT,
TH_INFO_DEBUG,
TH_INFO_DEBUG_TEXT,
+ TH_INFO_PROPERTY,
+ TH_INFO_PROPERTY_TEXT,
+ TH_INFO_OPERATOR,
+ TH_INFO_OPERATOR_TEXT,
TH_VIEW_OVERLAY,
TH_V3D_CLIPPING_BORDER,
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index cc68e303e4a..c058fefb4fa 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -124,7 +124,7 @@ bool ui_but_can_align(const uiBut *but)
int ui_but_align_opposite_to_area_align_get(const ARegion *ar)
{
- switch (ar->alignment) {
+ switch (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)) {
case RGN_ALIGN_TOP:
return UI_BUT_ALIGN_DOWN;
case RGN_ALIGN_BOTTOM:
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index c8baa1a7c7b..15fc23bc539 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -270,79 +270,8 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
{
- Main *bmain = CTX_data_main(C);
- ID *id;
- bAction *action;
- FCurve *fcu;
- bool driven;
- bool special;
-
- fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special);
-
- if (fcu == NULL) {
- return;
- }
-
- if (special) {
- /* NLA Strip property */
- if (IS_AUTOKEY_ON(scene)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
-
- insert_keyframe_direct(
- reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, NULL, 0);
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
- }
- }
- else if (driven) {
- /* Driver - Try to insert keyframe using the driver's input as the frame,
- * making it easier to set up corrective drivers
- */
- if (IS_AUTOKEY_ON(scene)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
-
- insert_keyframe_direct(reports,
- but->rnapoin,
- but->rnaprop,
- fcu,
- cfra,
- ts->keyframe_type,
- NULL,
- INSERTKEY_DRIVER);
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
- }
- }
- else {
- id = but->rnapoin.owner_id;
-
- /* TODO: this should probably respect the keyingset only option for anim */
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- short flag = ANIM_get_keyframing_flags(scene, 1);
-
- fcu->flag &= ~FCURVE_SELECTED;
-
- /* Note: We use but->rnaindex instead of fcu->array_index,
- * because a button may control all items of an array at once.
- * E.g., color wheels (see T42567). */
- BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1));
- insert_keyframe(bmain,
- reports,
- id,
- action,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- but->rnaindex,
- cfra,
- ts->keyframe_type,
- NULL,
- flag);
-
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
- }
- }
+ const int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
+ ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, rnaindex, cfra);
}
void ui_but_anim_copy_driver(bContext *C)
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index b34188684e6..7332f3ee776 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -791,7 +791,10 @@ static void ui_apply_but_undo(uiBut *but)
/* Exception for renaming ID data, we always need undo pushes in this case,
* because undo systems track data by their ID, see: T67002. */
extern PropertyRNA rna_ID_name;
- if (but->rnaprop == &rna_ID_name) {
+ /* Exception for active shape-key, since changing this in edit-mode updates
+ * the shape key from object mode data. */
+ extern PropertyRNA rna_Object_active_shape_key_index;
+ if (ELEM(but->rnaprop, &rna_ID_name, &rna_Object_active_shape_key_index)) {
/* pass */
}
else {
@@ -1886,11 +1889,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);
int lock_axis = -1;
- if (ELEM(data->region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+
+ if (ELEM(ar_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
lock_axis = 0;
}
- else if (ELEM(data->region->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ else if (ELEM(ar_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
lock_axis = 1;
}
if (lock_axis != -1) {
@@ -2237,7 +2242,13 @@ static void ui_but_set_float_array(
RNA_property_float_set_index(&but->rnapoin, but->rnaprop, i, values[i]);
}
if (data) {
- data->value = values[but->rnaindex];
+ if (but->type == UI_BTYPE_UNITVEC) {
+ BLI_assert(array_length == 3);
+ copy_v3_v3(data->vec, values);
+ }
+ else {
+ data->value = values[but->rnaindex];
+ }
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -2346,7 +2357,10 @@ static void ui_but_paste_numeric_value(bContext *C,
}
}
-static void ui_but_paste_normalized_vector(bContext *C, uiBut *but, char *buf_paste)
+static void ui_but_paste_normalized_vector(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ char *buf_paste)
{
float xyz[3];
if (parse_float_array(buf_paste, xyz, 3)) {
@@ -2354,7 +2368,7 @@ static void ui_but_paste_normalized_vector(bContext *C, uiBut *but, char *buf_pa
/* better set Z up then have a zero vector */
xyz[2] = 1.0;
}
- ui_but_set_float_array(C, but, NULL, xyz, 3);
+ ui_but_set_float_array(C, but, data, xyz, 3);
}
else {
WM_report(RPT_ERROR, "Paste expected 3 numbers, formatted: '[n, n, n]'");
@@ -2642,7 +2656,7 @@ static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, cons
if (!has_required_data) {
break;
}
- ui_but_paste_normalized_vector(C, but, buf_paste);
+ ui_but_paste_normalized_vector(C, but, data, buf_paste);
break;
case UI_BTYPE_COLOR:
@@ -4360,8 +4374,10 @@ static int ui_do_but_TEX(
else if (but->dt == UI_EMBOSS_NONE && !event->ctrl) {
/* pass */
}
- else if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ else {
+ if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ }
return WM_UI_HANDLER_BREAK;
}
}
@@ -9501,7 +9517,8 @@ static int ui_handle_menu_event(bContext *C,
* To support we would need UI_RETURN_OUT_PARENT to be handled by
* top-level buttons, not just menus. Note that this isn't very important
* since it's easy to manually close these menus by clicking on them. */
- menu->menuretval = (level > 0) ? UI_RETURN_OUT_PARENT : UI_RETURN_OUT;
+ menu->menuretval = (level > 0 && is_parent_inside) ? UI_RETURN_OUT_PARENT :
+ UI_RETURN_OUT;
}
}
retval = WM_UI_HANDLER_BREAK;
@@ -9548,18 +9565,29 @@ static int ui_handle_menu_event(bContext *C,
break;
case WHEELUPMOUSE:
- case WHEELDOWNMOUSE: {
+ case WHEELDOWNMOUSE:
+ case MOUSEPAN: {
if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
}
else if (!ui_block_is_menu(block)) {
- const int scroll_dir = (event->type == WHEELUPMOUSE) ? 1 : -1;
- if (ui_menu_scroll_step(ar, block, scroll_dir)) {
- if (but) {
- but->active->cancel = true;
- button_activate_exit(C, but, but->active, false, false);
+ int type = event->type;
+ int val = event->val;
+
+ /* convert pan to scrollwheel */
+ if (type == MOUSEPAN) {
+ ui_pan_to_scroll(event, &type, &val);
+ }
+
+ if (type != MOUSEPAN) {
+ const int scroll_dir = (type == WHEELUPMOUSE) ? 1 : -1;
+ if (ui_menu_scroll_step(ar, block, scroll_dir)) {
+ if (but) {
+ but->active->cancel = true;
+ button_activate_exit(C, but, but->active, false, false);
+ }
+ WM_event_add_mousemove(C);
}
- WM_event_add_mousemove(C);
}
break;
}
@@ -9571,7 +9599,6 @@ static int ui_handle_menu_event(bContext *C,
case PAGEDOWNKEY:
case HOMEKEY:
case ENDKEY:
- case MOUSEPAN:
/* arrowkeys: only handle for block_loop blocks */
if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
@@ -10586,15 +10613,11 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
* number sliding, text editing, or when a menu block is open */
static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSED(userdata))
{
- ARegion *ar;
+ ARegion *menu_region = CTX_wm_menu(C);
+ ARegion *ar = menu_region ? menu_region : CTX_wm_region(C);
uiBut *but;
int retval = WM_UI_HANDLER_CONTINUE;
- ar = CTX_wm_menu(C);
- if (!ar) {
- ar = CTX_wm_region(C);
- }
-
but = ui_region_find_active_but(ar);
if (but) {
@@ -10613,7 +10636,13 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
(ui_screen_region_find_mouse_over(screen, event) == NULL) &&
(ELEM(but->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU)) &&
(but_other = ui_but_find_mouse_over(ar, event)) && (but != but_other) &&
- (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU))) {
+ (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU)) &&
+ /* Hover-opening menu's doesn't work well for buttons over one another
+ * along the same axis the menu is opening on (see T71719). */
+ (((data->menu->direction & (UI_DIR_LEFT | UI_DIR_RIGHT)) &&
+ BLI_rctf_isect_rect_x(&but->rect, &but_other->rect, NULL)) ||
+ ((data->menu->direction & (UI_DIR_DOWN | UI_DIR_UP)) &&
+ BLI_rctf_isect_rect_y(&but->rect, &but_other->rect, NULL)))) {
/* if mouse moves to a different root-level menu button,
* open it to replace the current menu */
if ((but_other->flag & UI_BUT_DISABLED) == 0) {
@@ -10651,9 +10680,18 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
ui_blocks_set_tooltips(ar, true);
}
+ if (but && but->active && but->active->menu) {
+ /* Set correct context menu-region. The handling button above breaks if we set the region
+ * first, so only set it for executing the after-funcs. */
+ CTX_wm_menu_set(C, but->active->menu->region);
+ }
+
/* delayed apply callbacks */
ui_apply_but_funcs_after(C);
+ /* Reset to previous context region. */
+ CTX_wm_menu_set(C, menu_region);
+
/* Don't handle double-click events,
* these will be converted into regular clicks which we handle. */
if (retval == WM_UI_HANDLER_CONTINUE) {
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 5f25316cf25..41606fce915 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -804,45 +804,6 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
return result;
}
-/* Generate the mipmap levels for the icon textures
- * During creation the source16 ImBuf will be freed to reduce memory overhead
- * A new ImBuf will be returned that needs is owned by the caller.
- *
- * FIXME: Mipmap levels are generated until the width of the image is 1, which
- * are too many levels than that are needed.*/
-static ImBuf *create_mono_icon_mipmaps(ImBuf *source32, ImBuf *source16, int level)
-{
- if (level == 0) {
- glTexImage2D(GL_TEXTURE_2D,
- level,
- GL_RGBA8,
- source32->x,
- source32->y,
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- source32->rect);
- return create_mono_icon_mipmaps(source32, source16, level + 1);
- }
- else {
- glTexImage2D(GL_TEXTURE_2D,
- level,
- GL_RGBA8,
- source16->x,
- source16->y,
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- source16->rect);
- if (source16->x > 1) {
- ImBuf *nbuf = IMB_onehalf(source16);
- IMB_freeImBuf(source16);
- source16 = create_mono_icon_mipmaps(source32, nbuf, level + 1);
- }
- return source16;
- }
-}
-
static void free_icons_textures(void)
{
if (icongltex.num_textures > 0) {
@@ -900,6 +861,8 @@ void UI_icons_reload_internal_textures(void)
icongltex.num_textures = need_icons_with_border ? 2 : 1;
glGenTextures(icongltex.num_textures, icongltex.id);
+ /* Note the filter and LOD bias were tweaked to better preserve icon
+ * sharpness at different UI scales. */
if (icongltex.id[0]) {
icongltex.w = b32buf->x;
icongltex.h = b32buf->y;
@@ -907,17 +870,57 @@ void UI_icons_reload_internal_textures(void)
icongltex.invh = 1.0f / b32buf->y;
glBindTexture(GL_TEXTURE_2D, icongltex.id[0]);
- b16buf = create_mono_icon_mipmaps(b32buf, b16buf, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA8,
+ b32buf->x,
+ b32buf->y,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ b32buf->rect);
+ glTexImage2D(GL_TEXTURE_2D,
+ 1,
+ GL_RGBA8,
+ b16buf->x,
+ b16buf->y,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ b16buf->rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
}
if (need_icons_with_border && icongltex.id[1]) {
glBindTexture(GL_TEXTURE_2D, icongltex.id[1]);
- b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA8,
+ b32buf_border->x,
+ b32buf_border->y,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ b32buf_border->rect);
+ glTexImage2D(GL_TEXTURE_2D,
+ 1,
+ GL_RGBA8,
+ b16buf_border->x,
+ b16buf_border->y,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ b16buf_border->rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
@@ -1506,7 +1509,7 @@ static void icon_draw_rect(float x,
return;
}
/* modulate color */
- float col[4] = {1.0f, 1.0f, 1.0f, alpha};
+ float col[4] = {alpha, alpha, alpha, alpha};
/* rect contains image in 'rendersize', we only scale if needed */
if (rw != w || rh != h) {
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index b7fd953ed63..3cc7aaddf38 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -74,79 +74,35 @@
#include "interface_intern.h"
-static void icon_draw_rect_input_small_text_ex(
- const rctf *rect, const float color[4], const float margin[2], const char *str, int font_size)
+static void icon_draw_rect_input_text(
+ const rctf *rect, const float color[4], const char *str, int font_size)
{
BLF_batch_draw_flush();
const int font_id = BLF_default();
BLF_color4fv(font_id, color);
BLF_size(font_id, font_size * U.pixelsize, U.dpi);
- BLF_position(font_id, rect->xmin + margin[0] * 2, rect->ymin + margin[1] * 5, 0.0f);
+ float width, height;
+ BLF_width_and_height(font_id, str, BLF_DRAW_STR_DUMMY_MAX, &width, &height);
+ float x = rect->xmin + (((rect->xmax - rect->xmin) - width) / 2.0f);
+ float y = rect->ymin + (((rect->ymax - rect->ymin) - height) / 2.0f);
+ BLF_position(font_id, x, y, 0.0f);
BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
BLF_batch_draw_flush();
}
-static void icon_draw_rect_input_small_text(const rctf *rect,
- const float color[4],
- const float margin[2],
- const char *str)
-{
- icon_draw_rect_input_small_text_ex(rect, color, margin, str, 8);
-}
-
-static void icon_draw_rect_input_default_text(const rctf *rect,
- const float color[4],
- const float margin[2],
- const char *str)
-{
- BLF_batch_draw_flush();
- const int font_id = BLF_default();
- BLF_color4fv(font_id, color);
- BLF_position(
- font_id, (int)(rect->xmin + margin[0] * 5), (int)(rect->ymin + margin[1] * 5), 0.0f);
- BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_batch_draw_flush();
-}
-
-static void icon_draw_rect_input_mono_text(const rctf *rect,
- const float color[4],
- const float margin[2],
- const char *str)
+static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4], const char *str)
{
BLF_batch_draw_flush();
const int font_id = blf_mono_font;
BLF_color4fv(font_id, color);
- BLF_size(font_id, 20 * U.pixelsize, U.dpi);
- BLF_position(
- font_id, (int)(rect->xmin + margin[0] * 5), (int)(rect->ymin + margin[1] * 5), 0.0f);
+ BLF_size(font_id, 19 * U.pixelsize, U.dpi);
+ float x = rect->xmin + (2.0f * U.pixelsize);
+ float y = rect->ymin + (1.0f * U.pixelsize);
+ BLF_position(font_id, x, y, 0.0f);
BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
BLF_batch_draw_flush();
}
-static void icon_draw_rect_input_line_prim(
- const rctf *rect, const float color[4], const int prim, const char lines[][2], int lines_len)
-{
- GPU_line_smooth(true);
- GPU_blend(true);
- BLI_assert(ELEM(prim, GPU_PRIM_LINE_LOOP, GPU_PRIM_LINE_STRIP));
- const uint pos_id = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4fv(color);
- immBegin(prim, lines_len);
- float w_inv = BLI_rctf_size_x(rect) / 255.0f;
- float h_inv = BLI_rctf_size_y(rect) / 255.0f;
- for (int i = 0; i < lines_len; i++) {
- immVertex2f(pos_id,
- round_fl_to_int(rect->xmin + ((float)lines[i][0] * w_inv)),
- round_fl_to_int(rect->ymin + ((float)lines[i][1] * h_inv)));
- }
- immEnd();
- immUnbindProgram();
- GPU_line_smooth(false);
- GPU_blend(false);
-}
-
void icon_draw_rect_input(float x,
float y,
int w,
@@ -156,11 +112,26 @@ void icon_draw_rect_input(float x,
short UNUSED(event_value))
{
float color[4];
- const float margin[2] = {w / 20.0f, h / 20.0f};
GPU_line_width(1.0f);
UI_GetThemeColor4fv(TH_TEXT, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(false, (int)x, (int)y, (int)(x + w), (int)(y + h), 4.0f, color);
+ UI_draw_roundbox_aa(
+ false, (int)x - U.pixelsize, (int)y, (int)(x + w), (int)(y + h), 3.0f * U.pixelsize, color);
+
+ const enum {
+ UNIX,
+ MACOS,
+ MSWIN,
+ } platform =
+
+#if defined(__APPLE__)
+ MACOS
+#elif defined(_WIN32)
+ MSWIN
+#else
+ UNIX
+#endif
+ ;
const rctf rect = {
.xmin = x,
@@ -169,125 +140,88 @@ void icon_draw_rect_input(float x,
.ymax = y + h,
};
- const bool simple_text = false;
-
if ((event_type >= AKEY) && (event_type <= ZKEY)) {
char str[2] = {'A' + (event_type - AKEY), '\0'};
- icon_draw_rect_input_default_text(&rect, color, margin, str);
+ icon_draw_rect_input_text(&rect, color, str, 13);
}
else if ((event_type >= F1KEY) && (event_type <= F12KEY)) {
char str[4];
SNPRINTF(str, "F%d", 1 + (event_type - F1KEY));
- icon_draw_rect_input_default_text(&rect, color, margin, str);
+ icon_draw_rect_input_text(&rect, color, str, event_type > F9KEY ? 8 : 10);
}
else if (event_type == LEFTSHIFTKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Shift");
- }
- else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -14.0f), (w / -14.0f));
- icon_draw_rect_input_mono_text(
- &rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa7, 0x0});
- }
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0});
}
else if (event_type == LEFTCTRLKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Ctrl");
+ if (platform == MACOS) {
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0});
}
else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -16.0f), 0.0f);
- icon_draw_rect_input_default_text(&rect_ofs, color, margin, "^");
+ icon_draw_rect_input_text(&rect, color, "Ctrl", 9);
}
}
else if (event_type == LEFTALTKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Alt");
+ if (platform == MACOS) {
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
}
else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -8.0f), 0.0f);
- icon_draw_rect_input_default_text(
- &rect_ofs, color, margin, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
+ icon_draw_rect_input_text(&rect, color, "Alt", 10);
}
}
else if (event_type == OSKEY) {
- icon_draw_rect_input_small_text(&rect, color, margin, "OS");
+ if (platform == MACOS) {
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x98, 0x0});
+ }
+ else if (platform == MSWIN) {
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0});
+ }
+ else {
+ icon_draw_rect_input_text(&rect, color, "OS", 10);
+ }
}
else if (event_type == DELKEY) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Del");
+ icon_draw_rect_input_text(&rect, color, "Del", 9);
}
else if (event_type == TABKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Tab");
- }
- else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f));
- icon_draw_rect_input_mono_text(
- &rect_ofs, color, margin, (const char[]){0xe2, 0x86, 0xb9, 0x0});
- }
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0});
}
else if (event_type == HOMEKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Home");
- }
- else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f));
- icon_draw_rect_input_mono_text(
- &rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa4, 0x0});
- }
+ icon_draw_rect_input_text(&rect, color, "Home", 6);
}
else if (event_type == ENDKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "End");
- }
- else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f));
- icon_draw_rect_input_mono_text(
- &rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa5, 0x0});
- }
+ icon_draw_rect_input_text(&rect, color, "End", 8);
}
else if (event_type == RETKEY) {
- if (simple_text) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Ret");
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0});
+ }
+ else if (event_type == ESCKEY) {
+ if (platform == MACOS) {
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0});
}
else {
- rctf rect_ofs = rect;
- BLI_rctf_translate(&rect_ofs, (w / -8.0f), (w / -6.0f));
- icon_draw_rect_input_mono_text(
- &rect_ofs, color, margin, (const char[]){0xe2, 0x8f, 0x8e, 0x0});
+ icon_draw_rect_input_text(&rect, color, "Esc", 8);
}
}
- else if (event_type == ESCKEY) {
- icon_draw_rect_input_small_text(&rect, color, margin, "Esc");
- }
else if (event_type == PAGEUPKEY) {
- icon_draw_rect_input_small_text_ex(
- &rect, color, margin, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 10);
+ icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8);
}
else if (event_type == PAGEDOWNKEY) {
- icon_draw_rect_input_small_text_ex(
- &rect, color, margin, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 10);
+ icon_draw_rect_input_text(
+ &rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8);
}
else if (event_type == LEFTARROWKEY) {
- icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x90, 0x0});
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0});
}
else if (event_type == UPARROWKEY) {
- icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x91, 0x0});
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x91, 0x0});
}
else if (event_type == RIGHTARROWKEY) {
- icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x92, 0x0});
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x92, 0x0});
}
else if (event_type == DOWNARROWKEY) {
- icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x93, 0x0});
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x93, 0x0});
}
else if (event_type == SPACEKEY) {
- const uchar lines[] = {60, 118, 60, 60, 195, 60, 195, 118};
- icon_draw_rect_input_line_prim(
- &rect, color, GPU_PRIM_LINE_STRIP, (const void *)lines, ARRAY_SIZE(lines) / 2);
+ icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x90, 0xa3, 0x0});
}
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 52696475c20..64c0e11976b 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1067,7 +1067,7 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C,
PropertyRNA **r_prop,
bool *r_is_undo)
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *ar = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
uiBlock *block;
uiBut *but, *prevbut = NULL;
@@ -1241,17 +1241,19 @@ static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but
char direction = UI_DIR_DOWN;
if (!but->drawstr[0]) {
- if (butregion->alignment == RGN_ALIGN_LEFT) {
- direction = UI_DIR_RIGHT;
- }
- else if (butregion->alignment == RGN_ALIGN_RIGHT) {
- direction = UI_DIR_LEFT;
- }
- else if (butregion->alignment == RGN_ALIGN_BOTTOM) {
- direction = UI_DIR_UP;
- }
- else {
- direction = UI_DIR_DOWN;
+ switch (RGN_ALIGN_ENUM_FROM_MASK(butregion->alignment)) {
+ case RGN_ALIGN_LEFT:
+ direction = UI_DIR_RIGHT;
+ break;
+ case RGN_ALIGN_RIGHT:
+ direction = UI_DIR_LEFT;
+ break;
+ case RGN_ALIGN_BOTTOM:
+ direction = UI_DIR_UP;
+ break;
+ default:
+ direction = UI_DIR_DOWN;
+ break;
}
}
UI_block_direction_set(block, direction);
@@ -2436,6 +2438,10 @@ void uiItemEnumR_string_prop(uiLayout *layout,
}
for (a = 0; item[a].identifier; a++) {
+ if (item[a].identifier[0] == '\0') {
+ /* Skip enum item separators. */
+ continue;
+ }
if (item[a].value == ivalue) {
const char *item_name = name ?
name :
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 8adb82a22c8..cc1b7187e45 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -131,7 +131,7 @@ typedef enum eSpaceButtons_Align {
BUT_AUTO = 2,
} eSpaceButtons_Align;
-static int panel_aligned(ScrArea *sa, ARegion *ar)
+static int panel_aligned(const ScrArea *sa, const ARegion *ar)
{
if (sa->spacetype == SPACE_PROPERTIES && ar->regiontype == RGN_TYPE_WINDOW) {
return BUT_VERTICAL;
@@ -367,7 +367,19 @@ Panel *UI_panel_begin(
return pa;
}
-void UI_panel_end(uiBlock *block, int width, int height, bool open)
+static float panel_region_offset_x_get(const ARegion *ar, int align)
+{
+ if (UI_panel_category_is_visible(ar)) {
+ if (align == BUT_VERTICAL && (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) != RGN_ALIGN_RIGHT)) {
+ return UI_PANEL_CATEGORY_MARGIN_WIDTH;
+ }
+ }
+
+ return 0;
+}
+
+void UI_panel_end(
+ const ScrArea *sa, const ARegion *ar, uiBlock *block, int width, int height, bool open)
{
Panel *pa = block->panel;
@@ -391,6 +403,7 @@ void UI_panel_end(uiBlock *block, int width, int height, bool open)
}
else {
int old_sizex = pa->sizex, old_sizey = pa->sizey;
+ int old_region_ofsx = pa->runtime.region_ofsx;
/* update width/height if non-zero */
if (width != 0) {
@@ -405,6 +418,11 @@ void UI_panel_end(uiBlock *block, int width, int height, bool open)
pa->runtime_flag |= PNL_ANIM_ALIGN;
pa->ofsy += old_sizey - pa->sizey;
}
+
+ int align = panel_aligned(sa, ar);
+ if (old_region_ofsx != panel_region_offset_x_get(ar, align)) {
+ pa->runtime_flag |= PNL_ANIM_ALIGN;
+ }
}
}
@@ -1004,7 +1022,6 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
int a, tot = 0;
bool done;
int align = panel_aligned(sa, ar);
- bool has_category_tabs = UI_panel_category_is_visible(ar);
/* count active, not tabbed panels */
for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -1061,14 +1078,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
/* 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(ar, align);
ps->pa->ofsx = 0;
ps->pa->ofsy = -get_panel_size_y(ps->pa);
-
- if (has_category_tabs) {
- if (align == BUT_VERTICAL && (ar->alignment != RGN_ALIGN_RIGHT)) {
- ps->pa->ofsx += UI_PANEL_CATEGORY_MARGIN_WIDTH;
- }
- }
+ ps->pa->ofsx += ps->pa->runtime.region_ofsx;
for (a = 0; a < tot - 1; a++, ps++) {
psnext = ps + 1;
@@ -1913,7 +1926,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
{
/* no tab outlines for */
// #define USE_FLAT_INACTIVE
- const bool is_left = (ar->alignment != RGN_ALIGN_RIGHT);
+ const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment != RGN_ALIGN_RIGHT);
View2D *v2d = &ar->v2d;
uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
@@ -2201,7 +2214,7 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
{
const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE);
const bool inside_tabregion =
- ((ar->alignment != RGN_ALIGN_RIGHT) ?
+ ((RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) != RGN_ALIGN_RIGHT) ?
(event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax) :
(event->mval[0] > ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmin));
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index fa471441cc9..d32cd5c17e2 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -364,7 +364,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
ED_area_update_region_sizes(wm, win, sa);
}
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
ED_region_tag_redraw(ar);
/* Reset zoom level (not well supported). */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index fed3c0b3d11..560c6146afe 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -280,13 +280,13 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
ARegion *ar = CTX_wm_region(C);
if (sa && ar) {
if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
}
if (ar->regiontype == RGN_TYPE_FOOTER) {
- if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index cd0421dde09..2042c15ed96 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -189,12 +189,12 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
/* Prefer popover from header to be positioned into the editor. */
else if (sa && ar) {
if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
if (ar->regiontype == RGN_TYPE_FOOTER) {
- if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == 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 63dee77e90e..867ac652505 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -524,20 +524,44 @@ void ui_popup_block_scrolltest(uiBlock *block)
static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
- wmWindow *win = CTX_wm_window(C);
+ wmWindow *ctx_win = CTX_wm_window(C);
+ ScrArea *ctx_sa = CTX_wm_area(C);
+ ARegion *ctx_ar = CTX_wm_region(C);
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = ctx_win;
bScreen *sc = 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) {
+ for (win = wm->windows.first; win; win = win->next) {
+ sc = WM_window_get_active_screen(win);
+ if (BLI_findindex(&sc->regionbase, handle->region) != -1) {
+ break;
+ }
+ }
+ }
+
+ BLI_assert(win && sc);
+
+ CTX_wm_window_set(C, win);
ui_region_temp_remove(C, sc, 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);
+
/* reset to region cursor (only if there's not another menu open) */
if (BLI_listbase_is_empty(&sc->regionbase)) {
- ED_region_cursor_set(win, CTX_wm_area(C), CTX_wm_region(C));
+ ED_region_cursor_set(win, ctx_sa, ctx_ar);
/* in case cursor needs to be changed again */
WM_event_add_mousemove(C);
}
if (handle->scrolltimer) {
- WM_event_remove_timer(CTX_wm_manager(C), win, handle->scrolltimer);
+ WM_event_remove_timer(wm, win, handle->scrolltimer);
}
}
@@ -728,7 +752,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
ui_popup_block_scrolltest(block);
/* adds subwindow */
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
/* get winmat now that we actually have the subwindow */
wmGetProjectionMatrix(block->winmat, &ar->winrct);
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 251bc86a3f5..94bcd6ab37d 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -639,7 +639,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but
}
/* adds subwindow */
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
/* notify change and redraw */
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index f4407d59d7f..7a0c04be356 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -292,6 +292,22 @@ static void ui_tooltip_region_free_cb(ARegion *ar)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name ToolTip Creation Utility Functions
+ * \{ */
+
+static char *ui_tooltip_text_python_from_op(bContext *C, wmOperatorType *ot, PointerRNA *opptr)
+{
+ char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, opptr);
+
+ /* Avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary. */
+ WM_operator_pystring_abbreviate(str, 32);
+
+ return str;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name ToolTip Creation
* \{ */
@@ -336,8 +352,7 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
.style = UI_TIP_STYLE_NORMAL,
.color_id = UI_TIP_LC_PYTHON,
});
- char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, kmi->ptr);
- WM_operator_pystring_abbreviate(str, 32);
+ char *str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr);
field->text = BLI_sprintfN(TIP_("Python: %s"), str);
MEM_freeN(str);
}
@@ -687,6 +702,19 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
}
+ /* Python */
+ if ((is_label == false) && (U.flag & USER_TOOLTIPS_PYTHON)) {
+ uiTooltipField *field = text_field_add(data,
+ &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_PYTHON,
+ .is_pad = true,
+ });
+ char *str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr);
+ field->text = BLI_sprintfN(TIP_("Python: %s"), str);
+ MEM_freeN(str);
+ }
+
/* Keymap */
/* This is too handy not to expose somehow, let's be sneaky for now. */
@@ -906,10 +934,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* so the context is passed to fieldf functions (some py fieldf functions use it) */
WM_operator_properties_sanitize(opptr, false);
- str = WM_operator_pystring_ex(C, NULL, false, false, but->optype, opptr);
-
- /* avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary */
- WM_operator_pystring_abbreviate(str, 32);
+ str = ui_tooltip_text_python_from_op(C, but->optype, opptr);
/* operator info */
if (U.flag & USER_TOOLTIPS_PYTHON) {
@@ -1366,7 +1391,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
}
/* adds subwindow */
- ED_region_init(ar);
+ ED_region_floating_initialize(ar);
/* notify change and redraw */
ED_region_tag_redraw(ar);
@@ -1380,6 +1405,10 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
/** \name ToolTip Public API
* \{ */
+/**
+ * \param is_label: When true, show a small tip that only shows the name,
+ * otherwise show the full tooltip.
+ */
ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
{
wmWindow *win = CTX_wm_window(C);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 71fa28640e0..4c86e3252ed 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -72,6 +72,7 @@
#include "BKE_particle.h"
#include "BKE_curveprofile.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@@ -1822,7 +1823,9 @@ static int modifier_can_delete(ModifierData *md)
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_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;
}
}
@@ -2843,8 +2846,13 @@ void uiTemplatePreview(uiLayout *layout,
col = uiLayoutColumn(row, true);
uiLayoutSetScaleX(col, 1.5);
uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemS(col);
- uiItemR(col, &material_ptr, "use_preview_world", 0, "", ICON_WORLD);
+
+ /* EEVEE preview file has baked lighting so use_preview_world has no effect,
+ * just hide the option until this feature is supported. */
+ if (!BKE_scene_uses_blender_eevee(CTX_data_scene(C))) {
+ uiItemS(col);
+ uiItemR(col, &material_ptr, "use_preview_world", 0, "", ICON_WORLD);
+ }
}
if (pr_texture) {
@@ -5013,7 +5021,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
0.0,
- TIP_("Set the point's handle type to sharp."));
+ TIP_("Set the point's handle type to sharp"));
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
@@ -5031,7 +5039,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
0.0,
- TIP_("Set the point's handle type to sharp."));
+ TIP_("Set the point's handle type to smooth"));
UI_but_funcN_set(bt, CurveProfile_buttons_setcurved, MEM_dupallocN(cb), profile);
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
@@ -6863,7 +6871,6 @@ static char *progress_tooltip_func(bContext *UNUSED(C), void *argN, const char *
void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
{
- bScreen *screen = CTX_wm_screen(C);
wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *sa = CTX_wm_area(C);
uiBlock *block;
@@ -7045,7 +7052,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
}
}
- if (screen->animtimer) {
+ if (ED_screen_animation_no_scrub(wm)) {
uiDefIconTextBut(block,
UI_BTYPE_BUT,
B_STOPANIM,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index d313310bfa1..fd2f652d40e 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2662,10 +2662,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
- }
- if (state & UI_ACTIVE) {
- widget_active_color(&wt->wcol);
+ /* Add "hover" highlight. Ideally this could apply in all cases,
+ * even if UI_SELECT. But currently this causes some flickering
+ * as buttons can be created and updated without respect to mouse
+ * position and so can draw without UI_ACTIVE set. See D6503. */
+ if (state & UI_ACTIVE) {
+ widget_active_color(&wt->wcol);
+ }
}
if (state & UI_BUT_REDALERT) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index f8b4d85a212..3aede744115 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -443,6 +443,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_BONE_POSE_ACTIVE:
cp = ts->bone_pose_active;
break;
+ case TH_BONE_LOCKED_WEIGHT:
+ cp = ts->bone_locked_weight;
+ break;
case TH_STRIP:
cp = ts->strip;
break;
@@ -969,6 +972,18 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_INFO_DEBUG_TEXT:
cp = ts->info_debug_text;
break;
+ case TH_INFO_PROPERTY:
+ cp = ts->info_property;
+ break;
+ case TH_INFO_PROPERTY_TEXT:
+ cp = ts->info_property_text;
+ break;
+ case TH_INFO_OPERATOR:
+ cp = ts->info_operator;
+ break;
+ case TH_INFO_OPERATOR_TEXT:
+ cp = ts->info_operator_text;
+ break;
case TH_V3D_CLIPPING_BORDER:
cp = ts->clipping_border_3d;
break;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index a3f84e7bdd0..a23bd7dad35 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -354,11 +354,6 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
/* note, scroll is being flipped in ED_region_panels() drawing */
v2d->scroll |= (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE);
- /* initialize without scroll bars (interferes with zoom level see: T47047) */
- if (do_init) {
- v2d->scroll |= (V2D_SCROLL_VERTICAL_FULLR | V2D_SCROLL_HORIZONTAL_FULLR);
- }
-
if (do_init) {
float panelzoom = (style) ? style->panelzoom : 1.0f;
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 7582ef3f41d..9f9e523b57b 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -316,7 +316,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -694,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index dad84c87fd7..3f51504d6ac 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -541,7 +541,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_COLLADA,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
@@ -870,7 +870,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_COLLADA,
FILE_BLENDER,
FILE_OPENFILE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 2818b134509..bb527ee6a3f 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -32,6 +32,8 @@
# include "BLI_string.h"
# include "BLI_utildefines.h"
+# include "BLT_translation.h"
+
# include "MEM_guardedalloc.h"
# include "RNA_access.h"
@@ -111,7 +113,6 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
MEM_SAFE_FREE(op->customdata);
const bool selected_objects_only = RNA_boolean_get(op->ptr, "selected_objects_only");
- const bool visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only");
const bool export_animation = RNA_boolean_get(op->ptr, "export_animation");
const bool export_hair = RNA_boolean_get(op->ptr, "export_hair");
const bool export_uvmaps = RNA_boolean_get(op->ptr, "export_uvmaps");
@@ -127,7 +128,6 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
export_normals,
export_materials,
selected_objects_only,
- visible_objects_only,
use_instancing,
evaluation_mode,
};
@@ -147,7 +147,6 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "selected_objects_only", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "visible_objects_only", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "export_animation", 0, NULL, ICON_NONE);
@@ -155,10 +154,13 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(col, ptr, "export_uvmaps", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "export_normals", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "export_materials", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_instancing", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "evaluation_mode", 0, NULL, ICON_NONE);
+
+ uiLayout *box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Experimental:"), ICON_NONE);
+ uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE);
}
void WM_OT_usd_export(struct wmOperatorType *ot)
@@ -183,58 +185,49 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna,
"selected_objects_only",
false,
- "Only Export Selected Objects",
+ "Selection Only",
"Only selected objects are exported. Unselected parents of selected objects are "
"exported as empty transform");
RNA_def_boolean(ot->srna,
- "visible_objects_only",
- true,
- "Only Export Visible Objects",
- "Only visible objects are exported. Invisible parents of visible objects are "
- "exported as empty transform");
-
- RNA_def_boolean(ot->srna,
"export_animation",
false,
- "Export Animation",
+ "Animation",
"When checked, the render frame range is exported. When false, only the current "
"frame is exported");
- RNA_def_boolean(ot->srna,
- "export_hair",
- false,
- "Export Hair",
- "When checked, hair is exported as USD curves");
+ RNA_def_boolean(
+ ot->srna, "export_hair", false, "Hair", "When checked, hair is exported as USD curves");
RNA_def_boolean(ot->srna,
"export_uvmaps",
true,
- "Export UV Maps",
+ "UV Maps",
"When checked, all UV maps of exported meshes are included in the export");
RNA_def_boolean(ot->srna,
"export_normals",
true,
- "Export Normals",
+ "Normals",
"When checked, normals of exported meshes are included in the export");
RNA_def_boolean(ot->srna,
"export_materials",
true,
- "Export Materials",
+ "Materials",
"When checked, the viewport settings of materials are exported as USD preview "
"materials, and material assignments are exported as geometry subsets");
RNA_def_boolean(ot->srna,
"use_instancing",
false,
- "Use Instancing (EXPERIMENTAL)",
- "When true, dupli-objects are written as instances of the original in USD. "
- "Experimental feature, not working perfectly");
+ "Instancing",
+ "When checked, instanced objects are exported as references in USD. "
+ "When unchecked, instanced objects are exported as real objects");
RNA_def_enum(ot->srna,
"evaluation_mode",
rna_enum_usd_export_evaluation_mode_items,
DAG_EVAL_RENDER,
- "Evaluation Mode",
- "Determines visibility of objects and modifier settings");
+ "Use Settings for",
+ "Determines visibility of objects, modifier settings, and other areas where there "
+ "are different settings for viewport and rendering");
}
#endif /* WITH_USD */
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index a7d1e54ad59..7a0124e72bb 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -92,7 +92,7 @@ static void make_prim_finish(bContext *C,
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
/* only recalc editmode tessface if we are staying in editmode */
- EDBM_update_generic(em, !exit_editmode, true);
+ EDBM_update_generic(obedit->data, !exit_editmode, true);
/* userdef */
if (exit_editmode) {
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
index 66832ceba7f..c748560ae1b 100644
--- a/source/blender/editors/mesh/editmesh_add_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -357,7 +357,7 @@ static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op)
}
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
index fb8ee85f9db..f9910f01f47 100644
--- a/source/blender/editors/mesh/editmesh_automerge.c
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -79,7 +79,7 @@ void EDBM_automerge(Object *obedit, bool update, const char hflag, const float d
BMO_op_finish(bm, &weldop);
if ((totvert_prev != bm->totvert) && update) {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
}
@@ -92,9 +92,9 @@ void EDBM_automerge(Object *obedit, bool update, const char hflag, const float d
* \{ */
void EDBM_automerge_and_split(Object *obedit,
- bool UNUSED(split_edges),
- bool split_faces,
- bool update,
+ const bool UNUSED(split_edges),
+ const bool split_faces,
+ const bool update,
const char hflag,
const float dist)
{
@@ -123,26 +123,10 @@ void EDBM_automerge_and_split(Object *obedit,
GHash *ghash_targetmap = BMO_SLOT_AS_GHASH(slot_targetmap);
- ok = BM_mesh_intersect_edges(bm, hflag, dist, ghash_targetmap);
+ ok = BM_mesh_intersect_edges(bm, hflag, dist, split_faces, ghash_targetmap);
if (ok) {
BMO_op_exec(bm, &weldop);
-
- BMEdge **edgenet = NULL;
- int edgenet_alloc_len = 0;
- if (split_faces) {
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, ghash_targetmap) {
- BMVert *v = BLI_ghashIterator_getValue(&gh_iter);
- // BLI_assert(BM_elem_flag_test(v, hflag) || hflag == BM_ELEM_TAG);
- BM_vert_weld_linked_wire_edges_into_linked_faces(
- bm, v, dist, &edgenet, &edgenet_alloc_len);
- }
- }
-
- if (edgenet) {
- MEM_freeN(edgenet);
- }
}
BMO_op_finish(bm, &weldop);
@@ -153,7 +137,7 @@ void EDBM_automerge_and_split(Object *obedit,
#endif
if (LIKELY(ok) && update) {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index acdf667b410..42fa3db7c57 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -77,7 +77,8 @@ static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f};
static const float value_scale_per_inch[NUM_VALUE_KINDS] = {0.0f, 100.0f, 1.0f, 4.0f};
typedef struct {
- BMEditMesh *em;
+ /** Every object must have a valid #BMEditMesh. */
+ Object *ob;
BMBackup mesh_backup;
} BevelObjectStore;
@@ -94,6 +95,7 @@ typedef struct {
uint ob_store_len;
/* modal only */
+ int launch_event;
float mcenter[2];
void *draw_handle_pixel;
short gizmo_flag;
@@ -261,7 +263,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (em->bm->totvertsel > 0) {
- opdata->ob_store[objects_used_len].em = em;
+ opdata->ob_store[objects_used_len].ob = obedit;
objects_used_len++;
}
}
@@ -300,8 +302,9 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
ARegion *ar = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
- opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(
- opdata->ob_store[ob_index].em);
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(em);
}
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
@@ -319,7 +322,6 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
static bool edbm_bevel_calc(wmOperator *op)
{
BevelData *opdata = op->customdata;
- BMEditMesh *em;
BMOperator bmop;
bool changed = false;
@@ -329,7 +331,7 @@ static bool edbm_bevel_calc(wmOperator *op)
const float profile = RNA_float_get(op->ptr, "profile");
const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
- int material = RNA_int_get(op->ptr, "material");
+ const int material_init = RNA_int_get(op->ptr, "material");
const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide");
const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam");
const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
@@ -342,18 +344,17 @@ static bool edbm_bevel_calc(wmOperator *op)
const int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method");
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
- em = opdata->ob_store[ob_index].em;
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
/* revert to original mesh */
if (opdata->is_modal) {
EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false);
}
- if (em->ob) {
- material = CLAMPIS(material, -1, em->ob->totcol - 1);
- }
+ const int material = CLAMPIS(material_init, -1, obedit->totcol - 1);
- Mesh *me = em->ob->data;
+ Mesh *me = obedit->data;
if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) {
/* harden_normals only has a visible effect if autosmooth is on, so turn it on */
@@ -406,7 +407,7 @@ static bool edbm_bevel_calc(wmOperator *op)
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
changed = true;
}
return changed;
@@ -421,6 +422,15 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op)
ED_area_status_text(sa, NULL);
}
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ /* Without this, faces surrounded by selected edges/verts will be unselected. */
+ if ((em->selectmode & SCE_SELECT_FACE) == 0) {
+ EDBM_selectmode_flush(em);
+ }
+ }
+
if (opdata->is_modal) {
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
@@ -443,9 +453,10 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op)
BevelData *opdata = op->customdata;
if (opdata->is_modal) {
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
- EDBM_redo_state_free(
- &opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true);
- EDBM_update_generic(opdata->ob_store[ob_index].em, false, true);
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, em, true);
+ EDBM_update_generic(obedit->data, false, true);
}
}
@@ -510,6 +521,8 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
opdata = op->customdata;
+ opdata->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
+
/* initialize mouse values */
if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) {
/* in this case the tool will likely do nothing,
@@ -700,7 +713,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
short eval = event->val;
/* When activated from toolbar, need to convert leftmouse release to confirm */
- if (etype == LEFTMOUSE && eval == KM_RELEASE && RNA_boolean_get(op->ptr, "release_confirm")) {
+ if (ELEM(etype, LEFTMOUSE, opdata->launch_event) && (eval == KM_RELEASE) &&
+ RNA_boolean_get(op->ptr, "release_confirm")) {
etype = EVT_MODAL_MAP;
eval = BEV_MODAL_CONFIRM;
}
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 4a511bbb5a2..b2af58e47f2 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -346,10 +346,9 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
BMOperator bmop_fill;
BMOperator bmop_attr;
+ /* The fill normal sign is ignored as the face-winding is defined by surrounding faces.
+ * The normal is passed so triangle fill wont have to calculate it. */
normalize_v3_v3(normal_fill, plane_no_local);
- if (clear_outer == true && clear_inner == false) {
- negate_v3(normal_fill);
- }
/* Fill */
BMO_op_initf(bm,
@@ -369,7 +368,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
"face_attribute_fill faces=%S use_normals=%b use_data=%b",
&bmop_fill,
"geom.out",
- false,
+ true,
true);
BMO_op_exec(bm, &bmop_attr);
@@ -384,7 +383,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
if (EDBM_op_finish(em, &bmop, op, true)) {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
EDBM_selectmode_flush(em);
ret = OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index c1c8a208471..b653484322a 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -306,7 +306,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -427,7 +427,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
* done.*/
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -482,7 +482,7 @@ static int edbm_extrude_context_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -528,7 +528,7 @@ static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -576,7 +576,7 @@ static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -624,7 +624,7 @@ static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -820,7 +820,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
/* also project the source, for retopo workflow */
if (use_proj) {
- EDBM_project_snap_verts(C, depsgraph, vc.ar, vc.em);
+ EDBM_project_snap_verts(C, depsgraph, vc.ar, vc.obedit, vc.em);
}
}
@@ -853,7 +853,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
}
if (use_proj) {
- EDBM_project_snap_verts(C, depsgraph, vc.ar, vc.em);
+ EDBM_project_snap_verts(C, depsgraph, vc.ar, vc.obedit, vc.em);
}
/* This normally happens when pushing undo but modal operators
@@ -861,7 +861,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
* done. */
EDBM_mesh_normals_update(vc.em);
- EDBM_update_generic(vc.em, true, true);
+ EDBM_update_generic(vc.obedit->data, true, true);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c
index 252f95a10ac..ef393acdb4e 100644
--- a/source/blender/editors/mesh/editmesh_extrude_screw.c
+++ b/source/blender/editors/mesh/editmesh_extrude_screw.c
@@ -155,7 +155,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index 7cad7e1e062..69274f77049 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -111,7 +111,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -199,7 +199,7 @@ void MESH_OT_spin(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
+ RNA_def_int(ot->srna, "steps", 12, 0, 1000000, "Steps", "Steps", 0, 1000);
prop = RNA_def_boolean(ot->srna, "dupli", 0, "Use Duplicates", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 1413e0db41d..a1b1ea31ead 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -51,7 +51,8 @@
#include "mesh_intern.h" /* own include */
typedef struct {
- BMEditMesh *em;
+ /** Must have a valid edit-mesh. */
+ Object *ob;
BMBackup mesh_backup;
} InsetObjectStore;
@@ -71,6 +72,7 @@ typedef struct {
uint ob_store_len;
/* modal only */
+ int launch_event;
float mcenter[2];
void *draw_handle_pixel;
short gizmo_flag;
@@ -141,7 +143,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (em->bm->totvertsel > 0) {
- opdata->ob_store[objects_used_len].em = em;
+ opdata->ob_store[objects_used_len].ob = obedit;
objects_used_len++;
}
}
@@ -167,8 +169,9 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
ARegion *ar = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
- opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(
- opdata->ob_store[ob_index].em);
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(em);
}
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
@@ -218,9 +221,10 @@ static void edbm_inset_cancel(bContext *C, wmOperator *op)
opdata = op->customdata;
if (opdata->is_modal) {
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
- EDBM_redo_state_free(
- &opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true);
- EDBM_update_generic(opdata->ob_store[ob_index].em, false, true);
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, em, true);
+ EDBM_update_generic(obedit->data, false, true);
}
}
@@ -233,7 +237,6 @@ static void edbm_inset_cancel(bContext *C, wmOperator *op)
static bool edbm_inset_calc(wmOperator *op)
{
InsetData *opdata;
- BMEditMesh *em;
BMOperator bmop;
bool changed = false;
@@ -252,7 +255,8 @@ static bool edbm_inset_calc(wmOperator *op)
opdata = op->customdata;
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
- em = opdata->ob_store[ob_index].em;
+ Object *obedit = opdata->ob_store[ob_index].ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (opdata->is_modal) {
EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false);
@@ -310,7 +314,7 @@ static bool edbm_inset_calc(wmOperator *op)
continue;
}
else {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
changed = true;
}
}
@@ -345,6 +349,8 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
opdata = op->customdata;
+ opdata->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
+
/* initialize mouse values */
if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) {
/* in this case the tool will likely do nothing,
@@ -386,6 +392,12 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
}
+ else if ((event->type == opdata->launch_event) && (event->val == KM_RELEASE) &&
+ RNA_boolean_get(op->ptr, "release_confirm")) {
+ edbm_inset_calc(op);
+ edbm_inset_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
else {
bool handled = false;
switch (event->type) {
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index ec740447f93..847a8ecacc3 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -101,7 +101,7 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
/**
* Use for intersect and boolean.
*/
-static void edbm_intersect_select(BMEditMesh *em, bool do_select)
+static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_select)
{
if (do_select) {
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
@@ -119,7 +119,7 @@ static void edbm_intersect_select(BMEditMesh *em, bool do_select)
}
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(me, true, true);
}
/* -------------------------------------------------------------------- */
@@ -212,7 +212,7 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
}
- edbm_intersect_select(em, has_isect);
+ edbm_intersect_select(em, obedit->data, has_isect);
if (!has_isect) {
isect_len++;
@@ -318,7 +318,7 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
boolean_operation,
eps);
- edbm_intersect_select(em, has_isect);
+ edbm_intersect_select(em, obedit->data, has_isect);
if (!has_isect) {
isect_len++;
@@ -847,7 +847,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
#endif
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
#ifdef USE_NET_ISLAND_CONNECT
/* we may have remaining isolated regions remaining,
@@ -952,7 +952,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BLI_ghash_free(face_edge_map, NULL, NULL);
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
BLI_stack_free(edges_loose);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 4c4aa4214b2..bad24eaa47c 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2564,7 +2564,7 @@ static void knifetool_finish_ex(KnifeTool_OpData *kcd)
EDBM_selectmode_flush(kcd->em);
EDBM_mesh_normals_update(kcd->em);
- EDBM_update_generic(kcd->em, true, true);
+ EDBM_update_generic(kcd->ob->data, true, true);
/* re-tessellating makes this invalid, dont use again by accident */
knifetool_free_bmbvh(kcd);
@@ -2658,11 +2658,11 @@ static void knifetool_init_bmbvh(KnifeTool_OpData *kcd)
BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id);
- Object *obedit_eval = (Object *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->em->ob->id);
+ Object *obedit_eval = (Object *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->ob->id);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
kcd->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
- kcd->vc.depsgraph, em_eval, scene_eval, NULL);
+ kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL);
kcd->bmbvh = BKE_bmbvh_new_from_editmesh(
kcd->em,
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 3c3e91e8afe..ef05eb4ffda 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -197,7 +197,7 @@ static void ringsel_finish(bContext *C, wmOperator *op)
/* when used in a macro the tessfaces will be recalculated anyway,
* this is needed here because modifiers depend on updated tessellation, see T45920 */
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(lcd->ob->data, true, true);
if (is_single) {
/* de-select endpoints */
@@ -636,7 +636,7 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (cuts != lcd->cuts) {
/* allow zero so you can backspace and type in a value
* otherwise 1 as minimum would make more sense */
- lcd->cuts = clamp_i(cuts, 0, SUBD_CUTS_MAX);
+ lcd->cuts = clamp_f(cuts, 0, SUBD_CUTS_MAX);
RNA_int_set(op->ptr, "number_cuts", (int)lcd->cuts);
ringsel_find_edge(lcd, (int)lcd->cuts);
show_cuts = true;
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 0d886360253..139f05db01c 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -80,6 +80,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ BKE_sculpt_mask_layers_ensure(ob, NULL);
+
Mesh *mesh = ob->data;
Mesh *new_mesh = BKE_mesh_copy(bmain, mesh);
@@ -104,9 +106,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
BMIter face_iter;
/* Delete all unmasked faces */
- const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
- BLI_assert(cd_vert_mask_offset != -1);
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
float mask_threshold = RNA_float_get(op->ptr, "mask_threshold");
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
@@ -124,6 +125,10 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ mul_v3_v3(v->co, ob->scale);
+ }
+
if (RNA_boolean_get(op->ptr, "add_boundary_loop")) {
BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
BM_elem_flag_set(ed, BM_ELEM_TAG, BM_edge_is_boundary(ed));
@@ -336,6 +341,8 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
View3D *v3d = CTX_wm_view3d(C);
+ BKE_sculpt_mask_layers_ensure(ob, NULL);
+
Mesh *mesh = ob->data;
Mesh *new_mesh = BKE_mesh_copy(bmain, mesh);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 06c41b78c37..e09bcaf4edc 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -270,7 +270,7 @@ static void mouse_mesh_shortest_path_vert(Scene *UNUSED(scene),
}
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
/** \} */
@@ -474,7 +474,7 @@ static void mouse_mesh_shortest_path_edge(Scene *scene,
}
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
if (op_params->edge_mode == EDGE_MODE_TAG_SEAM) {
ED_uvedit_live_unwrap(scene, &obedit, 1);
@@ -591,7 +591,7 @@ static void mouse_mesh_shortest_path_face(Scene *UNUSED(scene),
BM_mesh_active_face_set(bm, f_dst_last);
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index a91f0f9274e..781e77de34a 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -155,7 +155,7 @@ static int edbm_polybuild_transform_at_cursor_invoke(bContext *C,
}
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(vc.obedit->data, true, true);
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
@@ -238,7 +238,7 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
if (changed) {
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(vc.obedit->data, true, true);
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
@@ -403,7 +403,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con
if (changed) {
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(vc.obedit->data, true, true);
if (basact != NULL) {
if (vc.view_layer->basact != basact) {
@@ -493,7 +493,7 @@ static int edbm_polybuild_split_at_cursor_invoke(bContext *C,
if (changed) {
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(vc.obedit->data, true, true);
WM_event_add_mousemove(C);
@@ -586,7 +586,7 @@ static int edbm_polybuild_dissolve_at_cursor_invoke(bContext *C,
edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(vc.obedit->data, true, true);
if (vc.view_layer->basact != basact) {
ED_object_base_activate(C, basact);
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index ffdb434405e..71bf77cc788 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -1075,7 +1075,7 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
error_rip_failed = false;
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index 61253f06f9f..5dd3c85f34f 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -223,7 +223,7 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
BM_mesh_select_mode_flush(bm);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 40d57af97aa..6eabb079f4e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -75,15 +75,18 @@
/** \name Select Mirror
* \{ */
-void EDBM_select_mirrored(
- BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail)
+void EDBM_select_mirrored(BMEditMesh *em,
+ const Mesh *me,
+ const int axis,
+ const bool extend,
+ int *r_totmirr,
+ int *r_totfail)
{
- Mesh *me = (Mesh *)em->ob->data;
BMesh *bm = em->bm;
BMIter iter;
int totmirr = 0;
int totfail = 0;
- bool use_topology = (me && (me->editflag & ME_EDIT_MIRROR_TOPO));
+ bool use_topology = me->editflag & ME_EDIT_MIRROR_TOPO;
*r_totmirr = *r_totfail = 0;
@@ -3863,7 +3866,7 @@ static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
for (int axis = 0; axis < 3; axis++) {
if ((1 << axis) & axis_flag) {
- EDBM_select_mirrored(em, axis, extend, &tot_mirr_iter, &tot_fail_iter);
+ EDBM_select_mirrored(em, obedit->data, axis, extend, &tot_mirr_iter, &tot_fail_iter);
}
}
@@ -4220,7 +4223,7 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
if (edbm_deselect_nth(em, &op_params) == true) {
found_active_elt = true;
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
}
MEM_freeN(objects);
@@ -4954,7 +4957,7 @@ static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
EDBM_selectmode_to_scene(C);
}
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index 2782cc92aca..cee048b9513 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -497,7 +497,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
if (changed) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(ob->data, false, false);
}
}
@@ -519,7 +519,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
}
}
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(ob->data, false, false);
}
}
@@ -917,7 +917,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
if (changed) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(ob->data, false, false);
}
}
@@ -939,7 +939,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
}
}
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(ob->data, false, false);
}
}
@@ -1186,7 +1186,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
if (changed) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(ob->data, false, false);
}
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 4bffbb912d1..43a787481b1 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -96,13 +96,12 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
const float smooth = RNA_float_get(op->ptr, "smoothness");
const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
+ const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon");
- if (RNA_boolean_get(op->ptr, "ngon") &&
- RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) {
+ if (use_quad_tri && RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) {
RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
}
const int quad_corner_type = RNA_enum_get(op->ptr, "quadcorner");
- const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon");
const int seed = RNA_int_get(op->ptr, "seed");
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -133,7 +132,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
false,
seed);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -325,7 +324,7 @@ static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -385,7 +384,7 @@ static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
}
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -411,10 +410,10 @@ 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 *ar, BMEditMesh *em)
+void EDBM_project_snap_verts(
+ bContext *C, Depsgraph *depsgraph, ARegion *ar, Object *obedit, BMEditMesh *em)
{
Main *bmain = CTX_data_main(C);
- Object *obedit = em->ob;
BMIter iter;
BMVert *eve;
@@ -534,7 +533,7 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -663,7 +662,7 @@ static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
int totelem_new[3];
@@ -721,7 +720,7 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1004,7 +1003,7 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
changed_multi = true;
}
MEM_freeN(objects);
@@ -1080,8 +1079,7 @@ static int edbm_mark_seam_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);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -1151,7 +1149,7 @@ static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear);
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -1185,7 +1183,7 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-static bool edbm_connect_vert_pair(BMEditMesh *em, wmOperator *op)
+static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op)
{
BMesh *bm = em->bm;
BMOperator bmop;
@@ -1264,7 +1262,7 @@ static bool edbm_connect_vert_pair(BMEditMesh *em, wmOperator *op)
/* so newly created edges get the selection state from the vertex */
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(me, true, true);
}
}
MEM_freeN(verts);
@@ -1284,12 +1282,12 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!edbm_connect_vert_pair(em, op)) {
+ if (!edbm_connect_vert_pair(em, obedit->data, op)) {
failed_objects_len++;
}
}
MEM_freeN(objects);
- return failed_objects_len == objects_len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return failed_objects_len == objects_len ? OPERATOR_CANCELLED : OPERATOR_FINISHED;
}
void MESH_OT_vert_connect(wmOperatorType *ot)
@@ -1541,7 +1539,7 @@ static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
/* when there is only 2 vertices, we can ignore selection order */
if (is_pair) {
- if (!edbm_connect_vert_pair(em, op)) {
+ if (!edbm_connect_vert_pair(em, obedit->data, op)) {
failed_connect_len++;
}
continue;
@@ -1558,7 +1556,7 @@ static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
if (bm_vert_connect_select_history(bm)) {
EDBM_selectmode_flush(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
else {
failed_selection_order_len++;
@@ -1617,7 +1615,7 @@ static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
em, op, "faces.out", true, "connect_verts_concave faces=%hf", BM_ELEM_SELECT)) {
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1671,7 +1669,7 @@ static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1740,7 +1738,7 @@ static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1794,7 +1792,7 @@ static int edbm_edge_split_exec(bContext *C, wmOperator *op)
EDBM_select_flush(em);
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1863,7 +1861,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
if (!EDBM_op_finish(em, &bmop, op, true)) {
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1920,7 +1918,7 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -2031,7 +2029,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -2117,7 +2115,7 @@ static int edbm_hide_exec(bContext *C, wmOperator *op)
}
if (EDBM_mesh_hide(em, unselected)) {
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
changed = true;
}
}
@@ -2168,7 +2166,7 @@ static int edbm_reveal_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (EDBM_mesh_reveal(em, select)) {
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
}
MEM_freeN(objects);
@@ -2221,7 +2219,7 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -2335,7 +2333,7 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
EDBM_verts_mirror_cache_end(em);
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -2357,7 +2355,7 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_float_factor(
- ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
+ ot->srna, "factor", 0.0f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
RNA_def_int(
ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
@@ -2459,7 +2457,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
EDBM_verts_mirror_cache_end(em);
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -2552,7 +2550,7 @@ static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
}
mesh_set_smooth_faces(em, 1);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
MEM_freeN(objects);
@@ -2595,7 +2593,7 @@ static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
}
mesh_set_smooth_faces(em, 0);
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
MEM_freeN(objects);
@@ -2652,7 +2650,7 @@ static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
MEM_freeN(objects);
@@ -2685,7 +2683,7 @@ static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
if (!EDBM_op_finish(em, &bmop, op, true)) {
continue;
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
MEM_freeN(objects);
@@ -2723,7 +2721,7 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
}
/* dependencies graph and notification stuff */
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(ob->data, false, false);
}
MEM_freeN(objects);
@@ -2739,8 +2737,8 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
view_layer, CTX_wm_view3d(C), &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(ob);
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (em->bm->totfacesel == 0) {
continue;
@@ -2759,7 +2757,7 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
MEM_freeN(objects);
@@ -3003,7 +3001,7 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
/* once collapsed, we can't have edge/face selection */
if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
@@ -3176,7 +3174,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
if (count) {
count_multi += count;
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
}
MEM_freeN(objects);
@@ -3270,7 +3268,7 @@ static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
tot_shapekeys++;
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(me, false, false);
}
MEM_freeN(objects);
@@ -3396,7 +3394,7 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
interp_v3_v3v3(eve->co, eve->co, co, blend);
}
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(me, true, false);
}
}
MEM_freeN(objects);
@@ -3532,7 +3530,7 @@ static int edbm_solidify_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -3861,7 +3859,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
return OPERATOR_FINISHED;
}
@@ -4259,7 +4257,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
if (retval) {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(base->object->data, true, true);
}
}
MEM_freeN(bases);
@@ -4406,7 +4404,7 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -4679,7 +4677,7 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -4751,7 +4749,7 @@ static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -4834,7 +4832,7 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -4920,7 +4918,7 @@ static int edbm_poke_face_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5018,7 +5016,7 @@ static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5126,7 +5124,7 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5310,7 +5308,7 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op)
}
EDBM_selectmode_flush_ex(em, selectmode);
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5446,7 +5444,7 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
use_boundary_tear)) {
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5503,7 +5501,7 @@ static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5560,7 +5558,7 @@ static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5703,7 +5701,7 @@ static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
use_dissolve_boundaries,
delimit);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5790,7 +5788,7 @@ static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
/* tricky to maintain correct selection here, so just flush up from verts */
EDBM_select_flush(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
totelem_new[0] += bm->totvert;
totelem_new[1] += bm->totedge;
@@ -5881,7 +5879,7 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -5941,7 +5939,7 @@ static int edbm_split_exec(bContext *C, wmOperator *op)
/* Geometry has changed, need to recalc normals and looptris */
EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -6683,6 +6681,7 @@ static int edbm_bridge_tag_boundary_edges(BMesh *bm)
static int edbm_bridge_edge_loops_for_single_editmesh(wmOperator *op,
BMEditMesh *em,
+ struct Mesh *me,
const bool use_pairs,
const bool use_cyclic,
const bool use_merge,
@@ -6784,7 +6783,7 @@ static int edbm_bridge_edge_loops_for_single_editmesh(wmOperator *op,
}
if (EDBM_op_finish(em, &bmop, op, true)) {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(me, true, true);
}
/* Always return finished so the user can select different options. */
@@ -6813,7 +6812,7 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
}
edbm_bridge_edge_loops_for_single_editmesh(
- op, em, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
+ op, em, obedit->data, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -6919,7 +6918,7 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -7030,7 +7029,7 @@ static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
continue;
}
else {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
ret = OPERATOR_FINISHED;
}
}
@@ -7147,7 +7146,7 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
continue;
}
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
EDBM_selectmode_flush(em);
}
@@ -7236,7 +7235,7 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
continue;
}
else {
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(obedit->data, true, true);
EDBM_selectmode_flush(em);
}
}
@@ -7379,7 +7378,7 @@ static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
}
}
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
/* No need to end cache, just free the array. */
MEM_freeN(index);
@@ -7726,8 +7725,8 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_ensure_autosmooth(em, obedit->data);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
op->customdata = lnors_ed_arr;
@@ -8027,7 +8026,7 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *
RNA_property_float_set_array(op->ptr, prop_target, target);
}
point_normals_apply(C, op, target, do_reset);
- EDBM_update_generic(em, true, false); /* Recheck bools. */
+ EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
point_normals_update_header(C, op);
}
@@ -8058,7 +8057,6 @@ static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent
static int edbm_point_normals_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (!point_normals_init(C, op, NULL)) {
point_normals_free(C, op);
@@ -8073,7 +8071,7 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op)
point_normals_apply(C, op, target, false);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
point_normals_free(C, op);
return OPERATOR_FINISHED;
@@ -8293,8 +8291,8 @@ static int normals_split_merge(bContext *C, const bool do_merge)
BMEdge *e;
BMIter eiter;
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_ensure_autosmooth(em, obedit->data);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
/* Note that we need temp lnor editing data for all loops of all affected vertices, since by
* setting some faces/edges as smooth we are going to change clnors spaces... See also T65809.
@@ -8312,7 +8310,7 @@ static int normals_split_merge(bContext *C, const bool do_merge)
}
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
if (do_merge) {
normals_merge(bm, lnors_ed_arr);
@@ -8325,7 +8323,7 @@ static int normals_split_merge(bContext *C, const bool do_merge)
BM_loop_normal_editdata_array_free(lnors_ed_arr);
}
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -8417,9 +8415,9 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
BMLoop *l, *l_curr, *l_first;
BMIter fiter;
- BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_ensure_autosmooth(em, obedit->data);
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
@@ -8531,7 +8529,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
}
BLI_heapsimple_free(loop_weight, NULL);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -8656,8 +8654,8 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
continue;
}
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_ensure_autosmooth(em, obedit->data);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
@@ -8778,7 +8776,7 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
BM_loop_normal_editdata_array_free(lnors_ed_arr);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -8862,8 +8860,8 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_ensure_autosmooth(em, obedit->data);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
@@ -8926,7 +8924,7 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
MEM_freeN(loop_set);
MEM_freeN(vnors);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -8965,8 +8963,8 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
BMLoop *l;
BMIter fiter, liter;
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_ensure_autosmooth(em, obedit->data);
+ BKE_editmesh_lnorspace_update(em, obedit->data);
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop,
@@ -9028,7 +9026,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
BM_loop_normal_editdata_array_free(lnors_ed_arr);
MEM_freeN(smooth_normal);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
MEM_freeN(objects);
@@ -9117,7 +9115,7 @@ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op)
}
}
- EDBM_update_generic(em, false, false);
+ EDBM_update_generic(obedit->data, false, false);
}
MEM_freeN(objects);
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index d07ba05de20..faa80341b0f 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -560,12 +560,10 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
return um;
}
-static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh)
+static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *key)
{
BMEditMesh *em_tmp;
- Object *ob = em->ob;
BMesh *bm;
- Key *key = obmesh->key;
#ifdef USE_ARRAY_STORE
# ifdef USE_ARRAY_STORE_THREAD
@@ -607,7 +605,6 @@ static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh)
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
- em->ob = ob;
bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL;
@@ -766,7 +763,7 @@ static void mesh_undosys_step_decode(
continue;
}
BMEditMesh *em = me->edit_mesh;
- undomesh_to_editmesh(&elem->data, em, obedit->data);
+ undomesh_to_editmesh(&elem->data, obedit, em, me->key);
em->needs_flush_to_id = 1;
DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 42404554ed8..f7092a8c6ab 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -41,6 +41,7 @@
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "BKE_global.h"
#include "DEG_depsgraph.h"
@@ -51,6 +52,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
#include "ED_view3d.h"
#include "mesh_intern.h" /* own include */
@@ -159,16 +161,29 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool
em->emcopyusers = 0;
em->emcopy = NULL;
+ /**
+ * Note, we could pass in the mesh, however this is an exceptional case, allow a slow lookup.
+ *
+ * This is needed because the COW mesh makes a full copy of the #BMEditMesh
+ * instead of sharing the pointer, tagging since this has been freed above,
+ * the #BMEditMesh.emcopy needs to be flushed to the COW edit-mesh, see T55457.
+ */
+ {
+ Main *bmain = G_MAIN;
+ for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) {
+ if (mesh->edit_mesh == em) {
+ DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
+ break;
+ }
+ }
+ }
+
/* when copying, tessellation isn't to for faster copying,
* but means we need to re-tessellate here */
if (em->looptris == NULL) {
BKE_editmesh_looptri_calc(em);
}
- if (em->ob) {
- DEG_id_tag_update(&((Mesh *)em->ob->data)->id, ID_RECALC_COPY_ON_WRITE);
- }
-
return false;
}
else {
@@ -315,7 +330,6 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode;
me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
- me->edit_mesh->ob = ob;
/* we need to flush selection because the mode may have changed from when last in editmode */
EDBM_selectmode_flush(me->edit_mesh);
@@ -662,7 +676,9 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(BMesh *bm,
- const bool selected,
+ const Scene *scene,
+ const bool face_selected,
+ const bool uv_selected,
const bool use_winding,
const bool do_islands)
{
@@ -689,8 +705,17 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- totuv += efa->len;
+ if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ if (!uv_selected) {
+ totuv += efa->len;
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ totuv++;
+ }
+ }
+ }
}
}
@@ -715,7 +740,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
winding[j] = false;
}
- if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
float(*tf_uv)[2] = NULL;
if (use_winding) {
@@ -723,6 +748,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
buf->l = l;
buf->separate = 0;
buf->island = INVALID_ISLAND;
@@ -832,6 +861,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
efa = stack[--stacksize];
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)];
for (element = initelement; element; element = element->next) {
@@ -1041,7 +1074,6 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
float maxdist,
int *r_index)
{
- Mesh *me = (Mesh *)em->ob->data;
BMesh *bm = em->bm;
BMIter iter;
BMVert *v;
@@ -1074,7 +1106,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
BM_mesh_elem_index_ensure(bm, BM_VERT);
if (use_topology) {
- ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true);
+ ED_mesh_mirrtopo_init(em, NULL, &mesh_topo_store, true);
}
else {
tree = BLI_kdtree_3d_new(bm->totvert);
@@ -1395,12 +1427,12 @@ void EDBM_stats_update(BMEditMesh *em)
/* so many tools call these that we better make it a generic function.
*/
-void EDBM_update_generic(BMEditMesh *em, const bool do_tessellation, const bool is_destructive)
+void EDBM_update_generic(Mesh *mesh, const bool do_tessellation, const bool is_destructive)
{
- Object *ob = em->ob;
- /* order of calling isn't important */
- DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, ob->data);
+ BMEditMesh *em = mesh->edit_mesh;
+ /* Order of calling isn't important. */
+ DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
if (do_tessellation) {
BKE_editmesh_looptri_calc(em);
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
index e086eda9b33..628c8273bc5 100644
--- a/source/blender/editors/mesh/mesh_mirror.c
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -148,19 +148,15 @@ static int mirrtopo_vert_sort(const void *v1, const void *v2)
return 0;
}
-bool ED_mesh_mirrtopo_recalc_check(Mesh *me, Mesh *me_eval, MirrTopoStore_t *mesh_topo_store)
+bool ED_mesh_mirrtopo_recalc_check(BMEditMesh *em, Mesh *me, MirrTopoStore_t *mesh_topo_store)
{
- const bool is_editmode = (me->edit_mesh != NULL);
+ const bool is_editmode = em != NULL;
int totvert;
int totedge;
- if (me_eval) {
- totvert = me_eval->totvert;
- totedge = me_eval->totedge;
- }
- else if (me->edit_mesh) {
- totvert = me->edit_mesh->bm->totvert;
- totedge = me->edit_mesh->bm->totedge;
+ if (em) {
+ totvert = em->bm->totvert;
+ totedge = em->bm->totedge;
}
else {
totvert = me->totvert;
@@ -177,14 +173,16 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, Mesh *me_eval, MirrTopoStore_t *mes
}
}
-void ED_mesh_mirrtopo_init(Mesh *me,
- Mesh *me_eval,
+void ED_mesh_mirrtopo_init(BMEditMesh *em,
+ Mesh *me,
MirrTopoStore_t *mesh_topo_store,
const bool skip_em_vert_array_init)
{
- const bool is_editmode = (me->edit_mesh != NULL);
+ if (em) {
+ BLI_assert(me == NULL);
+ }
+ const bool is_editmode = (em != NULL);
MEdge *medge = NULL, *med;
- BMEditMesh *em = me_eval ? NULL : me->edit_mesh;
/* editmode*/
BMEdge *eed;
@@ -213,14 +211,14 @@ void ED_mesh_mirrtopo_init(Mesh *me,
totvert = em->bm->totvert;
}
else {
- totvert = me_eval ? me_eval->totvert : me->totvert;
+ totvert = me->totvert;
}
topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
/* Initialize the vert-edge-user counts used to detect unique topology */
if (em) {
- totedge = me->edit_mesh->bm->totedge;
+ totedge = em->bm->totedge;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
@@ -229,8 +227,8 @@ void ED_mesh_mirrtopo_init(Mesh *me,
}
}
else {
- totedge = me_eval ? me_eval->totedge : me->totedge;
- medge = me_eval ? me_eval->medge : me->medge;
+ totedge = me->totedge;
+ medge = me->medge;
for (a = 0, med = medge; a < totedge; a++, med++) {
const unsigned int i1 = med->v1, i2 = med->v2;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 772e7446430..380d9100ed4 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -801,13 +801,30 @@ static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1};
*/
int ED_mesh_mirror_topo_table(Object *ob, Mesh *me_eval, char mode)
{
+
+ Mesh *me_mirror = NULL;
+ BMEditMesh *em_mirror = NULL;
+
+ 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;
+ }
+ }
+
if (mode == 'u') { /* use table */
- if (ED_mesh_mirrtopo_recalc_check(ob->data, me_eval, &mesh_topo_store)) {
+ 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(ob->data, me_eval, &mesh_topo_store, false);
+ 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);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 5286637afe2..f55a4c7f5f9 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -603,27 +603,8 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op)
copy_v3_fl(ob->scale, radius);
probe = (LightProbe *)ob->data;
- probe->type = type;
- switch (type) {
- case LIGHTPROBE_TYPE_GRID:
- probe->distinf = 0.3f;
- probe->falloff = 1.0f;
- probe->clipsta = 0.01f;
- break;
- case LIGHTPROBE_TYPE_PLANAR:
- probe->distinf = 0.1f;
- probe->falloff = 0.5f;
- probe->clipsta = 0.001f;
- ob->empty_drawsize = 0.5f;
- break;
- case LIGHTPROBE_TYPE_CUBE:
- probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID;
- break;
- default:
- BLI_assert(!"LightProbe type not configured.");
- break;
- }
+ BKE_lightprobe_type_set(probe, type);
DEG_relations_tag_update(CTX_data_main(C));
@@ -2344,7 +2325,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!keep_original) {
/* other users */
- if (cu->id.us > 1) {
+ if (ID_REAL_USERS(&cu->id) > 1) {
for (ob1 = bmain->objects.first; ob1; ob1 = ob1->id.next) {
if (ob1->data == ob->data) {
ob1->type = OB_CURVE;
@@ -2693,6 +2674,8 @@ static int duplicate_exec(bContext *C, wmOperator *op)
copy_object_set_idnew(C);
+ ED_outliner_select_sync_from_object_tag(C);
+
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
index 29b0cb88935..b6f125c6f71 100644
--- a/source/blender/editors/object/object_data_transform.c
+++ b/source/blender/editors/object/object_data_transform.c
@@ -306,6 +306,9 @@ struct XFormObjectData_MetaBall {
struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode)
{
struct XFormObjectData *xod_base = NULL;
+ if (id == NULL) {
+ return xod_base;
+ }
switch (GS(id->name)) {
case ID_ME: {
Mesh *me = (Mesh *)id;
@@ -538,7 +541,7 @@ void ED_object_data_xform_tag_update(struct XFormObjectData *xod_base)
case ID_ME: {
Mesh *me = (Mesh *)xod_base->id;
if (xod_base->is_edit_mode) {
- EDBM_update_generic(me->edit_mesh, true, false);
+ EDBM_update_generic(me, true, false);
EDBM_mesh_normals_update(me->edit_mesh);
}
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 8012565ba2e..34e1b3b2b4b 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op)
/* Hide selected or unselected objects. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
+ if (!(base->flag & BASE_VISIBLE_VIEWLAYER)) {
continue;
}
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 303e53fa5ee..db946b63323 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -127,6 +127,11 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
md_eval->mode = mode;
}
+/** 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.
+ */
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index a130e3f3766..43aaecb887b 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -159,7 +159,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
/* props */
ot->prop = RNA_def_float_distance(
- ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f);
+ ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f);
RNA_def_float_factor(ot->srna,
"uniform",
0.0f,
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index c030c551374..f9e2a2b8a1a 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -386,6 +386,7 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
}
else {
ob = gob;
+ gob = NULL;
}
if (ob) {
@@ -1706,16 +1707,18 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
-static void libblock_relink_collection(Collection *collection)
+static void libblock_relink_collection(Collection *collection, const bool do_collection)
{
- BKE_libblock_relink_to_newid(&collection->id);
+ if (do_collection) {
+ BKE_libblock_relink_to_newid(&collection->id);
+ }
for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) {
BKE_libblock_relink_to_newid(&cob->ob->id);
}
for (CollectionChild *child = collection->children.first; child; child = child->next) {
- libblock_relink_collection(child->collection);
+ libblock_relink_collection(child->collection, true);
}
}
@@ -1753,8 +1756,13 @@ static Collection *single_object_users_collection(Main *bmain,
child_next = child->next;
Collection *collection_child_new = single_object_users_collection(
bmain, scene, child->collection, flag, copy_collections, false);
+
if (is_master_collection && copy_collections && child->collection != collection_child_new) {
- BKE_collection_child_add(bmain, collection, collection_child_new);
+ /* We do not want a collection sync here, our collections are in a complete uninitialized
+ * state currently. With current code, that would lead to a memory leak - because of reasons.
+ * It would be a useless loss of computing anyway, since caller has to fully refresh
+ * view-layers/collections caching at the end. */
+ BKE_collection_child_add_no_sync(collection, collection_child_new);
BLI_remlink(&collection->children, child);
MEM_freeN(child);
if (child == orig_child_last) {
@@ -1774,57 +1782,20 @@ static void single_object_users(
Collection *master_collection = scene->master_collection;
single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true);
- /* duplicate collections that consist entirely of duplicated objects */
- /* XXX I guess that was designed for calls from 'make single user' operator.
- * But since copy_collection is always false then, was not doing anything.
- * And that kind of behavior should be added at operator level,
- * not in a utility function also used by rather different code. */
-#if 0
- if (copy_collections) {
- Collection *collection, *collectionn;
- for (collection = bmain->collections.first; collection; collection = collection->id.next) {
- bool all_duplicated = true;
- bool any_duplicated = false;
-
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- any_duplicated = true;
- if (cob->ob->id.newid == NULL) {
- all_duplicated = false;
- break;
- }
- }
-
- if (any_duplicated && all_duplicated) {
- // TODO: test if this works, with child collections ..
- collectionn = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection));
-
- for (CollectionObject *cob = collectionn->gobject.first; cob; cob = cob->next) {
- cob->ob = (Object *)cob->ob->id.newid;
- }
- }
- }
- }
-#endif
+ /* Will also handle the master collection. */
+ BKE_libblock_relink_to_newid(&scene->id);
/* Collection and object pointers in collections */
- libblock_relink_collection(master_collection);
-
- /* collection pointers in scene */
- BKE_scene_groups_relink(scene);
+ libblock_relink_collection(scene->master_collection, false);
- /* active camera */
- ID_NEW_REMAP(scene->camera);
+ /* We also have to handle runtime things in UI. */
if (v3d) {
ID_NEW_REMAP(v3d->camera);
}
- /* Camera pointers of markers. */
- for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
- ID_NEW_REMAP(marker->camera);
- }
/* Making single user may affect other scenes if they share
* with current one some collections in their ViewLayer. */
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync_remap(bmain);
}
/* not an especially efficient function, only added so the single user
@@ -2050,13 +2021,19 @@ void ED_object_single_users(Main *bmain,
single_obdata_users(bmain, scene, NULL, NULL, 0);
single_object_action_users(bmain, scene, NULL, NULL, 0);
single_mat_users_expand(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
* 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. */
- libblock_relink_collection(scene->master_collection);
+
+ /* Will also handle the master collection. */
+ BKE_libblock_relink_to_newid(&scene->id);
+
+ /* Collection and object pointers in collections */
+ libblock_relink_collection(scene->master_collection, false);
}
/* Relink nodetrees' pointers that have been duplicated. */
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index bfe413ccb91..73fd45693a2 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -309,7 +309,7 @@ static void quadriflow_update_job(void *customdata, float progress, int *cancel)
static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes)
{
- MirrorModifierData mmd = {0};
+ MirrorModifierData mmd = {{0}};
mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
Mesh *mesh_bisect, *mesh_bisect_temp;
@@ -343,7 +343,7 @@ static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symme
static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
{
- MirrorModifierData mmd = {0};
+ MirrorModifierData mmd = {{0}};
mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
Mesh *mesh_mirror, *mesh_mirror_temp;
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index e8e0569f15e..05fa78aab1c 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -3179,6 +3179,8 @@ static int vertex_group_lock_exec(bContext *C, wmOperator *op)
vgroup_lock_all(ob, action);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 9d3388bd220..120c4929ecf 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1597,7 +1597,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet
* and flagging with PEK_HIDE will prevent selection. This might get restored once this is
* supported in drawing (but doesn't make much sense for hair anyways). */
- if (edit->psys->part->type == PART_EMITTER) {
+ if (edit->psys && edit->psys->part->type == PART_EMITTER) {
PE_hide_keys_time(scene, edit, CFRA);
}
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 4df74434c6a..c666697d15a 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1260,6 +1260,11 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
+ if (changed_tot > 0) {
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ DEG_graph_tag_relations_update(depsgraph);
+ }
+
if ((changed_tot == 0 && fail == 0) || fail) {
BKE_reportf(op->reports,
RPT_ERROR,
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 5414c2a44a2..63979e247bf 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -178,11 +178,12 @@ static bool fluid_initjob(
return true;
}
-static bool fluid_initpaths(FluidJob *job, ReportList *reports)
+static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
{
FluidDomainSettings *mds = job->mmd->domain;
char temp_dir[FILE_MAX];
temp_dir[0] = '\0';
+ bool is_relative = false;
const char *relbase = modifier_path_relbase(job->bmain, job->ob);
@@ -197,7 +198,7 @@ static bool fluid_initpaths(FluidJob *job, ReportList *reports)
}
BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR);
- BLI_path_abs(temp_dir, relbase);
+ is_relative = BLI_path_abs(temp_dir, relbase);
/* Ensure whole path exists */
const bool dir_exists = BLI_dir_create_recursive(temp_dir);
@@ -214,9 +215,6 @@ static bool fluid_initpaths(FluidJob *job, ReportList *reports)
temp_dir,
mds->cache_directory);
- BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR);
- BLI_path_abs(temp_dir, relbase);
-
/* Ensure whole path exists and is writable. */
if (!BLI_dir_create_recursive(temp_dir)) {
BKE_reportf(reports,
@@ -224,6 +222,7 @@ static bool fluid_initpaths(FluidJob *job, ReportList *reports)
"Fluid: Could not use default cache directory '%s', "
"please define a valid cache path manually",
temp_dir);
+ return false;
}
/* Copy final dir back into domain settings */
BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR);
@@ -231,6 +230,11 @@ static bool fluid_initpaths(FluidJob *job, ReportList *reports)
return false;
}
+ /* Change path back to is original state (ie relative or absolute). */
+ if (is_relative) {
+ BLI_path_rel(temp_dir, relbase);
+ }
+
/* Copy final dir back into domain settings */
BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR);
return true;
@@ -364,6 +368,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);
job->stop = stop;
job->do_update = do_update;
@@ -377,6 +382,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
mds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE;
@@ -384,6 +390,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
}
if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
mds->cache_flag |= FLUID_DOMAIN_BAKING_MESH;
@@ -392,6 +399,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
BLI_path_join(
temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(
temp_dir); /* Create 'particles' subdir if it does not exist already */
mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES);
@@ -400,6 +408,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
}
if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
mds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDE;
@@ -407,9 +416,11 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
}
if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
mds->cache_flag |= FLUID_DOMAIN_BAKING_DATA;
@@ -418,6 +429,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
if (mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
BLI_path_join(
temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_abs(temp_dir, relbase);
BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
}
}
@@ -442,6 +454,9 @@ static void fluid_free_endjob(void *customdata)
BKE_spacedata_draw_locks(false);
WM_set_locked_interface(G_MAIN->wm.first, false);
+ /* Reflect the now empty cache in the viewport too. */
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
/* Free was successful:
* Report for ended free job and how long it took */
if (job->success) {
@@ -463,7 +478,6 @@ static void fluid_free_startjob(void *customdata, short *stop, short *do_update,
{
FluidJob *job = customdata;
FluidDomainSettings *mds = job->mmd->domain;
- Scene *scene = job->scene;
job->stop = stop;
job->do_update = do_update;
@@ -495,14 +509,13 @@ static void fluid_free_startjob(void *customdata, short *stop, short *do_update,
}
#ifdef WITH_FLUID
BKE_fluid_cache_free(mds, job->ob, cache_map);
+#else
+ UNUSED_VARS(mds);
#endif
*do_update = true;
*stop = 0;
- /* Reset scene frame to cache frame start */
- CFRA = mds->cache_frame_start;
-
/* Update scene so that viewport shows freed up scene */
ED_update_for_newframe(job->bmain, job->depsgraph);
}
@@ -521,7 +534,7 @@ static int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
fluid_bake_free(job);
return OPERATOR_CANCELLED;
}
- if (!fluid_initpaths(job, op->reports)) {
+ if (!fluid_validatepaths(job, op->reports)) {
return OPERATOR_CANCELLED;
}
fluid_bake_startjob(job, NULL, NULL, NULL);
@@ -547,7 +560,7 @@ static int fluid_bake_invoke(struct bContext *C,
return OPERATOR_CANCELLED;
}
- if (!fluid_initpaths(job, op->reports)) {
+ if (!fluid_validatepaths(job, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -621,7 +634,7 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
job->type = op->type->idname;
job->name = op->type->name;
- if (!fluid_initpaths(job, op->reports)) {
+ if (!fluid_validatepaths(job, op->reports)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 5740dacd05f..11821fcdc45 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -955,7 +955,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_cursor_wait(1);
/* flush sculpt and editmode changes */
- ED_editors_flush_edits(bmain, true);
+ ED_editors_flush_edits_ex(bmain, true, false);
/* cleanup sequencer caches before starting user triggered render.
* otherwise, invalidated cache entries can make their way into
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 3a77e1e1565..43670c8fb1a 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -50,6 +50,7 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -526,15 +527,16 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
}
-static void gather_frames_to_render_for_adt(OGLRender *oglrender,
- int frame_start,
- int frame_end,
- const AnimData *adt)
+static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
{
if (adt == NULL || adt->action == NULL) {
return;
}
+ Scene *scene = oglrender->scene;
+ int frame_start = PSFRA;
+ int frame_end = PEFRA;
+
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
if (fcu->driver != NULL || fcu->fpt != NULL) {
/* Drivers have values for any point in time, so to get "the keyed frames" they are
@@ -561,13 +563,114 @@ static void gather_frames_to_render_for_adt(OGLRender *oglrender,
}
}
+static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender,
+ const bGPdata *gp)
+{
+ if (gp == NULL) {
+ return;
+ }
+
+ Scene *scene = oglrender->scene;
+ int frame_start = PSFRA;
+ int frame_end = PEFRA;
+
+ LISTBASE_FOREACH (const bGPDlayer *, gp_layer, &gp->layers) {
+ LISTBASE_FOREACH (const bGPDframe *, gp_frame, &gp_layer->frames) {
+ if (gp_frame->framenum < frame_start || gp_frame->framenum > frame_end) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(oglrender->render_frames, gp_frame->framenum - frame_start);
+ }
+ }
+}
+
+static int gather_frames_to_render_for_id(void *user_data_v, ID *id_self, ID **id_p, int cb_flag)
+{
+ if (id_p == NULL || *id_p == NULL) {
+ return IDWALK_RET_NOP;
+ }
+ ID *id = *id_p;
+
+ if (cb_flag == IDWALK_CB_LOOPBACK || id == id_self) {
+ /* IDs may end up referencing themselves one way or the other, and those
+ * (the id_self ones) have always already been processed. */
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ OGLRender *oglrender = user_data_v;
+
+ /* Whitelist of datablocks to follow pointers into. */
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ /* Whitelist: */
+ case ID_ME: /* Mesh */
+ case ID_CU: /* Curve */
+ case ID_MB: /* MetaBall */
+ case ID_MA: /* Material */
+ case ID_TE: /* Tex (Texture) */
+ case ID_IM: /* Image */
+ case ID_LT: /* Lattice */
+ case ID_LA: /* Light */
+ case ID_CA: /* Camera */
+ case ID_KE: /* Key (shape key) */
+ case ID_VF: /* VFont (Vector Font) */
+ case ID_TXT: /* Text */
+ case ID_SPK: /* Speaker */
+ case ID_SO: /* Sound */
+ case ID_AR: /* bArmature */
+ case ID_NT: /* bNodeTree */
+ case ID_PA: /* ParticleSettings */
+ case ID_MC: /* MovieClip */
+ case ID_MSK: /* Mask */
+ case ID_LP: /* LightProbe */
+ break;
+
+ /* Blacklist: */
+ case ID_SCE: /* Scene */
+ case ID_LI: /* Library */
+ case ID_OB: /* Object */
+ case ID_IP: /* Ipo (depreciated, replaced by FCurves) */
+ case ID_WO: /* World */
+ case ID_SCR: /* Screen */
+ case ID_GR: /* Group */
+ case ID_AC: /* bAction */
+ case ID_BR: /* Brush */
+ case ID_WM: /* WindowManager */
+ case ID_LS: /* FreestyleLineStyle */
+ case ID_PAL: /* Palette */
+ case ID_PC: /* PaintCurve */
+ case ID_CF: /* CacheFile */
+ case ID_WS: /* WorkSpace */
+ /* Only follow pointers to specific datablocks, to avoid ending up in
+ * unrelated datablocks and exploding the number of blocks we follow. If the
+ * frames of the animation of certain objects should be taken into account,
+ * they should have been selected by the user. */
+ return IDWALK_RET_STOP_RECURSION;
+
+ /* Special cases: */
+ case ID_GD: /* bGPdata, (Grease Pencil) */
+ /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation
+ * system that requires specific handling here. */
+ gather_frames_to_render_for_grease_pencil(oglrender, (bGPdata *)id);
+ break;
+ }
+
+ AnimData *adt = BKE_animdata_from_id(id);
+ gather_frames_to_render_for_adt(oglrender, adt);
+
+ return IDWALK_RET_NOP;
+}
+
/**
* Collect the frame numbers for which selected objects have keys in the animation data.
* The frames ares stored in #OGLRender.render_frames.
+ *
+ * Note that this follows all pointers to ID blocks, only filtering on ID type,
+ * so it will pick up keys from pointers in custom properties as well.
*/
static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
{
- Scene *scene = CTX_data_scene(C);
+ Scene *scene = oglrender->scene;
int frame_start = PSFRA;
int frame_end = PEFRA;
@@ -579,14 +682,15 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
- if (ob->adt != NULL) {
- gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, ob->adt);
- }
+ ID *id = &ob->id;
- AnimData *adt = BKE_animdata_from_id(ob->data);
- if (adt != NULL) {
- gather_frames_to_render_for_adt(oglrender, frame_start, frame_end, adt);
- }
+ /* Gather the frames from the object animation data. */
+ AnimData *adt = BKE_animdata_from_id(id);
+ gather_frames_to_render_for_adt(oglrender, adt);
+
+ /* Gather the frames from linked datablocks (materials, shapkeys, etc.). */
+ BKE_library_foreach_ID_link(
+ NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
}
CTX_DATA_END;
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 7705278443f..22c91686bbf 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -65,7 +65,7 @@ Scene *ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod me
/* these can't be handled in blenkernel currently, so do them here */
if (method == SCE_COPY_FULL) {
- ED_editors_flush_edits(bmain, false);
+ ED_editors_flush_edits(bmain);
ED_object_single_users(bmain, scene_new, true, true);
}
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 98bee156090..7db634660af 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1141,6 +1141,9 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
}
}
+ /* Guard against flags slipping through that would have to be masked out in usages below. */
+ BLI_assert(align1 == RGN_ALIGN_ENUM_FROM_MASK(align1));
+
/* translate or close */
if (ar1) {
if (align1 == RGN_ALIGN_LEFT) {
@@ -1244,6 +1247,20 @@ static void region_rect_recursive(
alignment = RGN_ALIGN_NONE;
}
+ /* If both the ARegion.sizex/y and the prefsize are 0, the region is tagged as too small, even
+ * before the layout for dynamic regions is created. #wm_draw_window_offscreen() allows the
+ * layout to be created despite the RGN_FLAG_TOO_SMALL flag being set. But there may still be
+ * regions that don't have a separate ARegionType.layout callback. For those, set a default
+ * prefsize so they can become visible. */
+ if ((ar->flag & RGN_FLAG_DYNAMIC_SIZE) && !(ar->type->layout)) {
+ if ((ar->sizex == 0) && (ar->type->prefsizex == 0)) {
+ ar->type->prefsizex = AREAMINX;
+ }
+ if ((ar->sizey == 0) && (ar->type->prefsizey == 0)) {
+ ar->type->prefsizey = HEADERY;
+ }
+ }
+
/* prefsize, taking into account DPI */
int prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex);
int prefsizey;
@@ -1323,7 +1340,7 @@ static void region_rect_recursive(
else if (alignment == RGN_ALIGN_TOP || alignment == RGN_ALIGN_BOTTOM) {
rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(winrct, 'v', prefsizey) < 0) {
+ if ((prefsizey == 0) || (rct_fits(winrct, 'v', prefsizey) < 0)) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
@@ -1348,7 +1365,7 @@ static void region_rect_recursive(
else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(winrct, 'h', prefsizex) < 0) {
+ if ((prefsizex == 0) || (rct_fits(winrct, 'h', prefsizex) < 0)) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
@@ -1437,6 +1454,10 @@ static void region_rect_recursive(
BLI_rcti_init(remainder, 0, 0, 0, 0);
}
+ /* Fix any negative dimensions. This can happen when a quad split 3d view gets to small. (see
+ * T72200). */
+ BLI_rcti_sanitize(&ar->winrct);
+
quad++;
}
}
@@ -1474,11 +1495,16 @@ static void region_rect_recursive(
ar->winrct.xmin = ar->winrct.xmax;
break;
case RGN_ALIGN_LEFT:
+ ar->winrct.xmax = ar->winrct.xmin;
+ break;
default:
/* prevent winrct to be valid */
ar->winrct.xmax = ar->winrct.xmin;
break;
}
+
+ /* Size on one axis is now 0, the other axis may still be invalid (negative) though. */
+ BLI_rcti_sanitize(&ar->winrct);
}
/* restore prev-split exception */
@@ -1496,6 +1522,8 @@ static void region_rect_recursive(
*overlap_remainder = *remainder;
}
+ BLI_assert(BLI_rcti_is_valid(&ar->winrct));
+
region_rect_recursive(sa, ar->next, remainder, overlap_remainder, quad);
/* Tag for redraw if size changes. */
@@ -1594,11 +1622,6 @@ static void ed_default_handlers(
WM_gizmomap_add_handlers(ar, ar->gizmo_map);
}
}
- if (flag & ED_KEYMAP_TOOL) {
- WM_event_add_keymap_handler_dynamic(
- &ar->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa);
- WM_event_add_keymap_handler_dynamic(&ar->handlers, WM_event_get_keymap_from_toolsystem, sa);
- }
if (flag & ED_KEYMAP_VIEW2D) {
/* 2d-viewport handling+manipulation */
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0);
@@ -1619,6 +1642,11 @@ static void ed_default_handlers(
keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0);
WM_event_add_keymap_handler(handlers, keymap);
}
+ if (flag & ED_KEYMAP_TOOL) {
+ WM_event_add_keymap_handler_dynamic(
+ &ar->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa);
+ WM_event_add_keymap_handler_dynamic(&ar->handlers, WM_event_get_keymap_from_toolsystem, sa);
+ }
if (flag & ED_KEYMAP_FRAMES) {
/* frame changing/jumping (for all spaces) */
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Frames", 0, 0);
@@ -1813,8 +1841,10 @@ void ED_region_update_rect(ARegion *ar)
}
/* externally called for floating regions like menus */
-void ED_region_init(ARegion *ar)
+void ED_region_floating_initialize(ARegion *ar)
{
+ BLI_assert(ar->alignment == RGN_ALIGN_FLOAT);
+
/* refresh can be called before window opened */
region_subwindow(ar);
@@ -2316,7 +2346,7 @@ static void ed_panel_draw(const bContext *C,
}
}
- UI_panel_end(block, w, h, open);
+ UI_panel_end(sa, ar, block, w, h, open);
}
/**
@@ -2560,7 +2590,7 @@ void ED_region_panels_draw(const bContext *C, ARegion *ar)
/* scrollers */
const rcti *mask = NULL;
rcti mask_buf;
- if (ar->runtime.category && (ar->alignment == RGN_ALIGN_RIGHT)) {
+ if (ar->runtime.category && (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT)) {
UI_view2d_mask_from_win(v2d, &mask_buf);
mask_buf.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH;
mask = &mask_buf;
@@ -3322,7 +3352,9 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect)
for (; arn; arn = arn->next) {
if (ar != arn && arn->overlap) {
if (BLI_rcti_isect(rect, &arn->winrct, NULL)) {
- if (ELEM(arn->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ int alignment = RGN_ALIGN_ENUM_FROM_MASK(arn->alignment);
+
+ if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
/* Overlap left, also check 1 pixel offset (2 regions on one side). */
if (ABS(rect->xmin - arn->winrct.xmin) < 2) {
rect->xmin = arn->winrct.xmax;
@@ -3333,7 +3365,7 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect)
rect->xmax = arn->winrct.xmin;
}
}
- else if (ELEM(arn->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
/* Same logic as above for vertical regions. */
if (ABS(rect->ymin - arn->winrct.ymin) < 2) {
rect->ymin = arn->winrct.ymax;
@@ -3342,7 +3374,7 @@ static void region_visible_rect_calc(ARegion *ar, rcti *rect)
rect->ymax = arn->winrct.ymin;
}
}
- else if (arn->alignment == RGN_ALIGN_FLOAT) {
+ else if (alignment == RGN_ALIGN_FLOAT) {
/* Skip floating. */
}
else {
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 46559efc614..942050aaffd 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -67,10 +67,12 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *ar, rcti *r_ar_gut
if (UI_panel_category_is_visible(ar)) {
const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&ar->v2d) *
UI_PANEL_CATEGORY_MARGIN_WIDTH);
- if (ar->alignment == RGN_ALIGN_LEFT) {
+ const int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment);
+
+ if (alignment == RGN_ALIGN_LEFT) {
r_ar_gutter->xmax = r_ar_gutter->xmin + category_tabs_width;
}
- else if (ar->alignment == RGN_ALIGN_RIGHT) {
+ else if (alignment == RGN_ALIGN_RIGHT) {
r_ar_gutter->xmin = r_ar_gutter->xmax - category_tabs_width;
}
else {
@@ -141,14 +143,16 @@ bool ED_region_contains_xy(const ARegion *ar, const int event_xy[2])
else {
/* Side-bar & any other kind of overlapping region. */
+ const int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment);
+
/* Check alignment to avoid region tabs being clipped out
* by only clipping a single axis for aligned regions. */
- if (ELEM(ar->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
if (!ED_region_overlap_isect_x_with_margin(ar, event_xy[0], overlap_margin)) {
return false;
}
}
- else if (ELEM(ar->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
if (ED_region_panel_category_gutter_isect_xy(ar, event_xy)) {
/* pass */
}
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 61fb9d5a3a8..12de1ddb795 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -33,6 +33,7 @@
#include "ED_screen.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
/* -------------------------------------------------------------------- */
/** \name Generic Tool System Region Callbacks
@@ -63,17 +64,27 @@ void ED_region_generic_tools_region_message_subscribe(const struct bContext *UNU
int ED_region_generic_tools_region_snap_size(const ARegion *ar, int size, int axis)
{
if (axis == 0) {
- /* Note, this depends on the icon size: see #ICON_DEFAULT_HEIGHT_TOOLBAR. */
- const float snap_units[] = {2 + 0.8f, 4 + 0.8f};
- const float aspect = BLI_rctf_size_x(&ar->v2d.cur) / (BLI_rcti_size_x(&ar->v2d.mask) + 1);
+ /* Using Y axis avoids slight feedback loop when adjusting X. */
+ const float aspect = BLI_rctf_size_y(&ar->v2d.cur) / (BLI_rcti_size_y(&ar->v2d.mask) + 1);
+ const float icon_size = ICON_DEFAULT_HEIGHT_TOOLBAR / aspect;
+ const float column = 1.25f * icon_size;
+ const float margin = 0.5f * icon_size;
+ const float snap_units[] = {
+ column + margin,
+ (2.0f * column) + margin,
+ (2.7f * column) + margin,
+ };
int best_diff = INT_MAX;
int best_size = size;
- for (uint i = 0; i < ARRAY_SIZE(snap_units); i += 1) {
- const int test_size = (snap_units[i] * U.widget_unit) / (UI_DPI_FAC * aspect);
- const int test_diff = ABS(test_size - size);
- if (test_diff < best_diff) {
- best_size = test_size;
- best_diff = test_diff;
+ /* Only snap if less than last snap unit. */
+ if (size <= snap_units[ARRAY_SIZE(snap_units) - 1]) {
+ for (uint i = 0; i < ARRAY_SIZE(snap_units); i += 1) {
+ const int test_size = snap_units[i];
+ const int test_diff = ABS(test_size - size);
+ if (test_diff < best_diff) {
+ best_size = test_size;
+ best_diff = test_diff;
+ }
}
}
return best_size;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index f7742c5e50a..a840d199823 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -90,11 +90,14 @@ const char *screen_context_dir[] = {
"selected_editable_sequences", /* sequencer */
"gpencil_data",
"gpencil_data_owner", /* grease pencil data */
+ "annotation_data",
+ "annotation_data_owner",
"visible_gpencil_layers",
"editable_gpencil_layers",
"editable_gpencil_strokes",
"active_gpencil_layer",
"active_gpencil_frame",
+ "active_annotation_layer",
"active_operator",
"visible_fcurves",
"editable_fcurves",
@@ -506,7 +509,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
* 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((ID *)sc, sa, scene, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -515,14 +518,33 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "gpencil_data_owner")) {
/* Pointer to which data/datablock owns the reference to the Grease Pencil data being used
- * (as gpencil_data).
- * XXX: see comment for gpencil_data case.
- */
+ * (as gpencil_data). */
bGPdata **gpd_ptr = NULL;
PointerRNA ptr;
/* get pointer to Grease Pencil Data */
- gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, sa, scene, obact, &ptr);
+ gpd_ptr = ED_gpencil_data_get_pointers_direct(sa, obact, &ptr);
+
+ if (gpd_ptr) {
+ CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "annotation_data")) {
+ bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
+
+ if (gpd) {
+ CTX_data_id_pointer_set(result, &gpd->id);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "annotation_data_owner")) {
+ /* Pointer to which data/datablock owns the reference to the Grease Pencil data being used. */
+ bGPdata **gpd_ptr = NULL;
+ PointerRNA ptr;
+
+ /* Get pointer to Grease Pencil Data. */
+ gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)sc, sa, scene, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
@@ -530,8 +552,19 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_gpencil_layer")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+
+ if (gpd) {
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ if (gpl) {
+ CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
+ return 1;
+ }
+ }
+ }
+ else if (CTX_data_equals(member, "active_annotation_layer")) {
+ bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
@@ -543,8 +576,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_gpencil_frame")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
@@ -556,8 +588,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "visible_gpencil_layers")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -572,8 +603,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "editable_gpencil_layers")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -588,8 +618,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
if (gpd) {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 7c47f7439ab..14ea3aca623 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -929,6 +929,8 @@ static void actionzone_exit(wmOperator *op)
MEM_freeN(op->customdata);
}
op->customdata = NULL;
+
+ G.moving &= ~G_TRANSFORM_WM;
}
/* send EVT_ACTIONZONE event */
@@ -986,9 +988,11 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
else {
+ BLI_assert(ELEM(sad->az->type, AZONE_AREA, AZONE_REGION_SCROLL));
+
/* add modal handler */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
-
return OPERATOR_RUNNING_MODAL;
}
}
@@ -1807,9 +1811,8 @@ static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
- G.moving |= G_TRANSFORM_WM;
-
/* add temp handler */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2115,6 +2118,8 @@ static void area_split_exit(bContext *C, wmOperator *op)
/* this makes sure aligned edges will result in aligned grabbing */
BKE_screen_remove_double_scrverts(CTX_wm_screen(C));
BKE_screen_remove_double_scredges(CTX_wm_screen(C));
+
+ G.moving &= ~G_TRANSFORM_WM;
}
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
@@ -2247,6 +2252,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
area_move_set_limits(win, sc, dir, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2526,6 +2532,14 @@ static bool is_split_edge(const int alignment, const AZEdge edge)
((alignment == RGN_ALIGN_RIGHT) && (edge == AE_LEFT_TO_TOPRIGHT));
}
+static void region_scale_exit(wmOperator *op)
+{
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+
+ G.moving &= ~G_TRANSFORM_WM;
+}
+
static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
sActionzoneData *sad = event->customdata;
@@ -2579,6 +2593,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
CLAMP(rmd->maxsize, 0, 1000);
/* add temp handler */
+ G.moving |= G_TRANSFORM_WM;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2651,7 +2666,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* region sizes now get multiplied */
delta /= UI_DPI_FAC;
- rmd->ar->sizex = rmd->origval + delta;
+ const int size_no_snap = rmd->origval + delta;
+ rmd->ar->sizex = size_no_snap;
if (rmd->ar->type->snap_size) {
short sizex_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizex, 0);
@@ -2661,7 +2677,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
- if (rmd->ar->sizex < UI_UNIT_X) {
+ if (size_no_snap < UI_UNIT_X / aspect) {
rmd->ar->sizex = rmd->origval;
if (!(rmd->ar->flag & RGN_FLAG_HIDDEN)) {
region_scale_toggle_hidden(C, rmd);
@@ -2683,7 +2699,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* region sizes now get multiplied */
delta /= UI_DPI_FAC;
- rmd->ar->sizey = rmd->origval + delta;
+ const int size_no_snap = rmd->origval + delta;
+ rmd->ar->sizey = size_no_snap;
if (rmd->ar->type->snap_size) {
short sizey_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizey, 1);
@@ -2696,7 +2713,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* note, 'UI_UNIT_Y/4' means you need to drag the footer and execute region
* almost all the way down for it to become hidden, this is done
* otherwise its too easy to do this by accident */
- if (rmd->ar->sizey < UI_UNIT_Y / 4) {
+ if (size_no_snap < (UI_UNIT_Y / 4) / aspect) {
rmd->ar->sizey = rmd->origval;
if (!(rmd->ar->flag & RGN_FLAG_HIDDEN)) {
region_scale_toggle_hidden(C, rmd);
@@ -2727,8 +2744,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_area_tag_redraw(rmd->sa);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+
+ region_scale_exit(op);
return OPERATOR_FINISHED;
}
@@ -2743,8 +2760,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void region_scale_cancel(bContext *UNUSED(C), wmOperator *op)
{
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+ region_scale_exit(op);
}
static void SCREEN_OT_region_scale(wmOperatorType *ot)
@@ -3627,6 +3643,15 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
/** \name Repeat Last Operator
* \{ */
+static bool repeat_history_poll(bContext *C)
+{
+ if (!ED_operator_screenactive(C)) {
+ return false;
+ }
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return !BLI_listbase_is_empty(&wm->operators);
+}
+
static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3660,7 +3685,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot)
/* api callbacks */
ot->exec = repeat_last_exec;
- ot->poll = ED_operator_screenactive;
+ ot->poll = repeat_history_poll;
}
/** \} */
@@ -3727,8 +3752,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = repeat_history_invoke;
ot->exec = repeat_history_exec;
-
- ot->poll = ED_operator_screenactive;
+ ot->poll = repeat_history_poll;
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
}
@@ -3759,8 +3783,7 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot)
/* api callbacks */
ot->invoke = redo_last_invoke;
-
- ot->poll = ED_operator_screenactive;
+ ot->poll = repeat_history_poll;
}
/** \} */
@@ -4098,8 +4121,9 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") :
- IFACE_("Flip to Top");
+ const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->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);
@@ -4144,8 +4168,9 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") :
- IFACE_("Flip to Top");
+ const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->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);
@@ -4170,8 +4195,9 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
const ARegion *ar = CTX_wm_region(C);
- const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") :
- IFACE_("Flip to Left");
+ const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_LEFT) ?
+ IFACE_("Flip to Right") :
+ IFACE_("Flip to Left");
/* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
@@ -4824,7 +4850,10 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
+
region->flag |= RGN_FLAG_HIDDEN;
+ ED_region_visibility_change_update(C, area, region);
+
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 856072ec47a..19b4b9f569c 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -252,14 +252,14 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
TexSnapshot *target;
MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
- eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
+ ePaintOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
GLubyte *buffer = NULL;
int size;
bool refresh;
- eOverlayControlFlags invalid = ((primary) ?
- (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY) :
- (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY));
+ ePaintOverlayControlFlags invalid =
+ ((primary) ? (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY) :
+ (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY));
target = (primary) ? &primary_snap : &secondary_snap;
refresh = !target->overlay_texture || (invalid != 0) ||
@@ -422,7 +422,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
{
bool init;
- eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
+ ePaintOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
GLubyte *buffer = NULL;
int size;
@@ -836,7 +836,7 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
bool alpha_overlay_active = false;
- eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
+ ePaintOverlayControlFlags flags = BKE_paint_get_overlay_flags();
gpuPushAttr(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
/* Translate to region. */
@@ -1329,7 +1329,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* set various defaults */
const float *outline_col = brush->add_col;
- const float outline_alpha = 0.7f;
+ const float outline_alpha = brush->add_col[3];
float translation[2] = {x, y};
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
@@ -1461,15 +1461,30 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
}
- /* Draw pose brush origin */
+ /* Draw pose brush origins. */
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
if (update_previews) {
BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
- sculpt_pose_calc_pose_data(
- sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL);
+
+ /* Free the previous pose brush preview. */
+ if (ss->pose_ik_chain_preview) {
+ sculpt_pose_ik_chain_free(ss->pose_ik_chain_preview);
+ }
+
+ /* Generate a new pose brush preview from the current cursor location. */
+ ss->pose_ik_chain_preview = sculpt_pose_ik_chain_init(
+ sd, vc.obact, ss, brush, gi.location, rds);
+ }
+
+ /* Draw the pose brush rotation origins. */
+ for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
+ cursor_draw_point_screen_space(pos,
+ ar,
+ ss->pose_ik_chain_preview->segments[i].initial_orig,
+ vc.obact->obmat,
+ 3);
}
- cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
}
/* Draw 3D brush cursor */
@@ -1518,9 +1533,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
GPU_line_width(2.0f);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, ss->pose_origin);
- immVertex3fv(pos, gi.location);
+
+ immBegin(GPU_PRIM_LINES, ss->pose_ik_chain_preview->tot_segments * 2);
+ for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
+ immVertex3fv(pos, ss->pose_ik_chain_preview->segments[i].initial_orig);
+ immVertex3fv(pos, ss->pose_ik_chain_preview->segments[i].initial_head);
+ }
+
immEnd();
}
@@ -1547,16 +1566,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
else {
if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
- /* Draw cursor location preview when the stroke is active using the data from StrokeCache
- */
- float cursor_location[3];
wmViewport(&ar->winrct);
- copy_v3_v3(cursor_location, ss->cache->true_location);
- if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- add_v3_v3(cursor_location, ss->cache->grab_delta);
- }
- cursor_draw_point_with_symmetry(
- pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
/* Draw cached dynamic mesh preview lines */
if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index de09a52258f..6d1a32d1c45 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -939,7 +939,7 @@ void PAINT_OT_grab_clone(wmOperatorType *ot)
/******************** sample color operator ********************/
typedef struct {
bool show_cursor;
- short event_type;
+ short launch_event;
float initcolor[3];
bool sample_palette;
} SampleColorData;
@@ -1000,7 +1000,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
ARegion *ar = CTX_wm_region(C);
wmWindow *win = CTX_wm_window(C);
- data->event_type = event->type;
+ data->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
data->sample_palette = false;
@@ -1036,7 +1036,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
- if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
+ if ((event->type == data->launch_event) && (event->val == KM_RELEASE)) {
if (data->show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 53beb981522..6f2e4a0055d 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -45,6 +45,7 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
enum ePaintMode;
+enum ePaintSymmetryFlags;
typedef struct CoNo {
float co[3];
@@ -306,8 +307,8 @@ bool mask_paint_poll(struct bContext *C);
bool paint_curve_poll(struct bContext *C);
bool facemask_paint_poll(struct bContext *C);
-void flip_v3_v3(float out[3], const float in[3], const char symm);
-void flip_qt_qt(float out[3], const float in[3], const char symm);
+void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
+void flip_qt_qt(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
/* stroke operator */
typedef enum BrushStrokeMode {
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 6252741799a..7863e18394c 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -562,7 +562,7 @@ typedef struct {
float *dim_target;
float *rot_target;
float *pos_target;
- short event_type;
+ short launch_event;
} StencilControlData;
static void stencil_set_target(StencilControlData *scd)
@@ -626,7 +626,7 @@ static int stencil_control_invoke(bContext *C, wmOperator *op, const wmEvent *ev
stencil_set_target(scd);
scd->mode = RNA_enum_get(op->ptr, "mode");
- scd->event_type = event->type;
+ scd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
scd->area_size[0] = ar->winx;
scd->area_size[1] = ar->winy;
@@ -709,7 +709,7 @@ static int stencil_control_modal(bContext *C, wmOperator *op, const wmEvent *eve
{
StencilControlData *scd = op->customdata;
- if (event->type == scd->event_type && event->val == KM_RELEASE) {
+ if (event->type == scd->launch_event && event->val == KM_RELEASE) {
MEM_freeN(op->customdata);
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index a014fe7fdff..db22729e8b0 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -412,7 +412,7 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
}
/* Uses symm to selectively flip any axis of a coordinate. */
-void flip_v3_v3(float out[3], const float in[3], const char symm)
+void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
{
if (symm & PAINT_SYMM_X) {
out[0] = -in[0];
@@ -434,7 +434,7 @@ void flip_v3_v3(float out[3], const float in[3], const char symm)
}
}
-void flip_qt_qt(float out[4], const float in[4], const char symm)
+void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
{
float axis[3], angle;
@@ -519,13 +519,20 @@ void paint_sample_color(
}
if (image) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (ibuf && ibuf->rect) {
- float uv[2];
- float u, v;
- imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
- sample_success = true;
-
+ float uv[2];
+ float u, v;
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+
+ imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
+
+ if (image->source == IMA_SRC_TILED) {
+ float new_uv[2];
+ iuser.tile = BKE_image_get_tile_from_pos(image, uv, new_uv, NULL);
+ u = new_uv[0];
+ v = new_uv[1];
+ }
+ else {
u = fmodf(uv[0], 1.0f);
v = fmodf(uv[1], 1.0f);
@@ -535,6 +542,11 @@ void paint_sample_color(
if (v < 0.0f) {
v += 1.0f;
}
+ }
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, NULL);
+ if (ibuf && ibuf->rect) {
+ sample_success = true;
u = u * ibuf->x;
v = v * ibuf->y;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index cafdd72c7cd..7372ea6d44a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1512,14 +1512,9 @@ static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, P
/* Truly temporary data that isn't stored in properties */
if (cache->first_time) {
- if (!BKE_brush_use_locked_size(scene, brush)) {
- cache->initial_radius = paint_calc_object_space_radius(
- cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
- BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
- }
- else {
- cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
- }
+ cache->initial_radius = paint_calc_object_space_radius(
+ cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
+ BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
}
if (BKE_brush_use_size_pressure(brush) &&
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b26d706bbf4..5663b109dc4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -443,7 +443,7 @@ static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
}
static int sculpt_nearest_vertex_get(
- Sculpt *sd, Object *ob, float co[3], float max_distance, bool use_original)
+ Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
{
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
@@ -1256,7 +1256,7 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
return false;
}
- if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
+ if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) {
return true;
}
return false;
@@ -1330,11 +1330,16 @@ static void sculpt_automasking_init(Sculpt *sd, Object *ob)
/* ===== Sculpting =====
*/
-static void flip_v3(float v[3], const char symm)
+static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
{
flip_v3_v3(v, v, symm);
}
+static void flip_qt(float quat[3], const ePaintSymmetryFlags symm)
+{
+ flip_qt_qt(quat, quat, symm);
+}
+
static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
float mirror[3];
@@ -1750,7 +1755,7 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
- case SCULPT_TOOL_TOPOLOGY:
+ case SCULPT_TOOL_SLIDE_RELAX:
return alpha * pressure * overlap * feather * 2.0f;
case SCULPT_TOOL_CLAY_STRIPS:
/* Clay Strips needs less strength to compensate the curve */
@@ -1921,7 +1926,8 @@ float tex_strength(SculptSession *ss,
bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
- float *center, nearest[3];
+ const float *center;
+ float nearest[3];
if (data->center) {
center = data->center;
}
@@ -3136,7 +3142,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-static void do_topology_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -3527,15 +3533,143 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
}
+static ePaintSymmetryAreas sculpt_get_vertex_symm_area(const float co[3])
+{
+ ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT;
+ if (co[0] < 0.0f) {
+ symm_area |= PAINT_SYMM_AREA_X;
+ }
+ if (co[1] < 0.0f) {
+ symm_area |= PAINT_SYMM_AREA_Y;
+ }
+ if (co[2] < 0.0f) {
+ symm_area |= PAINT_SYMM_AREA_Z;
+ }
+ return symm_area;
+}
+
+static void sculpt_flip_v3_by_symm_area(float v[3],
+ const ePaintSymmetryFlags symm,
+ const ePaintSymmetryAreas symmarea,
+ const float pivot[3])
+{
+ for (char i = 0; i < 3; i++) {
+ ePaintSymmetryFlags symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (symmarea & symm_it) {
+ flip_v3(v, symm_it);
+ }
+ if (pivot[0] < 0) {
+ flip_v3(v, symm_it);
+ }
+ }
+ }
+}
+
+static void sculpt_flip_quat_by_symm_area(float quat[3],
+ const ePaintSymmetryFlags symm,
+ const ePaintSymmetryAreas symmarea,
+ const float pivot[3])
+{
+ for (char i = 0; i < 3; i++) {
+ ePaintSymmetryFlags symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (symmarea & symm_it) {
+ flip_qt(quat, symm_it);
+ }
+ if (pivot[0] < 0) {
+ flip_qt(quat, symm_it);
+ }
+ }
+ }
+}
+
+static void pose_solve_ik_chain(SculptPoseIKChain *ik_chain, const float initial_target[3])
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ int tot_segments = ik_chain->tot_segments;
+
+ float target[3];
+
+ /* Set the initial target. */
+ copy_v3_v3(target, initial_target);
+
+ /* Solve the positions and rotations of all segments in the chain. */
+ for (int i = 0; i < tot_segments; i++) {
+ float initial_orientation[3];
+ float current_orientation[3];
+ float current_head_position[3];
+ float current_origin_position[3];
+
+ /* Calculate the rotation to orientate the segment to the target from its initial state. */
+ sub_v3_v3v3(current_orientation, target, segments[i].orig);
+ normalize_v3(current_orientation);
+ sub_v3_v3v3(initial_orientation, segments[i].initial_head, segments[i].initial_orig);
+ normalize_v3(initial_orientation);
+ rotation_between_vecs_to_quat(segments[i].rot, initial_orientation, current_orientation);
+
+ /* Rotate the segment by calculating a new head position. */
+ madd_v3_v3v3fl(current_head_position, segments[i].orig, current_orientation, segments[i].len);
+
+ /* Move the origin of the segment towards the target. */
+ sub_v3_v3v3(current_origin_position, target, current_head_position);
+
+ /* Store the new head and origin positions to the segment. */
+ copy_v3_v3(segments[i].head, current_head_position);
+ add_v3_v3(segments[i].orig, current_origin_position);
+
+ /* Use the origin of this segment as target for the next segment in the chain. */
+ copy_v3_v3(target, segments[i].orig);
+ }
+
+ /* Move back the whole chain to preserve the anchor point. */
+ float anchor_diff[3];
+ sub_v3_v3v3(
+ anchor_diff, segments[tot_segments - 1].initial_orig, segments[tot_segments - 1].orig);
+
+ for (int i = 0; i < tot_segments; i++) {
+ add_v3_v3(segments[i].orig, anchor_diff);
+ add_v3_v3(segments[i].head, anchor_diff);
+ }
+}
+
+static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain,
+ const Brush *brush,
+ const float roll)
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ float initial_orientation[3];
+ float initial_rotation[4];
+ float current_rotation[4];
+
+ sub_v3_v3v3(initial_orientation, segments[i].initial_head, segments[i].initial_orig);
+ normalize_v3(initial_orientation);
+
+ /* Calculate the current roll angle using the brush curve. */
+ float current_roll = roll * BKE_brush_curve_strength(brush, i, tot_segments);
+
+ axis_angle_normalized_to_quat(initial_rotation, initial_orientation, 0.0f);
+ axis_angle_normalized_to_quat(current_rotation, initial_orientation, current_roll);
+
+ /* Store the difference of the rotations in the segment rotation. */
+ rotation_between_quats_to_quat(segments[i].rot, current_rotation, initial_rotation);
+ }
+}
+
static void do_pose_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
PBVHVertexIter vd;
- float disp[3], val[3];
+ float disp[3], new_co[3];
float final_pos[3];
SculptOrigVertData orig_data;
@@ -3543,25 +3677,41 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
-
sculpt_orig_vert_data_update(&orig_data, &vd);
- if (check_vertex_pivot_symmetry(
- orig_data.co, data->pose_initial_co, ss->cache->mirror_symmetry_pass)) {
- copy_v3_v3(val, orig_data.co);
- mul_m4_v3(data->transform_trans_inv, val);
- mul_m4_v3(data->transform_rot, val);
- mul_m4_v3(data->transform_trans, val);
- sub_v3_v3v3(disp, val, orig_data.co);
-
- mul_v3_fl(disp, ss->cache->pose_factor[vd.index]);
+
+ float total_disp[3];
+ zero_v3(total_disp);
+
+ ePaintSymmetryAreas symm_area = sculpt_get_vertex_symm_area(orig_data.co);
+
+ /* Calculate the displacement of each vertex for all the segments in the chain. */
+ for (int ik = 0; ik < ik_chain->tot_segments; ik++) {
+ copy_v3_v3(new_co, orig_data.co);
+
+ /* Get the transform matrix for the vertex symmetry area to calculate a displacement in the
+ * vertex. */
+ mul_m4_v3(segments[ik].pivot_mat_inv[(int)symm_area], new_co);
+ mul_m4_v3(segments[ik].trans_mat[(int)symm_area], new_co);
+ mul_m4_v3(segments[ik].pivot_mat[(int)symm_area], new_co);
+
+ /* Apply the segment weight of the vertex to the displacement. */
+ sub_v3_v3v3(disp, new_co, orig_data.co);
+ mul_v3_fl(disp, segments[ik].weights[vd.index]);
+
+ /* Apply the vertex mask to the displacement. */
float mask = vd.mask ? *vd.mask : 0.0f;
mul_v3_fl(disp, 1.0f - mask);
- add_v3_v3v3(final_pos, orig_data.co, disp);
- copy_v3_v3(vd.co, final_pos);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ /* Accumulate the displacement. */
+ add_v3_v3(total_disp, disp);
+ }
+
+ /* Apply the accumulated displacement to the vertex. */
+ add_v3_v3v3(final_pos, orig_data.co, total_disp);
+ copy_v3_v3(vd.co, final_pos);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BKE_pbvh_vertex_iter_end;
@@ -3571,32 +3721,75 @@ static void 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], rot_quat[4], initial_v[3], current_v[3], temp[3];
- float pose_origin[3];
- float pose_initial_co[3];
- float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
+ float grab_delta[3];
+ float ik_target[3];
+ const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ /* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be
+ * ignored. */
+ if (ss->cache->mirror_symmetry_pass != 0) {
+ return;
+ }
+
+ 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);
- copy_v3_v3(pose_origin, ss->cache->pose_origin);
- flip_v3(pose_origin, (char)ss->cache->mirror_symmetry_pass);
+ /* Solve the IK positions */
+ pose_solve_ik_chain(ik_chain, ik_target);
+ }
+
+ /* Flip the segment chain in all symmetry axis and calculate the transform matrices for each
+ * possible combination. */
+ /* 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++) {
+ float symm_rot[4];
+ float symm_orig[3];
+ float symm_initial_orig[3];
- copy_v3_v3(pose_initial_co, ss->cache->pose_initial_co);
- flip_v3(pose_initial_co, (char)ss->cache->mirror_symmetry_pass);
+ ePaintSymmetryAreas symm_area = symm_it;
- sub_v3_v3v3(initial_v, pose_initial_co, pose_origin);
- normalize_v3(initial_v);
+ copy_qt_qt(symm_rot, ik_chain->segments[i].rot);
+ copy_v3_v3(symm_orig, ik_chain->segments[i].orig);
+ copy_v3_v3(symm_initial_orig, ik_chain->segments[i].initial_orig);
- add_v3_v3v3(temp, pose_initial_co, grab_delta);
- sub_v3_v3v3(current_v, temp, pose_origin);
- normalize_v3(current_v);
+ /* Flip the origins and rotation quats of each segment. */
+ sculpt_flip_quat_by_symm_area(symm_rot, symm, symm_area, ss->cache->orig_grab_location);
+ sculpt_flip_v3_by_symm_area(symm_orig, symm, symm_area, ss->cache->orig_grab_location);
+ sculpt_flip_v3_by_symm_area(
+ symm_initial_orig, symm, symm_area, ss->cache->orig_grab_location);
- rotation_between_vecs_to_quat(rot_quat, initial_v, current_v);
- unit_m4(transform_rot);
- unit_m4(transform_trans);
- quat_to_mat4(transform_rot, rot_quat);
- translate_m4(transform_trans, pose_origin[0], pose_origin[1], pose_origin[2]);
- invert_m4_m4(transform_trans_inv, transform_trans);
+ /* 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);
+
+ translate_m4(ik_chain->segments[i].trans_mat[symm_it],
+ symm_orig[0] - symm_initial_orig[0],
+ symm_orig[1] - symm_initial_orig[1],
+ symm_orig[2] - symm_initial_orig[2]);
+ translate_m4(
+ ik_chain->segments[i].pivot_mat[symm_it], symm_orig[0], symm_orig[1], symm_orig[2]);
+ invert_m4_m4(ik_chain->segments[i].pivot_mat_inv[symm_it],
+ ik_chain->segments[i].pivot_mat[symm_it]);
+ }
+ }
SculptThreadedTaskData data = {
.sd = sd,
@@ -3604,11 +3797,6 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.brush = brush,
.nodes = nodes,
.grab_delta = grab_delta,
- .pose_origin = pose_origin,
- .pose_initial_co = pose_initial_co,
- .transform_rot = transform_rot,
- .transform_trans = transform_trans,
- .transform_trans_inv = transform_trans_inv,
};
PBVHParallelSettings settings;
@@ -3629,23 +3817,24 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
PoseGrowFactorTLSData *gftd = tls->userdata_chunk;
SculptSession *ss = data->ob->sculpt;
const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- const float *active_co = sculpt_active_vertex_co_get(ss);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SculptVertexNeighborIter ni;
float max = 0.0f;
+
+ /* Grow the factor. */
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
float vmask_f = data->prev_mask[ni.index];
- if (vmask_f > max) {
- max = vmask_f;
- }
+ max = MAX2(vmask_f, max);
}
sculpt_vertex_neighbors_iter_end(ni);
- if (max != data->prev_mask[vd.index]) {
+
+ /* Keep the count of the vertices that where added to the factors in this grow iteration. */
+ if (max > data->prev_mask[vd.index]) {
data->pose_factor[vd.index] = max;
- if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) {
+ if (check_vertex_pivot_symmetry(vd.co, data->pose_initial_co, symm)) {
add_v3_v3(gftd->pos_avg, vd.co);
gftd->pos_count++;
}
@@ -3665,9 +3854,16 @@ static void pose_brush_grow_factor_reduce(const void *__restrict UNUSED(userdata
join->pos_count += gftd->pos_count;
}
-/* Grow the factor until its boundary is near to the offset pose origin */
-static void sculpt_pose_grow_pose_factor(
- Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor)
+/* Grow the factor until its boundary is near to the offset pose origin or outside the target
+ * distance. */
+static void sculpt_pose_grow_pose_factor(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ float pose_origin[3],
+ float pose_target[3],
+ float max_len,
+ float *r_pose_origin,
+ float *pose_factor)
{
PBVHNode **nodes;
PBVH *pbvh = ob->sculpt->pbvh;
@@ -3681,6 +3877,8 @@ static void sculpt_pose_grow_pose_factor(
.totnode = totnode,
.pose_factor = pose_factor,
};
+
+ data.pose_initial_co = pose_target;
PBVHParallelSettings settings;
PoseGrowFactorTLSData gftd;
gftd.pos_count = 0;
@@ -3698,19 +3896,44 @@ static void sculpt_pose_grow_pose_factor(
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);
+
if (gftd.pos_count != 0) {
mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count);
- float len = len_v3v3(gftd.pos_avg, pose_origin);
- if (len < prev_len) {
- prev_len = len;
- grow_next_iteration = true;
+ if (pose_origin) {
+ /* Test with pose origin. Used when growing the factors to compensate the Origin Offset. */
+ /* Stop when the factor's avg_pos starts moving away from the origin instead of getting
+ * closer to it. */
+ float len = len_v3v3(gftd.pos_avg, pose_origin);
+ if (len < prev_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
}
else {
- grow_next_iteration = false;
- memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ /* Test with length. Used to calculate the origin positions of the IK chain. */
+ /* Stops when the factors have grown enough to generate a new segment origin. */
+ float len = len_v3v3(gftd.pos_avg, pose_target);
+ if (len < max_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ if (r_pose_origin) {
+ copy_v3_v3(r_pose_origin, gftd.pos_avg);
+ }
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
}
}
else {
+ if (r_pose_origin) {
+ copy_v3_v3(r_pose_origin, pose_target);
+ }
grow_next_iteration = false;
}
}
@@ -3736,10 +3959,6 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3
return false;
}
-/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
- *
- * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
- * be calculated. */
typedef struct PoseFloodFillData {
float pose_initial_co[3];
float radius;
@@ -3774,6 +3993,10 @@ static bool pose_floodfill_cb(
return false;
}
+/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
+ *
+ * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
+ * be calculated. */
void sculpt_pose_calc_pose_data(Sculpt *sd,
Object *ob,
SculptSession *ss,
@@ -3812,8 +4035,11 @@ void sculpt_pose_calc_pose_data(Sculpt *sd,
madd_v3_v3fl(fdata.pose_origin, pose_d, radius * pose_offset);
copy_v3_v3(r_pose_origin, fdata.pose_origin);
+ /* Do the initial grow of the factors to get the first segment of the chain with Origin Offset.
+ */
if (pose_offset != 0.0f && r_pose_factor) {
- sculpt_pose_grow_pose_factor(sd, ob, ss, fdata.pose_origin, r_pose_factor);
+ sculpt_pose_grow_pose_factor(
+ sd, ob, ss, fdata.pose_origin, fdata.pose_origin, 0, NULL, r_pose_factor);
}
}
@@ -3827,33 +4053,137 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SculptVertexNeighborIter ni;
- float avg = 0;
- int total = 0;
+ float avg = 0.0f;
+ int total = 0.0f;
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
- avg += ss->cache->pose_factor[ni.index];
+ avg += data->pose_factor[ni.index];
total++;
}
sculpt_vertex_neighbors_iter_end(ni);
if (total > 0) {
- ss->cache->pose_factor[vd.index] = avg / (float)total;
+ data->pose_factor[vd.index] = avg / total;
}
}
BKE_pbvh_vertex_iter_end;
}
-static void sculpt_pose_brush_init(
- Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius)
+void sculpt_pose_ik_chain_free(SculptPoseIKChain *ik_chain)
{
- float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
+ for (int i = 0; i < ik_chain->tot_segments; i++) {
+ MEM_SAFE_FREE(ik_chain->segments[i].weights);
+ }
+ MEM_SAFE_FREE(ik_chain->segments);
+ MEM_SAFE_FREE(ik_chain);
+}
- sculpt_pose_calc_pose_data(
- sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor);
+SculptPoseIKChain *sculpt_pose_ik_chain_init(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ Brush *br,
+ const float initial_location[3],
+ const float radius)
+{
+
+ float chain_end[3];
+ float chain_segment_len = len_v3v3(initial_location, chain_end) / br->pose_ik_segments;
+ chain_segment_len = radius * (1.0f + br->pose_offset);
+ float next_chain_segment_target[3];
+
+ int totvert = sculpt_vertex_count_get(ss);
+ int nearest_vertex_index = sculpt_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
+
+ /* Init the buffers used to keep track of the changes in the pose factors as more segments are
+ * added to the IK chain. */
+
+ /* This stores the whole pose factors values as they grow through the mesh. */
+ float *pose_factor_grow = MEM_callocN(totvert * sizeof(float), "Pose Factor Grow");
+
+ /* This stores the previous status of the factors when growing a new iteration. */
+ float *pose_factor_grow_prev = MEM_callocN(totvert * sizeof(float),
+ "Pose Factor Grow Prev Iteration");
+
+ 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");
+ }
+
+ /* 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);
+ sculpt_pose_calc_pose_data(sd,
+ ob,
+ ss,
+ next_chain_segment_target,
+ radius,
+ br->pose_offset,
+ ik_chain->segments[0].orig,
+ pose_factor_grow);
+
+ copy_v3_v3(next_chain_segment_target, ik_chain->segments[0].orig);
+
+ /* Init the weights of this segment and store the status of the pose factors to start calculating
+ * new segment origins. */
+ for (int j = 0; j < totvert; j++) {
+ ik_chain->segments[0].weights[j] = pose_factor_grow[j];
+ pose_factor_grow_prev[j] = pose_factor_grow[j];
+ }
+
+ /* Calculate the next segments in the chain growing the pose factors. */
+ for (int i = 1; i < ik_chain->tot_segments; i++) {
+
+ /* Grow the factors to get the new segment origin. */
+ sculpt_pose_grow_pose_factor(sd,
+ ob,
+ ss,
+ NULL,
+ next_chain_segment_target,
+ chain_segment_len,
+ ik_chain->segments[i].orig,
+ pose_factor_grow);
+ copy_v3_v3(next_chain_segment_target, ik_chain->segments[i].orig);
+
+ /* Create the weights for this segment from the difference between the previous grow factor
+ * iteration an the current iteration. */
+ for (int j = 0; j < totvert; j++) {
+ ik_chain->segments[i].weights[j] = pose_factor_grow[j] - pose_factor_grow_prev[j];
+ /* Store the current grow factor status for the next interation. */
+ pose_factor_grow_prev[j] = pose_factor_grow[j];
+ }
+ }
+
+ /* 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);
+ }
+ 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);
+ }
+
+ MEM_freeN(pose_factor_grow);
+ MEM_freeN(pose_factor_grow_prev);
- copy_v3_v3(ss->cache->pose_initial_co, initial_location);
- ss->cache->pose_factor = pose_factor;
+ return ik_chain;
+}
+static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
+{
PBVHNode **nodes;
PBVH *pbvh = ob->sculpt->pbvh;
int totnode;
@@ -3867,11 +4197,18 @@ static void sculpt_pose_brush_init(
.nodes = nodes,
};
- /* Smooth the pose brush factor for cleaner deformation */
- for (int i = 0; i < br->pose_smooth_iterations; i++) {
- PBVHParallelSettings 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);
+ /* Init the IK chain that is going to be used to deform the vertices. */
+ ss->cache->pose_ik_chain = sculpt_pose_ik_chain_init(
+ sd, ob, ss, br, ss->cache->true_location, ss->cache->radius);
+
+ /* Smooth the weights of each segment for cleaner deformation. */
+ 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;
+ 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);
+ }
}
MEM_SAFE_FREE(nodes);
@@ -5625,24 +5962,14 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Build a list of all nodes that are potentially within the brush's area of influence */
/* These brushes need to update all nodes as they are not constrained by the brush radius */
- if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ /* Elastic deform needs all nodes to avoid artifacts as the effect of the brush is not
+ * constrained by the radius */
+ /* Pose needs all nodes because it applies all symmetry iterations at the same time and the IK
+ * chain can grow to any area of the model. */
+ /* This can be optimized by filtering the nodes after calculating the chain. */
+ if (ELEM(brush->sculpt_tool, SCULPT_TOOL_ELASTIC_DEFORM, SCULPT_TOOL_POSE)) {
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
}
- else if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
- /* After smoothing the pose factor an arbitrary number of times, the pose factor values can
- * expand to nodes that are not inside the original radius of the brush. Using a slightly
- * bigger radius should prevent those artifacts. */
- /* We can optimize this further by removing the nodes that have all 0 values in the pose factor
- * after calculating it. */
- float final_radius = ss->cache->radius * 1.5f * (1.0f + brush->pose_offset);
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = final_radius * final_radius,
- .original = true,
- };
- BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
- }
else {
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
@@ -5686,7 +6013,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0) {
- sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
+ sculpt_pose_brush_init(sd, ob, ss, brush);
}
bool invert = ss->cache->pen_flip || ss->cache->invert || brush->flag & BRUSH_DIR_IN;
@@ -5769,8 +6096,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_ELASTIC_DEFORM:
do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
- case SCULPT_TOOL_TOPOLOGY:
- do_topology_brush(sd, ob, nodes, totnode);
+ case SCULPT_TOOL_SLIDE_RELAX:
+ do_slide_relax_brush(sd, ob, nodes, totnode);
break;
}
@@ -6285,8 +6612,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Pose Brush";
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
return "Multiplane Scrape Brush";
- case SCULPT_TOOL_TOPOLOGY:
- return "Topology Slide/Relax Brush";
+ case SCULPT_TOOL_SLIDE_RELAX:
+ return "Slide/Relax Brush";
}
return "Sculpting";
@@ -6301,8 +6628,8 @@ void sculpt_cache_free(StrokeCache *cache)
if (cache->dial) {
MEM_freeN(cache->dial);
}
- if (cache->pose_factor) {
- MEM_freeN(cache->pose_factor);
+ if (cache->pose_ik_chain) {
+ sculpt_pose_ik_chain_free(cache->pose_ik_chain);
}
MEM_freeN(cache);
}
@@ -6410,7 +6737,7 @@ static void sculpt_update_cache_invariants(
cache->saved_mask_brush_tool = brush->mask_tool;
brush->mask_tool = BRUSH_MASK_SMOOTH;
}
- else if (brush->sculpt_tool == SCULPT_TOOL_TOPOLOGY) {
+ else if (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) {
/* Do nothing, this tool has its own smooth mode */
}
else {
@@ -6790,7 +7117,7 @@ static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss
(brush->sculpt_tool == SCULPT_TOOL_SMOOTH) || (brush->autosmooth_factor > 0) ||
((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) ||
(brush->sculpt_tool == SCULPT_TOOL_POSE) ||
- (brush->sculpt_tool == SCULPT_TOOL_TOPOLOGY));
+ (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX));
}
static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
@@ -7212,9 +7539,7 @@ static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
ED_region_tag_redraw(ar);
}
else {
- /* Fast path where we just update the BVH nodes that changed, and redraw
- * only the part of the 3D viewport where changes happened. */
- rcti r;
+ /* Fast path where we just update the BVH nodes that changed. */
if (update_flags & SCULPT_UPDATE_COORDS) {
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
@@ -7224,21 +7549,7 @@ static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
sculpt_update_object_bounding_box(ob);
}
- if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
- if (ss->cache) {
- ss->cache->current_r = r;
- }
-
- /* previous is not set in the current cache else
- * the partial rect will always grow */
- sculpt_extend_redraw_rect_previous(ob, &r);
-
- r.xmin += ar->winrct.xmin - 2;
- r.xmax += ar->winrct.xmin + 2;
- r.ymin += ar->winrct.ymin - 2;
- r.ymax += ar->winrct.ymin + 2;
- ED_region_tag_redraw_partial(ar, &r, true);
- }
+ ED_region_tag_redraw(ar);
}
}
@@ -7251,7 +7562,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate
RegionView3D *rv3d = CTX_wm_region_view3d(C);
SculptSession *ss = ob->sculpt;
Mesh *mesh = ob->data;
- bool need_tag = (mesh->id.us > 1); /* Always needed for linked duplicates. */
+ bool need_tag = (ID_REAL_USERS(&mesh->id) > 1); /* Always needed for linked duplicates. */
if (rv3d) {
rv3d->rflag &= ~RV3D_PAINTING;
@@ -7438,7 +7749,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
brush->mask_tool = ss->cache->saved_mask_brush_tool;
}
- else if (brush->sculpt_tool == SCULPT_TOOL_TOPOLOGY) {
+ else if (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) {
/* Do nothing */
}
else {
@@ -8068,7 +8379,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
Mesh *mesh = ob->data;
Mesh *mesh_mirror;
- MirrorModifierData mmd = {0};
+ MirrorModifierData mmd = {{0}};
int axis = 0;
mmd.flag = 0;
mmd.tolerance = 0.005f;
@@ -8536,14 +8847,14 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *ar, int
}
}
-static void sample_detail(bContext *C, int mx, int my, int mode)
+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 *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
if (ar == NULL) {
- return;
+ return OPERATOR_CANCELLED;
}
/* Set context to 3D view. */
@@ -8556,12 +8867,29 @@ static void sample_detail(bContext *C, int mx, int my, int mode)
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, ar, 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;
}
@@ -8569,6 +8897,8 @@ static void sample_detail(bContext *C, int mx, int my, int mode)
/* 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)
@@ -8576,8 +8906,7 @@ 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");
- sample_detail(C, ss_co[0], ss_co[1], mode);
- return OPERATOR_FINISHED;
+ 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))
@@ -9985,79 +10314,6 @@ void ED_sculpt_init_transform(struct bContext *C)
sculpt_filter_cache_init(ob, sd);
}
-typedef enum PaintSymmetryAreas {
- AREA_SYMM_X = (1 << 0),
- AREA_SYMM_Y = (1 << 1),
- AREA_SYMM_Z = (1 << 2),
-} PaintSymmetryAreas;
-
-static char sculpt_get_vertex_symm_area(float co[3])
-{
- float vco[3];
- char symm_area = 0;
- copy_v3_v3(vco, co);
- if (vco[0] < 0) {
- symm_area |= AREA_SYMM_X;
- }
- if (vco[1] < 0) {
- symm_area |= AREA_SYMM_Y;
- }
- if (vco[2] < 0) {
- symm_area |= AREA_SYMM_Z;
- }
- return symm_area;
-}
-
-static void flip_qt(float qt[4], char symm)
-{
- float euler[3];
- if (symm & PAINT_SYMM_X) {
- quat_to_eul(euler, qt);
- euler[1] = -euler[1];
- euler[2] = -euler[2];
- eul_to_quat(qt, euler);
- }
- if (symm & PAINT_SYMM_Y) {
- quat_to_eul(euler, qt);
- euler[0] = -euler[0];
- euler[2] = -euler[2];
- eul_to_quat(qt, euler);
- }
- if (symm & PAINT_SYMM_Z) {
- quat_to_eul(euler, qt);
- euler[0] = -euler[0];
- euler[1] = -euler[1];
- eul_to_quat(qt, euler);
- }
-}
-
-static void sculpt_flip_transform_by_symm_area(
- float disp[3], float rot[4], char symm, char symmarea, float pivot[3])
-{
-
- for (char i = 0; i < 3; i++) {
- char symm_it = 1 << i;
- if (symm & symm_it) {
- if (symmarea & symm_it) {
- if (disp) {
- flip_v3(disp, symm_it);
- }
- if (rot) {
- flip_qt(rot, symm_it);
- }
- }
- if (pivot[0] < 0) {
- if (disp) {
- flip_v3(disp, symm_it);
- }
- if (rot) {
- flip_qt(rot, symm_it);
- }
- }
- }
- }
-}
-
static void sculpt_transform_task_cb(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -10119,7 +10375,9 @@ void ED_sculpt_update_modal_transform(struct bContext *C)
transform_mat[4][4];
copy_v3_v3(final_pivot_pos, ss->pivot_pos);
- for (int i = 0; i < 8; i++) {
+ 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);
@@ -10130,20 +10388,20 @@ void ED_sculpt_update_modal_transform(struct bContext *C)
/* Translation matrix */
sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
- sculpt_flip_transform_by_symm_area(d_t, NULL, symm, (char)i, 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_transform_by_symm_area(NULL, d_r, symm, (char)i, ss->init_pivot_pos);
+ 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_transform_by_symm_area(final_pivot_pos, NULL, symm, (char)i, ss->init_pivot_pos);
+ 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);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index e9ad31d6f25..5d92b202997 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -37,6 +37,7 @@ struct KeyBlock;
struct Object;
struct SculptUndoNode;
struct bContext;
+struct SculptPoseIKChainSegment;
bool sculpt_mode_poll(struct bContext *C);
bool sculpt_mode_poll_view3d(struct bContext *C);
@@ -74,6 +75,15 @@ void sculpt_pose_calc_pose_data(struct Sculpt *sd,
float *r_pose_origin,
float *r_pose_factor);
+struct SculptPoseIKChain *sculpt_pose_ik_chain_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br,
+ const float initial_location[3],
+ const float radius);
+
+void sculpt_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
+
/* Sculpt PBVH abstraction API */
const float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
@@ -201,10 +211,9 @@ typedef struct SculptThreadedTaskData {
float *prev_mask;
- float *pose_origin;
- float *pose_initial_co;
float *pose_factor;
- float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4];
+ float *pose_initial_co;
+ int pose_chain_segment;
float multiplane_scrape_angle;
float multiplane_scrape_planes[2][4];
@@ -250,7 +259,7 @@ typedef struct {
struct Sculpt *sd;
struct SculptSession *ss;
float radius_squared;
- float *center;
+ const float *center;
bool original;
bool ignore_fully_masked;
} SculptSearchSphereData;
@@ -379,9 +388,7 @@ typedef struct StrokeCache {
float anchored_location[3];
/* Pose brush */
- float *pose_factor;
- float pose_initial_co[3];
- float pose_origin[3];
+ struct SculptPoseIKChain *pose_ik_chain;
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index fec3bd88f0b..366eeae219c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -498,7 +498,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
SculptUndoNode *unode;
- bool update = false, rebuild = false, update_mask = false;
+ bool update = false, rebuild = false, update_mask = false, update_visibility = false;
bool need_mask = false;
for (unode = lb->first; unode; unode = unode->next) {
@@ -575,6 +575,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_HIDDEN:
if (sculpt_undo_restore_hidden(C, unode)) {
rebuild = true;
+ update_visibility = true;
}
break;
case SCULPT_UNDO_MASK:
@@ -631,7 +632,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
- tag_update |= ((Mesh *)ob->data)->id.us > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d);
+ tag_update |= ID_REAL_USERS(ob->data) > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d);
if (ss->shapekey_active || ss->deform_modifiers_active) {
Mesh *mesh = ob->data;
@@ -641,6 +642,11 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
tag_update |= true;
}
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && update_visibility) {
+ Mesh *mesh = ob->data;
+ BKE_mesh_flush_hidden_from_verts(mesh);
+ }
+
if (tag_update) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 8fbaf3396bd..5beaff5ef00 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -521,18 +521,18 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
/* We will need island information */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true, true);
+ data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, true);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, true, true);
+ data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, true);
}
}
else {
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true, false);
+ data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, false);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, true, false);
+ data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, false);
}
}
@@ -807,6 +807,23 @@ static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
+static bool uv_sculpt_stroke_poll(bContext *C)
+{
+ if (ED_operator_uvedit_space_image(C)) {
+ /* While these values could be initialized on demand,
+ * the only case this would be useful is running from the operator search popup.
+ * This is such a corner case that it's simpler to check a brush has already been created
+ * (something the tool system ensures). */
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&ts->uvsculpt->paint);
+ if (brush != NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
{
static const EnumPropertyItem stroke_mode_items[] = {
@@ -832,7 +849,7 @@ void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
/* api callbacks */
ot->invoke = uv_sculpt_stroke_invoke;
ot->modal = uv_sculpt_stroke_modal;
- ot->poll = ED_operator_uvedit_space_image;
+ ot->poll = uv_sculpt_stroke_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/sound/CMakeLists.txt b/source/blender/editors/sound/CMakeLists.txt
index 7f4b5a45aa3..b4099edce68 100644
--- a/source/blender/editors/sound/CMakeLists.txt
+++ b/source/blender/editors/sound/CMakeLists.txt
@@ -47,6 +47,9 @@ if(WITH_AUDASPACE)
)
list(APPEND LIB
bf_intern_audaspace
+
+ ${AUDASPACE_C_LIBRARIES}
+ ${AUDASPACE_PY_LIBRARIES}
)
add_definitions(-DWITH_AUDASPACE)
endif()
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 5ceaefd6309..5fdabea62c1 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -211,12 +211,13 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
PointerRNA ptr, idptr;
PropertyRNA *prop;
+ bAction *oldact = NULL;
+ AnimData *adt = NULL;
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
- bAction *action = NULL, *oldact = NULL;
- AnimData *adt = NULL;
+ /* The operator was called from a button. */
PointerRNA oldptr;
oldptr = RNA_property_pointer_get(&ptr, prop);
@@ -229,6 +230,13 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
adt = ED_actedit_animdata_from_context(C);
}
+ }
+ else {
+ adt = ED_actedit_animdata_from_context(C);
+ oldact = adt->action;
+ }
+ {
+ bAction *action = NULL;
/* Perform stashing operation - But only if there is an action */
if (adt && oldact) {
@@ -257,12 +265,14 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
/* create action */
action = action_create_new(C, oldact);
- /* set this new action
- * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
- */
- RNA_id_pointer_create(&action->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
- RNA_property_update(C, &ptr, prop);
+ if (prop) {
+ /* set this new action
+ * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
+ */
+ RNA_id_pointer_create(&action->id, &idptr);
+ RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_update(C, &ptr, prop);
+ }
}
/* set notifier that keyframes have changed */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 5eac041b217..6e44992ea6e 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -488,9 +488,9 @@ static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
void ACTION_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Frame";
+ ot->name = "Go to Current Frame";
ot->idname = "ACTION_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
+ ot->description = "Move the view to the playhead";
/* 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 ca6efb5f69e..09a0c297d35 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1718,7 +1718,7 @@ static int mouse_action_keys(bAnimContext *ac,
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
- if (wait_to_deselect_others && is_selected) {
+ if (wait_to_deselect_others) {
ret_value = OPERATOR_RUNNING_MODAL;
}
else {
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index d78ff8eb5d4..46a62b6f0a8 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -137,7 +137,6 @@ void ED_spacetypes_init(void)
ED_gizmotypes_button_2d();
ED_gizmotypes_dial_3d();
ED_gizmotypes_move_3d();
- ED_gizmotypes_arrow_2d();
ED_gizmotypes_arrow_3d();
ED_gizmotypes_preselect_3d();
ED_gizmotypes_primitive_3d();
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index a404b6e8f19..dd4b38e5b3f 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -443,6 +443,8 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
buttons_area_redraw(sa, BCONTEXT_OBJECT);
buttons_area_redraw(sa, BCONTEXT_DATA);
buttons_area_redraw(sa, BCONTEXT_PHYSICS);
+ /* Needed to refresh context path when changing active particle system index. */
+ buttons_area_redraw(sa, BCONTEXT_PARTICLE);
break;
case ND_SHADING:
case ND_SHADING_DRAW:
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 4a4b85cbf8f..3ede0158f7a 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -374,7 +374,7 @@ void CLIP_OT_reload(wmOperatorType *ot)
typedef struct ViewPanData {
float x, y;
float xof, yof, xorig, yorig;
- int event_type;
+ int launch_event;
bool own_cursor;
float *vec;
} ViewPanData;
@@ -406,7 +406,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
copy_v2_v2(&vpd->xof, vpd->vec);
copy_v2_v2(&vpd->xorig, &vpd->xof);
- vpd->event_type = event->type;
+ vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
WM_event_add_modal_handler(C, op);
}
@@ -493,7 +493,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
default:
- if (event->type == vpd->event_type && event->val == KM_RELEASE) {
+ if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
view_pan_exit(C, op, 0);
return OPERATOR_FINISHED;
@@ -548,7 +548,7 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
typedef struct ViewZoomData {
float x, y;
float zoom;
- int event_type;
+ int launch_event;
float location[2];
wmTimer *timer;
double timer_lastdraw;
@@ -579,7 +579,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
vpd->x = event->x;
vpd->y = event->y;
vpd->zoom = sc->zoom;
- vpd->event_type = event->type;
+ vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
ED_clip_mouse_pos(sc, ar, event->mval, vpd->location);
@@ -697,7 +697,7 @@ static int view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
view_zoom_apply(C, vpd, op, event, use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS));
break;
default:
- if (event->type == vpd->event_type && event->val == KM_RELEASE) {
+ if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
view_zoom_exit(C, op, 0);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 16305a9b17b..04c939ec41b 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -1083,11 +1083,7 @@ static void graph_region_draw(const bContext *C, ARegion *ar)
/* scale indicators */
{
rcti rect;
- BLI_rcti_init(&rect,
- 0,
- 15 * UI_DPI_FAC,
- 15 * UI_DPI_FAC,
- UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y);
UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT);
}
}
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
index 7d2324d3f48..03fe1c74e2a 100644
--- a/source/blender/editors/space_clip/tracking_ops_plane.c
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -98,7 +98,7 @@ void CLIP_OT_create_plane_track(wmOperatorType *ot)
/********************** Slide plane marker corner operator *********************/
typedef struct SlidePlaneMarkerData {
- int event_type;
+ int launch_event;
MovieTrackingPlaneTrack *plane_track;
MovieTrackingPlaneMarker *plane_marker;
int width, height;
@@ -195,7 +195,7 @@ static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event)
customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data");
- customdata->event_type = event->type;
+ customdata->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
@@ -345,7 +345,7 @@ static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent *
case LEFTMOUSE:
case RIGHTMOUSE:
- if (event->type == data->event_type && event->val == KM_RELEASE) {
+ if (event->type == data->launch_event && event->val == KM_RELEASE) {
/* Marker is now keyframed. */
data->plane_marker->flag &= ~PLANE_MARKER_TRACKED;
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index bf6683ffc33..c9dde11cbeb 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -42,22 +42,33 @@
#include "../space_info/textview.h"
-static void console_line_color(unsigned char fg[3], int type)
+static int console_line_data(struct TextViewContext *tvc,
+ unsigned char fg[4],
+ unsigned char UNUSED(bg[4]),
+ int *UNUSED(icon),
+ unsigned char UNUSED(icon_fg[4]),
+ unsigned char UNUSED(icon_bg[4]))
{
- switch (type) {
+ ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter;
+ int fg_id = TH_TEXT;
+
+ switch (cl_iter->type) {
case CONSOLE_LINE_OUTPUT:
- UI_GetThemeColor3ubv(TH_CONSOLE_OUTPUT, fg);
+ fg_id = TH_CONSOLE_OUTPUT;
break;
case CONSOLE_LINE_INPUT:
- UI_GetThemeColor3ubv(TH_CONSOLE_INPUT, fg);
+ fg_id = TH_CONSOLE_INPUT;
break;
case CONSOLE_LINE_INFO:
- UI_GetThemeColor3ubv(TH_CONSOLE_INFO, fg);
+ fg_id = TH_CONSOLE_INFO;
break;
case CONSOLE_LINE_ERROR:
- UI_GetThemeColor3ubv(TH_CONSOLE_ERROR, fg);
+ fg_id = TH_CONSOLE_ERROR;
break;
}
+
+ UI_GetThemeColor4ubv(fg_id, fg);
+ return TVC_LINE_FG;
}
void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy)
@@ -137,47 +148,36 @@ static void console_cursor_wrap_offset(
return;
}
-static int console_textview_line_color(struct TextViewContext *tvc,
- unsigned char fg[3],
- unsigned char UNUSED(bg[3]))
+static void console_textview_draw_cursor(struct TextViewContext *tvc)
{
- ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter;
-
- /* annoying hack, to draw the prompt */
- if (tvc->iter_index == 0) {
- const SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
- const ConsoleLine *cl = (ConsoleLine *)sc->history.last;
- int offl = 0, offc = 0;
- int xy[2] = {tvc->draw_rect.xmin, tvc->draw_rect.ymin};
- int pen[2];
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- xy[1] += tvc->lheight / 6;
-
- console_cursor_wrap_offset(sc->prompt, tvc->columns, &offl, &offc, NULL);
- console_cursor_wrap_offset(cl->line, tvc->columns, &offl, &offc, cl->line + cl->cursor);
- pen[0] = tvc->cwidth * offc;
- pen[1] = -2 - tvc->lheight * offl;
-
- console_cursor_wrap_offset(cl->line + cl->cursor, tvc->columns, &offl, &offc, NULL);
- pen[1] += tvc->lheight * offl;
-
- /* cursor */
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColor(TH_CONSOLE_CURSOR);
-
- immRectf(pos,
- (xy[0] + pen[0]) - U.pixelsize,
- (xy[1] + pen[1]),
- (xy[0] + pen[0]) + U.pixelsize,
- (xy[1] + pen[1] + tvc->lheight));
-
- immUnbindProgram();
- }
-
- console_line_color(fg, cl_iter->type);
-
- return TVC_LINE_FG;
+ const SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
+ const ConsoleLine *cl = (ConsoleLine *)sc->history.last;
+ int offl = 0, offc = 0;
+ int xy[2] = {tvc->draw_rect.xmin, tvc->draw_rect.ymin};
+ int pen[2];
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ xy[1] += tvc->lheight * 0.35f;
+
+ console_cursor_wrap_offset(sc->prompt, tvc->columns, &offl, &offc, NULL);
+ console_cursor_wrap_offset(cl->line, tvc->columns, &offl, &offc, cl->line + cl->cursor);
+ pen[0] = tvc->cwidth * (offc + tvc->margin_left_chars);
+ pen[1] = -2 - tvc->lheight * offl;
+
+ console_cursor_wrap_offset(cl->line + cl->cursor, tvc->columns, &offl, &offc, NULL);
+ pen[1] += tvc->lheight * offl;
+
+ /* cursor */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_CONSOLE_CURSOR);
+
+ immRectf(pos,
+ (xy[0] + pen[0]) - U.pixelsize,
+ (xy[1] + pen[1]),
+ (xy[0] + pen[0]) + U.pixelsize,
+ (xy[1] + pen[1] + tvc->lheight));
+
+ immUnbindProgram();
}
static void console_textview_const_colors(TextViewContext *UNUSED(tvc), unsigned char bg_sel[4])
@@ -187,11 +187,9 @@ static void console_textview_const_colors(TextViewContext *UNUSED(tvc), unsigned
static void console_textview_draw_rect_calc(const ARegion *ar, rcti *draw_rect)
{
- const int margin = 4 * UI_DPI_FAC;
- draw_rect->xmin = margin;
- draw_rect->xmax = ar->winx - (margin + V2D_SCROLL_WIDTH);
- draw_rect->ymin = margin;
- /* No margin at the top (allow text to scroll off the window). */
+ draw_rect->xmin = 0;
+ draw_rect->xmax = ar->winx;
+ draw_rect->ymin = 0;
draw_rect->ymax = ar->winy;
}
@@ -214,7 +212,8 @@ static int console_textview_main__internal(struct SpaceConsole *sc,
tvc.step = console_textview_step;
tvc.line_get = console_textview_line_get;
- tvc.line_color = console_textview_line_color;
+ tvc.line_data = console_line_data;
+ tvc.draw_cursor = console_textview_draw_cursor;
tvc.const_colors = console_textview_const_colors;
tvc.arg1 = sc;
@@ -223,7 +222,9 @@ static int console_textview_main__internal(struct SpaceConsole *sc,
/* view */
tvc.sel_start = sc->sel_start;
tvc.sel_end = sc->sel_end;
- tvc.lheight = sc->lheight * UI_DPI_FAC;
+ tvc.lheight = sc->lheight * 1.2f * UI_DPI_FAC;
+ tvc.margin_left_chars = 1;
+ tvc.margin_right_chars = 2;
tvc.scroll_ymin = v2d->cur.ymin;
tvc.scroll_ymax = v2d->cur.ymax;
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 77e6266b830..61eb4db8300 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -322,7 +322,7 @@ static FileSelect file_select(
if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
sfile->params->active_file = -1;
}
- else {
+ else if (sel.last >= 0) {
ARegion *ar = CTX_wm_region(C);
const FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index a567aeed826..fa904e0934b 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -947,15 +947,13 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
return filelist_geticon_image_ex(file->typeflag, file->relpath);
}
-static int filelist_geticon_ex(const int typeflag,
- const int blentype,
- const char *relpath,
- const bool is_main,
- const bool ignore_libdir)
+static int filelist_geticon_ex(FileDirEntry *file, const char *root, const bool is_main, const bool ignore_libdir)
{
+ const int typeflag = file->typeflag;
+
if ((typeflag & FILE_TYPE_DIR) &&
!(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) {
- if (FILENAME_IS_PARENT(relpath)) {
+ if (FILENAME_IS_PARENT(file->relpath)) {
return is_main ? ICON_FILE_PARENT : ICON_NONE;
}
else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) {
@@ -969,6 +967,20 @@ static int filelist_geticon_ex(const int typeflag,
* (e.g. when used over previews). */
return ICON_FILE_FOLDER;
}
+ else {
+ /* If this path is in System list then use that icon. */
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS);
+ char fullpath[FILE_MAX_LIBEXTRA];
+ BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
+ BLI_add_slash(fullpath);
+ for (; tfsm; tfsm = tfsm->next) {
+ if (STREQ(tfsm->path, fullpath)) {
+ /* Never want a little folder inside a large one. */
+ return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
+ }
+ }
+ }
}
if (typeflag & FILE_TYPE_BLENDER) {
@@ -1014,7 +1026,7 @@ static int filelist_geticon_ex(const int typeflag,
return ICON_FILE_ARCHIVE;
}
else if (typeflag & FILE_TYPE_BLENDERLIB) {
- const int ret = UI_idcode_icon_get(blentype);
+ const int ret = UI_idcode_icon_get(file->blentype);
if (ret != ICON_NONE) {
return ret;
}
@@ -1026,7 +1038,7 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
{
FileDirEntry *file = filelist_geticon_get_file(filelist, index);
- return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false);
+ return filelist_geticon_ex(file, filelist->filelist.root, is_main, false);
}
/* ********** Main ********** */
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index f9506da39a8..eaabd907f23 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -31,6 +31,8 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
+#include "BLT_translation.h"
+
#include "BKE_appdir.h"
#include "ED_fileselect.h"
@@ -270,7 +272,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
FSMenuCategory category,
const char *path,
const char *name,
- const int icon,
+ int icon,
FSMenuInsert flag)
{
FSMenuEntry *fsm_prev;
@@ -311,19 +313,22 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
fsm_iter->path = BLI_strdup(path);
fsm_iter->save = (flag & FS_INSERT_SAVE) != 0;
- if ((category == FS_CATEGORY_RECENT) && (!name || !name[0])) {
- /* Special handling when adding new recent entry - check if dir exists in
- * some other categories, and try to use name from there if so. */
+ /* If entry is also in another list, use that icon and maybe name. */
+ if (ELEM(category, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT)) {
+
FSMenuCategory cats[] = {
FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS};
int i = ARRAY_SIZE(cats);
+ if (category == FS_CATEGORY_BOOKMARKS) {
+ i--;
+ }
while (i--) {
FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]);
-
for (; tfsm; tfsm = tfsm->next) {
if (STREQ(tfsm->path, fsm_iter->path)) {
- if (tfsm->name[0]) {
+ icon = tfsm->icon;
+ if (tfsm->name[0] && (!name || !name[0])) {
name = tfsm->name;
}
break;
@@ -485,6 +490,25 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
fclose(fp);
}
+#ifdef WIN32
+/* Add a Windows known folder path to the System list. */
+static void fsmenu_add_windows_folder(struct FSMenu *fsmenu,
+ REFKNOWNFOLDERID rfid,
+ const char *name,
+ const int icon,
+ FSMenuInsert flag)
+{
+ LPWSTR pPath;
+ char line[FILE_MAXDIR];
+ if (SHGetKnownFolderPath(rfid, 0, NULL, &pPath) == S_OK) {
+ BLI_strncpy_wchar_as_utf8(line, pPath, FILE_MAXDIR);
+ CoTaskMemFree(pPath);
+ BLI_add_slash(line);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, name, icon, flag);
+ }
+}
+#endif
+
void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
{
char line[FILE_MAXDIR];
@@ -541,16 +565,24 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
}
}
- /* Adding Desktop and My Documents */
+ /* Get Special Folder Locations. */
if (read_bookmarks) {
- SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0);
- BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR);
- fsmenu_insert_entry(
- fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DOCUMENTS, FS_INSERT_SORTED);
- SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0);
- BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR);
- fsmenu_insert_entry(
- fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DESKTOP, FS_INSERT_SORTED);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Profile, IFACE_("Home"), ICON_HOME, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Desktop, IFACE_("Desktop"), ICON_DESKTOP, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Documents, IFACE_("Documents"), ICON_DOCUMENTS, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Downloads, IFACE_("Downloads"), ICON_IMPORT, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Music, IFACE_("Music"), ICON_FILE_SOUND, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Pictures, IFACE_("Pictures"), ICON_FILE_IMAGE, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Videos, IFACE_("Videos"), ICON_FILE_MOVIE, FS_INSERT_LAST);
+ fsmenu_add_windows_folder(
+ fsmenu, &FOLDERID_Fonts, IFACE_("Fonts"), ICON_FONTPREVIEW, FS_INSERT_LAST);
}
}
#else
@@ -578,11 +610,41 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX);
+ /* Get name of the volume. */
+ char name[FILE_MAXFILE] = "";
+ CFStringRef nameString = NULL;
+ CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeLocalizedNameKey, &nameString, NULL);
+ if (nameString != NULL) {
+ CFStringGetCString(nameString, name, sizeof(name), kCFStringEncodingUTF8);
+ CFRelease(nameString);
+ }
+
+ /* Set icon for regular, removable or network drive. */
+ int icon = ICON_DISK_DRIVE;
+ CFBooleanRef localKey = NULL;
+ CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeIsLocalKey, &localKey, NULL);
+ if (localKey != NULL) {
+ if (!CFBooleanGetValue(localKey)) {
+ icon = ICON_NETWORK_DRIVE;
+ }
+ else {
+ CFBooleanRef ejectableKey = NULL;
+ CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeIsEjectableKey, &ejectableKey, NULL);
+ if (ejectableKey != NULL) {
+ if (CFBooleanGetValue(ejectableKey)) {
+ icon = ICON_EXTERNAL_DRIVE;
+ }
+ CFRelease(ejectableKey);
+ }
+ }
+ CFRelease(localKey);
+ }
+
/* Add end slash for consistency with other platforms */
BLI_add_slash(defPath);
fsmenu_insert_entry(
- fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
+ fsmenu, FS_CATEGORY_SYSTEM, defPath, name[0] ? name : NULL, icon, FS_INSERT_SORTED);
}
CFRelease(volEnum);
@@ -616,12 +678,12 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
}
- /* Add end slash for consistency with other platforms */
- BLI_add_slash(line);
-
/* Exclude "all my files" as it makes no sense in blender fileselector */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
+ /* Add end slash for consistency with other platforms */
+ BLI_add_slash(line);
+
fsmenu_insert_entry(
fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_FILE_FOLDER, FS_INSERT_LAST);
}
@@ -640,13 +702,75 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
const char *home = BLI_getenv("HOME");
if (read_bookmarks && home) {
+
BLI_snprintf(line, sizeof(line), "%s/", home);
- fsmenu_insert_entry(
- fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_HOME, FS_INSERT_SORTED);
- BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
if (BLI_exists(line)) {
fsmenu_insert_entry(
- fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_DESKTOP, FS_INSERT_SORTED);
+ fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, IFACE_("Home"), ICON_HOME, FS_INSERT_LAST);
+ }
+
+ /* Follow the XDG spec, check if these are available. */
+
+ /* TODO: parse "$XDG_CONFIG_HOME/user-dirs.dirs" for localized paths. */
+
+ BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
+ if (BLI_exists(line)) {
+ fsmenu_insert_entry(fsmenu,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ line,
+ IFACE_("Desktop"),
+ ICON_DESKTOP,
+ FS_INSERT_LAST);
+ }
+
+ BLI_snprintf(line, sizeof(line), "%s/Documents/", home);
+ if (BLI_exists(line)) {
+ fsmenu_insert_entry(fsmenu,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ line,
+ IFACE_("Documents"),
+ ICON_DOCUMENTS,
+ FS_INSERT_LAST);
+ }
+
+ BLI_snprintf(line, sizeof(line), "%s/Downloads/", home);
+ if (BLI_exists(line)) {
+ fsmenu_insert_entry(fsmenu,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ line,
+ IFACE_("Downloads"),
+ ICON_IMPORT,
+ FS_INSERT_LAST);
+ }
+
+ BLI_snprintf(line, sizeof(line), "%s/Videos/", home);
+ if (BLI_exists(line)) {
+ fsmenu_insert_entry(fsmenu,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ line,
+ IFACE_("Videos"),
+ ICON_FILE_MOVIE,
+ FS_INSERT_LAST);
+ }
+
+ BLI_snprintf(line, sizeof(line), "%s/Pictures/", home);
+ if (BLI_exists(line)) {
+ fsmenu_insert_entry(fsmenu,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ line,
+ IFACE_("Pictures"),
+ ICON_FILE_IMAGE,
+ FS_INSERT_LAST);
+ }
+
+ BLI_snprintf(line, sizeof(line), "%s/Music/", home);
+ if (BLI_exists(line)) {
+ fsmenu_insert_entry(fsmenu,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ line,
+ IFACE_("Music"),
+ ICON_FILE_SOUND,
+ FS_INSERT_LAST);
}
}
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index a33783b1905..17cfdf1c7f0 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -42,7 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
enum FSMenuCategory category,
const char *path,
const char *name,
- const int icon,
+ int icon,
const enum FSMenuInsert flag);
/** Refresh 'valid' status of given menu entry */
diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt
index f4d31886e3f..8170c920990 100644
--- a/source/blender/editors/space_graph/CMakeLists.txt
+++ b/source/blender/editors/space_graph/CMakeLists.txt
@@ -56,6 +56,9 @@ if(WITH_AUDASPACE)
)
list(APPEND LIB
bf_intern_audaspace
+
+ ${AUDASPACE_C_LIBRARIES}
+ ${AUDASPACE_PY_LIBRARIES}
)
add_definitions(-DWITH_AUDASPACE)
endif()
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 6c95e74e834..0a3663372be 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -156,7 +156,7 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
FCurve *fcu;
PointerRNA fcu_ptr;
uiLayout *layout = pa->layout;
- uiLayout *col, *row, *sub;
+ uiLayout *col;
char name[256];
int icon = 0;
@@ -193,27 +193,26 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
}
uiItemL(col, name, icon);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
/* RNA-Path Editing - only really should be enabled when things aren't working */
- col = uiLayoutColumn(layout, true);
+ col = uiLayoutColumn(layout, false);
uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED) != 0);
uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE);
/* color settings */
col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Display Color:"), ICON_NONE);
+ uiItemR(col, &fcu_ptr, "color_mode", 0, "Display Color", ICON_NONE);
- row = uiLayoutRow(col, true);
- uiItemR(row, &fcu_ptr, "color_mode", 0, "", ICON_NONE);
-
- sub = uiLayoutRow(row, true);
- uiLayoutSetEnabled(sub, (fcu->color_mode == FCURVE_COLOR_CUSTOM));
- uiItemR(sub, &fcu_ptr, "color", 0, "", ICON_NONE);
+ if (fcu->color_mode == FCURVE_COLOR_CUSTOM) {
+ uiItemR(col, &fcu_ptr, "color", 0, "Color", ICON_NONE);
+ }
/* smoothing setting */
col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Auto Handle Smoothing:"), ICON_NONE);
- uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "", ICON_NONE);
+ uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "Handle Smoothing", ICON_NONE);
MEM_freeN(ale);
}
@@ -339,6 +338,9 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
BezTriple *bezt, *prevbezt;
uiLayout *layout = pa->layout;
+ const ARegion *ar = 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 = ar->winx;
uiLayout *col;
uiBlock *block;
@@ -348,6 +350,8 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
block = uiLayoutGetBlock(layout);
/* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* only show this info if there are keyframes to edit */
if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
@@ -404,57 +408,60 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
col = uiLayoutColumn(layout, true);
/* keyframe itself */
{
- uiItemL(col, IFACE_("Key:"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- IFACE_("Frame:"),
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
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);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- IFACE_("Value:"),
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
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);
}
/* previous handle - only if previous was Bezier interpolation */
if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
- uiItemL(col, IFACE_("Left Handle:"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "X:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_left",
@@ -466,13 +473,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);
+ uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "Y:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_left",
@@ -485,14 +493,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
- /* XXX: with label? */
+ uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
NULL,
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_left_type",
@@ -508,15 +516,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
/* 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(col, IFACE_("Right Handle:"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "X:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_right",
@@ -528,13 +537,14 @@ 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);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
- "Y:",
+ "",
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_right",
@@ -547,14 +557,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
- /* XXX: with label? */
+ uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
NULL,
0,
0,
- UI_UNIT_X,
+ but_max_width,
UI_UNIT_Y,
&bezt_ptr,
"handle_right_type",
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 03df93e4c8a..2060288bb0e 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -292,13 +292,12 @@ static int graphkeys_viewall(bContext *C,
/* Give some more space at the borders. */
BLI_rctf_scale(&cur_new, 1.1f);
- /* Take regions into account, that could block the view. */
+ /* Take regions into account, that could block the view.
+ * Marker region is supposed to be larger than the scroll-bar, so prioritize it.*/
float pad_top = UI_TIME_SCRUB_MARGIN_Y;
- float pad_bottom = 0;
- if (!BLI_listbase_is_empty(ED_context_get_markers(C))) {
- pad_bottom = UI_MARKER_MARGIN_Y;
- }
- BLI_rctf_pad_y(&cur_new, ac.ar->sizey * UI_DPI_FAC, pad_bottom, pad_top);
+ float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ? V2D_SCROLL_HANDLE_HEIGHT :
+ UI_MARKER_MARGIN_Y;
+ BLI_rctf_pad_y(&cur_new, ac.ar->winy, pad_bottom, pad_top);
UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx);
return OPERATOR_FINISHED;
@@ -384,9 +383,9 @@ static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
void GRAPH_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Frame";
+ ot->name = "Go to Current Frame";
ot->idname = "GRAPH_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
+ ot->description = "Move the view to the playhead";
/* api callbacks */
ot->exec = graphkeys_view_frame_exec;
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 7bc907bb3db..d01e4112fd0 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -326,11 +326,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
/* scale numbers */
{
rcti rect;
- BLI_rcti_init(&rect,
- 0,
- 15 * UI_DPI_FAC,
- 15 * UI_DPI_FAC,
- UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y);
UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_SCROLL_TEXT);
}
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 9b091979f1e..17c6f76a1d9 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -305,7 +305,7 @@ static bool image_sample_poll(bContext *C)
typedef struct ViewPanData {
float x, y;
float xof, yof;
- int event_type;
+ int launch_event;
bool own_cursor;
} ViewPanData;
@@ -327,7 +327,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even
vpd->y = event->y;
vpd->xof = sima->xof;
vpd->yof = sima->yof;
- vpd->event_type = event->type;
+ vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
WM_event_add_modal_handler(C, op);
}
@@ -398,7 +398,7 @@ static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *even
image_view_pan_exec(C, op);
break;
default:
- if (event->type == vpd->event_type && event->val == KM_RELEASE) {
+ if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
image_view_pan_exit(C, op, false);
return OPERATOR_FINISHED;
}
@@ -452,7 +452,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
typedef struct ViewZoomData {
float origx, origy;
float zoom;
- int event_type;
+ int launch_event;
float location[2];
/* needed for continuous zoom */
@@ -483,7 +483,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve
vpd->origx = event->x;
vpd->origy = event->y;
vpd->zoom = sima->zoom;
- vpd->event_type = event->type;
+ vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
UI_view2d_region_to_view(
&ar->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
@@ -633,7 +633,7 @@ static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *eve
else if (event->type == MOUSEMOVE) {
event_code = VIEW_APPLY;
}
- else if (event->type == vpd->event_type && event->val == KM_RELEASE) {
+ else if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
@@ -1318,7 +1318,9 @@ static int image_get_udim(char *filepath, LinkNodePair *udim_tiles)
BLI_filelist_free(dir, totfile);
if (is_udim && has_primary) {
- BLI_stringenc_path(filepath, dirname, base_head, base_tail, digits, 1001);
+ char primary_filename[FILE_MAX];
+ BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001);
+ BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
return max_udim - 1000;
}
return 0;
@@ -3354,6 +3356,9 @@ static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
{
+ if (sima->image == NULL) {
+ return false;
+ }
float uv[2];
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &uv[0], &uv[1]);
int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
@@ -4277,6 +4282,33 @@ static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
uiItemR(col[1], ptr, "float", 0, NULL, ICON_NONE);
}
+static void initialize_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
+{
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ if (tile != NULL) {
+ iuser.tile = tile->tile_number;
+ }
+
+ /* Acquire ibuf to get the default values.
+ * If the specified tile has no ibuf, try acquiring the main tile instead
+ * (unless the specified tile already was the main tile).*/
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL && (tile != NULL) && (tile->tile_number != 1001)) {
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ }
+
+ if (ibuf != NULL) {
+ /* Initialize properties from reference tile. */
+ RNA_int_set(ptr, "width", ibuf->x);
+ RNA_int_set(ptr, "height", ibuf->y);
+ RNA_boolean_set(ptr, "float", ibuf->rect_float != NULL);
+ RNA_boolean_set(ptr, "alpha", ibuf->planes > 24);
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+}
+
static void def_fill_tile(StructOrFunctionRNA *srna)
{
PropertyRNA *prop;
@@ -4356,6 +4388,9 @@ static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev
}
}
+ ImageTile *tile = BLI_findlink(&ima->tiles, ima->active_tile_index);
+ initialize_fill_tile(op->ptr, ima, tile);
+
RNA_int_set(op->ptr, "number", next_number);
RNA_int_set(op->ptr, "count", 1);
RNA_string_set(op->ptr, "label", "");
@@ -4485,17 +4520,7 @@ static int tile_fill_exec(bContext *C, wmOperator *op)
static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Image *ima = CTX_data_edit_image(C);
-
- /* Acquire first tile to get the defaults. */
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf != NULL) {
- RNA_int_set(op->ptr, "width", ibuf->x);
- RNA_int_set(op->ptr, "height", ibuf->y);
- RNA_boolean_set(op->ptr, "float", ibuf->rect_float != NULL);
- RNA_boolean_set(op->ptr, "alpha", ibuf->planes > 24);
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
+ initialize_fill_tile(op->ptr, CTX_data_edit_image(C), NULL);
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 2f93be8ae38..57560c560d7 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -470,11 +470,7 @@ static void IMAGE_GGT_gizmo2d(wmGizmoGroupType *gzgt)
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
- gzgt->poll = ED_widgetgroup_gizmo2d_xform_poll;
- gzgt->setup = ED_widgetgroup_gizmo2d_xform_setup;
- gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
- gzgt->refresh = ED_widgetgroup_gizmo2d_xform_refresh;
- gzgt->draw_prepare = ED_widgetgroup_gizmo2d_xform_draw_prepare;
+ ED_widgetgroup_gizmo2d_xform_callbacks_set(gzgt);
}
static void IMAGE_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
@@ -488,11 +484,7 @@ static void IMAGE_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
- gzgt->poll = ED_widgetgroup_gizmo2d_xform_poll;
- gzgt->setup = ED_widgetgroup_gizmo2d_xform_setup_no_cage;
- gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
- gzgt->refresh = ED_widgetgroup_gizmo2d_xform_refresh;
- gzgt->draw_prepare = ED_widgetgroup_gizmo2d_xform_draw_prepare;
+ ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(gzgt);
}
static void IMAGE_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
@@ -506,11 +498,7 @@ static void IMAGE_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
- gzgt->poll = ED_widgetgroup_gizmo2d_resize_poll;
- gzgt->setup = ED_widgetgroup_gizmo2d_resize_setup;
- gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
- gzgt->refresh = ED_widgetgroup_gizmo2d_resize_refresh;
- gzgt->draw_prepare = ED_widgetgroup_gizmo2d_resize_draw_prepare;
+ ED_widgetgroup_gizmo2d_resize_callbacks_set(gzgt);
}
static void IMAGE_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
@@ -524,11 +512,7 @@ static void IMAGE_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
- gzgt->poll = ED_widgetgroup_gizmo2d_rotate_poll;
- gzgt->setup = ED_widgetgroup_gizmo2d_rotate_setup;
- gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
- gzgt->refresh = ED_widgetgroup_gizmo2d_rotate_refresh;
- gzgt->draw_prepare = ED_widgetgroup_gizmo2d_rotate_draw_prepare;
+ ED_widgetgroup_gizmo2d_rotate_callbacks_set(gzgt);
}
static void IMAGE_GGT_navigate(wmGizmoGroupType *gzgt)
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 64570459532..d86e0e2af97 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -42,48 +42,78 @@
#include "textview.h"
#include "GPU_framebuffer.h"
-/* complicates things a bit, so leaving in old simple code */
-#define USE_INFO_NEWLINE
-
-static void info_report_color(unsigned char *fg,
- unsigned char *bg,
- Report *report,
- const short do_tint)
+static int report_line_data(struct TextViewContext *tvc,
+ unsigned char fg[4],
+ unsigned char bg[4],
+ int *icon,
+ unsigned char icon_fg[4],
+ unsigned char icon_bg[4])
{
- int bg_id = TH_BACK, fg_id = TH_TEXT;
- int shade = do_tint ? 0 : -6;
+ Report *report = (Report *)tvc->iter;
- if (report->flag & SELECT) {
- bg_id = TH_INFO_SELECTED;
- fg_id = TH_INFO_SELECTED_TEXT;
- }
- else if (report->type & RPT_ERROR_ALL) {
- bg_id = TH_INFO_ERROR;
- fg_id = TH_INFO_ERROR_TEXT;
+ /* Same text color no matter what type of report. */
+ UI_GetThemeColor4ubv((report->flag & SELECT) ? TH_INFO_SELECTED_TEXT : TH_TEXT, fg);
+
+ /* Zebra striping for background. */
+ int bg_id = (report->flag & SELECT) ? TH_INFO_SELECTED : TH_BACK;
+ int shade = tvc->iter_tmp % 2 ? 4 : -4;
+ UI_GetThemeColorShade4ubv(bg_id, shade, bg);
+
+ /* Icon color and backgound depend of report type. */
+
+ int icon_fg_id;
+ int icon_bg_id;
+
+ if (report->type & RPT_ERROR_ALL) {
+ icon_fg_id = TH_INFO_ERROR_TEXT;
+ icon_bg_id = TH_INFO_ERROR;
+ *icon = ICON_CANCEL;
}
else if (report->type & RPT_WARNING_ALL) {
- bg_id = TH_INFO_WARNING;
- fg_id = TH_INFO_WARNING_TEXT;
+ icon_fg_id = TH_INFO_WARNING_TEXT;
+ icon_bg_id = TH_INFO_WARNING;
+ *icon = ICON_ERROR;
}
else if (report->type & RPT_INFO_ALL) {
- bg_id = TH_INFO_INFO;
- fg_id = TH_INFO_INFO_TEXT;
+ icon_fg_id = TH_INFO_INFO_TEXT;
+ icon_bg_id = TH_INFO_INFO;
+ *icon = ICON_INFO;
}
else if (report->type & RPT_DEBUG_ALL) {
- bg_id = TH_INFO_DEBUG;
- fg_id = TH_INFO_DEBUG_TEXT;
+ icon_fg_id = TH_INFO_DEBUG_TEXT;
+ icon_bg_id = TH_INFO_DEBUG;
+ *icon = ICON_SYSTEM;
+ }
+ else if (report->type & RPT_PROPERTY) {
+ icon_fg_id = TH_INFO_PROPERTY_TEXT;
+ icon_bg_id = TH_INFO_PROPERTY;
+ *icon = ICON_OPTIONS;
+ }
+ else if (report->type & RPT_OPERATOR) {
+ icon_fg_id = TH_INFO_OPERATOR_TEXT;
+ icon_bg_id = TH_INFO_OPERATOR;
+ *icon = ICON_CHECKMARK;
}
else {
- bg_id = TH_BACK;
- fg_id = TH_TEXT;
+ *icon = ICON_NONE;
}
- UI_GetThemeColorShade3ubv(bg_id, shade, bg);
- UI_GetThemeColor3ubv(fg_id, fg);
+ if (report->flag & SELECT) {
+ icon_fg_id = TH_INFO_SELECTED;
+ icon_bg_id = TH_INFO_SELECTED_TEXT;
+ }
+
+ if (*icon != ICON_NONE) {
+ UI_GetThemeColor4ubv(icon_fg_id, icon_fg);
+ UI_GetThemeColor4ubv(icon_bg_id, icon_bg);
+ return TVC_LINE_FG | TVC_LINE_BG | TVC_LINE_ICON | TVC_LINE_ICON_FG | TVC_LINE_ICON_BG;
+ }
+ else {
+ return TVC_LINE_FG | TVC_LINE_BG;
+ }
}
/* reports! */
-#ifdef USE_INFO_NEWLINE
static void report_textview_init__internal(TextViewContext *tvc)
{
Report *report = (Report *)tvc->iter;
@@ -108,14 +138,11 @@ static int report_textview_skip__internal(TextViewContext *tvc)
return (tvc->iter != NULL);
}
-#endif // USE_INFO_NEWLINE
-
static int report_textview_begin(TextViewContext *tvc)
{
- // SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
ReportList *reports = (ReportList *)tvc->arg2;
- tvc->lheight = 14 * UI_DPI_FAC; // sc->lheight;
+ tvc->lheight = 14 * UI_DPI_FAC;
tvc->sel_start = 0;
tvc->sel_end = 0;
@@ -125,7 +152,6 @@ static int report_textview_begin(TextViewContext *tvc)
UI_ThemeClearColor(TH_BACK);
GPU_clear(GPU_COLOR_BIT);
-#ifdef USE_INFO_NEWLINE
tvc->iter_tmp = 0;
if (tvc->iter && report_textview_skip__internal(tvc)) {
/* init the newline iterator */
@@ -137,9 +163,6 @@ static int report_textview_begin(TextViewContext *tvc)
else {
return false;
}
-#else
- return (tvc->iter != NULL);
-#endif
}
static void report_textview_end(TextViewContext *UNUSED(tvc))
@@ -147,7 +170,6 @@ static void report_textview_end(TextViewContext *UNUSED(tvc))
/* pass */
}
-#ifdef USE_INFO_NEWLINE
static int report_textview_step(TextViewContext *tvc)
{
/* simple case, but no newline support */
@@ -184,57 +206,11 @@ static int report_textview_line_get(struct TextViewContext *tvc, const char **li
return 1;
}
-static int report_textview_line_color(struct TextViewContext *tvc,
- unsigned char fg[3],
- unsigned char bg[3])
-{
- Report *report = (Report *)tvc->iter;
- info_report_color(fg, bg, report, tvc->iter_tmp % 2);
- return TVC_LINE_FG | TVC_LINE_BG;
-}
-
-#else // USE_INFO_NEWLINE
-
-static int report_textview_step(TextViewContext *tvc)
-{
- SpaceInfo *sinfo = (SpaceInfo *)tvc->arg1;
- const int report_mask = info_report_mask(sinfo);
- do {
- tvc->iter = (void *)((Link *)tvc->iter)->prev;
- } while (tvc->iter && (((Report *)tvc->iter)->type & report_mask) == 0);
-
- return (tvc->iter != NULL);
-}
-
-static int report_textview_line_get(struct TextViewContext *tvc, const char **line, int *len)
-{
- Report *report = (Report *)tvc->iter;
- *line = report->message;
- *len = report->len;
-
- return 1;
-}
-
-static int report_textview_line_color(struct TextViewContext *tvc,
- unsigned char fg[3],
- unsigned char bg[3])
-{
- Report *report = (Report *)tvc->iter;
- info_report_color(fg, bg, report, tvc->iter_tmp % 2);
- return TVC_LINE_FG | TVC_LINE_BG;
-}
-
-#endif // USE_INFO_NEWLINE
-
-#undef USE_INFO_NEWLINE
-
static void info_textview_draw_rect_calc(const ARegion *ar, rcti *draw_rect)
{
- const int margin = 4 * UI_DPI_FAC;
- draw_rect->xmin = margin;
- draw_rect->xmax = ar->winx - (V2D_SCROLL_WIDTH + margin);
- draw_rect->ymin = margin;
- /* No margin at the top (allow text to scroll off the window). */
+ draw_rect->xmin = 0;
+ draw_rect->xmax = ar->winx;
+ draw_rect->ymin = 0;
draw_rect->ymax = ar->winy;
}
@@ -256,7 +232,7 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo,
tvc.step = report_textview_step;
tvc.line_get = report_textview_line_get;
- tvc.line_color = report_textview_line_color;
+ tvc.line_data = report_line_data;
tvc.const_colors = NULL;
tvc.arg1 = sinfo;
@@ -265,7 +241,10 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo,
/* view */
tvc.sel_start = 0;
tvc.sel_end = 0;
- tvc.lheight = 14 * UI_DPI_FAC; // sc->lheight;
+ tvc.lheight = 17 * UI_DPI_FAC;
+ tvc.row_vpadding = 0.4 * tvc.lheight;
+ tvc.margin_left_chars = 5;
+ tvc.margin_right_chars = 2;
tvc.scroll_ymin = v2d->cur.ymin;
tvc.scroll_ymax = v2d->cur.ymax;
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 1bc583461a5..9828034aaac 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -35,12 +35,16 @@
#include "GPU_immediate.h"
#include "GPU_state.h"
+#include "BKE_report.h"
+#include "UI_interface.h"
+#include "UI_interface_icons.h"
+
#include "textview.h"
static void console_font_begin(const int font_id, const int lheight)
{
- /* 0.875 is based on: 16 pixels lines get 14 pixel text. */
- BLF_size(font_id, 0.875 * lheight, 72);
+ /* Font size in relation to line height. */
+ BLF_size(font_id, 0.8f * lheight, 72);
}
typedef struct TextViewDrawState {
@@ -49,6 +53,9 @@ typedef struct TextViewDrawState {
int lheight;
/** Text vertical offset per line. */
int lofs;
+ int margin_left_chars;
+ int margin_right_chars;
+ int row_vpadding;
/** Number of characters that fit into the width of the console (fixed width). */
int columns;
const rcti *draw_rect;
@@ -68,16 +75,19 @@ BLI_INLINE void console_step_sel(TextViewDrawState *tds, const int step)
}
static void console_draw_sel(const char *str,
- const int sel[2],
const int xy[2],
const int str_len_draw,
- const int cwidth,
- const int lheight,
+ TextViewDrawState *tds,
const unsigned char bg_sel[4])
{
+ const int sel[2] = {tds->sel[0], tds->sel[1]};
+ const int cwidth = tds->cwidth;
+ const int lheight = tds->lheight;
+
if (sel[0] <= str_len_draw && sel[1] >= 0) {
- const int sta = BLI_str_utf8_offset_to_column(str, max_ii(sel[0], 0));
- const int end = BLI_str_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw));
+ const int sta = BLI_str_utf8_offset_to_column(str, max_ii(sel[0], 0)) + tds->margin_left_chars;
+ const int end = BLI_str_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw)) +
+ tds->margin_left_chars;
GPU_blend(true);
GPU_blend_set_func_separate(
@@ -134,20 +144,32 @@ static int console_wrap_offsets(const char *str, int len, int width, int *lines,
static bool console_draw_string(TextViewDrawState *tds,
const char *str,
int str_len,
- const unsigned char fg[3],
- const unsigned char bg[3],
+ const unsigned char fg[4],
+ const unsigned char bg[4],
+ int icon,
+ const unsigned char icon_fg[4],
+ const unsigned char icon_bg[4],
const unsigned char bg_sel[4])
{
int tot_lines; /* Total number of lines for wrapping. */
int *offsets; /* Offsets of line beginnings for wrapping. */
- int y_next;
- str_len = console_wrap_offsets(str, str_len, tds->columns, &tot_lines, &offsets);
- y_next = tds->xy[1] + tds->lheight * tot_lines;
+ str_len = console_wrap_offsets(str,
+ str_len,
+ tds->columns - (tds->margin_left_chars + tds->margin_right_chars),
+ &tot_lines,
+ &offsets);
+
+
+ int line_height = (tot_lines * tds->lheight) + (tds->row_vpadding * 2);
+ int line_bottom = tds->xy[1];
+ int line_top = line_bottom + line_height;
+
+ int y_next = line_top;
/* Just advance the height. */
if (tds->do_draw == false) {
- if (tds->mval_pick_offset && tds->mval[1] != INT_MAX && tds->xy[1] <= tds->mval[1]) {
+ if (tds->mval_pick_offset && tds->mval[1] != INT_MAX && line_bottom <= tds->mval[1]) {
if (y_next >= tds->mval[1]) {
int ofs = 0;
@@ -186,107 +208,111 @@ static bool console_draw_string(TextViewDrawState *tds,
return true;
}
- /* Check if we need to wrap lines. */
- if (tot_lines > 1) {
- const int initial_offset = offsets[tot_lines - 1];
- size_t len = str_len - initial_offset;
- const char *s = str + initial_offset;
- int i;
-
- int sel_orig[2];
- copy_v2_v2_int(sel_orig, tds->sel);
-
- /* Invert and swap for wrapping. */
- tds->sel[0] = str_len - sel_orig[1];
- tds->sel[1] = str_len - sel_orig[0];
-
- if (bg) {
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- immUniformColor3ubv(bg);
- immRecti(
- pos, 0, tds->xy[1], tds->draw_rect->xmax, (tds->xy[1] + (tds->lheight * tot_lines)));
-
- immUnbindProgram();
- }
-
- /* Last part needs no clipping. */
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
- BLF_color3ubv(tds->font_id, fg);
- BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
-
- if (tds->sel[0] != tds->sel[1]) {
- console_step_sel(tds, -initial_offset);
- /* BLF_color3ub(tds->font_id, 255, 0, 0); // debug */
- console_draw_sel(s, tds->sel, tds->xy, len, tds->cwidth, tds->lheight, bg_sel);
- }
+ size_t len;
+ const char *s;
+ int i;
- tds->xy[1] += tds->lheight;
+ int sel_orig[2];
+ copy_v2_v2_int(sel_orig, tds->sel);
- for (i = tot_lines - 1; i > 0; i--) {
- len = offsets[i] - offsets[i - 1];
- s = str + offsets[i - 1];
+ /* Invert and swap for wrapping. */
+ tds->sel[0] = str_len - sel_orig[1];
+ tds->sel[1] = str_len - sel_orig[0];
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
- BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
+ if (bg) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(bg);
+ immRecti(pos, 0, line_bottom, tds->draw_rect->xmax, line_top);
+ immUnbindProgram();
+ }
- if (tds->sel[0] != tds->sel[1]) {
- console_step_sel(tds, len);
- /* BLF_color3ub(tds->font_id, 0, 255, 0); // debug */
- console_draw_sel(s, tds->sel, tds->xy, len, tds->cwidth, tds->lheight, bg_sel);
- }
+ if (icon_bg) {
+ float col[4];
+ int bg_size = 20 * UI_DPI_FAC;
+ float vpadding = (tds->lheight + (tds->row_vpadding * 2) - bg_size) / 2;
+ float hpadding = ((tds->margin_left_chars * tds->cwidth) - bg_size) / 2;
+
+ rgba_uchar_to_float(col, icon_bg);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(true,
+ hpadding,
+ line_top - bg_size - vpadding,
+ bg_size + hpadding,
+ line_top - vpadding,
+ 4 * UI_DPI_FAC,
+ col);
+ }
- tds->xy[1] += tds->lheight;
+ if (icon) {
+ int vpadding = (tds->lheight + (tds->row_vpadding * 2) - UI_DPI_ICON_SIZE) / 2;
+ int hpadding = ((tds->margin_left_chars * tds->cwidth) - UI_DPI_ICON_SIZE) / 2;
- /* Check if were out of view bounds. */
- if (tds->xy[1] > tds->scroll_ymax) {
- MEM_freeN(offsets);
- return false;
- }
- }
+ GPU_blend(true);
+ UI_icon_draw_ex(hpadding,
+ line_top - UI_DPI_ICON_SIZE - vpadding,
+ icon,
+ (16 / UI_DPI_ICON_SIZE),
+ 1.0f,
+ 0.0f,
+ icon_fg,
+ false);
+ GPU_blend(false);
+ }
- copy_v2_v2_int(tds->sel, sel_orig);
- console_step_sel(tds, -(str_len + 1));
+ tds->xy[1] += tds->row_vpadding;
+
+ /* Last part needs no clipping. */
+ const int final_offset = offsets[tot_lines - 1];
+ len = str_len - final_offset;
+ s = str + final_offset;
+ BLF_position(tds->font_id,
+ tds->xy[0] + (tds->margin_left_chars * tds->cwidth),
+ tds->lofs + line_bottom + tds->row_vpadding,
+ 0);
+ BLF_color4ubv(tds->font_id, fg);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
+
+ if (tds->sel[0] != tds->sel[1]) {
+ console_step_sel(tds, -final_offset);
+ int pos[2] = {tds->xy[0], line_bottom};
+ console_draw_sel(s, pos, len, tds, bg_sel);
}
- else {
- /* Simple, no wrap. */
- if (bg) {
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ tds->xy[1] += tds->lheight;
- immUniformColor3ubv(bg);
- immRecti(pos, 0, tds->xy[1], tds->draw_rect->xmax, tds->xy[1] + tds->lheight);
+ BLF_color4ubv(tds->font_id, fg);
- immUnbindProgram();
- }
+ for (i = tot_lines - 1; i > 0; i--) {
+ len = offsets[i] - offsets[i - 1];
+ s = str + offsets[i - 1];
- BLF_color3ubv(tds->font_id, fg);
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
- BLF_draw_mono(tds->font_id, str, str_len, tds->cwidth);
+ BLF_position(tds->font_id,
+ tds->xy[0] + (tds->margin_left_chars * tds->cwidth),
+ tds->lofs + tds->xy[1],
+ 0);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
if (tds->sel[0] != tds->sel[1]) {
- int isel[2];
-
- isel[0] = str_len - tds->sel[1];
- isel[1] = str_len - tds->sel[0];
-
- /* BLF_color3ub(tds->font_id, 255, 255, 0); // debug */
- console_draw_sel(str, isel, tds->xy, str_len, tds->cwidth, tds->lheight, bg_sel);
- console_step_sel(tds, -(str_len + 1));
+ console_step_sel(tds, len);
+ console_draw_sel(s, tds->xy, len, tds, bg_sel);
}
tds->xy[1] += tds->lheight;
+ /* Check if were out of view bounds. */
if (tds->xy[1] > tds->scroll_ymax) {
MEM_freeN(offsets);
return false;
}
}
+ tds->xy[1] = y_next;
+
+ copy_v2_v2_int(tds->sel, sel_orig);
+ console_step_sel(tds, -(str_len + 1));
+
MEM_freeN(offsets);
return true;
}
@@ -310,7 +336,8 @@ int textview_draw(TextViewContext *tvc,
int xy[2];
/* Disable selection by. */
int sel[2] = {-1, -1};
- unsigned char fg[3], bg[3];
+ unsigned char fg[4], bg[4], icon_fg[4], icon_bg[4];
+ int icon = 0;
const int font_id = blf_mono_font;
console_font_begin(font_id, tvc->lheight);
@@ -338,6 +365,9 @@ int textview_draw(TextViewContext *tvc,
tds.cwidth = (int)BLF_fixed_width(font_id);
BLI_assert(tds.cwidth > 0);
tds.lheight = tvc->lheight;
+ tds.margin_left_chars = tvc->margin_left_chars;
+ tds.margin_right_chars = tvc->margin_right_chars;
+ tds.row_vpadding = tvc->row_vpadding;
tds.lofs = -BLF_descender(font_id);
/* Note, scroll bar must be already subtracted. */
tds.columns = (tvc->draw_rect.xmax - tvc->draw_rect.xmin) / tds.cwidth;
@@ -374,12 +404,12 @@ int textview_draw(TextViewContext *tvc,
do {
const char *ext_line;
int ext_len;
- int color_flag = 0;
+ int data_flag = 0;
const int y_prev = xy[1];
if (do_draw) {
- color_flag = tvc->line_color(tvc, fg, bg);
+ data_flag = tvc->line_data(tvc, fg, bg, &icon, icon_fg, icon_bg);
}
tvc->line_get(tvc, &ext_line, &ext_len);
@@ -387,8 +417,11 @@ int textview_draw(TextViewContext *tvc,
if (!console_draw_string(&tds,
ext_line,
ext_len,
- (color_flag & TVC_LINE_FG) ? fg : NULL,
- (color_flag & TVC_LINE_BG) ? bg : NULL,
+ (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) {
@@ -397,6 +430,12 @@ int textview_draw(TextViewContext *tvc,
}
}
+ if (do_draw) {
+ if (tvc->draw_cursor && tvc->iter_index == 0) {
+ tvc->draw_cursor(tvc);
+ }
+ }
+
if ((mval[1] != INT_MAX) && (mval[1] >= y_prev && mval[1] <= xy[1])) {
*r_mval_pick_item = (void *)tvc->iter;
break;
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 578236bbd13..3f7ba9739c4 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -31,6 +31,10 @@ typedef struct TextViewContext {
int cwidth; /* shouldnt be needed! */
int columns; /* shouldnt be needed! */
+ int row_vpadding;
+ int margin_left_chars;
+ int margin_right_chars;
+
/** Area to draw: (0, 0, winx, winy) with a margin applied and scroll-bar subtracted. */
rcti draw_rect;
@@ -46,7 +50,13 @@ typedef struct TextViewContext {
/* iterator */
int (*step)(struct TextViewContext *tvc);
int (*line_get)(struct TextViewContext *tvc, const char **, int *);
- int (*line_color)(struct TextViewContext *tvc, unsigned char fg[3], unsigned char bg[3]);
+ int (*line_data)(struct TextViewContext *tvc,
+ unsigned char fg[4],
+ unsigned char bg[4],
+ int *icon,
+ unsigned char icon_fg[4],
+ unsigned char icon_bg[4]);
+ void (*draw_cursor)(struct TextViewContext *tvc);
/* constant theme colors */
void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]);
void *iter;
@@ -66,7 +76,12 @@ int textview_draw(struct TextViewContext *tvc,
void **r_mval_pick_item,
int *r_mval_pick_offset);
-#define TVC_LINE_FG (1 << 0)
-#define TVC_LINE_BG (1 << 1)
+enum {
+ TVC_LINE_FG = (1 << 0),
+ TVC_LINE_BG = (1 << 1),
+ TVC_LINE_ICON = (1 << 2),
+ TVC_LINE_ICON_FG = (1 << 3),
+ TVC_LINE_ICON_BG = (1 << 4)
+};
#endif /* __TEXTVIEW_H__ */
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index b908ed2b7ee..4277e579274 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -193,12 +193,6 @@ static bool nla_animdata_panel_poll(const bContext *C, PanelType *UNUSED(pt))
return (nla_panel_context(C, &ptr, NULL, NULL) && (ptr.data != NULL));
}
-static bool nla_track_panel_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- PointerRNA ptr;
- return (nla_panel_context(C, NULL, &ptr, NULL) && (ptr.data != NULL));
-}
-
static bool nla_strip_panel_poll(const bContext *C, PanelType *UNUSED(pt))
{
PointerRNA ptr;
@@ -262,6 +256,8 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
block = uiLayoutGetBlock(layout);
UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* AnimData Source Properties ----------------------------------- */
@@ -301,36 +297,53 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
/* extrapolation */
row = uiLayoutRow(layout, true);
- uiItemR(row, &adt_ptr, "action_extrapolation", 0, NULL, ICON_NONE);
+ uiItemR(row, &adt_ptr, "action_extrapolation", 0, IFACE_("Extrapolation"), ICON_NONE);
/* blending */
row = uiLayoutRow(layout, true);
- uiItemR(row, &adt_ptr, "action_blend_type", 0, NULL, ICON_NONE);
+ uiItemR(row, &adt_ptr, "action_blend_type", 0, IFACE_("Blending"), ICON_NONE);
/* influence */
row = uiLayoutRow(layout, true);
- uiItemR(row, &adt_ptr, "action_influence", 0, NULL, ICON_NONE);
+ uiItemR(row, &adt_ptr, "action_influence", 0, IFACE_("Influence"), ICON_NONE);
}
-/* active NLA-Track */
-static void nla_panel_track(const bContext *C, Panel *pa)
+/* generic settings for active NLA-Strip */
+static void nla_panel_stripname(const bContext *C, Panel *pa)
{
- PointerRNA nlt_ptr;
+ PointerRNA strip_ptr;
uiLayout *layout = pa->layout;
uiLayout *row;
uiBlock *block;
- /* check context and also validity of pointer */
- if (!nla_panel_context(C, NULL, &nlt_ptr, NULL)) {
+ if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
return;
}
block = uiLayoutGetBlock(layout);
UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
- /* Info - Active NLA-Context:Track ---------------------- */
- row = uiLayoutRow(layout, true);
- uiItemR(row, &nlt_ptr, "name", 0, NULL, ICON_NLA);
+ /* Strip Properties ------------------------------------- */
+ /* strip type */
+ row = uiLayoutRow(layout, false);
+ if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_CLIP) {
+ uiItemL(row, "", ICON_ANIM);
+ }
+ else if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_TRANSITION) {
+ uiItemL(row, "", ICON_ARROW_LEFTRIGHT);
+ }
+ else if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_META) {
+ uiItemL(row, "", ICON_SEQ_STRIP_META);
+ }
+ else if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_SOUND) {
+ uiItemL(row, "", ICON_SOUND);
+ }
+
+ uiItemR(row, &strip_ptr, "name", 0, "", ICON_NLA);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiItemR(row, &strip_ptr, "mute", 0, "", ICON_NONE);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
/* generic settings for active NLA-Strip */
@@ -338,7 +351,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
{
PointerRNA strip_ptr;
uiLayout *layout = pa->layout;
- uiLayout *column, *row, *sub;
+ uiLayout *column;
uiBlock *block;
short showEvalProps = 1;
@@ -351,15 +364,14 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
/* Strip Properties ------------------------------------- */
/* strip type */
- row = uiLayoutColumn(layout, true);
- uiItemR(row, &strip_ptr, "name", 0, NULL, ICON_NLA); // XXX icon?
- uiItemR(row, &strip_ptr, "type", 0, NULL, ICON_NONE);
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* strip extents */
column = uiLayoutColumn(layout, true);
- uiItemL(column, IFACE_("Strip Extents:"), ICON_NONE);
- uiItemR(column, &strip_ptr, "frame_start", 0, NULL, ICON_NONE);
- uiItemR(column, &strip_ptr, "frame_end", 0, NULL, ICON_NONE);
+ uiItemR(column, &strip_ptr, "frame_start", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
/* Evaluation-Related Strip Properties ------------------ */
@@ -371,33 +383,35 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
/* only show if allowed to... */
if (showEvalProps) {
/* extrapolation */
- row = uiLayoutRow(layout, true);
- uiItemR(row, &strip_ptr, "extrapolation", 0, NULL, ICON_NONE);
-
- /* blending */
- row = uiLayoutRow(layout, true);
- uiItemR(row, &strip_ptr, "blend_type", 0, NULL, ICON_NONE);
+ column = uiLayoutColumn(layout, false);
+ uiItemR(column, &strip_ptr, "extrapolation", 0, NULL, ICON_NONE);
+ uiItemR(column, &strip_ptr, "blend_type", 0, NULL, ICON_NONE);
/* Blend in/out + auto-blending:
* - blend in/out can only be set when autoblending is off
*/
+
+ uiItemS(layout);
+
+ column = uiLayoutColumn(layout, true);
+ uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_auto_blend") == false);
+ 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?
- sub = uiLayoutColumn(column, true);
- uiLayoutSetActive(sub, RNA_boolean_get(&strip_ptr, "use_auto_blend") == false);
- uiItemR(sub, &strip_ptr, "blend_in", 0, NULL, ICON_NONE);
- uiItemR(sub, &strip_ptr, "blend_out", 0, NULL, ICON_NONE);
+ uiItemS(layout);
/* settings */
column = uiLayoutColumn(layout, true);
uiLayoutSetActive(column,
!(RNA_boolean_get(&strip_ptr, "use_animated_influence") ||
RNA_boolean_get(&strip_ptr, "use_animated_time")));
- uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
- uiItemR(column, &strip_ptr, "mute", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
}
}
@@ -416,6 +430,8 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
block = uiLayoutGetBlock(layout);
UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* Strip Properties ------------------------------------- */
/* action pointer */
@@ -425,9 +441,8 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
/* action extents */
// XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column = uiLayoutColumn(layout, true);
- uiItemL(column, IFACE_("Action Extents:"), ICON_NONE);
- uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Start Frame"), ICON_NONE);
- uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End Frame"), ICON_NONE);
+ 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. */
@@ -438,17 +453,16 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
/* action usage */
column = uiLayoutColumn(layout, true);
uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_time") == false);
- uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
- uiItemR(column, &strip_ptr, "scale", 0, NULL, ICON_NONE);
+ uiItemR(column, &strip_ptr, "scale", 0, IFACE_("Playback Scale"), ICON_NONE);
uiItemR(column, &strip_ptr, "repeat", 0, NULL, ICON_NONE);
}
/* evaluation settings for active NLA-Strip */
-static void nla_panel_evaluation(const bContext *C, Panel *pa)
+static void nla_panel_animated_influence_header(const bContext *C, Panel *pa)
{
PointerRNA strip_ptr;
uiLayout *layout = pa->layout;
- uiLayout *col, *sub;
+ uiLayout *col;
uiBlock *block;
/* check context and also validity of pointer */
@@ -460,20 +474,65 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa)
UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
col = uiLayoutColumn(layout, true);
- uiItemR(col, &strip_ptr, "use_animated_influence", 0, NULL, ICON_NONE);
+ uiItemR(col, &strip_ptr, "use_animated_influence", 0, "", ICON_NONE);
+}
- sub = uiLayoutColumn(col, true);
- uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_influence"));
- uiItemR(sub, &strip_ptr, "influence", 0, NULL, ICON_NONE);
+/* evaluation settings for active NLA-Strip */
+static void nla_panel_evaluation(const bContext *C, Panel *pa)
+{
+ PointerRNA strip_ptr;
+ uiLayout *layout = pa->layout;
+ uiBlock *block;
+
+ /* check context and also validity of pointer */
+ if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
+ return;
+ }
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetEnabled(layout, RNA_boolean_get(&strip_ptr, "use_animated_influence"));
+ uiItemR(layout, &strip_ptr, "influence", 0, NULL, ICON_NONE);
+}
+
+static void nla_panel_animated_strip_time_header(const bContext *C, Panel *pa)
+{
+ PointerRNA strip_ptr;
+ uiLayout *layout = pa->layout;
+ uiLayout *col;
+ uiBlock *block;
+
+ /* check context and also validity of pointer */
+ if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
+ return;
+ }
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
col = uiLayoutColumn(layout, true);
- sub = uiLayoutRow(col, false);
- uiItemR(sub, &strip_ptr, "use_animated_time", 0, NULL, ICON_NONE);
- uiItemR(sub, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
+ uiItemR(col, &strip_ptr, "use_animated_time", 0, "", ICON_NONE);
+}
+
+static void nla_panel_animated_strip_time(const bContext *C, Panel *pa)
+{
+ PointerRNA strip_ptr;
+ uiLayout *layout = pa->layout;
+ uiBlock *block;
- sub = uiLayoutRow(col, false);
- uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_time"));
- uiItemR(sub, &strip_ptr, "strip_time", 0, NULL, ICON_NONE);
+ /* check context and also validity of pointer */
+ if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
+ return;
+ }
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetEnabled(layout, RNA_boolean_get(&strip_ptr, "use_animated_time"));
+ uiItemR(layout, &strip_ptr, "strip_time", 0, NULL, ICON_NONE);
}
/* F-Modifiers for active NLA-Strip */
@@ -527,26 +586,27 @@ void nla_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata");
strcpy(pt->idname, "NLA_PT_animdata");
strcpy(pt->label, N_("Animation Data"));
- strcpy(pt->category, "Animations");
+ strcpy(pt->category, "Edited Action");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
pt->draw = nla_panel_animdata;
pt->poll = nla_animdata_panel_poll;
- pt->flag = PNL_DEFAULT_CLOSED;
BLI_addtail(&art->paneltypes, pt);
- pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
- strcpy(pt->idname, "NLA_PT_track");
- strcpy(pt->label, N_("Active Track"));
- strcpy(pt->category, "Animations");
+ pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
+ strcpy(pt->idname, "NLA_PT_stripname");
+ strcpy(pt->label, N_("Active Strip Name"));
+ strcpy(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = nla_panel_track;
- pt->poll = nla_track_panel_poll;
+ pt->flag = PNL_NO_HEADER;
+ pt->draw = nla_panel_stripname;
+ pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
- pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
+ PanelType *pt_properties = pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties");
strcpy(pt->label, N_("Active Strip"));
- strcpy(pt->category, "Animations");
+ strcpy(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_properties;
pt->poll = nla_strip_panel_poll;
@@ -555,19 +615,39 @@ void nla_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_actionclip");
strcpy(pt->label, N_("Action Clip"));
- strcpy(pt->category, "Animations");
+ strcpy(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_actclip;
+ pt->flag = PNL_DEFAULT_CLOSED;
pt->poll = nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation");
- strcpy(pt->label, N_("Evaluation"));
- strcpy(pt->category, "Animations");
+ strcpy(pt->parent_id, "NLA_PT_properties");
+ strcpy(pt->label, N_("Animated Influence"));
+ strcpy(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_evaluation;
+ pt->draw_header = nla_panel_animated_influence_header;
+ pt->parent = pt_properties;
+ pt->flag = PNL_DEFAULT_CLOSED;
+ pt->poll = nla_strip_eval_panel_poll;
+ BLI_addtail(&pt_properties->children, BLI_genericNodeN(pt));
+ BLI_addtail(&art->paneltypes, pt);
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animated strip time");
+ strcpy(pt->idname, "NLA_PT_animated_strip_time");
+ strcpy(pt->parent_id, "NLA_PT_properties");
+ strcpy(pt->label, N_("Animated Strip Time"));
+ strcpy(pt->category, "Strip");
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = nla_panel_animated_strip_time;
+ pt->draw_header = nla_panel_animated_strip_time_header;
+ pt->parent = pt_properties;
+ pt->flag = PNL_DEFAULT_CLOSED;
pt->poll = nla_strip_eval_panel_poll;
+ BLI_addtail(&pt_properties->children, BLI_genericNodeN(pt));
BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 04a20efe887..0f170b1f530 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -565,9 +565,9 @@ static int nlaedit_viewframe_exec(bContext *C, wmOperator *op)
void NLA_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Frame";
+ ot->name = "Go to Current Frame";
ot->idname = "NLA_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
+ ot->description = "Move the view to the playhead";
/* api callbacks */
ot->exec = nlaedit_viewframe_exec;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 2c2989a284d..a341be5bf65 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -295,6 +295,10 @@ static void outliner_object_set_flag_recursive_cb(bContext *C,
}
else {
Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
+ /* Child can be in a collection excluded from viewlayer. */
+ if (base_iter == NULL) {
+ continue;
+ }
RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr);
}
RNA_property_boolean_set(&ptr, base_or_object_prop, value);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 234da323de6..c9eeb2cff20 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -46,6 +46,7 @@
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
+#include "BKE_object.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_layer.h"
@@ -678,8 +679,8 @@ static void object_delete_cb(bContext *C,
}
// check also library later
- if (ob == CTX_data_edit_object(C)) {
- ED_object_editmode_exit(C, EM_FREEDATA);
+ if ((ob->mode && OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) {
+ ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
}
BKE_id_delete(bmain, ob);
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 7f7cfff12ef..1bb1a1c5964 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1267,6 +1267,7 @@ static TreeElement *outliner_add_library_contents(Main *mainvar,
for (a = 0; a < tot; a++) {
if (lbarray[a] && lbarray[a]->first) {
ID *id = lbarray[a]->first;
+ const bool is_library = (GS(id->name) == ID_LI) && (lib != NULL);
/* check if there's data in current lib */
for (; id; id = id->next) {
@@ -1275,7 +1276,9 @@ static TreeElement *outliner_add_library_contents(Main *mainvar,
}
}
- if (id) {
+ /* We always want to create an entry for libraries, even if/when we have no more IDs from
+ * them. This invalid state is important to show to user as well.*/
+ if (id != NULL || is_library) {
if (!tenlib) {
/* Create library tree element on demand, depending if there are any data-blocks. */
if (lib) {
@@ -1288,18 +1291,20 @@ static TreeElement *outliner_add_library_contents(Main *mainvar,
}
/* Create data-block list parent element on demand. */
- if (filter_id_type) {
- ten = tenlib;
- }
- else {
- ten = outliner_add_element(soops, &tenlib->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
- ten->name = outliner_idcode_to_plural(GS(id->name));
- }
+ if (id != NULL) {
+ if (filter_id_type) {
+ ten = tenlib;
+ }
+ else {
+ ten = outliner_add_element(soops, &tenlib->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+ ten->name = outliner_idcode_to_plural(GS(id->name));
+ }
- for (id = lbarray[a]->first; id; id = id->next) {
- if (outliner_library_id_show(lib, id, filter_id_type)) {
- outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (outliner_library_id_show(lib, id, filter_id_type)) {
+ outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ }
}
}
}
@@ -2186,6 +2191,8 @@ static int outliner_filter_subtree(SpaceOutliner *soops,
te_next = te->next;
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
/* Don't free the tree, but extract the children from the parent and add to this tree. */
+ /* This also needs filtering the subtree prior (see T69246). */
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
te_next = outliner_extract_children_from_subtree(te, lb);
continue;
}
@@ -2304,9 +2311,8 @@ void outliner_build_tree(
for (lib = mainvar->libraries.first; lib; lib = lib->id.next) {
ten = outliner_add_library_contents(mainvar, soops, &soops->tree, lib);
- if (ten) {
- lib->id.newid = (ID *)ten;
- }
+ BLI_assert(ten != NULL);
+ lib->id.newid = (ID *)ten;
}
/* make hierarchy */
ten = soops->tree.first;
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 84ded1dd2c7..da7d9e2a8f3 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -62,6 +62,10 @@ if(WITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${AUDASPACE_C_LIBRARIES}
+ ${AUDASPACE_PY_LIBRARIES}
+ )
endif()
if(WITH_INTERNATIONAL)
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ee3dceb6acd..9e8fa6475a0 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -96,8 +96,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
INT_MAX,
"Start Frame",
"Start frame of the sequence strip",
- INT_MIN,
- INT_MAX);
+ -MAXFRAME,
+ MAXFRAME);
}
if (flag & SEQPROP_ENDFRAME) {
@@ -109,8 +109,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
INT_MAX,
"End Frame",
"End frame for the color strip",
- INT_MIN,
- INT_MAX);
+ -MAXFRAME,
+ MAXFRAME);
}
RNA_def_int(
@@ -312,6 +312,26 @@ static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequenc
}
}
+static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ /* Hide start/end frames for effect strips that are locked to their parents' location. */
+ if (BKE_sequence_effect_get_num_inputs(type) != 0) {
+ if ((STREQ(prop_id, "frame_start")) || (STREQ(prop_id, "frame_end"))) {
+ return false;
+ }
+ }
+ if ((type != SEQ_TYPE_COLOR) && (STREQ(prop_id, "color"))) {
+ return false;
+ }
+
+ return true;
+}
+
/* add scene operator */
static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
@@ -578,7 +598,8 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
ED_sequencer_deselect_all(scene);
}
- if (RNA_struct_property_is_set(op->ptr, "files")) {
+ if (RNA_struct_property_is_set(op->ptr, "files") &&
+ RNA_struct_property_is_set(op->ptr, "directory")) {
tot_files = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
}
@@ -591,7 +612,7 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
char dir_only[FILE_MAX];
char file_only[FILE_MAX];
- BLI_split_dir_part(seq_load.path, dir_only, sizeof(dir_only));
+ RNA_string_get(op->ptr, "directory", dir_only);
RNA_BEGIN (op->ptr, itemptr, "files") {
Sequence *seq;
@@ -1065,8 +1086,8 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
/* 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 */
if (seq1 == NULL && end_frame <= start_frame) {
- BKE_report(op->reports, RPT_ERROR, "Start and end frame are not set");
- return OPERATOR_CANCELLED;
+ end_frame = start_frame + 1;
+ RNA_int_set(op->ptr, "frame_end", end_frame);
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type);
@@ -1160,6 +1181,8 @@ static int sequencer_add_effect_strip_invoke(bContext *C,
void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Effect Strip";
ot->idname = "SEQUENCER_OT_effect_strip_add";
@@ -1170,25 +1193,27 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
ot->exec = sequencer_add_effect_strip_exec;
ot->poll = ED_operator_sequencer_active_editable;
+ ot->poll_property = seq_effect_add_properties_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
- RNA_def_float_vector(ot->srna,
- "color",
- 3,
- NULL,
- 0.0f,
- 1.0f,
- "Color",
- "Initialize the strip with this color (only used when type='COLOR')",
- 0.0f,
- 1.0f);
+ sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+ prop = RNA_def_float_color(ot->srna,
+ "color",
+ 3,
+ NULL,
+ 0.0f,
+ 1.0f,
+ "Color",
+ "Initialize the strip with this color (only used when type='COLOR')",
+ 0.0f,
+ 1.0f);
+ RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 70cb28fa937..bef4a7cdd22 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1023,27 +1023,25 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
SeqRenderData context = {0};
ImBuf *ibuf;
int rectx, recty;
- float render_size;
- float proxy_size = 100.0;
+ double render_size;
short is_break = G.is_break;
- render_size = sseq->render_size;
- if (render_size == 0) {
- render_size = scene->r.size;
- }
- else {
- proxy_size = render_size;
+ if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_NONE) {
+ return NULL;
}
- if (render_size < 0) {
- return NULL;
+ if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
+ render_size = scene->r.size / 100.0;
+ }
+ else {
+ render_size = BKE_sequencer_rendersize_to_scale_factor(sseq->render_size);
}
- rectx = (render_size * (float)scene->r.xsch) / 100.0f + 0.5f;
- recty = (render_size * (float)scene->r.ysch) / 100.0f + 0.5f;
+ rectx = render_size * scene->r.xsch + 0.5;
+ recty = render_size * scene->r.ysch + 0.5;
BKE_sequencer_new_render_data(
- bmain, depsgraph, scene, rectx, recty, proxy_size, false, &context);
+ bmain, depsgraph, scene, rectx, recty, sseq->render_size, false, &context);
context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
/* Sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
@@ -1628,23 +1626,19 @@ void sequencer_draw_preview(const bContext *C,
void drawprefetchseqspace(Scene *scene, ARegion *UNUSED(ar), SpaceSeq *sseq)
{
int rectx, recty;
- int render_size = sseq->render_size;
- int proxy_size = 100.0;
- if (render_size == 0) {
- render_size = scene->r.size;
- }
- else {
- proxy_size = render_size;
- }
- if (render_size < 0) {
+ int render_size = BKE_sequencer_rendersize_to_scale_factor(sseq->render_size);
+ if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_NONE) {
return;
}
- rectx = (render_size * scene->r.xsch) / 100;
- recty = (render_size * scene->r.ysch) / 100;
+ if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
+ render_size = scene->r.size / 100.0;
+ }
+ rectx = render_size * scene->r.xsch + 0.5;
+ recty = render_size * scene->r.ysch + 0.5;
if (sseq->mainb != SEQ_DRAW_SEQUENCE) {
- give_ibuf_prefetch_request(rectx, recty, (scene->r.cfra), sseq->chanshown, proxy_size);
+ give_ibuf_prefetch_request(rectx, recty, (scene->r.cfra), sseq->chanshown, sseq->render_size);
}
}
#endif
@@ -2119,11 +2113,7 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* channel numbers */
{
rcti rect;
- BLI_rcti_init(&rect,
- 0,
- 15 * UI_DPI_FAC,
- 15 * UI_DPI_FAC,
- UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y);
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y);
UI_view2d_draw_scale_y__block(ar, v2d, &rect, TH_SCROLL_TEXT);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 57a0d63c35e..a1177454acd 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -103,6 +103,7 @@ EnumPropertyItem prop_side_types[] = {
{SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
{SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
{SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""},
+ {SEQ_SIDE_NO_CHANGE, "NO_CHANGE", 0, "No change", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -958,6 +959,8 @@ static bool cut_seq_list(Main *bmain,
Scene *scene,
ListBase *slist,
int cutframe,
+ int channel,
+ bool use_cursor_position,
Sequence *(*cut_seq)(Main *bmain, Scene *, Sequence *, ListBase *, int))
{
Sequence *seq, *seq_next_iter;
@@ -968,8 +971,8 @@ static bool cut_seq_list(Main *bmain,
while (seq && seq != seq_first_new) {
seq_next_iter = seq->next; /* we need this because we may remove seq */
seq->tmp = NULL;
- if (seq->flag & SELECT) {
- if (cutframe > seq->startdisp && cutframe < seq->enddisp) {
+ if (use_cursor_position) {
+ if (seq->machine == channel && seq->startdisp < cutframe && seq->enddisp > cutframe) {
Sequence *seqn = cut_seq(bmain, scene, seq, slist, cutframe);
if (seqn) {
if (seq_first_new == NULL) {
@@ -977,16 +980,28 @@ static bool cut_seq_list(Main *bmain,
}
}
}
- else if (seq->enddisp <= cutframe) {
- /* do nothing */
- }
- else if (seq->startdisp >= cutframe) {
- /* move to tail */
- BLI_remlink(slist, seq);
- BLI_addtail(slist, seq);
+ }
+ else {
+ if (seq->flag & SELECT) {
+ if (cutframe > seq->startdisp && cutframe < seq->enddisp) {
+ Sequence *seqn = cut_seq(bmain, scene, seq, slist, cutframe);
+ if (seqn) {
+ if (seq_first_new == NULL) {
+ seq_first_new = seqn;
+ }
+ }
+ }
+ else if (seq->enddisp <= cutframe) {
+ /* do nothing */
+ }
+ else if (seq->startdisp >= cutframe) {
+ /* move to tail */
+ BLI_remlink(slist, seq);
+ BLI_addtail(slist, seq);
- if (seq_first_new == NULL) {
- seq_first_new = seq;
+ if (seq_first_new == NULL) {
+ seq_first_new = seq;
+ }
}
}
}
@@ -2154,40 +2169,64 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- int cut_side, cut_hard, cut_frame;
-
- bool changed;
+ int cut_side, cut_hard, cut_frame, cut_channel;
+ bool changed, use_cursor_position, ignore_selection;
+ bool seq_selected = false;
cut_frame = RNA_int_get(op->ptr, "frame");
+ cut_channel = RNA_int_get(op->ptr, "channel");
+ use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position");
cut_hard = RNA_enum_get(op->ptr, "type");
cut_side = RNA_enum_get(op->ptr, "side");
+ ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
if (cut_hard == SEQ_CUT_HARD) {
- changed = cut_seq_list(bmain, scene, ed->seqbasep, cut_frame, cut_seq_hard);
+ changed = cut_seq_list(
+ bmain, scene, ed->seqbasep, cut_frame, cut_channel, use_cursor_position, cut_seq_hard);
}
else {
- changed = cut_seq_list(bmain, scene, ed->seqbasep, cut_frame, cut_seq_soft);
+ changed = cut_seq_list(
+ bmain, scene, ed->seqbasep, cut_frame, cut_channel, use_cursor_position, cut_seq_soft);
}
if (changed) { /* got new strips ? */
Sequence *seq;
- if (cut_side != SEQ_SIDE_BOTH) {
- SEQP_BEGIN (ed, seq) {
- if (cut_side == SEQ_SIDE_LEFT) {
- if (seq->startdisp >= cut_frame) {
- seq->flag &= ~SEQ_ALLSEL;
+ if (ignore_selection) {
+ if (use_cursor_position) {
+ SEQP_BEGIN (ed, seq) {
+ if (seq->enddisp == cut_frame && seq->machine == cut_channel) {
+ seq_selected = seq->flag & SEQ_ALLSEL;
}
}
- else {
- if (seq->enddisp <= cut_frame) {
- seq->flag &= ~SEQ_ALLSEL;
+ SEQ_END;
+ if (!seq_selected) {
+ SEQP_BEGIN (ed, seq) {
+ if (seq->startdisp == cut_frame && seq->machine == cut_channel) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
}
+ SEQ_END;
}
}
- SEQ_END;
}
-
+ else {
+ if (cut_side != SEQ_SIDE_BOTH) {
+ SEQP_BEGIN (ed, seq) {
+ if (cut_side == SEQ_SIDE_LEFT) {
+ if (seq->startdisp >= cut_frame) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+ }
+ else {
+ if (seq->enddisp <= cut_frame) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+ }
+ }
+ SEQ_END;
+ }
+ }
SEQP_BEGIN (ed, seq) {
if (seq->seq1 || seq->seq2 || seq->seq3) {
BKE_sequence_calc(scene, seq);
@@ -2204,7 +2243,8 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
else {
- return OPERATOR_CANCELLED;
+ /* Passthrough to selection if used as tool. */
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
}
@@ -2224,7 +2264,17 @@ static int sequencer_cut_invoke(bContext *C, wmOperator *op, const wmEvent *even
cut_side = SEQ_SIDE_BOTH;
}
}
- RNA_int_set(op->ptr, "frame", cut_frame);
+
+ float mouseloc[2];
+ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
+
+ if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
+ RNA_int_set(op->ptr, "frame", mouseloc[0]);
+ }
+ else {
+ RNA_int_set(op->ptr, "frame", cut_frame);
+ }
+ RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", cut_side);
/*RNA_enum_set(op->ptr, "type", cut_hard); */ /*This type is set from the key shortcut */
return sequencer_cut_exec(C, op);
@@ -2255,19 +2305,43 @@ void SEQUENCER_OT_cut(struct wmOperatorType *ot)
"Frame where selected strips will be cut",
INT_MIN,
INT_MAX);
+ RNA_def_int(ot->srna,
+ "channel",
+ 0,
+ INT_MIN,
+ INT_MAX,
+ "Channel",
+ "Channel in which strip will be cut",
+ INT_MIN,
+ INT_MAX);
RNA_def_enum(ot->srna,
"type",
prop_cut_types,
SEQ_CUT_SOFT,
"Type",
"The type of cut operation to perform on strips");
+ RNA_def_boolean(ot->srna,
+ "use_cursor_position",
+ 0,
+ "Use Cursor Position",
+ "Cut at position of the cursor instead of playhead");
prop = RNA_def_enum(ot->srna,
"side",
prop_side_types,
SEQ_SIDE_MOUSE,
"Side",
"The side that remains selected after cutting");
+
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "ignore_selection",
+ false,
+ "Ignore Selection",
+ "Make cut event if strip is not selected preserving selection state after cut");
+
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
#undef SEQ_SIDE_MOUSE
@@ -2326,9 +2400,6 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* to give to transform */
- RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/* delete operator */
@@ -3153,7 +3224,7 @@ void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
ot->poll = sequencer_strip_jump_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
@@ -4246,5 +4317,5 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index f262c6518aa..b90dc5e10ff 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -123,6 +123,8 @@ static int strip_modifier_remove_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Remove Strip Modifier";
ot->idname = "SEQUENCER_OT_strip_modifier_remove";
@@ -136,7 +138,8 @@ void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+ prop = RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/*********************** Move operator *************************/
@@ -183,6 +186,8 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static const EnumPropertyItem direction_items[] = {
{SEQ_MODIFIER_MOVE_UP, "UP", 0, "Up", "Move modifier up in the stack"},
{SEQ_MODIFIER_MOVE_DOWN, "DOWN", 0, "Down", "Move modifier down in the stack"},
@@ -202,8 +207,10 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
- RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", "");
+ prop = RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/*********************** Copy to selected operator *************************/
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index a51b08f7525..a5bb66ca65f 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -312,7 +312,7 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
ot->poll = sequencer_edit_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
@@ -353,7 +353,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
ot->poll = sequencer_edit_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
}
static int sequencer_select_exec(bContext *C, wmOperator *op)
@@ -647,7 +647,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->poll = ED_operator_sequencer_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
WM_operator_properties_generic_select(ot);
@@ -1086,7 +1086,7 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
ot->poll = ED_operator_sequencer_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
WM_operator_properties_gesture_box(ot);
@@ -1292,7 +1292,7 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
bool changed = false;
SEQP_BEGIN (ed, seq) {
- if (!((seq->startdisp >= actseq->enddisp) || (seq->enddisp < actseq->startdisp))) {
+ if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
seq->flag |= SELECT;
changed = true;
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 6e1b9d62f0e..53202b65838 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -95,6 +95,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS;
+ /* tool header */
+ ar = MEM_callocN(sizeof(ARegion), "tool header for sequencer");
+
+ BLI_addtail(&sseq->regionbase, ar);
+ ar->regiontype = RGN_TYPE_TOOL_HEADER;
+ ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ ar->flag = RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for sequencer");
@@ -110,6 +118,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
ar->alignment = RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
+ /* toolbar */
+ ar = MEM_callocN(sizeof(ARegion), "tools for sequencer");
+
+ BLI_addtail(&sseq->regionbase, ar);
+ ar->regiontype = RGN_TYPE_TOOLS;
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar->flag = RGN_FLAG_HIDDEN;
+
/* preview region */
/* NOTE: if you change values here, also change them in sequencer_init_preview_region */
ar = MEM_callocN(sizeof(ARegion), "preview region for sequencer");
@@ -618,6 +634,23 @@ static void sequencer_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
+/* *********************** toolbar region ************************ */
+/* add handlers, stuff you only do once or on area/region changes */
+static void sequencer_tools_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap;
+
+ ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
+ ED_region_panels_init(wm, ar);
+
+ keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
+ WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
+}
+
+static void sequencer_tools_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
+}
/* *********************** preview region ************************ */
static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *ar)
{
@@ -832,7 +865,7 @@ void ED_spacetype_sequencer(void)
art->draw = sequencer_main_region_draw;
art->listener = sequencer_main_region_listener;
art->message_subscribe = sequencer_main_region_message_subscribe;
- art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
+ art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
BLI_addhead(&st->regiontypes, art);
@@ -842,7 +875,8 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_preview_region_init;
art->draw = sequencer_preview_region_draw;
art->listener = sequencer_preview_region_listener;
- art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
+ art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
+ ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
@@ -850,12 +884,35 @@ void ED_spacetype_sequencer(void)
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH * 1.3f;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+ art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui;
art->listener = sequencer_buttons_region_listener;
art->init = sequencer_buttons_region_init;
art->draw = sequencer_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
sequencer_buttons_register(art);
+ /* regions: tool(bar) */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tools region");
+ art->regionid = RGN_TYPE_TOOLS;
+ art->prefsizex = 58; /* XXX */
+ art->prefsizey = 50; /* XXX */
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+ art->message_subscribe = ED_region_generic_tools_region_message_subscribe;
+ art->snap_size = ED_region_generic_tools_region_snap_size;
+ art->init = sequencer_tools_region_init;
+ art->draw = sequencer_tools_region_draw;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: tool header */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tool header region");
+ art->regionid = RGN_TYPE_TOOL_HEADER;
+ art->prefsizey = HEADERY;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
+ art->listener = sequencer_main_region_listener;
+ art->init = sequencer_header_region_init;
+ art->draw = sequencer_header_region_draw;
+ art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header;
+ BLI_addhead(&st->regiontypes, art);
/* regions: header */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
@@ -869,6 +926,10 @@ void ED_spacetype_sequencer(void)
BLI_addhead(&st->regiontypes, art);
+ /* regions: 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 */
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index 63f27b4d74a..69060daa171 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -81,7 +81,7 @@ static SpaceLink *statusbar_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
static void statusbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
{
- if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) {
+ if (ELEM(RGN_ALIGN_ENUM_FROM_MASK(region->alignment), RGN_ALIGN_RIGHT)) {
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
ED_region_header_init(region);
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index 935e288c7be..6bbb0d529ab 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -66,7 +66,8 @@ static int txtfmt_lua_find_keyword(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
- } else { i = 0; }
+ } else { i = 0;
+ }
/* clang-format on */
@@ -123,7 +124,8 @@ static int txtfmt_lua_find_specialvar(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len;
- } else { i = 0; }
+ } else { i = 0;
+ }
/* clang-format on */
@@ -144,7 +146,8 @@ static int txtfmt_lua_find_bool(const char *string)
if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
- } else { i = 0; }
+ } else { i = 0;
+ }
/* clang-format on */
@@ -164,7 +167,8 @@ static char txtfmt_lua_format_identifier(const char *str)
if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_lua_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
- } else { fmt = FMT_TYPE_DEFAULT; }
+ } else { fmt = FMT_TYPE_DEFAULT;
+ }
/* clang-format on */
@@ -308,9 +312,9 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_
/* Special vars(v) or built-in keywords(b) */
/* keep in sync with 'txtfmt_osl_format_identifier()' */
- if ((i = txtfmt_lua_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
+ if ((i = txtfmt_lua_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_lua_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
-}
+ }
/* clang-format on */
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index 2da4488e901..0275a293e7a 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -64,8 +64,8 @@ static int txtfmt_osl_find_builtinfunc(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "vector", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "void", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -122,8 +122,8 @@ static int txtfmt_osl_find_reserved(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "varying", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "virtual", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "volatile", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -153,8 +153,8 @@ static int txtfmt_osl_find_specialvar(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -193,8 +193,8 @@ static char txtfmt_osl_format_identifier(const char *str)
} else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
} else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED;
} else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE;
- } else { fmt = FMT_TYPE_DEFAULT;
-}
+ } else { fmt = FMT_TYPE_DEFAULT;
+ }
/* clang-format on */
@@ -327,7 +327,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
} else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
} else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
-}
+ }
/* clang-format on */
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
index 21df7b5b76a..13830aa7c4d 100644
--- a/source/blender/editors/space_text/text_format_pov.c
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -80,8 +80,8 @@ static int txtfmt_pov_find_keyword(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "end", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "for", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "if", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -239,8 +239,8 @@ static int txtfmt_pov_find_reserved_keywords(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "chr", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "str", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -475,8 +475,8 @@ static int txtfmt_pov_find_reserved_builtins(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "x", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "y", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "z", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format off */
@@ -695,8 +695,8 @@ static int txtfmt_pov_find_specialvar(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "edwards", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "peters", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "gall", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* If next source char is an identifier (eg. 'i' in "definite") no match */
return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
@@ -746,8 +746,8 @@ static int txtfmt_pov_find_bool(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "sys", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "tga", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -762,12 +762,12 @@ static char txtfmt_pov_format_identifier(const char *str)
/* Keep aligned args for readability. */
/* clang-format off */
- if ((txtfmt_pov_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
+ if ((txtfmt_pov_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_pov_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
} else if ((txtfmt_pov_find_reserved_keywords(str)) != -1) { fmt = FMT_TYPE_RESERVED;
} else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE;
- } else { fmt = FMT_TYPE_DEFAULT;
-}
+ } else { fmt = FMT_TYPE_DEFAULT;
+ }
/* clang-format on */
@@ -905,11 +905,11 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_
/* Special vars(v) or built-in keywords(b) */
/* keep in sync with 'txtfmt_pov_format_identifier()' */
- if ((i = txtfmt_pov_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
+ if ((i = txtfmt_pov_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_pov_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) { prev = FMT_TYPE_RESERVED;
} else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
-}
+ }
/* clang-format on */
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
index b349b38e551..08f6d10ac6d 100644
--- a/source/blender/editors/space_text/text_format_pov_ini.c
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -91,8 +91,8 @@ static int txtfmt_ini_find_keyword(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "P", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "T", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -304,8 +304,8 @@ static int txtfmt_ini_find_reserved(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -335,8 +335,8 @@ static int txtfmt_ini_find_bool(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "%k", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "%h", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "%w", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -483,7 +483,7 @@ static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool
/* Special vars(v) or built-in keywords(b) */
/* keep in sync with 'txtfmt_ini_format_identifier()' */
- if ((i = txtfmt_ini_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
+ if ((i = txtfmt_ini_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_ini_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
}
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index d84beb79be6..48c522c5e1b 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -88,8 +88,8 @@ static int txtfmt_py_find_builtinfunc(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "with", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "yield", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -114,10 +114,10 @@ static int txtfmt_py_find_specialvar(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "class", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0;
+ }
/* clang-format on */
@@ -155,11 +155,11 @@ static int txtfmt_py_find_bool(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "True", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "False", len)) { i = len;
- } else { i = 0;
-}
+ if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "True", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "False", len)) { i = len;
+ } else { i = 0;
+ }
/* clang-format on */
@@ -170,6 +170,144 @@ static int txtfmt_py_find_bool(const char *string)
return i;
}
+/* Numeral character matching. */
+#define TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL(txtfmt_py_numeral_char_is_fn) \
+ { \
+ uint count = 0; \
+ for (; txtfmt_py_numeral_char_is_fn(*string); string += 1) { \
+ count += 1; \
+ } \
+ return count; \
+ } \
+ ((void)0)
+
+/* Binary. */
+static bool txtfmt_py_numeral_char_is_binary(const char c)
+{
+ return ELEM(c, '0', '1') || (c == '_');
+}
+static uint txtfmt_py_numeral_string_count_binary(const char *string)
+{
+ TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL(txtfmt_py_numeral_char_is_binary);
+}
+
+/* Octal. */
+static bool txtfmt_py_numeral_char_is_octal(const char c)
+{
+ return (c >= '0' && c <= '7') || (c == '_');
+}
+static uint txtfmt_py_numeral_string_count_octal(const char *string)
+{
+ TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL(txtfmt_py_numeral_char_is_octal);
+}
+
+/* Decimal. */
+static bool txtfmt_py_numeral_char_is_decimal(const char c)
+{
+ return (c >= '0' && c <= '9') || (c == '_');
+}
+static uint txtfmt_py_numeral_string_count_decimal(const char *string)
+{
+ TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL(txtfmt_py_numeral_char_is_decimal);
+}
+
+/* Hexadecimal. */
+static bool txtfmt_py_numeral_char_is_hexadecimal(const char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c == '_');
+}
+static uint txtfmt_py_numeral_string_count_hexadecimal(const char *string)
+{
+ TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL(txtfmt_py_numeral_char_is_hexadecimal);
+}
+
+/* Zeros. */
+static bool txtfmt_py_numeral_char_is_zero(const char c)
+{
+ return (c == '0') || (c == '_');
+}
+static uint txtfmt_py_numeral_string_count_zeros(const char *string)
+{
+ TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL(txtfmt_py_numeral_char_is_zero);
+}
+
+#undef TXTFMT_PY_NUMERAL_STRING_COUNT_IMPL
+
+static int txtfmt_py_find_numeral_inner(const char *string)
+{
+ if (string == NULL || *string == '\0') {
+ return -1;
+ }
+
+ const char first = *string, second = *(string + 1);
+
+ /* Decimal dot must be followed by a digit, any decimal digit.
+ * Note that the there can be any number of leading zeros after
+ * the decimal point (leading zeros are not allowed in integers) */
+ if (first == '.') {
+ if (text_check_digit(second)) {
+ return 1 + txtfmt_py_numeral_string_count_decimal(string + 1);
+ }
+ }
+ else if (first == '0') {
+ /* Numerals starting with '0x' or '0X' is followed by hexadecimal digits. */
+ if (ELEM(second, 'x', 'X')) {
+ return 2 + txtfmt_py_numeral_string_count_hexadecimal(string + 2);
+ }
+ /* Numerals starting with '0o' or '0O' is followed by octal digits. */
+ if (ELEM(second, 'o', 'O')) {
+ return 2 + txtfmt_py_numeral_string_count_octal(string + 2);
+ }
+ /* Numerals starting with '0b' or '0B' is followed by binary digits. */
+ if (ELEM(second, 'b', 'B')) {
+ return 2 + txtfmt_py_numeral_string_count_binary(string + 2);
+ }
+ /* Other numerals starting with '0' can be followed by any number of '0' characters. */
+ if (ELEM(second, '0', '_')) {
+ return 2 + txtfmt_py_numeral_string_count_zeros(string + 2);
+ }
+ }
+ /* Any non-zero digit is the start of a decimal number. */
+ else if (first > '0' && first <= '9') {
+ return 1 + txtfmt_py_numeral_string_count_decimal(string + 1);
+ }
+ /* A single zero is also allowed. */
+ return (first == '0') ? 1 : 0;
+}
+
+static int txtfmt_py_literal_numeral(const char *string, char prev_fmt)
+{
+ if (string == NULL || *string == '\0') {
+ return -1;
+ }
+
+ const char first = *string, second = *(string + 1);
+
+ if (prev_fmt == FMT_TYPE_NUMERAL) {
+ /* Previous was a number; if immediately followed by 'e' or 'E' and a digit,
+ * it's a base 10 exponent (scientific notation). */
+ if (ELEM(first, 'e', 'E') && (text_check_digit(second) || second == '-')) {
+ return 1 + txtfmt_py_find_numeral_inner(string + 1);
+ }
+ /* Previous was a number; if immediately followed by '.' it's a floating point decimal number.
+ * Note: keep the decimal point, it's needed to allow leading zeros. */
+ if ((prev_fmt == FMT_TYPE_NUMERAL) && (first == '.')) {
+ return txtfmt_py_find_numeral_inner(string);
+ }
+ /* "Imaginary" part of a complex number ends with 'j' */
+ if (ELEM(first, 'j', 'J') && !text_check_digit(second)) {
+ return 1;
+ }
+ }
+ else if ((prev_fmt != FMT_TYPE_DEFAULT) &&
+ (text_check_digit(first) || (first == '.' && text_check_digit(second)))) {
+ /* New numeral, starting with a digit or a decimal point followed by a digit. */
+ return txtfmt_py_find_numeral_inner(string);
+ }
+ /* Not a literal numeral. */
+ return 0;
+}
+
static char txtfmt_py_format_identifier(const char *str)
{
char fmt;
@@ -177,11 +315,11 @@ static char txtfmt_py_format_identifier(const char *str)
/* Keep aligned args for readability. */
/* clang-format off */
- if ((txtfmt_py_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
+ if ((txtfmt_py_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_py_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
} else if ((txtfmt_py_find_decorator(str)) != -1) { fmt = FMT_TYPE_RESERVED;
- } else { fmt = FMT_TYPE_DEFAULT;
-}
+ } else { fmt = FMT_TYPE_DEFAULT;
+ }
/* clang-format on */
return fmt;
@@ -289,10 +427,9 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
- /* Numbers (digits not part of an identifier and periods followed by digits) */
- else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
- (*str == '.' && text_check_digit(*(str + 1)))) {
- *fmt = FMT_TYPE_NUMERAL;
+ /* Literal numerals, "numbers". */
+ else if ((i = txtfmt_py_literal_numeral(str, prev)) > 0) {
+ text_format_fill(&str, &fmt, FMT_TYPE_NUMERAL, i);
}
/* Booleans */
else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_py_find_bool(str)) != -1) {
@@ -320,10 +457,10 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
/* Special vars(v) or built-in keywords(b) */
/* keep in sync with 'txtfmt_py_format_identifier()' */
- if ((i = txtfmt_py_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
+ if ((i = txtfmt_py_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_py_find_decorator(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
-}
+ }
/* clang-format on */
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 725a49e417e..d62fcf45d68 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -103,7 +103,7 @@ static void topbar_main_region_init(wmWindowManager *wm, ARegion *region)
wmKeyMap *keymap;
/* force delayed UI_view2d_region_reinit call */
- if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) {
+ if (ELEM(RGN_ALIGN_ENUM_FROM_MASK(region->alignment), RGN_ALIGN_RIGHT)) {
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
@@ -123,7 +123,7 @@ static void topbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
/* add handlers, stuff you only do once or on area/region changes */
static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
- if ((ar->alignment & ~RGN_SPLIT_PREV) == RGN_ALIGN_RIGHT) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT) {
ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
ED_region_header_init(ar);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 76d9065905a..e2d32181bb3 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1032,19 +1032,9 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
}
}
-/* concept is to retrieve cursor type context-less */
static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
- if (WM_cursor_set_from_tool(win, sa, ar)) {
- 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 {
+ if (!WM_cursor_set_from_tool(win, sa, ar)) {
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index d40f79cea3f..83fb87264e3 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -158,6 +158,12 @@ typedef struct ViewOpsData {
float trackvec[3];
/** Dolly only. */
float mousevec[3];
+
+ /**
+ * #RegionView3D.persp set after auto-perspective is applied.
+ * If we want the value before running the operator, add a separate member.
+ */
+ char persp;
} init;
/** Previous state (previous modal event handled). */
@@ -413,6 +419,7 @@ static void viewops_data_create(bContext *C,
* we may want to make this optional but for now its needed always */
ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d);
+ vod->init.persp = rv3d->persp;
vod->init.dist = rv3d->dist;
vod->init.camzoom = rv3d->camzoom;
copy_qt_qt(vod->init.quat, rv3d->viewquat);
@@ -613,6 +620,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
float zaxis_best[3];
int x, y, z;
bool found = false;
+ bool is_axis_aligned = false;
invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat);
@@ -630,6 +638,10 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) {
copy_v3_v3(zaxis_best, zaxis_test);
found = true;
+
+ if (abs(x) + abs(y) + abs(z) == 1) {
+ is_axis_aligned = true;
+ }
}
}
}
@@ -700,6 +712,17 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
copy_qt_qt(rv3d->viewquat, quat_best);
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
+
+ if (U.uiflag & USER_AUTOPERSP) {
+ if (is_axis_aligned) {
+ if (rv3d->persp == RV3D_PERSP) {
+ rv3d->persp = RV3D_ORTHO;
+ }
+ }
+ }
+ }
+ else if (U.uiflag & USER_AUTOPERSP) {
+ rv3d->persp = vod->init.persp;
}
}
@@ -758,7 +781,32 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
quat_to_mat3(m, vod->curr.viewquat);
invert_m3_m3(m_inv, m);
- /* avoid gimble lock */
+ /* Avoid Gimble Lock
+ *
+ * Even though turn-table mode is in use, this can occur when the user exits the camera view
+ * or when aligning the view to a rotated object.
+ *
+ * We have gimble lock when the user's view is rotated +/- 90 degrees along the view axis.
+ * In this case the vertical rotation is the same as the sideways turntable motion.
+ * Making it impossible to get out of the gimble locked state without resetting the view.
+ *
+ * The logic below lets the user exit out of this state without any abrupt 'fix'
+ * which would be disorienting.
+ *
+ * This works by blending two horizons:
+ * - Rotated-horizon: `cross_v3_v3v3(xaxis, zvec_global, m_inv[2])`
+ * When only this is used, this turntable rotation works - but it's side-ways
+ * (as if the entire turn-table has been placed on it's side)
+ * While there is no gimble lock, it's also awkward to use.
+ * - Un-rotated-horizon: `m_inv[0]`
+ * When only this is used, the turntable rotation can have gimbal lock.
+ *
+ * The solution used here is to blend between these two values,
+ * so the severity of the gimbal lock is used to blend the rotated horizon.
+ * Blending isn't essential, it just makes the transition smoother.
+ *
+ * This allows sideways turn-table rotation on a Z axis that isn't world-space Z,
+ * While up-down turntable rotation eventually corrects gimble lock. */
#if 1
if (len_squared_v3v3(zvec_global, m_inv[2]) > 0.001f) {
float fac;
@@ -834,6 +882,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
event_code = VIEW_APPLY;
break;
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
+ vod->rv3d->persp = vod->init.persp;
vod->axis_snap = false;
event_code = VIEW_APPLY;
break;
@@ -1448,10 +1497,20 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const bool is_orbit_around_pivot = (U.ndof_flag & NDOF_MODE_ORBIT) ||
ED_view3d_offset_lock_check(v3d, rv3d);
const bool has_rotation = ndof_has_rotate(ndof, rv3d);
- const bool has_translate = !is_zero_v2(ndof->tvec) && ndof_has_translate(ndof, v3d, rv3d);
- const bool has_zoom = (ndof->tvec[2] != 0.0f);
+ bool has_translate, has_zoom;
- /* Rotation first because dynamic offset resets offset otherwise (and disasbles panning). */
+ if (is_orbit_around_pivot) {
+ /* Orbit preference or forced lock (Z zooms). */
+ has_translate = !is_zero_v2(ndof->tvec) && ndof_has_translate(ndof, v3d, rv3d);
+ has_zoom = (ndof->tvec[2] != 0.0f);
+ }
+ else {
+ /* Free preference (Z translates). */
+ has_translate = ndof_has_translate(ndof, v3d, rv3d);
+ has_zoom = false;
+ }
+
+ /* Rotation first because dynamic offset resets offset otherwise (and disables panning). */
if (has_rotation) {
const float dist_backup = rv3d->dist;
if (!is_orbit_around_pivot) {
@@ -4944,6 +5003,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
.use_object_edit_cage = false,
+ .use_occlusion_test = true,
},
mval_fl,
NULL,
@@ -4957,10 +5017,9 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
copy_v3_v3(cursor_co, ray_co);
}
- float tquat[4];
-
/* Math normal (Z). */
{
+ float tquat[4];
float z_src[3] = {0, 0, 1};
mul_qt_v3(cursor_quat, z_src);
rotation_between_vecs_to_quat(tquat, z_src, ray_no);
@@ -4975,13 +5034,34 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
dot_v3v3(ray_no, obmat[2]),
};
const int ortho_axis = axis_dominant_v3_ortho_single(ortho_axis_dot);
- float x_src[3] = {1, 0, 0};
- float x_dst[3];
- mul_qt_v3(cursor_quat, x_src);
- project_plane_v3_v3v3(x_dst, obmat[ortho_axis], ray_no);
- normalize_v3(x_dst);
- rotation_between_vecs_to_quat(tquat, x_src, x_dst);
- mul_qt_qtqt(cursor_quat, tquat, cursor_quat);
+
+ float tquat_best[4];
+ float angle_best = -1.0f;
+
+ float tan_dst[3];
+ project_plane_v3_v3v3(tan_dst, obmat[ortho_axis], ray_no);
+ normalize_v3(tan_dst);
+
+ /* As the tangent is arbitrary from the users point of view,
+ * make the cursor 'roll' on the shortest angle.
+ * otherwise this can cause noticeable 'flipping', see T72419. */
+ for (int axis = 0; axis < 2; axis++) {
+ float tan_src[3] = {0, 0, 0};
+ tan_src[axis] = 1.0f;
+ mul_qt_v3(cursor_quat, tan_src);
+
+ for (int axis_sign = 0; axis_sign < 2; axis_sign++) {
+ float tquat_test[4];
+ rotation_between_vecs_to_quat(tquat_test, tan_src, tan_dst);
+ const float angle_test = angle_normalized_qt(tquat_test);
+ if (angle_test < angle_best || angle_best == -1.0f) {
+ angle_best = angle_test;
+ copy_qt_qt(tquat_best, tquat_test);
+ }
+ negate_v3(tan_src);
+ }
+ }
+ mul_qt_qtqt(cursor_quat, tquat_best, cursor_quat);
}
}
ED_transform_snap_object_context_destroy(snap_context);
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 504b10888e8..75ab6518a4f 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -515,12 +515,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
return -1;
}
-static int gizmo_axis_cursor_get(wmGizmo *gz)
+static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz))
{
- if (gz->highlight_part > 0) {
- return WM_CURSOR_EDIT;
- }
- return WM_CURSOR_NSEW_SCROLL;
+ return WM_CURSOR_DEFAULT;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
index 8cd5ed7a478..75d0384182b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
@@ -22,6 +22,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "ED_screen.h"
#include "ED_transform.h"
@@ -52,10 +53,6 @@ static const char *handle_free_id;
static bool WIDGETGROUP_tool_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
- if (!USER_EXPERIMENTAL_TEST(&U, use_tool_fallback)) {
- return false;
- }
-
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
@@ -65,6 +62,11 @@ static bool WIDGETGROUP_tool_generic_poll(const bContext *C, wmGizmoGroupType *g
return false;
}
+ /* Without this, refreshing the gizmo jitters in some cases with edit-mesh smooth. See T72948. */
+ if (G.moving & G_TRANSFORM_EDIT) {
+ return false;
+ }
+
return true;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 092142a83cd..89baf60bd8c 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1785,7 +1785,13 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
return hits;
}
-/* returns basact */
+/**
+ * \param has_bones: When true, skip non-bone hits, also allow bases to be used
+ * that are visible but not select-able,
+ * since you may be in pose mode with an an unselect-able object.
+ *
+ * \return the active base or NULL.
+ */
static Base *mouse_select_eval_buffer(ViewContext *vc,
const uint *buffer,
int hits,
@@ -1827,7 +1833,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
base = FIRSTBASE(view_layer);
while (base) {
- if (BASE_SELECTABLE(v3d, base)) {
+ if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
if (base->object->runtime.select_id == selcol) {
break;
}
@@ -1844,7 +1850,8 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
while (base) {
/* skip objects with select restriction, to prevent prematurely ending this loop
* with an un-selectable choice */
- if ((base->flag & BASE_SELECTABLE) == 0) {
+ if (has_bones ? (base->flag & BASE_VISIBLE_VIEWLAYER) == 0 :
+ (base->flag & BASE_SELECTABLE) == 0) {
base = base->next;
if (base == NULL) {
base = FIRSTBASE(view_layer);
@@ -1854,7 +1861,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
}
}
- if (BASE_SELECTABLE(v3d, base)) {
+ if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
for (a = 0; a < hits; a++) {
if (has_bones) {
/* skip non-bone objects */
@@ -2077,7 +2084,8 @@ static bool ed_object_select_pick(bContext *C,
if (has_bones && basact) {
if (basact->object->type == OB_CAMERA) {
- if (oldbasact == basact) {
+ MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
+ if (clip != NULL && oldbasact == basact) {
int i, hitresult;
bool changed = false;
@@ -2094,7 +2102,6 @@ static bool ed_object_select_pick(bContext *C,
* in height word, this buffer value belongs to camera. not to bundle
*/
if (buffer[4 * i + 3] & 0xFFFF0000) {
- MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase;
MovieTrackingTrack *track;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 35a116dc4b3..f13f41779c2 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -61,14 +61,16 @@
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]);
static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
-/* *********************** operators ******************** */
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Grid Operator
+ * \{ */
/** Snaps every individual object center to its nearest point on the grid. */
static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
- Object *obedit = CTX_data_edit_object(C);
+ Object *obact = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
RegionView3D *rv3d = CTX_wm_region_data(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -79,13 +81,13 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
- if (obedit) {
+ if (OBEDIT_FROM_OBACT(obact)) {
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++) {
- obedit = objects[ob_index];
+ Object *obedit = objects[ob_index];
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -122,91 +124,117 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
}
MEM_freeN(objects);
}
- else {
+ else if (OBPOSE_FROM_OBACT(obact)) {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
-
- FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
+ uint objects_len = 0;
+ Object **objects_eval = BKE_object_pose_array_get(view_layer_eval, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_eval = objects_eval[ob_index];
Object *ob = DEG_get_original_object(ob_eval);
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan_eval;
- bArmature *arm_eval = ob_eval->data;
-
- invert_m4_m4(ob_eval->imat, ob_eval->obmat);
-
- for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval;
- pchan_eval = pchan_eval->next) {
- if (pchan_eval->bone->flag & BONE_SELECTED) {
- if (pchan_eval->bone->layer & arm_eval->layer) {
- if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
- float nLoc[3];
-
- /* get nearest grid point to snap to */
- copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
- /* We must operate in world space! */
- mul_m4_v3(ob_eval->obmat, nLoc);
- vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
- vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
- vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
- /* Back in object space... */
- mul_m4_v3(ob_eval->imat, vec);
-
- /* Get location of grid point in pose space. */
- BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
-
- /* adjust location on the original pchan*/
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
- pchan->loc[0] = vec[0];
- }
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
- pchan->loc[1] = vec[1];
- }
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
- pchan->loc[2] = vec[2];
- }
-
- /* auto-keyframing */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ bPoseChannel *pchan_eval;
+ bArmature *arm_eval = ob_eval->data;
+
+ invert_m4_m4(ob_eval->imat, ob_eval->obmat);
+
+ for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) {
+ if (pchan_eval->bone->flag & BONE_SELECTED) {
+ if (pchan_eval->bone->layer & arm_eval->layer) {
+ if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
+ float nLoc[3];
+
+ /* get nearest grid point to snap to */
+ copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
+ /* We must operate in world space! */
+ mul_m4_v3(ob_eval->obmat, nLoc);
+ vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
+ vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
+ vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
+ /* Back in object space... */
+ mul_m4_v3(ob_eval->imat, vec);
+
+ /* Get location of grid point in pose space. */
+ BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
+
+ /* adjust location on the original pchan*/
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
+ pchan->loc[0] = vec[0];
}
- /* if the bone has a parent and is connected to the parent,
- * don't do anything - will break chain unless we do auto-ik.
- */
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
+ pchan->loc[1] = vec[1];
+ }
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
+ pchan->loc[2] = vec[2];
+ }
+
+ /* auto-keyframing */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
}
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
}
}
- ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
- else {
- vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
- vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
- vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
+ ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
- if (ob->parent) {
- float originmat[3][3];
- BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ MEM_freeN(objects_eval);
+ }
+ else {
+ /* Object mode. */
+ Main *bmain = CTX_data_main(C);
- invert_m3_m3(imat, originmat);
- mul_m3_v3(imat, vec);
- }
- if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
- ob->loc[0] = ob_eval->loc[0] + vec[0];
- }
- if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
- ob->loc[1] = ob_eval->loc[1] + vec[1];
- }
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
- ob->loc[2] = ob_eval->loc[2] + vec[2];
- }
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
- /* auto-keyframing */
- ED_autokeyframe_object(C, scene, ob, ks);
+ const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ SCE_XFORM_DATA_ORIGIN);
+ struct XFormObjectData_Container *xds = NULL;
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ if (use_transform_data_origin) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ xds = ED_object_data_xform_container_create();
+ }
+
+ FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
+ Object *ob = DEG_get_original_object(ob_eval);
+ vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
+ vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
+ vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
+
+ if (ob->parent) {
+ float originmat[3][3];
+ BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
+
+ invert_m3_m3(imat, originmat);
+ mul_m3_v3(imat, vec);
+ }
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] = ob_eval->loc[0] + vec[0];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] = ob_eval->loc[1] + vec[1];
}
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] = ob_eval->loc[2] + vec[2];
+ }
+
+ /* auto-keyframing */
+ ED_autokeyframe_object(C, scene, ob, ks);
+
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_item_ensure(xds, ob);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
FOREACH_SELECTED_EDITABLE_OBJECT_END;
+
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_update_all(xds, bmain, depsgraph);
+ ED_object_data_xform_container_destroy(xds);
+ }
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -229,7 +257,11 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Location (Utility)
+ * \{ */
/**
* Snaps the selection as a whole (use_offset=true) or each selected object to the given location.
@@ -317,12 +349,12 @@ static int snap_selected_to_location(bContext *C,
}
MEM_freeN(objects);
}
- else if (obact && (obact->mode & OB_MODE_POSE)) {
+ else if (OBPOSE_FROM_OBACT(obact)) {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ Object **objects = BKE_object_pose_array_get(view_layer, v3d, &objects_len);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
bPoseChannel *pchan;
@@ -393,6 +425,7 @@ static int snap_selected_to_location(bContext *C,
else {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ListBase ctx_data_list;
CollectionPointerLink *ctx_ob;
@@ -411,6 +444,22 @@ static int snap_selected_to_location(bContext *C,
ob->flag |= OB_DONE;
}
+ const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
+ SCE_XFORM_DATA_ORIGIN);
+ struct XFormObjectData_Container *xds = NULL;
+
+ if (use_transform_data_origin) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ xds = ED_object_data_xform_container_create();
+
+ /* Initialize the transform data in a separate loop because the depsgraph
+ * may be evaluated while setting the locations. */
+ for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ ob = ctx_ob->ptr.data;
+ ED_object_data_xform_container_item_ensure(xds, ob);
+ }
+ }
+
for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
ob = ctx_ob->ptr.data;
@@ -431,7 +480,7 @@ static int snap_selected_to_location(bContext *C,
float originmat[3][3], parentmat[4][4];
/* Use the evaluated object here because sometimes
* `ob->parent->runtime.curve_cache` is required. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
@@ -457,6 +506,11 @@ static int snap_selected_to_location(bContext *C,
}
BLI_freelistN(&ctx_data_list);
+
+ if (use_transform_data_origin) {
+ ED_object_data_xform_container_update_all(xds, bmain, depsgraph);
+ ED_object_data_xform_container_destroy(xds);
+ }
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -464,6 +518,12 @@ static int snap_selected_to_location(bContext *C,
return OPERATOR_FINISHED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Cursor Operator
+ * \{ */
+
static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
{
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
@@ -497,7 +557,11 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
"If the selection should be snapped as a whole or by each object center");
}
-/* *************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection to Active Operator
+ * \{ */
/** Snaps each selected object to the location of the active selected object. */
static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
@@ -527,7 +591,11 @@ void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Grid Operator
+ * \{ */
/** Snaps the 3D cursor location to its nearest point on the grid. */
static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
@@ -565,7 +633,11 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* **************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Selection Operator
+ * \{ */
/**
* Returns the center position of a tracking marker visible on the viewport
@@ -761,7 +833,11 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Active Operator
+ * \{ */
/**
* Calculates the center position of the active object in global space.
@@ -809,7 +885,11 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* **************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor to Center Operator
+ * \{ */
/** Snaps the 3D cursor location to the origin and clears cursor rotation. */
static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op))
@@ -842,7 +922,11 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* **************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Min/Max Object Vertices Utility
+ * \{ */
/**
* Calculates the bounding box corners (min and max) for \a obedit.
@@ -890,3 +974,5 @@ bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
return true;
}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 494e7529975..34470896fb9 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -676,7 +676,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
return;
}
- if ((walk->is_cursor_absolute == false) && event->is_motion_absolute) {
+ if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) {
walk->is_cursor_absolute = true;
copy_v2_v2_int(walk->prev_mval, event->mval);
copy_v2_v2_int(walk->center_mval, event->mval);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 7112444655b..ec39b457082 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -856,7 +856,7 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
if (t->spacetype != SPACE_VIEW3D) {
return false;
}
- else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) {
+ else if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) {
return false;
}
else if (!validSnap(t)) {
@@ -2479,7 +2479,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else if (!do_skip) {
const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
if (preserve_clnor) {
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_lnorspace_update(em, tc->obedit->data);
t->flag |= T_CLNOR_REBUILD;
}
BM_lnorspace_invalidate(em->bm, true);
@@ -2561,7 +2561,7 @@ int transformEnd(bContext *C, TransInfo *t)
/* aftertrans does insert keyframes, and clears base flags; doesn't read transdata */
special_aftertrans_update(C, t);
- /* free data */
+ /* Free data, also handles overlap [in freeTransCustomData()]. */
postTrans(C, t);
/* send events out for redraws */
@@ -4657,8 +4657,8 @@ static void initNormalRotation(TransInfo *t)
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ BKE_editmesh_ensure_autosmooth(em, tc->obedit->data);
+ BKE_editmesh_lnorspace_update(em, tc->obedit->data);
storeCustomLNorValue(tc, bm);
}
@@ -8777,9 +8777,10 @@ static void applyTimeTranslateValue(TransInfo *t, float value)
/* It doesn't matter whether we apply to t->data or
* t->data2d, but t->data2d is more convenient. */
for (i = 0; i < tc->data_len; i++, td++, td2d++) {
- /* it is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from
+ /* It is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from.
* (this is only valid when not in NLA)
+ * (also: masks and gpencil dont have animadata)
*/
AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
@@ -8810,7 +8811,7 @@ static void applyTimeTranslateValue(TransInfo *t, float value)
val = floorf(val + 0.5f);
}
- *(td->val) = td->ival + val;
+ *(td->val) = td->ival + val * td->factor;
}
/* apply nearest snapping */
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index db8f36883f8..869c23de74c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -450,20 +450,15 @@ 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 */
@@ -1350,6 +1345,15 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
return true;
}
}
+ else if (con->type == CONSTRAINT_TYPE_ACTION) {
+ /* The Action constraint only does this in the Before mode. */
+ bActionConstraint *data = (bActionConstraint *)con->data;
+
+ if (ELEM(data->mix_mode, ACTCON_MIX_BEFORE) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) {
+ return true;
+ }
+ }
else if (con->type == CONSTRAINT_TYPE_TRANSFORM) {
/* Transform constraint needs it for rotation at least (r.57309),
* but doing so when translating may also mess things up [#36203]
@@ -1888,8 +1892,8 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
- /* marker transform, not especially nice but we may want to move markers
- * at the same time as keyframes in the dope sheet. */
+ /* Marker transform, not especially nice but we may want to move markers
+ * at the same time as strips in the Video Sequencer. */
if ((sseq->flag & SEQ_MARKER_TRANS) && (canceled == 0)) {
/* cant use TFM_TIME_EXTEND
* for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index cc023688c8e..0edf55ece7e 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -86,6 +86,7 @@ static void add_pose_transdata(
td->flag |= TD_NO_LOC;
}
+ td->extra = pchan;
td->protectflag = pchan->protectflag;
td->loc = pchan->loc;
@@ -364,7 +365,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
* (but they must be selected, and only one ik-solver per chain should get added) */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone->layer & arm->layer) {
- if (pchan->bone->flag & BONE_SELECTED) {
+ if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
/* Rule: no IK for solitatry (unconnected) bones */
for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
if (bonec->flag & BONE_CONNECTED) {
@@ -379,7 +380,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
if (pchan->parent) {
/* only adds if there's no IK yet (and no parent bone was selected) */
for (parent = pchan->parent; parent; parent = parent->parent) {
- if (parent->bone->flag & BONE_SELECTED) {
+ if (parent->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
break;
}
}
@@ -513,14 +514,6 @@ void createTransPose(TransInfo *t)
}
}
- /* do we need to add temporal IK chains? */
- if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
- if (pose_grab_with_ik(bmain, ob)) {
- t->flag |= T_AUTOIK;
- has_translate_rotate[0] = true;
- }
- }
-
if (mirror) {
int total_mirrored = 0;
for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -541,16 +534,6 @@ void createTransPose(TransInfo *t)
}
}
- /* if there are no translatable bones, do rotation */
- if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
- if (has_translate_rotate[1]) {
- t->mode = TFM_ROTATION;
- }
- else {
- t->mode = TFM_RESIZE;
- }
- }
-
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->data_len == 0) {
continue;
@@ -582,20 +565,32 @@ void createTransPose(TransInfo *t)
td->val = NULL;
}
- /* use pose channels to fill trans data */
- td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, pchan, ob, tc, td);
-
- if (mirror) {
+ if (mirror) {
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
if (pchan_mirror) {
+ pchan_mirror->bone->flag |= BONE_TRANSFORM_MIRROR;
pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative);
pid_index++;
}
}
+ }
+ }
+ /* do we need to add temporal IK chains? */
+ if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) {
+ if (pose_grab_with_ik(bmain, ob)) {
+ t->flag |= T_AUTOIK;
+ has_translate_rotate[0] = true;
+ }
+ }
+
+ /* use pose channels to fill trans data */
+ td = tc->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ add_pose_transdata(t, pchan, ob, tc, td);
td++;
}
}
@@ -603,10 +598,20 @@ void createTransPose(TransInfo *t)
if (td != (tc->data + tc->data_len)) {
BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
}
+ }
- /* initialize initial auto=ik chainlen's? */
- if (t->flag & T_AUTOIK) {
- transform_autoik_update(t, 0);
+ /* initialize initial auto=ik chainlen's? */
+ if (t->flag & T_AUTOIK) {
+ transform_autoik_update(t, 0);
+ }
+
+ /* if there are no translatable bones, do rotation */
+ if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
+ if (has_translate_rotate[1]) {
+ t->mode = TFM_ROTATION;
+ }
+ else {
+ t->mode = TFM_RESIZE;
}
}
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 234e383be5f..80c0afc3f56 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -63,6 +63,10 @@ static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
void createTransGPencil(bContext *C, TransInfo *t)
{
+ if (t->data_container_len == 0) {
+ return;
+ }
+
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 8b7dcecf9e8..5d3d1d936a2 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1451,7 +1451,8 @@ void createTransUVs(bContext *C, TransInfo *t)
if (is_prop_connected || is_island_center) {
/* create element map with island information */
const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ const bool use_uvsel = !is_prop_connected;
+ elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, use_uvsel, false, true);
if (elementmap == NULL) {
continue;
}
@@ -1547,16 +1548,17 @@ void createTransUVs(bContext *C, TransInfo *t)
if (is_prop_connected || is_island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
-
- if (is_prop_connected) {
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
+ if (element) {
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
}
- }
- if (is_island_center) {
- center = island_center[element->island].co;
+ if (is_island_center) {
+ center = island_center[element->island].co;
+ }
}
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 86b6ebe3ffa..4baf0e8a3cb 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -381,6 +381,10 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
if (overlap) {
+ const bool use_sync_markers = (((SpaceSeq *)t->sa->spacedata.first)->flag &
+ SEQ_MARKER_TRANS) != 0;
+ ListBase *markers = &t->scene->markers;
+
bool has_effect_root = false, has_effect_any = false;
for (seq = seqbasep->first; seq; seq = seq->next) {
seq->tmp = NULL;
@@ -425,7 +429,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
}
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->machine >= MAXSEQ * 2) {
@@ -437,10 +441,10 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
}
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
}
else {
- BKE_sequence_base_shuffle_time(seqbasep, t->scene);
+ BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
}
if (has_effect_any) {
diff --git a/source/blender/editors/transform/transform_draw.c b/source/blender/editors/transform/transform_draw.c
deleted file mode 100644
index e44442b7e49..00000000000
--- a/source/blender/editors/transform/transform_draw.c
+++ /dev/null
@@ -1,114 +0,0 @@
-
-/* -------------------------------------------------------------------- */
-/** \name Auto-Key (Pixel Space)
- * \{ */
-
-/* just draw a little warning message in the top-right corner of the viewport
- * to warn that autokeying is enabled */
-static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
-{
- const char *printable = IFACE_("Auto Keying On");
- float printable_size[2];
- int xco, yco;
-
- const rcti *rect = ED_region_visible_rect(ar);
-
- const int font_id = BLF_default();
- BLF_width_and_height(
- font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
-
- xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
- yco = (rect->ymax - U.widget_unit);
-
- /* 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];
- UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
- BLF_color3ubv(font_id, color);
-#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
-
- /* autokey recording icon... */
- 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_REC);
-
- GPU_blend(false);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Constraints (View Space)
- * \{ */
-
-/* called from drawview.c, as an extra per-window draw option */
-void drawPropCircle(const struct bContext *C, TransInfo *t)
-{
- if (t->flag & T_PROP_EDIT) {
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float tmat[4][4], imat[4][4];
- int depth_test_enabled;
-
- if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) {
- copy_m4_m4(tmat, rv3d->viewmat);
- invert_m4_m4(imat, tmat);
- }
- else {
- unit_m4(tmat);
- unit_m4(imat);
- }
-
- GPU_matrix_push();
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* pass */
- }
- else if (t->spacetype == SPACE_IMAGE) {
- GPU_matrix_scale_2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]);
- }
- else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
- /* only scale y */
- rcti *mask = &t->ar->v2d.mask;
- rctf *datamask = &t->ar->v2d.cur;
- float xsize = BLI_rctf_size_x(datamask);
- float ysize = BLI_rctf_size_y(datamask);
- float xmask = BLI_rcti_size_x(mask);
- float ymask = BLI_rcti_size_y(mask);
- GPU_matrix_scale_2f(1.0f, (ysize / xsize) * (xmask / ymask));
- }
-
- depth_test_enabled = GPU_depth_test_enabled();
- if (depth_test_enabled) {
- GPU_depth_test(false);
- }
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformThemeColor(TH_GRID);
-
- GPU_logic_op_invert_set(true);
- imm_drawcircball(t->center_global, t->prop_size, imat, pos);
- GPU_logic_op_invert_set(false);
-
- immUnbindProgram();
-
- if (depth_test_enabled) {
- GPU_depth_test(true);
- }
-
- GPU_matrix_pop();
- }
-}
-
-/** \} */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 9031dc06e3f..5595c3a0e38 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -31,6 +31,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_screen_types.h"
@@ -785,50 +786,61 @@ static void recalcData_spaceclip(TransInfo *t)
* if pose bone (partial) selected, copy data.
* context; posemode armature, with mirror editing enabled.
*
- * \param pid: Optional, apply relative transform when set.
+ * \param pid: Optional, apply relative transform when set (has no effect on mirrored bones).
*/
-static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid)
+static void pose_transform_mirror_update(TransInfo *t,
+ TransDataContainer *tc,
+ Object *ob,
+ PoseInitData_Mirror *pid)
{
float flip_mtx[4][4];
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
- for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
- pchan_orig = pchan_orig->next) {
- /* Clear the MIRROR flag from previous runs */
- pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
- }
-
- for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
- pchan_orig = pchan_orig->next) {
- /* no layer check, correct mirror is more important */
- if (pchan_orig->bone->flag & BONE_TRANSFORM) {
- bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
-
- if (pchan) {
- /* also do bbone scaling */
- pchan->bone->xwidth = pchan_orig->bone->xwidth;
- pchan->bone->zwidth = pchan_orig->bone->zwidth;
-
- /* we assume X-axis flipping for now */
- pchan->curve_in_x = pchan_orig->curve_in_x * -1;
- pchan->curve_out_x = pchan_orig->curve_out_x * -1;
- pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
- pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
-
- float pchan_mtx_final[4][4];
- BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
- mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
- mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
- if (pid) {
- mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
- pid++;
- }
- BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+ TransData *td = tc->data;
+ for (int i = tc->data_len; i--; td++) {
+ bPoseChannel *pchan_orig = td->extra;
+ BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM);
+ /* No layer check, correct mirror is more important. */
+ bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
+ if (pchan == NULL) {
+ continue;
+ }
+
+ /* Also do bbone scaling. */
+ pchan->bone->xwidth = pchan_orig->bone->xwidth;
+ pchan->bone->zwidth = pchan_orig->bone->zwidth;
- /* set flag to let autokeyframe know to keyframe the mirrred bone */
- pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
+ /* We assume X-axis flipping for now. */
+ pchan->curve_in_x = pchan_orig->curve_in_x * -1;
+ pchan->curve_out_x = pchan_orig->curve_out_x * -1;
+ pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
+ pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
+
+ float pchan_mtx_final[4][4];
+ BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
+ mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
+ mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
+ if (pid) {
+ mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
+ }
+ BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+
+ /* In this case we can do target-less IK grabbing. */
+ if (t->mode == TFM_TRANSLATION) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data == NULL) {
+ continue;
}
+ mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
+ if (pid) {
+ /* TODO(germano): Realitve Mirror support */
+ }
+ data->flag |= CONSTRAINT_IK_AUTO;
+ }
+
+ if (pid) {
+ pid++;
}
}
}
@@ -1045,7 +1057,7 @@ static void recalcData_objects(TransInfo *t)
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
bPose *pose = ob->pose;
if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) {
- pose_transform_mirror_update(ob, NULL);
+ pose_transform_mirror_update(t, tc, ob, NULL);
}
}
}
@@ -1063,7 +1075,7 @@ static void recalcData_objects(TransInfo *t)
if (pose->flag & POSE_MIRROR_RELATIVE) {
pid = tc->custom.type.data;
}
- pose_transform_mirror_update(ob, pid);
+ pose_transform_mirror_update(t, tc, ob, pid);
}
else {
restoreMirrorPoseBones(tc);
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 3f0032cc7cc..793552865a6 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -44,7 +44,9 @@
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h" /* XXX */
+#include "WM_message.h"
+#include "ED_gizmo_utils.h"
#include "ED_image.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
@@ -53,14 +55,79 @@
#include "transform.h" /* own include */
/* -------------------------------------------------------------------- */
+/** \name Shared Callback's
+ */
+
+static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
+ return false;
+ }
+
+ if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
+ return false;
+ }
+
+ ScrArea *sa = CTX_wm_area(C);
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = sa->spacedata.first;
+ Object *obedit = CTX_data_edit_object(C);
+ if (!ED_space_image_show_uvedit(sima, obedit)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus,
+ /* Additional args. */
+ bScreen *screen,
+ ScrArea *sa,
+ ARegion *ar)
+{
+ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
+ .owner = ar,
+ .user_data = gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ };
+
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = sa->spacedata.first;
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima, &ptr);
+ {
+ extern PropertyRNA rna_SpaceImageEditor_pivot_point;
+ extern PropertyRNA rna_SpaceImageEditor_cursor_location;
+ const PropertyRNA *props[] = {
+ &rna_SpaceImageEditor_pivot_point,
+ (sima->around == V3D_AROUND_CURSOR) ? &rna_SpaceImageEditor_cursor_location : NULL,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ if (props[i] == NULL) {
+ continue;
+ }
+ WM_msg_subscribe_rna(mbus, &ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+ break;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Arrow / Cage Gizmo Group
*
* Defines public functions, not the gizmo it's self:
*
- * - #ED_widgetgroup_gizmo2d_xform_setup
- * - #ED_widgetgroup_gizmo2d_xform_refresh
- * - #ED_widgetgroup_gizmo2d_xform_draw_prepare
- * - #ED_widgetgroup_gizmo2d_xform_poll
+ * - #ED_widgetgroup_gizmo2d_xform_callbacks_set
+ * - #ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set
*
* \{ */
@@ -115,7 +182,7 @@ static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_co
static GizmoGroup2D *gizmogroup2d_init(wmGizmoGroup *gzgroup)
{
- const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_2d", true);
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
@@ -137,7 +204,7 @@ static GizmoGroup2D *gizmogroup2d_init(wmGizmoGroup *gzgroup)
/**
* Calculates origin in view space, use with #gizmo2d_origin_to_region.
*/
-static void gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
+static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
{
float min_buf[2], max_buf[2];
if (r_min == NULL) {
@@ -148,24 +215,42 @@ static void gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
}
ScrArea *sa = CTX_wm_area(C);
+ bool changed = false;
if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
+ 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(CTX_data_scene(C), ima, objects, objects_len, r_min, r_max)) {
- zero_v2(r_min);
- zero_v2(r_max);
+ if (ED_uvedit_minmax_multi(scene, ima, objects, objects_len, r_min, r_max)) {
+ changed = true;
}
MEM_freeN(objects);
}
- else {
+
+ if (changed == false) {
zero_v2(r_min);
zero_v2(r_max);
}
+
mid_v2_v2v2(r_center, r_min, r_max);
+ return changed;
+}
+
+static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
+{
+ ScrArea *sa = CTX_wm_area(C);
+ bool has_select = false;
+ zero_v2(r_center);
+ if (sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = sa->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);
+ }
+ return has_select;
}
/**
@@ -187,7 +272,7 @@ static int gizmo2d_modal(bContext *C,
ARegion *ar = CTX_wm_region(C);
float origin[3];
- gizmo2d_calc_bounds(C, origin, NULL, NULL);
+ gizmo2d_calc_center(C, origin);
gizmo2d_origin_to_region(ar, origin);
WM_gizmo_set_matrix_location(widget, origin);
@@ -196,7 +281,7 @@ static int gizmo2d_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-void ED_widgetgroup_gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
@@ -204,23 +289,30 @@ void ED_widgetgroup_gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup
for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
wmGizmo *gz = ggd->translate_xy[i];
- const float offset[3] = {0.0f, 0.2f};
/* custom handler! */
WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
- WM_gizmo_set_scale(gz, U.gizmo_size);
if (i < 2) {
float color[4], color_hi[4];
gizmo2d_get_axis_color(i, color, color_hi);
/* set up widget data */
- RNA_float_set(gz->ptr, "angle", -M_PI_2 * i);
RNA_float_set(gz->ptr, "length", 0.8f);
+ float axis[3] = {0.0f};
+ axis[(i + 1) % 2] = 1.0f;
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
+
+ float offset[3] = {0, 0, 0};
+ offset[2] = 0.18f;
WM_gizmo_set_matrix_offset_location(gz, offset);
+ gz->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
+
WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
WM_gizmo_set_color(gz, color);
WM_gizmo_set_color_highlight(gz, color_hi);
+
+ WM_gizmo_set_scale(gz, 1.0f);
}
else {
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
@@ -230,6 +322,9 @@ void ED_widgetgroup_gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup
/* Make the center low alpha. */
WM_gizmo_set_line_width(gz, 2.0f);
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+
+ WM_gizmo_set_scale(gz, 0.2f);
}
/* Assign operator. */
@@ -289,18 +384,24 @@ void ED_widgetgroup_gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup
}
}
-void ED_widgetgroup_gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
{
- ED_widgetgroup_gizmo2d_xform_setup(C, gzgroup);
+ gizmo2d_xform_setup(C, gzgroup);
GizmoGroup2D *ggd = gzgroup->customdata;
ggd->no_cage = true;
}
-void ED_widgetgroup_gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup2D *ggd = gzgroup->customdata;
float origin[3];
- gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
+ bool has_select;
+ if (ggd->no_cage) {
+ has_select = gizmo2d_calc_center(C, origin);
+ }
+ else {
+ has_select = gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
+ }
copy_v2_v2(ggd->origin, origin);
bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
@@ -314,62 +415,70 @@ void ED_widgetgroup_gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgro
}
}
- if (show_cage) {
- ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
+ if (has_select == false) {
for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
- wmGizmo *gz = ggd->translate_xy[i];
- gz->flag |= WM_GIZMO_HIDDEN;
+ ggd->translate_xy[i]->flag |= WM_GIZMO_HIDDEN;
}
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
}
else {
- ggd->cage->flag |= WM_GIZMO_HIDDEN;
- for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
- wmGizmo *gz = ggd->translate_xy[i];
- gz->flag &= ~WM_GIZMO_HIDDEN;
+ if (show_cage) {
+ ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ gz->flag |= WM_GIZMO_HIDDEN;
+ }
+ }
+ else {
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ wmGizmo *gz = ggd->translate_xy[i];
+ gz->flag &= ~WM_GIZMO_HIDDEN;
+ }
}
- }
- if (show_cage) {
- wmGizmoOpElem *gzop;
- float mid[2];
- const float *min = ggd->min;
- const float *max = ggd->max;
- mid_v2_v2v2(mid, min, max);
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
- PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
+ if (show_cage) {
+ wmGizmoOpElem *gzop;
+ float mid[2];
+ const float *min = ggd->min;
+ const float *max = ggd->max;
+ mid_v2_v2v2(mid, min, max);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
+ PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
+ RNA_property_float_set_array(
+ &gzop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
+ }
}
}
-void ED_widgetgroup_gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *ar = CTX_wm_region(C);
GizmoGroup2D *ggd = gzgroup->customdata;
@@ -389,44 +498,30 @@ void ED_widgetgroup_gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *
ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]);
}
-/* TODO (Julian)
- * - Called on every redraw, better to do a more simple poll and check for selection in _refresh
- * - UV editing only, could be expanded for other things.
- */
-bool ED_widgetgroup_gizmo2d_xform_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus)
{
- if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
- return false;
- }
-
- SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
-
- if (ED_space_image_show_uvedit(sima, obedit)) {
- Image *ima = ED_space_image(sima);
- Scene *scene = CTX_data_scene(C);
- 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);
-
- /* check if there's a selected poly */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar);
+}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- return true;
- }
- }
- }
- }
+void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
+{
+ gzgt->poll = gizmo2d_generic_poll;
+ gzgt->setup = gizmo2d_xform_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = gizmo2d_xform_refresh;
+ gzgt->draw_prepare = gizmo2d_xform_draw_prepare;
+}
- return false;
+void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
+{
+ ED_widgetgroup_gizmo2d_xform_callbacks_set(gzgt);
+ gzgt->setup = gizmo2d_xform_setup_no_cage;
+ gzgt->message_subscribe = gizmo2d_xform_no_cage_message_subscribe;
}
/** \} */
@@ -436,10 +531,7 @@ bool ED_widgetgroup_gizmo2d_xform_poll(const bContext *C, wmGizmoGroupType *UNUS
*
* Defines public functions, not the gizmo it's self:
*
- * - #ED_widgetgroup_gizmo2d_resize_setup
- * - #ED_widgetgroup_gizmo2d_resize_refresh
- * - #ED_widgetgroup_gizmo2d_resize_draw_prepare
- * - #ED_widgetgroup_gizmo2d_resize_poll
+ * - #ED_widgetgroup_gizmo2d_resize_callbacks_set
*
* \{ */
@@ -450,7 +542,7 @@ typedef struct GizmoGroup_Resize2D {
static GizmoGroup_Resize2D *gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
{
- const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_2d", true);
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
GizmoGroup_Resize2D *ggd = MEM_callocN(sizeof(GizmoGroup_Resize2D), __func__);
@@ -462,15 +554,26 @@ static GizmoGroup_Resize2D *gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
return ggd;
}
-void ED_widgetgroup_gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
float origin[3];
- gizmo2d_calc_bounds(C, origin, NULL, NULL);
- copy_v2_v2(ggd->origin, origin);
+ const bool has_select = gizmo2d_calc_center(C, origin);
+
+ if (has_select == false) {
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
+ ggd->gizmo_xy[i]->flag |= WM_GIZMO_HIDDEN;
+ }
+ }
+ else {
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
+ ggd->gizmo_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
+ }
+ copy_v2_v2(ggd->origin, origin);
+ }
}
-void ED_widgetgroup_gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *ar = CTX_wm_region(C);
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
@@ -494,12 +597,7 @@ void ED_widgetgroup_gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup
}
}
-bool ED_widgetgroup_gizmo2d_resize_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
-{
- return ED_widgetgroup_gizmo2d_xform_poll(C, NULL);
-}
-
-void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
@@ -511,22 +609,24 @@ void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup
/* custom handler! */
WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
- WM_gizmo_set_scale(gz, U.gizmo_size);
if (i < 2) {
- const float offset[3] = {0.0f, 0.2f};
float color[4], color_hi[4];
gizmo2d_get_axis_color(i, color, color_hi);
/* set up widget data */
- RNA_float_set(gz->ptr, "angle", -M_PI_2 * i);
- RNA_float_set(gz->ptr, "length", 0.8f);
+ RNA_float_set(gz->ptr, "length", 1.0f);
+ float axis[3] = {0.0f};
+ axis[(i + 1) % 2] = 1.0f;
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
+
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
- WM_gizmo_set_matrix_offset_location(gz, offset);
WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
WM_gizmo_set_color(gz, color);
WM_gizmo_set_color_highlight(gz, color_hi);
+
+ WM_gizmo_set_scale(gz, 1.0f);
}
else {
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
@@ -536,6 +636,9 @@ void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup
/* Make the center low alpha. */
WM_gizmo_set_line_width(gz, 2.0f);
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+
+ WM_gizmo_set_scale(gz, 1.2f);
}
/* Assign operator. */
@@ -551,6 +654,26 @@ void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup
}
}
+static void gizmo2d_resize_message_subscribe(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar);
+}
+
+void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
+{
+ gzgt->poll = gizmo2d_generic_poll;
+ gzgt->setup = gizmo2d_resize_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = gizmo2d_resize_refresh;
+ gzgt->draw_prepare = gizmo2d_resize_draw_prepare;
+ gzgt->message_subscribe = gizmo2d_resize_message_subscribe;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -559,9 +682,6 @@ void ED_widgetgroup_gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup
* Defines public functions, not the gizmo it's self:
*
* - #ED_widgetgroup_gizmo2d_rotate_setup
- * - #ED_widgetgroup_gizmo2d_rotate_refresh
- * - #ED_widgetgroup_gizmo2d_rotate_draw_prepare
- * - #ED_widgetgroup_gizmo2d_rotate_poll
*
* \{ */
@@ -581,15 +701,22 @@ static GizmoGroup_Rotate2D *gizmogroup2d_rotate_init(wmGizmoGroup *gzgroup)
return ggd;
}
-void ED_widgetgroup_gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
float origin[3];
- gizmo2d_calc_bounds(C, origin, NULL, NULL);
- copy_v2_v2(ggd->origin, origin);
+ const bool has_select = gizmo2d_calc_center(C, origin);
+
+ if (has_select == false) {
+ ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
+ }
+ else {
+ ggd->gizmo->flag &= ~WM_GIZMO_HIDDEN;
+ copy_v2_v2(ggd->origin, origin);
+ }
}
-void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *ar = CTX_wm_region(C);
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
@@ -611,12 +738,7 @@ void ED_widgetgroup_gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup
WM_gizmo_set_matrix_location(gz, origin);
}
-bool ED_widgetgroup_gizmo2d_rotate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
-{
- return ED_widgetgroup_gizmo2d_xform_poll(C, NULL);
-}
-
-void ED_widgetgroup_gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+static void gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
@@ -629,7 +751,7 @@ void ED_widgetgroup_gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup
/* custom handler! */
WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
- WM_gizmo_set_scale(gz, U.gizmo_size);
+ WM_gizmo_set_scale(gz, 1.2f);
{
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
@@ -639,6 +761,7 @@ void ED_widgetgroup_gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup
/* Make the center low alpha. */
WM_gizmo_set_line_width(gz, 2.0f);
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
+ WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
}
/* Assign operator. */
@@ -647,4 +770,24 @@ void ED_widgetgroup_gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup
}
}
+static void gizmo2d_rotate_message_subscribe(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar);
+}
+
+void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
+{
+ gzgt->poll = gizmo2d_generic_poll;
+ gzgt->setup = gizmo2d_rotate_setup;
+ gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
+ gzgt->refresh = gizmo2d_rotate_refresh;
+ gzgt->draw_prepare = gizmo2d_rotate_draw_prepare;
+ gzgt->message_subscribe = gizmo2d_rotate_message_subscribe;
+}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index b2d8671fbce..09992e8be0e 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -720,7 +720,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;
- RNA_def_float_vector_xyz(
+ RNA_def_float_translation(
ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Move", "", -FLT_MAX, FLT_MAX);
WM_operatortype_props_advanced_begin(ot);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 3159464072e..1952a2c862e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -413,7 +413,7 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
int total = 0;
for (bone = lb->first; bone; bone = bone->next) {
- bone->flag &= ~BONE_TRANSFORM;
+ bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
do_next = do_it;
if (do_it) {
if (bone->layer & arm->layer) {
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 604ecb984a9..63b9eb3937a 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -130,6 +130,8 @@ struct SnapObjectContext {
/* Object -> SnapObjectData map */
struct {
GHash *object_map;
+ /** Map object-data to objects so objects share edit mode data. */
+ GHash *data_to_object_map;
MemArena *mem_arena;
} cache;
@@ -164,6 +166,21 @@ static void bm_mesh_minmax(BMesh *bm, float r_min[3], float r_max[3])
}
}
+static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob)
+{
+ SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ if (sod == NULL) {
+ if (sctx->cache.data_to_object_map != NULL) {
+ ob = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob->data);
+ /* Could be NULl when mixing edit-mode and non edit-mode objects. */
+ if (ob != NULL) {
+ sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ }
+ }
+ }
+ return sod;
+}
+
static SnapObjectData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
{
void **sod_p;
@@ -182,13 +199,28 @@ static SnapObjectData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, O
return *sod_p;
}
-/* Use `em->ob` as the key in ghash since the editmesh is used
- * to create bvhtree and is the same for each linked object. */
static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
+ Object *ob,
BMEditMesh *em)
{
void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, em->ob, &sod_p)) {
+
+ {
+ /* Use object-data as the key in ghash since the editmesh
+ * is used to create bvhtree and is the same for each linked object. */
+ if (sctx->cache.data_to_object_map == NULL) {
+ sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__);
+ }
+ void **ob_p;
+ if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob->data, &ob_p)) {
+ ob = *ob_p;
+ }
+ else {
+ *ob_p = ob;
+ }
+ }
+
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_EDIT_MESH);
}
else {
@@ -617,8 +649,6 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
return retval;
}
- BLI_assert(BKE_object_get_pre_modified_mesh(em->ob) == BKE_object_get_pre_modified_mesh(ob));
-
float imat[4][4];
float ray_start_local[3], ray_normal_local[3];
float local_scale, local_depth, len_diff = 0.0f;
@@ -638,7 +668,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
local_depth *= local_scale;
}
- SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, em);
+ SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob, em);
/* Test BoundBox */
@@ -666,7 +696,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
BVHTreeFromEditMesh *treedata = sod->bvh_trees[2];
- BVHCache **em_bvh_cache = &((Mesh *)em->ob->data)->runtime.bvh_cache;
+ BVHCache **em_bvh_cache = &((Mesh *)ob->data)->runtime.bvh_cache;
if (sctx->callbacks.edit_mesh.test_face_fn == NULL) {
/* The tree is owned by the Mesh and may have been freed since we last used! */
@@ -803,7 +833,7 @@ static bool raycastObj(SnapObjectContext *sctx,
{
bool retval = false;
if (use_occlusion_test) {
- if (use_obedit && sctx->use_v3d && XRAY_ENABLED(sctx->v3d_data.v3d)) {
+ if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
/* Use of occlude geometry in editing mode disabled. */
return false;
}
@@ -1365,13 +1395,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
.dist_sq = SQUARE(*dist_px),
};
- SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
- if (sod == NULL) {
- /* The object is in edit mode, and the key used
- * was the object referenced in BMEditMesh */
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- sod = BLI_ghash_lookup(sctx->cache.object_map, em->ob);
- }
+ SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
BLI_assert(sod != NULL);
@@ -1492,13 +1516,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
- SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
- if (sod == NULL) {
- /* The object is in edit mode, and the key used
- * was the object referenced in BMEditMesh */
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- sod = BLI_ghash_lookup(sctx->cache.object_map, em->ob);
- }
+ SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
BLI_assert(sod != NULL);
@@ -2380,7 +2398,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
float dist_px_sq = SQUARE(*dist_px);
- SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, em);
+ SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob, em);
/* Test BoundBox */
@@ -2390,7 +2408,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
return 0;
}
- BVHCache **em_bvh_cache = &((Mesh *)em->ob->data)->runtime.bvh_cache;
+ BVHCache **em_bvh_cache = &((Mesh *)ob->data)->runtime.bvh_cache;
if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
if (sod->bvh_trees[0] == NULL) {
@@ -2750,6 +2768,8 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain,
sctx->depsgraph = depsgraph;
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
+ /* Initialize as needed (edit-mode only). */
+ sctx->cache.data_to_object_map = NULL;
sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
return sctx;
@@ -2797,6 +2817,9 @@ static void snap_object_data_free(void *sod_v)
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
{
BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
+ if (sctx->cache.data_to_object_map != NULL) {
+ BLI_ghash_free(sctx->cache.data_to_object_map, NULL, NULL);
+ }
BLI_memarena_free(sctx->cache.mem_arena);
MEM_freeN(sctx);
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 9770b52158a..8e190ed9c73 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -464,6 +464,15 @@ static bool ed_undo_redo_poll(bContext *C)
WM_operator_check_ui_enabled(C, last_op->type->name));
}
+static bool ed_undo_poll(bContext *C)
+{
+ if (!ed_undo_is_init_and_screenactive_poll(C)) {
+ return false;
+ }
+ UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
+ return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL);
+}
+
void ED_OT_undo(wmOperatorType *ot)
{
/* identifiers */
@@ -473,7 +482,7 @@ void ED_OT_undo(wmOperatorType *ot)
/* api callbacks */
ot->exec = ed_undo_exec;
- ot->poll = ed_undo_is_init_and_screenactive_poll;
+ ot->poll = ed_undo_poll;
}
void ED_OT_undo_push(wmOperatorType *ot)
@@ -498,6 +507,15 @@ void ED_OT_undo_push(wmOperatorType *ot)
"");
}
+static bool ed_redo_poll(bContext *C)
+{
+ if (!ed_undo_is_init_and_screenactive_poll(C)) {
+ return false;
+ }
+ UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
+ return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL);
+}
+
void ED_OT_redo(wmOperatorType *ot)
{
/* identifiers */
@@ -507,7 +525,7 @@ void ED_OT_redo(wmOperatorType *ot)
/* api callbacks */
ot->exec = ed_redo_exec;
- ot->poll = ed_undo_is_init_and_screenactive_poll;
+ ot->poll = ed_redo_poll;
}
void ED_OT_undo_redo(wmOperatorType *ot)
@@ -697,6 +715,16 @@ static int undo_history_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+static bool undo_history_poll(bContext *C)
+{
+ if (!ed_undo_is_init_and_screenactive_poll(C)) {
+ return false;
+ }
+ UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
+ /* More than just original state entry. */
+ return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
+}
+
void ED_OT_undo_history(wmOperatorType *ot)
{
/* identifiers */
@@ -707,7 +735,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = ed_undo_is_init_and_screenactive_poll;
+ ot->poll = undo_history_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 1a33b50ff10..b4b89c31414 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -228,6 +228,63 @@ void ED_editors_exit(Main *bmain, bool do_undo_system)
ED_mesh_mirror_topo_table(NULL, NULL, 'e');
}
+bool ED_editors_flush_edits_for_object_ex(Main *bmain,
+ Object *ob,
+ bool for_render,
+ bool check_needs_flush)
+{
+ bool has_edited = false;
+ if (ob->mode & OB_MODE_SCULPT) {
+ /* Don't allow flushing while in the middle of a stroke (frees data in use).
+ * Auto-save prevents this from happening but scripts
+ * may cause a flush on saving: T53986. */
+ if ((ob->sculpt && ob->sculpt->cache) == 0) {
+
+ {
+ char *needs_flush_ptr = &ob->sculpt->needs_flush_to_id;
+ if (check_needs_flush && (*needs_flush_ptr == 0)) {
+ return false;
+ }
+ *needs_flush_ptr = 0;
+ }
+
+ /* flush multires changes (for sculpt) */
+ multires_flush_sculpt_updates(ob);
+ has_edited = true;
+
+ if (for_render) {
+ /* flush changes from dynamic topology sculpt */
+ BKE_sculptsession_bm_to_me_for_render(ob);
+ }
+ else {
+ /* Set reorder=false so that saving the file doesn't reorder
+ * the BMesh's elements */
+ BKE_sculptsession_bm_to_me(ob, false);
+ }
+ }
+ }
+ else if (ob->mode & OB_MODE_EDIT) {
+
+ char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(ob->data);
+ if (needs_flush_ptr != NULL) {
+ if (check_needs_flush && (*needs_flush_ptr == 0)) {
+ return false;
+ }
+ *needs_flush_ptr = 0;
+ }
+
+ /* get editmode results */
+ has_edited = true;
+ ED_object_editmode_load(bmain, ob);
+ }
+ return has_edited;
+}
+
+bool ED_editors_flush_edits_for_object(Main *bmain, Object *ob)
+{
+ return ED_editors_flush_edits_for_object_ex(bmain, ob, false, false);
+}
+
/* flush any temp data from object editing to DNA before writing files,
* rendering, copying, etc. */
bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
@@ -239,49 +296,7 @@ bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_fl
* exiting we might not have a context for edit object and multiple sculpt
* objects can exist at the same time */
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->mode & OB_MODE_SCULPT) {
- /* Don't allow flushing while in the middle of a stroke (frees data in use).
- * Auto-save prevents this from happening but scripts
- * may cause a flush on saving: T53986. */
- if ((ob->sculpt && ob->sculpt->cache) == 0) {
-
- {
- char *needs_flush_ptr = &ob->sculpt->needs_flush_to_id;
- if (check_needs_flush && (*needs_flush_ptr == 0)) {
- continue;
- }
- *needs_flush_ptr = 0;
- }
-
- /* flush multires changes (for sculpt) */
- multires_flush_sculpt_updates(ob);
- has_edited = true;
-
- if (for_render) {
- /* flush changes from dynamic topology sculpt */
- BKE_sculptsession_bm_to_me_for_render(ob);
- }
- else {
- /* Set reorder=false so that saving the file doesn't reorder
- * the BMesh's elements */
- BKE_sculptsession_bm_to_me(ob, false);
- }
- }
- }
- else if (ob->mode & OB_MODE_EDIT) {
-
- char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(ob->data);
- if (needs_flush_ptr != NULL) {
- if (check_needs_flush && (*needs_flush_ptr == 0)) {
- continue;
- }
- *needs_flush_ptr = 0;
- }
-
- /* get editmode results */
- has_edited = true;
- ED_object_editmode_load(bmain, ob);
- }
+ has_edited |= ED_editors_flush_edits_for_object_ex(bmain, ob, for_render, check_needs_flush);
}
bmain->is_memfile_undo_flush_needed = false;
@@ -289,9 +304,9 @@ bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_fl
return has_edited;
}
-bool ED_editors_flush_edits(Main *bmain, bool for_render)
+bool ED_editors_flush_edits(Main *bmain)
{
- return ED_editors_flush_edits_ex(bmain, for_render, false);
+ return ED_editors_flush_edits_ex(bmain, false, false);
}
/* ***** XXX: functions are using old blender names, cleanup later ***** */
@@ -472,7 +487,7 @@ void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id,
static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
- ED_editors_flush_edits(bmain, false);
+ ED_editors_flush_edits(bmain);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index fafd54804c0..528fca85fa7 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -217,7 +217,7 @@ static void uvedit_get_batches(Object *ob,
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
- Scene *scene,
+ const Scene *scene,
Object *obedit,
Depsgraph *depsgraph)
{
@@ -237,11 +237,11 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
}
}
-static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
+static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgraph)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *me = ob_eval->data;
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
float col[4];
UI_GetThemeColor4fv(TH_UV_SHADOW, col);
@@ -296,7 +296,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
/* draws uv's in the image space */
static void draw_uvs(SpaceImage *sima,
- Scene *scene,
+ const Scene *scene,
Depsgraph *depsgraph,
UVEditGPUBatches *batch,
float tot_area_ratio,
@@ -496,7 +496,7 @@ static void draw_uv_shadows_get(
}
void ED_uvedit_draw_main(SpaceImage *sima,
- Scene *scene,
+ const Scene *scene,
ViewLayer *view_layer,
Object *obedit,
Object *obact,
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 1de4d05a721..5be3f676658 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -81,6 +81,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -274,7 +275,7 @@ bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
}
}
-bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
+bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
{
return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
}
@@ -290,7 +291,7 @@ bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *
return uvedit_face_visible_nolocal_ex(ts, efa);
}
}
-bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *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);
}
@@ -315,12 +316,12 @@ bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int c
return true;
}
}
-bool uvedit_face_select_test(Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
+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(struct Scene *scene,
+bool uvedit_face_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
const bool select,
@@ -335,10 +336,13 @@ bool uvedit_face_select_set(struct Scene *scene,
}
}
-bool uvedit_face_select_enable(
- Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, const int 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)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
BM_face_select_set(em->bm, efa, true);
@@ -362,12 +366,12 @@ bool uvedit_face_select_enable(
return false;
}
-bool uvedit_face_select_disable(Scene *scene,
+bool uvedit_face_select_disable(const Scene *scene,
BMEditMesh *em,
BMFace *efa,
const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
BM_face_select_set(em->bm, efa, false);
@@ -411,13 +415,13 @@ bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_
return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
}
}
-bool uvedit_edge_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+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,
- Scene *scene,
+ const Scene *scene,
BMLoop *l,
const bool select,
const bool do_history,
@@ -432,11 +436,14 @@ void uvedit_edge_select_set(BMEditMesh *em,
}
}
-void uvedit_edge_select_enable(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int 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)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -466,12 +473,12 @@ void uvedit_edge_select_enable(
}
void uvedit_edge_select_disable(BMEditMesh *em,
- Scene *scene,
+ const Scene *scene,
BMLoop *l,
const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -511,13 +518,13 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo
return (luv->flag & MLOOPUV_VERTSEL) != 0;
}
}
-bool uvedit_uv_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+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,
- Scene *scene,
+ const Scene *scene,
BMLoop *l,
const bool select,
const bool do_history,
@@ -531,10 +538,13 @@ void uvedit_uv_select_set(BMEditMesh *em,
}
}
-void uvedit_uv_select_enable(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int 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)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -554,9 +564,12 @@ void uvedit_uv_select_enable(
}
}
-void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+void uvedit_uv_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
@@ -618,7 +631,7 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-bool ED_uvedit_minmax_multi(Scene *scene,
+bool ED_uvedit_minmax_multi(const Scene *scene,
Image *ima,
Object **objects_edit,
uint objects_len,
@@ -656,7 +669,8 @@ bool ED_uvedit_minmax_multi(Scene *scene,
return changed;
}
-bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+bool ED_uvedit_minmax(
+ const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
{
return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
}
@@ -680,7 +694,7 @@ void ED_uvedit_select_all(BMesh *bm)
}
static bool ED_uvedit_median_multi(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
+ const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
{
unsigned int sel = 0;
zero_v2(co);
@@ -716,16 +730,12 @@ static bool ED_uvedit_median_multi(
return (sel != 0);
}
-static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene,
- Image *ima,
- Object *obedit,
- float co[2])
-{
- return ED_uvedit_median_multi(scene, ima, &obedit, 1, co);
-}
-
-bool ED_uvedit_center_multi(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode)
+bool ED_uvedit_center_multi(const Scene *scene,
+ Image *ima,
+ Object **objects_edit,
+ uint objects_len,
+ float cent[2],
+ char mode)
{
bool changed = false;
@@ -745,9 +755,46 @@ bool ED_uvedit_center_multi(
return changed;
}
-bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
+bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
+ Scene *scene,
+ ViewLayer *view_layer,
+ float r_center[2],
+ char mode,
+ bool *r_has_select)
{
- return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode);
+ bool changed = false;
+ switch (mode) {
+ case V3D_AROUND_CURSOR: {
+ copy_v2_v2(r_center, sima->cursor);
+ changed = true;
+ if (r_has_select != NULL) {
+ 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);
+ MEM_freeN(objects);
+ }
+ break;
+ }
+ default: {
+ 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);
+ MEM_freeN(objects);
+ if (r_has_select != NULL) {
+ *r_has_select = changed;
+ }
+ break;
+ }
+ }
+ return changed;
+}
+
+bool ED_uvedit_center_from_pivot(
+ SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode)
+{
+ return ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, mode, NULL);
}
/** \} */
@@ -976,8 +1023,12 @@ bool uv_find_nearest_vert_multi(Scene *scene,
return found;
}
-bool ED_uvedit_nearest_uv(
- Scene *scene, Object *obedit, Image *ima, const float co[2], float *dist_sq, float r_uv[2])
+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;
@@ -1011,7 +1062,7 @@ bool ED_uvedit_nearest_uv(
}
}
-bool ED_uvedit_nearest_uv_multi(Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const Scene *scene,
Image *ima,
Object **objects,
const uint objects_len,
@@ -1472,7 +1523,7 @@ static int uv_select_more_less(bContext *C, const bool select)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@@ -1639,7 +1690,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
float cent[2], min[2], max[2];
@@ -1952,7 +2003,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -2097,7 +2148,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -2271,7 +2322,7 @@ static void UV_OT_weld(wmOperatorType *ot)
static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -2316,7 +2367,7 @@ static bool uv_select_is_any_selected_multi(Scene *scene,
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
{
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -2389,7 +2440,7 @@ static int uv_select_all_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2470,7 +2521,7 @@ static int uv_mouse_select_multi(bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
@@ -2905,7 +2956,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
float limit[2];
@@ -3078,7 +3129,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
BMFace *efa;
@@ -3163,7 +3214,7 @@ static void UV_OT_select_split(wmOperatorType *ot)
ot->poll = ED_operator_uvedit; /* requires space image */
}
-static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select)
+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) {
@@ -3278,7 +3329,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima,
* This only needs to be done when the Mesh is not used for
* selection (so for sticky modes, vertex or location based). */
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -3364,7 +3415,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima,
* This only needs to be done when the Mesh is not used for
* selection (so for sticky modes, vertex or location based). */
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -3443,7 +3494,7 @@ 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);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
@@ -3463,6 +3514,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
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");
@@ -3472,7 +3524,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ if (use_pre_deselect) {
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
@@ -3490,8 +3542,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
/* handle face selection mode */
float cent[2];
- changed = false;
-
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
/* assume not touched */
BM_elem_flag_disable(efa, BM_ELEM_TAG);
@@ -3544,7 +3594,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
}
}
- if (changed) {
+ if (changed || use_pre_deselect) {
changed_multi = true;
uv_select_sync_flush(ts, em, select);
@@ -3603,7 +3653,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
Image *ima = CTX_data_edit_image(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ARegion *ar = CTX_wm_region(C);
BMFace *efa;
BMLoop *l;
@@ -3640,9 +3690,10 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
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);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ 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);
- changed_multi = true;
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@@ -3655,7 +3706,6 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
/* do selection */
if (use_face_center) {
- changed = false;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
/* assume not touched */
@@ -3693,7 +3743,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
}
}
- if (changed) {
+ if (changed || use_pre_deselect) {
changed_multi = true;
uv_select_sync_flush(ts, em, select);
@@ -3743,12 +3793,13 @@ static bool do_lasso_select_mesh_uv(bContext *C,
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ 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;
@@ -3764,7 +3815,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ if (use_pre_deselect) {
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
@@ -3829,7 +3880,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
}
}
- if (changed) {
+ if (changed || use_pre_deselect) {
changed_multi = true;
uv_select_sync_flush(ts, em, select);
@@ -4119,7 +4170,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
+ 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");
float offset[2] = {0};
@@ -4214,7 +4265,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
const bool clear = RNA_boolean_get(op->ptr, "clear");
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -4291,7 +4342,7 @@ 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);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
BMFace *efa;
@@ -4622,7 +4673,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -4636,7 +4687,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (EDBM_mesh_hide(em, swap)) {
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
return OPERATOR_FINISHED;
}
@@ -4745,7 +4796,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
@@ -4764,7 +4815,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
/* 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(em, true, false);
+ EDBM_update_generic(obedit->data, true, false);
}
return OPERATOR_FINISHED;
}
@@ -4890,6 +4941,12 @@ static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "location", sima->cursor);
+ {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ bScreen *screen = CTX_wm_screen(C);
+ WM_msg_publish_rna_prop(mbus, &screen->id, sima, SpaceImageEditor, cursor_location);
+ }
+
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
return OPERATOR_FINISHED;
@@ -5098,7 +5155,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ const ToolSettings *ts = scene->toolsettings;
BMFace *efa;
BMLoop *loop;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 5a8301fae67..5d3d016e6c1 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1935,10 +1935,10 @@ static StitchState *stitch_init(bContext *C,
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true);
}
else {
- state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
}
if (!state->element_map) {
state_delete(state);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 1db038bef94..1e758771f6a 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -75,7 +75,7 @@
#include "uvedit_intern.h"
#include "uvedit_parametrizer.h"
-static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf)
+static void modifier_unwrap_state(Object *obedit, const Scene *scene, bool *r_use_subsurf)
{
ModifierData *md;
bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
@@ -95,56 +95,28 @@ static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subs
*r_use_subsurf = subsurf;
}
-static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit)
+static bool ED_uvedit_ensure_uvs(Object *obedit)
{
+ if (ED_uvedit_test(obedit)) {
+ return 1;
+ }
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter;
- Image *ima;
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *slink;
- SpaceImage *sima;
int cd_loop_uv_offset;
- if (ED_uvedit_test(obedit)) {
- return 1;
- }
-
if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
ED_mesh_uv_texture_add(obedit->data, NULL, true, true);
}
+ /* Happens when there are no faces. */
if (!ED_uvedit_test(obedit)) {
return 0;
}
cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- ima = CTX_data_edit_image(C);
-
- if (!ima) {
- /* no image in context in the 3d view, we find first image window .. */
- sc = CTX_wm_screen(C);
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- slink = sa->spacedata.first;
- if (slink->spacetype == SPACE_IMAGE) {
- sima = (SpaceImage *)slink;
-
- ima = sima->image;
- if (ima) {
- if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE) {
- ima = NULL;
- }
- else {
- break;
- }
- }
- }
- }
- }
-
/* select new UV's (ignore UV_SYNC_SELECTION in this case) */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMIter liter;
@@ -168,7 +140,7 @@ typedef struct UnwrapOptions {
bool correct_aspect; /* Correct for mapped image texture aspect ratio. */
} UnwrapOptions;
-static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, const UnwrapOptions *options)
+static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const UnwrapOptions *options)
{
BMFace *efa;
BMLoop *l;
@@ -207,7 +179,7 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, const UnwrapOpti
return false;
}
-static bool uvedit_have_selection_multi(Scene *scene,
+static bool uvedit_have_selection_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options)
@@ -224,7 +196,8 @@ static bool uvedit_have_selection_multi(Scene *scene,
return have_select;
}
-void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
+void ED_uvedit_get_aspect(
+ const Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
{
bool sloppy = true;
bool selected = false;
@@ -244,8 +217,11 @@ void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *as
}
}
-static void construct_param_handle_face_add(
- ParamHandle *handle, Scene *scene, BMFace *efa, int face_index, const int cd_loop_uv_offset)
+static void construct_param_handle_face_add(ParamHandle *handle,
+ const Scene *scene,
+ BMFace *efa,
+ int face_index,
+ const int cd_loop_uv_offset)
{
ParamKey key;
ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
@@ -276,7 +252,7 @@ static void construct_param_handle_face_add(
}
/* See: construct_param_handle_multi to handle multiple objects at once. */
-static ParamHandle *construct_param_handle(Scene *scene,
+static ParamHandle *construct_param_handle(const Scene *scene,
Object *ob,
BMesh *bm,
const UnwrapOptions *options)
@@ -348,7 +324,7 @@ static ParamHandle *construct_param_handle(Scene *scene,
/**
* Version of #construct_param_handle_single that handles multiple objects.
*/
-static ParamHandle *construct_param_handle_multi(Scene *scene,
+static ParamHandle *construct_param_handle_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options)
@@ -437,7 +413,7 @@ static void texface_from_original_index(BMFace *efa,
float **uv,
ParamBool *pin,
ParamBool *select,
- Scene *scene,
+ const Scene *scene,
const int cd_loop_uv_offset)
{
BMLoop *l;
@@ -468,7 +444,7 @@ static void texface_from_original_index(BMFace *efa,
* The many modifications required to make the original function(see above)
* work justified the existence of a new function.
*/
-static ParamHandle *construct_param_handle_subsurfed(Scene *scene,
+static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
Object *ob,
BMEditMesh *em,
const UnwrapOptions *options)
@@ -656,7 +632,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene,
/* ******************** Minimize Stretch operator **************** */
typedef struct MinStretch {
- Scene *scene;
+ const Scene *scene;
Object **objects_edit;
uint objects_len;
ParamHandle *handle;
@@ -668,7 +644,7 @@ typedef struct MinStretch {
static bool minimize_stretch_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const UnwrapOptions options = {
@@ -711,7 +687,7 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
{
MinStretch *ms = op->customdata;
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -752,7 +728,7 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
{
MinStretch *ms = op->customdata;
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -928,7 +904,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* ******************** Pack Islands operator **************** */
-static void uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm)
+static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
{
const UnwrapOptions options = {
.topology_from_uvs = true,
@@ -947,7 +923,7 @@ static void uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm)
param_delete(handle);
}
-static void uvedit_pack_islands_multi(Scene *scene,
+static void uvedit_pack_islands_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options,
@@ -970,7 +946,7 @@ static void uvedit_pack_islands_multi(Scene *scene,
static int pack_islands_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
const UnwrapOptions options = {
.topology_from_uvs = true,
@@ -1028,7 +1004,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -1200,8 +1176,12 @@ static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3
mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
}
-static void uv_map_transform_center(
- Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em, float r_center[3], float r_bounds[2][3])
+static void uv_map_transform_center(const Scene *scene,
+ View3D *v3d,
+ Object *ob,
+ BMEditMesh *em,
+ float r_center[3],
+ float r_bounds[2][3])
{
/* only operates on the edit object - this is all that's needed now */
const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
@@ -1395,7 +1375,7 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
-static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
+static void correct_uv_aspect(const Scene *scene, Object *ob, BMEditMesh *em)
{
BMLoop *l;
BMIter iter, liter;
@@ -1462,7 +1442,7 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
"Scale UV coordinates to bounds after unwrapping");
}
-static void uv_map_clip_correct_multi(Scene *scene,
+static void uv_map_clip_correct_multi(const Scene *scene,
Object **objects,
uint objects_len,
wmOperator *op)
@@ -1552,7 +1532,7 @@ static void uv_map_clip_correct_multi(Scene *scene,
}
}
-static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
+static void uv_map_clip_correct(const Scene *scene, Object *ob, wmOperator *op)
{
uv_map_clip_correct_multi(scene, &ob, 1, op);
}
@@ -1560,7 +1540,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
/* ******************** Unwrap operator **************** */
/* Assumes UV Map exists, doesn't run update funcs. */
-static void uvedit_unwrap(Scene *scene, Object *obedit, const UnwrapOptions *options)
+static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOptions *options)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
@@ -1589,7 +1569,7 @@ static void uvedit_unwrap(Scene *scene, Object *obedit, const UnwrapOptions *opt
param_delete(handle);
}
-static void uvedit_unwrap_multi(Scene *scene,
+static void uvedit_unwrap_multi(const Scene *scene,
Object **objects,
const int objects_len,
const UnwrapOptions *options)
@@ -1602,7 +1582,7 @@ static void uvedit_unwrap_multi(Scene *scene,
}
}
-void ED_uvedit_live_unwrap(Scene *scene, Object **objects, int objects_len)
+void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len)
{
if (scene->toolsettings->edge_mode_live_unwrap) {
const UnwrapOptions options = {
@@ -1628,7 +1608,7 @@ enum {
static int unwrap_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
int method = RNA_enum_get(op->ptr, "method");
const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
int reported_errors = 0;
@@ -1661,7 +1641,7 @@ static int unwrap_exec(bContext *C, wmOperator *op)
float obsize[3];
bool use_subsurf_final;
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -1823,7 +1803,7 @@ static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
static int uv_from_view_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -1861,7 +1841,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
bool changed = false;
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -1987,7 +1967,6 @@ void UV_OT_project_from_view(wmOperatorType *ot)
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -2004,7 +1983,7 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2087,7 +2066,7 @@ static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
static int sphere_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2107,7 +2086,7 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2181,7 +2160,7 @@ static void uv_cylinder_project(float target[2],
static int cylinder_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2201,7 +2180,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2298,7 +2277,7 @@ static void uvedit_unwrap_cube_project(BMesh *bm,
static int cube_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
@@ -2317,7 +2296,7 @@ static int cube_project_exec(bContext *C, wmOperator *op)
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ if (!ED_uvedit_ensure_uvs(obedit)) {
continue;
}
@@ -2384,7 +2363,7 @@ void UV_OT_cube_project(wmOperatorType *ot)
/************************* Simple UVs for texture painting *****************/
-void ED_uvedit_add_simple_uvs(Main *bmain, Scene *scene, Object *ob)
+void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
{
Mesh *me = ob->data;
bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index ba5172c7916..8270476e9dd 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -549,6 +549,9 @@ set(SRC
set(LIB
bf_python_mathutils
+
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
)
set(INC
diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp
index 3e3a939a8fe..a2f0a3395af 100644
--- a/source/blender/freestyle/intern/application/AppConfig.cpp
+++ b/source/blender/freestyle/intern/application/AppConfig.cpp
@@ -53,10 +53,6 @@ void Path::setRootDir(const string &iRootDir)
string(DIR_SEP.c_str());
_BrushesPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) +
"textures" + string(DIR_SEP.c_str()) + "brushes" + string(DIR_SEP.c_str());
- _PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "modules" + string(DIR_SEP.c_str());
- if (getenv("PYTHONPATH")) {
- _PythonPath += string(PATH_SEP.c_str()) + string(getenv("PYTHONPATH"));
- }
_EnvMapDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) +
"env_map" + string(DIR_SEP.c_str());
_MapsDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "maps" +
diff --git a/source/blender/freestyle/intern/application/AppConfig.h b/source/blender/freestyle/intern/application/AppConfig.h
index cc2a3962ecd..9369ed81d50 100644
--- a/source/blender/freestyle/intern/application/AppConfig.h
+++ b/source/blender/freestyle/intern/application/AppConfig.h
@@ -43,7 +43,6 @@ class Path {
string _ModelsPath;
string _PatternsPath;
string _BrushesPath;
- string _PythonPath;
string _EnvMapDir;
string _MapsDir;
string _HomeDir;
@@ -72,10 +71,6 @@ class Path {
{
return _BrushesPath;
}
- const string &getPythonPath() const
- {
- return _PythonPath;
- }
const string &getEnvMapDir() const
{
return _EnvMapDir;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index dc6677bdcf4..8b125828fdc 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -35,9 +35,9 @@
#include "../system/FreestyleConfig.h"
#include "../system/RenderMonitor.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 06087cd7fa6..f96f5f119c0 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -23,9 +23,9 @@
#include "../application/AppConfig.h"
#include "../stroke/Canvas.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "RNA_access.h"
#include "RNA_types.h"
@@ -118,8 +118,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
freestyle_scene->id.properties = IDP_CopyProperty_ex(old_scene->id.properties, 0);
}
// Copy eevee render settings.
- freestyle_scene->eevee = old_scene->eevee;
- freestyle_scene->eevee.light_cache = NULL;
+ BKE_scene_copy_data_eevee(freestyle_scene, old_scene);
/* Render with transparent background. */
freestyle_scene->r.alphamode = R_ALPHAPREMUL;
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 07839ac6e61..0567bd0df06 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -32,10 +32,10 @@
using namespace std;
using namespace Freestyle;
-extern "C" {
-
#include "MEM_guardedalloc.h"
+extern "C" {
+
#include "DNA_camera_types.h"
#include "DNA_collection_types.h"
#include "DNA_freestyle_types.h"
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 1fed6a00463..255a1b2a152 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -31,10 +31,10 @@ extern "C" {
#include "StringUtils.h"
#include "Interpreter.h"
-// soc
-extern "C" {
#include "MEM_guardedalloc.h"
+// soc
+extern "C" {
#include "DNA_text_types.h"
#include "BKE_context.h"
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 8daeda67c80..25f9ef886e9 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -129,6 +129,7 @@ set(SRC
)
set(LIB
+ ${BLENDER_GL_LIBRARIES}
)
if(NOT WITH_SYSTEM_GLEW)
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index a5363c7a42c..8c166ed6b64 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -71,12 +71,13 @@ typedef enum eGPUType {
/* Values not in GPU_DATATYPE_STR */
GPU_TEX1D_ARRAY = 1001,
GPU_TEX2D = 1002,
- GPU_TEX3D = 1003,
- GPU_SHADOW2D = 1004,
- GPU_TEXCUBE = 1005,
+ GPU_TEX2D_ARRAY = 1003,
+ GPU_TEX3D = 1004,
+ GPU_SHADOW2D = 1005,
+ GPU_TEXCUBE = 1006,
/* GLSL Struct types */
- GPU_CLOSURE = 1006,
+ GPU_CLOSURE = 1007,
/* Opengl Attributes */
GPU_ATTR = 3001,
@@ -142,7 +143,8 @@ typedef enum eGPUMaterialStatus {
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_constant(float *num);
GPUNodeLink *GPU_uniform(float *num);
-GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, int tile);
+GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser);
+GPUNodeLink *GPU_image_tilemap(struct Image *ima, struct ImageUser *iuser);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer);
GPUNodeLink *GPU_builtin(eGPUBuiltin builtin);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index a8e8ca72023..bb6af227369 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -36,6 +36,7 @@ struct ImageUser;
struct MovieClip;
struct MovieClipUser;
struct PreviewImage;
+struct ImBuf;
struct GPUFrameBuffer;
typedef struct GPUTexture GPUTexture;
@@ -187,7 +188,10 @@ GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert);
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer);
GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode);
-GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, int textarget);
+GPUTexture *GPU_texture_from_blender(struct Image *ima,
+ struct ImageUser *iuser,
+ struct ImBuf *ibuf,
+ int textarget);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
/* movie clip drawing */
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 2c74afd2d8e..bf7b1908321 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -116,7 +116,7 @@ void gpu_pbvh_init()
g_vbo_id.msk = GPU_vertformat_attr_add(
&g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
g_vbo_id.col = GPU_vertformat_attr_add(
- &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
}
@@ -240,8 +240,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
for (int j = 0; j < 3; j++) {
const int loop_index = lt->tri[j];
const int vidx = face_vert_indices[i][j];
- const uchar *elem = &vcol[loop_index].r;
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, elem);
+ 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);
}
}
}
@@ -289,8 +294,13 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
if (show_vcol) {
const uint loop_index = lt->tri[j];
- const uchar *elem = &vcol[loop_index].r;
- memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4);
+ 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));
}
}
}
@@ -654,7 +664,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
}
if (show_vcol) {
- char vcol[4] = {255, 255, 255, 255};
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol);
}
@@ -705,7 +715,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
empty_mask = empty_mask && (fmask == 0.0f);
}
- char vcol[4] = {255, 255, 255, 255};
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol);
@@ -781,7 +791,7 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
}
if (show_vcol) {
- static char vcol[4] = {255, 255, 255, 255};
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
}
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index ca804a26acd..a7dd34a5f96 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -279,6 +279,9 @@ static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
if (!type && gpu_str_prefix(code, "sampler1DArray")) {
type = GPU_TEX1D_ARRAY;
}
+ if (!type && gpu_str_prefix(code, "sampler2DArray")) {
+ type = GPU_TEX2D_ARRAY;
+ }
if (!type && gpu_str_prefix(code, "sampler2D")) {
type = GPU_TEX2D;
}
@@ -618,7 +621,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
input->bindtex = false;
if (input->ima) {
/* input is texture from image */
- codegen_set_texid(bindhash, input, &texid, input->ima, input->image_tile);
+ codegen_set_texid(bindhash, input, &texid, input->ima, input->type);
}
else if (input->coba) {
/* input is color band texture, check coba pointer */
@@ -657,10 +660,18 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds,
if (input->source == GPU_SOURCE_TEX) {
/* create exactly one sampler for each texture */
if (codegen_input_has_texture(input) && input->bindtex) {
- BLI_dynstr_appendf(ds,
- "uniform %s samp%d;\n",
- (input->coba) ? "sampler1DArray" : "sampler2D",
- input->texid);
+ const char *type;
+ if (input->coba || input->type == GPU_TEX1D_ARRAY) {
+ type = "sampler1DArray";
+ }
+ else if (input->type == GPU_TEX2D_ARRAY) {
+ type = "sampler2DArray";
+ }
+ else {
+ BLI_assert(input->type == GPU_TEX2D);
+ type = "sampler2D";
+ }
+ BLI_dynstr_appendf(ds, "uniform %s samp%d;\n", type, input->texid);
}
}
else if (input->source == GPU_SOURCE_BUILTIN) {
@@ -1031,12 +1042,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
input->attr_id,
attr_prefix_get(input->attr_type),
attr_safe_name);
- /* Auto attribute can be vertex color byte buffer.
- * We need to know and convert them to linear space in VS. */
- if (input->attr_type == CD_AUTO_FROM_NAME) {
- BLI_dynstr_appendf(ds, "uniform bool ba%s;\n", attr_safe_name);
- BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%s\n", input->attr_id, attr_safe_name);
- }
}
BLI_dynstr_appendf(ds,
"out %s var%d%s;\n",
@@ -1090,24 +1095,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n");
- BLI_dynstr_append(ds,
- "#define USE_ATTR\n"
- "vec3 srgb_to_linear_attr(vec3 c) {\n"
- "\tc = max(c, vec3(0.0));\n"
- "\tvec3 c1 = c * (1.0 / 12.92);\n"
- "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n"
- "\treturn mix(c1, c2, step(vec3(0.04045), c));\n"
- "}\n\n");
-
- BLI_dynstr_append(ds,
- "vec4 srgba_to_linear_attr(vec4 c) {\n"
- "\tc = max(c, vec4(0.0));\n"
- "\tvec4 c1 = c * (1.0 / 12.92);\n"
- "\tvec4 c2 = pow((c + 0.055) * (1.0 / 1.055), vec4(2.4));\n"
- "\tvec4 final = mix(c1, c2, step(vec4(0.04045), c));"
- "\treturn vec4(final.xyz, c.a);\n"
- "}\n\n");
-
/* Prototype because defined later. */
BLI_dynstr_append(ds,
"vec2 hair_get_customdata_vec2(const samplerBuffer);\n"
@@ -1213,22 +1200,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
input->attr_id,
use_geom ? "g" : "");
}
- else if (input->attr_type == CD_MCOL) {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = srgba_to_linear_attr(att%d);\n",
- input->attr_id,
- use_geom ? "g" : "",
- input->attr_id);
- }
- else if (input->attr_type == CD_AUTO_FROM_NAME) {
- BLI_dynstr_appendf(ds,
- "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attr(att%d) : att%d;\n",
- input->attr_id,
- use_geom ? "g" : "",
- input->attr_id,
- input->attr_id,
- input->attr_id);
- }
else {
BLI_dynstr_appendf(
ds, "\tvar%d%s = att%d;\n", input->attr_id, use_geom ? "g" : "", input->attr_id);
@@ -1329,17 +1300,12 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons
"barycentricPosg[2]);\n");
}
- BLI_dynstr_append(ds, "\tgl_Position = gl_in[0].gl_Position;\n");
- BLI_dynstr_append(ds, "\tpass_attr(0);\n");
- BLI_dynstr_append(ds, "\tEmitVertex();\n");
-
- BLI_dynstr_append(ds, "\tgl_Position = gl_in[1].gl_Position;\n");
- BLI_dynstr_append(ds, "\tpass_attr(1);\n");
- BLI_dynstr_append(ds, "\tEmitVertex();\n");
-
- BLI_dynstr_append(ds, "\tgl_Position = gl_in[2].gl_Position;\n");
- BLI_dynstr_append(ds, "\tpass_attr(2);\n");
- BLI_dynstr_append(ds, "\tEmitVertex();\n");
+ for (int i = 0; i < 3; i++) {
+ BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[%d].gl_Position;\n", i);
+ BLI_dynstr_appendf(ds, "\tgl_ClipDistance[0] = gl_in[%d].gl_ClipDistance[0];\n", i);
+ BLI_dynstr_appendf(ds, "\tpass_attr(%d);\n", i);
+ BLI_dynstr_append(ds, "\tEmitVertex();\n");
+ }
BLI_dynstr_append(ds, "}\n");
}
}
@@ -1544,10 +1510,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->coba = link->coba;
break;
case GPU_NODE_LINK_IMAGE_BLENDER:
+ case GPU_NODE_LINK_IMAGE_TILEMAP:
input->source = GPU_SOURCE_TEX;
input->ima = link->ima;
input->iuser = link->iuser;
- input->image_tile = link->image_tile;
break;
case GPU_NODE_LINK_ATTR:
input->source = GPU_SOURCE_ATTR;
@@ -1792,13 +1758,12 @@ GPUNodeLink *GPU_uniform(float *num)
return link;
}
-GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, int tile)
+GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser)
{
GPUNodeLink *link = GPU_node_link_create();
link->link_type = GPU_NODE_LINK_IMAGE_BLENDER;
link->ima = ima;
link->iuser = iuser;
- link->image_tile = tile;
return link;
}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 0e6982c603e..f8e1b76580f 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -59,6 +59,7 @@ typedef enum {
GPU_NODE_LINK_COLORBAND,
GPU_NODE_LINK_CONSTANT,
GPU_NODE_LINK_IMAGE_BLENDER,
+ GPU_NODE_LINK_IMAGE_TILEMAP,
GPU_NODE_LINK_OUTPUT,
GPU_NODE_LINK_UNIFORM,
} GPUNodeLinkType;
@@ -95,11 +96,10 @@ struct GPUNodeLink {
const char *attr_name;
CustomDataType attr_type;
};
- /* GPU_NODE_LINK_IMAGE_BLENDER */
+ /* GPU_NODE_LINK_IMAGE_BLENDER | GPU_NODE_LINK_IMAGE_TILEMAP */
struct {
struct Image *ima;
struct ImageUser *iuser;
- int image_tile;
};
};
};
@@ -139,7 +139,6 @@ typedef struct GPUInput {
struct ImageUser *iuser; /* image user */
bool bindtex; /* input is responsible for binding the texture? */
int texid; /* number for multitexture, starting from zero */
- int image_tile; /* image tile */
eGPUType textype; /* texture type (2D, 1D Array ...) */
};
/* GPU_SOURCE_ATTR */
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 95738bb1a95..cfeb7f6bedb 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -31,6 +31,7 @@
#include <string.h>
#include "BLI_blenlib.h"
+#include "BLI_boxpack_2d.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_threads.h"
@@ -71,7 +72,7 @@ static bool is_power_of_2_resolution(int w, int h)
static bool is_over_resolution_limit(GLenum textarget, int w, int h)
{
- int size = (textarget == GL_TEXTURE_2D) ? GPU_max_texture_size() : GPU_max_cube_map_size();
+ int size = (textarget == GL_TEXTURE_CUBE_MAP) ? GPU_max_cube_map_size() : GPU_max_texture_size();
int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
return (w > reslimit || h > reslimit);
@@ -179,18 +180,294 @@ float GPU_get_anisotropic(void)
/* Set OpenGL state for an MTFace */
-static GPUTexture **gpu_get_tile_gputexture(ImageTile *tile, GLenum textarget)
+static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget)
{
if (textarget == GL_TEXTURE_2D) {
- return &tile->gputexture[TEXTARGET_TEXTURE_2D];
+ return &ima->gputexture[TEXTARGET_TEXTURE_2D];
}
else if (textarget == GL_TEXTURE_CUBE_MAP) {
- return &tile->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
+ return &ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
+ }
+ else if (textarget == GL_TEXTURE_2D_ARRAY) {
+ return &ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY];
+ }
+ else if (textarget == GL_TEXTURE_1D_ARRAY) {
+ return &ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING];
}
return NULL;
}
+static uint gpu_texture_create_tile_mapping(Image *ima)
+{
+ GPUTexture *tilearray = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY];
+ if (tilearray == NULL) {
+ return 0;
+ }
+
+ float array_w = GPU_texture_width(tilearray);
+ float array_h = GPU_texture_height(tilearray);
+
+ ImageTile *last_tile = ima->tiles.last;
+ /* Tiles are sorted by number. */
+ int max_tile = last_tile->tile_number - 1001;
+
+ /* create image */
+ int bindcode;
+ glGenTextures(1, (GLuint *)&bindcode);
+ glBindTexture(GL_TEXTURE_1D_ARRAY, bindcode);
+
+ int width = max_tile + 1;
+ float *data = MEM_callocN(width * 8 * sizeof(float), __func__);
+ for (int i = 0; i < width; i++) {
+ data[4 * i] = -1.0f;
+ }
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ int i = tile->tile_number - 1001;
+ data[4 * i] = tile->runtime.tilearray_layer;
+
+ float *tile_info = &data[4 * width + 4 * i];
+ tile_info[0] = tile->runtime.tilearray_offset[0] / array_w;
+ tile_info[1] = tile->runtime.tilearray_offset[1] / array_h;
+ tile_info[2] = tile->runtime.tilearray_size[0] / array_w;
+ tile_info[3] = tile->runtime.tilearray_size[1] / array_h;
+ }
+
+ glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA32F, width, 2, 0, GL_RGBA, GL_FLOAT, data);
+ MEM_freeN(data);
+
+ glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glBindTexture(GL_TEXTURE_1D_ARRAY, 0);
+
+ return bindcode;
+}
+
+typedef struct PackTile {
+ FixedSizeBoxPack boxpack;
+ ImageTile *tile;
+ float pack_score;
+} PackTile;
+
+static int compare_packtile(const void *a, const void *b)
+{
+ const PackTile *tile_a = a;
+ const PackTile *tile_b = b;
+
+ return tile_a->pack_score < tile_b->pack_score;
+}
+
+static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
+{
+ int arraywidth = 0, arrayheight = 0;
+
+ ListBase boxes = {NULL};
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+
+ if (ibuf) {
+ PackTile *packtile = MEM_callocN(sizeof(PackTile), __func__);
+ packtile->tile = tile;
+ packtile->boxpack.w = ibuf->x;
+ packtile->boxpack.h = ibuf->y;
+
+ if (is_over_resolution_limit(
+ GL_TEXTURE_2D_ARRAY, packtile->boxpack.w, packtile->boxpack.h)) {
+ packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
+ packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
+ }
+ arraywidth = max_ii(arraywidth, packtile->boxpack.w);
+ arrayheight = max_ii(arrayheight, packtile->boxpack.h);
+
+ /* We sort the tiles by decreasing size, with an additional penalty term
+ * for high aspect ratios. This improves packing efficiency. */
+ float w = packtile->boxpack.w, h = packtile->boxpack.h;
+ packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h;
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ BLI_addtail(&boxes, packtile);
+ }
+ }
+
+ BLI_assert(arraywidth > 0 && arrayheight > 0);
+
+ BLI_listbase_sort(&boxes, compare_packtile);
+ int arraylayers = 0;
+ /* Keep adding layers until all tiles are packed. */
+ while (boxes.first != NULL) {
+ ListBase packed = {NULL};
+ BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
+ BLI_assert(packed.first != NULL);
+
+ LISTBASE_FOREACH (PackTile *, packtile, &packed) {
+ ImageTile *tile = packtile->tile;
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int *tilesize = tile->runtime.tilearray_size;
+
+ tileoffset[0] = packtile->boxpack.x;
+ tileoffset[1] = packtile->boxpack.y;
+ tilesize[0] = packtile->boxpack.w;
+ tilesize[1] = packtile->boxpack.h;
+ tile->runtime.tilearray_layer = arraylayers;
+ }
+
+ BLI_freelistN(&packed);
+ arraylayers++;
+ }
+
+ /* create image */
+ int bindcode;
+ glGenTextures(1, (GLuint *)&bindcode);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, bindcode);
+
+ GLenum data_type, internal_format;
+ if (main_ibuf->rect_float) {
+ data_type = GL_FLOAT;
+ internal_format = GL_RGBA16F;
+ }
+ else {
+ data_type = GL_UNSIGNED_BYTE;
+ internal_format = GL_RGBA8;
+ if (!IMB_colormanagement_space_is_data(main_ibuf->rect_colorspace) &&
+ !IMB_colormanagement_space_is_scene_linear(main_ibuf->rect_colorspace)) {
+ internal_format = GL_SRGB8_ALPHA8;
+ }
+ }
+
+ glTexImage3D(GL_TEXTURE_2D_ARRAY,
+ 0,
+ internal_format,
+ arraywidth,
+ arrayheight,
+ arraylayers,
+ 0,
+ GL_RGBA,
+ data_type,
+ NULL);
+
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ int tilelayer = tile->runtime.tilearray_layer;
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int *tilesize = tile->runtime.tilearray_size;
+
+ if (tilesize[0] == 0 || tilesize[1] == 0) {
+ continue;
+ }
+
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile->tile_number;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ BLI_assert(ibuf != NULL);
+
+ bool needs_scale = (ibuf->x != tilesize[0] || ibuf->y != tilesize[1]);
+
+ ImBuf *scale_ibuf = NULL;
+ if (ibuf->rect_float) {
+ float *rect_float = ibuf->rect_float;
+
+ const bool store_premultiplied = ima->alpha_mode != IMA_ALPHA_STRAIGHT;
+ if (ibuf->channels != 4 || !store_premultiplied) {
+ rect_float = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
+ IMB_colormanagement_imbuf_to_float_texture(
+ rect_float, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
+ }
+
+ float *pixeldata = rect_float;
+ if (needs_scale) {
+ scale_ibuf = IMB_allocFromBuffer(NULL, rect_float, ibuf->x, ibuf->y, 4);
+ IMB_scaleImBuf(scale_ibuf, tilesize[0], tilesize[1]);
+ pixeldata = scale_ibuf->rect_float;
+ }
+
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
+ 0,
+ tileoffset[0],
+ tileoffset[1],
+ tilelayer,
+ tilesize[0],
+ tilesize[1],
+ 1,
+ GL_RGBA,
+ GL_FLOAT,
+ pixeldata);
+
+ if (rect_float != ibuf->rect_float) {
+ MEM_freeN(rect_float);
+ }
+ }
+ else {
+ unsigned int *rect = ibuf->rect;
+
+ if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
+ IMB_colormanagement_imbuf_to_byte_texture((uchar *)rect,
+ 0,
+ 0,
+ ibuf->x,
+ ibuf->y,
+ ibuf,
+ internal_format == GL_SRGB8_ALPHA8,
+ ima->alpha_mode == IMA_ALPHA_PREMUL);
+ }
+
+ unsigned int *pixeldata = rect;
+ if (needs_scale) {
+ scale_ibuf = IMB_allocFromBuffer(rect, NULL, ibuf->x, ibuf->y, 4);
+ IMB_scaleImBuf(scale_ibuf, tilesize[0], tilesize[1]);
+ pixeldata = scale_ibuf->rect;
+ }
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
+ 0,
+ tileoffset[0],
+ tileoffset[1],
+ tilelayer,
+ tilesize[0],
+ tilesize[1],
+ 1,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ pixeldata);
+
+ if (rect != ibuf->rect) {
+ MEM_freeN(rect);
+ }
+ }
+
+ if (scale_ibuf != NULL) {
+ IMB_freeImBuf(scale_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);
+
+ return bindcode;
+}
+
static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget)
{
uint bindcode = 0;
@@ -305,48 +582,105 @@ static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip,
return NULL;
}
-static void gpu_texture_update_scaled(
- uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h)
+static ImBuf *update_do_scale(uchar *rect,
+ float *rect_float,
+ int *x,
+ int *y,
+ int *w,
+ int *h,
+ int limit_w,
+ int limit_h,
+ int full_w,
+ int full_h)
{
/* Partial update with scaling. */
- int limit_w = smaller_power_of_2_limit(full_w);
- int limit_h = smaller_power_of_2_limit(full_h);
float xratio = limit_w / (float)full_w;
float yratio = limit_h / (float)full_h;
+ int part_w = *w, part_h = *h;
+
/* Find sub coordinates in scaled image. Take ceiling because we will be
* losing 1 pixel due to rounding errors in x,y. */
- int sub_x = x * xratio;
- int sub_y = y * yratio;
- int sub_w = (int)ceil(xratio * w);
- int sub_h = (int)ceil(yratio * h);
+ *x *= xratio;
+ *y *= yratio;
+ *w = (int)ceil(xratio * (*w));
+ *h = (int)ceil(yratio * (*h));
/* ...but take back if we are over the limit! */
- if (sub_w + sub_x > limit_w) {
- sub_w--;
+ if (*x + *w > limit_w) {
+ (*w)--;
}
- if (sub_h + sub_y > limit_h) {
- sub_h--;
+ if (*y + *h > limit_h) {
+ (*h)--;
}
/* Scale pixels. */
- ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h, 4);
- IMB_scaleImBuf(ibuf, sub_w, sub_h);
+ ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, part_w, part_h, 4);
+ IMB_scaleImBuf(ibuf, *w, *h);
+
+ return ibuf;
+}
+
+static void gpu_texture_update_scaled_array(uchar *rect,
+ float *rect_float,
+ int full_w,
+ int full_h,
+ int x,
+ int y,
+ int layer,
+ const int *tile_offset,
+ const int *tile_size,
+ int w,
+ int h)
+{
+ ImBuf *ibuf = update_do_scale(
+ rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h);
+
+ /* Shift to account for tile packing. */
+ x += tile_offset[0];
+ y += tile_offset[1];
if (ibuf->rect_float) {
- glTexSubImage2D(
- GL_TEXTURE_2D, 0, sub_x, sub_y, sub_w, sub_h, GL_RGBA, GL_FLOAT, ibuf->rect_float);
+ glTexSubImage3D(
+ GL_TEXTURE_2D_ARRAY, 0, x, y, layer, w, h, 1, GL_RGBA, GL_FLOAT, ibuf->rect_float);
}
else {
- glTexSubImage2D(
- GL_TEXTURE_2D, 0, sub_x, sub_y, sub_w, sub_h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ glTexSubImage3D(
+ GL_TEXTURE_2D_ARRAY, 0, x, y, layer, w, h, 1, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
}
IMB_freeImBuf(ibuf);
}
-static void gpu_texture_update_unscaled(
- uchar *rect, float *rect_float, int x, int y, int w, int h, GLint tex_stride, GLint tex_offset)
+static void gpu_texture_update_scaled(
+ uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h)
+{
+ /* Partial update with scaling. */
+ int limit_w = smaller_power_of_2_limit(full_w);
+ int limit_h = smaller_power_of_2_limit(full_h);
+
+ ImBuf *ibuf = update_do_scale(
+ rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
+
+ if (ibuf->rect_float) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, ibuf->rect_float);
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+
+ IMB_freeImBuf(ibuf);
+}
+
+static void gpu_texture_update_unscaled(uchar *rect,
+ float *rect_float,
+ int x,
+ int y,
+ int layer,
+ int w,
+ int h,
+ GLint tex_stride,
+ GLint tex_offset)
{
/* Partial update without scaling. Stride and offset are used to copy only a
* subset of a possible larger buffer than what we are updating. */
@@ -354,22 +688,61 @@ static void gpu_texture_update_unscaled(
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
glPixelStorei(GL_UNPACK_ROW_LENGTH, tex_stride);
- if (rect_float == NULL) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect + tex_offset);
+ if (layer >= 0) {
+ if (rect_float == NULL) {
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
+ 0,
+ x,
+ y,
+ layer,
+ w,
+ h,
+ 1,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ rect + tex_offset);
+ }
+ else {
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
+ 0,
+ x,
+ y,
+ layer,
+ w,
+ h,
+ 1,
+ GL_RGBA,
+ GL_FLOAT,
+ rect_float + tex_offset);
+ }
}
else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, rect_float + tex_offset);
+ if (rect_float == NULL) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect + tex_offset);
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, rect_float + tex_offset);
+ }
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
}
-static void gpu_texture_update_from_ibuf(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+static void gpu_texture_update_from_ibuf(
+ GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
{
/* Partial update of texture for texture painting. This is often much
- * quicker than fully updating the texture for high resolution images.
- * Assumes the OpenGL texture is bound to 0. */
- const bool scaled = is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y);
+ * quicker than fully updating the texture for high resolution images. */
+ GPU_texture_bind(tex, 0);
+
+ bool scaled;
+ if (tile != NULL) {
+ int *tilesize = tile->runtime.tilearray_size;
+ scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
+ }
+ else {
+ scaled = is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y);
+ }
if (scaled) {
/* Extra padding to account for bleed from neighboring pixels. */
@@ -429,11 +802,35 @@ static void gpu_texture_update_from_ibuf(Image *ima, ImBuf *ibuf, int x, int y,
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
- gpu_texture_update_scaled(rect, rect_float, ibuf->x, ibuf->y, x, y, w, h);
+ if (tile != NULL) {
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int *tilesize = tile->runtime.tilearray_size;
+ int tilelayer = tile->runtime.tilearray_layer;
+ gpu_texture_update_scaled_array(
+ rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
+ }
+ else {
+ gpu_texture_update_scaled(rect, rect_float, ibuf->x, ibuf->y, x, y, w, h);
+ }
}
else {
/* Fast update at same resolution. */
- gpu_texture_update_unscaled(rect, rect_float, x, y, w, h, tex_stride, tex_offset);
+ if (tile != NULL) {
+ int *tileoffset = tile->runtime.tilearray_offset;
+ int tilelayer = tile->runtime.tilearray_layer;
+ gpu_texture_update_unscaled(rect,
+ rect_float,
+ x + tileoffset[0],
+ y + tileoffset[1],
+ tilelayer,
+ w,
+ h,
+ tex_stride,
+ tex_offset);
+ }
+ else {
+ gpu_texture_update_unscaled(rect, rect_float, x, y, -1, w, h, tex_stride, tex_offset);
+ }
}
/* Free buffers if needed. */
@@ -443,9 +840,22 @@ static void gpu_texture_update_from_ibuf(Image *ima, ImBuf *ibuf, int x, int y,
if (rect_float && rect_float != ibuf->rect_float) {
MEM_freeN(rect_float);
}
+
+ if (GPU_get_mipmap()) {
+ glGenerateMipmap((tile != NULL) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D);
+ }
+ else {
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+ }
+
+ GPU_texture_unbind(tex);
}
-GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget)
+/* Get the GPUTexture for a given `Image`.
+ *
+ * `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
+ * available. It is also required when requesting the GPUTexture for a render result. */
+GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, int textarget)
{
if (ima == NULL) {
return NULL;
@@ -460,19 +870,8 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
/* Tag as in active use for garbage collector. */
BKE_image_tag_time(ima);
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
-
- if (tile == NULL) {
- /* TODO(lukas): When a tile gets deleted, the materials using the image
- * aren't rebuilt and therefore continue to use it.
- * This workaround isn't ideal, the result should be a pink color
- * (for a missing tile). With the current behavior, new tiles also won't
- * be detected. */
- tile = BKE_image_get_tile(ima, 0);
- }
-
/* Test if we already have a texture. */
- GPUTexture **tex = gpu_get_tile_gputexture(tile, textarget);
+ GPUTexture **tex = gpu_get_image_gputexture(ima, textarget);
if (*tex) {
return *tex;
}
@@ -480,25 +879,40 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
/* Check if we have a valid image. If not, we return a dummy
* texture with zero bindcode so we don't keep trying. */
uint bindcode = 0;
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
if (tile->ok == 0) {
*tex = GPU_texture_from_bindcode(textarget, bindcode);
return *tex;
}
/* check if we have a valid image buffer */
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf == NULL) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
+ ImBuf *ibuf_intern = ibuf;
+ if (ibuf_intern == NULL) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf_intern == NULL) {
+ *tex = GPU_texture_from_bindcode(textarget, bindcode);
+ return *tex;
+ }
}
- bindcode = gpu_texture_create_from_ibuf(ima, ibuf, textarget);
+ if (textarget == GL_TEXTURE_2D_ARRAY) {
+ bindcode = gpu_texture_create_tile_array(ima, ibuf_intern);
+ }
+ else if (textarget == GL_TEXTURE_1D_ARRAY) {
+ bindcode = gpu_texture_create_tile_mapping(ima);
+ }
+ else {
+ bindcode = gpu_texture_create_from_ibuf(ima, ibuf_intern, textarget);
+ }
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ /* if `ibuf` was given, we don't own the `ibuf_intern` */
+ if (ibuf == NULL) {
+ BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ }
*tex = GPU_texture_from_bindcode(textarget, bindcode);
- GPU_texture_orig_size_set(*tex, ibuf->x, ibuf->y);
+ GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
return *tex;
}
@@ -856,13 +1270,15 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
if (BKE_image_has_opengl_texture(ima)) {
if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
- if (tex != NULL) {
- GPU_texture_bind(tex, 0);
- 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));
- GPU_texture_unbind(tex);
+ for (int a = 0; a < TEXTARGET_COUNT; a++) {
+ if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) {
+ GPUTexture *tex = ima->gputexture[a];
+ if (tex != NULL) {
+ GPU_texture_bind(tex, 0);
+ 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));
+ GPU_texture_unbind(tex);
+ }
}
}
}
@@ -878,13 +1294,15 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
else {
for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
if (BKE_image_has_opengl_texture(ima)) {
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
- if (tex != NULL) {
- GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(tex);
+ for (int a = 0; a < TEXTARGET_COUNT; a++) {
+ if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) {
+ GPUTexture *tex = ima->gputexture[a];
+ if (tex != NULL) {
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ GPU_texture_unbind(tex);
+ }
}
}
}
@@ -899,26 +1317,22 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
{
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
- if ((tex == NULL) || (ibuf == NULL) || (w == 0) || (h == 0)) {
+ if ((ibuf == NULL) || (w == 0) || (h == 0)) {
/* Full reload of texture. */
GPU_free_image(ima);
}
- else {
- /* Partial update of texture. */
- GPU_texture_bind(tex, 0);
- gpu_texture_update_from_ibuf(ima, ibuf, x, y, w, h);
-
- if (GPU_get_mipmap()) {
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
+ GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D];
+ /* Check if we need to update the main gputexture. */
+ if (tex != NULL && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
+ }
- GPU_texture_unbind(tex);
+ /* Check if we need to update the array gputexture. */
+ tex = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY];
+ if (tex != NULL) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
}
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -960,13 +1374,11 @@ void GPU_free_unused_buffers(Main *bmain)
static void gpu_free_image_immediate(Image *ima)
{
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- /* free glsl image binding */
- if (tile->gputexture[i] != NULL) {
- GPU_texture_free(tile->gputexture[i]);
- tile->gputexture[i] = NULL;
- }
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ /* free glsl image binding */
+ if (ima->gputexture[i] != NULL) {
+ GPU_texture_free(ima->gputexture[i]);
+ ima->gputexture[i] = NULL;
}
}
diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c
index 871052bb070..a758787466f 100644
--- a/source/blender/gpu/intern/gpu_platform.c
+++ b/source/blender/gpu/intern/gpu_platform.c
@@ -158,7 +158,8 @@ void gpu_platform_init(void)
if (strstr(renderer, "UHD Graphics") ||
/* Not UHD but affected by the same bugs. */
- strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) {
+ strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2") ||
+ strstr(renderer, "Whiskey Lake")) {
GPG.device |= GPU_DEVICE_INTEL_UHD;
}
}
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 497fc13a2c8..84328b8dfd4 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1032,10 +1032,6 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint
GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
{
- /* see GPUInput::textarget: it can take two values - GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP
- * these values are correct for glDisable, so textarget can be safely used in
- * GPU_texture_bind/GPU_texture_unbind through tex->target_base */
- /* (is any of this obsolete now that we don't glEnable/Disable textures?) */
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->bindcode = bindcode;
tex->number = -1;
@@ -1052,12 +1048,8 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
else {
GLint w, h;
- GLenum gettarget;
-
- if (textarget == GL_TEXTURE_2D) {
- gettarget = GL_TEXTURE_2D;
- }
- else {
+ GLenum gettarget = textarget;
+ if (textarget == GL_TEXTURE_CUBE_MAP) {
gettarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
}
@@ -1072,56 +1064,6 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
return tex;
}
-GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
-{
- GPUTexture *tex = prv->gputexture[0];
- GLuint bindcode = 0;
-
- if (tex) {
- bindcode = tex->bindcode;
- }
-
- /* this binds a texture, so that's why we restore it to 0 */
- if (bindcode == 0) {
- GPU_create_gl_tex(
- &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, false, NULL);
- }
- if (tex) {
- tex->bindcode = bindcode;
- glBindTexture(GL_TEXTURE_2D, 0);
- return tex;
- }
-
- tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->bindcode = bindcode;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = GL_TEXTURE_2D;
- tex->target_base = GL_TEXTURE_2D;
- tex->format = -1;
- tex->components = -1;
-
- prv->gputexture[0] = tex;
-
- if (!glIsTexture(tex->bindcode)) {
- GPU_print_error_debug("Blender Texture Not Loaded");
- }
- else {
- GLint w, h;
-
- glBindTexture(GL_TEXTURE_2D, tex->bindcode);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
-
- tex->w = w;
- tex->h = h;
- }
-
- glBindTexture(GL_TEXTURE_2D, 0);
-
- return tex;
-}
-
GPUTexture *GPU_texture_create_1d(int w,
eGPUTextureFormat tex_format,
const float *pixels,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
index de3be98b715..94f69d35b7e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
@@ -106,7 +106,7 @@ void math_fraction(float a, float b, float c, out float result)
void math_modulo(float a, float b, float c, out float result)
{
- result = c_mod(a, b);
+ result = compatible_fmod(a, b);
}
void math_trunc(float a, float b, float c, out float result)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
index e8487fb5d42..df1c0479159 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -5,10 +5,11 @@ float safe_divide(float a, float b)
return (b != 0.0) ? a / b : 0.0;
}
-/* Modulo with C sign convention. mod in GLSL will take absolute for negative numbers. */
-float c_mod(float a, float b)
+/* fmod function compatible with OSL using nvidia reference example. */
+float compatible_fmod(float a, float b)
{
- return (b != 0.0 && a != b) ? sign(a) * mod(abs(a), b) : 0.0;
+ float c = (b != 0.0) ? fract(abs(a / b)) * abs(b) : 0.0;
+ return (a < 0.0) ? -c : c;
}
float compatible_pow(float x, float y)
@@ -88,9 +89,9 @@ vec4 safe_divide(vec4 a, float b)
return (b != 0.0) ? a / b : vec4(0.0);
}
-vec3 c_mod(vec3 a, vec3 b)
+vec3 compatible_fmod(vec3 a, vec3 b)
{
- return vec3(c_mod(a.x, b.x), c_mod(a.y, b.y), c_mod(a.z, b.z));
+ return vec3(compatible_fmod(a.x, b.x), compatible_fmod(a.y, b.y), compatible_fmod(a.z, b.z));
}
void invert_z(vec3 v, out vec3 outv)
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 fadb3b92df4..4633e59fde1 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
@@ -354,67 +354,92 @@ void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
alpha = 0.0;
}
-void node_tex_tile_map(vec3 co, out vec4 color, out vec3 map)
+bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
{
- float tx = floor(co.x);
- float ty = floor(co.y);
+ vec2 tile_pos = floor(co.xy);
- if (tx < 0 || ty < 0 || tx >= 10)
- map = vec3(0, 0, -1);
- else
- map = vec3(co.x - tx, co.y - ty, 1001 + 10 * ty + tx);
+ if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
+ return false;
- color = vec4(1.0, 0.0, 1.0, 1.0);
+ float tile = 10 * tile_pos.y + tile_pos.x;
+ if (tile >= textureSize(map, 0).x)
+ return false;
+
+ /* Fetch tile information. */
+ float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
+ if (tile_layer < 0)
+ return false;
+
+ vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
+
+ co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
+ return true;
}
void node_tex_tile_linear(
- vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+ vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
{
- if (map.z == tile_id) {
- vec3 co = map.xyy;
- node_tex_image_linear(co, ima, color, alpha);
+ if (node_tex_tile_lookup(co, ima, map)) {
+ color = safe_color(texture(ima, co));
}
else {
- color = in_color;
- alpha = color.a;
+ color = vec4(1.0, 0.0, 1.0, 1.0);
}
+
+ alpha = color.a;
}
void node_tex_tile_nearest(
- vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+ vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
{
- if (map.z == tile_id) {
- vec3 co = map.xyy;
- node_tex_image_nearest(co, ima, color, 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 = in_color;
- alpha = color.a;
+ color = vec4(1.0, 0.0, 1.0, 1.0);
}
+
+ alpha = color.a;
}
void node_tex_tile_cubic(
- vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+ vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
{
- if (map.z == tile_id) {
- vec3 co = map.xyy;
- node_tex_image_cubic(co, ima, color, alpha);
+ if (node_tex_tile_lookup(co, ima, map)) {
+ 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);
+
+ vec2 s0 = w0 + w1;
+ vec2 s1 = w2 + w3;
+
+ vec2 f0 = w1 / (w0 + w1);
+ vec2 f1 = w3 / (w2 + w3);
+
+ vec4 final_co;
+ final_co.xy = tc - 1.0 + f0;
+ final_co.zw = tc + 1.0 + f1;
+ final_co /= tex_size.xyxy;
+
+ color = safe_color(textureLod(ima, vec3(final_co.xy, co.z), 0.0)) * s0.x * s0.y;
+ color += safe_color(textureLod(ima, vec3(final_co.zy, co.z), 0.0)) * s1.x * s0.y;
+ color += safe_color(textureLod(ima, vec3(final_co.xw, co.z), 0.0)) * s0.x * s1.y;
+ color += safe_color(textureLod(ima, vec3(final_co.zw, co.z), 0.0)) * s1.x * s1.y;
}
else {
- color = in_color;
- alpha = color.a;
+ color = vec4(1.0, 0.0, 1.0, 1.0);
}
+
+ alpha = color.a;
}
void node_tex_tile_smart(
- vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
+ vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
{
- if (map.z == tile_id) {
- vec3 co = map.xyy;
- node_tex_image_smart(co, ima, color, alpha);
- }
- else {
- color = in_color;
- alpha = color.a;
- }
+ node_tex_tile_cubic(co, ima, map, color, alpha);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
index fce511deb79..b11d13a0413 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
@@ -1,21 +1,25 @@
/* White Noise */
-void node_white_noise_1d(vec3 vector, float w, out float value)
+void node_white_noise_1d(vec3 vector, float w, out float value, out vec4 color)
{
value = hash_float_to_float(w);
+ color.xyz = hash_float_to_vec3(w);
}
-void node_white_noise_2d(vec3 vector, float w, out float value)
+void node_white_noise_2d(vec3 vector, float w, out float value, out vec4 color)
{
value = hash_vec2_to_float(vector.xy);
+ color.xyz = hash_vec2_to_vec3(vector.xy);
}
-void node_white_noise_3d(vec3 vector, float w, out float value)
+void node_white_noise_3d(vec3 vector, float w, out float value, out vec4 color)
{
value = hash_vec3_to_float(vector);
+ color.xyz = hash_vec3_to_vec3(vector);
}
-void node_white_noise_4d(vec3 vector, float w, out float value)
+void node_white_noise_4d(vec3 vector, float w, out float value, out vec4 color)
{
value = hash_vec4_to_float(vec4(vector, w));
+ color.xyz = hash_vec4_to_vec3(vec4(vector, w));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
index 35d2e903cf4..63e97e66c90 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl
@@ -1,8 +1,41 @@
-void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
+/* ext is vec4(in_x, in_dy, out_x, out_dy). */
+float curve_extrapolate(float x, float y, vec4 ext)
{
- vec4 co = vec4(vec * 0.5 + 0.5, layer);
+ if (x < 0.0) {
+ return y + x * ext.y;
+ }
+ else if (x > 1.0) {
+ return y + (x - 1.0) * ext.w;
+ }
+ else {
+ return y;
+ }
+}
+
+#define RANGE_RESCALE(x, min, range) ((x - min) * range)
+
+void curves_vec(float fac,
+ vec3 vec,
+ sampler1DArray curvemap,
+ float layer,
+ vec3 range,
+ vec4 ext_x,
+ vec4 ext_y,
+ vec4 ext_z,
+ out vec3 outvec)
+{
+ vec4 co = vec4(vec, layer);
+
+ vec3 xyz_min = vec3(ext_x.x, ext_y.x, ext_z.x);
+ co.xyz = RANGE_RESCALE(co.xyz, xyz_min, range);
+
outvec.x = texture(curvemap, co.xw).x;
outvec.y = texture(curvemap, co.yw).y;
outvec.z = texture(curvemap, co.zw).z;
+
+ outvec.x = curve_extrapolate(co.x, outvec.r, ext_x);
+ outvec.y = curve_extrapolate(co.y, outvec.g, ext_y);
+ outvec.z = curve_extrapolate(co.z, outvec.b, ext_z);
+
outvec = mix(vec, outvec, fac);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
index 93132b6044f..420f177e146 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -76,7 +76,7 @@ void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float
void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outVector = c_mod(a, b);
+ outVector = compatible_fmod(a, b);
}
void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index b8d43b8e9c2..7aab644fc12 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -90,6 +90,9 @@ set(LIB
bf_intern_guardedalloc
bf_intern_memutil
bf_intern_opencolorio
+
+ ${PNG_LIBRARIES}
+ ${JPEG_LIBRARIES}
)
if(WITH_IMAGE_OPENEXR)
@@ -110,6 +113,9 @@ if(WITH_IMAGE_TIFF)
list(APPEND SRC
intern/tiff.c
)
+ list(APPEND LIB
+ ${TIFF_LIBRARY}
+ )
add_definitions(-DWITH_TIFF)
endif()
@@ -128,6 +134,9 @@ if(WITH_IMAGE_OPENJPEG)
list(APPEND SRC
intern/jp2.c
)
+ list(APPEND LIB
+ ${OPENJPEG_LIBRARIES}
+ )
add_definitions(-DWITH_OPENJPEG ${OPENJPEG_DEFINES})
endif()
@@ -149,6 +158,10 @@ if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${FFMPEG_LIBRARIES}
+ ${OPENJPEG_LIBRARIES}
+ )
add_definitions(-DWITH_FFMPEG)
remove_strict_c_flags_file(
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index ae3ac624e3b..58ecfce5a63 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -39,26 +39,26 @@
*/
typedef struct BMPINFOHEADER {
- unsigned int biSize;
- unsigned int biWidth;
- unsigned int biHeight;
- unsigned short biPlanes;
- unsigned short biBitCount;
- unsigned int biCompression;
- unsigned int biSizeImage;
- unsigned int biXPelsPerMeter;
- unsigned int biYPelsPerMeter;
- unsigned int biClrUsed;
- unsigned int biClrImportant;
+ uint biSize;
+ uint biWidth;
+ uint biHeight;
+ ushort biPlanes;
+ ushort biBitCount;
+ uint biCompression;
+ uint biSizeImage;
+ uint biXPelsPerMeter;
+ uint biYPelsPerMeter;
+ uint biClrUsed;
+ uint biClrImportant;
} BMPINFOHEADER;
#if 0
typedef struct BMPHEADER {
- unsigned short biType;
- unsigned int biSize;
- unsigned short biRes1;
- unsigned short biRes2;
- unsigned int biOffBits;
+ ushort biType;
+ uint biSize;
+ ushort biRes1;
+ ushort biRes2;
+ uint biOffBits;
} BMPHEADER;
#endif
@@ -70,12 +70,12 @@ typedef struct BMPHEADER {
CHECK_HEADER_FIELD(_mem, "CI") || CHECK_HEADER_FIELD(_mem, "CP") || \
CHECK_HEADER_FIELD(_mem, "IC") || CHECK_HEADER_FIELD(_mem, "PT"))
-static int checkbmp(const unsigned char *mem)
+static int checkbmp(const uchar *mem)
{
int ret_val = 0;
BMPINFOHEADER bmi;
- unsigned int u;
+ uint u;
if (mem) {
if (CHECK_HEADER_FIELD_BMP(mem)) {
@@ -104,22 +104,19 @@ static int checkbmp(const unsigned char *mem)
return (ret_val);
}
-int imb_is_a_bmp(const unsigned char *buf)
+int imb_is_a_bmp(const uchar *buf)
{
return checkbmp(buf);
}
-struct ImBuf *imb_bmp_decode(const unsigned char *mem,
- size_t size,
- int flags,
- char colorspace[IM_MAX_SPACE])
+ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
- struct ImBuf *ibuf = NULL;
+ ImBuf *ibuf = NULL;
BMPINFOHEADER bmi;
int x, y, depth, ibuf_depth, skip;
- const unsigned char *bmp;
- unsigned char *rect;
- unsigned short col;
+ const uchar *bmp;
+ uchar *rect;
+ ushort col;
double xppm, yppm;
bool top_to_bottom = false;
@@ -177,7 +174,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem,
return NULL;
}
- rect = (unsigned char *)ibuf->rect;
+ rect = (uchar *)ibuf->rect;
if (depth <= 8) {
const int rowsize = (depth * x + 31) / 32 * 4;
@@ -190,7 +187,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem,
int nbytes = 0;
const char *pcol;
if (top_to_bottom) {
- rect = (unsigned char *)&ibuf->rect[(i - 1) * x];
+ rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
bitoffs -= depth;
@@ -219,7 +216,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem,
else if (depth == 16) {
for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
- rect = (unsigned char *)&ibuf->rect[(i - 1) * x];
+ rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
col = bmp[0] + (bmp[1] << 8);
@@ -237,7 +234,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem,
const int x_pad = x % 4;
for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
- rect = (unsigned char *)&ibuf->rect[(i - 1) * x];
+ rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
rect[0] = bmp[2];
@@ -255,7 +252,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem,
else if (depth == 32) {
for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
- rect = (unsigned char *)&ibuf->rect[(i - 1) * x];
+ rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
rect[0] = bmp[2];
@@ -282,7 +279,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem,
#undef CHECK_HEADER_FIELD
/* Couple of helper functions for writing our data */
-static int putIntLSB(unsigned int ui, FILE *ofile)
+static int putIntLSB(uint ui, FILE *ofile)
{
putc((ui >> 0) & 0xFF, ofile);
putc((ui >> 8) & 0xFF, ofile);
@@ -290,42 +287,44 @@ static int putIntLSB(unsigned int ui, FILE *ofile)
return putc((ui >> 24) & 0xFF, ofile);
}
-static int putShortLSB(unsigned short us, FILE *ofile)
+static int putShortLSB(ushort us, FILE *ofile)
{
putc((us >> 0) & 0xFF, ofile);
return putc((us >> 8) & 0xFF, ofile);
}
/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
-int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags)
+int imb_savebmp(ImBuf *ibuf, const char *name, int UNUSED(flags))
{
BMPINFOHEADER infoheader;
- size_t bytesize, extrabytes, ptr;
- uchar *data;
- FILE *ofile;
- (void)flags; /* unused */
+ const size_t bytes_per_pixel = (ibuf->planes + 7) >> 3;
+ BLI_assert(bytes_per_pixel == 1 || bytes_per_pixel == 3);
- extrabytes = (4 - ibuf->x * 3 % 4) % 4;
- bytesize = (ibuf->x * 3 + extrabytes) * ibuf->y;
+ const size_t pad_bytes_per_scanline = (4 - ibuf->x * bytes_per_pixel % 4) % 4;
+ const size_t bytesize = (ibuf->x * bytes_per_pixel + pad_bytes_per_scanline) * ibuf->y;
- data = (uchar *)ibuf->rect;
- ofile = BLI_fopen(name, "wb");
- if (!ofile) {
+ const uchar *data = (const uchar *)ibuf->rect;
+ FILE *ofile = BLI_fopen(name, "wb");
+ if (ofile == NULL) {
return 0;
}
- putShortLSB(19778, ofile); /* "BM" */
- putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile); /* Total file size */
- putShortLSB(0, ofile); /* Res1 */
- putShortLSB(0, ofile); /* Res2 */
- putIntLSB(BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile);
+ const bool is_grayscale = bytes_per_pixel == 1;
+ const size_t palette_size = is_grayscale ? 255 * 4 : 0; /* RGBA32 */
+ const size_t pixel_array_start = BMP_FILEHEADER_SIZE + sizeof(infoheader) + palette_size;
+
+ putShortLSB(19778, ofile); /* "BM" */
+ putIntLSB(bytesize + pixel_array_start, ofile); /* Total file size */
+ putShortLSB(0, ofile); /* Res1 */
+ putShortLSB(0, ofile); /* Res2 */
+ putIntLSB(pixel_array_start, ofile); /* offset to start of pixel array */
putIntLSB(sizeof(infoheader), ofile);
putIntLSB(ibuf->x, ofile);
putIntLSB(ibuf->y, ofile);
putShortLSB(1, ofile);
- putShortLSB(24, ofile);
+ putShortLSB(is_grayscale ? 8 : 24, ofile);
putIntLSB(0, ofile);
putIntLSB(bytesize, ofile);
putIntLSB((int)(ibuf->ppm[0] + 0.5), ofile);
@@ -333,24 +332,52 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags)
putIntLSB(0, ofile);
putIntLSB(0, ofile);
- /* Need to write out padded image data in bgr format */
- for (size_t y = 0; y < ibuf->y; y++) {
- for (size_t x = 0; x < ibuf->x; x++) {
- ptr = (x + y * ibuf->x) * 4;
- if (putc(data[ptr + 2], ofile) == EOF) {
- return 0;
- }
- if (putc(data[ptr + 1], ofile) == EOF) {
- return 0;
+ /* color palette table, which is just every grayscale color, full alpha */
+ if (is_grayscale) {
+ for (char i = 0; i < 255; i++) {
+ putc(i, ofile);
+ putc(i, ofile);
+ putc(i, ofile);
+ putc(0xFF, ofile);
+ }
+ }
+
+ if (is_grayscale) {
+ for (size_t y = 0; y < ibuf->y; y++) {
+ for (size_t x = 0; x < ibuf->x; x++) {
+ const size_t ptr = (x + y * ibuf->x) * 4;
+ if (putc(data[ptr], ofile) == EOF) {
+ return 0;
+ }
}
- if (putc(data[ptr], ofile) == EOF) {
- return 0;
+ /* Add padding here. */
+ for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
+ if (putc(0, ofile) == EOF) {
+ return 0;
+ }
}
}
- /* add padding here */
- for (size_t t = 0; t < extrabytes; t++) {
- if (putc(0, ofile) == EOF) {
- return 0;
+ }
+ else {
+ /* Need to write out padded image data in BGR format. */
+ for (size_t y = 0; y < ibuf->y; y++) {
+ for (size_t x = 0; x < ibuf->x; x++) {
+ const size_t ptr = (x + y * ibuf->x) * 4;
+ if (putc(data[ptr + 2], ofile) == EOF) {
+ return 0;
+ }
+ if (putc(data[ptr + 1], ofile) == EOF) {
+ return 0;
+ }
+ if (putc(data[ptr], ofile) == EOF) {
+ return 0;
+ }
+ }
+ /* Add padding here. */
+ for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
+ if (putc(0, ofile) == EOF) {
+ return 0;
+ }
}
}
}
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
index 984e62bc75a..211b6a0b40e 100644
--- a/source/blender/imbuf/intern/oiio/CMakeLists.txt
+++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt
@@ -47,11 +47,22 @@ if(WITH_OPENIMAGEIO)
${OPENIMAGEIO_INCLUDE_DIRS}
${BOOST_INCLUDE_DIR}
)
+ list(APPEND LIB
+ ${OPENIMAGEIO_LIBRARIES}
+ )
if(WITH_IMAGE_OPENEXR)
list(APPEND INC_SYS
${OPENEXR_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${OPENEXR_LIBRARIES}
+ )
endif()
+
+ list(APPEND LIB
+ ${BOOST_LIBRARIES}
+ )
+
add_definitions(-DWITH_OPENIMAGEIO)
endif()
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index d2147f833c3..e001b8b21c4 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -33,9 +33,9 @@
#include "openimageio_api.h"
#include <OpenImageIO/imageio.h>
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "BLI_blenlib.h"
#include "IMB_imbuf_types.h"
diff --git a/source/blender/imbuf/intern/openexr/CMakeLists.txt b/source/blender/imbuf/intern/openexr/CMakeLists.txt
index fc584ace81e..a84f31c7025 100644
--- a/source/blender/imbuf/intern/openexr/CMakeLists.txt
+++ b/source/blender/imbuf/intern/openexr/CMakeLists.txt
@@ -47,6 +47,9 @@ if(WITH_IMAGE_OPENEXR)
list(APPEND INC_SYS
${OPENEXR_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${OPENEXR_LIBRARIES}
+ )
add_definitions(-DWITH_OPENEXR)
endif()
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 88dfa42a416..e1513169736 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -65,6 +65,8 @@
# include "utfconv.h"
#endif
+#include "MEM_guardedalloc.h"
+
extern "C" {
// The following prevents a linking error in debug mode for MSVC using the libs in CVS
@@ -74,8 +76,6 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
}
#endif
-#include "MEM_guardedalloc.h"
-
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BLI_threads.h"
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index fce68b11fe4..a75b01f2f75 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -457,9 +457,8 @@ typedef enum ID_Type {
(!ID_IS_LINKED((_id)) && ID_IS_OVERRIDE_LIBRARY((_id)) && \
(((ID *)(_id))->override_library->flag & OVERRIDE_LIBRARY_AUTO))
-/* No copy-on-write for these types.
- * Keep in sync with check_datablocks_copy_on_writable and deg_copy_on_write_is_needed */
-#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_LS, ID_PAL, ID_IM))
+/* Check whether datablock type is covered by copy-on-write. */
+#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_PAL, ID_IM))
#ifdef GS
# undef GS
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 354344328d3..7192b1295aa 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -252,7 +252,8 @@ typedef enum eBone_Flag {
BONE_ADD_PARENT_END_ROLL = (1 << 24),
/** this bone was transformed by the mirror function */
BONE_TRANSFORM_MIRROR = (1 << 25),
-
+ /** this bone is associated with a locked vertex group, ONLY USE FOR DRAWING */
+ BONE_DRAW_LOCKED_WEIGHT = (1 << 26),
} eBone_Flag;
/* bone->inherit_scale_mode */
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index 9d3689ce4ee..eec154ea09d 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -85,10 +85,10 @@
/* brush appearance */ \
\
/* add mode color is light red */ \
- .add_col = {1.0, 0.39, 0.39}, \
+ .add_col = {1.0, 0.39, 0.39, 0.9}, \
\
/* subtract mode color is light blue */ \
- .sub_col = {0.39, 0.39, 1.0}, \
+ .sub_col = {0.39, 0.39, 1.0, 0.9}, \
\
.stencil_pos = {256, 256}, \
.stencil_dimension = {256, 256}, \
@@ -96,6 +96,7 @@
/* sculpting defaults to the draw tool for new brushes */ \
.sculpt_tool = SCULPT_TOOL_DRAW, \
.pose_smooth_iterations = 4, \
+ .pose_ik_segments = 1, \
\
/* A kernel radius of 1 has almost no effect (T63233). */ \
.blur_kernel_radius = 2, \
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3860ea6b312..e711fd13822 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -336,8 +336,7 @@ typedef struct Brush {
/* pose */
float pose_offset;
int pose_smooth_iterations;
-
- char _pad2[4];
+ int pose_ik_segments;
/* multiplane scrape */
float multiplane_scrape_angle;
@@ -357,8 +356,8 @@ typedef struct Brush {
/* fill tool */
float fill_threshold;
- float add_col[3];
- float sub_col[3];
+ float add_col[4];
+ float sub_col[4];
float stencil_pos[2];
float stencil_dimension[2];
@@ -505,7 +504,7 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_ELASTIC_DEFORM = 21,
SCULPT_TOOL_POSE = 22,
SCULPT_TOOL_MULTIPLANE_SCRAPE = 23,
- SCULPT_TOOL_TOPOLOGY = 24,
+ SCULPT_TOOL_SLIDE_RELAX = 24,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
@@ -520,7 +519,7 @@ typedef enum eBrushUVSculptTool {
ELEM(t, \
SCULPT_TOOL_DRAW, \
SCULPT_TOOL_DRAW_SHARP, \
- SCULPT_TOOL_TOPOLOGY, \
+ SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_CREASE, \
SCULPT_TOOL_BLOB, \
SCULPT_TOOL_LAYER, \
@@ -543,7 +542,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_LAYER, \
SCULPT_TOOL_DRAW_SHARP, \
- SCULPT_TOOL_TOPOLOGY, \
+ SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_ELASTIC_DEFORM, \
SCULPT_TOOL_POSE, \
\
@@ -558,7 +557,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_DRAW_SHARP, \
- SCULPT_TOOL_TOPOLOGY, \
+ SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_MASK) == 0)
/* ImagePaintSettings.tool */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 0baa11c3059..f816041010b 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -336,6 +336,8 @@ typedef struct bActionConstraint {
float min;
float max;
int flag;
+ char mix_mode;
+ char _pad[7];
struct bAction *act;
/** MAX_ID_NAME-2. */
char subtarget[64];
@@ -865,6 +867,16 @@ typedef enum eActionConstraint_Flags {
ACTCON_BONE_USE_OBJECT_ACTION = (1 << 0),
} eActionConstraint_Flags;
+/* bActionConstraint.mix_mode */
+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,
+ /* Multiply the action transformation on the left, with anti-shear scale handling. */
+ ACTCON_MIX_BEFORE,
+} eActionConstraint_MixMode;
+
/* Locked-Axis Values (Locked Track) */
typedef enum eLockAxis_Modes {
LOCK_X = 0,
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 13eaa8925bc..a8d10471bb8 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -330,7 +330,7 @@ enum {
CU_BACK = 1 << 2,
CU_PATH = 1 << 3,
CU_FOLLOW = 1 << 4,
- CU_UV_ORCO = 1 << 5,
+ /* CU_UV_ORCO = 1 << 5, */ /* DEPRECATED */
CU_DEFORM_BOUNDS_OFF = 1 << 6,
CU_STRETCH = 1 << 7,
/* CU_OFFS_PATHDIST = 1 << 8, */ /* DEPRECATED */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index a42de5fe47b..afa7a5e58ba 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -181,6 +181,7 @@ typedef struct bGPDstroke_Runtime {
/** Original stroke (used to dereference evaluated data) */
struct bGPDstroke *gps_orig;
+ void *_pad2;
} bGPDstroke_Runtime;
/* Grease-Pencil Annotations - 'Stroke'
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 1c58d03a1a8..9a6cb24796f 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -91,11 +91,17 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
+typedef struct ImageTile_Runtime {
+ int tilearray_layer;
+ int _pad;
+ int tilearray_offset[2];
+ int tilearray_size[2];
+} ImageTile_Runtime;
+
typedef struct ImageTile {
struct ImageTile *next, *prev;
- /** Not written in file 2 = TEXTARGET_COUNT. */
- struct GPUTexture *gputexture[2];
+ struct ImageTile_Runtime runtime;
char ok;
char _pad[3];
@@ -114,7 +120,9 @@ typedef struct ImageTile {
enum {
TEXTARGET_TEXTURE_2D = 0,
TEXTARGET_TEXTURE_CUBE_MAP = 1,
- TEXTARGET_COUNT = 2,
+ TEXTARGET_TEXTURE_2D_ARRAY = 2,
+ TEXTARGET_TEXTURE_TILE_MAPPING = 3,
+ TEXTARGET_COUNT = 4,
};
typedef struct Image {
@@ -125,6 +133,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
+ /** Not written in file 4 = TEXTARGET_COUNT. */
+ struct GPUTexture *gputexture[4];
/* sources from: */
ListBase anims;
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index ebaaf72b3ae..648389d610f 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -27,50 +27,67 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
-/*tessellation face, see MLoop/MPoly for the real face data*/
-typedef struct MFace {
- unsigned int v1, v2, v3, v4;
- short mat_nr;
- /** We keep edcode, for conversion to edges draw flags in old files. */
- char edcode, flag;
-} MFace;
-
-typedef struct MEdge {
- unsigned int v1, v2;
- char crease, bweight;
- short flag;
-} MEdge;
-
-typedef struct MDeformWeight {
- int def_nr;
- float weight;
-} MDeformWeight;
-
-typedef struct MDeformVert {
- struct MDeformWeight *dw;
- int totweight;
- /** Flag only in use for weightpaint now. */
- int flag;
-} MDeformVert;
+/* -------------------------------------------------------------------- */
+/** \name Geometry Elements
+ * \{ */
+/**
+ * Mesh Vertices.
+ *
+ * Typically accessed from #Mesh.mvert
+ */
typedef struct MVert {
float co[3];
+ /**
+ * Cache the normal, can always be recalculated from surrounding faces.
+ * See #CD_CUSTOMLOOPNORMAL for custom normals.
+ */
short no[3];
char flag, bweight;
} MVert;
+/** #MVert.flag */
+enum {
+ /* SELECT = (1 << 0), */
+ ME_VERT_TMP_TAG = (1 << 2),
+ ME_HIDE = (1 << 4),
+ ME_VERT_FACEDOT = (1 << 5),
+ /* ME_VERT_MERGED = (1 << 6), */
+ ME_VERT_PBVH_UPDATE = (1 << 7),
+};
+
/**
- * Tessellation vertex color data.
- * at the moment alpha is abused for vertex painting and not used for transparency,
- * note that red and blue are swapped.
+ * Mesh Edges.
+ *
+ * Typically accessed from #Mesh.medge
*/
-typedef struct MCol {
- unsigned char a, r, g, b;
-} MCol;
+typedef struct MEdge {
+ /** Un-ordered vertex indices (cannot match). */
+ unsigned int v1, v2;
+ char crease, bweight;
+ short flag;
+} MEdge;
+
+/** #MEdge.flag */
+enum {
+ /* SELECT = (1 << 0), */
+ ME_EDGEDRAW = (1 << 1),
+ ME_SEAM = (1 << 2),
+ /* ME_HIDE = (1 << 4), */
+ ME_EDGERENDER = (1 << 5),
+ ME_LOOSEEDGE = (1 << 7),
+ ME_EDGE_TMP_TAG = (1 << 8),
+ ME_SHARP = (1 << 9), /* only reason this flag remains a 'short' */
+};
-/* new face structure, replaces MFace, which is now only used for storing tessellations.*/
+/**
+ * Mesh Faces
+ * This only stores the polygon size & flags, the vertex & edge indices are stored in the #MLoop.
+ *
+ * Typically accessed from #Mesh.mpoly.
+ */
typedef struct MPoly {
- /* offset into loop array and number of loops in the face */
+ /** Offset into loop array and number of loops in the face. */
int loopstart;
/** Keep signed since we need to subtract when getting the previous loop. */
int totloop;
@@ -78,14 +95,62 @@ typedef struct MPoly {
char flag, _pad;
} MPoly;
-/* the e here is because we want to move away from relying on edge hashes.*/
+/** #MPoly.flag */
+enum {
+ ME_SMOOTH = (1 << 0),
+ ME_FACE_SEL = (1 << 1),
+ /* ME_HIDE = (1 << 4), */
+};
+
+/**
+ * Mesh Loops.
+ * Each loop represents the corner of a polygon (#MPoly).
+ *
+ * Typically accessed from #Mesh.mloop.
+ */
typedef struct MLoop {
/** Vertex index. */
unsigned int v;
- /** Edge index. */
+ /**
+ * Edge index.
+ *
+ * \note The e here is because we want to move away from relying on edge hashes.
+ */
unsigned int e;
} MLoop;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ordered Selection Storage
+ * \{ */
+
+/**
+ * Optionally store the order of selected elements.
+ * This wont always be set since only some selection operations have an order.
+ *
+ * Typically accessed from #Mesh.mselect
+ */
+typedef struct MSelect {
+ /** Index in the vertex, edge or polygon array. */
+ int index;
+ /** #ME_VSEL, #ME_ESEL, #ME_FSEL. */
+ int type;
+} MSelect;
+
+/** #MSelect.type */
+enum {
+ ME_VSEL = 0,
+ ME_ESEL = 1,
+ ME_FSEL = 2,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Tesselation Runtime Data
+ * \{ */
+
/**
* #MLoopTri's are lightweight triangulation data,
* for functionality that doesn't support ngons (#MPoly).
@@ -187,12 +252,84 @@ typedef struct MVertTri {
unsigned int tri[3];
} MVertTri;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data (Generic)
+ * \{ */
+
+/** Custom Data Properties */
+typedef struct MFloatProperty {
+ float f;
+} MFloatProperty;
+typedef struct MIntProperty {
+ int i;
+} MIntProperty;
+typedef struct MStringProperty {
+ char s[255], s_len;
+} MStringProperty;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data (Vertex)
+ * \{ */
+
+/**
+ * Vertex group index and weight for #MDeformVert.dw
+ */
+typedef struct MDeformWeight {
+ /** The index for the vertex group, must *always* be unique when in an array. */
+ int def_nr;
+ /** Weight between 0.0 and 1.0. */
+ float weight;
+} MDeformWeight;
+
+typedef struct MDeformVert {
+ struct MDeformWeight *dw;
+ int totweight;
+ /** Flag is only in use as a run-time tag at the moment. */
+ int flag;
+} MDeformVert;
+
+typedef struct MVertSkin {
+ /**
+ * Radii of the skin, define how big the generated frames are.
+ * Currently only the first two elements are used.
+ */
+ float radius[3];
+
+ /** #eMVertSkinFlag */
+ int flag;
+} MVertSkin;
+
+typedef enum eMVertSkinFlag {
+ /** Marks a vertex as the edge-graph root, used for calculating rotations for all connected
+ * edges (recursively). Also used to choose a root when generating an armature.
+ */
+ MVERT_SKIN_ROOT = 1,
+
+ /** Marks a branch vertex (vertex with more than two connected edges), so that it's neighbors
+ * are directly hulled together, rather than the default of generating intermediate frames.
+ */
+ MVERT_SKIN_LOOSE = 2,
+} eMVertSkinFlag;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data (Loop)
+ * \{ */
+
+/**
+ * UV coordinate for a polygon face & flag for selection & other options.
+ */
typedef struct MLoopUV {
float uv[2];
int flag;
} MLoopUV;
-/*mloopuv->flag*/
+/** #MLoopUV.flag */
enum {
MLOOPUV_EDGESEL = (1 << 0),
MLOOPUV_VERTSEL = (1 << 1),
@@ -200,17 +337,157 @@ enum {
};
/**
- * at the moment alpha is abused for vertex painting,
- * otherwise it should _always_ be initialized to 255
- * Mostly its not used for transparency...
- * (except for blender-internal rendering, see [#34096]).
- *
- * \note red and blue are _not_ swapped, as they are with #MCol
+ * \note While alpha is currently is not in the view-port,
+ * this may eventually be added back, keep this value set to 255.
*/
typedef struct MLoopCol {
unsigned char r, g, b, a;
} MLoopCol;
+/** Multi-Resolution loop data. */
+typedef struct MDisps {
+ /* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */
+ int totdisp;
+ int level;
+ float (*disps)[3];
+
+ /**
+ * Used for hiding parts of a multires mesh.
+ * Essentially the multires equivalent of #MVert.flag's ME_HIDE bit.
+ *
+ * \note This is a bitmap, keep in sync with type used in BLI_bitmap.h
+ */
+ unsigned int *hidden;
+} MDisps;
+
+/** Multi-Resolution grid loop data. */
+typedef struct GridPaintMask {
+ /**
+ * The data array contains `grid_size * grid_size` elements.
+ * Where `grid_size = (1 << (level - 1)) + 1`.
+ */
+ float *data;
+
+ /** The maximum multires level associated with this grid. */
+ unsigned int level;
+
+ char _pad[4];
+} GridPaintMask;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data (Original Space for Poly, Face)
+ * \{ */
+
+/**
+ * Original space within a face (similar to UV coordinates),
+ * however they are used to determine the original position in a face.
+ *
+ * Unlike UV's these are not user editable and always start out using a fixed 0-1 range.
+ * Currently only used for particle placement.
+ */
+#
+#
+typedef struct OrigSpaceFace {
+ float uv[4][2];
+} OrigSpaceFace;
+
+#
+#
+typedef struct OrigSpaceLoop {
+ float uv[2];
+} OrigSpaceLoop;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data (FreeStyle for Edge, Face)
+ * \{ */
+
+typedef struct FreestyleEdge {
+ char flag;
+ char _pad[3];
+} FreestyleEdge;
+
+/** #FreestyleEdge.flag */
+enum {
+ FREESTYLE_EDGE_MARK = 1,
+};
+
+typedef struct FreestyleFace {
+ char flag;
+ char _pad[3];
+} FreestyleFace;
+
+/** #FreestyleFace.flag */
+enum {
+ FREESTYLE_FACE_MARK = 1,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utility Macros
+ * \{ */
+
+#define ME_POLY_LOOP_PREV(mloop, mp, i) \
+ (&(mloop)[(mp)->loopstart + (((i) + (mp)->totloop - 1) % (mp)->totloop)])
+#define ME_POLY_LOOP_NEXT(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + 1) % (mp)->totloop)])
+
+/** Number of tri's that make up this polygon once tessellated. */
+#define ME_POLY_TRI_TOT(mp) ((mp)->totloop - 2)
+
+/**
+ * Check out-of-bounds material, note that this is nearly always prevented,
+ * yet its still possible in rare cases.
+ * So usage such as array lookup needs to check.
+ */
+#define ME_MAT_NR_TEST(mat_nr, totmat) \
+ (CHECK_TYPE_ANY(mat_nr, short, const short), \
+ CHECK_TYPE_ANY(totmat, short, const short), \
+ (LIKELY(mat_nr < totmat) ? mat_nr : 0))
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Deprecated Structs
+ * \{ */
+
+/**
+ * Used in Blender pre 2.63, See #MLoop, #MPoly for face data stored in the blend file.
+ * Use for reading old files and in a handful of cases which should be removed eventually.
+ */
+typedef struct MFace {
+ unsigned int v1, v2, v3, v4;
+ short mat_nr;
+ /** We keep edcode, for conversion to edges draw flags in old files. */
+ char edcode, flag;
+} MFace;
+
+/** #MFace.edcode */
+enum {
+ ME_V1V2 = (1 << 0),
+ ME_V2V3 = (1 << 1),
+ ME_V3V1 = (1 << 2),
+ ME_V3V4 = ME_V3V1,
+ ME_V4V1 = (1 << 3),
+};
+
+/** Tessellation uv face data. */
+typedef struct MTFace {
+ float uv[4][2];
+} MTFace;
+
+/**
+ * Tessellation vertex color data.
+ *
+ * \note The red and blue are swapped for historical reasons.
+ */
+typedef struct MCol {
+ unsigned char a, r, g, b;
+} MCol;
+
#define MESH_MLOOPCOL_FROM_MCOL(_mloopcol, _mcol) \
{ \
MLoopCol *mloopcol__tmp = _mloopcol; \
@@ -233,50 +510,10 @@ typedef struct MLoopCol {
} \
(void)0
-typedef struct MSelect {
- int index;
- /** ME_VSEL/ME_ESEL/ME_FSEL. */
- int type;
-} MSelect;
-
-/*tessellation uv face data*/
-typedef struct MTFace {
- float uv[4][2];
-} MTFace;
-
-/*Custom Data Properties*/
-typedef struct MFloatProperty {
- float f;
-} MFloatProperty;
-typedef struct MIntProperty {
+/** Old game engine recast navigation data, while unused 2.7x files may contain this. */
+typedef struct MRecast {
int i;
-} MIntProperty;
-typedef struct MStringProperty {
- char s[255], s_len;
-} MStringProperty;
-
-typedef struct OrigSpaceFace {
- float uv[4][2];
-} OrigSpaceFace;
-
-typedef struct OrigSpaceLoop {
- float uv[2];
-} OrigSpaceLoop;
-
-typedef struct MDisps {
- /* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */
- int totdisp;
- int level;
- float (*disps)[3];
-
- /**
- * Used for hiding parts of a multires mesh.
- * Essentially the multires equivalent of MVert.flag's ME_HIDE bit.
- *
- * \note This is a bitmap, keep in sync with type used in BLI_bitmap.h
- */
- unsigned int *hidden;
-} MDisps;
+} MRecast;
/** Multires structs kept for compatibility with old files. */
typedef struct MultiresCol {
@@ -326,131 +563,8 @@ typedef struct Multires {
short *edge_flags;
char *edge_creases;
} Multires;
+/* End multi-res structs. */
-/* End Multires */
-
-typedef struct MRecast {
- int i;
-} MRecast;
-
-typedef struct GridPaintMask {
- /* The data array contains gridsize*gridsize elements */
- float *data;
-
- /* The maximum multires level associated with this grid */
- unsigned int level;
-
- char _pad[4];
-} GridPaintMask;
-
-typedef enum eMVertSkinFlag {
- /** Marks a vertex as the edge-graph root, used for calculating rotations for all connected
- * edges (recursively). Also used to choose a root when generating an armature.
- */
- MVERT_SKIN_ROOT = 1,
-
- /** Marks a branch vertex (vertex with more than two connected edges), so that it's neighbors
- * are directly hulled together, rather than the default of generating intermediate frames.
- */
- MVERT_SKIN_LOOSE = 2,
-} eMVertSkinFlag;
-
-typedef struct MVertSkin {
- /* Radii of the skin, define how big the generated frames are.
- * Currently only the first two elements are used. */
- float radius[3];
-
- /* eMVertSkinFlag */
- int flag;
-} MVertSkin;
-
-typedef struct FreestyleEdge {
- char flag;
- char _pad[3];
-} FreestyleEdge;
-
-/* FreestyleEdge->flag */
-enum {
- FREESTYLE_EDGE_MARK = 1,
-};
-
-typedef struct FreestyleFace {
- char flag;
- char _pad[3];
-} FreestyleFace;
-
-/* FreestyleFace->flag */
-enum {
- FREESTYLE_FACE_MARK = 1,
-};
-
-/* mvert->flag */
-enum {
- /* SELECT = (1 << 0), */
- ME_VERT_TMP_TAG = (1 << 2),
- ME_HIDE = (1 << 4),
- ME_VERT_FACEDOT = (1 << 5),
- /* ME_VERT_MERGED = (1 << 6), */
- ME_VERT_PBVH_UPDATE = (1 << 7),
-};
-
-/* medge->flag */
-enum {
- /* SELECT = (1 << 0), */
- ME_EDGEDRAW = (1 << 1),
- ME_SEAM = (1 << 2),
- /* ME_HIDE = (1 << 4), */
- ME_EDGERENDER = (1 << 5),
- ME_LOOSEEDGE = (1 << 7),
- ME_EDGE_TMP_TAG = (1 << 8),
- ME_SHARP = (1 << 9), /* only reason this flag remains a 'short' */
-};
-
-/* puno = vertexnormal (mface) */
-enum {
- ME_PROJXY = (1 << 4),
- ME_PROJXZ = (1 << 5),
- ME_PROJYZ = (1 << 6),
-};
-
-/* edcode (mface) */
-enum {
- ME_V1V2 = (1 << 0),
- ME_V2V3 = (1 << 1),
- ME_V3V1 = (1 << 2),
- ME_V3V4 = ME_V3V1,
- ME_V4V1 = (1 << 3),
-};
-
-/* flag (mface) */
-enum {
- ME_SMOOTH = (1 << 0),
- ME_FACE_SEL = (1 << 1),
- /* ME_HIDE = (1 << 4), */
-};
-
-#define ME_POLY_LOOP_PREV(mloop, mp, i) \
- (&(mloop)[(mp)->loopstart + (((i) + (mp)->totloop - 1) % (mp)->totloop)])
-#define ME_POLY_LOOP_NEXT(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + 1) % (mp)->totloop)])
-
-/* number of tri's that make up this polygon once tessellated */
-#define ME_POLY_TRI_TOT(mp) ((mp)->totloop - 2)
-
-/**
- * Check out-of-bounds material, note that this is nearly always prevented,
- * yet its still possible in rare cases.
- * So usage such as array lookup needs to check.
- */
-#define ME_MAT_NR_TEST(mat_nr, totmat) \
- (CHECK_TYPE_ANY(mat_nr, short, const short), \
- CHECK_TYPE_ANY(totmat, short, const short), \
- (LIKELY(mat_nr < totmat) ? mat_nr : 0))
-
-/* mselect->type */
-enum {
- ME_VSEL = 0,
- ME_ESEL = 1,
- ME_FSEL = 2,
-};
+/** \} */
#endif /* __DNA_MESHDATA_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 9db993cca59..62817c3b563 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -611,6 +611,7 @@ typedef struct CastModifierData {
/* Cast modifier flags */
enum {
/* And what bout (1 << 0) flag? ;) */
+ MOD_CAST_INVERT_VGROUP = (1 << 0),
MOD_CAST_X = (1 << 1),
MOD_CAST_Y = (1 << 2),
MOD_CAST_Z = (1 << 3),
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 2e0c43bdb51..5548a8405f9 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -64,8 +64,8 @@ typedef struct MovieClipProxy {
typedef struct MovieClip_RuntimeGPUTexture {
void *next, *prev;
MovieClipUser user;
- /** Not written in file 2 = TEXTARGET_COUNT. */
- struct GPUTexture *gputexture[2];
+ /** Not written in file 4 = TEXTARGET_COUNT. */
+ struct GPUTexture *gputexture[4];
} MovieClip_RuntimeGPUTexture;
typedef struct MovieClip_Runtime {
diff --git a/source/blender/makesdna/DNA_object_defaults.h b/source/blender/makesdna/DNA_object_defaults.h
index 1105a8fd4e1..554d68f2d4a 100644
--- a/source/blender/makesdna/DNA_object_defaults.h
+++ b/source/blender/makesdna/DNA_object_defaults.h
@@ -66,7 +66,6 @@
.col_mask = 0xffff, \
.preview = NULL, \
.duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER, \
- .fluidsimSettings = NULL, \
.pc_ids = {NULL, NULL}, \
}
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index f6389f8793a..a1a9772c028 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -409,8 +409,6 @@ typedef struct Object {
struct FluidsimSettings *fluidsimSettings
DNA_DEPRECATED; // XXX deprecated... replaced by mantaflow, keep for readfile
- struct DerivedMesh *derivedDeform, *derivedFinal;
-
ListBase pc_ids;
/** Settings for Bullet rigid body. */
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 5012fbeca91..373c193b4ab 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -443,6 +443,10 @@ enum {
PART_FLUID_BUBBLE = 6,
PART_FLUID_FOAM = 7,
PART_FLUID_TRACER = 8,
+ PART_FLUID_SPRAYFOAM = 9,
+ PART_FLUID_SPRAYBUBBLE = 10,
+ PART_FLUID_FOAMBUBBLE = 11,
+ PART_FLUID_SPRAYFOAMBUBBLE = 12,
};
/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 988baff8481..c06a0447e9e 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1863,6 +1863,7 @@ typedef struct Scene {
/** Settings to be override by workspaces. */
IDProperty *layer_properties;
+ void *_pad9;
struct SceneDisplay display;
struct SceneEEVEE eevee;
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index d3c5a707b44..a52767834a4 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -129,6 +129,12 @@ typedef struct ScrAreaMap {
ListBase areabase;
} 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];
+} Panel_Runtime;
+
/** The part from uiBlock that needs saved in file. */
typedef struct Panel {
struct Panel *next, *prev;
@@ -159,6 +165,8 @@ typedef struct Panel {
void *activedata;
/** Sub panels. */
ListBase children;
+
+ Panel_Runtime runtime;
} Panel;
/**
@@ -409,7 +417,9 @@ typedef struct ARegion {
short flag;
/** Current split size in unscaled pixels (if zero it uses regiontype).
- * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`. */
+ * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`.
+ * However to get the current region size, you should usually use winx/winy from above, not this!
+ */
short sizex, sizey;
/** Private, cached notifier events. */
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index ead1bcc943d..3d3d215b973 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -406,8 +406,8 @@ typedef struct ColorMapping {
/* return value */
#define TEX_INT 0
-#define TEX_RGB 1
-#define TEX_NOR 2
+#define TEX_RGB (1 << 0)
+#define TEX_NOR (1 << 1)
/* pr_texture in material, world, light. */
#define TEX_PR_TEXTURE 0
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 1f92b134e4c..d741f22cc4f 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -283,13 +283,12 @@ typedef struct ThemeSpace {
unsigned char normal[4];
unsigned char vertex_normal[4];
unsigned char loop_normal[4];
- unsigned char bone_solid[4], bone_pose[4], bone_pose_active[4];
+ unsigned char bone_solid[4], bone_pose[4], bone_pose_active[4], bone_locked_weight[4];
unsigned char strip[4], strip_select[4];
unsigned char cframe[4];
unsigned char time_keyframe[4], time_gp_keyframe[4];
unsigned char freestyle_edge_mark[4], freestyle_face_mark[4];
unsigned char time_scrub_background[4];
- char _pad5[4];
unsigned char nurb_uline[4], nurb_vline[4];
unsigned char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4];
@@ -414,6 +413,8 @@ typedef struct ThemeSpace {
unsigned char info_warning[4], info_warning_text[4];
unsigned char info_info[4], info_info_text[4];
unsigned char info_debug[4], info_debug_text[4];
+ unsigned char info_property[4], info_property_text[4];
+ unsigned char info_operator[4], info_operator_text[4];
unsigned char paint_curve_pivot[4];
unsigned char paint_curve_handle[4];
@@ -601,10 +602,7 @@ typedef struct UserDef_FileSpaceData {
} UserDef_FileSpaceData;
typedef struct UserDef_Experimental {
- char use_tool_fallback;
- char use_usd_exporter;
-
- char _pad0[6];
+ char _pad0[8]; /* makesdna does not allow empty structs. */
} UserDef_Experimental;
#define USER_EXPERIMENTAL_TEST(userdef, member) \
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index 573b076542e..d2461657480 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -35,8 +35,7 @@ typedef struct bToolRef_Runtime {
char gizmo_group[64];
char data_block[64];
- /** Optionally use these when not interacting directly with the primary tools gizmo. */
- char idname_fallback[64];
+ /** Keymap for #bToolRef.idname_fallback, if set. */
char keymap_fallback[64];
/** Use to infer primary operator to use when setting accelerator keys. */
@@ -51,6 +50,9 @@ typedef struct bToolRef {
struct bToolRef *next, *prev;
char idname[64];
+ /** Optionally use these when not interacting directly with the primary tools gizmo. */
+ char idname_fallback[64];
+
/** Use to avoid initializing the same tool multiple times. */
short tag;
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 77e3fe67ff4..b45d71d3c9d 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -943,7 +943,11 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
/* Write size verification to file. */
{
- char *name_static = alloca(namelen + 1);
+ /* Normally 'alloca' would be used here, however we can't in a loop.
+ * Use an over-sized buffer instead. */
+ char name_static[1024];
+ BLI_assert(sizeof(name_static) > namelen);
+
DNA_elem_id_strip_copy(name_static, cp);
const char *str_pair[2] = {types[structtype], name_static};
const char *name_alias = BLI_ghash_lookup(g_version_data.elem_map_alias_from_static,
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 0beb14614ec..349b30fa64e 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -233,6 +233,16 @@ PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont,
const char *ui_description,
float softmin,
float softmax);
+PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont,
+ const char *identifier,
+ int len,
+ const float *default_value,
+ float hardmin,
+ float hardmax,
+ const char *ui_name,
+ const char *ui_description,
+ float softmin,
+ float softmax);
PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont,
const char *identifier,
int len,
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index d7f6ec1fb5a..c10436ae08e 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -52,6 +52,7 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[];
extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern const EnumPropertyItem rna_enum_space_graph_mode_items[];
+extern const EnumPropertyItem rna_enum_space_sequencer_view_type_items[];
extern const EnumPropertyItem rna_enum_space_type_items[];
extern const EnumPropertyItem rna_enum_space_image_mode_items[];
extern const EnumPropertyItem rna_enum_space_image_mode_all_items[];
@@ -141,6 +142,8 @@ extern const EnumPropertyItem rna_enum_texture_type_items[];
extern const EnumPropertyItem rna_enum_light_type_items[];
+extern const EnumPropertyItem rna_enum_lightprobes_type_items[];
+
extern const EnumPropertyItem rna_enum_unpack_method_items[];
extern const EnumPropertyItem rna_enum_object_type_items[];
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 86a12b66db7..3429fd25242 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -229,6 +229,10 @@ if(WITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${AUDASPACE_C_LIBRARIES}
+ ${AUDASPACE_PY_LIBRARIES}
+ )
endif()
if(WITH_CODEC_FFMPEG)
@@ -238,6 +242,9 @@ if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${FFMPEG_LIBRARIES}
+ )
add_definitions(-DWITH_FFMPEG)
endif()
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index d8889455ac7..bd2e522c4b4 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -3762,25 +3762,59 @@ void RNA_property_pointer_set(PointerRNA *ptr,
ReportList *reports)
{
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
+ IDProperty *idprop = rna_idproperty_check(&prop, ptr);
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
- /* Check types */
- if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "%s: expected %s type, not %s.\n",
- __func__,
- pprop->type->identifier,
- ptr_value.type->identifier);
- return;
+ /* Check types. */
+ if (pprop->set != NULL) {
+ /* Assigning to a real RNA property. */
+ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "%s: expected %s type, not %s.\n",
+ __func__,
+ pprop->type->identifier,
+ ptr_value.type->identifier);
+ return;
+ }
+ }
+ else {
+ /* Assigning to an IDProperty desguised as RNA one. */
+ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, &RNA_ID)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "%s: expected ID type, not %s.\n",
+ __func__,
+ ptr_value.type->identifier);
+ return;
+ }
}
- /* RNA */
- if (pprop->set && !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
- !((prop->flag & PROP_ID_SELF_CHECK) && ptr->owner_id == ptr_value.owner_id)) {
+ /* We got an existing IDProperty. */
+ if (idprop != NULL) {
+ /* Not-yet-defined ID IDProps have an IDP_GROUP type, not an IDP_ID one - because of reasons?
+ * XXX This has to be investigated fully - there might be a good reason for it, but off hands
+ * this seems really weird... */
+ if (idprop->type == IDP_ID) {
+ IDP_AssignID(idprop, ptr_value.data, 0);
+ rna_idproperty_touch(idprop);
+ }
+ else {
+ BLI_assert(idprop->type == IDP_GROUP);
+
+ IDPropertyTemplate val = {.id = ptr_value.data};
+ IDProperty *group = RNA_struct_idprops(ptr, true);
+ BLI_assert(group != NULL);
+
+ IDP_ReplaceInGroup_ex(group, IDP_New(IDP_ID, &val, idprop->name), idprop);
+ }
+ }
+ /* RNA property. */
+ else if (pprop->set && !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
+ !((prop->flag & PROP_ID_SELF_CHECK) && ptr->owner_id == ptr_value.owner_id)) {
pprop->set(ptr, ptr_value, reports);
}
- /* IDProperty */
+ /* IDProperty desguised as RNA property (and not yet defined in ptr). */
else if (prop->flag & PROP_EDITABLE) {
IDPropertyTemplate val = {0};
IDProperty *group;
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index f539da488ce..61a1f1ffcd5 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -63,6 +63,8 @@ static void rna_AnimViz_path_start_frame_set(PointerRNA *ptr, int value)
/* XXX: watchit! Path Start > MAXFRAME/2 could be a problem... */
data->path_sf = value;
+ FRAMENUMBER_MIN_CLAMP(data->path_sf);
+
CLAMP(data->path_ef, data->path_sf + 1, MAXFRAME / 2);
}
@@ -71,7 +73,11 @@ static void rna_AnimViz_path_end_frame_set(PointerRNA *ptr, int value)
bAnimVizSettings *data = (bAnimVizSettings *)ptr->data;
data->path_ef = value;
- CLAMP(data->path_sf, 1, data->path_ef - 1);
+ CLAMP_MAX(data->path_sf, data->path_ef - 1);
+ if (U.flag & USER_NONEGFRAMES) {
+ CLAMP_MIN(data->path_sf, 0);
+ CLAMP_MIN(data->path_ef, 1);
+ }
}
#else
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 5b683ffd80e..aded0a6ba09 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -93,7 +93,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""},
{SCULPT_TOOL_NUDGE, "NUDGE", ICON_BRUSH_NUDGE, "Nudge", ""},
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
- {SCULPT_TOOL_TOPOLOGY, "TOPOLOGY", ICON_BRUSH_GRAB, "Topology", ""},
+ {SCULPT_TOOL_SLIDE_RELAX, "TOPOLOGY", ICON_BRUSH_GRAB, "Slide Relax", ""},
{0, "", 0, NULL, NULL},
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
@@ -1927,6 +1927,16 @@ static void rna_def_brush(BlenderRNA *brna)
"Smooth iterations applied after calculating the pose factor of each vertex");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_ik_segments", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "pose_ik_segments");
+ RNA_def_property_range(prop, 1, 20);
+ RNA_def_property_ui_range(prop, 1, 20, 1, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "Pose IK Segments",
+ "Number of segments of the inverse kinematics chain that will deform the mesh");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);
@@ -2374,13 +2384,13 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "add_col");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Add Color", "Color of cursor when adding");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "cursor_color_subtract", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "sub_col");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Subtract Color", "Color of cursor when subtracting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 679ccc9725b..215ccc78bc2 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -329,10 +329,11 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
WM_main_add_notifier(NC_LINESTYLE, linestyle);
break;
}
+ /* ColorRamp for particle display is owned by the object (see T54422) */
+ case ID_OB:
case ID_PA: {
ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
- DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_REDO);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, part);
}
default:
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 6a10074810d..8e57de9baeb 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -633,6 +633,23 @@ static void rna_ArmatureConstraint_target_clear(ID *id, bConstraint *con, Main *
ED_object_constraint_dependency_tag_update(bmain, (Object *)id, con);
}
+static void rna_ActionConstraint_mix_mode_set(PointerRNA *ptr, int value)
+{
+ bConstraint *con = (bConstraint *)ptr->data;
+ bActionConstraint *acon = (bActionConstraint *)con->data;
+
+ acon->mix_mode = value;
+
+ /* The After mode can be computed in world space for efficiency
+ * and backward compatibility, while Before requires Local. */
+ if (ELEM(value, ACTCON_MIX_AFTER, ACTCON_MIX_AFTER_FULL)) {
+ con->ownspace = CONSTRAINT_SPACE_WORLD;
+ }
+ else {
+ con->ownspace = CONSTRAINT_SPACE_LOCAL;
+ }
+}
+
static void rna_ActionConstraint_minmax_range(
PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax))
{
@@ -1618,6 +1635,29 @@ static void rna_def_constraint_action(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem mix_mode_items[] = {
+ {ACTCON_MIX_BEFORE,
+ "BEFORE",
+ 0,
+ "Before Original",
+ "Apply the action channels before the original transformation, "
+ "as if applied to an imaginary parent with Aligned Inherit Scale"},
+ {ACTCON_MIX_AFTER,
+ "AFTER",
+ 0,
+ "After Original",
+ "Apply the action channels after the original transformation, "
+ "as if applied to an imaginary child with Aligned Inherit Scale"},
+ {ACTCON_MIX_AFTER_FULL,
+ "AFTER_FULL",
+ 0,
+ "After Original (Full Scale)",
+ "Apply the action channels after the original transformation, as if "
+ "applied to an imaginary child with Full Inherit Scale. This mode "
+ "can create shear and is provided only for backward compatibility"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "ActionConstraint", "Constraint");
RNA_def_struct_ui_text(
srna, "Action Constraint", "Map an action to the transform axes of a bone");
@@ -1626,6 +1666,16 @@ static void rna_def_constraint_action(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ 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_enum_funcs(prop, NULL, "rna_ActionConstraint_mix_mode_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Mix Mode",
+ "Specify how existing transformations and the action channels are combined");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
prop = RNA_def_property(srna, "transform_channel", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, transform_channel_items);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index d7deccef355..b295a169c83 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -51,29 +51,25 @@ static const EnumPropertyItem beztriple_handle_type_items[] = {
#endif
const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = {
- {HD_FREE,
- "FREE",
- ICON_HANDLETYPE_FREE_VEC,
- "Free",
- "Completely independent manually set handle"},
+ {HD_FREE, "FREE", ICON_HANDLE_FREE, "Free", "Completely independent manually set handle"},
{HD_ALIGN,
"ALIGNED",
- ICON_HANDLETYPE_ALIGNED_VEC,
+ ICON_HANDLE_ALIGNED,
"Aligned",
"Manually set handle with rotation locked together with its pair"},
{HD_VECT,
"VECTOR",
- ICON_HANDLETYPE_VECTOR_VEC,
+ ICON_HANDLE_VECTOR,
"Vector",
"Automatic handles that create straight lines"},
{HD_AUTO,
"AUTO",
- ICON_HANDLETYPE_AUTO_VEC,
+ ICON_HANDLE_AUTO,
"Automatic",
"Automatic handles that create smooth curves"},
{HD_AUTO_ANIM,
"AUTO_CLAMPED",
- ICON_HANDLETYPE_AUTO_CLAMP_VEC,
+ ICON_HANDLE_AUTOCLAMPED,
"Auto Clamped",
"Automatic handles that create smooth curves which only change direction at keyframes"},
{0, NULL, 0, NULL, NULL},
@@ -1033,16 +1029,9 @@ static void rna_def_path(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
}
-static void rna_def_nurbs(BlenderRNA *UNUSED(brna), StructRNA *srna)
+static void rna_def_nurbs(BlenderRNA *UNUSED(brna), StructRNA *UNUSED(srna))
{
- PropertyRNA *prop;
-
- /* flags */
- prop = RNA_def_property(srna, "use_uv_as_generated", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_UV_ORCO);
- RNA_def_property_ui_text(
- prop, "Use UV for Mapping", "Uses the UV values as Generated textured coordinates");
- RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+ /* Nothing. */
}
static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
@@ -1757,12 +1746,6 @@ static void rna_def_curve(BlenderRNA *brna)
prop, "rna_Curve_texspace_size_get", "rna_Curve_texspace_size_set", NULL);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
- prop = RNA_def_property(srna, "use_uv_as_generated", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_UV_ORCO);
- RNA_def_property_ui_text(
- prop, "Use UV for mapping", "Uses the UV values as Generated textured coordinates");
- RNA_def_property_update(prop, 0, "rna_Curve_update_data");
-
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 55aa529a30e..73a59cbba11 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3888,6 +3888,36 @@ PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont_,
return prop;
}
+PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont_,
+ const char *identifier,
+ int len,
+ const float *default_value,
+ float hardmin,
+ float hardmax,
+ const char *ui_name,
+ const char *ui_description,
+ float softmin,
+ float softmax)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_vector(cont_,
+ identifier,
+ len,
+ default_value,
+ hardmin,
+ hardmax,
+ ui_name,
+ ui_description,
+ softmin,
+ softmax);
+ prop->subtype = PROP_TRANSLATION;
+
+ RNA_def_property_ui_range(prop, softmin, softmax, 1, RNA_TRANSLATION_PREC_DEFAULT);
+
+ return prop;
+}
+
PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 53fa863f6da..01f240e715b 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -73,7 +73,7 @@ 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 *scene, PointerRNA *ptr)
+static void rna_Fluid_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
if (settings->mmd && settings->mmd->domain) {
@@ -81,7 +81,6 @@ static void rna_Fluid_resetCache(Main *UNUSED(bmain), Scene *scene, PointerRNA *
FLUID_DOMAIN_OUTDATED_NOISE |
FLUID_DOMAIN_OUTDATED_MESH |
FLUID_DOMAIN_OUTDATED_PARTICLES);
- scene->r.cfra = settings->cache_frame_start;
}
DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
}
@@ -153,22 +152,6 @@ static bool rna_Fluid_parts_exists(PointerRNA *ptr, int ptype)
return false;
}
-static void rna_Fluid_draw_type_update(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- struct PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->owner_id;
- FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
-
- /* Wireframe mode more convenient when particles present */
- if (settings->particle_type == 0) {
- ob->dt = OB_SOLID;
- }
- else {
- ob->dt = OB_WIRE;
- }
-}
-
static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
@@ -176,26 +159,25 @@ static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *p
mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FLIP);
+ /* Only create a particle system in liquid domain mode. */
+ if (mmd->domain->type != FLUID_DOMAIN_TYPE_LIQUID) {
+ rna_Fluid_reset(bmain, scene, ptr);
+ return;
+ }
+
if (ob->type == OB_MESH && !exists) {
- rna_Fluid_parts_create(bmain,
- ptr,
- "FlipParticleSettings",
- "FLIP Particles",
- "FLIP Particle System",
- PART_FLUID_FLIP);
+ rna_Fluid_parts_create(
+ bmain, ptr, "LiquidParticleSettings", "Liquid", "Liquid Particle System", PART_FLUID_FLIP);
mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FLIP;
}
else {
rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP);
- rna_Fluid_resetCache(bmain, scene, ptr);
-
mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
}
- rna_Fluid_draw_type_update(NULL, NULL, ptr);
- rna_Fluid_reset(bmain, scene, ptr);
+ rna_Fluid_update(bmain, scene, ptr);
}
-static void rna_Fluid_spray_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_spray_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
@@ -203,25 +185,17 @@ static void rna_Fluid_spray_parts_update(Main *bmain, Scene *scene, PointerRNA *
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY);
if (ob->type == OB_MESH && !exists) {
- rna_Fluid_parts_create(bmain,
- ptr,
- "SprayParticleSettings",
- "Spray Particles",
- "Spray Particle System",
- PART_FLUID_SPRAY);
+ rna_Fluid_parts_create(
+ bmain, ptr, "SprayParticleSettings", "Spray", "Spray Particle System", PART_FLUID_SPRAY);
mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
}
else {
rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY);
- rna_Fluid_resetCache(bmain, scene, ptr);
-
mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY;
}
- rna_Fluid_draw_type_update(NULL, NULL, ptr);
- rna_Fluid_reset(bmain, scene, ptr);
}
-static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
@@ -232,22 +206,18 @@ static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *scene, PointerRNA
rna_Fluid_parts_create(bmain,
ptr,
"BubbleParticleSettings",
- "Bubble Particles",
+ "Bubbles",
"Bubble Particle System",
PART_FLUID_BUBBLE);
mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
}
else {
rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE);
- rna_Fluid_resetCache(bmain, scene, ptr);
-
mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE;
}
- rna_Fluid_draw_type_update(NULL, NULL, ptr);
- rna_Fluid_reset(bmain, scene, ptr);
}
-static void rna_Fluid_foam_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_foam_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
@@ -255,25 +225,17 @@ static void rna_Fluid_foam_parts_update(Main *bmain, Scene *scene, PointerRNA *p
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM);
if (ob->type == OB_MESH && !exists) {
- rna_Fluid_parts_create(bmain,
- ptr,
- "FoamParticleSettings",
- "Foam Particles",
- "Foam Particle System",
- PART_FLUID_FOAM);
+ rna_Fluid_parts_create(
+ bmain, ptr, "FoamParticleSettings", "Foam", "Foam Particle System", PART_FLUID_FOAM);
mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
}
else {
rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM);
- rna_Fluid_resetCache(bmain, scene, ptr);
-
mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM;
}
- rna_Fluid_draw_type_update(NULL, NULL, ptr);
- rna_Fluid_reset(bmain, scene, ptr);
}
-static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
@@ -284,19 +246,15 @@ static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *scene, PointerRNA
rna_Fluid_parts_create(bmain,
ptr,
"TracerParticleSettings",
- "Tracer Particles",
+ "Tracers",
"Tracer Particle System",
PART_FLUID_TRACER);
mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_TRACER;
}
else {
rna_Fluid_parts_delete(ptr, PART_FLUID_TRACER);
- rna_Fluid_resetCache(bmain, scene, ptr);
-
mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER;
}
- rna_Fluid_draw_type_update(NULL, NULL, ptr);
- rna_Fluid_reset(bmain, scene, ptr);
}
static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -306,102 +264,131 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR
mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_OFF) {
- rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE);
+
+ bool exists_spray = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY);
+ bool exists_foam = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM);
+ bool exists_bubble = rna_Fluid_parts_exists(ptr, PART_FLUID_BUBBLE);
- // re-add each particle type if enabled
- if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) {
+ /* Re-add each particle type if enabled and no particle system exists for them anymore. */
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && !exists_spray) {
rna_Fluid_spray_parts_update(bmain, scene, ptr);
}
- if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) {
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && !exists_foam) {
rna_Fluid_foam_parts_update(bmain, scene, ptr);
}
- if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) {
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && !exists_bubble) {
rna_Fluid_bubble_parts_update(bmain, scene, ptr);
}
}
else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM) {
- if (ob->type == OB_MESH &&
- !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM))) {
- rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM));
- }
- rna_Fluid_parts_create(bmain,
- ptr,
- "SprayFoamParticleSettings",
- "Spray + Foam Particles",
- "Spray + Foam Particle System",
- (PART_FLUID_SPRAY | PART_FLUID_FOAM));
-
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
-
- // re-add bubbles if enabled
- if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) {
- rna_Fluid_bubble_parts_update(bmain, scene, ptr);
+ if (ob->type == OB_MESH && !rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAYFOAM)) {
+
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayFoamParticleSettings",
+ "Spray + Foam",
+ "Spray + Foam Particle System",
+ PART_FLUID_SPRAYFOAM);
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE);
+
+ /* Re-add spray if enabled and no particle system exists for it anymore. */
+ bool exists_bubble = rna_Fluid_parts_exists(ptr, PART_FLUID_BUBBLE);
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && !exists_bubble) {
+ rna_Fluid_bubble_parts_update(bmain, scene, ptr);
+ }
}
}
else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE) {
- if (ob->type == OB_MESH &&
- !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_BUBBLE))) {
- rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_BUBBLE));
- }
- rna_Fluid_parts_create(bmain,
- ptr,
- "SprayBubbleParticleSettings",
- "Spray + Bubble Particles",
- "Spray + Bubble Particle System",
- (PART_FLUID_SPRAY | PART_FLUID_BUBBLE));
-
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
-
- // re-add foam if enabled
- if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) {
- rna_Fluid_foam_parts_update(bmain, scene, ptr);
+ if (ob->type == OB_MESH && !rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAYBUBBLE)) {
+
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayBubbleParticleSettings",
+ "Spray + Bubbles",
+ "Spray + Bubble Particle System",
+ PART_FLUID_SPRAYBUBBLE);
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE);
+
+ /* Re-add foam if enabled and no particle system exists for it anymore. */
+ bool exists_foam = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM);
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && !exists_foam) {
+ rna_Fluid_foam_parts_update(bmain, scene, ptr);
+ }
}
}
else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE) {
- if (ob->type == OB_MESH &&
- !rna_Fluid_parts_exists(ptr, (PART_FLUID_FOAM | PART_FLUID_BUBBLE))) {
- rna_Fluid_parts_delete(ptr, (PART_FLUID_FOAM | PART_FLUID_BUBBLE));
- }
- rna_Fluid_parts_create(bmain,
- ptr,
- "FoamBubbleParticleSettings",
- "Foam + Bubble Particles",
- "Foam + Bubble Particle System",
- (PART_FLUID_FOAM | PART_FLUID_BUBBLE));
-
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
-
- // re-add spray if enabled
- if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) {
- rna_Fluid_spray_parts_update(bmain, scene, ptr);
+ if (ob->type == OB_MESH && !rna_Fluid_parts_exists(ptr, PART_FLUID_FOAMBUBBLE)) {
+
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "FoamBubbleParticleSettings",
+ "Foam + Bubble Particles",
+ "Foam + Bubble Particle System",
+ PART_FLUID_FOAMBUBBLE);
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAMBUBBLE);
+
+ /* Re-add foam if enabled and no particle system exists for it anymore. */
+ bool exists_spray = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY);
+ if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && !exists_spray) {
+ rna_Fluid_spray_parts_update(bmain, scene, ptr);
+ }
}
}
else if (mmd->domain->sndparticle_combined_export ==
SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE) {
- if (ob->type == OB_MESH &&
- !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE))) {
- rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE));
+ if (ob->type == OB_MESH && !rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAYFOAMBUBBLE)) {
+
+ rna_Fluid_parts_create(bmain,
+ ptr,
+ "SprayFoamBubbleParticleSettings",
+ "Spray + Foam + Bubbles",
+ "Spray + Foam + Bubble Particle System",
+ PART_FLUID_SPRAYFOAMBUBBLE);
+
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
+ mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
+
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYBUBBLE);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FOAMBUBBLE);
}
- rna_Fluid_parts_create(bmain,
- ptr,
- "SprayFoamBubbleParticleSettings",
- "Spray + Foam + Bubble Particles",
- "Spray + Foam + Bubble Particle System",
- (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE));
-
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY;
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM;
- mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE;
}
else {
// sanity check, should not occur
printf("ERROR: Unexpected combined export setting encountered!");
}
- rna_Fluid_resetCache(bmain, scene, ptr);
- rna_Fluid_draw_type_update(NULL, NULL, ptr);
}
static void rna_Fluid_cachetype_mesh_set(struct PointerRNA *ptr, int value)
@@ -992,13 +979,18 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"REPLAY",
0,
"Replay",
- "Use the timeline to bake the scene. Pausing and resuming possible."},
+ "Use the timeline to bake the scene. Pausing and resuming possible"},
{FLUID_DOMAIN_CACHE_MODULAR,
"MODULAR",
0,
"Modular",
- "Bake every stage of the simulation on its own. Can pause and resume bake jobs."},
- {FLUID_DOMAIN_CACHE_FINAL, "FINAL", 0, "Final", "Bake the entire simulation at once."},
+ "Bake every stage of the simulation separately. Pausing and resuming possible"},
+ {FLUID_DOMAIN_CACHE_FINAL,
+ "FINAL",
+ 0,
+ "Final",
+ "Bake the entire simulation at once. Only generates the most essential cache files. "
+ "Pausing and resuming not possible"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem smoke_data_depth_items[] = {
@@ -1028,7 +1020,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
0,
"Domain",
"Use a fluid domain for guiding (domain needs to be baked already so that velocities can "
- "be extracted but can be of any type)"},
+ "be extracted). Guiding domain can be of any type (i.e. gas or liquid)"},
{FLUID_DOMAIN_GUIDE_SRC_EFFECTOR,
"EFFECTOR",
0,
@@ -1284,7 +1276,11 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "maxres");
RNA_def_property_range(prop, 6, 10000);
RNA_def_property_ui_range(prop, 24, 10000, 2, -1);
- RNA_def_property_ui_text(prop, "Max Res", "Resolution used for the fluid domain");
+ RNA_def_property_ui_text(
+ prop,
+ "Maximum Resolution",
+ "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");
@@ -1330,7 +1326,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, domain_types);
RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_domaintype_set", NULL);
RNA_def_property_ui_text(prop, "Domain Type", "Change domain 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_flip_parts_update");
/* smoke domain options */
@@ -1340,8 +1336,8 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
RNA_def_property_ui_text(
prop,
- "Density",
- "How much density affects smoke motion (higher value results in faster rising smoke)");
+ "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");
prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
@@ -1350,21 +1346,24 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5);
RNA_def_property_ui_text(
prop,
- "Heat",
- "How much heat affects smoke motion (higher value results in faster rising smoke)");
+ "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");
prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "diss_speed");
RNA_def_property_range(prop, 1.0, 10000.0);
RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1);
- RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed");
+ RNA_def_property_ui_text(
+ prop,
+ "Dissolve Speed",
+ "Determine how quickly the smoke dissolves (higher value makes smoke disappear faster)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
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/rotation in fluid");
+ 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");
prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE);
@@ -1374,12 +1373,15 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
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", "Enable smoke to disappear over time");
+ 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");
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);
- RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x ");
+ RNA_def_property_ui_text(
+ 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");
/* flame options */
@@ -1388,7 +1390,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.01, 4.0);
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 (use larger values for smaller flame)");
+ 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");
prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
@@ -1406,13 +1408,19 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.5, 5.0);
RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5);
- RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames");
+ RNA_def_property_ui_text(
+ 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");
prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 1.0, 10.0);
RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5);
- RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames");
+ RNA_def_property_ui_text(
+ 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");
prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -1447,8 +1455,8 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 1, 10, 1, -1);
RNA_def_property_ui_text(prop,
"Noise Scale",
- "Scale underlying noise grids by this factor. Noise grids have size "
- "factor times base resolution");
+ "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");
@@ -1456,7 +1464,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "noise_type");
RNA_def_property_enum_items(prop, prop_noise_type_items);
RNA_def_property_ui_text(
- prop, "Noise Method", "Noise method which is used for creating the high resolution");
+ 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");
@@ -1514,10 +1522,10 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "particle_radius", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop,
- "Radius",
- "Particle radius factor. Use this parameter when the simulation appears to leak volume");
+ RNA_def_property_ui_text(prop,
+ "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");
prop = RNA_def_property(srna, "particle_band_width", PROP_FLOAT, PROP_NONE);
@@ -1530,9 +1538,9 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
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);
- RNA_def_property_ui_text(prop, "FLIP", "Create FLIP particle system");
+ RNA_def_property_ui_text(prop, "FLIP", "Create liquid particle system");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Fluid_flip_parts_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_flip_parts_update");
prop = RNA_def_property(srna, "use_fractions", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_FRACTIONS);
@@ -1620,8 +1628,9 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 1, 10, 1, -1);
RNA_def_property_ui_text(prop,
"Mesh scale",
- "Scale underlying mesh grids by this factor. Mesh grids have size "
- "factor times base resolution");
+ "The mesh simulation is scaled up by this factor (compared to the base "
+ "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");
@@ -1647,19 +1656,19 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_SPEED_VECTORS);
- RNA_def_property_ui_text(
- prop,
- "Speed Vectors",
- "Generate speed vectors (will be loaded automatically during render for motion blur)");
+ RNA_def_property_ui_text(prop,
+ "Speed Vectors",
+ "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");
prop = RNA_def_property(srna, "mesh_particle_radius", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop,
- "Radius",
- "Particle radius factor (higher value results in larger (meshed) particles)");
+ RNA_def_property_ui_text(prop,
+ "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");
/* secondary particles options */
@@ -1668,36 +1677,36 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
RNA_def_property_ui_text(prop,
- "tauMin_wc",
+ "Minimum Wave Crest Potential",
"Lower clamping threshold for marking fluid cells as wave crests "
- "(lower values result in more marked cells)");
+ "(lower value results in more marked cells)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_tau_max_wc", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
RNA_def_property_ui_text(prop,
- "tauMax_wc",
+ "Maximum Wave Crest Potential",
"Upper clamping threshold for marking fluid cells as wave crests "
- "(higher values result in less marked cells)");
+ "(higher value results in less marked cells)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_tau_min_ta", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 3);
RNA_def_property_ui_text(prop,
- "tauMin_ta",
+ "Minimum Trapped Air Potential",
"Lower clamping threshold for marking fluid cells where air is trapped "
- "(lower values result in more marked cells)");
+ "(lower value results in more marked cells)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_tau_max_ta", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3);
RNA_def_property_ui_text(prop,
- "tauMax_ta",
+ "Maximum Trapped Air Potential",
"Upper clamping threshold for marking fluid cells where air is trapped "
- "(higher values result in less marked cells)");
+ "(highe value results in less marked cells)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_tau_min_k", PROP_FLOAT, PROP_NONE);
@@ -1717,7 +1726,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"tauMax_k",
"Upper clamping threshold that indicates the fluid speed where cells no longer emit more "
- "particles (higher values result in generally less particles)");
+ "particles (higher value results in generally less particles)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_k_wc", PROP_INT, PROP_NONE);
@@ -1740,8 +1749,8 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2);
RNA_def_property_ui_text(prop,
- "Buoyancy",
- "Amount of buoyancy force that rises bubbles (high values result in "
+ "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");
@@ -1749,21 +1758,21 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 100.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2);
RNA_def_property_ui_text(prop,
- "Drag",
+ "Bubble Drag",
"Amount of drag force that moves bubbles along with the fluid (high "
- "values result in bubble movement mainly along with the fluid)");
+ "value results in bubble movement mainly along with the fluid)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_l_min", PROP_FLOAT, PROP_NONE);
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, "Lifetime(min)", "Lowest possible particle lifetime");
+ RNA_def_property_ui_text(prop, "Minimum Lifetime", "Lowest possible particle lifetime");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_l_max", PROP_FLOAT, PROP_NONE);
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, "Lifetime(max)", "Highest possible particle lifetime");
+ RNA_def_property_ui_text(prop, "Maximum Lifetime", "Highest possible particle lifetime");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "sndparticle_boundary", PROP_ENUM, PROP_NONE);
@@ -1807,9 +1816,9 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_range(prop, 1, 10, 1, -1);
RNA_def_property_ui_text(prop,
- "Mesh scale",
- "Scale underlying particle grids by this factor. Particle grids have "
- "size factor times base resolution");
+ "Particle scale",
+ "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");
@@ -1817,25 +1826,25 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_SPRAY);
RNA_def_property_ui_text(prop, "Spray", "Create spray particle system");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Fluid_spray_parts_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_spray_parts_update");
prop = RNA_def_property(srna, "use_bubble_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_BUBBLE);
RNA_def_property_ui_text(prop, "Bubble", "Create bubble particle system");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Fluid_bubble_parts_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_bubble_parts_update");
prop = RNA_def_property(srna, "use_foam_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FOAM);
RNA_def_property_ui_text(prop, "Foam", "Create foam particle system");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Fluid_foam_parts_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_foam_parts_update");
prop = RNA_def_property(srna, "use_tracer_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_TRACER);
RNA_def_property_ui_text(prop, "Tracer", "Create tracer particle system");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, 0, "rna_Fluid_tracer_parts_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_tracer_parts_update");
/* fluid guiding options */
@@ -1857,7 +1866,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Weight",
- "Guiding velocity factor (higher value results in bigger guiding velocities)");
+ "Guiding velocity factor (higher value results in greater guiding velocities)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
prop = RNA_def_property(srna, "guide_source", PROP_ENUM, PROP_NONE);
@@ -2033,7 +2042,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
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 larger timesteps)");
+ prop, "CFL", "Maximal velocity per cell (higher value results in greater timesteps)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE);
@@ -2362,18 +2371,28 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5);
- RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume");
+ RNA_def_property_ui_text(prop,
+ "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");
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", "Maximum distance from mesh surface to emit fluid");
+ RNA_def_property_ui_text(prop,
+ "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");
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);
- RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh");
+ RNA_def_property_ui_text(
+ prop,
+ "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");
prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index d07bf542954..9f5f1635536 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -385,8 +385,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
+ GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index c4ec0a84a2c..7b5612ef8e7 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -216,14 +216,13 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
-static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int tile_number)
+static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
{
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.framenr = frame;
- iuser.tile = tile_number;
- GPUTexture *tex = GPU_texture_from_blender(image, &iuser, GL_TEXTURE_2D);
+ GPUTexture *tex = GPU_texture_from_blender(image, &iuser, NULL, GL_TEXTURE_2D);
if (tex == NULL) {
BKE_reportf(reports, RPT_ERROR, "Failed to load image texture '%s'", image->id.name + 2);
@@ -233,15 +232,14 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int t
return GL_NO_ERROR;
}
-static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int tile_number)
+static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
{
int error = GL_NO_ERROR;
BKE_image_tag_time(image);
- ImageTile *tile = BKE_image_get_tile(image, tile_number);
- if (tile->gputexture[TEXTARGET_TEXTURE_2D] == NULL) {
- error = rna_Image_gl_load(image, reports, frame, tile_number);
+ if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL) {
+ error = rna_Image_gl_load(image, reports, frame);
}
return error;
@@ -336,7 +334,6 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
- RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "Tile", "Tile of a tiled image", 0, INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
@@ -351,7 +348,6 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
- RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "Tile", "Tile of a tiled image", 0, INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index d85c5c5f249..9df21a16e90 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -250,6 +250,9 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
case ID_AR:
type = OB_ARMATURE;
break;
+ case ID_LP:
+ type = OB_LIGHTPROBE;
+ break;
default: {
const char *idname;
if (RNA_enum_id_from_value(rna_enum_id_type_items, GS(data->name), &idname) == 0) {
@@ -665,12 +668,15 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name
return linestyle;
}
-static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name)
+static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name, int type)
{
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
LightProbe *probe = BKE_lightprobe_add(bmain, safe_name);
+
+ BKE_lightprobe_type_set(probe, type);
+
id_us_min(&probe->id);
return probe;
}
@@ -2079,6 +2085,9 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a new probe to the main database");
parm = RNA_def_string(func, "name", "Probe", 0, "", "New name for the data-block");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(
+ func, "type", rna_enum_lightprobes_type_items, 0, "Type", "The type of lightprobe to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "lightprobe", "LightProbe", "", "New light probe data-block");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 5890c3fe8a2..5e21fc883a9 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -2987,7 +2987,7 @@ static void rna_def_mesh(BlenderRNA *brna)
/* Remesh */
prop = RNA_def_property(srna, "remesh_voxel_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_size");
- RNA_def_property_range(prop, 0.00001f, FLT_MAX);
+ RNA_def_property_range(prop, 0.0001f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0001f, FLT_MAX, 0.01, 4);
RNA_def_property_ui_text(prop,
"Voxel Size",
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 589ce1414bb..8117085974c 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -3217,6 +3217,11 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
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);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_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, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_X);
RNA_def_property_ui_text(prop, "X", "");
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 97cab783aed..cf84d38a880 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -801,7 +801,8 @@ static void rna_def_nlastrip(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED);
- RNA_def_property_ui_text(prop, "Muted", "Disable NLA Strip evaluation");
+ RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1);
+ RNA_def_property_ui_text(prop, "Mute", "Disable NLA Strip evaluation");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
prop = RNA_def_property(srna, "use_reverse", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index a39ace3ff7f..1e6fe053c3b 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -25,6 +25,7 @@
#include "DNA_brush_types.h"
#include "DNA_collection_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_force_types.h"
@@ -196,6 +197,13 @@ const EnumPropertyItem rna_enum_metaelem_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_lightprobes_type_items[] = {
+ {LIGHTPROBE_TYPE_CUBE, "CUBE", ICON_LIGHTPROBE_CUBEMAP, "Cube", ""},
+ {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Planar", ""},
+ {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Grid", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
/* used for 2 enums */
#define OBTYPE_CU_CURVE \
{ \
@@ -375,36 +383,44 @@ static void rna_Object_matrix_basis_set(PointerRNA *ptr, const float values[16])
BKE_object_apply_mat4(ob, (float(*)[4])values, false, false);
}
-void rna_Object_internal_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+void rna_Object_internal_update_data_impl(PointerRNA *ptr)
{
DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ptr->owner_id);
}
-void rna_Object_internal_update_data_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+void rna_Object_internal_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ rna_Object_internal_update_data_impl(ptr);
+}
+
+void rna_Object_internal_update_data_dependency(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
DEG_relations_tag_update(bmain);
- rna_Object_internal_update_data(bmain, scene, ptr);
+ rna_Object_internal_update_data_impl(ptr);
}
-static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr)
+static void rna_Object_active_shape_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- if (CTX_data_edit_object(C) == ob) {
+ if (BKE_object_is_in_editmode(ob)) {
/* exit/enter editmode to get new shape */
switch (ob->type) {
- case OB_MESH:
+ case OB_MESH: {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ int select_mode = em->selectmode;
EDBM_mesh_load(bmain, ob);
- EDBM_mesh_make(ob, scene->toolsettings->selectmode, true);
+ EDBM_mesh_make(ob, select_mode, true);
+ em = me->edit_mesh;
- DEG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update(&me->id, 0);
- EDBM_mesh_normals_update(((Mesh *)ob->data)->edit_mesh);
- BKE_editmesh_looptri_calc(((Mesh *)ob->data)->edit_mesh);
+ EDBM_mesh_normals_update(em);
+ BKE_editmesh_looptri_calc(em);
break;
+ }
case OB_CURVE:
case OB_SURF:
ED_curve_editnurb_load(bmain, ob);
@@ -417,7 +433,7 @@ static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr)
}
}
- rna_Object_internal_update_data(bmain, scene, ptr);
+ rna_Object_internal_update_data_impl(ptr);
}
static void rna_Object_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -1514,7 +1530,7 @@ static void rna_Object_modifier_clear(Object *object, bContext *C)
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
}
-bool rna_Object_modifiers_override_apply(Main *UNUSED(bmain),
+bool rna_Object_modifiers_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
PointerRNA *UNUSED(ptr_storage),
@@ -1537,7 +1553,7 @@ bool rna_Object_modifiers_override_apply(Main *UNUSED(bmain),
/* 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' constraint in both _src *and* _dst. */
+ * So we should always find 'anchor' modifier in both _src *and* _dst. */
ModifierData *mod_anchor = NULL;
if (opop->subitem_local_name && opop->subitem_local_name[0]) {
mod_anchor = BLI_findstring(
@@ -1560,18 +1576,32 @@ bool rna_Object_modifiers_override_apply(Main *UNUSED(bmain),
BLI_assert(mod_src != NULL);
- ModifierData *mod_dst = modifier_new(mod_src->type);
+ /* While it would be nicer to use lower-level 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(
+ NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type);
+
+ /* XXX Current handling of 'copy' from particle-system modifier is *very* bad (it keeps same psys
+ * pointer as source, then calling code copies psys of object separately and do some magic
+ * remapping of pointers...), unfortunately several pieces of code in Object editing area rely on
+ * this behavior. So for now, hacking around it to get it doing what we want it to do, as getting
+ * a proper behavior would be everything but trivial, and this whole particle thingy is
+ * end-of-life. */
+ ParticleSystem *psys_dst = (mod_dst->type == eModifierType_ParticleSystem) ?
+ ((ParticleSystemModifierData *)mod_dst)->psys :
+ NULL;
modifier_copyData(mod_src, mod_dst);
+ if (mod_dst->type == eModifierType_ParticleSystem) {
+ psys_dst->flag &= ~PSYS_DELETE;
+ ((ParticleSystemModifierData *)mod_dst)->psys = psys_dst;
+ }
+ BLI_remlink(&ob_dst->modifiers, mod_dst);
/* This handles NULL anchor as expected by adding at head of list. */
BLI_insertlinkafter(&ob_dst->modifiers, mod_anchor, mod_dst);
- /* This should actually *not* be needed in typical cases.
- * However, if overridden source was edited,
- * we *may* have some new conflicting names. */
- modifier_unique_name(&ob_dst->modifiers, mod_dst);
-
- // printf("%s: We inserted a modifier...\n", __func__);
+ // printf("%s: We inserted a modifier '%s'...\n", __func__, mod_dst->name);
return true;
}
@@ -2767,14 +2797,14 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_location", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_LOCX);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Lock Location", "Lock editing of location in the interface");
+ RNA_def_property_ui_text(prop, "Lock Location", "Lock editing of location when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
prop = RNA_def_property(srna, "lock_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROTX);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation in the interface");
+ RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2786,7 +2816,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Lock Rotation (4D Angle)",
- "Lock editing of 'angle' component of four-component rotations in the interface");
+ "Lock editing of 'angle' component of four-component rotations when transforming");
/* XXX this needs a better name */
prop = RNA_def_property(srna, "lock_rotations_4d", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROT4D);
@@ -2798,7 +2828,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_SCALEX);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Lock Scale", "Lock editing of scale in the interface");
+ RNA_def_property_ui_text(prop, "Lock Scale", "Lock editing of scale when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -3187,7 +3217,6 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_shape_key_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "shapenr");
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* XXX this is really unpredictable... */
RNA_def_property_int_funcs(prop,
"rna_Object_active_shape_key_index_get",
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index f3ca10e332a..4155c453440 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -120,6 +120,29 @@ static const EnumPropertyItem part_hair_ren_as_items[] = {
};
#endif
+static const EnumPropertyItem part_type_items[] = {
+ {PART_EMITTER, "EMITTER", 0, "Emitter", ""},
+ /*{PART_REACTOR, "REACTOR", 0, "Reactor", ""}, */
+ {PART_HAIR, "HAIR", 0, "Hair", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+#ifdef RNA_RUNTIME
+static const EnumPropertyItem part_fluid_type_items[] = {
+ {PART_FLUID, "FLUID", 0, "Fluid", ""},
+ {PART_FLUID_FLIP, "FLIP", 0, "Liquid", ""},
+ {PART_FLUID_SPRAY, "SPRAY", 0, "Spray", ""},
+ {PART_FLUID_BUBBLE, "BUBBLE", 0, "Bubble", ""},
+ {PART_FLUID_FOAM, "FOAM", 0, "Foam", ""},
+ {PART_FLUID_TRACER, "TRACER", 0, "Tracer", ""},
+ {PART_FLUID_SPRAYFOAM, "SPRAYFOAM", 0, "Spray-Foam", ""},
+ {PART_FLUID_SPRAYBUBBLE, "SPRAYBUBBLE", 0, "Spray-Bubble", ""},
+ {PART_FLUID_FOAMBUBBLE, "FOAMBUBBLE", 0, "Foam-Bubble", ""},
+ {PART_FLUID_SPRAYFOAMBUBBLE, "SPRAYFOAMBUBBLE", 0, "Spray-Foam-Bubble", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+#endif
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
@@ -286,6 +309,11 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle,
psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, nor, 0, 0, sd.orco, 0);
# endif
+ if (modifier->mesh_final == NULL) {
+ BKE_report(reports, RPT_ERROR, "uv_on_emitter() requires a modifier from an evaluated object");
+ return;
+ }
+
/* get uvco & mcol */
int num = particle->num_dmcache;
int from = modifier->psys->part->from;
@@ -862,7 +890,7 @@ static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value)
/* check for clipping */
if (value > settings->end) {
- value = settings->end;
+ settings->end = value;
}
/*if (settings->type==PART_REACTOR && value < 1.0) */
@@ -881,7 +909,7 @@ static void rna_PartSettings_end_set(struct PointerRNA *ptr, float value)
/* check for clipping */
if (value < settings->sta) {
- value = settings->sta;
+ settings->sta = value;
}
settings->end = value;
@@ -959,7 +987,11 @@ static int rna_PartSettings_is_fluid_get(PointerRNA *ptr)
PART_FLUID_FOAM,
PART_FLUID_SPRAY,
PART_FLUID_BUBBLE,
- PART_FLUID_TRACER));
+ PART_FLUID_TRACER,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE));
}
static void rna_ParticleSettings_use_clump_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -1230,6 +1262,21 @@ static int rna_ParticleDupliWeight_name_length(PointerRNA *ptr)
return strlen(tstr);
}
+static const EnumPropertyItem *rna_Particle_type_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
+
+ if (part->type == PART_HAIR || part->type == PART_EMITTER) {
+ return part_type_items;
+ }
+ else {
+ return part_fluid_type_items;
+ }
+}
+
static const EnumPropertyItem *rna_Particle_from_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -1763,9 +1810,14 @@ static void rna_def_particle(BlenderRNA *brna)
/* UVs */
func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter");
- RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh");
+ RNA_def_function_ui_description(func,
+ "Obtain UV coordinates for a particle on an evaluated mesh.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ parm = RNA_def_pointer(func,
+ "modifier",
+ "ParticleSystemModifier",
+ "",
+ "Particle modifier from an evaluated object");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
RNA_def_property_array(parm, 2);
@@ -2246,13 +2298,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem type_items[] = {
- {PART_EMITTER, "EMITTER", 0, "Emitter", ""},
- /*{PART_REACTOR, "REACTOR", 0, "Reactor", ""}, */
- {PART_HAIR, "HAIR", 0, "Hair", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem phys_type_items[] = {
{PART_PHYS_NO, "NO", 0, "None", ""},
{PART_PHYS_NEWTON, "NEWTON", 0, "Newtonian", ""},
@@ -2479,8 +2524,9 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_enum_items(prop, part_type_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Particle_type_itemf");
RNA_def_property_ui_text(prop, "Type", "Particle Type");
RNA_def_property_update(prop, 0, "rna_Particle_change_type");
@@ -3419,7 +3465,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "rad_root");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 2);
- RNA_def_property_ui_text(prop, "Root", "Strand width at the root");
+ RNA_def_property_ui_text(prop, "Root Diameter", "Strand diameter width at the root");
RNA_def_property_update(
prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
@@ -3427,7 +3473,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "rad_tip");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 2);
- RNA_def_property_ui_text(prop, "Tip", "Strand width at the tip");
+ RNA_def_property_ui_text(prop, "Tip Diameter", "Strand diameter width at the tip");
RNA_def_property_update(
prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 8c4b7dd52d9..85c4352d277 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -1356,7 +1356,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_location", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_LOCX);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Lock Location", "Lock editing of location in the interface");
+ RNA_def_property_ui_text(prop, "Lock Location", "Lock editing of location when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -1364,7 +1364,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_ROTX);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation in the interface");
+ RNA_def_property_ui_text(prop, "Lock Rotation", "Lock editing of rotation when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -1376,7 +1376,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Lock Rotation (4D Angle)",
- "Lock editing of 'angle' component of four-component rotations in the interface");
+ "Lock editing of 'angle' component of four-component rotations when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -1394,7 +1394,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "lock_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", OB_LOCK_SCALEX);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Lock Scale", "Lock editing of scale in the interface");
+ RNA_def_property_ui_text(prop, "Lock Scale", "Lock editing of scale when transforming");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -1663,7 +1663,9 @@ static void rna_def_pose(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mirror_relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", POSE_MIRROR_RELATIVE);
RNA_def_property_ui_text(
- prop, "Relative Mirror", "Apply relative transformations in X-mirror mode");
+ prop,
+ "Relative Mirror",
+ "Apply relative transformations in X-mirror mode (not supported with Auto IK)");
RNA_def_struct_path_func(srna, "rna_Pose_path");
RNA_def_property_update(prop, 0, "rna_Pose_update");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 4f969ad2bf8..52be8f3ccc7 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -943,8 +943,8 @@ static void rna_Scene_start_frame_set(PointerRNA *ptr, int value)
CLAMP(value, MINFRAME, MAXFRAME);
data->r.sfra = value;
- if (data->r.sfra >= data->r.efra) {
- data->r.efra = MIN2(data->r.sfra, MAXFRAME);
+ if (value > data->r.efra) {
+ data->r.efra = MIN2(value, MAXFRAME);
}
}
@@ -954,8 +954,8 @@ static void rna_Scene_end_frame_set(PointerRNA *ptr, int value)
CLAMP(value, MINFRAME, MAXFRAME);
data->r.efra = value;
- if (data->r.sfra >= data->r.efra) {
- data->r.sfra = MAX2(data->r.efra, MINFRAME);
+ if (data->r.sfra > value) {
+ data->r.sfra = MAX2(value, MINFRAME);
}
}
@@ -987,10 +987,12 @@ static void rna_Scene_preview_range_start_frame_set(PointerRNA *ptr, int value)
/* TODO: or just refuse to set instead? */
data->r.pefra = data->r.efra;
}
-
- /* now set normally */
- CLAMP(value, MINAFRAME, data->r.pefra);
+ CLAMP(value, MINAFRAME, MAXFRAME);
data->r.psfra = value;
+
+ if (value > data->r.pefra) {
+ data->r.pefra = MIN2(value, MAXFRAME);
+ }
}
static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
@@ -1003,10 +1005,12 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
/* TODO: or just refuse to set instead? */
data->r.psfra = data->r.sfra;
}
-
- /* now set normally */
- CLAMP(value, data->r.psfra, MAXFRAME);
+ CLAMP(value, MINAFRAME, MAXFRAME);
data->r.pefra = value;
+
+ if (data->r.psfra > value) {
+ data->r.psfra = MAX2(value, MINAFRAME);
+ }
}
static void rna_Scene_show_subframe_update(Main *UNUSED(bmain),
@@ -3021,17 +3025,21 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_transform_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_AXIS_ALIGN);
RNA_def_property_ui_text(
- prop, "Only Locations", "Manipulate origins (object, pose and weight paint mode only)");
+ prop,
+ "Only Locations",
+ "Only transform object locations, without affecting rotation or scaling");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_transform_data_origin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_DATA_ORIGIN);
- RNA_def_property_ui_text(prop, "Transform Origins", "Manipulate object data");
+ RNA_def_property_ui_text(
+ prop, "Transform Origins", "Transform object origins, while leaving the shape in place");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_transform_skip_children", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_SKIP_CHILDREN);
- RNA_def_property_ui_text(prop, "Transform Parents", "Don't transform children");
+ RNA_def_property_ui_text(
+ prop, "Transform Parents", "Transform the parents, leaving the children in place");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 2c5f93e28ed..16dbe38f866 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2701,15 +2701,15 @@ static void rna_def_text(StructRNA *srna)
{
/* Avoid text icons because they imply this aligns within a frame, see: T71082 */
static const EnumPropertyItem text_align_x_items[] = {
- {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", 0, "Left", ""},
- {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", 0, "Center", ""},
- {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", 0, "Right", ""},
+ {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", ICON_ANCHOR_LEFT, "Left", ""},
+ {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", ICON_ANCHOR_CENTER, "Center", ""},
+ {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", ICON_ANCHOR_RIGHT, "Right", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem text_align_y_items[] = {
- {SEQ_TEXT_ALIGN_Y_TOP, "TOP", 0, "Top", ""},
- {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", 0, "Center", ""},
- {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", ""},
+ {SEQ_TEXT_ALIGN_Y_TOP, "TOP", ICON_ANCHOR_TOP, "Top", ""},
+ {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", ICON_ANCHOR_CENTER, "Center", ""},
+ {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ANCHOR_BOTTOM, "Bottom", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index b7da8d616d3..d14742077ff 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -161,6 +161,13 @@ const EnumPropertyItem rna_enum_space_graph_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_space_sequencer_view_type_items[] = {
+ {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
+ {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""},
+ {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SPLITVIEW, "Sequencer/Preview", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#define SACT_ITEM_DOPESHEET \
{ \
SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene" \
@@ -2654,7 +2661,9 @@ static void rna_def_space(BlenderRNA *brna)
/* access to V2D_VIEWSYNC_SCREEN_TIME */
prop = RNA_def_property(srna, "show_locked_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Space_view2d_sync_get", "rna_Space_view2d_sync_set");
- RNA_def_property_ui_text(prop, "Lock Time to Other Windows", "");
+ RNA_def_property_ui_text(prop,
+ "Sync Visible Range",
+ "Syncronize the visible timeline range with other time-based editors");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Space_view2d_sync_update");
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_HEADER));
@@ -3489,7 +3498,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres");
+ RNA_def_property_ui_text(prop, "HDRI Preview", "Show HDRI preview spheres");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE);
@@ -3500,8 +3509,10 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
- RNA_def_property_ui_text(
- prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
+ RNA_def_property_ui_text(prop,
+ "Wireframe Threshold",
+ "Adjust the angle threshold for displaying edges "
+ "(1.0 for all)");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -4470,17 +4481,6 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem view_type_items[] = {
- {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
- {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""},
- {SEQ_VIEW_SEQUENCE_PREVIEW,
- "SEQUENCER_PREVIEW",
- ICON_SEQ_SPLITVIEW,
- "Sequencer/Preview",
- ""},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem display_mode_items[] = {
{SEQ_DRAW_IMG_IMBUF, "IMAGE", ICON_SEQ_PREVIEW, "Image Preview", ""},
{SEQ_DRAW_IMG_WAVEFORM, "WAVEFORM", ICON_SEQ_LUMA_WAVEFORM, "Luma Waveform", ""},
@@ -4540,12 +4540,14 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SpaceSeq");
RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data");
- rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI));
+ rna_def_space_generic_show_region_toggles(srna,
+ (1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_UI) |
+ (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_HUD));
/* view type, fairly important */
prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "view");
- RNA_def_property_enum_items(prop, view_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_sequencer_view_type_items);
RNA_def_property_ui_text(
prop, "View Type", "Type of the Sequencer view (sequencer, preview or both)");
RNA_def_property_update(prop, 0, "rna_Sequencer_view_type_update");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 1f15288d2d6..b9fb8638c49 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -580,9 +580,6 @@ static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *p
return USER_EXPERIMENTAL_TEST(userdef, member); \
}
-RNA_USERDEF_EXPERIMENTAL_BOOLEAN_GET(use_tool_fallback)
-RNA_USERDEF_EXPERIMENTAL_BOOLEAN_GET(use_usd_exporter)
-
static bAddon *rna_userdef_addon_new(void)
{
ListBase *addons_list = &U.addons;
@@ -2234,6 +2231,14 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bone Solid", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+ prop = RNA_def_property(srna, "bone_locked_weight", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(
+ prop,
+ "Bone Locked Weight",
+ "Shade for bones corresponding to a locked weight group during painting");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
/* misc */
prop = RNA_def_property(srna, "bundle_solid", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -2511,63 +2516,73 @@ static void rna_def_userdef_theme_space_info(BlenderRNA *brna)
rna_def_userdef_theme_spaces_main(srna);
prop = RNA_def_property(srna, "info_selected", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_selected");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Selected Line Background", "");
+ RNA_def_property_ui_text(prop, "Selected Line Background", "Background color of selected line");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_selected_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_selected_text");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Selected Line Text", "");
+ RNA_def_property_ui_text(prop, "Selected Line Text Color", "Text color of selected line");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_error", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_error");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Error Background", "");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Error Icon Background", "Background color of Error icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_error_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_error_text");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Error Text", "");
+ RNA_def_property_ui_text(prop, "Error Icon Foreground", "Foreground color of Error icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_warning", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_warning");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Warning Background", "");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Warning Icon Background", "Background color of Warning icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_warning_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_warning_text");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Warning Text", "");
+ RNA_def_property_ui_text(prop, "Warning Icon Foreground", "Foreground color of Warning icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_info", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_info");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Info Background", "");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Info Icon Background", "Background color of Info icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_info_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_info_text");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Info Text", "");
+ RNA_def_property_ui_text(prop, "Info Icon Foreground", "Foreground color of Info icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_debug", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_debug");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Debug Background", "");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Debug Icon Background", "Background color of Debug icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "info_debug_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "info_debug_text");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Debug Text", "");
+ RNA_def_property_ui_text(prop, "Debug Icon Foreground", "Foreground color of Debug icon");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "info_property", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Property Icon Background", "Backgrond color of Property icon");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "info_property_text", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Property Icon Foreground", "Foreground color of Property icon");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "info_operator", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Operator Icon Background", "Background color of Operator icon");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "info_operator_text", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Operator Icon Foreground", "Foreground color of Operator icon");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
@@ -4511,8 +4526,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "lookdev_sphere_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "lookdev_sphere_size");
RNA_def_property_range(prop, 50, 400);
- RNA_def_property_ui_text(
- prop, "Look Dev Spheres Size", "Maximum diameter of the look development sphere size");
+ RNA_def_property_ui_text(prop, "HDRI Preview Size", "Diameter of the HDRI preview spheres");
RNA_def_property_update(prop, 0, "rna_userdef_update");
/* View2D Grid Displays */
@@ -5851,25 +5865,12 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
static void rna_def_userdef_experimental(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
srna = RNA_def_struct(brna, "PreferencesExperimental", NULL);
RNA_def_struct_sdna(srna, "UserDef_Experimental");
RNA_def_struct_nested(brna, srna, "Preferences");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "Experimental", "Experimental features");
-
- prop = RNA_def_property(srna, "use_tool_fallback", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_tool_fallback", 1);
- RNA_def_property_boolean_funcs(prop, "rna_userdef_experimental_use_tool_fallback_get", NULL);
- RNA_def_property_ui_text(prop, "Fallback Tool Support", "Allow selection with an active tool");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "use_usd_exporter", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_usd_exporter", 1);
- RNA_def_property_boolean_funcs(prop, "rna_userdef_experimental_use_usd_exporter_get", NULL);
- RNA_def_property_ui_text(prop, "USD Exporter", "Enable exporting to the USD format");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index a57be90b08c..bf3c562f95f 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -90,6 +90,7 @@ static const EnumPropertyItem event_mouse_type_items[] = {
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""},
{MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""},
+ {MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", ""},
{0, "", 0, NULL, NULL},
{WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""},
{WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""},
@@ -186,6 +187,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", "MsPan"},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", "MsZoom"},
{MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", "MsRot"},
+ {MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", "MsSmartZoom"},
{0, "", 0, NULL, NULL},
{WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", "WhUp"},
{WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", "WhDown"},
@@ -302,6 +304,11 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{F17KEY, "F17", 0, "F17", ""},
{F18KEY, "F18", 0, "F18", ""},
{F19KEY, "F19", 0, "F19", ""},
+ {F20KEY, "F20", 0, "F20", ""},
+ {F21KEY, "F21", 0, "F21", ""},
+ {F22KEY, "F22", 0, "F22", ""},
+ {F23KEY, "F23", 0, "F23", ""},
+ {F24KEY, "F24", 0, "F24", ""},
{PAUSEKEY, "PAUSE", 0, "Pause", ""},
{INSERTKEY, "INSERT", 0, "Insert", "Ins"},
{HOMEKEY, "HOME", 0, "Home", ""},
@@ -2180,7 +2187,7 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Is Tablet", "The event has tablet data");
prop = RNA_def_property(srna, "is_mouse_absolute", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "is_motion_absolute", 1);
+ RNA_def_property_boolean_sdna(prop, NULL, "tablet.is_motion_absolute", 1);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input");
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 7c6e3c2730b..32e348ea72f 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -152,7 +152,17 @@ static bToolRef *rna_WorkSpace_tools_from_space_node(WorkSpace *workspace, bool
},
create);
}
-
+static bToolRef *rna_WorkSpace_tools_from_space_sequencer(WorkSpace *workspace,
+ int mode,
+ bool create)
+{
+ return rna_WorkSpace_tools_from_tkey(workspace,
+ &(bToolKey){
+ .space_type = SPACE_SEQ,
+ .mode = mode,
+ },
+ create);
+}
const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
@@ -164,6 +174,8 @@ const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C),
return rna_enum_context_mode_items;
case SPACE_IMAGE:
return rna_enum_space_image_mode_all_items;
+ case SPACE_SEQ:
+ return rna_enum_space_sequencer_view_type_items;
}
return DummyRNA_DEFAULT_items;
}
@@ -192,18 +204,6 @@ static int rna_WorkSpaceTool_widget_length(PointerRNA *ptr)
return tref->runtime ? strlen(tref->runtime->gizmo_group) : 0;
}
-static void rna_WorkSpaceTool_tool_fallback_get(PointerRNA *ptr, char *value)
-{
- bToolRef *tref = ptr->data;
- strcpy(value, tref->runtime ? tref->runtime->idname_fallback : "");
-}
-
-static int rna_WorkSpaceTool_tool_fallback_length(PointerRNA *ptr)
-{
- bToolRef *tref = ptr->data;
- return tref->runtime ? strlen(tref->runtime->idname_fallback) : 0;
-}
-
#else /* RNA_RUNTIME */
static void rna_def_workspace_owner(BlenderRNA *brna)
@@ -270,6 +270,10 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Identifier", "");
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "idname_fallback", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Identifier Fallback", "");
+ RNA_def_struct_name_property(srna, prop);
+
prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Index", "");
@@ -300,14 +304,6 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Widget", "");
RNA_def_property_string_funcs(
prop, "rna_WorkSpaceTool_widget_get", "rna_WorkSpaceTool_widget_length", NULL);
- RNA_define_verify_sdna(1);
-
- prop = RNA_def_property(srna, "tool_fallback", PROP_STRING, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Fallback", "");
- RNA_def_property_string_funcs(
- prop, "rna_WorkSpaceTool_tool_fallback_get", "rna_WorkSpaceTool_tool_fallback_length", NULL);
- RNA_define_verify_sdna(1);
RNA_api_workspace_tool(srna);
}
@@ -351,6 +347,16 @@ static void rna_def_workspace_tools(BlenderRNA *brna, PropertyRNA *cprop)
/* return type */
parm = RNA_def_pointer(func, "result", "WorkSpaceTool", "", "");
RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(
+ srna, "from_space_sequencer", "rna_WorkSpace_tools_from_space_sequencer");
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_enum(func, "mode", rna_enum_space_sequencer_view_type_items, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "create", false, "Create", "");
+ /* return type */
+ parm = RNA_def_pointer(func, "result", "WorkSpaceTool", "", "");
+ RNA_def_function_return(func, parm);
}
static void rna_def_workspace(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c
index 5cc55bfad8a..4fb6677199f 100644
--- a/source/blender/makesrna/intern/rna_workspace_api.c
+++ b/source/blender/makesrna/intern/rna_workspace_api.c
@@ -63,7 +63,9 @@ static void rna_WorkSpaceTool_setup(ID *id,
STRNCPY(tref_rt.op, op_idname);
tref_rt.index = index;
- STRNCPY(tref_rt.idname_fallback, idname_fallback);
+ /* While it's logical to assign both these values from setup,
+ * it's useful to stored this in DNA for re-use, exceptional case: write to the 'tref'. */
+ STRNCPY(tref->idname_fallback, idname_fallback);
STRNCPY(tref_rt.keymap_fallback, keymap_fallback);
WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, idname);
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 0bf1dd8e2b3..b070a3c7127 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -105,6 +105,7 @@ static void sphere_do(CastModifierData *cmd,
int numVerts)
{
MDeformVert *dvert = NULL;
+ const bool invert_vgroup = (cmd->flag & MOD_CAST_INVERT_VGROUP) != 0;
Object *ctrl_ob = NULL;
@@ -198,7 +199,9 @@ static void sphere_do(CastModifierData *cmd,
}
if (dvert) {
- const float weight = defvert_find_weight(&dvert[i], defgrp_index);
+ const float weight = invert_vgroup ? 1.0f - defvert_find_weight(&dvert[i], defgrp_index) :
+ defvert_find_weight(&dvert[i], defgrp_index);
+
if (weight == 0.0f) {
continue;
}
@@ -240,6 +243,8 @@ static void cuboid_do(CastModifierData *cmd,
int numVerts)
{
MDeformVert *dvert = NULL;
+ const bool invert_vgroup = (cmd->flag & MOD_CAST_INVERT_VGROUP) != 0;
+
Object *ctrl_ob = NULL;
int i, defgrp_index;
@@ -365,7 +370,9 @@ static void cuboid_do(CastModifierData *cmd,
}
if (dvert) {
- const float weight = defvert_find_weight(&dvert[i], defgrp_index);
+ const float weight = invert_vgroup ? 1.0f - defvert_find_weight(&dvert[i], defgrp_index) :
+ defvert_find_weight(&dvert[i], defgrp_index);
+
if (weight == 0.0f) {
continue;
}
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 26ee75140a6..83d8439f046 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -177,8 +177,7 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* structName */ "DynamicPaintModifierData",
/* structSize */ sizeof(DynamicPaintModifierData),
/* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh |
- /* eModifierTypeFlag_SupportsMapping |*/
+ /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_UsesPointCache | eModifierTypeFlag_Single |
eModifierTypeFlag_UsesPreview,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 49bb8691764..f4c2e78d1ac 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -164,6 +164,9 @@ static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *ps
if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) {
return true;
}
+ if (pa->flag & (PARS_UNEXIST | PARS_NO_DISP)) {
+ return true;
+ }
}
if (pimd->particle_amount == 1.0f) {
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index b8d0b19b7bf..6e4b0edb004 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -108,8 +108,10 @@ static void deformVerts(ModifierData *md,
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
Mesh *mesh_src = NULL;
- if (ctx->object->type == OB_MESH) {
- /* mesh_src is only needed for vgroups. */
+ if (ELEM(ctx->object->type, OB_MESH, OB_LATTICE) ||
+ (swmd->shrinkType == MOD_SHRINKWRAP_PROJECT)) {
+ /* mesh_src is needed for vgroups, but also used as ShrinkwrapCalcData.vert when projecting.
+ * Avoid time-consuming mesh conversion for curves when not projecting. */
mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index be7bbb86e4d..799c1c966a3 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -163,6 +163,8 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
+ const float ofs_front_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? ofs_front : ofs_back));
+ const float ofs_back_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? ofs_back : ofs_front));
const float offset_fac_vg = smd->offset_fac_vg;
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
const float offset = fabsf(smd->offset) * smd->offset_clamp;
@@ -1262,15 +1264,16 @@ 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;
if (!null_faces[face->index]) {
mul_v3_v3fl(normals_queue[queue_index],
poly_nors[face->index],
face->reversed ? -1 : 1);
- normals_queue[queue_index++][3] = face->reversed ? ofs_back : ofs_front;
+ normals_queue[queue_index++][3] = ofs;
}
else {
mul_v3_v3fl(face_nors[0], poly_nors[face->index], face->reversed ? -1 : 1);
- nor_ofs[0] = face->reversed ? ofs_back : ofs_front;
+ nor_ofs[0] = ofs;
}
}
}
@@ -1280,7 +1283,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
uint face_nors_len = 0;
- const float stop_explosion = 1 - fabsf(smd->offset_fac) * 0.05f;
+ const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f;
while (queue_index > 0) {
if (face_nors_len == 0) {
if (queue_index <= 2) {
@@ -1371,50 +1374,23 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
MEM_freeN(normals_queue);
/* When up to 3 constraint normals are found. */
- float d, q;
- switch (face_nors_len) {
- case 0:
- mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]);
- disable_boundary_fix = true;
- break;
- case 1:
- mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]);
- disable_boundary_fix = true;
- break;
- case 2:
- q = dot_v3v3(face_nors[0], face_nors[1]);
- d = 1.0f - q * q;
- if (LIKELY(d > FLT_EPSILON) && q < stop_explosion) {
- d = 1.0f / d;
- mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d);
- mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d);
- add_v3_v3v3(nor, face_nors[0], face_nors[1]);
- }
- else {
- mul_v3_fl(face_nors[0], nor_ofs[0] * 0.5f);
- mul_v3_fl(face_nors[1], nor_ofs[1] * 0.5f);
- add_v3_v3v3(nor, face_nors[0], face_nors[1]);
- }
- if (!disable_boundary_fix) {
- cross_v3_v3v3(move_nor, face_nors[0], face_nors[1]);
- }
- break;
- case 3:
- q = dot_v3v3(face_nors[0], face_nors[1]);
- d = 1.0f - q * q;
- float *free_nor = move_nor; /* No need to allocate a new array. */
- cross_v3_v3v3(free_nor, face_nors[0], face_nors[1]);
- if (LIKELY(d > FLT_EPSILON) && q < stop_explosion) {
- d = 1.0f / d;
- mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d);
- mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d);
- add_v3_v3v3(nor, face_nors[0], face_nors[1]);
- }
- else {
- mul_v3_fl(face_nors[0], nor_ofs[0] * 0.5f);
- mul_v3_fl(face_nors[1], nor_ofs[1] * 0.5f);
- add_v3_v3v3(nor, face_nors[0], face_nors[1]);
- }
+ if (ELEM(face_nors_len, 2, 3)) {
+ const float q = dot_v3v3(face_nors[0], face_nors[1]);
+ float d = 1.0f - q * q;
+ cross_v3_v3v3(move_nor, face_nors[0], face_nors[1]);
+ if (d > FLT_EPSILON * 10 && q < stop_explosion) {
+ d = 1.0f / d;
+ mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d);
+ mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d);
+ }
+ else {
+ d = 1.0f / (fabsf(q) + 1.0f);
+ mul_v3_fl(face_nors[0], nor_ofs[0] * d);
+ mul_v3_fl(face_nors[1], nor_ofs[1] * d);
+ }
+ add_v3_v3v3(nor, face_nors[0], face_nors[1]);
+ if (face_nors_len == 3) {
+ float *free_nor = move_nor;
mul_v3_fl(face_nors[2], nor_ofs[2]);
d = dot_v3v3(face_nors[2], free_nor);
if (LIKELY(fabsf(d) > FLT_EPSILON)) {
@@ -1423,12 +1399,15 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
sub_v3_v3(nor, free_nor);
}
disable_boundary_fix = true;
- break;
- default:
- BLI_assert(0);
+ }
+ }
+ else {
+ BLI_assert(face_nors_len < 2);
+ mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]);
+ disable_boundary_fix = true;
}
}
- /* Simple/Even Method. */
+ /* Fixed/Even Method. */
else {
float total_angle = 0;
float total_angle_back = 0;
@@ -1447,8 +1426,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
if (face && (first_edge == NULL ||
(first_edge->faces[0] != face && first_edge->faces[1] != face))) {
float angle = 1.0f;
- float ofs = face->reversed ? -max_ff(1.0e-5f, ofs_back) :
- max_ff(1.0e-5f, ofs_front);
+ float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped;
if (smd->nonmanifold_offset_mode ==
MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) {
MLoop *ml_next = orig_mloop + face->face->loopstart;
@@ -1495,17 +1473,16 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
/* Set normal length with selected method. */
if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) {
- float d = dot_v3v3(nor, nor_back);
if (has_front) {
- float length = len_squared_v3(nor);
- if (LIKELY(length > FLT_EPSILON)) {
- mul_v3_fl(nor, total_angle / length);
+ float length_sq = len_squared_v3(nor);
+ if (LIKELY(length_sq > FLT_EPSILON)) {
+ mul_v3_fl(nor, total_angle / length_sq);
}
}
if (has_back) {
- float length = len_squared_v3(nor_back);
- if (LIKELY(length > FLT_EPSILON)) {
- mul_v3_fl(nor_back, total_angle_back / length);
+ float length_sq = len_squared_v3(nor_back);
+ if (LIKELY(length_sq > FLT_EPSILON)) {
+ mul_v3_fl(nor_back, total_angle_back / length_sq);
}
if (!has_front) {
copy_v3_v3(nor, nor_back);
@@ -1518,7 +1495,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
if (LIKELY(fabsf(q) > FLT_EPSILON)) {
q /= nor_length * nor_back_length;
}
- d = 1.0f - q * q;
+ float d = 1.0f - q * q;
if (LIKELY(d > FLT_EPSILON)) {
d = 1.0f / d;
if (LIKELY(nor_length > FLT_EPSILON)) {
@@ -1543,6 +1520,9 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
if (has_back && total_angle_back > FLT_EPSILON) {
mul_v3_fl(nor_back, 1.0f / total_angle_back);
add_v3_v3(nor, nor_back);
+ if (has_front && total_angle > FLT_EPSILON) {
+ mul_v3_fl(nor, 0.5f);
+ }
}
}
/* Set move_nor for boundary fix. */
@@ -1625,24 +1605,26 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
/* Do clamping. */
if (do_clamp) {
if (do_angle_clamp) {
- float min_length = 0;
- float angle = 0.5f * M_PI;
- uint k = 0;
- for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
- float length = orig_edge_lengths[(*p)->old_edge];
- float e_ang = (*p)->angle;
- if (e_ang > angle) {
- angle = e_ang;
- }
- if (length < min_length || k == 0) {
- min_length = length;
+ if (g->edges_len > 2) {
+ float min_length = 0;
+ float angle = 0.5f * M_PI;
+ uint k = 0;
+ for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
+ float length = orig_edge_lengths[(*p)->old_edge];
+ float e_ang = (*p)->angle;
+ if (e_ang > angle) {
+ angle = e_ang;
+ }
+ if (length < min_length || k == 0) {
+ min_length = length;
+ }
}
- }
- float cos_ang = cosf(angle * 0.5f);
- if (cos_ang > 0) {
- float max_off = min_length * 0.5f / cos_ang;
- if (max_off < offset * 0.5f) {
- scalar_vgroup *= max_off / offset * 2;
+ float cos_ang = cosf(angle * 0.5f);
+ if (cos_ang > 0) {
+ float max_off = min_length * 0.5f / cos_ang;
+ if (max_off < offset * 0.5f) {
+ scalar_vgroup *= max_off / offset * 2;
+ }
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index de32b90a5e3..6ec7d1069de 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -979,7 +979,8 @@ static void bindVert(void *__restrict userdata,
freeBindData(bwdata);
}
-static bool surfacedeformBind(SurfaceDeformModifierData *smd,
+static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
+ SurfaceDeformModifierData *smd_eval,
float (*vertexCos)[3],
uint numverts,
uint tnumpoly,
@@ -999,38 +1000,38 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
vert_edges = MEM_calloc_arrayN(tnumverts, sizeof(*vert_edges), "SDefVertEdgeMap");
if (vert_edges == NULL) {
- modifier_setError((ModifierData *)smd, "Out of memory");
+ modifier_setError((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, "Out of memory");
+ modifier_setError((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, "Out of memory");
+ modifier_setError((ModifierData *)smd_eval, "Out of memory");
MEM_freeN(vert_edges);
MEM_freeN(adj_array);
return false;
}
- smd->verts = MEM_malloc_arrayN(numverts, sizeof(*smd->verts), "SDefBindVerts");
- if (smd->verts == NULL) {
- modifier_setError((ModifierData *)smd, "Out of memory");
+ 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");
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, "Out of memory");
+ modifier_setError((ModifierData *)smd_eval, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
- MEM_freeN(smd->verts);
- smd->verts = NULL;
+ MEM_freeN(smd_orig->verts);
+ smd_orig->verts = NULL;
return false;
}
@@ -1038,16 +1039,16 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
mpoly, medge, mloop, tnumpoly, tnumedges, vert_edges, adj_array, edge_polys);
if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
- modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons");
+ modifier_setError((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->verts);
- smd->verts = NULL;
+ MEM_freeN(smd_orig->verts);
+ smd_orig->verts = NULL;
return false;
}
- smd->numverts = numverts;
- smd->numpoly = tnumpoly;
+ smd_orig->numverts = numverts;
+ smd_orig->numpoly = tnumpoly;
SDefBindCalcData data = {
.treeData = &treeData,
@@ -1058,22 +1059,22 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
.mloop = mloop,
.looptri = BKE_mesh_runtime_looptri_ensure(target),
.targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetBindVertArray"),
- .bind_verts = smd->verts,
+ .bind_verts = smd_orig->verts,
.vertexCos = vertexCos,
- .falloff = smd->falloff,
+ .falloff = smd_orig->falloff,
.success = MOD_SDEF_BIND_RESULT_SUCCESS,
};
if (data.targetCos == NULL) {
- modifier_setError((ModifierData *)smd, "Out of memory");
- freeData((ModifierData *)smd);
+ modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ freeData((ModifierData *)smd_orig);
return false;
}
- invert_m4_m4(data.imat, smd->mat);
+ invert_m4_m4(data.imat, smd_orig->mat);
for (int i = 0; i < tnumverts; i++) {
- mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
+ mul_v3_m4v3(data.targetCos[i], smd_orig->mat, mvert[i].co);
}
TaskParallelSettings settings;
@@ -1084,28 +1085,28 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd,
MEM_freeN(data.targetCos);
if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
- modifier_setError((ModifierData *)smd, "Out of memory");
- freeData((ModifierData *)smd);
+ modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ freeData((ModifierData *)smd_orig);
}
else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
- modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons");
- freeData((ModifierData *)smd);
+ modifier_setError((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, "Target contains concave polygons");
- freeData((ModifierData *)smd);
+ modifier_setError((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, "Target contains overlapping verts");
- freeData((ModifierData *)smd);
+ modifier_setError((ModifierData *)smd_eval, "Target contains overlapping verts");
+ freeData((ModifierData *)smd_orig);
}
else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) {
/* I know this message is vague, but I could not think of a way
* 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, "Target contains invalid polygons");
- freeData((ModifierData *)smd);
+ modifier_setError((ModifierData *)smd_eval, "Target contains invalid polygons");
+ freeData((ModifierData *)smd_orig);
}
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
@@ -1216,7 +1217,7 @@ static void surfacedeformModifier_do(ModifierData *md,
invert_m4_m4(tmp_mat, ob->obmat);
mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->obmat);
- if (!surfacedeformBind(smd_orig, vertexCos, numverts, tnumpoly, tnumverts, target)) {
+ if (!surfacedeformBind(smd_orig, smd, vertexCos, numverts, tnumpoly, tnumverts, target)) {
smd->flags &= ~MOD_SDEF_BIND;
}
/* Early abort, this is binding 'call', no need to perform whole evaluation. */
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index b393cedbd37..f96ec9a82e5 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -1602,6 +1602,7 @@ static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, in
struct WeldOverlapData *data = userdata;
const MVert *mvert = data->mvert;
const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co);
+ BLI_assert(dist_sq <= ((data->merge_dist_sq + FLT_EPSILON) * 3));
return dist_sq <= data->merge_dist_sq;
}
return false;
@@ -1629,13 +1630,15 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
if (defgrp_index != -1) {
MDeformVert *dvert, *dv;
dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
- dv = &dvert[0];
- v_mask = BLI_BITMAP_NEW(totvert, __func__);
- for (i = 0; i < totvert; i++, dv++) {
- const bool found = defvert_find_weight(dv, defgrp_index) > 0.0f;
- if (found) {
- BLI_BITMAP_ENABLE(v_mask, i);
- v_mask_act++;
+ if (dvert) {
+ dv = &dvert[0];
+ v_mask = BLI_BITMAP_NEW(totvert, __func__);
+ for (i = 0; i < totvert; i++, dv++) {
+ const bool found = defvert_find_weight(dv, defgrp_index) > 0.0f;
+ if (found) {
+ BLI_BITMAP_ENABLE(v_mask, i);
+ v_mask_act++;
+ }
}
}
}
@@ -1644,7 +1647,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
/* 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, 6, 0, NULL);
+ &treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist / 2, 2, 6, 0, NULL);
if (v_mask) {
MEM_freeN(v_mask);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 2eb2a6b380a..e15eb5af2c4 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -275,6 +275,10 @@ if(WITH_PYTHON)
list(APPEND INC_SYS
${PYTHON_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
+ )
add_definitions(-DWITH_PYTHON)
endif()
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index ffeeb7525d5..612cd0c9293 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -332,7 +332,16 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
bNodeSocket *group_socket = group_node->inputs.first;
for (; group_socket; group_socket = group_socket->next) {
+
if (group_socket->link != NULL) {
+ bNodeLink *link = group_socket->link;
+ /* Fix the case where the socket is actually converting the data. (see T71374)
+ * We only do the case of lossy conversion to float.*/
+ if ((group_socket->type == SOCK_FLOAT) && (link->fromsock->type != link->tosock->type)) {
+ bNode *node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW);
+ nodeAddLink(localtree, link->fromnode, link->fromsock, node, node->inputs.first);
+ nodeAddLink(localtree, node, node->outputs.first, group_node, group_socket);
+ }
continue;
}
@@ -636,7 +645,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
if (node->tmp_flag >= 0) {
int id = node->tmp_flag;
nodes_copy[id] = BKE_node_copy_ex(
- ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
+ ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false);
nodes_copy[id]->tmp_flag = -2; /* Copy */
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index 6292d7b5062..d20b919a7fb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -64,10 +64,44 @@ static int gpu_shader_curve_vec(GPUMaterial *mat,
float *array, layer;
int size;
- BKE_curvemapping_table_RGBA(node->storage, &array, &size);
+ CurveMapping *cumap = node->storage;
+
+ BKE_curvemapping_table_RGBA(cumap, &array, &size);
GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
- return GPU_stack_link(mat, node, "curves_vec", in, out, tex, GPU_constant(&layer));
+ float ext_xyz[3][4];
+ float range_xyz[3];
+
+ for (int a = 0; a < 3; a++) {
+ const CurveMap *cm = &cumap->cm[a];
+ ext_xyz[a][0] = cm->mintable;
+ ext_xyz[a][2] = cm->maxtable;
+ range_xyz[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
+ /* Compute extrapolation gradients. */
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
+ ext_xyz[a][1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_xyz[a])) :
+ 1e8f;
+ ext_xyz[a][3] = (cm->ext_out[0] != 0.0f) ?
+ (cm->ext_out[1] / (cm->ext_out[0] * range_xyz[a])) :
+ 1e8f;
+ }
+ else {
+ ext_xyz[a][1] = 0.0f;
+ ext_xyz[a][3] = 0.0f;
+ }
+ }
+
+ return GPU_stack_link(mat,
+ node,
+ "curves_vec",
+ in,
+ out,
+ tex,
+ GPU_constant(&layer),
+ GPU_uniform(range_xyz),
+ GPU_uniform(ext_xyz[0]),
+ GPU_uniform(ext_xyz[1]),
+ GPU_uniform(ext_xyz[2]));
}
void register_node_type_sh_curve_vec(void)
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 72ad5581050..6c380efe0b2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -88,7 +88,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
"node_tex_environment_equirectangular",
in[0].link,
GPU_constant(&clamp_size),
- GPU_image(ima, iuser, 0),
+ GPU_image(ima, iuser),
&in[0].link);
}
else {
@@ -103,7 +103,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPU_link(mat,
"node_tex_image_linear_no_mip",
in[0].link,
- GPU_image(ima, iuser, 0),
+ GPU_image(ima, iuser),
&out[0].link,
&outalpha);
break;
@@ -111,17 +111,13 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPU_link(mat,
"node_tex_image_nearest",
in[0].link,
- GPU_image(ima, iuser, 0),
+ GPU_image(ima, iuser),
&out[0].link,
&outalpha);
break;
default:
- GPU_link(mat,
- "node_tex_image_cubic",
- in[0].link,
- GPU_image(ima, iuser, 0),
- &out[0].link,
- &outalpha);
+ GPU_link(
+ mat, "node_tex_image_cubic", in[0].link, GPU_image(ima, iuser), &out[0].link, &outalpha);
break;
}
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 34a5e323490..781fd1eb579 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -130,21 +130,19 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
if (ima->source == IMA_SRC_TILED) {
- GPUNodeLink *map;
- GPU_link(mat, "node_tex_tile_map", in[0].link, &out[0].link, &map);
- /* This is not exactly great, but if we want to support different sizes per
- * tile and older hardware, which rules out better methods like texture arrays. */
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- float tile_number = tile->tile_number;
- GPU_link(mat,
- names_tiled[tex->interpolation],
- map,
- GPU_uniform(&tile_number),
- GPU_image(ima, iuser, tile->tile_number),
- out[0].link,
- &out[0].link,
- &out[1].link);
- }
+ /* The tiled shader needs both the tile array itself as well as the mapping from tile to array
+ * position. Which of these to allocate is automatically decided based on the shader argument
+ * type, so here the first GPU_image(ima, iuser) will resolve to the array and the second to
+ * the mapping since the third argument in the shader has type sampler2DArray while
+ * the fourth is sampler1DArray.
+ */
+ GPU_stack_link(mat,
+ node,
+ names_tiled[tex->interpolation],
+ in,
+ out,
+ GPU_image(ima, iuser),
+ GPU_image(ima, iuser));
}
else {
switch (tex->projection) {
@@ -159,20 +157,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPU_link(mat, "set_rgb", *texco, &input_coords);
}
if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, 0), texco);
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
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(ima, iuser, 0);
+ gpu_image = GPU_image(ima, iuser);
/* 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(ima, iuser, 0), &col1, &col2, &col3);
+ GPU_link(mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser), &col1, &col2, &col3);
GPU_stack_link(
mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend);
break;
@@ -186,9 +184,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPU_link(mat, "set_rgb", *texco, &input_coords);
}
if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, 0), texco);
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
break;
case SHD_PROJ_TUBE:
@@ -200,9 +198,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPU_link(mat, "set_rgb", *texco, &input_coords);
}
if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, 0), texco);
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, 0));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
break;
}
@@ -210,7 +208,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
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(ima, iuser, 0), out[0].link);
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser), out[0].link);
}
}
}
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 ec4fedec27c..0dfacb19729 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
@@ -28,6 +28,7 @@ static bNodeSocketTemplate sh_node_tex_white_noise_in[] = {
static bNodeSocketTemplate sh_node_tex_white_noise_out[] = {
{SOCK_FLOAT, 0, N_("Value")},
+ {SOCK_RGBA, 0, N_("Color")},
{-1, 0, ""},
};
diff --git a/source/blender/physics/CMakeLists.txt b/source/blender/physics/CMakeLists.txt
index edcfdceb697..10520a18513 100644
--- a/source/blender/physics/CMakeLists.txt
+++ b/source/blender/physics/CMakeLists.txt
@@ -48,4 +48,10 @@ set(SRC
set(LIB
)
+if(WITH_OPENMP_STATIC)
+ list(APPEND LIB
+ ${OpenMP_LIBRARIES}
+ )
+endif()
+
blender_add_lib(bf_physics "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 999cefde104..8f079a75f14 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -21,9 +21,9 @@
* \ingroup bph
*/
-extern "C" {
#include "MEM_guardedalloc.h"
+extern "C" {
#include "DNA_cloth_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_force_types.h"
@@ -82,8 +82,13 @@ static float cloth_calc_volume(ClothModifierData *clmd)
Implicit_Data *data = cloth->implicit;
float vol = 0;
+ /* Early exit for hair, as it never has volume. */
+ if (clmd->hairdata) {
+ return 0.0f;
+ }
+
if (clmd->sim_parms->vgroup_pressure > 0) {
- for (unsigned int i = 0; i < cloth->tri_num; i++) {
+ for (unsigned int i = 0; i < cloth->primitive_num; i++) {
bool skip_face = false;
/* We have custom vertex weights for pressure. */
const MVertTri *vt = &tri[i];
@@ -103,7 +108,7 @@ static float cloth_calc_volume(ClothModifierData *clmd)
}
}
else {
- for (unsigned int i = 0; i < cloth->tri_num; i++) {
+ for (unsigned int i = 0; i < cloth->primitive_num; i++) {
const MVertTri *vt = &tri[i];
vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]);
}
@@ -174,96 +179,17 @@ void BKE_cloth_solver_set_volume(ClothModifierData *clmd)
cloth->initial_mesh_volume = cloth_calc_volume(clmd);
}
-static bool collision_response(ClothModifierData *clmd,
- CollisionModifierData *collmd,
- CollPair *collpair,
- float dt,
- float restitution,
- float r_impulse[3])
-{
- Cloth *cloth = clmd->clothObject;
- int index = collpair->ap1;
- bool result = false;
-
- float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- float margin_distance = (float)collpair->distance - epsilon2;
- float mag_v_rel;
-
- zero_v3(r_impulse);
-
- if (margin_distance > 0.0f) {
- return false; /* XXX tested before already? */
- }
-
- /* only handle static collisions here */
- if (collpair->flag & COLLISION_IN_FUTURE) {
- return false;
- }
-
- /* velocity */
- copy_v3_v3(v1, cloth->verts[index].v);
- collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
- /* relative velocity = velocity of the cloth point relative to the collider */
- sub_v3_v3v3(v_rel_old, v1, v2_old);
- sub_v3_v3v3(v_rel_new, v1, v2_new);
- /* normal component of the relative velocity */
- mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
- /* only valid when moving toward the collider */
- if (mag_v_rel < -ALMOST_ZERO) {
- float v_nor_old, v_nor_new;
- float v_tan_old[3], v_tan_new[3];
- float bounce, repulse;
-
- /* Collision response based on
- * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
- * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
- */
-
- v_nor_old = mag_v_rel;
- v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
- madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
- madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
- bounce = -v_nor_old * restitution;
-
- repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
- /* XXX this clamping factor is quite arbitrary ...
- * not sure if there is a more scientific approach, but seems to give good results
- */
- CLAMP(repulse, 0.0f, 4.0f * bounce);
-
- if (margin_distance < -epsilon2) {
- mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
- }
- else {
- bounce = 0.0f;
- mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
- }
-
- result = true;
- }
-
- return result;
-}
-
/* Init constraint matrix
* This is part of the modified CG method suggested by Baraff/Witkin in
* "Large Steps in Cloth Simulation" (Siggraph 1998)
*/
-static void cloth_setup_constraints(ClothModifierData *clmd,
- ColliderContacts *contacts,
- int totcolliders,
- float dt)
+static void cloth_setup_constraints(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
Implicit_Data *data = cloth->implicit;
ClothVertex *verts = cloth->verts;
int mvert_num = cloth->mvert_num;
- int i, j, v;
+ int v;
const float ZERO[3] = {0.0f, 0.0f, 0.0f};
@@ -277,37 +203,6 @@ static void cloth_setup_constraints(ClothModifierData *clmd,
verts[v].impulse_count = 0;
}
-
- for (i = 0; i < totcolliders; i++) {
- ColliderContacts *ct = &contacts[i];
- for (j = 0; j < ct->totcollisions; j++) {
- CollPair *collpair = &ct->collisions[j];
- // float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
- float restitution = 0.0f;
- int v = collpair->face1;
- float impulse[3];
-
- /* pinned verts handled separately */
- if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
- continue;
- }
-
- /* XXX cheap way of avoiding instability from multiple collisions in the same step
- * this should eventually be supported ...
- */
- if (verts[v].impulse_count > 0) {
- continue;
- }
-
- /* calculate collision response */
- if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse)) {
- continue;
- }
-
- BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
- ++verts[v].impulse_count;
- }
- }
}
/* computes where the cloth would be if it were subject to perfectly stiff edges
@@ -657,8 +552,8 @@ static void cloth_calc_force(
#ifdef CLOTH_FORCE_DRAG
BPH_mass_spring_force_drag(data, drag);
#endif
- /* handle pressure forces */
- if (parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) {
+ /* handle pressure forces (making sure that this never gets computed for hair). */
+ if ((parms->flags & CLOTH_SIMSETTINGS_FLAG_PRESSURE) && (clmd->hairdata == NULL)) {
/* The difference in pressure between the inside and outside of the mesh.*/
float pressure_difference = 0.0f;
@@ -691,7 +586,7 @@ static void cloth_calc_force(
pressure_difference *= clmd->sim_parms->pressure_factor;
- for (i = 0; i < cloth->tri_num; i++) {
+ for (i = 0; i < cloth->primitive_num; i++) {
const MVertTri *vt = &tri[i];
if (fabs(pressure_difference) > 1E-6f) {
if (clmd->sim_parms->vgroup_pressure > 0) {
@@ -744,13 +639,14 @@ static void cloth_calc_force(
effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
- for (i = 0; i < cloth->tri_num; i++) {
- const MVertTri *vt = &tri[i];
- BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
+ /* Hair has only edges. */
+ if ((clmd->hairdata == NULL) && (cloth->primitive_num > 0)) {
+ for (i = 0; i < cloth->primitive_num; i++) {
+ const MVertTri *vt = &tri[i];
+ BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
+ }
}
-
- /* Hair has only edges */
- if (cloth->tri_num == 0) {
+ else {
#if 0
ClothHairData *hairdata = clmd->hairdata;
ClothHairData *hair_ij, *hair_kl;
@@ -1241,8 +1137,6 @@ int BPH_cloth_solve(
unsigned int mvert_num = cloth->mvert_num;
float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale;
Implicit_Data *id = cloth->implicit;
- ColliderContacts *contacts = NULL;
- int totcolliders = 0;
BKE_sim_debug_data_clear_category("collision");
@@ -1269,25 +1163,8 @@ int BPH_cloth_solve(
while (step < tf) {
ImplicitSolverResult result;
- if (is_hair) {
- /* copy velocities for collision */
- for (i = 0; i < mvert_num; i++) {
- BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
- /* determine contact points */
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
- cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders);
- }
-
- /* setup vertex constraints for pinned vertices and contacts */
- cloth_setup_constraints(clmd, contacts, totcolliders, dt);
- }
- else {
- /* setup vertex constraints for pinned vertices */
- cloth_setup_constraints(clmd, NULL, 0, dt);
- }
+ /* setup vertex constraints for pinned vertices */
+ cloth_setup_constraints(clmd);
/* initialize forces to zero */
BPH_mass_spring_clear_forces(id);
@@ -1300,9 +1177,7 @@ int BPH_cloth_solve(
cloth_record_result(clmd, &result, dt);
/* Calculate collision impulses. */
- if (!is_hair) {
- cloth_solve_collisions(depsgraph, ob, clmd, step, dt);
- }
+ cloth_solve_collisions(depsgraph, ob, clmd, step, dt);
if (is_hair) {
cloth_continuum_step(clmd, dt);
@@ -1327,11 +1202,6 @@ int BPH_cloth_solve(
BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
}
- /* free contact points */
- if (contacts) {
- cloth_free_contacts(contacts, totcolliders);
- }
-
step += dt;
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index be2fd6c4e53..810c86c115a 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -51,6 +51,7 @@ int BPY_is_pyconstraint(struct Text *text);
void BPY_python_start(int argc, const char **argv);
void BPY_python_end(void);
void BPY_python_reset(struct bContext *C);
+void BPY_python_use_system_env(void);
/* global interpreter lock */
diff --git a/source/blender/python/bmesh/CMakeLists.txt b/source/blender/python/bmesh/CMakeLists.txt
index 3875057185a..818498fe7db 100644
--- a/source/blender/python/bmesh/CMakeLists.txt
+++ b/source/blender/python/bmesh/CMakeLists.txt
@@ -55,6 +55,9 @@ set(LIB
bf_blenkernel
bf_blenlib
bf_python_mathutils
+
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
)
if(WITH_FREESTYLE)
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 8ab5e7adea7..7f5b10e6759 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -148,9 +148,9 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args,
{
extern void EDBM_update_generic(
- BMEditMesh * em, const bool do_tessface, const bool is_destructive);
+ struct Mesh * me, const bool do_tessface, const bool is_destructive);
- EDBM_update_generic(me->edit_mesh, do_loop_triangles, is_destructive);
+ EDBM_update_generic(me, do_loop_triangles, is_destructive);
}
Py_RETURN_NONE;
diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt
index c878103e19d..822f05bad90 100644
--- a/source/blender/python/generic/CMakeLists.txt
+++ b/source/blender/python/generic/CMakeLists.txt
@@ -50,6 +50,8 @@ set(SRC
set(LIB
${GLEW_LIBRARY}
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
)
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt
index ca0e6ced42b..22a3d3a79de 100644
--- a/source/blender/python/gpu/CMakeLists.txt
+++ b/source/blender/python/gpu/CMakeLists.txt
@@ -55,6 +55,8 @@ set(SRC
)
set(LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
)
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 9aa364c4436..cfb61edee62 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
bpy_app_sdl.c
bpy_app_timers.c
bpy_app_translations.c
+ bpy_app_usd.c
bpy_capi_utils.c
bpy_driver.c
bpy_gizmo_wrap.c
@@ -95,6 +96,7 @@ set(SRC
bpy_app_sdl.h
bpy_app_timers.h
bpy_app_translations.h
+ bpy_app_usd.h
bpy_capi_utils.h
bpy_driver.h
bpy_gizmo_wrap.h
@@ -123,6 +125,9 @@ set(LIB
bf_editor_interface
bf_editor_space_api
bf_python_gpu
+
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
)
# only to check if buildinfo is available
@@ -156,6 +161,9 @@ if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${FFMPEG_LIBRARIES}
+ )
add_definitions(-DWITH_FFMPEG)
endif()
@@ -244,6 +252,11 @@ if(WITH_SDL)
list(APPEND INC_SYS
${SDL_INCLUDE_DIR}
)
+ if(NOT WITH_SDL_DYNLOAD)
+ list(APPEND LIB
+ ${SDL_LIBRARY}
+ )
+ endif()
add_definitions(-DWITH_SDL)
endif()
@@ -302,6 +315,9 @@ endif()
if(WITH_USD)
add_definitions(-DWITH_USD)
+ list(APPEND INC
+ ../../usd
+ )
endif()
if(WITH_OPENIMAGEIO)
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 043b31007f1..678df0d8993 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -33,6 +33,7 @@
#include "bpy_app_opensubdiv.h"
#include "bpy_app_openvdb.h"
#include "bpy_app_sdl.h"
+#include "bpy_app_usd.h"
#include "bpy_app_build_options.h"
#include "bpy_app_translations.h"
@@ -108,6 +109,7 @@ static PyStructSequence_Field app_info_fields[] = {
/* submodules */
{"alembic", "Alembic library information backend"},
+ {"usd", "USD library information backend"},
{"ffmpeg", "FFmpeg library information backend"},
{"ocio", "OpenColorIO library information backend"},
{"oiio", "OpenImageIO library information backend"},
@@ -201,6 +203,7 @@ static PyObject *make_app_info(void)
#endif
SetObjItem(BPY_app_alembic_struct());
+ SetObjItem(BPY_app_usd_struct());
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
diff --git a/source/blender/python/intern/bpy_app_usd.c b/source/blender/python/intern/bpy_app_usd.c
new file mode 100644
index 00000000000..d87d218a5e5
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_usd.c
@@ -0,0 +1,107 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+
+#include "bpy_app_usd.h"
+
+#include "../generic/py_capi_utils.h"
+
+#ifdef WITH_USD
+# include "usd.h"
+#endif
+
+static PyTypeObject BlenderAppUSDType;
+
+static PyStructSequence_Field app_usd_info_fields[] = {
+ {"supported", "Boolean, True when Blender is built with USD support"},
+ {"version", "The USD version as a tuple of 3 numbers"},
+ {"version_string", "The USD version formatted as a string"},
+ {NULL},
+};
+
+static PyStructSequence_Desc app_usd_info_desc = {
+ "bpy.app.usd", /* name */
+ "This module contains information about the Universal Scene Description library Bender is "
+ "linked against", /* doc */
+ app_usd_info_fields, /* fields */
+ ARRAY_SIZE(app_usd_info_fields) - 1,
+};
+
+static PyObject *make_usd_info(void)
+{
+ PyObject *usd_info = PyStructSequence_New(&BlenderAppUSDType);
+
+ if (usd_info == NULL) {
+ return NULL;
+ }
+
+ int pos = 0;
+
+#ifndef WITH_USD
+# define SetStrItem(str) PyStructSequence_SET_ITEM(usd_info, pos++, PyUnicode_FromString(str))
+#endif
+
+#define SetObjItem(obj) PyStructSequence_SET_ITEM(usd_info, pos++, obj)
+
+#ifdef WITH_USD
+ const int curversion = USD_get_version();
+ const int major = curversion / 10000;
+ const int minor = (curversion / 100) % 100;
+ const int patch = curversion % 100;
+
+ SetObjItem(PyBool_FromLong(1));
+ SetObjItem(PyC_Tuple_Pack_I32(major, minor, patch));
+ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch));
+#else
+ SetObjItem(PyBool_FromLong(0));
+ SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
+ SetStrItem("Unknown");
+#endif
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(usd_info);
+ return NULL;
+ }
+
+#undef SetStrItem
+#undef SetObjItem
+
+ return usd_info;
+}
+
+PyObject *BPY_app_usd_struct(void)
+{
+ PyStructSequence_InitType(&BlenderAppUSDType, &app_usd_info_desc);
+
+ PyObject *ret = make_usd_info();
+
+ /* prevent user from creating new instances */
+ BlenderAppUSDType.tp_init = NULL;
+ BlenderAppUSDType.tp_new = NULL;
+ BlenderAppUSDType.tp_hash = (hashfunc)
+ _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+
+ return ret;
+}
diff --git a/source/blender/python/intern/bpy_app_usd.h b/source/blender/python/intern/bpy_app_usd.h
new file mode 100644
index 00000000000..e3e1d72b366
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_usd.h
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_APP_USD_H__
+#define __BPY_APP_USD_H__
+
+PyObject *BPY_app_usd_struct(void);
+
+#endif /* __BPY_APP_USD_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 9acf05abfe2..28afab1a6eb 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -84,6 +84,9 @@ CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
* stop bpy_context_clear from invalidating. */
static int py_call_level = 0;
+/* Set by command line arguments before Python starts. */
+static bool py_use_system_env = false;
+
// #define TIME_PY_RUN // simple python tests. prints on exit.
#ifdef TIME_PY_RUN
@@ -276,6 +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.
+ * Since an incorrect 'PYTHONPATH' causes difficult to debug errors, see: T72807. */
+ Py_IgnoreEnvironmentFlag = !py_use_system_env;
+
Py_Initialize();
// PySys_SetArgv(argc, argv); /* broken in py3, not a huge deal */
@@ -408,6 +415,12 @@ void BPY_python_reset(bContext *C)
BPY_modules_load_user(C);
}
+void BPY_python_use_system_env(void)
+{
+ BLI_assert(!Py_IsInitialized());
+ py_use_system_env = true;
+}
+
static void python_script_error_jump_text(struct Text *text)
{
int lineno;
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index cdb562a3233..e34432f0c54 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -58,6 +58,9 @@ set(SRC
set(LIB
bf_blenlib
bf_python_ext
+
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
)
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index fcb6a77bf36..859ece61ace 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1246,7 +1246,8 @@ PyDoc_STRVAR(M_Geometry_tessellate_polygon_doc,
".. function:: tessellate_polygon(veclist_list)\n"
"\n"
" Takes a list of polylines (each point a pair or triplet of numbers) and returns "
- "the point indices for a polyline filled with triangles.\n"
+ "the point indices for a polyline filled with triangles. Does not handle degenerate "
+ "geometry (such as zero-length lines due to consecutive identical points).\n"
"\n"
" :arg veclist_list: list of polylines\n"
" :rtype: list\n");
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 47d0986fabd..253741401f1 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -112,7 +112,7 @@ int imagewrap(Tex *tex,
texres->tin = texres->ta = texres->tr = texres->tg = texres->tb = 0.0f;
/* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? 3 : 1;
+ retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
/* quick tests */
if (ima == NULL) {
@@ -1035,7 +1035,7 @@ static int imagewraposa_aniso(Tex *tex,
texres->tin = texres->ta = texres->tr = texres->tg = texres->tb = 0.f;
/* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? 3 : 1;
+ retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
/* quick tests */
if (ibuf == NULL && ima == NULL) {
@@ -1492,7 +1492,7 @@ int imagewraposa(Tex *tex,
texres->tin = texres->ta = texres->tr = texres->tg = texres->tb = 0.0f;
/* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? 3 : 1;
+ retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
/* quick tests */
if (ibuf == NULL && ima == NULL) {
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index b5c2db96c47..0bf03347b80 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -1547,10 +1547,10 @@ void render_result_rect_get_pixels(RenderResult *rr,
{
RenderView *rv = RE_RenderViewGetById(rr, view_id);
- if (rv->rect32) {
+ if (rv && rv->rect32) {
memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty);
}
- else if (rv->rectf) {
+ else if (rv && rv->rectf) {
IMB_display_buffer_transform_apply((unsigned char *)rect,
rv->rectf,
rr->rectx,
diff --git a/source/blender/usd/CMakeLists.txt b/source/blender/usd/CMakeLists.txt
index 12d281f643d..6ea02f44d76 100644
--- a/source/blender/usd/CMakeLists.txt
+++ b/source/blender/usd/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
usd.h
intern/abstract_hierarchy_iterator.h
+ intern/usd_exporter_context.h
intern/usd_hierarchy_iterator.h
intern/usd_writer_abstract.h
intern/usd_writer_camera.h
@@ -78,4 +79,31 @@ set(LIB
bf_blenlib
)
+list(APPEND LIB
+ ${BOOST_LIBRARIES}
+)
+
+list(APPEND LIB
+)
+
blender_add_lib(bf_usd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WIN32)
+ set_property(TARGET bf_usd APPEND_STRING PROPERTY LINK_FLAGS_DEBUG " /WHOLEARCHIVE:${USD_DEBUG_LIB}")
+ set_property(TARGET bf_usd APPEND_STRING PROPERTY LINK_FLAGS_RELEASE " /WHOLEARCHIVE:${USD_RELEASE_LIB}")
+ set_property(TARGET bf_usd APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO " /WHOLEARCHIVE:${USD_RELEASE_LIB}")
+ set_property(TARGET bf_usd APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL " /WHOLEARCHIVE:${USD_RELEASE_LIB}")
+endif()
+
+# Source: https://github.com/PixarAnimationStudios/USD/blob/master/BUILDING.md#linking-whole-archives
+if(WIN32)
+ target_link_libraries(bf_usd ${USD_LIBRARIES})
+elseif(CMAKE_COMPILER_IS_GNUCXX)
+ target_link_libraries(bf_usd "-Wl,--whole-archive ${USD_LIBRARIES} -Wl,--no-whole-archive ${TBB_LIBRARIES}")
+elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ target_link_libraries(bf_usd -Wl,-force_load ${USD_LIBRARIES})
+else()
+ message(FATAL_ERROR "Unknown how to link USD with your compiler ${CMAKE_CXX_COMPILER_ID}")
+endif()
+
+target_link_libraries(bf_usd ${TBB_LIBRARIES})
diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/usd/intern/abstract_hierarchy_iterator.cc
index 3ad2b2ce5d8..a8ed2c5f2a5 100644
--- a/source/blender/usd/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/usd/intern/abstract_hierarchy_iterator.cc
@@ -88,6 +88,7 @@ AbstractHierarchyIterator::~AbstractHierarchyIterator()
void AbstractHierarchyIterator::iterate_and_write()
{
export_graph_construct();
+ connect_loose_objects();
export_graph_prune();
determine_export_paths(HierarchyContext::root());
determine_duplication_references(HierarchyContext::root(), "");
@@ -125,10 +126,10 @@ std::string AbstractHierarchyIterator::get_object_data_path(const HierarchyConte
return path_concatenate(context->export_path, get_object_data_name(context->object));
}
-void AbstractHierarchyIterator::debug_print_export_graph() const
+void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &graph) const
{
size_t total_graph_size = 0;
- for (const ExportGraph::value_type &map_iter : export_graph_) {
+ for (const ExportGraph::value_type &map_iter : graph) {
const DupliAndDuplicator &parent_info = map_iter.first;
Object *const export_parent = parent_info.first;
Object *const duplicator = parent_info.second;
@@ -174,11 +175,6 @@ void AbstractHierarchyIterator::export_graph_construct()
object,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) {
- if (object->base_flag & BASE_HOLDOUT) {
- visit_object(object, object->parent, true);
- continue;
- }
-
// Non-instanced objects always have their object-parent as export-parent.
const bool weak_export = mark_as_weak_export(object);
visit_object(object, object->parent, weak_export);
@@ -215,6 +211,48 @@ void AbstractHierarchyIterator::export_graph_construct()
DEG_OBJECT_ITER_END;
}
+void AbstractHierarchyIterator::connect_loose_objects()
+{
+ // Find those objects whose parent is not part of the export graph; these
+ // objects would be skipped when traversing the graph as a hierarchy.
+ // These objects will have to be re-attached to some parent object in order to
+ // fit into the hierarchy.
+ ExportGraph loose_objects_graph = export_graph_;
+ for (const ExportGraph::value_type &map_iter : export_graph_) {
+ for (const HierarchyContext *child : map_iter.second) {
+ // An object that is marked as a child of another object is not considered 'loose'.
+ loose_objects_graph.erase(std::make_pair(child->object, child->duplicator));
+ }
+ }
+ // The root of the hierarchy is always found, so it's never considered 'loose'.
+ loose_objects_graph.erase(std::make_pair(nullptr, nullptr));
+
+ // Iterate over the loose objects and connect them to their export parent.
+ 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);
+ if (found_parent_iter != export_graph_.end()) {
+ break;
+ }
+ // 'export_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);
+
+ object = export_parent;
+ export_parent = export_parent->parent;
+ }
+ }
+}
+
static bool remove_weak_subtrees(const HierarchyContext *context,
AbstractHierarchyIterator::ExportGraph &clean_graph,
const AbstractHierarchyIterator::ExportGraph &input_graph)
@@ -411,8 +449,6 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont
unit_m4(parent_matrix_inv_world);
}
- const std::string &parent_export_path = parent_context ? parent_context->export_path : "";
-
for (HierarchyContext *context : graph_children(parent_context)) {
copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world);
diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.h b/source/blender/usd/intern/abstract_hierarchy_iterator.h
index ea31e94cf9b..8bca2ddd447 100644
--- a/source/blender/usd/intern/abstract_hierarchy_iterator.h
+++ b/source/blender/usd/intern/abstract_hierarchy_iterator.h
@@ -128,14 +128,16 @@ class AbstractHierarchyIterator {
public:
/* Mapping from export path to writer. */
typedef std::map<std::string, AbstractHierarchyWriter *> WriterMap;
- /* Pair of a duplicated object and its duplicator, typically a pair of HierarchyContext::object
- * and HierarchyContext::duplicator. */
+ /* Pair of a (potentially duplicated) object and its duplicator (or nullptr).
+ * This is typically used to store a pair of HierarchyContext::object and
+ * HierarchyContext::duplicator. */
typedef std::pair<Object *, Object *> DupliAndDuplicator;
/* All the children of some object, as per the export hierarchy. */
typedef std::set<HierarchyContext *> ExportChildren;
/* Mapping from an object and its duplicator to the object's export-children. */
typedef std::map<DupliAndDuplicator, ExportChildren> ExportGraph;
- /* Mapping from (potential) duplicator ID to export path. */
+ /* Mapping from ID to its export path. This is used for instancing; given an
+ * instanced datablock, the export path of the original can be looked up. */
typedef std::map<ID *, std::string> ExportPathMap;
protected:
@@ -171,9 +173,10 @@ class AbstractHierarchyIterator {
virtual std::string get_object_data_path(const HierarchyContext *context) const;
private:
- void debug_print_export_graph() const;
+ void debug_print_export_graph(const ExportGraph &graph) const;
void export_graph_construct();
+ void connect_loose_objects();
void export_graph_prune();
void export_graph_clear();
diff --git a/source/blender/usd/intern/usd_capi.cc b/source/blender/usd/intern/usd_capi.cc
index 502f8677174..83e11cd7bf3 100644
--- a/source/blender/usd/intern/usd_capi.cc
+++ b/source/blender/usd/intern/usd_capi.cc
@@ -20,9 +20,12 @@
#include "usd.h"
#include "usd_hierarchy_iterator.h"
+#include <pxr/pxr.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdGeom/tokens.h>
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -39,8 +42,6 @@ extern "C" {
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "MEM_guardedalloc.h"
-
#include "WM_api.h"
#include "WM_types.h"
}
@@ -216,3 +217,17 @@ bool USD_export(bContext *C,
return export_ok;
}
+
+int USD_get_version(void)
+{
+ /* USD 19.11 defines:
+ *
+ * #define PXR_MAJOR_VERSION 0
+ * #define PXR_MINOR_VERSION 19
+ * #define PXR_PATCH_VERSION 11
+ * #define PXR_VERSION 1911
+ *
+ * So the major version is implicit/invisible in the public version number.
+ */
+ return PXR_VERSION;
+}
diff --git a/source/blender/usd/intern/usd_hierarchy_iterator.cc b/source/blender/usd/intern/usd_hierarchy_iterator.cc
index f53cba8b2c6..d56de8cff13 100644
--- a/source/blender/usd/intern/usd_hierarchy_iterator.cc
+++ b/source/blender/usd/intern/usd_hierarchy_iterator.cc
@@ -56,9 +56,6 @@ bool USDHierarchyIterator::mark_as_weak_export(const Object *object) const
if (params_.selected_objects_only && (object->base_flag & BASE_SELECTED) == 0) {
return true;
}
- if (params_.visible_objects_only && (object->base_flag & BASE_VISIBLE_VIEWLAYER) == 0) {
- return true;
- }
return false;
}
diff --git a/source/blender/usd/usd.h b/source/blender/usd/usd.h
index 1a6f5819e21..8a5575d53cf 100644
--- a/source/blender/usd/usd.h
+++ b/source/blender/usd/usd.h
@@ -36,7 +36,6 @@ struct USDExportParams {
bool export_normals;
bool export_materials;
bool selected_objects_only;
- bool visible_objects_only;
bool use_instancing;
enum eEvaluationMode evaluation_mode;
};
@@ -55,6 +54,8 @@ bool USD_export(struct bContext *C,
const struct USDExportParams *params,
bool as_background_job);
+int USD_get_version(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index ab87f81dba5..e7a4ca9a005 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
intern/wm_cursors.c
intern/wm_dragdrop.c
intern/wm_draw.c
+ intern/wm_event_query.c
intern/wm_event_system.c
intern/wm_files.c
intern/wm_files_link.c
@@ -122,6 +123,10 @@ if(WITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${AUDASPACE_C_LIBRARIES}
+ ${AUDASPACE_PY_LIBRARIES}
+ )
endif()
add_definitions(${GL_DEFINITIONS})
@@ -138,6 +143,9 @@ if(WITH_CODEC_FFMPEG)
list(APPEND INC_SYS
${FFMPEG_INCLUDE_DIRS}
)
+ list(APPEND LIB
+ ${FFMPEG_LIBRARIES}
+ )
add_definitions(-DWITH_FFMPEG)
endif()
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index d24157a22a6..cfdb15026fd 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -205,11 +205,6 @@ void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *ar);
void WM_cursor_warp(struct wmWindow *win, int x, int y);
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
-float WM_cursor_pressure(const struct wmWindow *win);
-
-/* event map */
-int WM_userdef_event_map(int kmitype);
-int WM_userdef_event_type_from_keymap_type(int kmitype);
/* handlers */
@@ -250,6 +245,11 @@ wmKeyMapItem *WM_event_match_keymap_item(struct bContext *C,
wmKeyMap *keymap,
const struct wmEvent *event);
+wmKeyMapItem *WM_event_match_keymap_item_from_handlers(struct bContext *C,
+ struct wmWindowManager *wm,
+ struct ListBase *handlers,
+ const struct wmEvent *event);
+
typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata);
typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
@@ -294,8 +294,6 @@ struct wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers,
/* mouse */
void WM_event_add_mousemove(const struct bContext *C);
-bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
-bool WM_event_is_last_mousemove(const struct wmEvent *event);
#ifdef WITH_INPUT_NDOF
/* 3D mouse */
@@ -631,15 +629,9 @@ bool WM_gesture_is_modal_first(const struct wmGesture *gesture);
/* fileselecting support */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
-int WM_event_modifier_flag(const struct wmEvent *event);
-void WM_event_print(const struct wmEvent *event);
void WM_operator_region_active_win_set(struct bContext *C);
-int WM_event_drag_threshold(const struct wmEvent *event);
-bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
-bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
-
/* drag and drop */
struct wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
@@ -783,6 +775,36 @@ bool write_crash_blend(void);
/* Lock the interface for any communication */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
+/* For testing only 'G_FLAG_EVENT_SIMULATE' */
+struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
+
+const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
+ int button_index,
+ int type_index);
+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);
+bool WM_window_modal_keymap_status_draw(struct bContext *C,
+ struct wmWindow *win,
+ struct uiLayout *layout);
+
+/* wm_event_query.c */
+void WM_event_print(const struct wmEvent *event);
+
+int WM_event_modifier_flag(const struct wmEvent *event);
+
+bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
+bool WM_event_is_last_mousemove(const struct wmEvent *event);
+
+int WM_event_drag_threshold(const struct wmEvent *event);
+bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
+bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
+
+/* event map */
+int WM_userdef_event_map(int kmitype);
+int WM_userdef_event_type_from_keymap_type(int kmitype);
+
#ifdef WITH_INPUT_NDOF
void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof,
float r_pan[3],
@@ -800,20 +822,6 @@ bool WM_event_is_tablet(const struct wmEvent *event);
bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
-/* For testing only 'G_FLAG_EVENT_SIMULATE' */
-struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
-
-const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
- int button_index,
- int type_index);
-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);
-bool WM_window_modal_keymap_status_draw(struct bContext *C,
- struct wmWindow *win,
- struct uiLayout *layout);
-
/* wm_tooltip.c */
typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
struct ARegion *ar,
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 4a9a9cf8705..16c072afccf 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -55,8 +55,6 @@ void WM_keyconfig_update_operatortype(void);
void WM_keymap_clear(struct wmKeyMap *keymap);
-wmKeyMapItem *WM_keymap_verify_item(
- struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_item(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src);
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index 620150ba14f..36cb5be7547 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -41,8 +41,8 @@ struct wmOperatorType;
/* wm_toolsystem.c */
-#define WM_TOOLSYSTEM_SPACE_MASK ((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D))
-
+#define WM_TOOLSYSTEM_SPACE_MASK \
+ ((1 << SPACE_IMAGE) | (1 << SPACE_NODE) | (1 << SPACE_VIEW3D) | (1 << SPACE_SEQ))
/* Values that define a categoey of active tool. */
typedef struct bToolKey {
int space_type;
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 0c3a5f92113..5870802d02b 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -505,6 +505,19 @@ typedef struct wmGesture {
/* ************** wmEvent ************************ */
+typedef struct wmTabletData {
+ /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
+ int active;
+ /** range 0.0 (not touching) to 1.0 (full pressure). */
+ float pressure;
+ /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */
+ float x_tilt;
+ /** as above. */
+ float y_tilt;
+ /** Interpret mouse motion as absolute as typical for tablets. */
+ char is_motion_absolute;
+} wmTabletData;
+
/**
* Each event should have full modifier state.
* event comes from event manager and from keymap.
@@ -546,13 +559,9 @@ typedef struct wmEvent {
/** Set in case a #KM_PRESS went by unhandled. */
char check_click;
char check_drag;
- char is_motion_absolute;
- /** Keymap item, set by handler (weak?). */
- const char *keymap_idname;
-
- /** Tablet info, only use when the tablet is active. */
- const struct wmTabletData *tablet_data;
+ /** Tablet info, available for mouse move and button events. */
+ wmTabletData tablet;
/* custom data */
/** Custom data type, stylus, 6dof, see wm_event_types.h */
@@ -580,18 +589,6 @@ bool WM_event_cursor_click_drag_threshold_met(const wmEvent *event);
*/
#define WM_EVENT_CURSOR_MOTION_THRESHOLD ((float)U.move_threshold * U.dpi_fac)
-/* ************** custom wmEvent data ************** */
-typedef struct wmTabletData {
- /** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
- int Active;
- /** range 0.0 (not touching) to 1.0 (full pressure). */
- float Pressure;
- /** range 0.0 (upright) to 1.0 (tilted fully against the tablet surface). */
- float Xtilt;
- /** as above. */
- float Ytilt;
-} wmTabletData;
-
/** Motion progress, for modal handlers. */
typedef enum {
P_NOT_STARTED,
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index c2fbaaaa83c..7b07546f668 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -236,6 +236,10 @@ void WM_gizmo_target_property_subscribe_all(struct wmGizmo *gz,
struct wmMsgBus *mbus,
struct ARegion *ar);
+void WM_gizmo_target_property_anim_autokey(struct bContext *C,
+ const struct wmGizmo *gz,
+ struct wmGizmoProperty *gz_prop);
+
/* -------------------------------------------------------------------- */
/* wmGizmoGroup */
@@ -285,7 +289,8 @@ eWM_GizmoFlagMapDrawStep WM_gizmomap_drawstep_from_gizmo_group(const struct wmGi
void WM_gizmomap_tag_refresh_drawstep(struct wmGizmoMap *gzmap,
const eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_tag_refresh(struct wmGizmoMap *gzmap);
-bool WM_gizmomap_tag_refresh_check(struct wmGizmoMap *gzmap);
+
+bool WM_gizmomap_tag_delay_refresh_for_tweak_check(struct wmGizmoMap *gzmap);
void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
const struct bContext *C,
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index a8ca65a8a83..e2fb4dc3e0e 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -503,9 +503,6 @@ void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C)
/* Exclude matrix_offset from scale. */
scale *= ED_view3d_pixel_size_no_ui_scale(rv3d, matrix_world[3]);
}
- else {
- scale *= 0.02f;
- }
}
gz->scale_final = gz->scale_basis * scale;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index 73bee883cf8..14657bfa6bd 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -33,6 +33,7 @@
#include "BLI_buffer.h"
#include "BLI_listbase.h"
+#include "BLI_rect.h"
#include "BLI_string.h"
#include "BKE_context.h"
@@ -1154,7 +1155,10 @@ void WM_gizmo_group_refresh(const bContext *C, wmGizmoGroup *gzgroup)
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
if (!gz || gz->parent_gzgroup != gzgroup) {
wmWindow *win = CTX_wm_window(C);
- if (win->tweak) {
+ ARegion *ar = CTX_wm_region(C);
+ BLI_assert(ar->gizmo_map == gzmap);
+ /* Check if the tweak event originated from this region. */
+ if ((win->tweak != NULL) && BLI_rcti_compare(&ar->winrct, &win->tweak->winrct)) {
/* We need to run refresh again. */
gzgroup->init_flag &= ~WM_GIZMOGROUP_INIT_REFRESH;
WM_gizmomap_tag_refresh_drawstep(gzmap, WM_gizmomap_drawstep_from_gizmo_group(gzgroup));
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index c3dfdd9a419..383ca806d35 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -333,13 +333,11 @@ void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
}
}
-bool WM_gizmomap_tag_refresh_check(wmGizmoMap *gzmap)
+bool WM_gizmomap_tag_delay_refresh_for_tweak_check(wmGizmoMap *gzmap)
{
- if (gzmap) {
- for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
- if (gzmap->update_flag[i] & (GIZMOMAP_IS_PREPARE_DRAW | GIZMOMAP_IS_REFRESH_CALLBACK)) {
- return true;
- }
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ if (gzgroup->hide.delay_refresh_for_tweak) {
+ return true;
}
}
return false;
@@ -1090,7 +1088,7 @@ void wm_gizmomap_modal_set(
gz->state |= WM_GIZMO_STATE_MODAL;
gzmap->gzmap_context.modal = gz;
- if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->is_motion_absolute == false)) {
+ if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->tablet.is_motion_absolute == false)) {
WM_cursor_grab_enable(win, WM_CURSOR_WRAP_XY, true, NULL);
copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x);
gzmap->gzmap_context.event_grabcursor = win->grabcursor;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index 094fdf3f514..8acdf2de86f 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -33,6 +33,7 @@
#include "wm.h"
+#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -357,4 +358,19 @@ void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus,
}
}
+/**
+ * Auto-key function if auto-key is enabled.
+ */
+void WM_gizmo_target_property_anim_autokey(bContext *C,
+ const wmGizmo *UNUSED(gz),
+ wmGizmoProperty *gz_prop)
+{
+ if (gz_prop->prop != NULL) {
+ Scene *scene = CTX_data_scene(C);
+ const float cfra = (float)CFRA;
+ const int index = gz_prop->index == -1 ? 0 : gz_prop->index;
+ ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra);
+ }
+}
+
/** \} */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 77e17ad4687..454239e5cf0 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -275,6 +275,11 @@ void WM_check(bContext *C)
return;
}
+ /* Run before loading the keyconfig. */
+ if (wm->message_bus == NULL) {
+ wm->message_bus = WM_msgbus_create();
+ }
+
if (!G.background) {
/* case: fileread */
if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
@@ -286,10 +291,6 @@ void WM_check(bContext *C)
wm_window_ghostwindows_ensure(wm);
}
- if (wm->message_bus == NULL) {
- wm->message_bus = WM_msgbus_create();
- }
-
/* case: fileread */
/* note: this runs in bg mode to set the screen context cb */
if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 8e796a7981a..b82865a727d 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -304,8 +304,7 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
if ((G.debug & G_DEBUG) == 0) {
if (win->ghostwin) {
- /* Note: There is no tabletdata on Windows if no tablet device is connected. */
- if (win->eventstate->is_motion_absolute == false) {
+ if (win->eventstate->tablet.is_motion_absolute == false) {
GHOST_SetCursorGrab(win->ghostwin, mode, mode_axis, bounds, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 09b7d89fc2b..a26a728461d 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -514,12 +514,12 @@ void wm_draw_region_blend(ARegion *ar, int view, bool blend)
/* Slide vertical panels */
float ofs_x = BLI_rcti_size_x(&ar->winrct) * (1.0f - alpha_easing);
- if (ar->alignment == RGN_ALIGN_RIGHT) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_RIGHT) {
rect_geo.xmin += ofs_x;
rect_tex.xmax *= alpha_easing;
alpha = 1.0f;
}
- else if (ar->alignment == RGN_ALIGN_LEFT) {
+ else if (RGN_ALIGN_ENUM_FROM_MASK(ar->alignment) == RGN_ALIGN_LEFT) {
rect_geo.xmax -= ofs_x;
rect_tex.xmin += 1.0f - alpha_easing;
alpha = 1.0f;
@@ -581,7 +581,14 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
/* Compute UI layouts for dynamically size regions. */
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->visible && ar->do_draw && ar->type && ar->type->layout) {
+ /* 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). */
+ const bool ignore_visibility = (ar->flag & RGN_FLAG_DYNAMIC_SIZE) &&
+ (ar->flag & RGN_FLAG_TOO_SMALL) &&
+ !(ar->flag & RGN_FLAG_HIDDEN);
+
+ if ((ar->visible || ignore_visibility) && ar->do_draw && ar->type && ar->type->layout) {
CTX_wm_region_set(C, ar);
ED_region_do_layout(C, ar);
CTX_wm_region_set(C, NULL);
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
new file mode 100644
index 00000000000..3cec185fd36
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -0,0 +1,427 @@
+/*
+ * 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) 2007 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * Read-only queries utility functions for the event system.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DNA_listBase.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_event_system.h"
+#include "wm_event_types.h"
+
+#include "RNA_enum_types.h"
+
+#include "DEG_depsgraph.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Event Printing
+ * \{ */
+
+/* for debugging only, getting inspecting events manually is tedious */
+void WM_event_print(const wmEvent *event)
+{
+ if (event) {
+ const char *unknown = "UNKNOWN";
+ const char *type_id = unknown;
+ const char *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);
+
+ printf(
+ "wmEvent type:%d / %s, val:%d / %s,\n"
+ " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
+ " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
+ event->type,
+ type_id,
+ event->val,
+ val_id,
+ event->shift,
+ event->ctrl,
+ event->alt,
+ event->oskey,
+ event->keymodifier,
+ event->x,
+ event->y,
+ event->ascii,
+ BLI_str_utf8_size(event->utf8_buf),
+ event->utf8_buf,
+ (const void *)event);
+
+#ifdef WITH_INPUT_NDOF
+ if (ISNDOF(event->type)) {
+ const wmNDOFMotionData *ndof = event->customdata;
+ if (event->type == NDOF_MOTION) {
+ printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
+ UNPACK3(ndof->rvec),
+ UNPACK3(ndof->tvec),
+ ndof->dt,
+ ndof->progress);
+ }
+ else {
+ /* ndof buttons printed already */
+ }
+ }
+#endif /* WITH_INPUT_NDOF */
+
+ if (event->tablet.active != EVT_TABLET_NONE) {
+ const wmTabletData *wmtab = &event->tablet;
+ printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
+ wmtab->active,
+ wmtab->pressure,
+ wmtab->x_tilt,
+ wmtab->y_tilt);
+ }
+ }
+ else {
+ printf("wmEvent - NULL\n");
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Modifier/Type Queries
+ * \{ */
+
+int WM_event_modifier_flag(const wmEvent *event)
+{
+ int flag = 0;
+ if (event->ctrl) {
+ flag |= KM_CTRL;
+ }
+ if (event->alt) {
+ flag |= KM_ALT;
+ }
+ if (event->shift) {
+ flag |= KM_SHIFT;
+ }
+ if (event->oskey) {
+ flag |= KM_OSKEY;
+ }
+ return flag;
+}
+
+bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask)
+{
+ /* Keyboard. */
+ if (mask & EVT_TYPE_MASK_KEYBOARD) {
+ if (ISKEYBOARD(event_type)) {
+ return true;
+ }
+ }
+ else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) {
+ if (ISKEYMODIFIER(event_type)) {
+ return true;
+ }
+ }
+
+ /* Mouse. */
+ if (mask & EVT_TYPE_MASK_MOUSE) {
+ if (ISMOUSE(event_type)) {
+ return true;
+ }
+ }
+ else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) {
+ if (ISMOUSE_WHEEL(event_type)) {
+ return true;
+ }
+ }
+ else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) {
+ if (ISMOUSE_GESTURE(event_type)) {
+ return true;
+ }
+ }
+
+ /* Tweak. */
+ if (mask & EVT_TYPE_MASK_TWEAK) {
+ if (ISTWEAK(event_type)) {
+ return true;
+ }
+ }
+
+ /* Action Zone. */
+ if (mask & EVT_TYPE_MASK_ACTIONZONE) {
+ if (IS_EVENT_ACTIONZONE(event_type)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Motion Queries
+ * \{ */
+
+/* for modal callbacks, check configuration for how to interpret exit with tweaks */
+bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
+{
+ /* if the release-confirm userpref setting is enabled,
+ * tweak events can be canceled when mouse is released
+ */
+ if (U.flag & USER_RELEASECONFIRM) {
+ /* option on, so can exit with km-release */
+ if (event->val == KM_RELEASE) {
+ switch (tweak_event) {
+ case EVT_TWEAK_L:
+ case EVT_TWEAK_M:
+ case EVT_TWEAK_R:
+ return 1;
+ }
+ }
+ else {
+ /* if the initial event wasn't a tweak event then
+ * ignore USER_RELEASECONFIRM setting: see [#26756] */
+ if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
+ return 1;
+ }
+ }
+ }
+ else {
+ /* this is fine as long as not doing km-release, otherwise
+ * some items (i.e. markers) being tweaked may end up getting
+ * dropped all over
+ */
+ if (event->val != KM_RELEASE) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+bool WM_event_is_last_mousemove(const wmEvent *event)
+{
+ while ((event = event->next)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Click/Drag Checks
+ *
+ * Values under this limit are detected as clicks.
+ *
+ * \{ */
+
+int WM_event_drag_threshold(const struct wmEvent *event)
+{
+ int drag_threshold;
+ if (WM_event_is_tablet(event)) {
+ drag_threshold = U.drag_threshold_tablet;
+ }
+ else if (ISMOUSE(event->prevtype)) {
+ drag_threshold = U.drag_threshold_mouse;
+ }
+ else {
+ /* Typically keyboard, could be NDOF button or other less common types. */
+ drag_threshold = U.drag_threshold;
+ }
+ return drag_threshold * U.dpi_fac;
+}
+
+bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2])
+{
+ const int drag_threshold = WM_event_drag_threshold(event);
+ return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold;
+}
+
+bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
+{
+ const int drag_delta[2] = {
+ prev_xy[0] - event->x,
+ prev_xy[1] - event->y,
+ };
+ return WM_event_drag_test_with_delta(event, drag_delta);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Preference Mapping
+ * \{ */
+
+int WM_userdef_event_map(int kmitype)
+{
+ switch (kmitype) {
+ case WHEELOUTMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
+ case WHEELINMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
+ }
+
+ return kmitype;
+}
+
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
+int WM_userdef_event_type_from_keymap_type(int kmitype)
+{
+ switch (kmitype) {
+ case EVT_TWEAK_L:
+ return LEFTMOUSE;
+ case EVT_TWEAK_M:
+ return MIDDLEMOUSE;
+ case EVT_TWEAK_R:
+ return RIGHTMOUSE;
+ case WHEELOUTMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
+ case WHEELINMOUSE:
+ return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
+ }
+
+ return kmitype;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event NDOF Input Access
+ * \{ */
+
+#ifdef WITH_INPUT_NDOF
+
+void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom)
+{
+ int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS;
+ r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f);
+}
+
+void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3])
+{
+ r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
+ r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
+}
+
+float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
+{
+ float angle;
+ angle = normalize_v3_v3(axis, ndof->rvec);
+
+ axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
+ axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
+ axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
+
+ return ndof->dt * angle;
+}
+
+void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
+{
+ float axis[3];
+ float angle;
+
+ angle = WM_event_ndof_to_axis_angle(ndof, axis);
+ axis_angle_to_quat(q, axis, angle);
+}
+#endif /* WITH_INPUT_NDOF */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Tablet Input Access
+ * \{ */
+
+/* applies the global tablet pressure correction curve */
+float wm_pressure_curve(float pressure)
+{
+ if (U.pressure_threshold_max != 0.0f) {
+ pressure /= U.pressure_threshold_max;
+ }
+
+ CLAMP(pressure, 0.0f, 1.0f);
+
+ if (U.pressure_softness != 0.0f) {
+ pressure = powf(pressure, powf(4.0f, -U.pressure_softness));
+ }
+
+ return pressure;
+}
+
+/* if this is a tablet event, return tablet pressure and set *pen_flip
+ * to 1 if the eraser tool is being used, 0 otherwise */
+float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
+{
+ if (tilt) {
+ tilt[0] = event->tablet.x_tilt;
+ tilt[1] = event->tablet.y_tilt;
+ }
+
+ if (pen_flip) {
+ (*pen_flip) = (event->tablet.active == EVT_TABLET_ERASER);
+ }
+
+ return event->tablet.pressure;
+}
+
+bool WM_event_is_tablet(const struct wmEvent *event)
+{
+ return (event->tablet.active != EVT_TABLET_NONE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event IME Input Access
+ * \{ */
+
+#ifdef WITH_INPUT_IME
+/* most os using ctrl/oskey + space to switch ime, avoid added space */
+bool WM_event_is_ime_switch(const struct wmEvent *event)
+{
+ return event->val == KM_PRESS && event->type == SPACEKEY &&
+ (event->ctrl || event->oskey || event->shift || event->alt);
+}
+#endif
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 77d59dd3a8f..7339f463855 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -70,7 +70,6 @@
#include "RNA_access.h"
#include "UI_interface.h"
-#include "UI_view2d.h"
#include "PIL_time.h"
@@ -84,8 +83,6 @@
#include "wm_event_system.h"
#include "wm_event_types.h"
-#include "RNA_enum_types.h"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -104,7 +101,6 @@
#define USE_GIZMO_MOUSE_PRIORITY_HACK
static void wm_notifier_clear(wmNotifier *note);
-static void update_tablet_data(wmWindow *win, wmEvent *event);
static int wm_operator_call_internal(bContext *C,
wmOperatorType *ot,
@@ -114,7 +110,11 @@ static int wm_operator_call_internal(bContext *C,
const bool poll_only,
wmEvent *event);
-/* ************ event management ************** */
+static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot);
+
+/* -------------------------------------------------------------------- */
+/** \name Event Management
+ * \{ */
wmEvent *wm_event_add_ex(wmWindow *win,
const wmEvent *event_to_add,
@@ -124,14 +124,6 @@ wmEvent *wm_event_add_ex(wmWindow *win,
*event = *event_to_add;
- update_tablet_data(win, event);
-
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- /* We could have a preference to support relative tablet motion (we can't detect that). */
- event->is_motion_absolute = ((event->tablet_data != NULL) &&
- (event->tablet_data->Active != GHOST_kTabletModeNone));
- }
-
if (event_to_add_after == NULL) {
BLI_addtail(&win->queue, event);
}
@@ -175,10 +167,6 @@ void wm_event_free(wmEvent *event)
}
}
- if (event->tablet_data) {
- MEM_freeN((void *)event->tablet_data);
- }
-
MEM_freeN(event);
}
@@ -193,13 +181,14 @@ void wm_event_free_all(wmWindow *win)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
{
- /* make sure we don't copy any owned pointers */
- BLI_assert(win->eventstate->tablet_data == NULL);
-
*event = *(win->eventstate);
}
-/* ********************* notifiers, listeners *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Notifiers & Listeners
+ * \{ */
static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, void *reference)
{
@@ -578,7 +567,11 @@ static int wm_event_always_pass(const wmEvent *event)
return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
}
-/* ********************* ui handler ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Handling
+ * \{ */
static int wm_handler_ui_call(bContext *C,
wmEventHandler_UI *handler,
@@ -669,7 +662,87 @@ static void wm_handler_ui_cancel(bContext *C)
}
}
-/* ********************* operators ******************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name WM Reports
+ *
+ * Access to #wmWindowManager.reports
+ * \{ */
+
+/**
+ * Show the report in the info header.
+ */
+void WM_report_banner_show(void)
+{
+ wmWindowManager *wm = G_MAIN->wm.first;
+ ReportList *wm_reports = &wm->reports;
+ ReportTimerInfo *rti;
+
+ /* After adding reports to the global list, reset the report timer. */
+ WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+
+ /* Records time since last report was added */
+ wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
+
+ rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ wm_reports->reporttimer->customdata = rti;
+}
+
+#ifdef WITH_INPUT_NDOF
+void WM_ndof_deadzone_set(float deadzone)
+{
+ GHOST_setNDOFDeadZone(deadzone);
+}
+#endif
+
+static void wm_add_reports(ReportList *reports)
+{
+ /* if the caller owns them, handle this */
+ if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
+ wmWindowManager *wm = G_MAIN->wm.first;
+
+ /* add reports to the global list, otherwise they are not seen */
+ BLI_movelisttolist(&wm->reports.list, &reports->list);
+
+ WM_report_banner_show();
+ }
+}
+
+void WM_report(ReportType type, const char *message)
+{
+ ReportList reports;
+
+ BKE_reports_init(&reports, RPT_STORE);
+ BKE_report(&reports, type, message);
+
+ wm_add_reports(&reports);
+
+ BKE_reports_clear(&reports);
+}
+
+void WM_reportf(ReportType type, const char *format, ...)
+{
+ DynStr *ds;
+ va_list args;
+
+ ds = BLI_dynstr_new();
+ va_start(args, format);
+ BLI_dynstr_vappendf(ds, format, args);
+ va_end(args);
+
+ char *str = BLI_dynstr_get_cstring(ds);
+ WM_report(type, str);
+ MEM_freeN(str);
+
+ BLI_dynstr_free(ds);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Logic
+ * \{ */
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
{
@@ -748,164 +821,6 @@ void WM_operator_region_active_win_set(bContext *C)
}
}
-int WM_event_modifier_flag(const wmEvent *event)
-{
- int flag = 0;
- if (event->ctrl) {
- flag |= KM_CTRL;
- }
- if (event->alt) {
- flag |= KM_ALT;
- }
- if (event->shift) {
- flag |= KM_SHIFT;
- }
- if (event->oskey) {
- flag |= KM_OSKEY;
- }
- return flag;
-}
-
-/* for debugging only, getting inspecting events manually is tedious */
-void WM_event_print(const wmEvent *event)
-{
- if (event) {
- const char *unknown = "UNKNOWN";
- const char *type_id = unknown;
- const char *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);
-
- printf(
- "wmEvent type:%d / %s, val:%d / %s,\n"
- " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
- " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n",
- event->type,
- type_id,
- event->val,
- val_id,
- event->shift,
- event->ctrl,
- event->alt,
- event->oskey,
- event->keymodifier,
- event->x,
- event->y,
- event->ascii,
- BLI_str_utf8_size(event->utf8_buf),
- event->utf8_buf,
- event->keymap_idname,
- (const void *)event);
-
-#ifdef WITH_INPUT_NDOF
- if (ISNDOF(event->type)) {
- const wmNDOFMotionData *ndof = event->customdata;
- if (event->type == NDOF_MOTION) {
- printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
- UNPACK3(ndof->rvec),
- UNPACK3(ndof->tvec),
- ndof->dt,
- ndof->progress);
- }
- else {
- /* ndof buttons printed already */
- }
- }
-#endif /* WITH_INPUT_NDOF */
-
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
- wmtab->Active,
- wmtab->Pressure,
- wmtab->Xtilt,
- wmtab->Ytilt);
- }
- }
- else {
- printf("wmEvent - NULL\n");
- }
-}
-
-/**
- * Show the report in the info header.
- */
-void WM_report_banner_show(void)
-{
- wmWindowManager *wm = G_MAIN->wm.first;
- ReportList *wm_reports = &wm->reports;
- ReportTimerInfo *rti;
-
- /* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
-
- /* Records time since last report was added */
- wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
-
- rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
- wm_reports->reporttimer->customdata = rti;
-}
-
-bool WM_event_is_last_mousemove(const wmEvent *event)
-{
- while ((event = event->next)) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- return false;
- }
- }
- return true;
-}
-
-#ifdef WITH_INPUT_NDOF
-void WM_ndof_deadzone_set(float deadzone)
-{
- GHOST_setNDOFDeadZone(deadzone);
-}
-#endif
-
-static void wm_add_reports(ReportList *reports)
-{
- /* if the caller owns them, handle this */
- if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
- wmWindowManager *wm = G_MAIN->wm.first;
-
- /* add reports to the global list, otherwise they are not seen */
- BLI_movelisttolist(&wm->reports.list, &reports->list);
-
- WM_report_banner_show();
- }
-}
-
-void WM_report(ReportType type, const char *message)
-{
- ReportList reports;
-
- BKE_reports_init(&reports, RPT_STORE);
- BKE_report(&reports, type, message);
-
- wm_add_reports(&reports);
-
- BKE_reports_clear(&reports);
-}
-
-void WM_reportf(ReportType type, const char *format, ...)
-{
- DynStr *ds;
- va_list args;
-
- ds = BLI_dynstr_new();
- va_start(args, format);
- BLI_dynstr_vappendf(ds, format, args);
- va_end(args);
-
- char *str = BLI_dynstr_get_cstring(ds);
- WM_report(type, str);
- MEM_freeN(str);
-
- BLI_dynstr_free(ds);
-}
-
/* (caller_owns_reports == true) when called from python */
static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
{
@@ -1287,105 +1202,6 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
}
}
-#if 1 /* may want to disable operator remembering previous state for testing */
-
-static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties)
-{
- bool changed = false;
- IDPropertyTemplate val = {0};
- IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
- PropertyRNA *iterprop;
-
- CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
-
- iterprop = RNA_struct_iterator_property(op->type->srna);
-
- RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
- PropertyRNA *prop = itemptr.data;
- if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
- if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
- const char *identifier = RNA_property_identifier(prop);
- IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier);
- if (idp_src) {
- IDProperty *idp_dst = IDP_CopyProperty(idp_src);
-
- /* note - in the future this may need to be done recursively,
- * but for now RNA doesn't access nested operators */
- idp_dst->flag |= IDP_FLAG_GHOST;
-
- /* add to temporary group instead of immediate replace,
- * because we are iterating over this group */
- IDP_AddToGroup(replaceprops, idp_dst);
- changed = true;
- }
- }
- }
- }
- RNA_PROP_END;
-
- IDP_MergeGroup(op->properties, replaceprops, true);
- IDP_FreeProperty(replaceprops);
- return changed;
-}
-
-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) {
- IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname);
- if (idp_src) {
- changed |= operator_last_properties_init_impl(opm, idp_src);
- }
- }
- }
- return changed;
-}
-
-bool WM_operator_last_properties_store(wmOperator *op)
-{
- if (op->type->last_properties) {
- IDP_FreeProperty(op->type->last_properties);
- op->type->last_properties = NULL;
- }
-
- if (op->properties) {
- CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
- op->type->last_properties = IDP_CopyProperty(op->properties);
- }
-
- if (op->macro.first != NULL) {
- for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
- if (opm->properties) {
- if (op->type->last_properties == NULL) {
- op->type->last_properties = IDP_New(
- IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties");
- }
- IDProperty *idp_macro = IDP_CopyProperty(opm->properties);
- STRNCPY(idp_macro->name, opm->idname);
- IDP_ReplaceInGroup(op->type->last_properties, idp_macro);
- }
- }
- }
-
- return (op->type->last_properties != NULL);
-}
-
-#else
-
-bool WM_operator_last_properties_init(wmOperator *UNUSED(op))
-{
- return false;
-}
-
-bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
-{
- return false;
-}
-
-#endif
-
/**
* Also used for exec when 'event' is NULL.
*/
@@ -1794,7 +1610,13 @@ int WM_operator_call_py(bContext *C,
return retval;
}
-/* ********************* handlers *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Handler Types
+ *
+ * General API for different handler types.
+ * \{ */
/* future extra customadata free? */
void wm_event_free_handler(wmEventHandler *handler)
@@ -1934,42 +1756,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
}
}
-/* do userdef mappings */
-int WM_userdef_event_map(int kmitype)
-{
- switch (kmitype) {
- case WHEELOUTMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
- case WHEELINMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
- }
-
- return kmitype;
-}
-
-/**
- * Use so we can check if 'wmEvent.type' is released in modal operators.
- *
- * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
- */
-int WM_userdef_event_type_from_keymap_type(int kmitype)
-{
- switch (kmitype) {
- case EVT_TWEAK_L:
- return LEFTMOUSE;
- case EVT_TWEAK_M:
- return MIDDLEMOUSE;
- case EVT_TWEAK_R:
- return RIGHTMOUSE;
- case WHEELOUTMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
- case WHEELINMOUSE:
- return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
- }
-
- return kmitype;
-}
-
static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
{
if (kmi->flag & KMI_INACTIVE) {
@@ -1991,19 +1777,16 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
if (kmitype != KM_ANY) {
if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
- const wmTabletData *wmtab = winevent->tablet_data;
+ const wmTabletData *wmtab = &winevent->tablet;
- if (wmtab == NULL) {
- return false;
- }
- else if (winevent->type != LEFTMOUSE) {
+ if (winevent->type != LEFTMOUSE) {
/* tablet events can occur on hover + keypress */
return false;
}
- else if ((kmitype == TABLET_STYLUS) && (wmtab->Active != EVT_TABLET_STYLUS)) {
+ else if ((kmitype == TABLET_STYLUS) && (wmtab->active != EVT_TABLET_STYLUS)) {
return false;
}
- else if ((kmitype == TABLET_ERASER) && (wmtab->Active != EVT_TABLET_ERASER)) {
+ else if ((kmitype == TABLET_ERASER) && (wmtab->active != EVT_TABLET_ERASER)) {
return false;
}
}
@@ -2073,12 +1856,23 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
return NULL;
}
-/* operator exists */
-static void wm_event_modalkeymap(const bContext *C,
- wmOperator *op,
- wmEvent *event,
- bool *dbl_click_disabled)
+/**
+ * This function prepares events for use with #wmOperatorType.modal by:
+ *
+ * - Matching keymap items with the operators modal keymap.
+ * - Converting double click events into press events,
+ * allowing them to be restored when the events aren't handled.
+ *
+ * This is done since we only want to use double click events to match key-map items,
+ * allowing modal functions to check for press/release events without having to interpret them.
+ */
+static void wm_event_modalkeymap_begin(const bContext *C,
+ wmOperator *op,
+ wmEvent *event,
+ bool *dbl_click_disabled)
{
+ BLI_assert(event->type != EVT_MODAL_MAP);
+
/* support for modal keymap in macros */
if (op->opm) {
op = op->opm;
@@ -2107,12 +1901,19 @@ static void wm_event_modalkeymap(const bContext *C,
event->prevval = event_match->val;
event->type = EVT_MODAL_MAP;
event->val = kmi->propvalue;
+
+ /* Avoid double-click events even in the case of 'EVT_MODAL_MAP',
+ * since it's possible users configure double-click keymap items
+ * which would break when modal functions expect press/release. */
+ if (event->prevtype == KM_DBL_CLICK) {
+ event->prevtype = KM_PRESS;
+ *dbl_click_disabled = true;
+ }
}
}
- else {
- /* modal keymap checking returns handled events fine, but all hardcoded modal
- * handling typically swallows all events (OPERATOR_RUNNING_MODAL).
- * This bypass just disables support for double clicks in hardcoded modal handlers */
+
+ if (event->type != EVT_MODAL_MAP) {
+ /* This bypass just disables support for double-click in modal handlers. */
if (event->val == KM_DBL_CLICK) {
event->val = KM_PRESS;
*dbl_click_disabled = true;
@@ -2121,25 +1922,13 @@ static void wm_event_modalkeymap(const bContext *C,
}
/**
- * Check whether operator is allowed to run in case interface is locked,
- * If interface is unlocked, will always return truth.
+ * Restore changes from #wm_event_modalkeymap_begin
+ *
+ * \warning bad hacking event system...
+ * better restore event type for checking of #KM_CLICK for example.
+ * Modal maps could use different method (ton).
*/
-static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
-
- if (wm->is_interface_locked) {
- if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
- return false;
- }
- }
-
- return true;
-}
-
-/* bad hacking event system... better restore event type for checking of KM_CLICK for example */
-/* XXX modal maps could use different method (ton) */
-static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled)
+static void wm_event_modalkeymap_end(wmEvent *event, bool dbl_click_disabled)
{
if (event->type == EVT_MODAL_MAP) {
event->type = event->prevtype;
@@ -2147,7 +1936,8 @@ static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled)
event->val = event->prevval;
event->prevval = 0;
}
- else if (dbl_click_disabled) {
+
+ if (dbl_click_disabled) {
event->val = KM_DBL_CLICK;
}
}
@@ -2157,7 +1947,8 @@ static int wm_handler_operator_call(bContext *C,
ListBase *handlers,
wmEventHandler *handler_base,
wmEvent *event,
- PointerRNA *properties)
+ PointerRNA *properties,
+ const char *kmi_idname)
{
int retval = OPERATOR_PASS_THROUGH;
@@ -2182,7 +1973,7 @@ static int wm_handler_operator_call(bContext *C,
wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
- wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
+ wm_event_modalkeymap_begin(C, op, event, &dbl_click_disabled);
if (ot->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
@@ -2197,7 +1988,7 @@ static int wm_handler_operator_call(bContext *C,
* the event, operator etc have all been freed. - campbell */
if (CTX_wm_manager(C) == wm) {
- wm_event_modalmap_end(event, dbl_click_disabled);
+ wm_event_modalkeymap_end(event, dbl_click_disabled);
if (ot->flag & OPTYPE_UNDO) {
wm->op_undo_depth--;
@@ -2259,7 +2050,7 @@ static int wm_handler_operator_call(bContext *C,
}
}
else {
- wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0);
if (ot && wm_operator_check_locked_interface(C, ot)) {
bool use_last_properties = true;
@@ -2597,10 +2388,8 @@ static int wm_handlers_do_keymap_with_keymap_handler(
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
- /* weak, but allows interactive callback to not use rawkey */
- event->keymap_idname = kmi->idname;
-
- action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr);
+ action |= wm_handler_operator_call(
+ C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
if (action & WM_HANDLER_BREAK) {
/* not always_pass here, it denotes removed handler_base */
@@ -2654,13 +2443,11 @@ static int wm_handlers_do_keymap_with_gizmo_handler(
if (wm_eventmatch(event, kmi)) {
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
- /* weak, but allows interactive callback to not use rawkey */
- event->keymap_idname = kmi->idname;
-
CTX_wm_gizmo_group_set(C, gzgroup);
/* handler->op is called later, we want keymap op to be triggered here */
- action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr);
+ action |= wm_handler_operator_call(
+ C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
CTX_wm_gizmo_group_set(C, NULL);
@@ -2811,12 +2598,6 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
BLI_assert(gzmap != NULL);
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
- /* Special case, needed so postponed refresh can respond to events,
- * see #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK for details. */
- if (WM_gizmomap_tag_refresh_check(gzmap)) {
- ED_region_tag_redraw(region);
- }
-
if (region->gizmo_map != handler->gizmo_map) {
WM_gizmomap_tag_refresh(handler->gizmo_map);
}
@@ -2957,7 +2738,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
}
else {
- action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL);
+ action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL);
}
}
else {
@@ -3536,7 +3317,11 @@ void wm_event_do_handlers(bContext *C)
WM_gizmoconfig_update(CTX_data_main(C));
}
-/* ********** filesector handling ************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name File Selector Handling
+ * \{ */
void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval)
{
@@ -3633,6 +3418,12 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
WM_event_fileselect_event(wm, op, EVT_FILESELECT_FULL_OPEN);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modal Operator Handling
+ * \{ */
+
#if 0
/* lets not expose struct outside wm? */
static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
@@ -3751,10 +3542,6 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
wmEventHandler_Keymap *handler)
{
- if (!USER_EXPERIMENTAL_TEST(&U, use_tool_fallback)) {
- return NULL;
- }
-
ScrArea *sa = handler->dynamic.user_data;
handler->keymap_tool = NULL;
bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
@@ -4060,92 +3847,11 @@ void WM_event_add_mousemove(const bContext *C)
window->addmousemove = 1;
}
-/* for modal callbacks, check configuration for how to interpret exit with tweaks */
-bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
-{
- /* if the release-confirm userpref setting is enabled,
- * tweak events can be canceled when mouse is released
- */
- if (U.flag & USER_RELEASECONFIRM) {
- /* option on, so can exit with km-release */
- if (event->val == KM_RELEASE) {
- switch (tweak_event) {
- case EVT_TWEAK_L:
- case EVT_TWEAK_M:
- case EVT_TWEAK_R:
- return 1;
- }
- }
- else {
- /* if the initial event wasn't a tweak event then
- * ignore USER_RELEASECONFIRM setting: see [#26756] */
- if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
- return 1;
- }
- }
- }
- else {
- /* this is fine as long as not doing km-release, otherwise
- * some items (i.e. markers) being tweaked may end up getting
- * dropped all over
- */
- if (event->val != KM_RELEASE) {
- return 1;
- }
- }
-
- return 0;
-}
-
-bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask)
-{
- /* Keyboard. */
- if (mask & EVT_TYPE_MASK_KEYBOARD) {
- if (ISKEYBOARD(event_type)) {
- return true;
- }
- }
- else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) {
- if (ISKEYMODIFIER(event_type)) {
- return true;
- }
- }
-
- /* Mouse. */
- if (mask & EVT_TYPE_MASK_MOUSE) {
- if (ISMOUSE(event_type)) {
- return true;
- }
- }
- else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) {
- if (ISMOUSE_WHEEL(event_type)) {
- return true;
- }
- }
- else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) {
- if (ISMOUSE_GESTURE(event_type)) {
- return true;
- }
- }
-
- /* Tweak. */
- if (mask & EVT_TYPE_MASK_TWEAK) {
- if (ISTWEAK(event_type)) {
- return true;
- }
- }
-
- /* Action Zone. */
- if (mask & EVT_TYPE_MASK_ACTIONZONE) {
- if (IS_EVENT_ACTIONZONE(event_type)) {
- return true;
- }
- }
-
- return false;
-}
+/** \} */
-/* ********************* ghost stuff *************** */
+/* -------------------------------------------------------------------- */
+/** \name Ghost Event Conversion
+ * \{ */
static int convert_key(GHOST_TKey key)
{
@@ -4158,7 +3864,7 @@ static int convert_key(GHOST_TKey key)
else if (key >= GHOST_kKeyNumpad0 && key <= GHOST_kKeyNumpad9) {
return (PAD0 + ((int)key - GHOST_kKeyNumpad0));
}
- else if (key >= GHOST_kKeyF1 && key <= GHOST_kKeyF19) {
+ else if (key >= GHOST_kKeyF1 && key <= GHOST_kKeyF24) {
return (F1KEY + ((int)key - GHOST_kKeyF1));
}
else {
@@ -4378,41 +4084,23 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
}
}
-/* applies the global tablet pressure correction curve */
-float wm_pressure_curve(float pressure)
-{
- if (U.pressure_threshold_max != 0.0f) {
- pressure /= U.pressure_threshold_max;
- }
-
- CLAMP(pressure, 0.0f, 1.0f);
-
- if (U.pressure_softness != 0.0f) {
- pressure = powf(pressure, powf(4.0f, -U.pressure_softness));
- }
-
- return pressure;
-}
-
-/* adds customdata to event */
-static void update_tablet_data(wmWindow *win, wmEvent *event)
+void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
- const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
-
- /* if there's tablet data from an active tablet device then add it */
- if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
- struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
-
- wmtab->Active = (int)td->Active;
- wmtab->Pressure = wm_pressure_curve(td->Pressure);
- wmtab->Xtilt = td->Xtilt;
- wmtab->Ytilt = td->Ytilt;
-
- event->tablet_data = wmtab;
- // printf("%s: using tablet %.5f\n", __func__, wmtab->Pressure);
+ if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
+ wmtab->active = (int)tablet_data->Active;
+ wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
+ wmtab->x_tilt = tablet_data->Xtilt;
+ wmtab->y_tilt = tablet_data->Ytilt;
+ /* We could have a preference to support relative tablet motion (we can't detect that). */
+ wmtab->is_motion_absolute = true;
+ // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
}
else {
- event->tablet_data = NULL;
+ wmtab->active = EVT_TABLET_NONE;
+ wmtab->pressure = 1.0f;
+ wmtab->x_tilt = 0.0f;
+ wmtab->y_tilt = 0.0f;
+ wmtab->is_motion_absolute = false;
// printf("%s: not using tablet\n", __func__);
}
}
@@ -4564,6 +4252,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
copy_v2_v2_int(&event.x, &cd->x);
wm_stereo3d_mouse_offset_apply(win, &event.x);
+ wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
event.prevtype = event.type;
event.prevval = event.val;
@@ -4571,7 +4260,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
{
wmEvent *event_new = wm_event_add_mousemove(win, &event);
copy_v2_v2_int(&evt->x, &event_new->x);
- evt->is_motion_absolute = event_new->is_motion_absolute;
+ evt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
/* also add to other window if event is there, this makes overdraws disappear nicely */
@@ -4589,7 +4278,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
{
wmEvent *event_new = wm_event_add_mousemove(owin, &oevent);
copy_v2_v2_int(&oevt->x, &event_new->x);
- oevt->is_motion_absolute = event_new->is_motion_absolute;
+ oevt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
}
}
@@ -4603,6 +4292,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
pd->deltaX = -pd->deltaX;
pd->deltaY = -pd->deltaY;
break;
+ case GHOST_kTrackpadEventSmartMagnify:
+ event.type = MOUSESMARTZOOM;
+ break;
case GHOST_kTrackpadEventRotate:
event.type = MOUSEROTATE;
break;
@@ -4653,6 +4345,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.type = MIDDLEMOUSE;
}
+ /* Get tablet data. */
+ wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
+
wm_eventemulation(&event, false);
/* copy previous state to prev event state (two old!) */
@@ -4663,17 +4358,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
evt->val = event.val;
evt->type = event.type;
- if (win->active == 0) {
- int cx, cy;
-
- /* Entering window, update mouse pos.
- * (ghost sends win-activate *after* the mouseclick in window!) */
- wm_get_cursor_position(win, &cx, &cy);
-
- event.x = evt->x = cx;
- event.y = evt->y = cy;
- }
-
/* double click test */
if (wm_event_is_double_click(&event, evt)) {
CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
@@ -4694,6 +4378,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
oevent.y = event.y;
oevent.type = event.type;
oevent.val = event.val;
+ oevent.tablet = event.tablet;
wm_event_add(owin, &oevent);
}
@@ -4960,6 +4645,29 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#endif
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name WM Interface Locking
+ * \{ */
+
+/**
+ * Check whether operator is allowed to run in case interface is locked,
+ * If interface is unlocked, will always return truth.
+ */
+static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ if (wm->is_interface_locked) {
+ if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
{
/* This will prevent events from being handled while interface is locked
@@ -4981,97 +4689,12 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
BKE_spacedata_draw_locks(lock);
}
-#ifdef WITH_INPUT_NDOF
-/* -------------------------------------------------------------------- */
-/* NDOF */
+/** \} */
-/** \name NDOF Utility Functions
+/* -------------------------------------------------------------------- */
+/** \name Event / Keymap Matching API
* \{ */
-void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom)
-{
- int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS;
- r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f);
- r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f);
- r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f);
-}
-
-void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3])
-{
- r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
- r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
- r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
-}
-
-float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
-{
- float angle;
- angle = normalize_v3_v3(axis, ndof->rvec);
-
- axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f);
- axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f);
- axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f);
-
- return ndof->dt * angle;
-}
-
-void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
-{
- float axis[3];
- float angle;
-
- angle = WM_event_ndof_to_axis_angle(ndof, axis);
- axis_angle_to_quat(q, axis, angle);
-}
-#endif /* WITH_INPUT_NDOF */
-
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- * to 1 if the eraser tool is being used, 0 otherwise */
-float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
-{
- int erasor = 0;
- float pressure = 1;
-
- if (tilt) {
- zero_v2(tilt);
- }
-
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
-
- erasor = (wmtab->Active == EVT_TABLET_ERASER);
- if (wmtab->Active != EVT_TABLET_NONE) {
- pressure = wmtab->Pressure;
- if (tilt) {
- tilt[0] = wmtab->Xtilt;
- tilt[1] = wmtab->Ytilt;
- }
- }
- }
-
- if (pen_flip) {
- (*pen_flip) = erasor;
- }
-
- return pressure;
-}
-
-bool WM_event_is_tablet(const struct wmEvent *event)
-{
- return (event->tablet_data) ? true : false;
-}
-
-#ifdef WITH_INPUT_IME
-/* most os using ctrl/oskey + space to switch ime, avoid added space */
-bool WM_event_is_ime_switch(const struct wmEvent *event)
-{
- return event->val == KM_PRESS && event->type == SPACEKEY &&
- (event->ctrl || event->oskey || event->shift || event->alt);
-}
-#endif
-
-/** \} */
-
wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler)
{
wmKeyMap *keymap;
@@ -5099,10 +4722,10 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm
return NULL;
}
-static wmKeyMapItem *wm_kmi_from_event(bContext *C,
- wmWindowManager *wm,
- ListBase *handlers,
- const wmEvent *event)
+wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C,
+ wmWindowManager *wm,
+ ListBase *handlers,
+ const wmEvent *event)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
/* during this loop, ui handlers for nested menus can tag multiple handlers free */
@@ -5125,6 +4748,8 @@ static wmKeyMapItem *wm_kmi_from_event(bContext *C,
return NULL;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Cursor Keymap Status
*
@@ -5337,7 +4962,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wm_eventemulation(&test_event, true);
wmKeyMapItem *kmi = NULL;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- kmi = wm_kmi_from_event(C, wm, handlers[handler_index], &test_event);
+ kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event);
if (kmi) {
break;
}
@@ -5433,43 +5058,3 @@ bool WM_window_modal_keymap_status_draw(bContext *UNUSED(C), wmWindow *win, uiLa
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Event Click/Drag Checks
- *
- * Values under this limit are detected as clicks.
- *
- * \{ */
-
-int WM_event_drag_threshold(const struct wmEvent *event)
-{
- int drag_threshold;
- if (WM_event_is_tablet(event)) {
- drag_threshold = U.drag_threshold_tablet;
- }
- else if (ISMOUSE(event->prevtype)) {
- drag_threshold = U.drag_threshold_mouse;
- }
- else {
- /* Typically keyboard, could be NDOF button or other less common types. */
- drag_threshold = U.drag_threshold;
- }
- return drag_threshold * U.dpi_fac;
-}
-
-bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2])
-{
- const int drag_threshold = WM_event_drag_threshold(event);
- return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold;
-}
-
-bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
-{
- const int drag_delta[2] = {
- prev_xy[0] - event->x,
- prev_xy[1] - event->y,
- };
- return WM_event_drag_test_with_delta(event, drag_delta);
-}
-
-/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index aa74aa81a74..0835f128f51 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1386,7 +1386,7 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
/* don't forget not to return without! */
WM_cursor_wait(1);
- ED_editors_flush_edits(bmain, false);
+ ED_editors_flush_edits(bmain);
fileflags |= G_FILE_HISTORY; /* write file history */
@@ -1527,7 +1527,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
Main *bmain = CTX_data_main(C);
int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
- ED_editors_flush_edits(bmain, false);
+ ED_editors_flush_edits(bmain);
/* Error reporting into console */
BLO_write_file(bmain, filepath, fileflags, NULL, NULL);
@@ -1655,7 +1655,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
printf("Writing homefile: '%s' ", filepath);
- ED_editors_flush_edits(bmain, false);
+ ED_editors_flush_edits(bmain);
/* force save as regular blend file */
fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 5dd67355f54..a5f32b4ff1f 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -466,16 +466,17 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
wmWindow *window = CTX_wm_window(C);
wmGesture *gesture = window->tweak;
rcti *rect = gesture->customdata;
- int val;
+ bool gesture_end = false;
switch (event->type) {
case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE: {
rect->xmax = event->x - gesture->winrct.xmin;
rect->ymax = event->y - gesture->winrct.ymin;
- if ((val = wm_gesture_evaluate(gesture, event))) {
+ const int val = wm_gesture_evaluate(gesture, event);
+ if (val != 0) {
wmEvent tevent;
wm_event_init_from_window(window, &tevent);
@@ -499,16 +500,17 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
* (which may be in the queue already), are handled in order, see T44740 */
wm_event_add_ex(window, &tevent, event);
- WM_gesture_end(C, gesture); /* frees gesture itself, and unregisters from window */
+ gesture_end = true;
}
break;
+ }
case LEFTMOUSE:
case RIGHTMOUSE:
case MIDDLEMOUSE:
if (gesture->event_type == event->type) {
- WM_gesture_end(C, gesture);
+ gesture_end = true;
/* when tweak fails we should give the other keymap entries a chance */
@@ -518,10 +520,24 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
break;
default:
if (!ISTIMER(event->type) && event->type != EVENT_NONE) {
- WM_gesture_end(C, gesture);
+ gesture_end = true;
}
break;
}
+
+ if (gesture_end) {
+ /* Frees gesture itself, and unregisters from window. */
+ WM_gesture_end(C, gesture);
+
+ /* This isn't very nice but needed to redraw gizmos which are hidden while tweaking,
+ * See #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK for details. */
+ ARegion *ar = CTX_wm_region(C);
+ if ((ar != NULL) && (ar->gizmo_map != NULL)) {
+ if (WM_gizmomap_tag_delay_refresh_for_tweak_check(ar->gizmo_map)) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
}
/* standard tweak, called after window handlers passed on event */
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 42433c9f843..2f4abbe20d8 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -499,7 +499,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE);
- has_edited = ED_editors_flush_edits(bmain, false);
+ has_edited = ED_editors_flush_edits(bmain);
if ((has_edited && BLO_write_file(bmain, filename, fileflags, NULL, NULL)) ||
(undo_memfile && BLO_memfile_write_file(undo_memfile, filename))) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 4e7a7bf96f1..1809a233ce1 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -505,31 +505,6 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
}
}
-/* if item was added, then bail out */
-wmKeyMapItem *WM_keymap_verify_item(
- wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
-{
- wmKeyMapItem *kmi;
-
- for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
- if (STREQLEN(kmi->idname, idname, OP_MAX_TYPENAME)) {
- break;
- }
- }
- if (kmi == NULL) {
- kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
-
- BLI_addtail(&keymap->items, kmi);
- BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
-
- keymap_item_set_id(keymap, kmi);
-
- keymap_event_set(kmi, type, val, modifier, keymodifier);
- wm_keymap_item_properties_set(kmi);
- }
- return kmi;
-}
-
/* always add item */
wmKeyMapItem *WM_keymap_add_item(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 2a40fb138c0..4c0b35a65e5 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -157,6 +157,7 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "filter_alembic", (filter & FILE_TYPE_ALEMBIC) != 0, "Filter Alembic files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "filter_usd", (filter & FILE_TYPE_USD) != 0, "Filter USD files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index ce10ea56251..44afa708136 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -26,6 +26,7 @@
#include "BLI_string.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "RNA_access.h"
@@ -147,6 +148,7 @@ static bool interactive_value_update(ValueInteraction *inter,
* \{ */
struct ObCustomData_ForEditMode {
+ int launch_event;
bool wait_for_input;
bool is_active;
bool is_first;
@@ -176,6 +178,8 @@ static void op_generic_value_exit(wmOperator *op)
MEM_freeN(cd->objects_xform);
MEM_freeN(cd);
}
+
+ G.moving &= ~G_TRANSFORM_EDIT;
}
static void op_generic_value_restore(wmOperator *op)
@@ -194,6 +198,10 @@ static void op_generic_value_cancel(bContext *UNUSED(C), wmOperator *op)
static int op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ if (RNA_property_is_set(op->ptr, op->type->prop)) {
+ return WM_operator_call_notest(C, op);
+ }
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -204,6 +212,7 @@ static int op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
struct ObCustomData_ForEditMode *cd = MEM_callocN(sizeof(*cd), __func__);
+ cd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
cd->wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
cd->is_active = !cd->wait_for_input;
cd->is_first = true;
@@ -224,12 +233,23 @@ static int op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *e
op->customdata = cd;
WM_event_add_modal_handler(C, op);
+ G.moving |= G_TRANSFORM_EDIT;
+
return OPERATOR_RUNNING_MODAL;
}
static int op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
struct ObCustomData_ForEditMode *cd = op->customdata;
+
+ /* Special case, check if we release the event that activated this operator. */
+ if ((event->type == cd->launch_event) && (event->val == KM_RELEASE)) {
+ if (cd->wait_for_input == false) {
+ op_generic_value_exit(op);
+ return OPERATOR_FINISHED;
+ }
+ }
+
switch (event->type) {
case MOUSEMOVE:
case LEFTCTRLKEY:
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 61f51de41a5..5837e8e952c 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -720,6 +720,111 @@ void WM_operator_properties_free(PointerRNA *ptr)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Operator Last Properties API
+ * \{ */
+
+#if 1 /* may want to disable operator remembering previous state for testing */
+
+static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties)
+{
+ bool changed = false;
+ IDPropertyTemplate val = {0};
+ IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ PropertyRNA *iterprop;
+
+ CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
+
+ iterprop = RNA_struct_iterator_property(op->type->srna);
+
+ RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
+ PropertyRNA *prop = itemptr.data;
+ if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
+ if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
+ const char *identifier = RNA_property_identifier(prop);
+ IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier);
+ if (idp_src) {
+ IDProperty *idp_dst = IDP_CopyProperty(idp_src);
+
+ /* note - in the future this may need to be done recursively,
+ * but for now RNA doesn't access nested operators */
+ idp_dst->flag |= IDP_FLAG_GHOST;
+
+ /* add to temporary group instead of immediate replace,
+ * because we are iterating over this group */
+ IDP_AddToGroup(replaceprops, idp_dst);
+ changed = true;
+ }
+ }
+ }
+ }
+ RNA_PROP_END;
+
+ IDP_MergeGroup(op->properties, replaceprops, true);
+ IDP_FreeProperty(replaceprops);
+ return changed;
+}
+
+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) {
+ IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname);
+ if (idp_src) {
+ changed |= operator_last_properties_init_impl(opm, idp_src);
+ }
+ }
+ }
+ return changed;
+}
+
+bool WM_operator_last_properties_store(wmOperator *op)
+{
+ if (op->type->last_properties) {
+ IDP_FreeProperty(op->type->last_properties);
+ op->type->last_properties = NULL;
+ }
+
+ if (op->properties) {
+ CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
+ op->type->last_properties = IDP_CopyProperty(op->properties);
+ }
+
+ if (op->macro.first != NULL) {
+ for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
+ if (opm->properties) {
+ if (op->type->last_properties == NULL) {
+ op->type->last_properties = IDP_New(
+ IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties");
+ }
+ IDProperty *idp_macro = IDP_CopyProperty(opm->properties);
+ STRNCPY(idp_macro->name, opm->type->idname);
+ IDP_ReplaceInGroup(op->type->last_properties, idp_macro);
+ }
+ }
+ }
+
+ return (op->type->last_properties != NULL);
+}
+
+#else
+
+bool WM_operator_last_properties_init(wmOperator *UNUSED(op))
+{
+ return false;
+}
+
+bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
+{
+ return false;
+}
+
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Default Operator Callbacks
* \{ */
@@ -1238,15 +1343,17 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, 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, layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
}
else {
uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ 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);
@@ -2209,7 +2316,8 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
short strdrawlen = 0;
float strwidth, strheight;
float r1 = 0.0f, r2 = 0.0f, rmin = 0.0, tex_radius, alpha;
- float zoom[2], col[3] = {1, 1, 1};
+ float zoom[2], col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float text_color[4];
switch (rc->subtype) {
case PROP_NONE:
@@ -2336,6 +2444,8 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
immUnbindProgram();
BLF_size(fontid, 1.75f * fstyle_points * U.pixelsize, U.dpi);
+ UI_GetThemeColor4fv(TH_TEXT_HI, text_color);
+ BLF_color4fv(fontid, text_color);
/* draw value */
BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
@@ -2477,7 +2587,7 @@ static int radial_control_get_properties(bContext *C, wmOperator *op)
}
if (!radial_control_get_path(
- &ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 3, RC_PROP_REQUIRE_FLOAT)) {
+ &ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 4, RC_PROP_REQUIRE_FLOAT)) {
return 0;
}
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index c79f75b5b21..8e49e47c492 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -351,11 +351,11 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
*tref->runtime = *tref_rt;
}
- /* FIXME: ideally Python could check this gizmo group flag and not
+ /* Ideally Python could check this gizmo group flag and not
* pass in the argument to begin with. */
bool use_fallback_keymap = false;
- if (USER_EXPERIMENTAL_TEST(&U, use_tool_fallback)) {
+ if (tref->idname_fallback[0] || tref->runtime->keymap_fallback[0]) {
if (tref_rt->gizmo_group[0]) {
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(tref_rt->gizmo_group, false);
if (gzgt) {
@@ -366,7 +366,7 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
}
}
if (use_fallback_keymap == false) {
- tref->runtime->idname_fallback[0] = '\0';
+ tref->idname_fallback[0] = '\0';
tref->runtime->keymap_fallback[0] = '\0';
}
@@ -487,6 +487,8 @@ static bool toolsystem_key_ensure_check(const bToolKey *tkey)
break;
case SPACE_NODE:
return true;
+ case SPACE_SEQ:
+ return true;
}
return false;
}
@@ -516,6 +518,11 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp
mode = 0;
break;
}
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = sa->spacedata.first;
+ mode = sseq->view;
+ break;
+ }
}
return mode;
}
@@ -736,6 +743,17 @@ static const char *toolsystem_default_tool(const bToolKey *tkey)
case SPACE_NODE: {
return "builtin.select_box";
}
+ case SPACE_SEQ: {
+ switch (tkey->mode) {
+ case SEQ_VIEW_SEQUENCE:
+ return "builtin.select";
+ case SEQ_VIEW_PREVIEW:
+ return "builtin.annotate";
+ case SEQ_VIEW_SEQUENCE_PREVIEW:
+ return "builtin.select";
+ }
+ return "builtin.select_box";
+ }
}
return "builtin.select_box";
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index e68d4902c66..4f70eeefb76 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -395,6 +395,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
if (U.uiflag & USER_SAVE_PROMPT) {
if (wm_file_or_image_is_modified(C) && !G.background) {
+ wm_window_raise(win);
wm_confirm_quit(C);
}
else {
@@ -547,6 +548,12 @@ void WM_window_set_dpi(const wmWindow *win)
BLF_default_dpi(U.pixelsize * U.dpi);
}
+static void wm_window_update_eventstate(wmWindow *win)
+{
+ /* Update mouse position when a window is activated. */
+ wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+}
+
static void wm_window_ensure_eventstate(wmWindow *win)
{
if (win->eventstate) {
@@ -554,7 +561,7 @@ static void wm_window_ensure_eventstate(wmWindow *win)
}
win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
- wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+ wm_window_update_eventstate(win);
}
/* belongs to below */
@@ -702,6 +709,8 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo
/* happens after fileread */
wm_window_ensure_eventstate(win);
+
+ WM_window_set_dpi(win);
}
/* add keymap handlers (1 handler for all keys in map!) */
@@ -1206,7 +1215,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventWindowActivate: {
GHOST_TEventKeyData kdata;
wmEvent event;
- int wx, wy;
const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) |
(query_qual(CONTROL) ? KM_CTRL : 0) |
(query_qual(ALT) ? KM_ALT : 0) | (query_qual(OS) ? KM_OSKEY : 0));
@@ -1291,10 +1299,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->eventstate->keymodifier = 0;
/* entering window, update mouse pos. but no event */
- wm_get_cursor_position(win, &wx, &wy);
-
- win->eventstate->x = wx;
- win->eventstate->y = wy;
+ wm_window_update_eventstate(win);
win->addmousemove = 1; /* enables highlighted buttons */
@@ -1455,12 +1460,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventDraggingDropDone: {
wmEvent event;
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
- int wx, wy;
/* entering window, update mouse pos */
- wm_get_cursor_position(win, &wx, &wy);
- win->eventstate->x = wx;
- win->eventstate->y = wy;
+ wm_window_update_eventstate(win);
wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */
@@ -1542,9 +1544,21 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wm_event_add_ghostevent(wm, win, type, data);
break;
}
- default:
+ case GHOST_kEventButtonDown:
+ case GHOST_kEventButtonUp: {
+ if (win->active == 0) {
+ /* Entering window, update cursor and tablet state.
+ * (ghost sends win-activate *after* the mouse-click in window!) */
+ wm_window_update_eventstate(win);
+ }
+
+ wm_event_add_ghostevent(wm, win, type, data);
+ break;
+ }
+ default: {
wm_event_add_ghostevent(wm, win, type, data);
break;
+ }
}
}
return 1;
@@ -2098,21 +2112,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
}
}
-/**
- * Get the cursor pressure, in most cases you'll want to use wmTabletData from the event
- */
-float WM_cursor_pressure(const struct wmWindow *win)
-{
- const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
- /* if there's tablet data from an active tablet device then add it */
- if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
- return wm_pressure_curve(td->Pressure);
- }
- else {
- return -1.0f;
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -2189,8 +2188,8 @@ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
}
}
- BLI_assert(screen_rect.xmin < screen_rect.xmax);
- BLI_assert(screen_rect.ymin < screen_rect.ymax);
+ BLI_assert(BLI_rcti_is_valid(&screen_rect));
+
*r_rect = screen_rect;
}
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
index 0c2ce9783ec..97ca879736e 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -339,14 +339,14 @@ void WM_msg_subscribe_ID(struct wmMsgBus *mbus,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
- wmMsgParams_RNA msg_key_params = {NULL};
+ wmMsgParams_RNA msg_key_params = {{NULL}};
RNA_id_pointer_create(id, &msg_key_params.ptr);
WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr);
}
void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id)
{
- wmMsgParams_RNA msg_key_params = {NULL};
+ wmMsgParams_RNA msg_key_params = {{NULL}};
RNA_id_pointer_create(id, &msg_key_params.ptr);
WM_msg_publish_rna_params(mbus, &msg_key_params);
}
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index c53ccda170a..97c5980e3e7 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -31,6 +31,7 @@
#define WM_HANDLER_MODAL 4 /* MODAL|BREAK means unhandled */
struct ARegion;
+struct GHOST_TabletData;
struct ScrArea;
/* wmKeyMap is in DNA_windowmanager.h, it's saveable */
@@ -148,7 +149,9 @@ 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);
+/* 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);
/* wm_keymap.c */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 3bd0851d60c..ebb0d7dd878 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -63,6 +63,8 @@ enum {
MOUSEPAN = 0x000e,
MOUSEZOOM = 0x000f,
MOUSEROTATE = 0x0010,
+ MOUSESMARTZOOM = 0x0017,
+
/* defaults from ghost */
WHEELUPMOUSE = 0x000a,
WHEELDOWNMOUSE = 0x000b,
@@ -223,6 +225,11 @@ enum {
F17KEY = 0x013c, /* 316 */
F18KEY = 0x013d, /* 317 */
F19KEY = 0x013e, /* 318 */
+ F20KEY = 0x013f, /* 319 */
+ F21KEY = 0x0140, /* 320 */
+ F22KEY = 0x0141, /* 321 */
+ F23KEY = 0x0142, /* 322 */
+ F24KEY = 0x0143, /* 323 */
/* *** End of keyboard codes. *** */
@@ -347,14 +354,15 @@ enum {
/* test whether the event is a key on the keyboard */
#define ISKEYBOARD(event_type) \
(((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \
- ((event_type) >= 0x012c && (event_type) <= 0x013f))
+ ((event_type) >= 0x012c && (event_type) <= 0x0143))
/* test whether the event is a modifier key */
#define ISKEYMODIFIER(event_type) \
(((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) || (event_type) == OSKEY)
/* test whether the event is a mouse button */
-#define ISMOUSE(event_type) ((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE)
+#define ISMOUSE(event_type) \
+ (((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) || (event_type) == MOUSESMARTZOOM)
#define ISMOUSE_WHEEL(event_type) ((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE)
#define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSEROTATE)