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:
-rw-r--r--CMakeLists.txt17
-rw-r--r--build_files/build_environment/cmake/harvest.cmake6
-rwxr-xr-xbuild_files/build_environment/install_deps.sh175
-rw-r--r--build_files/cmake/platform/platform_unix.cmake4
-rwxr-xr-xbuild_files/package_spec/build_debian.sh43
-rw-r--r--build_files/package_spec/debian/changelog5
-rw-r--r--build_files/package_spec/debian/compat1
-rw-r--r--build_files/package_spec/debian/control24
-rw-r--r--build_files/package_spec/debian/copyright41
-rw-r--r--build_files/package_spec/debian/docs2
-rw-r--r--build_files/package_spec/debian/menu4
-rwxr-xr-xbuild_files/package_spec/debian/rules44
-rw-r--r--build_files/package_spec/debian/source/format1
-rw-r--r--build_files/package_spec/debian/watch3
-rw-r--r--build_files/package_spec/pacman/PKGBUILD66
-rw-r--r--build_files/package_spec/pacman/blender.install29
-rw-r--r--build_files/package_spec/rpm/blender.spec.in88
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--doc/python_api/examples/gpu.5.py3
-rw-r--r--intern/cycles/device/device_optix.cpp4
-rw-r--r--intern/cycles/kernel/shaders/node_ies_light.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_mapping.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_vector_math.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_white_noise_texture.osl12
-rw-r--r--intern/cycles/kernel/svm/svm_white_noise.h68
-rw-r--r--intern/cycles/render/nodes.cpp5
-rw-r--r--intern/cycles/util/util_version.h2
-rw-r--r--intern/ghost/GHOST_IWindow.h6
-rw-r--r--intern/ghost/GHOST_Types.h13
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp2
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp74
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.h2
-rw-r--r--intern/ghost/intern/GHOST_EventButton.h1
-rw-r--r--intern/ghost/intern/GHOST_EventCursor.h1
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp4
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm35
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp4
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp14
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp93
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.h6
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowViewCocoa.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp13
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp78
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h9
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h26
-rw-r--r--intern/guardedalloc/intern/mallocn.c3
-rw-r--r--intern/guardedalloc/intern/mallocn_guarded_impl.c32
-rw-r--r--intern/guardedalloc/intern/mallocn_intern.h2
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c23
-rw-r--r--intern/libmv/CMakeLists.txt2
-rwxr-xr-xintern/libmv/bundle.sh2
-rw-r--r--release/datafiles/bfont.ttfbin191532 -> 194320 bytes
-rw-r--r--release/datafiles/blender_icons.svg104
-rw-r--r--release/datafiles/blender_icons16/icon16_anchor_bottom.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_anchor_center.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_anchor_left.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_anchor_right.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_anchor_top.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_brushes_all.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_folder_redirect.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_handle_aligned.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_handle_auto.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_handle_autoclamped.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_handle_free.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_handle_vector.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_anchor_bottom.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_anchor_center.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_anchor_left.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_anchor_right.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_anchor_top.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_brushes_all.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_folder_redirect.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_handle_aligned.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_handle_auto.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_handle_autoclamped.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_handle_free.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_handle_vector.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/bmonofont.ttfbin309588 -> 314980 bytes
-rw-r--r--release/datafiles/fonts/bmonofont-i18n.ttf.gzbin2623844 -> 2686344 bytes
-rw-r--r--release/datafiles/fonts/droidsans.ttf.gzbin2487589 -> 2436926 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default_theme.c27
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py4
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py4
-rw-r--r--release/scripts/modules/rna_prop_ui.py5
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py62
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py102
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py14
-rw-r--r--release/scripts/startup/bl_ui/properties_data_empty.py32
-rw-r--r--release/scripts/startup/bl_ui/properties_data_light.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py2
-rw-r--r--release/scripts/startup/bl_ui/space_info.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py45
-rw-r--r--release/scripts/startup/bl_ui/space_text.py33
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py10
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py107
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py4
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py61
-rw-r--r--source/blender/alembic/intern/abc_curves.cc2
-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/blenfont/intern/blf.c5
-rw-r--r--source/blender/blenkernel/BKE_animsys.h4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_cloth.h20
-rw-r--r--source/blender/blenkernel/BKE_icons.h5
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h1
-rw-r--r--source/blender/blenkernel/BKE_object.h1
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h1
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c22
-rw-r--r--source/blender/blenkernel/intern/cloth.c118
-rw-r--r--source/blender/blenkernel/intern/collision.c673
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c19
-rw-r--r--source/blender/blenkernel/intern/curve.c137
-rw-r--r--source/blender/blenkernel/intern/icons.c4
-rw-r--r--source/blender/blenkernel/intern/icons_rasterize.c14
-rw-r--r--source/blender/blenkernel/intern/image.c1
-rw-r--r--source/blender/blenkernel/intern/library_query.c2
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c24
-rw-r--r--source/blender/blenkernel/intern/multires.c18
-rw-r--r--source/blender/blenkernel/intern/object.c20
-rw-r--r--source/blender/blenkernel/intern/workspace.c8
-rw-r--r--source/blender/blenlib/BLI_rect.h4
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c3495
-rw-r--r--source/blender/blenlib/intern/rct.c80
-rw-r--r--source/blender/blenloader/intern/readfile.c9
-rw-r--r--source/blender/blenloader/intern/versioning_280.c57
-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/bmesh/tools/bmesh_bevel.c430
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c323
-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/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.cpp4
-rw-r--r--source/blender/collada/collada_utils.cpp21
-rw-r--r--source/blender/collada/collada_utils.h5
-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.cc9
-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.cc166
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h8
-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.cc18
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc309
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-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.cc31
-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.cc24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc44
-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.cc9
-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.cc15
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc133
-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_materials.c32
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c52
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl21
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c3
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c2
-rw-r--r--source/blender/draw/intern/draw_cache.c39
-rw-r--r--source/blender/draw/intern/draw_cache.h10
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h6
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c18
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c82
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c2
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c6
-rw-r--r--source/blender/editors/armature/armature_naming.c1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c10
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c41
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c41
-rw-r--r--source/blender/editors/include/ED_armature.h181
-rw-r--r--source/blender/editors/include/ED_screen.h2
-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_handlers.c40
-rw-r--r--source/blender/editors/interface/interface_icons.c100
-rw-r--r--source/blender/editors/interface/interface_icons_event.c197
-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.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c3
-rw-r--r--source/blender/editors/interface/interface_widgets.c15
-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/mesh/editmesh_automerge.c54
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c2
-rw-r--r--source/blender/editors/object/object_add.c21
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_relations.c6
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/screen/area.c59
-rw-r--r--source/blender/editors/screen/area_query.c12
-rw-r--r--source/blender/editors/screen/screen_ops.c35
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c8
-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.c4
-rw-r--r--source/blender/editors/space_clip/space_clip.c6
-rw-r--r--source/blender/editors/space_console/console_draw.c107
-rw-r--r--source/blender/editors/space_file/filelist.c27
-rw-r--r--source/blender/editors/space_file/fsmenu.c164
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-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_info/info_draw.c153
-rw-r--r--source/blender/editors/space_info/textview.c228
-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_sequencer/sequencer_add.c58
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c6
-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.c8
-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_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.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c2
-rw-r--r--source/blender/editors/transform/transform_draw.c114
-rw-r--r--source/blender/editors/transform/transform_ops.c2
-rw-r--r--source/blender/editors/undo/ed_undo.c34
-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.cpp2
-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/intern/gpu_buffers.c26
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c40
-rw-r--r--source/blender/gpu/intern/gpu_texture.c50
-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_white_noise.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl2
-rw-r--r--source/blender/imbuf/intern/bmp.c157
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp4
-rw-r--r--source/blender/makesdna/DNA_armature_types.h3
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h14
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/DNA_screen_types.h12
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-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/rna_curve.c14
-rw-r--r--source/blender/makesrna/intern/rna_define.c30
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c11
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c15
-rw-r--r--source/blender/makesrna/intern/rna_nla.c3
-rw-r--r--source/blender/makesrna/intern/rna_object.c12
-rw-r--r--source/blender/makesrna/intern/rna_particle.c4
-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.c28
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c66
-rw-r--r--source/blender/makesrna/intern/rna_wm.c4
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c24
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c11
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c4
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c1
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp176
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c3
-rw-r--r--source/blender/usd/CMakeLists.txt1
-rw-r--r--source/blender/usd/intern/usd_capi.cc4
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h62
-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/intern/wm_gizmo_map.c2
-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.c773
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c26
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c105
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c18
-rw-r--r--source/blender/windowmanager/intern/wm_window.c54
-rw-r--r--source/blender/windowmanager/wm_event_system.h3
-rw-r--r--source/blender/windowmanager/wm_event_types.h5
-rw-r--r--source/creator/creator_signals.c11
m---------source/tools0
-rw-r--r--tests/gtests/CMakeLists.txt3
-rw-r--r--tests/gtests/blenlib/BLI_array_store_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_delaunay_2d_test.cc895
-rw-r--r--tests/gtests/blenlib/BLI_ghash_performance_test.cc3
-rw-r--r--tests/gtests/blenlib/BLI_heap_simple_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_heap_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_kdopbvh_test.cc3
-rw-r--r--tests/gtests/blenlib/BLI_listbase_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_memiter_test.cc3
-rw-r--r--tests/gtests/blenlib/BLI_polyfill_2d_test.cc3
-rw-r--r--tests/gtests/blenlib/BLI_task_performance_test.cc4
-rw-r--r--tests/gtests/blenlib/BLI_task_test.cc4
-rw-r--r--tests/gtests/blenloader/CMakeLists.txt4
-rw-r--r--tests/gtests/blenloader/blendfile_loading_base_test.cc4
-rw-r--r--tests/gtests/ffmpeg/CMakeLists.txt44
-rw-r--r--tests/gtests/ffmpeg/ffmpeg_codecs.cc147
-rw-r--r--tests/gtests/guardedalloc/guardedalloc_alignment_test.cc76
-rw-r--r--tests/gtests/usd/CMakeLists.txt4
-rw-r--r--tests/python/CMakeLists.txt27
-rw-r--r--tests/python/bevel_operator.py184
-rw-r--r--tests/python/bl_pyapi_mathutils.py39
-rw-r--r--tests/python/boolean_operator.py68
-rw-r--r--tests/python/modifiers.py236
-rw-r--r--tests/python/modules/mesh_test.py495
-rwxr-xr-xtests/python/modules/test_utils.py1
-rw-r--r--tests/python/operators.py172
394 files changed, 10535 insertions, 6527 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2bac16c339a..bbca47f26c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -980,7 +980,7 @@ if(WITH_GL_PROFILE_ES20)
)
endif()
- list(APPEND BLENDER_GL_LIBRARIES OPENGLES_LIBRARY)
+ list(APPEND BLENDER_GL_LIBRARIES "${OPENGLES_LIBRARY}")
else()
set(OPENGLES_LIBRARY "" CACHE FILEPATH "OpenGL ES 2.0 library file")
@@ -1040,7 +1040,10 @@ else()
endif()
if(WITH_GL_EGL)
- list(APPEND GL_DEFINITIONS -DWITH_GL_EGL)
+ find_package(OpenGL REQUIRED EGL)
+ list(APPEND BLENDER_GL_LIBRARIES OpenGL::EGL)
+
+ list(APPEND GL_DEFINITIONS -DWITH_GL_EGL -DGLEW_EGL -DGLEW_INC_EGL)
if(WITH_SYSTEM_GLES)
if(NOT OPENGLES_EGL_LIBRARY)
@@ -1050,7 +1053,7 @@ if(WITH_GL_EGL)
)
endif()
- list(APPEND BLENDER_GL_LIBRARIES OPENGLES_EGL_LIBRARY)
+ list(APPEND BLENDER_GL_LIBRARIES ${OPENGLES_EGL_LIBRARY})
else()
set(OPENGLES_EGL_LIBRARY "" CACHE FILEPATH "EGL library file")
@@ -1090,10 +1093,6 @@ else()
list(APPEND GL_DEFINITIONS -DWITH_GL_PROFILE_CORE)
endif()
-if(WITH_GL_EGL)
- list(APPEND GL_DEFINITIONS -DWITH_EGL)
-endif()
-
#-----------------------------------------------------------------------------
# Configure OpenMP.
if(WITH_OPENMP)
@@ -1165,10 +1164,6 @@ else()
list(APPEND GL_DEFINITIONS -DGL_ES_VERSION_1_0=0 -DGL_ES_VERSION_CL_1_1=0 -DGL_ES_VERSION_CM_1_1=0)
endif()
- if(WITH_GL_EGL)
- list(APPEND GL_DEFINITIONS -DGLEW_INC_EGL)
- endif()
-
set(BLENDER_GLEW_LIBRARIES extern_glew_es bf_intern_glew_mx)
else()
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index 5b5c254b150..5fb62e330af 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -62,14 +62,8 @@ if(BUILD_MODE STREQUAL Debug)
# OpenImageIO
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_d.lib &&
${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO_Util.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_Util_d.lib &&
- # python
- ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/python/ ${HARVEST_TARGET}/python/ &&
# hdf5
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hdf5/lib ${HARVEST_TARGET}/hdf5/lib &&
- # numpy
- ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}d.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_numpy_${NUMPY_SHORT_VERSION}d.tar.gz &&
- # python
- ${CMAKE_COMMAND} -E copy ${LIBDIR}/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.tar.gz ${HARVEST_TARGET}/Release/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.tar.gz
DEPENDS Package_Python
)
endif()
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index dd15fb0d2ed..bc9ee802810 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -19,7 +19,32 @@
# A shell script installing/building all needed dependencies to build Blender, for some Linux distributions.
-##### Args and Help Handling #####
+# ----------------------------------------------------------------------------
+# Debugging Helpers
+#
+# Use for developing this script (keep first).
+
+# Useful for debugging this script:
+USE_DEBUG_TRAP=${USE_DEBUG_TRAP:-0}
+USE_DEBUG_LOG=${USE_DEBUG_LOG:-0}
+
+# Print the line that exits.
+if [ $USE_DEBUG_TRAP -ne 0 ]; then
+ err_report() {
+ echo "Error on line $1"
+ exit 1
+ }
+ trap 'err_report $LINENO' ERR
+fi
+
+# Noisy, show every line that runs with it's line number.
+if [ $USE_DEBUG_LOG -ne 0 ]; then
+ PS4='\e[0;33m$(printf %4d ${LINENO}):\e\033[0m '
+ set -x
+fi
+
+# ----------------------------------------------------------------------------
+# Args and Help Handling
# Parse command line!
ARGS=$( \
@@ -305,7 +330,8 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-ffmpeg
Unconditionally skip FFMpeg installation/building.\""
-##### Main Vars #####
+# ----------------------------------------------------------------------------
+# Main Vars
DO_SHOW_DEPS=false
@@ -447,7 +473,8 @@ LANG_BACK=$LANG
LANG=""
export LANG
-##### Generic Helpers #####
+# ----------------------------------------------------------------------------
+# Generic Helpers
BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
@@ -489,7 +516,8 @@ PRINT() {
_echo "$@"
}
-##### Args Handling #####
+# ----------------------------------------------------------------------------
+# Args Handling
# Finish parsing the commandline args.
eval set -- "$ARGS"
@@ -892,7 +920,8 @@ CXXFLAGS_BACK=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -std=c++11"
export CXXFLAGS
-#### Show Dependencies ####
+# ----------------------------------------------------------------------------
+# Show Dependencies
# Need those to be after we defined versions...
DEPS_COMMON_INFO="\"COMMON DEPENDENCIES:
@@ -940,9 +969,8 @@ if [ "$DO_SHOW_DEPS" = true ]; then
exit 0
fi
-
-
-##### Generic Helpers #####
+# ----------------------------------------------------------------------------
+# Generic Helpers
# Check return code of wget for success...
download() {
@@ -965,15 +993,25 @@ download() {
fi
}
+version_sanitize() {
+ # Remove suffix such as '1.3_RC2', keeping only '1.3'.
+ # Needed for numeric comparisons.
+ local val=$(sed -r 's/^([^_]+).*/\1/' <<< "$1")
+ # Remove trailing punctuation such as '1.0.', keeping only '1.0'.
+ val=$(sed -r 's/[[:punct:]]*$//g' <<< "$val")
+ echo $val
+}
+
# Return 0 if $1 = $2 (i.e. 1.01.0 = 1.1, but 1.1.1 != 1.1), else 1.
# $1 and $2 should be version numbers made of numbers only.
version_eq() {
- backIFS=$IFS
- IFS='.'
+ local VER_1=$(version_sanitize "$1")
+ local VER_2=$(version_sanitize "$2")
+ local IFS='.'
# Split both version numbers into their numeric elements.
- arr1=( $1 )
- arr2=( $2 )
+ arr1=( $VER_1 )
+ arr2=( $VER_2 )
ret=1
@@ -983,8 +1021,8 @@ version_eq() {
_t=$count1
count1=$count2
count2=$_t
- arr1=( $2 )
- arr2=( $1 )
+ arr1=( $VER_2 )
+ arr2=( $VER_1 )
fi
ret=0
@@ -1004,7 +1042,6 @@ version_eq() {
fi
done
- IFS=$backIFS
return $ret
}
@@ -1035,12 +1072,13 @@ version_ge_lt() {
# $1 and $2 should be version numbers made of numbers only.
# $1 should be at least as long as $2!
version_match() {
- backIFS=$IFS
- IFS='.'
+ local VER_1=$(version_sanitize "$1")
+ local VER_2=$(version_sanitize "$2")
+ local IFS='.'
# Split both version numbers into their numeric elements.
- arr1=( $1 )
- arr2=( $2 )
+ arr1=( $VER_1 )
+ arr2=( $VER_2 )
ret=1
@@ -1057,11 +1095,12 @@ version_match() {
done
fi
- IFS=$backIFS
return $ret
}
-##### Generic compile helpers #####
+# ----------------------------------------------------------------------------
+# Generic compile helpers
+
prepare_opt() {
INFO "Ensuring $INST exists and is writable by us"
if [ ! $SUDO ]; then
@@ -1123,7 +1162,9 @@ run_ldconfig() {
PRINT ""
}
-#### Build Python ####
+# ----------------------------------------------------------------------------
+# Build Python
+
_init_python() {
_src=$SRC/Python-$PYTHON_VERSION
_git=false
@@ -1192,7 +1233,9 @@ compile_Python() {
fi
}
-##### Build Numpy #####
+# ----------------------------------------------------------------------------
+# Build Numpy
+
_init_numpy() {
_src=$SRC/numpy-$NUMPY_VERSION
_git=false
@@ -1259,7 +1302,9 @@ compile_Numpy() {
fi
}
-#### Build Boost ####
+# ----------------------------------------------------------------------------
+# Build Boost
+
_init_boost() {
_src=$SRC/boost-$BOOST_VERSION
_git=false
@@ -1337,7 +1382,9 @@ compile_Boost() {
run_ldconfig "boost"
}
-#### Build OCIO ####
+# ----------------------------------------------------------------------------
+# Build OCIO
+
_init_ocio() {
_src=$SRC/OpenColorIO-$OCIO_VERSION
if [ "$OCIO_USE_REPO" = true ]; then
@@ -1452,7 +1499,9 @@ compile_OCIO() {
run_ldconfig "ocio"
}
-#### Build ILMBase ####
+# ----------------------------------------------------------------------------
+# Build ILMBase
+
_init_ilmbase() {
_src=$SRC/ILMBase-$ILMBASE_VERSION
_git=false
@@ -1543,7 +1592,9 @@ compile_ILMBASE() {
magic_compile_set ilmbase-$ILMBASE_VERSION $ilmbase_magic
}
-#### Build OpenEXR ####
+# ----------------------------------------------------------------------------
+# Build OpenEXR
+
_init_openexr() {
_src=$SRC/OpenEXR-$OPENEXR_VERSION
_git=true
@@ -1663,7 +1714,9 @@ compile_OPENEXR() {
run_ldconfig "openexr"
}
-#### Build OIIO ####
+# ----------------------------------------------------------------------------
+# Build OIIO
+
_init_oiio() {
_src=$SRC/OpenImageIO-$OIIO_VERSION
_git=true
@@ -1804,7 +1857,9 @@ compile_OIIO() {
run_ldconfig "oiio"
}
-#### Build LLVM ####
+# ----------------------------------------------------------------------------
+# Build LLVM
+
_init_llvm() {
_src=$SRC/LLVM-$LLVM_VERSION
_src_clang=$SRC/CLANG-$LLVM_VERSION
@@ -1904,7 +1959,9 @@ compile_LLVM() {
fi
}
-#### Build OSL ####
+# ----------------------------------------------------------------------------
+# Build OSL
+
_init_osl() {
_src=$SRC/OpenShadingLanguage-$OSL_VERSION
_git=true
@@ -2034,7 +2091,9 @@ compile_OSL() {
run_ldconfig "osl"
}
-#### Build OSD ####
+# ----------------------------------------------------------------------------
+# Build OSD
+
_init_osd() {
_src=$SRC/OpenSubdiv-$OSD_VERSION
_git=true
@@ -2131,7 +2190,9 @@ compile_OSD() {
run_ldconfig "osd"
}
-#### Build Blosc ####
+# ----------------------------------------------------------------------------
+# Build Blosc
+
_init_blosc() {
_src=$SRC/c-blosc-$OPENVDB_BLOSC_VERSION
_git=false
@@ -2218,7 +2279,9 @@ compile_BLOSC() {
run_ldconfig "blosc"
}
-#### Build OpenVDB ####
+# ----------------------------------------------------------------------------
+# Build OpenVDB
+
_init_openvdb() {
_src=$SRC/openvdb-$OPENVDB_VERSION
_git=false
@@ -2319,7 +2382,9 @@ compile_OPENVDB() {
run_ldconfig "openvdb"
}
-#### Build Alembic ####
+# ----------------------------------------------------------------------------
+# Build Alembic
+
_init_alembic() {
_src=$SRC/alembic-$ALEMBIC_VERSION
_git=false
@@ -2412,7 +2477,9 @@ compile_ALEMBIC() {
run_ldconfig "alembic"
}
-#### Build OpenCOLLADA ####
+# ----------------------------------------------------------------------------
+# Build OpenCOLLADA
+
_init_opencollada() {
_src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION
_git=true
@@ -2504,7 +2571,9 @@ compile_OpenCOLLADA() {
fi
}
-#### Build Embree ####
+# ----------------------------------------------------------------------------
+# Build Embree
+
_init_embree() {
_src=$SRC/embree-$EMBREE_VERSION
_git=true
@@ -2599,7 +2668,9 @@ compile_Embree() {
fi
}
-#### Build OpenImageDenoise ####
+# ----------------------------------------------------------------------------
+# Build OpenImageDenoise
+
_init_oidn() {
_src=$SRC/oidn-$OIDN_VERSION
_git=true
@@ -2691,7 +2762,9 @@ compile_OIDN() {
run_ldconfig "oidn"
}
-#### Build FFMPEG ####
+# ----------------------------------------------------------------------------
+# Build FFMPEG
+
_init_ffmpeg() {
_src=$SRC/ffmpeg-$FFMPEG_VERSION
_inst=$INST/ffmpeg-$FFMPEG_VERSION
@@ -2806,7 +2879,9 @@ compile_FFmpeg() {
}
-#### Install on DEB-like ####
+# ----------------------------------------------------------------------------
+# Install on DEB-like
+
get_package_version_DEB() {
dpkg-query -W -f '${Version}' $1 | sed -r 's/([0-9]+:)?(([0-9]+\.?)+([0-9]+)).*/\2/'
}
@@ -3341,7 +3416,9 @@ install_DEB() {
}
-#### Install on RPM-like ####
+# ----------------------------------------------------------------------------
+# Install on RPM-like
+
rpm_flavour() {
if [ -f /etc/redhat-release ]; then
if [ "`grep '[6-7]\.' /etc/redhat-release`" ]; then
@@ -3936,7 +4013,9 @@ install_RPM() {
}
-#### Install on ARCH-like ####
+# ----------------------------------------------------------------------------
+# Install on ARCH-like
+
get_package_version_ARCH() {
pacman -Si $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+?(([0-9]+\.?)+).*/\1/'
}
@@ -4056,7 +4135,7 @@ install_ARCH() {
fi
if [ "$WITH_JACK" = true ]; then
- _packages="$_packages jack"
+ _packages="$_packages jack2"
fi
PRINT ""
@@ -4426,7 +4505,8 @@ install_ARCH() {
}
-#### Install on other distro (very limited!) ####
+# ----------------------------------------------------------------------------
+# Install on other distro (very limited!)
install_OTHER() {
PRINT ""
@@ -4621,7 +4701,8 @@ install_OTHER() {
fi
}
-#### Printing User Info ####
+# ----------------------------------------------------------------------------
+# Printing User Info
print_info_ffmpeglink_DEB() {
dpkg -L $_packages | grep -e ".*\/lib[^\/]\+\.so" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", gensub(/.*lib([^\/]+)\.so/, "\\1", "g", $0)); nlines++ }'
@@ -4713,7 +4794,7 @@ print_info() {
_1="-D PYTHON_VERSION=$PYTHON_VERSION_MIN"
PRINT " $_1"
_buildargs="$_buildargs $_1"
- if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then
+ if [ -d "$INST/python-$PYTHON_VERSION_MIN" ]; then
_1="-D PYTHON_ROOT_DIR=$INST/python-$PYTHON_VERSION_MIN"
PRINT " $_1"
_buildargs="$_buildargs $_1"
@@ -4889,7 +4970,9 @@ print_info() {
PRINT " cmake $_buildargs ."
}
-#### "Main" ####
+# ----------------------------------------------------------------------------
+# "Main"
+
# Detect distribution type used on this machine
if [ -f /etc/debian_version ]; then
DISTRO="DEB"
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 5d46ee751af..e09287f05d9 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -53,6 +53,10 @@ if(EXISTS ${LIBDIR})
set(CMAKE_PREFIX_PATH ${LIBDIR}/zlib ${LIB_SUBDIRS})
set(WITH_STATIC_LIBS ON)
set(WITH_OPENMP_STATIC ON)
+ set(Boost_NO_BOOST_CMAKE ON)
+ set(BOOST_ROOT ${LIBDIR}/boost)
+ set(BOOST_LIBRARYDIR ${LIBDIR}/boost/lib)
+ set(Boost_NO_SYSTEM_PATHS ON)
endif()
if(WITH_STATIC_LIBS)
diff --git a/build_files/package_spec/build_debian.sh b/build_files/package_spec/build_debian.sh
deleted file mode 100755
index a6d94428a88..00000000000
--- a/build_files/package_spec/build_debian.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/sh
-# Builds a debian package from SVN source.
-#
-# For parallel builds use:
-# DEB_BUILD_OPTIONS="parallel=5" sh build_files/package_spec/build_debian.sh
-
-# this needs to run in the root dir.
-cd $(dirname $0)/../../
-rm -rf debian
-cp -a build_files/package_spec/debian .
-
-
-# Get values from blender to use in debian/changelog.
-# value may be formatted: 35042:35051M
-BLENDER_REVISION=$(svnversion | cut -d: -f2 | tr -dc 0-9)
-
-blender_version=$(grep BLENDER_VERSION source/blender/blenkernel/BKE_blender.h | tr -dc 0-9)
-blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' source/blender/blenkernel/BKE_blender.h)
-BLENDER_VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100)
-
-# map the version a -> 1, to conform to debian naming convention
-# not to be confused with blender's internal subversions
-if [ "$blender_version_char" ]; then
- BLENDER_VERSION=${BLENDER_VERSION}.$(expr index abcdefghijklmnopqrstuvwxyz $blender_version_char)
-fi
-
-DEB_VERSION=${BLENDER_VERSION}+svn${BLENDER_REVISION}-bf
-
-# update debian/changelog
-dch -b -v $DEB_VERSION "New upstream SVN snapshot."
-
-
-# run the rules makefile
-rm -rf get-orig-source
-debian/rules get-orig-source SVN_URL=.
-mv *.gz ../
-
-# build the package
-debuild -i -us -uc -b
-
-
-# remove temp dir
-rm -rf debian
diff --git a/build_files/package_spec/debian/changelog b/build_files/package_spec/debian/changelog
deleted file mode 100644
index 0559bb0c4d8..00000000000
--- a/build_files/package_spec/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-blender (2.56+svn34749-bf) unstable; urgency=low
-
- * New upstream SVN snapshot.
-
- -- Dan Eicher <dan@trollwerks.org> Wed, 09 Feb 2011 18:55:24 -0700
diff --git a/build_files/package_spec/debian/compat b/build_files/package_spec/debian/compat
deleted file mode 100644
index 7f8f011eb73..00000000000
--- a/build_files/package_spec/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-7
diff --git a/build_files/package_spec/debian/control b/build_files/package_spec/debian/control
deleted file mode 100644
index addd71760d8..00000000000
--- a/build_files/package_spec/debian/control
+++ /dev/null
@@ -1,24 +0,0 @@
-Source: blender
-Section: graphics
-Priority: extra
-Maintainer: Dan Eicher <dan@trollwerks.org>
-Build-Depends: debhelper (>= 7.0.50~), cmake, python3, python, libfreetype6-dev, libglu1-mesa-dev, libilmbase-dev, libopenexr-dev, libjpeg62-dev, libopenal-dev, libpng12-dev, libsdl-dev, libtiff4-dev, libx11-dev, libxi-dev, zlib1g-dev, python3.2-dev, libopenjpeg-dev
-Standards-Version: 3.9.1
-Homepage: http://blender.org/
-X-Python3-Version: >= 3.2, << 3.3
-
-Package: blender-snapshot
-Architecture: any
-Depends: ${shlibs:Depends}, ${python3:Depends}, ${misc:Depends}
-Provides: blender
-Conflicts: blender
-Replaces: blender
-Description: Very fast and versatile 3D modeller/renderer
- Blender is an integrated 3d suite for modelling, animation, rendering,
- post-production, interactive creation and playback (games). Blender has its
- own particular user interface, which is implemented entirely in OpenGL and
- designed with speed in mind. Python bindings are available for scripting;
- import/export features for popular file formats like 3D Studio and Wavefront
- Obj are implemented as scripts by the community. Stills, animations, models
- for games or other third party engines and interactive content in the form of
- a standalone binary and/or a web plug-in are common products of Blender use.
diff --git a/build_files/package_spec/debian/copyright b/build_files/package_spec/debian/copyright
deleted file mode 100644
index 0f7287208af..00000000000
--- a/build_files/package_spec/debian/copyright
+++ /dev/null
@@ -1,41 +0,0 @@
-This work was packaged for Debian by:
-
- Dan Eicher <dan@trollwerks.org> on Tue, 08 Feb 2011 21:59:32 -0700
-
-It was downloaded from:
-
- http://blender.org
-
-Copyright:
-
- Copyright (C) 2002-2011 Blender Foundation
-
-License:
-
- This package 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 package 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, see <http://www.gnu.org/licenses/>
-
-On Debian systems, the complete text of the GNU General
-Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
-
-
-The Debian packaging is:
-
- Copyright (C) 2011 Dan Eicher <dan@trollwerks.org>
-
-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.
-
-
diff --git a/build_files/package_spec/debian/docs b/build_files/package_spec/debian/docs
deleted file mode 100644
index 886845257bc..00000000000
--- a/build_files/package_spec/debian/docs
+++ /dev/null
@@ -1,2 +0,0 @@
-release/text/copyright.txt
-release/text/readme.html
diff --git a/build_files/package_spec/debian/menu b/build_files/package_spec/debian/menu
deleted file mode 100644
index d69c7354f3c..00000000000
--- a/build_files/package_spec/debian/menu
+++ /dev/null
@@ -1,4 +0,0 @@
-?package(blender-snapshot):needs="X11" section="Applications/Graphics"\
- longtitle="Blender 3D modeler / renderer"\
- icon="/usr/share/icons/hicolor/scalable/apps/blender.svg"\
- title="blender" command="/usr/bin/blender"
diff --git a/build_files/package_spec/debian/rules b/build_files/package_spec/debian/rules
deleted file mode 100755
index 7a3d2d52adc..00000000000
--- a/build_files/package_spec/debian/rules
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-
-SVN_URL := https://svn.blender.org/svnroot/bf-blender/trunk/blender
-REV := $(shell dpkg-parsechangelog | sed -rne 's,^Version: .*[+~]svn([0-9]+).*,\1,p')
-VER := $(shell dpkg-parsechangelog | sed -rne 's,^Version: ([^-]+).*,\1,p')
-REL := $(shell dpkg-parsechangelog | sed -rne 's,^Version: ([0-9]+\.[0-9]+).*,\1,p')
-TARBALL = blender_$(VER).orig.tar.gz
-BLDDIR = debian/cmake
-
-%:
- dh $@ -Scmake -B$(BLDDIR) --parallel --with python3 --without python-support
-
-override_dh_auto_configure:
- # blender spesific CMake options
- dh_auto_configure -- \
- -DCMAKE_BUILD_TYPE:STRING=Release \
- -DWITH_INSTALL_PORTABLE:BOOL=OFF \
- -DWITH_PYTHON_INSTALL:BOOL=OFF \
- -DWITH_OPENCOLLADA:BOOL=OFF
-
-override_dh_auto_test:
- # don't run CTest
-
-override_dh_install:
- dh_install
-
- # remove duplicated docs
- rm -rf debian/blender-snapshot/usr/share/doc/blender
-
-override_dh_python3:
- dh_python3 -V 3.2-3.3 /usr/share/blender/$(REL)/scripts
-
-get-orig-source:
- rm -rf get-orig-source $(TARBALL)
- mkdir get-orig-source
- if [ "$(SVN_URL)" = . ] && [ `svnversion` = "$(REV)" ]; then \
- svn -q export . get-orig-source/blender-$(VER); \
- else \
- svn -q export -r $(REV) $(SVN_URL) get-orig-source/blender-$(VER); \
- fi
- GZIP='--best --no-name' tar czf $(TARBALL) -C get-orig-source blender-$(VER)
- rm -rf get-orig-source
- @echo "$(TARBALL) created; move it to the right destination to build the package"
diff --git a/build_files/package_spec/debian/source/format b/build_files/package_spec/debian/source/format
deleted file mode 100644
index 163aaf8d82b..00000000000
--- a/build_files/package_spec/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/build_files/package_spec/debian/watch b/build_files/package_spec/debian/watch
deleted file mode 100644
index 0f8473b25ef..00000000000
--- a/build_files/package_spec/debian/watch
+++ /dev/null
@@ -1,3 +0,0 @@
-version=3
-opts=uversionmangle=s/[a-z]$/.$&/;s/[j-s]$/1$&/;s/[t-z]$/2$&/;tr/a-z/1-90-90-6/ \
-http://download.blender.org/source/blender-([0-9.]+[a-z]?)\.tar\.gz
diff --git a/build_files/package_spec/pacman/PKGBUILD b/build_files/package_spec/pacman/PKGBUILD
deleted file mode 100644
index aea5acd13e4..00000000000
--- a/build_files/package_spec/pacman/PKGBUILD
+++ /dev/null
@@ -1,66 +0,0 @@
-# Maintainer: Campbell Barton <ideasman42 at gmail dot com>
-
-# custom blender vars
-blender_srcdir=$(dirname $startdir)"/../.."
-blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h | awk '{print $3}')
-blender_version=$(expr $blender_version / 100).$(expr $blender_version % 100) # 256 -> 2.56
-blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h)
-# blender_subversion=$(grep BLENDER_SUBVERSION $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}')
-
-# map the version a -> 1
-# not to be confused with blender's internal subversions
-if [ "$blender_version_char" ]; then
- blender_version_full=${blender_version}.$(expr index abcdefghijklmnopqrstuvwxyz $blender_version_char)
-else
- blender_version_full=${blender_version}
-fi
-
-blender_ver_string=$blender_version+git$blender_version_full
-
-pkgname=blender-snapshot
-pkgver=$blender_ver_string
-pkgrel=1
-pkgdesc="A fully integrated 3D graphics creation suite"
-arch=('i686' 'x86_64')
-url="www.blender.org"
-license=('GPL')
-groups=()
-depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.5'
- 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl'
- 'libsndfile' 'ffmpeg')
-makedepends=('cmake' 'git')
-optdepends=()
-provides=()
-conflicts=('blender')
-replaces=('blender')
-backup=()
-options=()
-install=blender.install
-# use current git to make the package.
-# source=(http://download.blender.org/source/$pkgname-$pkgver.tar.gz)
-# md5sums=('27edb80c82c25252d43d6a01980d953a') #generate with 'makepkg -g'
-source=()
-md5sums=()
-noextract=()
-
-build() {
- mkdir -p $srcdir/build
- cd $srcdir/build
- cmake $blender_srcdir \
- -DCMAKE_INSTALL_PREFIX:PATH=/usr \
- -DCMAKE_BUILD_TYPE:STRING=Release \
- -DWITH_INSTALL_PORTABLE:BOOL=OFF \
- -DWITH_PYTHON_INSTALL:BOOL=OFF \
- -DWITH_OPENCOLLADA:BOOL=OFF
-
- make $MAKEFLAGS
-}
-
-package() {
- cd $srcdir/build
- make DESTDIR="$pkgdir" install
- python -m compileall \
- $pkgdir/usr/share/blender/$blender_version/scripts/startup \
- $pkgdir/usr/share/blender/$blender_version/scripts/modules \
- $pkgdir/usr/share/blender/$blender_version/scripts/addons
-}
diff --git a/build_files/package_spec/pacman/blender.install b/build_files/package_spec/pacman/blender.install
deleted file mode 100644
index f2d37ec7a2b..00000000000
--- a/build_files/package_spec/pacman/blender.install
+++ /dev/null
@@ -1,29 +0,0 @@
-post_install() {
- cat << EOF
-
-NOTE
-----
-Happy blending!
-
-EOF
- echo "update desktop mime database..."
- update-desktop-database
-}
-
-post_upgrade() {
- post_install $1
-}
-
-pre_remove() {
- /bin/true
-}
-
-post_remove() {
- echo "update desktop mime database..."
- update-desktop-database
-}
-
-op=$1
-shift
-
-$op $*
diff --git a/build_files/package_spec/rpm/blender.spec.in b/build_files/package_spec/rpm/blender.spec.in
deleted file mode 100644
index e75cc8ec7a6..00000000000
--- a/build_files/package_spec/rpm/blender.spec.in
+++ /dev/null
@@ -1,88 +0,0 @@
-# -*- rpm-spec -*-
-%global __python %{__python3}
-%global blender_api @CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@
-
-%define _rpmdir @CPACK_RPM_DIRECTORY@
-%define _rpmfilename @CPACK_RPM_FILE_NAME@
-%define _unpackaged_files_terminate_build 0
-%define _topdir @CPACK_RPM_DIRECTORY@
-
-BuildRoot: @CPACK_RPM_DIRECTORY@/@CPACK_PACKAGE_FILE_NAME@@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH@
-Summary: @CPACK_RPM_PACKAGE_SUMMARY@
-Name: @CPACK_RPM_PACKAGE_NAME@
-Version: @CPACK_RPM_PACKAGE_VERSION@
-Release: @CPACK_RPM_PACKAGE_RELEASE@%{?dist}
-License: @CPACK_RPM_PACKAGE_LICENSE@
-Group: @CPACK_RPM_PACKAGE_GROUP@
-Vendor: @CPACK_RPM_PACKAGE_VENDOR@
-Epoch: 1
-
-Requires(post): desktop-file-utils
-Requires(post): shared-mime-info
-Requires(postun): desktop-file-utils
-Requires(postun): shared-mime-info
-
-Provides: blender(ABI) = %{blender_api}
-Provides: blender-fonts = %{?epoch:%{epoch}:}%{version}-%{release}
-
-Obsoletes: blender-fonts <= 2.49a-9
-
-%description
-Blender is an integrated 3d suite for modelling, animation, rendering,
-post-production, interactive creation and playback (games). Blender has its
-own particular user interface, which is implemented entirely in OpenGL and
-designed with speed in mind. Python bindings are available for scripting;
-import/export features for popular file formats like 3D Studio and Wavefront
-Obj are implemented as scripts by the community. Stills, animations, models
-for games or other third party engines and interactive content in the form of
-a standalone binary and/or a web plug-in are common products of Blender use.
-
-# This is a shortcutted spec file generated by CMake RPM generator
-# we skip _install step because CPack does that for us.
-# We do only save CPack installed tree in _prepr
-# and then restore it in build.
-%prep
-mv ${RPM_BUILD_ROOT} "@CPACK_TOPLEVEL_DIRECTORY@/tmpBBroot"
-
-%install
-if [ -e ${RPM_BUILD_ROOT} ];
-then
- rm -rf ${RPM_BUILD_ROOT}
-fi
-mv "@CPACK_TOPLEVEL_DIRECTORY@/tmpBBroot" ${RPM_BUILD_ROOT}
-
-rm -f ${RPM_BUILD_ROOT}%{_bindir}/blender-thumbnailer.py
-
-%find_lang %{name}
-
-%clean
-rm -rf ${RPM_BUILD_ROOT}
-
-%post
-touch --no-create %{_datadir}/icons/hicolor
-if [ -x %{_bindir}/gtk-update-icon-cache ]; then
- %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor
-fi
-%{_bindir}/update-desktop-database %{_datadir}/applications || :
-
-%postun
-%{_bindir}/update-desktop-database %{_datadir}/applications
-touch --no-create %{_datadir}/icons/hicolor
-if [ -x %{_bindir}/gtk-update-icon-cache ]; then
- %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor
-fi || :
-
-%files -f blender.lang
-%defattr(-,root,root,-)
-%{_bindir}/%{name}
-%{_datadir}/%{name}/%{blender_api}/datafiles/fonts
-%{_datadir}/%{name}/%{blender_api}/datafiles/colormanagement
-%{_datadir}/%{name}/%{blender_api}/datafiles/locale/languages
-%{_datadir}/%{name}/%{blender_api}/scripts
-%{_datadir}/icons/hicolor/*/apps/%{name}.*
-%{_datadir}/applications/%{name}.desktop
-%{_datadir}/doc/%{name}
-%{_mandir}/man1/%{name}.*
-
-%changelog
-@CPACK_RPM_SPEC_CHANGELOG@
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index c07a80bf0d5..ecd60957f2b 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "V2.82"
+PROJECT_NUMBER = "V2.83"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/doc/python_api/examples/gpu.5.py b/doc/python_api/examples/gpu.5.py
index 855f9a28e44..e05290a9442 100644
--- a/doc/python_api/examples/gpu.5.py
+++ b/doc/python_api/examples/gpu.5.py
@@ -4,6 +4,7 @@ Mesh with Random Vertex Colors
"""
import bpy
import gpu
+import bgl
import numpy as np
from random import random
from gpu_extras.batch import batch_for_shader
@@ -30,7 +31,9 @@ batch = batch_for_shader(
def draw():
+ bgl.glEnable(bgl.GL_DEPTH_TEST)
batch.draw(shader)
+ bgl.glDisable(bgl.GL_DEPTH_TEST)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index 8a8eef0e059..c1106b367ca 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -1188,8 +1188,8 @@ class OptiXDevice : public Device {
out_data,
sizes.outputSizeInBytes,
&out_handle,
- &compacted_size_prop,
- 1));
+ background ? &compacted_size_prop : NULL,
+ background ? 1 : 0));
// Wait for all operations to finish
check_result_cuda_ret(cuStreamSynchronize(NULL));
diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl
index 6e9181cde40..4d881eb3b65 100644
--- a/intern/cycles/kernel/shaders/node_ies_light.osl
+++ b/intern/cycles/kernel/shaders/node_ies_light.osl
@@ -31,7 +31,7 @@ shader node_ies_light(int use_mapping = 0,
p = transform(mapping, p);
}
- p = normalize(p);
+ p = normalize((vector)p);
float v_angle = acos(-p[2]);
float h_angle = atan2(p[0], p[1]) + M_PI;
diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/shaders/node_mapping.osl
index 8eed0ae9c48..e8a9d940eda 100644
--- a/intern/cycles/kernel/shaders/node_mapping.osl
+++ b/intern/cycles/kernel/shaders/node_mapping.osl
@@ -65,7 +65,7 @@ shader node_mapping(string type = "point",
VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale));
}
else if (type == "normal") {
- VectorOut = normalize(transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
+ VectorOut = normalize((vector)transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
}
else {
warning("%s", "Unknown Mapping vector type!");
diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl
index fd5e27aa144..4fa9b3bb57b 100644
--- a/intern/cycles/kernel/shaders/node_vector_math.osl
+++ b/intern/cycles/kernel/shaders/node_vector_math.osl
@@ -92,7 +92,7 @@ shader node_vector_math(string type = "add",
Vector = ceil(Vector1);
}
else if (type == "modulo") {
- Vector = mod(Vector1, Vector2);
+ Vector = fmod(Vector1, Vector2);
}
else if (type == "fraction") {
Vector = Vector1 - floor(Vector1);
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 5de4aeef943..10a9f7a6329 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -603,7 +603,7 @@ void voronoi_distance_to_edge_3d(vector3 coord, float randomness, output float o
vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
- normalize(perpendicularToEdge));
+ normalize((vector)perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
diff --git a/intern/cycles/kernel/shaders/node_white_noise_texture.osl b/intern/cycles/kernel/shaders/node_white_noise_texture.osl
index f026fb4ab39..95f91d25e5e 100644
--- a/intern/cycles/kernel/shaders/node_white_noise_texture.osl
+++ b/intern/cycles/kernel/shaders/node_white_noise_texture.osl
@@ -15,23 +15,33 @@
*/
#include "stdosl.h"
+#include "vector2.h"
+#include "vector4.h"
+#include "node_hash.h"
+
+#define vector3 point
shader node_white_noise_texture(string dimensions = "3D",
point Vector = point(0.0, 0.0, 0.0),
float W = 0.0,
- output float Value = 0.0)
+ output float Value = 0.0,
+ output color Color = 0.0)
{
if (dimensions == "1D") {
Value = noise("hash", W);
+ Color = hash_float_to_color(W);
}
else if (dimensions == "2D") {
Value = noise("hash", Vector[0], Vector[1]);
+ Color = hash_vector2_to_color(vector2(Vector[0], Vector[1]));
}
else if (dimensions == "3D") {
Value = noise("hash", Vector);
+ Color = hash_vector3_to_color(vector3(Vector[0], Vector[1], Vector[2]));
}
else if (dimensions == "4D") {
Value = noise("hash", Vector, W);
+ Color = hash_vector4_to_color(vector4(Vector[0], Vector[1], Vector[2], W));
}
else {
warning("%s", "Unknown dimension!");
diff --git a/intern/cycles/kernel/svm/svm_white_noise.h b/intern/cycles/kernel/svm/svm_white_noise.h
index 71d4591d25d..b30d85acaec 100644
--- a/intern/cycles/kernel/svm/svm_white_noise.h
+++ b/intern/cycles/kernel/svm/svm_white_noise.h
@@ -21,35 +21,61 @@ ccl_device void svm_node_tex_white_noise(KernelGlobals *kg,
float *stack,
uint dimensions,
uint inputs_stack_offsets,
- uint value_stack_offset,
+ uint ouptuts_stack_offsets,
int *offset)
{
- uint vector_stack_offset, w_stack_offset;
+ uint vector_stack_offset, w_stack_offset, value_stack_offset, color_stack_offset;
svm_unpack_node_uchar2(inputs_stack_offsets, &vector_stack_offset, &w_stack_offset);
+ svm_unpack_node_uchar2(ouptuts_stack_offsets, &value_stack_offset, &color_stack_offset);
float3 vector = stack_load_float3(stack, vector_stack_offset);
float w = stack_load_float(stack, w_stack_offset);
- float value;
- switch (dimensions) {
- case 1:
- value = hash_float_to_float(w);
- break;
- case 2:
- value = hash_float2_to_float(make_float2(vector.x, vector.y));
- break;
- case 3:
- value = hash_float3_to_float(vector);
- break;
- case 4:
- value = hash_float4_to_float(make_float4(vector.x, vector.y, vector.z, w));
- break;
- default:
- value = 0.0f;
- kernel_assert(0);
- break;
+ if (stack_valid(color_stack_offset)) {
+ float3 color;
+ switch (dimensions) {
+ case 1:
+ color = hash_float_to_float3(w);
+ break;
+ case 2:
+ color = hash_float2_to_float3(make_float2(vector.x, vector.y));
+ break;
+ case 3:
+ color = hash_float3_to_float3(vector);
+ break;
+ case 4:
+ color = hash_float4_to_float3(make_float4(vector.x, vector.y, vector.z, w));
+ break;
+ default:
+ color = make_float3(1.0f, 0.0f, 1.0f);
+ kernel_assert(0);
+ break;
+ }
+ stack_store_float3(stack, color_stack_offset, color);
+ }
+
+ if (stack_valid(value_stack_offset)) {
+ float value;
+ switch (dimensions) {
+ case 1:
+ value = hash_float_to_float(w);
+ break;
+ case 2:
+ value = hash_float2_to_float(make_float2(vector.x, vector.y));
+ break;
+ case 3:
+ value = hash_float3_to_float(vector);
+ break;
+ case 4:
+ value = hash_float4_to_float(make_float4(vector.x, vector.y, vector.z, w));
+ break;
+ default:
+ value = 0.0f;
+ kernel_assert(0);
+ break;
+ }
+ stack_store_float(stack, value_stack_offset, value);
}
- stack_store_float(stack, value_stack_offset, value);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index e4339b40744..bdab2a99897 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -1288,6 +1288,7 @@ NODE_DEFINE(WhiteNoiseTextureNode)
SOCKET_IN_FLOAT(w, "W", 0.0f);
SOCKET_OUT_FLOAT(value, "Value");
+ SOCKET_OUT_COLOR(color, "Color");
return type;
}
@@ -1301,15 +1302,17 @@ void WhiteNoiseTextureNode::compile(SVMCompiler &compiler)
ShaderInput *vector_in = input("Vector");
ShaderInput *w_in = input("W");
ShaderOutput *value_out = output("Value");
+ ShaderOutput *color_out = output("Color");
int vector_stack_offset = compiler.stack_assign(vector_in);
int w_stack_offset = compiler.stack_assign(w_in);
int value_stack_offset = compiler.stack_assign(value_out);
+ int color_stack_offset = compiler.stack_assign(color_out);
compiler.add_node(NODE_TEX_WHITE_NOISE,
dimensions,
compiler.encode_uchar4(vector_stack_offset, w_stack_offset),
- value_stack_offset);
+ compiler.encode_uchar4(value_stack_offset, color_stack_offset));
}
void WhiteNoiseTextureNode::compile(OSLCompiler &compiler)
diff --git a/intern/cycles/util/util_version.h b/intern/cycles/util/util_version.h
index 7489eed8aed..bb2c99cc6d7 100644
--- a/intern/cycles/util/util_version.h
+++ b/intern/cycles/util/util_version.h
@@ -22,7 +22,7 @@
CCL_NAMESPACE_BEGIN
#define CYCLES_VERSION_MAJOR 1
-#define CYCLES_VERSION_MINOR 11
+#define CYCLES_VERSION_MINOR 12
#define CYCLES_VERSION_PATCH 0
#define CYCLES_MAKE_VERSION_STRING2(a, b, c) #a "." #b "." #c
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index c19d4bdf6bd..07133d86ce4 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -247,7 +247,11 @@ class GHOST_IWindow {
* Returns the tablet data (pressure etc).
* \return The tablet data (pressure etc).
*/
- virtual const GHOST_TabletData *GetTabletData() = 0;
+ virtual const GHOST_TabletData &GetTabletData()
+ {
+ /* Default state when no tablet is used, for systems without tablet support. */
+ return GHOST_TABLET_DATA_DEFAULT;
+ }
/***************************************************************************************
* Progress bar functionality
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index fab315e5f13..98dd1de867f 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -101,6 +101,12 @@ typedef struct GHOST_TabletData {
float Ytilt; /* as above */
} GHOST_TabletData;
+static const GHOST_TabletData GHOST_TABLET_DATA_DEFAULT = {
+ GHOST_kTabletModeNone, /* No tablet connected. */
+ 1.0f, /* Pressure */
+ 0.0f, /* Xtilt */
+ 0.0f}; /* Ytilt */
+
typedef enum {
GHOST_kNotVisible = 0,
GHOST_kPartiallyVisible,
@@ -409,11 +415,15 @@ typedef struct {
GHOST_TInt32 x;
/** The y-coordinate of the cursor position. */
GHOST_TInt32 y;
+ /** Associated tablet data. */
+ GHOST_TabletData tablet;
} GHOST_TEventCursorData;
typedef struct {
/** The mask of the mouse button. */
GHOST_TButtonMask button;
+ /** Associated tablet data. */
+ GHOST_TabletData tablet;
} GHOST_TEventButtonData;
typedef struct {
@@ -426,7 +436,8 @@ typedef enum {
GHOST_kTrackpadEventScroll,
GHOST_kTrackpadEventRotate,
GHOST_kTrackpadEventSwipe, /* Reserved, not used for now */
- GHOST_kTrackpadEventMagnify
+ GHOST_kTrackpadEventMagnify,
+ GHOST_kTrackpadEventSmartMagnify
} GHOST_TTrackpadEventSubTypes;
typedef struct {
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 1bed7afdfc4..3c3860bd2c0 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -708,7 +708,7 @@ void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api)
const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle)
{
- return ((GHOST_IWindow *)windowhandle)->GetTabletData();
+ return &((GHOST_IWindow *)windowhandle)->GetTabletData();
}
GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle)
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index d4eeda2a9ef..e072f0823f3 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -37,7 +37,7 @@
case code: \
return #code;
-static const char *get_egl_error_enum_string(EGLenum error)
+static const char *get_egl_error_enum_string(EGLint error)
{
switch (error) {
CASE_CODE_RETURN_STR(EGL_SUCCESS)
@@ -60,7 +60,7 @@ static const char *get_egl_error_enum_string(EGLenum error)
}
}
-static const char *get_egl_error_message_string(EGLenum error)
+static const char *get_egl_error_message_string(EGLint error)
{
switch (error) {
case EGL_SUCCESS:
@@ -129,7 +129,7 @@ static const char *get_egl_error_message_string(EGLenum error)
static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL)
{
if (!result) {
- EGLenum error = eglGetError();
+ const EGLint error = eglGetError();
const char *code = get_egl_error_enum_string(error);
const char *msg = get_egl_error_message_string(error);
@@ -140,13 +140,13 @@ static bool egl_chk(bool result, const char *file = NULL, int line = 0, const ch
file,
line,
text,
- error,
+ static_cast<unsigned int>(error),
code ? code : "<Unknown>",
msg ? msg : "<Unknown>");
#else
fprintf(stderr,
"EGL Error (0x%04X): %s: %s\n",
- error,
+ static_cast<unsigned int>(error),
code ? code : "<Unknown>",
msg ? msg : "<Unknown>");
#endif
@@ -225,8 +225,6 @@ GHOST_ContextEGL::GHOST_ContextEGL(bool stereoVisual,
choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_sharedContext)),
m_sharedCount(choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount))
{
- assert(m_nativeWindow != 0);
- assert(m_nativeDisplay != NULL);
}
GHOST_ContextEGL::~GHOST_ContextEGL()
@@ -253,8 +251,6 @@ GHOST_ContextEGL::~GHOST_ContextEGL()
if (m_surface != EGL_NO_SURFACE)
EGL_CHK(::eglDestroySurface(m_display, m_surface));
-
- EGL_CHK(::eglTerminate(m_display));
}
}
@@ -307,18 +303,35 @@ GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
if (m_display) {
bindAPI(m_api);
- return EGL_CHK(::eglMakeCurrent(m_display, None, None, NULL)) ? GHOST_kSuccess :
- GHOST_kFailure;
+ return EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) ?
+ GHOST_kSuccess :
+ GHOST_kFailure;
}
else {
return GHOST_kFailure;
}
}
-void GHOST_ContextEGL::initContextEGLEW()
+bool GHOST_ContextEGL::initContextEGLEW()
{
- if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK)
+ /* We have to manually get this function before we can call eglewInit, since
+ * it requires a display argument. glewInit() does the same, but we only want
+ * to intialize EGLEW here. */
+ eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay");
+ if (eglGetDisplay == NULL) {
+ return false;
+ }
+
+ if (!EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) {
+ return false;
+ }
+
+ if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK) {
fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n");
+ return false;
+ }
+
+ return true;
}
static const std::string &api_string(EGLenum api)
@@ -341,6 +354,10 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
m_stereoVisual = false; // It doesn't matter what the Window wants.
+ if (!initContextEGLEW()) {
+ return GHOST_kFailure;
+ }
+
#ifdef WITH_GL_ANGLE
// d3dcompiler_XX.dll needs to be loaded before ANGLE will work
if (s_d3dcompiler == NULL) {
@@ -360,11 +377,6 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
EGLSurface prev_read = eglGetCurrentSurface(EGL_READ);
EGLContext prev_context = eglGetCurrentContext();
- m_display = ::eglGetDisplay(m_nativeDisplay);
-
- if (!EGL_CHK(m_display != EGL_NO_DISPLAY))
- return GHOST_kFailure;
-
EGLint egl_major, egl_minor;
if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)))
@@ -375,8 +387,6 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)))
goto error;
- initContextEGLEW();
-
if (!bindAPI(m_api))
goto error;
@@ -419,6 +429,10 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
egl_minor);
}
}
+ else {
+ attrib_list.push_back(EGL_RENDERABLE_TYPE);
+ attrib_list.push_back(EGL_OPENGL_BIT);
+ }
attrib_list.push_back(EGL_RED_SIZE);
attrib_list.push_back(8);
@@ -434,6 +448,12 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
attrib_list.push_back(8);
#endif
+ if (m_nativeWindow == 0) {
+ // off-screen surface
+ attrib_list.push_back(EGL_SURFACE_TYPE);
+ attrib_list.push_back(EGL_PBUFFER_BIT);
+ }
+
attrib_list.push_back(EGL_NONE);
EGLConfig config;
@@ -445,7 +465,19 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
if (num_config != 1) // num_config should be exactly 1
goto error;
- m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL);
+ if (m_nativeWindow != 0) {
+ m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL);
+ }
+ else {
+ static const EGLint pb_attrib_list[] = {
+ EGL_WIDTH,
+ 1,
+ EGL_HEIGHT,
+ 1,
+ EGL_NONE,
+ };
+ m_surface = ::eglCreatePbufferSurface(m_display, config, pb_attrib_list);
+ }
if (!EGL_CHK(m_surface != EGL_NO_SURFACE))
goto error;
diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h
index cd6b0c959b7..da5ca7ef93f 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.h
+++ b/intern/ghost/intern/GHOST_ContextEGL.h
@@ -102,7 +102,7 @@ class GHOST_ContextEGL : public GHOST_Context {
GHOST_TSuccess getSwapInterval(int &intervalOut);
private:
- void initContextEGLEW();
+ bool initContextEGLEW();
EGLNativeDisplayType m_nativeDisplay;
EGLNativeWindowType m_nativeWindow;
diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h
index da1dc929f4f..0f9d3b7e6bc 100644
--- a/intern/ghost/intern/GHOST_EventButton.h
+++ b/intern/ghost/intern/GHOST_EventButton.h
@@ -46,6 +46,7 @@ class GHOST_EventButton : public GHOST_Event {
: GHOST_Event(time, type, window)
{
m_buttonEventData.button = button;
+ m_buttonEventData.tablet = window->GetTabletData();
m_data = &m_buttonEventData;
}
diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h
index ac40f78569d..41597db216a 100644
--- a/intern/ghost/intern/GHOST_EventCursor.h
+++ b/intern/ghost/intern/GHOST_EventCursor.h
@@ -48,6 +48,7 @@ class GHOST_EventCursor : public GHOST_Event {
{
m_cursorEventData.x = x;
m_cursorEventData.y = y;
+ m_cursorEventData.tablet = window->GetTabletData();
m_data = &m_cursorEventData;
}
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index 119c9f28223..e459da39d14 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -39,7 +39,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
if (event->getType() == GHOST_kEventWindowUpdate)
return false;
- std::cout << "\nGHOST_EventPrinter::processEvent, time: " << (GHOST_TInt32)event->getTime()
+ std::cout << "GHOST_EventPrinter::processEvent, time: " << (GHOST_TInt32)event->getTime()
<< ", type: ";
switch (event->getType()) {
case GHOST_kEventUnknown:
@@ -164,6 +164,8 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
break;
}
+ std::cout << std::endl;
+
std::cout.flush();
return handled;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 2f597aee476..297b73f8b14 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1451,11 +1451,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
break;
case NSEventTypeTabletProximity:
- ct.Pressure = 0;
- ct.Xtilt = 0;
- ct.Ytilt = 0;
+ /* Reset tablet data when device enters proximity or leaves. */
+ ct = GHOST_TABLET_DATA_DEFAULT;
if ([event isEnteringProximity]) {
- // pointer is entering tablet area proximity
+ /* Pointer is entering tablet area proximity. */
switch ([event pointingDeviceType]) {
case NSPointingDeviceTypePen:
ct.Active = GHOST_kTabletModeStylus;
@@ -1466,14 +1465,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
case NSPointingDeviceTypeCursor:
case NSPointingDeviceTypeUnknown:
default:
- ct.Active = GHOST_kTabletModeNone;
break;
}
}
- else {
- // pointer is leaving - return to mouse
- ct.Active = GHOST_kTabletModeNone;
- }
break;
default:
@@ -1524,46 +1518,45 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
switch ([event type]) {
case NSEventTypeLeftMouseDown:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeRightMouseDown:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeOtherMouseDown:
+ handleTabletEvent(event); // Handle tablet events combined with mouse events
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonDown,
window,
convertButton([event buttonNumber])));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeLeftMouseUp:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeRightMouseUp:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton(
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeOtherMouseUp:
+ handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonUp,
window,
convertButton([event buttonNumber])));
- handleTabletEvent(event); // Handle tablet events combined with mouse events
break;
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
- // Handle tablet events combined with mouse events
- handleTabletEvent(event);
+ handleTabletEvent(event); // Update window tablet state to be included in event.
case NSEventTypeMouseMoved: {
GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
@@ -1733,6 +1726,14 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
0));
} break;
+ case NSEventTypeSmartMagnify: {
+ NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
+ GHOST_TInt32 x, y;
+ window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+ pushEvent(new GHOST_EventTrackpad(
+ [event timestamp] * 1000, window, GHOST_kTrackpadEventSmartMagnify, x, y, 0, 0));
+ } break;
+
case NSEventTypeRotate: {
NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
GHOST_TInt32 x, y;
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index d3295d5584c..7ed912b8218 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -702,9 +702,9 @@ GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
// We should always check the window manager's list of windows
// and only process events on these windows.
- std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
+ const std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
- std::vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ std::vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
std::vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
for (; win_it != win_end; ++win_it) {
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index fa2fc9fff37..4a4016cbca1 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -443,6 +443,13 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent)
::DispatchMessageW(&msg);
hasEventHandled = true;
}
+
+ /* PeekMessage above is allowed to dispatch messages to the wndproc without us
+ * noticing, so we need to check the event manager here to see if there are
+ * events waiting in the queue.
+ */
+ hasEventHandled |= this->m_eventManager->getNumEvents() > 0;
+
} while (waitForEvent && !hasEventHandled);
return hasEventHandled;
@@ -894,6 +901,7 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
switch (type) {
case GHOST_kEventButtonDown:
+ /* Update window tablet data to be included in event. */
window->setTabletData(&pointerInfo.tabletData);
eventHandled = true;
return new GHOST_EventButton(
@@ -903,6 +911,7 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
return new GHOST_EventButton(
system->getMilliSeconds(), GHOST_kEventButtonUp, window, pointerInfo.buttonMask);
case GHOST_kEventCursorMove:
+ /* Update window tablet data to be included in event. */
window->setTabletData(&pointerInfo.tabletData);
eventHandled = true;
return new GHOST_EventCursor(system->getMilliSeconds(),
@@ -1451,7 +1460,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
////////////////////////////////////////////////////////////////////////
case WM_CLOSE:
/* The WM_CLOSE message is sent as a signal that a window
- * or an application should terminate. */
+ * or an application should terminate. Restore if minimized. */
+ if (IsIconic(hwnd)) {
+ ShowWindow(hwnd, SW_RESTORE);
+ }
event = processWindowEvent(GHOST_kEventWindowClose, window);
break;
case WM_ACTIVATE:
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index c50ff8e7426..2cc515ca3d7 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -50,6 +50,7 @@
#if defined(WITH_GL_EGL)
# include "GHOST_ContextEGL.h"
+# include <EGL/eglext.h>
#else
# include "GHOST_ContextGLX.h"
#endif
@@ -243,6 +244,10 @@ GHOST_SystemX11::~GHOST_SystemX11()
clearXInputDevices();
#endif /* WITH_X11_XINPUT */
+#ifdef WITH_GL_EGL
+ ::eglTerminate(::eglGetDisplay(m_display));
+#endif
+
if (m_xkb_descr) {
XkbFreeKeyboard(m_xkb_descr, XkbAllComponentsMask, true);
}
@@ -406,17 +411,39 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext()
#endif
const int profile_mask =
-#if defined(WITH_GL_PROFILE_CORE)
+#ifdef WITH_GL_EGL
+# if defined(WITH_GL_PROFILE_CORE)
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT;
+# elif defined(WITH_GL_PROFILE_COMPAT)
+ EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT;
+# else
+# error // must specify either core or compat at build time
+# endif
+#else
+# if defined(WITH_GL_PROFILE_CORE)
GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
-#elif defined(WITH_GL_PROFILE_COMPAT)
+# elif defined(WITH_GL_PROFILE_COMPAT)
GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
-#else
-# error // must specify either core or compat at build time
+# else
+# error // must specify either core or compat at build time
+# endif
#endif
GHOST_Context *context;
for (int minor = 5; minor >= 0; --minor) {
+#if defined(WITH_GL_EGL)
+ context = new GHOST_ContextEGL(false,
+ EGLNativeWindowType(nullptr),
+ EGLNativeDisplayType(m_display),
+ profile_mask,
+ 4,
+ minor,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS |
+ (false ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0),
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+#else
context = new GHOST_ContextGLX(false,
(Window)NULL,
m_display,
@@ -427,6 +454,7 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext()
GHOST_OPENGL_GLX_CONTEXT_FLAGS |
(false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+#endif
if (context->initializeDrawingContext())
return context;
@@ -434,6 +462,18 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext()
delete context;
}
+#if defined(WITH_GL_EGL)
+ context = new GHOST_ContextEGL(false,
+ EGLNativeWindowType(nullptr),
+ EGLNativeDisplayType(m_display),
+ profile_mask,
+ 3,
+ 3,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS |
+ (false ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0),
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+#else
context = new GHOST_ContextGLX(false,
(Window)NULL,
m_display,
@@ -444,6 +484,7 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext()
GHOST_OPENGL_GLX_CONTEXT_FLAGS |
(false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+#endif
if (context->initializeDrawingContext())
return context;
@@ -505,9 +546,9 @@ GHOST_WindowX11 *GHOST_SystemX11::findGhostWindow(Window xwind) const
* We should always check the window manager's list of windows
* and only process events on these windows. */
- vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
+ const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
- vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
for (; win_it != win_end; ++win_it) {
@@ -799,8 +840,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* update all window events */
{
- vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
- vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
+ vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
for (; win_it != win_end; ++win_it) {
@@ -823,7 +864,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* in the future we could have a ghost call window->CheckTabletProximity()
* but for now enough parts of the code are checking 'Active'
* - campbell */
- if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
+ if (window->GetTabletData().Active != GHOST_kTabletModeNone) {
bool any_proximity = false;
for (GHOST_TabletX11 &xtablet : m_xtablets) {
@@ -834,7 +875,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
if (!any_proximity) {
// printf("proximity disable\n");
- window->GetTabletData()->Active = GHOST_kTabletModeNone;
+ window->GetTabletData().Active = GHOST_kTabletModeNone;
}
}
#endif /* WITH_X11_XINPUT */
@@ -855,7 +896,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
XMotionEvent &xme = xe->xmotion;
#ifdef WITH_X11_XINPUT
- bool is_tablet = window->GetTabletData()->Active != GHOST_kTabletModeNone;
+ bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
#else
bool is_tablet = false;
#endif
@@ -1395,7 +1436,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* stroke might begin without leading ProxyIn event,
* this happens when window is opened when stylus is already hovering
* around tablet surface */
- window->GetTabletData()->Active = xtablet.mode;
+ window->GetTabletData().Active = xtablet.mode;
/* Note: This event might be generated with incomplete dataset
* (don't exactly know why, looks like in some cases, if the value does not change,
@@ -1408,7 +1449,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
((void)(val = data->axis_data[axis - axis_first]), true))
if (AXIS_VALUE_GET(2, axis_value)) {
- window->GetTabletData()->Pressure = axis_value / ((float)xtablet.PressureLevels);
+ window->GetTabletData().Pressure = axis_value / ((float)xtablet.PressureLevels);
}
/* the (short) cast and the & 0xffff is bizarre and unexplained anywhere,
@@ -1420,12 +1461,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* check this. --mont29
*/
if (AXIS_VALUE_GET(3, axis_value)) {
- window->GetTabletData()->Xtilt = (short)(axis_value & 0xffff) /
- ((float)xtablet.XtiltLevels);
+ window->GetTabletData().Xtilt = (short)(axis_value & 0xffff) /
+ ((float)xtablet.XtiltLevels);
}
if (AXIS_VALUE_GET(4, axis_value)) {
- window->GetTabletData()->Ytilt = (short)(axis_value & 0xffff) /
- ((float)xtablet.YtiltLevels);
+ window->GetTabletData().Ytilt = (short)(axis_value & 0xffff) /
+ ((float)xtablet.YtiltLevels);
}
# undef AXIS_VALUE_GET
@@ -1436,10 +1477,10 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
continue;
}
- window->GetTabletData()->Active = xtablet.mode;
+ window->GetTabletData().Active = xtablet.mode;
}
else if (xe->type == xtablet.ProxOutEvent) {
- window->GetTabletData()->Active = GHOST_kTabletModeNone;
+ window->GetTabletData().Active = GHOST_kTabletModeNone;
}
}
#endif // WITH_X11_XINPUT
@@ -1620,7 +1661,7 @@ void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)
bool GHOST_SystemX11::generateWindowExposeEvents()
{
- vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
+ vector<GHOST_WindowX11 *>::const_iterator w_start = m_dirty_windows.begin();
vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
bool anyProcessed = false;
@@ -1830,8 +1871,8 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
unsigned long pty_size, pty_items;
unsigned char *ltxt = *txt;
- vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
- vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
+ vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
Window win = window->getXWindow();
@@ -2036,8 +2077,8 @@ GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
else
sseln = m_atom.CLIPBOARD;
- vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
- vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
+ vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
Window win = window->getXWindow();
@@ -2116,8 +2157,8 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
{
Window m_window, owner;
- vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
- vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
+ const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
+ vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
m_window = window->getXWindow();
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index d260d0eacbc..a49949c2c8d 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -222,9 +222,9 @@ class GHOST_WindowCocoa : public GHOST_Window {
bool isDialog() const;
- const GHOST_TabletData *GetTabletData()
+ const GHOST_TabletData &GetTabletData()
{
- return &m_tablet;
+ return m_tablet;
}
GHOST_TabletData &GetCocoaTabletData()
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 41163239a2b..8c86d92bf75 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -397,7 +397,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
setTitle(title);
- m_tablet.Active = GHOST_kTabletModeNone;
+ m_tablet = GHOST_TABLET_DATA_DEFAULT;
CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
[windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 52a57edd4e9..d1d66c35de5 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -162,7 +162,7 @@ void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow *window)
}
}
-std::vector<GHOST_IWindow *> &GHOST_WindowManager::getWindows()
+const std::vector<GHOST_IWindow *> &GHOST_WindowManager::getWindows() const
{
return m_windows;
}
diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h
index 025d84f1f3d..c32689e4043 100644
--- a/intern/ghost/intern/GHOST_WindowManager.h
+++ b/intern/ghost/intern/GHOST_WindowManager.h
@@ -115,11 +115,9 @@ class GHOST_WindowManager {
/**
* Return a vector of the windows currently managed by this
* class.
- * \warning It is very dangerous to mess with the contents of
- * this vector. Please do not destroy or add windows use the
- * interface above for this,
+ * \return Const reference to the vector of windows managed
*/
- std::vector<GHOST_IWindow *> &getWindows();
+ const std::vector<GHOST_IWindow *> &getWindows() const;
/**
* Finds the window associated with an OS window object/handle
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index 29f3eee7cce..db40075e6ca 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -31,11 +31,6 @@ class GHOST_SystemNULL;
class GHOST_WindowNULL : public GHOST_Window {
public:
- const GHOST_TabletData *GetTabletData()
- {
- return NULL;
- }
-
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor)
{
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index d9342de4d69..6332ce584d2 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -48,11 +48,6 @@ class GHOST_WindowSDL : public GHOST_Window {
SDL_Cursor *m_sdl_custom_cursor;
public:
- const GHOST_TabletData *GetTabletData()
- {
- return NULL;
- }
-
GHOST_WindowSDL(GHOST_SystemSDL *system,
const STR_String &title,
GHOST_TInt32 left,
diff --git a/intern/ghost/intern/GHOST_WindowViewCocoa.h b/intern/ghost/intern/GHOST_WindowViewCocoa.h
index cee40924b73..14c70382916 100644
--- a/intern/ghost/intern/GHOST_WindowViewCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowViewCocoa.h
@@ -154,6 +154,11 @@
systemCocoa->handleMouseEvent(event);
}
+- (void)smartMagnifyWithEvent:(NSEvent *)event
+{
+ systemCocoa->handleMouseEvent(event);
+}
+
- (void)rotateWithEvent:(NSEvent *)event
{
systemCocoa->handleMouseEvent(event);
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index fd9e0240b1b..2ab0e837efb 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -89,8 +89,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
{
// Initialize tablet variables
memset(&m_wintab, 0, sizeof(m_wintab));
- memset(&m_tabletData, 0, sizeof(m_tabletData));
- m_tabletData.Active = GHOST_kTabletModeNone;
+ m_tabletData = GHOST_TABLET_DATA_DEFAULT;
// Create window
if (state != GHOST_kWindowStateFullScreen) {
@@ -645,6 +644,9 @@ GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
hWndToRaise = ::GetWindow(m_hWnd, GW_HWNDNEXT); /* the window to raise */
}
else {
+ if (getState() == GHOST_kWindowStateMinimized) {
+ setState(GHOST_kWindowStateNormal);
+ }
hWndInsertAfter = HWND_TOP;
hWndToRaise = NULL;
}
@@ -1085,10 +1087,7 @@ void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData)
m_tabletData = *pTabletData;
}
else {
- m_tabletData.Active = GHOST_kTabletModeNone;
- m_tabletData.Pressure = 1.0f;
- m_tabletData.Xtilt = 0.0f;
- m_tabletData.Ytilt = 0.0f;
+ m_tabletData = GHOST_TABLET_DATA_DEFAULT;
}
}
@@ -1150,8 +1149,6 @@ void GHOST_WindowWin32::processWin32TabletInitEvent()
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
}
}
-
- m_tabletData.Active = GHOST_kTabletModeNone;
}
m_tabletData.Active = GHOST_kTabletModeNone;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index f72f03855fd..4795539e0f9 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -392,9 +392,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
- const GHOST_TabletData *GetTabletData()
+ const GHOST_TabletData &GetTabletData()
{
- return &m_tabletData;
+ return m_tabletData;
}
void setTabletData(GHOST_TabletData *tabletData);
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index ae8d705fe4a..349b11728bd 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -25,6 +25,7 @@
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
+#include <X11/Xmd.h>
#ifdef WITH_X11_ALPHA
# include <X11/extensions/Xrender.h>
#endif
@@ -38,8 +39,9 @@
# include "GHOST_DropTargetX11.h"
#endif
-#if defined(WITH_GL_EGL)
+#ifdef WITH_GL_EGL
# include "GHOST_ContextEGL.h"
+# include <EGL/eglext.h>
#else
# include "GHOST_ContextGLX.h"
#endif
@@ -101,6 +103,18 @@ enum {
#define _NET_WM_STATE_ADD 1
// #define _NET_WM_STATE_TOGGLE 2 // UNUSED
+#ifdef WITH_GL_EGL
+
+static XVisualInfo *x11_visualinfo_from_egl(Display *display)
+{
+ int num_visuals;
+ XVisualInfo vinfo_template;
+ vinfo_template.screen = DefaultScreen(display);
+ return XGetVisualInfo(display, VisualScreenMask, &vinfo_template, &num_visuals);
+}
+
+#else
+
static XVisualInfo *x11_visualinfo_from_glx(Display *display,
bool stereoVisual,
bool needAlpha,
@@ -124,11 +138,11 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
return NULL;
}
glx_version = glx_major * 100 + glx_minor;
-#ifndef WITH_X11_ALPHA
+# ifndef WITH_X11_ALPHA
(void)glx_version;
-#endif
+# endif
-#ifdef WITH_X11_ALPHA
+# ifdef WITH_X11_ALPHA
if (needAlpha && glx_version >= 103 &&
(glXChooseFBConfig || (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB(
(const GLubyte *)"glXChooseFBConfig")) != NULL) &&
@@ -170,7 +184,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
}
}
else
-#endif
+# endif
{
/* legacy, don't use extension */
GHOST_X11_GL_GetAttributes(glx_attribs, 64, stereoVisual, needAlpha, false);
@@ -194,6 +208,8 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
return NULL;
}
+#endif // WITH_GL_EGL
+
GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
Display *display,
const STR_String &title,
@@ -230,8 +246,13 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
m_is_debug_context(is_debug)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
+#ifdef WITH_GL_EGL
+ m_visualInfo = x11_visualinfo_from_egl(m_display);
+ (void)alphaBackground;
+#else
m_visualInfo = x11_visualinfo_from_glx(
m_display, stereoVisual, alphaBackground, (GLXFBConfig *)&m_fbconfig);
+#endif
}
else {
XVisualInfo tmp = {0};
@@ -478,7 +499,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
#ifdef WITH_X11_XINPUT
refreshXInputDevices();
- m_tabletData.Active = GHOST_kTabletModeNone;
+ m_tabletData = GHOST_TABLET_DATA_DEFAULT;
#endif
/* now set up the rendering context. */
@@ -1318,17 +1339,40 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
#endif
const int profile_mask =
-#if defined(WITH_GL_PROFILE_CORE)
+#ifdef WITH_GL_EGL
+# if defined(WITH_GL_PROFILE_CORE)
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT;
+# elif defined(WITH_GL_PROFILE_COMPAT)
+ EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT;
+# else
+# error // must specify either core or compat at build time
+# endif
+#else
+# if defined(WITH_GL_PROFILE_CORE)
GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
-#elif defined(WITH_GL_PROFILE_COMPAT)
+# elif defined(WITH_GL_PROFILE_COMPAT)
GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
-#else
-# error // must specify either core or compat at build time
+# else
+# error // must specify either core or compat at build time
+# endif
#endif
GHOST_Context *context;
for (int minor = 5; minor >= 0; --minor) {
+#ifdef WITH_GL_EGL
+ context = new GHOST_ContextEGL(
+ m_wantStereoVisual,
+ EGLNativeWindowType(m_window),
+ EGLNativeDisplayType(m_display),
+ profile_mask,
+ 4,
+ minor,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS |
+ (m_is_debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0),
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+#else
context = new GHOST_ContextGLX(m_wantStereoVisual,
m_window,
m_display,
@@ -1339,6 +1383,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_GLX_CONTEXT_FLAGS |
(m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+#endif
if (context->initializeDrawingContext())
return context;
@@ -1346,6 +1391,18 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
delete context;
}
+#ifdef WITH_GL_EGL
+ context = new GHOST_ContextEGL(m_wantStereoVisual,
+ EGLNativeWindowType(m_window),
+ EGLNativeDisplayType(m_display),
+ profile_mask,
+ 3,
+ 3,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS |
+ (m_is_debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0),
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+#else
context = new GHOST_ContextGLX(m_wantStereoVisual,
m_window,
m_display,
@@ -1356,6 +1413,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_GLX_CONTEXT_FLAGS |
(m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
+#endif
if (context->initializeDrawingContext())
return context;
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index faf3acba234..a9914d88340 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -145,14 +145,9 @@ class GHOST_WindowX11 : public GHOST_Window {
*/
Window getXWindow();
#ifdef WITH_X11_XINPUT
- GHOST_TabletData *GetTabletData()
+ GHOST_TabletData &GetTabletData()
{
- return &m_tabletData;
- }
-#else // WITH_X11_XINPUT
- const GHOST_TabletData *GetTabletData()
- {
- return NULL;
+ return m_tabletData;
}
#endif // WITH_X11_XINPUT
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index b1a0eda0e22..2a4ae5355a0 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -231,6 +231,10 @@ extern const char *(*MEM_name_ptr)(void *vmemh);
void MEM_use_guarded_allocator(void);
#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifdef __cplusplus
/* alloc funcs for C++ only */
# define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \
public: \
@@ -253,6 +257,13 @@ void MEM_use_guarded_allocator(void);
MEM_freeN(mem); \
}
+/* Needed when type includes a namespace, then the namespace should not be
+ * specified after ~, so using a macro fails. */
+template<class T> inline void OBJECT_GUARDED_DESTRUCTOR(T *what)
+{
+ what->~T();
+}
+
# if defined __GNUC__
# define OBJECT_GUARDED_NEW(type, args...) new (MEM_mallocN(sizeof(type), __func__)) type(args)
# else
@@ -262,15 +273,20 @@ void MEM_use_guarded_allocator(void);
# define OBJECT_GUARDED_DELETE(what, type) \
{ \
if (what) { \
- ((type *)(what))->~type(); \
+ OBJECT_GUARDED_DESTRUCTOR((type *)what); \
MEM_freeN(what); \
} \
} \
(void)0
-#endif /* __cplusplus */
-
-#ifdef __cplusplus
-}
+# define OBJECT_GUARDED_SAFE_DELETE(what, type) \
+ { \
+ if (what) { \
+ OBJECT_GUARDED_DESTRUCTOR((type *)what); \
+ MEM_freeN(what); \
+ what = NULL; \
+ } \
+ } \
+ (void)0
#endif /* __cplusplus */
#endif /* __MEM_GUARDEDALLOC_H__ */
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index fa2d0d1e334..d24437c85f2 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -70,6 +70,9 @@ const char *(*MEM_name_ptr)(void *vmemh) = MEM_lockfree_name_ptr;
void *aligned_malloc(size_t size, size_t alignment)
{
+ /* posix_memalign requires alignment to be a multiple of sizeof(void *). */
+ assert(alignment >= ALIGNED_MALLOC_MINIMUM_ALIGNMENT);
+
#ifdef _WIN32
return _aligned_malloc(size, alignment);
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c
index ef74f394fb1..de2b2eee93a 100644
--- a/intern/guardedalloc/intern/mallocn_guarded_impl.c
+++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c
@@ -735,8 +735,19 @@ void MEM_guarded_printmemlist_stats(void)
mem_lock_thread();
- /* put memory blocks into array */
- printblock = malloc(sizeof(MemPrintBlock) * totblock);
+ if (totblock != 0) {
+ /* put memory blocks into array */
+ printblock = malloc(sizeof(MemPrintBlock) * totblock);
+
+ if (UNLIKELY(!printblock)) {
+ mem_unlock_thread();
+ print_error("malloc returned null while generating stats");
+ return;
+ }
+ }
+ else {
+ printblock = NULL;
+ }
pb = printblock;
totpb = 0;
@@ -745,7 +756,7 @@ void MEM_guarded_printmemlist_stats(void)
if (membl)
membl = MEMNEXT(membl);
- while (membl) {
+ while (membl && pb) {
pb->name = membl->name;
pb->len = membl->len;
pb->items = 1;
@@ -767,7 +778,10 @@ void MEM_guarded_printmemlist_stats(void)
}
/* sort by name and add together blocks with the same name */
- qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name);
+ if (totpb > 1) {
+ qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name);
+ }
+
for (a = 0, b = 0; a < totpb; a++) {
if (a == b) {
continue;
@@ -784,7 +798,10 @@ void MEM_guarded_printmemlist_stats(void)
totpb = b + 1;
/* sort by length and print */
- qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
+ if (totpb > 1) {
+ qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
+ }
+
printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use / (double)(1024 * 1024));
printf("peak memory len: %.3f MB\n", (double)peak_mem / (double)(1024 * 1024));
printf("slop memory len: %.3f MB\n", (double)mem_in_use_slop / (double)(1024 * 1024));
@@ -796,7 +813,10 @@ void MEM_guarded_printmemlist_stats(void)
(double)pb->len / 1024.0 / (double)pb->items,
pb->name);
}
- free(printblock);
+
+ if (printblock != NULL) {
+ free(printblock);
+ }
mem_unlock_thread();
diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h
index e6e090703d4..876607fdb77 100644
--- a/intern/guardedalloc/intern/mallocn_intern.h
+++ b/intern/guardedalloc/intern/mallocn_intern.h
@@ -107,6 +107,8 @@ size_t malloc_usable_size(void *ptr);
#include "mallocn_inline.h"
+#define ALIGNED_MALLOC_MINIMUM_ALIGNMENT sizeof(void *)
+
void *aligned_malloc(size_t size, size_t alignment);
void aligned_free(void *ptr);
diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
index e8fd8de738b..87091bb9862 100644
--- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c
+++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
@@ -346,7 +346,17 @@ void *MEM_lockfree_malloc_arrayN(size_t len, size_t size, const char *str)
void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str)
{
- MemHeadAligned *memh;
+ /* Huge alignment values doesn't make sense and they wouldn't fit into 'short' used in the
+ * MemHead. */
+ assert(alignment < 1024);
+
+ /* We only support alignments that are a power of two. */
+ assert(IS_POW2(alignment));
+
+ /* Some OS specific aligned allocators require a certain minimal alignment. */
+ if (alignment < ALIGNED_MALLOC_MINIMUM_ALIGNMENT) {
+ alignment = ALIGNED_MALLOC_MINIMUM_ALIGNMENT;
+ }
/* It's possible that MemHead's size is not properly aligned,
* do extra padding to deal with this.
@@ -356,17 +366,10 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
*/
size_t extra_padding = MEMHEAD_ALIGN_PADDING(alignment);
- /* Huge alignment values doesn't make sense and they
- * wouldn't fit into 'short' used in the MemHead.
- */
- assert(alignment < 1024);
-
- /* We only support alignment to a power of two. */
- assert(IS_POW2(alignment));
-
len = SIZET_ALIGN_4(len);
- memh = (MemHeadAligned *)aligned_malloc(len + extra_padding + sizeof(MemHeadAligned), alignment);
+ MemHeadAligned *memh = (MemHeadAligned *)aligned_malloc(
+ len + extra_padding + sizeof(MemHeadAligned), alignment);
if (LIKELY(memh)) {
/* We keep padding in the beginning of MemHead,
diff --git a/intern/libmv/CMakeLists.txt b/intern/libmv/CMakeLists.txt
index f587aee615b..1801751523a 100644
--- a/intern/libmv/CMakeLists.txt
+++ b/intern/libmv/CMakeLists.txt
@@ -133,9 +133,11 @@ if(WITH_LIBMV)
intern/image.h
intern/logging.h
intern/reconstruction.h
+ intern/region.h
intern/track_region.h
intern/tracks.h
intern/tracksN.h
+ intern/utildefines.h
libmv/autotrack/autotrack.h
libmv/autotrack/callbacks.h
libmv/autotrack/frame_accessor.h
diff --git a/intern/libmv/bundle.sh b/intern/libmv/bundle.sh
index 2601a2d6754..48da102b801 100755
--- a/intern/libmv/bundle.sh
+++ b/intern/libmv/bundle.sh
@@ -174,9 +174,11 @@ ${third_sources}
intern/image.h
intern/logging.h
intern/reconstruction.h
+ intern/region.h
intern/track_region.h
intern/tracks.h
intern/tracksN.h
+ intern/utildefines.h
${headers}
${third_headers}
diff --git a/release/datafiles/bfont.ttf b/release/datafiles/bfont.ttf
index 2217f9d1aad..7cb06a988ed 100644
--- a/release/datafiles/bfont.ttf
+++ b/release/datafiles/bfont.ttf
Binary files differ
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index 6a87ac0adaa..ebebc82695a 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -1048,6 +1048,9 @@
</linearGradient>
+ <filter color-interpolation-filters="sRGB" inkscape:collect="always" id="filter15613" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
+ <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615"/>
+ </filter>
<linearGradient id="linearGradient37542-55">
<stop id="stop37544-61" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
<stop id="stop37546-03" offset="1" style="stop-color:#ffffff;stop-opacity:1;"/>
@@ -1062,6 +1065,9 @@
</linearGradient>
+ <filter color-interpolation-filters="sRGB" inkscape:collect="always" id="filter15613-8" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
+ <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-1"/>
+ </filter>
<filter color-interpolation-filters="sRGB" inkscape:label="Greyscale" id="filter15388">
@@ -1321,6 +1327,14 @@
<radialGradient inkscape:collect="always" xlink:href="#linearGradient16595" id="radialGradient52883-6-8-3" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.39420438,-0.08239205,0.27256031,1.3040635,-362.22886,-161.73912)" cx="-302.79681" cy="462.0358" fx="-302.79681" fy="462.0358" r="8"/>
+ <filter style="color-interpolation-filters:sRGB" inkscape:collect="always" id="filter15613-7" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
+ <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-4"/>
+ </filter>
+
+
+ <filter style="color-interpolation-filters:sRGB" inkscape:collect="always" id="filter15613-8-8" x="-0.092011765" width="1.1840235" y="-0.097762503" height="1.1955251">
+ <feGaussianBlur inkscape:collect="always" stdDeviation="0.65175" id="feGaussianBlur15615-1-5"/>
+ </filter>
<filter style="color-interpolation-filters:sRGB" inkscape:label="Greyscale" id="filter15388-0">
@@ -3732,6 +3746,14 @@
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 449.50391,369 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 455 c 1.08333,0 2.07323,-0.26796 2.8125,-0.85938 C 458.55177,379.54921 459,378.625 459,377.5 c 0,-1.125 -0.44823,-2.04921 -1.1875,-2.64062 -0.49098,-0.39279 -1.11527,-0.59695 -1.78125,-0.72071 C 456.61178,373.63193 457,372.89881 457,372 c 0,-0.96354 -0.41934,-1.76349 -1.07422,-2.26758 C 455.27091,369.22833 454.41324,369 453.5,369 Z m 0.5,1 H 453.5 c 0.74361,0 1.38549,0.19369 1.81641,0.52539 0.43091,0.3317 0.68359,0.7813 0.68359,1.47461 0,0.69331 -0.25268,1.14291 -0.68359,1.47461 C 454.88549,373.80631 454.24361,374 453.5,374 h -3.49609 z m 0,5 h 3.46093 0.0352 1.5 c 0.91667,0 1.67677,0.23204 2.1875,0.64062 0.51073,0.40859 0.8125,0.98438 0.8125,1.85938 0,0.875 -0.30177,1.45079 -0.8125,1.85938 C 456.67677,379.76796 455.91667,380 455,380 h -4.99609 z" id="path10949-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccscsccscsccscscscccccscscscc"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 408.50391,369 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.91992 a 0.50005,0.50005 0 0 0 0,0.16211 V 380.5 a 0.50005,0.50005 0 1 0 1,0 V 376 h 3.25586 l 3.84961,4.8125 a 0.50024018,0.50024018 0 1 0 0.78124,-0.625 l -3.49414,-4.36914 c 1.48603,-0.40423 2.60743,-1.70768 2.60743,-3.31836 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0.5,1 h 3.5 c 1.38662,0 2.5,1.11337 2.5,2.5 0,1.38663 -1.11338,2.5 -2.5,2.5 a 0.50005,0.50005 0 0 0 -0.004,0 h -3.49609 z" id="path13132" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="M 431.51758,369.26562 C 429.42795,369.91461 428,371.85293 428,374.04102 V 376 c 0,1.78552 0.9537,3.43731 2.5,4.33008 1.54631,0.89277 3.45369,0.89277 5,0 1.5463,-0.89277 2.5,-2.54456 2.5,-4.33008 v -0.5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -4 a 0.50004997,0.50004997 0 1 0 0,1 h 3.5 c 0,1.42986 -0.7617,2.74991 -2,3.46484 -1.23829,0.71494 -2.76171,0.71494 -4,0 -1.2383,-0.71493 -2,-2.03498 -2,-3.46484 v -1.95898 c 0,-1.75422 1.13918,-3.30002 2.81445,-3.82032 1.69498,-0.52641 3.36746,-0.003 4.25196,1.5293 a 0.50050004,0.50050004 0 1 0 0.86718,-0.5 c -1.1155,-1.93212 -3.34609,-2.62724 -5.41601,-1.98438 z" id="path13141" inkscape:connector-curvature="0"/>
+ <g style="display:inline;fill:#ffffff;enable-background:new" id="g13321" transform="translate(-42.000002,21.000005)">
+ <g id="g13309" style="fill:#ffffff">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 365.49219,94.992188 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.004,0.0059 l -1.95313,1.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707032 L 365,96.707031 V 98.5 a 0.50005,0.50005 0 1 0 1,0 v -1.792969 l 1.14648,1.146485 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 l -1.95704,-1.957031 a 0.50005,0.50005 0 0 0 -0.40429,-0.197265 z m 9.05859,1.941406 a 0.50005,0.50005 0 0 0 -0.0586,0.0059 h -2.93164 a 0.50005,0.50005 0 1 0 0,1 h 1.79297 l -3.14649,3.146486 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3.14649,-3.146485 v 1.792965 a 0.50005,0.50005 0 1 0 1,0 v -2.931637 a 0.50005,0.50005 0 0 0 -0.50977,-0.574218 z m -0.0566,7.060546 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 375.29297,106 H 371.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z" id="path13047-6" inkscape:connector-curvature="0"/>
+ </g>
+ <g id="g13313" style="fill:#ffffff">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98000004;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 324.5,121 c -1.14583,0 -1.86235,0.56478 -2.18359,1.12695 C 321.99517,122.68912 322,123.25 322,123.25 V 125 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 327 v -1.75 c 0,0 0.005,-0.56088 -0.31641,-1.12305 C 326.36235,121.56478 325.64583,121 324.5,121 Z m 0,1 c 0.85417,0 1.13765,0.31022 1.31641,0.62305 C 325.99517,122.93588 326,123.25 326,123.25 V 125 h -3 v -1.75 c 0,0 0.005,-0.31412 0.18359,-0.62695 C 323.36235,122.31022 323.64583,122 324.5,122 Z m -0.5,4 h 1 v 2 h -1 z" transform="translate(42.000002,-21.000005)" id="rect13261" inkscape:connector-curvature="0"/>
+ </g>
+ </g>
<g inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" id="g13337" style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" transform="matrix(-1,0,0,1,1458,302.99979)">
<path style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1262.5,-278.49979 h -13 v -13 h 13 v 13" id="path14450" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 1257.5039,-287 c -0.191,-10e-4 -0.3661,0.1063 -0.4512,0.27734 l -3,6 c -0.1652,0.33223 0.076,0.72231 0.4473,0.72266 h 6 c 0.371,-3.5e-4 0.6125,-0.39043 0.4473,-0.72266 l -3,-6 c -0.084,-0.16853 -0.2552,-0.27571 -0.4434,-0.27734 z" id="path13331" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc"/>
@@ -3809,6 +3831,11 @@
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 237.49219,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 306 h 3 v 12 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -1.5 v -12 h 3 v 1.5 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 7,6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 V 312 h 2 v 6 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -6 h 2 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z" id="path6924-7" inkscape:connector-curvature="0"/>
</g>
<path inkscape:connector-curvature="0" d="m 353,628 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m 9,-3 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="path14337"/>
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 374.4375,121.17773 c -0.55229,-0.19531 -1.19407,-0.23097 -1.84766,0.002 -0.65359,0.23293 -1.30733,0.71399 -1.9707,1.49609 -0.28137,0.33173 -0.45085,0.79694 -0.61914,1.24219 -0.17701,-0.45587 -0.36207,-0.94012 -0.61914,-1.24219 -0.66249,-0.77846 -1.31558,-1.25837 -1.96875,-1.49023 -0.65317,-0.23186 -1.2953,-0.19616 -1.84766,-0.002 -1.10471,0.38842 -1.89002,1.32506 -2.44922,1.9961 a 0.50064603,0.50064603 0 1 0 0.76954,0.64062 c 0.54481,-0.65377 1.26345,-1.43095 2.00976,-1.69336 0.37316,-0.1312 0.7444,-0.1559 1.18359,0 0.4392,0.1559 0.95757,0.51168 1.54102,1.19727 0.19894,0.23376 0.56603,0.91963 0.64063,1.27734 A 0.50005,0.50005 0 0 0 369.75,125 h 0.5 a 0.50005,0.50005 0 0 0 0.49023,-0.40234 c 0.0736,-0.37229 0.37785,-0.96363 0.64063,-1.27344 0.58467,-0.68931 1.10595,-1.04668 1.54492,-1.20313 0.43897,-0.15644 0.80714,-0.13175 1.17969,0 0.74509,0.2635 1.46354,1.04375 2.00976,1.69922 a 0.50064603,0.50064603 0 1 0 0.76954,-0.64062 c -0.55904,-0.67084 -1.34269,-1.61133 -2.44727,-2.00196 z" id="path17826-1" inkscape:connector-curvature="0"/>
+ <g style="display:inline;fill:#ffffff;enable-background:new" id="g14433" transform="rotate(-90,380.52904,134)">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 390.04688,140.46484 a 0.50005,0.50005 0 0 0 -0.41797,0.20704 l -2.95508,3.93945 a 0.50005,0.50005 0 0 0 -0.01,0.70703 l 2.96485,3.95312 a 0.50019216,0.50019216 0 1 0 0.80078,-0.5996 l -2.40039,-3.20118 h 7.1914 l -0.63867,1.27735 a 0.50005635,0.50005635 0 1 0 0.89453,0.44726 l 0.96875,-1.93554 a 0.50005,0.50005 0 0 0 -0.006,-0.58399 l -0.96289,-1.92773 a 0.50005635,0.50005635 0 1 0 -0.89453,0.44726 l 0.63867,1.27539 h -7.1914 l 2.40039,-3.19922 a 0.50005,0.50005 0 0 0 -0.38281,-0.80664 z" id="path17796-5" inkscape:connector-curvature="0"/>
+ </g>
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 348.5,120 c -1.47879,0 -2.81353,0.43206 -3.80469,1.06641 C 343.70416,121.70075 343,122.54357 343,123.5 c 0,1.02778 0.79097,1.88608 1.87891,2.49805 1.08228,0.60878 2.52394,0.99597 4.09765,1 0.0129,9.4e-4 3.75669,0.27336 6.02344,-2.21094 V 127.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4.25 a 0.50005,0.50005 0 1 0 0,1 h 3.10156 c -1.87731,2.16501 -5.32031,2 -5.32031,2 A 0.50005,0.50005 0 0 0 349,126 c -1.41667,0 -2.71684,-0.36001 -3.62891,-0.87305 C 344.45903,124.61392 344,123.97222 344,123.5 c 0,-0.41012 0.41561,-1.06779 1.23438,-1.5918 C 346.05313,121.38419 347.21846,121 348.5,121 a 0.50005,0.50005 0 1 0 0,-1 z" id="path18766-5" inkscape:connector-curvature="0"/>
<g style="display:inline;fill:#ffffff;enable-background:new" id="g12950" transform="translate(-42.000002,4.4999696e-6)">
<g id="g12531-9" transform="translate(-209.00718,-44.00717)" style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 446.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452.4707 447.5 Z m 4.50718,10.00717 L 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z" id="path12529-5" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccc"/>
@@ -4137,6 +4164,66 @@
<g transform="translate(41.999999,42.000005)" style="display:inline;opacity:1;fill:#ffffff;enable-background:new" id="g22961">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 534.49219,599 C 534.2199,599 534,599.223 534,599.5 v 1.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 3 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.5 c 0,0.277 0.2199,0.5 0.49219,0.5 h 0.0156 C 534.7801,608 535,607.777 535,607.5 v -8 c 0,-0.277 -0.2199,-0.5 -0.49219,-0.5 z m 1.25781,1 v 7 H 537 c 1.69468,0 3,-1.30532 3,-3 v -1 c 0,-1.69468 -1.30532,-3 -3,-3 z" transform="translate(-41.999999,-42.000005)" id="path22706-5" inkscape:connector-curvature="0"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 499.48633,561.02734 c -0.55718,0.017 -0.67407,0.7946 -0.14649,0.97461 1.47614,0.5388 2.51343,1.91841 2.64454,3.53711 0.13105,1.61806 -0.67507,3.15416 -2.04493,3.94532 C 499.32404,569.8398 498.6905,570 498,570 h -9 v 1 h 9 c 0.84916,0 1.67422,-0.20648 2.43945,-0.64844 1.70819,-0.98656 2.70486,-2.89381 2.54297,-4.89258 -0.16183,-1.99811 -1.44941,-3.72267 -3.30078,-4.39843 -0.0622,-0.024 -0.12865,-0.0353 -0.19531,-0.0332 z" id="path22783-2-0" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc"/>
+ <g style="display:inline;enable-background:new" id="g25540" transform="translate(582,-1322)">
+ <g id="g25433" style="display:inline;enable-background:new">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -449.5,1609 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06836 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.35352,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 3.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z" id="path25304" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccccccccccccccc"/>
+ <circle style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="circle25308" cx="-443" cy="1608" r="1.5" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96"/>
+ </g>
+ <g id="g25466" style="display:inline;enable-background:new">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -365.49219,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 2.63867 c 0.0948,-0.3549 0.23771,-0.6892 0.42188,-1 z m 9.92383,0 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -9.92383,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06055 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.34571,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.34571,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z" id="path25334" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccc"/>
+ <circle style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="circle25338" cx="359" cy="-1613.0002" r="1.5" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" transform="scale(-1)"/>
+ </g>
+ <g id="g25449" style="display:inline;enable-background:new">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -406.5,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 3.93164,3 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 h 7.63867 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0.42188,3 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 8.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -4.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z" id="path25345" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccc"/>
+ <circle style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="circle25349" cx="-406" cy="-1613.0002" r="1.5" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" transform="scale(1,-1)"/>
+ </g>
+ <g transform="matrix(1,0,0,-1,21,3226.0001)" id="g25439" style="display:inline;enable-background:new">
+ <path sodipodi:nodetypes="ccccccccccccccccccccccccc" inkscape:connector-curvature="0" id="path25435" d="m -449.5,1609 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06836 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.35352,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 3.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
+ <circle inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" r="1.5" cy="1608" cx="-443" id="circle25437" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
+ </g>
+ <g transform="matrix(-1,0,0,1,-781.00069,0)" id="g25455" style="display:inline;enable-background:new">
+ <path sodipodi:nodetypes="cccccccccccccccccccc" inkscape:connector-curvature="0" id="path25451" d="m -406.5,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 3.93164,3 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 h 7.63867 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0.42188,3 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 8.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -4.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"/>
+ <circle transform="scale(1,-1)" inkscape:export-ydpi="96" inkscape:export-xdpi="96" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" r="1.5" cy="-1613.0002" cx="-406" id="circle25453" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"/>
+ </g>
+ </g>
+ <g transform="translate(791,-1295)" style="display:inline;enable-background:new" id="g25378-9">
+ <g transform="translate(1,-1)" id="g26210-2">
+ <path inkscape:connector-curvature="0" id="path24970-9" d="m -511.49974,1278.4919 -2.6e-4,-2.1822 c 2e-5,-2.8698 1.14768,-5.4099 3,-6.8448 1.85234,-1.4349 4.14766,-1.4349 6,0 1.85233,1.4349 2.99998,4.0575 3,6.9272 v 2.0998" style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" sodipodi:nodetypes="ccsccc"/>
+ <g transform="translate(-729.00712,939.005)" style="opacity:1" id="g24984-6">
+ <path sodipodi:nodetypes="cccccccccc" id="path24980-2" style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" d="m 228.50712,326.49495 h 2 v 2 h -2 z m -10.00994,0 h -2 v 2 h 2 z" inkscape:connector-curvature="0"/>
+ <path id="path24982-2" style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" d="m 228.5043,327.5 -2.49718,-0.005 M 218.5,327.5 l 2.50712,-0.005" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc"/>
+ </g>
+ <rect style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" id="rect24986-0" width="1.9999762" height="2" x="-506.5" y="1265.5" rx="0" ry="0"/>
+ </g>
+ <g transform="translate(-21,-64)" id="g25924-0">
+ <path sodipodi:nodetypes="ccsccc" style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m -511.49974,1341.4919 -2.6e-4,-2.1822 c 2e-5,-2.8698 1.14768,-5.4099 3,-6.8448 1.85234,-1.4349 4.14766,-1.4349 6,0 1.85233,1.4349 2.99998,4.0575 3,6.9272 v 2.0998" id="path25802-2" inkscape:connector-curvature="0"/>
+ <rect ry="0" rx="0" y="1329.5" x="-504.5" height="2" width="1.9999762" id="rect25810-8" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"/>
+ </g>
+ <g transform="matrix(1,0,0,-1,-21,2604.9941)" id="g25919-9">
+ <path sodipodi:nodetypes="ccccc" id="path25812-9" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" d="m -464.5,1340.5001 v -2 h 2 v 2 z" inkscape:connector-curvature="0"/>
+ <path sodipodi:nodetypes="cccc" id="path25814-0" style="display:inline;overflow:visible;visibility:visible;opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m -463.25,1339 5.75,-11.4994 m -6.25,11.4994 -5.75,-11.4994" inkscape:connector-curvature="0"/>
+ </g>
+ <g transform="matrix(-1,0,0,1,-968.99001,-84)" id="g25915-9">
+ <path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" d="m -503.5,1348.5 h -2 v 2 h 2 z" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" id="path25851-1"/>
+ <path sodipodi:nodetypes="csc" inkscape:connector-curvature="0" id="path25853-8" d="m -498.49506,1361.4978 -2.00459,-2.0055 c -2.16266,-2.1636 -3.0003,-5.1361 -3.0003,-7.9852 l 0.01,-1.0071" style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"/>
+ <path style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" d="m -511.5049,1361.4907 c 0,-2.8491 0.8375,-5.8217 3.0003,-7.9852 L -505.5,1350.5" id="path25855-4" inkscape:connector-curvature="0" sodipodi:nodetypes="csc"/>
+ <g id="g25861-1" transform="translate(-47,-2)">
+ <path sodipodi:nodetypes="ccccc" id="path25857-8" style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" d="m -457.50994,1358.5 h -2 v 2 h 2 z" inkscape:connector-curvature="0"/>
+ <path id="path25859-9" style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" d="m -458.5,1358 v -3" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
+ </g>
+ <g transform="rotate(90,-479.5,1328.5)" id="g25873-3">
+ <path inkscape:connector-curvature="0" d="m -457.50994,1359.5 h -2 v 2 h 2 z" style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="path25869-0" sodipodi:nodetypes="ccccc"/>
+ <path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" d="m -458.5,1359 v -3" style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" id="path25871-3"/>
+ </g>
+ </g>
+ <g id="g25347-2">
+ <g transform="translate(-43,-61)" id="g25301-4">
+ <path sodipodi:nodetypes="ccsccc" style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" d="m -510.49974,1338.4932 -2.6e-4,-0.2387 c 0,-2.5685 1.14768,-5.2795 3,-6.6953 1.85233,-1.4159 4.14765,-1.4159 5.99999,0 1.85233,1.4158 3,4.1268 3,6.6953 v 0.2387" id="path25297-7" inkscape:connector-curvature="0"/>
+ <rect ry="0" rx="0" y="1328.5" x="-503.5" height="2" width="1.9999762" id="rect25299-7" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"/>
+ </g>
+ <path sodipodi:nodetypes="ccccccccccccccc" id="path25355-6-1" style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" d="m -554,1265 h 3 v -1 h -3 z m 5,0 h 3 v -1 h -3 z m 5,0 h 3 v -1 h -3 z" inkscape:connector-curvature="0"/>
+ </g>
+ </g>
</g>
<g style="display:inline;fill:#ffffff;enable-background:new" transform="rotate(-180,349.00525,417)" id="g22180" inkscape:export-filename="C:\Users\Andrzej Ambroż\Desktop\mtrx.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m 324.95117,410.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 2.83908,0.33401 5.63985,-1.05664 6.5332,-3.3125 a 0.50005,0.50005 0 1 0 -0.92969,-0.36718 c -0.67177,1.69632 -3.05327,2.97373 -5.48633,2.6875 -1.98998,-0.23411 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 c -0.31249,0.377 -0.92604,0.69672 -1.66015,0.78906 a 0.50005,0.50005 0 1 0 0.125,0.99219 c 0.94034,-0.11828 1.77818,-0.50935 2.30469,-1.14453 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z" id="path22178" inkscape:connector-curvature="0"/>
@@ -5348,6 +5435,23 @@
<path sodipodi:nodetypes="csssscccccc" inkscape:connector-curvature="0" id="path28911-6" transform="translate(540,1)" d="m 7,654 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 H 8 v -8 z" style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"/>
<path sodipodi:nodetypes="ssccccsssccccc" inkscape:connector-curvature="0" style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" d="m 8,670 c -0.54532,0 -1,0.45468 -1,1 v 3 h 1 12 1 v -3 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 H 8 Z" transform="translate(540,-20)" id="path28913-4"/>
</g>
+ <g id="g25642" transform="translate(-63,-20)" style="display:inline;fill:#ffffff;fill-opacity:1;enable-background:new">
+ <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m -33.5,1328 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 11 c 3e-5,0.2761 0.22387,0.5 0.5,0.5 h 2.5 v -3 c 0,-1.645 1.35499,-3 3,-3 h 2.585938 l -1.292969,-1.293 a 1.0001,1.0001 0 0 1 0.726562,-1.7168 1.0001,1.0001 0 0 1 0.6875,0.3028 l 3,3 a 1.0001,1.0001 0 0 1 0,1.414 l -3,3 a 1.0001,1.0001 0 1 1 -1.414062,-1.414 L -25.414062,1336 H -28 c -0.56413,0 -1,0.4359 -1,1 v 3 h 8.5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -9 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 H -29 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z" transform="translate(397,-1232)" id="path25640"/>
+ </g>
+ <g transform="translate(712,-665)" style="display:inline;enable-background:new" id="g25686">
+ <g transform="rotate(-180,-177.49644,1250.0035)" id="g25671">
+ <path inkscape:connector-curvature="0" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -242.00195,1242.9922 c -0.58284,0 -1.10871,0.154 -1.47657,0.5215 -0.36785,0.3675 -0.52148,0.8952 -0.52148,1.4785 V 1248 h 6 v -2.4863 c -0.002,-0.3369 0.17839,-0.7279 0.47461,-1.0254 0.29622,-0.2975 0.68988,-0.4819 1.0293,-0.4844 0.65765,-0.012 0.6539,-0.9937 -0.004,-1 h -0.004 L -239,1243 v 0.4863 c 0.01,0.6762 -1.00956,0.6762 -1,0 v -0.4883 h -1 v 0.4903 c 0.01,0.6762 -1.00956,0.6762 -1,0 v -0.4922 h -0.002 z M -244,1249 v 0.5 c 0,0.2521 0.16407,0.4981 0.5,0.4863 l 1.50195,0.01 -0.002,5.9941 c -0.0191,1.3523 2.01913,1.3523 2,0 l -0.002,-5.9941 1.50195,-0.01 c 0.32137,0 0.5,-0.2464 0.5,-0.4863 v -0.5 z" transform="rotate(180,-208.99644,1250.0035)" id="path25652"/>
+ <g transform="matrix(1,0,0,-1,-61.992879,2500.0212)" id="g25669">
+ <g id="g25662" transform="translate(-17)">
+ <g transform="translate(-2,-2)" id="g25660"/>
+ </g>
+ </g>
+ </g>
+ <g id="g25684" transform="matrix(1,0,0,-1,0,2500.0142)">
+ <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" d="m -232,1242.9863 c -0.50478,0 -1.00956,0.3375 -1,1.0137 v 7 h 2 v -7 c 0.01,-0.6762 -0.49522,-1.0137 -1,-1.0137 z m 0,9.0274 c -1.09865,0 -2,0.9013 -2,2 0,0.8274 -0.13264,1.3367 -0.33203,1.5937 -0.1994,0.257 -0.49978,0.3926 -1.16797,0.3926 -0.11793,0 -0.23139,0.046 -0.32031,0.123 -0.0251,0.022 -0.048,0.046 -0.0684,0.072 -0.0409,0.053 -0.0708,0.1132 -0.0879,0.1777 -0.004,0.016 -0.007,0.033 -0.01,0.049 -0.003,0.017 -0.005,0.034 -0.006,0.051 -0.002,0.033 -7.6e-4,0.067 0.004,0.1 0.005,0.033 0.0138,0.065 0.0254,0.096 0.0107,0.031 0.0244,0.061 0.041,0.09 0.009,0.015 0.0188,0.029 0.0293,0.043 0.0403,0.053 0.0907,0.098 0.14844,0.1308 0.0742,0.043 0.15827,0.067 0.24414,0.068 2.01924,0 3.30957,-0.2641 4.16992,-0.7461 0.85624,-0.4797 1.23067,-1.2322 1.30078,-1.918 0.0175,-0.1066 0.0293,-0.2142 0.0293,-0.3222 0,-1.0987 -0.90135,-2 -2,-2 z" transform="matrix(1,0,0,-1,62.999999,2500.0142)" id="path25673" inkscape:connector-curvature="0" sodipodi:nodetypes="sccccssscscccccccccccccss"/>
+ <g transform="matrix(-1,0,0,1,-263.99995,0)" id="g25682"/>
+ </g>
+ </g>
</g>
<g inkscape:groupmode="layer" id="layer2" inkscape:label="EMPTY ICON TRACKING" style="display:none">
<g id="g16331" style="fill:#ffcc00">
diff --git a/release/datafiles/blender_icons16/icon16_anchor_bottom.dat b/release/datafiles/blender_icons16/icon16_anchor_bottom.dat
new file mode 100644
index 00000000000..e79dfded6ef
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_anchor_bottom.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_anchor_center.dat b/release/datafiles/blender_icons16/icon16_anchor_center.dat
new file mode 100644
index 00000000000..7dfbc8cce3a
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_anchor_center.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_anchor_left.dat b/release/datafiles/blender_icons16/icon16_anchor_left.dat
new file mode 100644
index 00000000000..665291de855
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_anchor_left.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_anchor_right.dat b/release/datafiles/blender_icons16/icon16_anchor_right.dat
new file mode 100644
index 00000000000..fcd2fe6c872
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_anchor_right.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_anchor_top.dat b/release/datafiles/blender_icons16/icon16_anchor_top.dat
new file mode 100644
index 00000000000..fc90b1fed63
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_anchor_top.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_brushes_all.dat b/release/datafiles/blender_icons16/icon16_brushes_all.dat
new file mode 100644
index 00000000000..82840288a39
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_brushes_all.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_folder_redirect.dat b/release/datafiles/blender_icons16/icon16_folder_redirect.dat
new file mode 100644
index 00000000000..90b3498c0fd
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_folder_redirect.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_handle_aligned.dat b/release/datafiles/blender_icons16/icon16_handle_aligned.dat
new file mode 100644
index 00000000000..5b265740449
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_handle_aligned.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_handle_auto.dat b/release/datafiles/blender_icons16/icon16_handle_auto.dat
new file mode 100644
index 00000000000..93e21513010
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_handle_auto.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_handle_autoclamped.dat b/release/datafiles/blender_icons16/icon16_handle_autoclamped.dat
new file mode 100644
index 00000000000..05e3b834710
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_handle_autoclamped.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_handle_free.dat b/release/datafiles/blender_icons16/icon16_handle_free.dat
new file mode 100644
index 00000000000..d3cf9857b53
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_handle_free.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_handle_vector.dat b/release/datafiles/blender_icons16/icon16_handle_vector.dat
new file mode 100644
index 00000000000..4d2e11ff72c
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_handle_vector.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_anchor_bottom.dat b/release/datafiles/blender_icons32/icon32_anchor_bottom.dat
new file mode 100644
index 00000000000..0e56e3c653b
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_anchor_bottom.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_anchor_center.dat b/release/datafiles/blender_icons32/icon32_anchor_center.dat
new file mode 100644
index 00000000000..0f859b7a316
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_anchor_center.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_anchor_left.dat b/release/datafiles/blender_icons32/icon32_anchor_left.dat
new file mode 100644
index 00000000000..354154d1cf6
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_anchor_left.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_anchor_right.dat b/release/datafiles/blender_icons32/icon32_anchor_right.dat
new file mode 100644
index 00000000000..7c7f7987596
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_anchor_right.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_anchor_top.dat b/release/datafiles/blender_icons32/icon32_anchor_top.dat
new file mode 100644
index 00000000000..d4d67ce90c3
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_anchor_top.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_brushes_all.dat b/release/datafiles/blender_icons32/icon32_brushes_all.dat
new file mode 100644
index 00000000000..d224036d082
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_brushes_all.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_folder_redirect.dat b/release/datafiles/blender_icons32/icon32_folder_redirect.dat
new file mode 100644
index 00000000000..45ed10c6f46
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_folder_redirect.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_handle_aligned.dat b/release/datafiles/blender_icons32/icon32_handle_aligned.dat
new file mode 100644
index 00000000000..7793d128216
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_handle_aligned.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_handle_auto.dat b/release/datafiles/blender_icons32/icon32_handle_auto.dat
new file mode 100644
index 00000000000..e8675fb5884
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_handle_auto.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_handle_autoclamped.dat b/release/datafiles/blender_icons32/icon32_handle_autoclamped.dat
new file mode 100644
index 00000000000..0bc5ba6275f
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_handle_autoclamped.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_handle_free.dat b/release/datafiles/blender_icons32/icon32_handle_free.dat
new file mode 100644
index 00000000000..a2ee1527b1d
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_handle_free.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_handle_vector.dat b/release/datafiles/blender_icons32/icon32_handle_vector.dat
new file mode 100644
index 00000000000..78788c56873
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_handle_vector.dat
Binary files differ
diff --git a/release/datafiles/bmonofont.ttf b/release/datafiles/bmonofont.ttf
index e95786a49e4..06235dce116 100644
--- a/release/datafiles/bmonofont.ttf
+++ b/release/datafiles/bmonofont.ttf
Binary files differ
diff --git a/release/datafiles/fonts/bmonofont-i18n.ttf.gz b/release/datafiles/fonts/bmonofont-i18n.ttf.gz
index 1453ad48c6c..2c3e00d1c75 100644
--- a/release/datafiles/fonts/bmonofont-i18n.ttf.gz
+++ b/release/datafiles/fonts/bmonofont-i18n.ttf.gz
Binary files differ
diff --git a/release/datafiles/fonts/droidsans.ttf.gz b/release/datafiles/fonts/droidsans.ttf.gz
index 8cd640ba525..858264142f1 100644
--- a/release/datafiles/fonts/droidsans.ttf.gz
+++ b/release/datafiles/fonts/droidsans.ttf.gz
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 8a05b618f031582c006c6f62b9e60619ab3eef8
+Subproject 74afb3ed35e3271b2609feaf67bea6b8bdffe7c
diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index 147b55f60ef..1eff85b6129 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -339,6 +339,7 @@ const bTheme U_theme_default = {
.bone_solid = RGBA(0xb2b2b2ff),
.bone_pose = RGBA(0x50c8ff50),
.bone_pose_active = RGBA(0x8cffff50),
+ .bone_locked_weight = RGBA(0xff000080),
.cframe = RGBA(0x60c040ff),
.time_keyframe = RGBA(0xddd700ff),
.time_gp_keyframe = RGBA(0xb5e61dff),
@@ -419,7 +420,7 @@ const bTheme U_theme_default = {
.list = RGBA(0x282828ff),
.list_title = RGBA(0xffffffff),
.list_text = RGBA(0xb8b8b8ff),
- .list_text_hi = RGBA(0xffffffff),
+ .list_text_hi = RGBA(0xffaf29ff),
.panelcolors = {
.header = RGBA(0x424242cc),
.back = RGBA(0x333333b3),
@@ -453,11 +454,11 @@ const bTheme U_theme_default = {
.anim_preview_range = RGBA(0xa14d0066),
},
.space_info = {
- .back = RGBA(0x42424200),
- .title = RGBA(0xeeeeeeff),
- .text = RGBA(0xe6e6e6ff),
+ .back = RGBA(0x28282800),
+ .title = RGBA(0xffffffff),
+ .text = RGBA(0xc3c3c3ff),
.text_hi = RGBA(0xffffffff),
- .header = RGBA(0x424242ff),
+ .header = RGBA(0x454545ff),
.header_text = RGBA(0xeeeeeeff),
.header_text_hi = RGBA(0xffffffff),
.tab_active = RGBA(0x4b4b4bff),
@@ -476,16 +477,20 @@ const bTheme U_theme_default = {
.vertex_size = 3,
.outline_width = 1,
.facedot_size = 4,
- .info_selected = RGBA(0x6080ffff),
+ .info_selected = RGBA(0x3b5689ff),
.info_selected_text = RGBA(0xffffffff),
- .info_error = RGBA(0x990000ff),
+ .info_error = RGBA(0xff613dff),
.info_error_text = RGBA(0xffffffff),
.info_warning = RGBA(0xb36a00ff),
.info_warning_text = RGBA(0xffffffff),
.info_info = RGBA(0x1d4383ff),
.info_info_text = RGBA(0xffffffff),
.info_debug = RGBA(0xd3d3d3ff),
- },
+ .info_property = RGBA(0x3ace87ff),
+ .info_property_text = RGBA(0xffffffff),
+ .info_operator = RGBA(0x3ace87ff),
+ .info_operator_text = RGBA(0xffffffff),
+ },
.space_action = {
.back = RGBA(0x42424200),
.title = RGBA(0xeeeeeeff),
@@ -505,7 +510,7 @@ const bTheme U_theme_default = {
.list = RGBA(0x282828ff),
.list_title = RGBA(0xffffffff),
.list_text = RGBA(0xb8b8b8ff),
- .list_text_hi = RGBA(0xffffffff),
+ .list_text_hi = RGBA(0xffaf29ff),
.panelcolors = {
.header = RGBA(0x424242cc),
.back = RGBA(0x333333b3),
@@ -556,14 +561,14 @@ const bTheme U_theme_default = {
.tab_inactive = RGBA(0x2b2b2bff),
.tab_back = RGBA(0x232323ff),
.tab_outline = RGBA(0x232323ff),
- .button = RGBA(0x282828ff),
+ .button = RGBA(0x424242ff),
.button_title = RGBA(0xffffffff),
.button_text = RGBA(0xe5e5e5ff),
.button_text_hi = RGBA(0xffffffff),
.list = RGBA(0x282828ff),
.list_title = RGBA(0xffffffff),
.list_text = RGBA(0xb8b8b8ff),
- .list_text_hi = RGBA(0xffffffff),
+ .list_text_hi = RGBA(0xffaf29ff),
.panelcolors = {
.header = RGBA(0x424242cc),
.back = RGBA(0x333333b3),
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 1470f353c65034db91131d21ab9c782d029a2ee
+Subproject ad6928706de2fa8f44fa35a275453c716d65e77
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject ffbaca558a27bab4716bcd51ca7ea1df8e4f4b1
+Subproject 70b649775eeeebedb02c1c7b7aa996a7f629417
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 4aaa30a0508..2034b2ac55c 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -599,8 +599,8 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
# We manually add funcs from bpy.app.translations
for func_id, func_ids in pgettext_variants:
func_translate_args[func_id] = pgettext_variants_args
- for func_id in func_ids:
- func_translate_args[func_id] = pgettext_variants_args
+ for sub_func_id in func_ids:
+ func_translate_args[sub_func_id] = pgettext_variants_args
# print(func_translate_args)
# Break recursive nodes look up on some kind of nodes.
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index 2cca4171193..7c22a86d687 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -1413,8 +1413,8 @@ class I18n:
"# and edit the translations by hand.",
"# Just carefully respect the format of the tuple!",
"",
- "# Tuple of tuples "
- "((msgctxt, msgid), (sources, gen_comments), (lang, translation, (is_fuzzy, comments)), ...)",
+ "# Tuple of tuples:",
+ "# ((msgctxt, msgid), (sources, gen_comments), (lang, translation, (is_fuzzy, comments)), ...)",
"translations_tuple = (",
]
# First gather all keys (msgctxt, msgid) - theoretically, all translations should share the same, but...
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 202fd865723..8dda8c90f85 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -277,14 +277,15 @@ def draw(layout, context, context_member, property_type, use_edit=True):
else:
val_draw = val
- row = flow.row(align=True)
+ row = layout.row(align=True)
box = row.box()
if use_edit:
split = box.split(factor=0.75)
row = split.row(align=True)
else:
- row = box.row(align=True)
+ split = box.split(factor=1.00)
+ row = split.row(align=True)
row.alignment = 'RIGHT'
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 8b398d1541c..629bc24abb3 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -290,12 +290,14 @@ def _template_items_proportional_editing(*, connected=False):
# Tool System Templates
-def _template_items_tool_select(params, operator, cursor_operator):
+def _template_items_tool_select(params, operator, cursor_operator, *, extend):
if params.select_mouse == 'LEFTMOUSE':
# Immediate select without quick delay.
return [
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("deselect_all", True)]}),
+ (operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ {"properties": [(extend, True)]}),
]
else:
# For right mouse, set the cursor.
@@ -940,6 +942,7 @@ def km_view3d(params):
# Visibility.
("view3d.localview", {"type": 'NUMPAD_SLASH', "value": 'PRESS'}, None),
("view3d.localview", {"type": 'SLASH', "value": 'PRESS'}, None),
+ ("view3d.localview", {"type": 'MOUSESMARTZOOM', "value": 'ANY'}, None),
("view3d.localview_remove_from", {"type": 'M', "value": 'PRESS'}, None),
# Navigation.
("view3d.rotate", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
@@ -2032,6 +2035,7 @@ def km_dopesheet(params):
op_menu_pie("VIEW3D_MT_proportional_editing_falloff_pie", {"type": 'O', "value": 'PRESS', "shift": True}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
+ ("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
*_template_items_context_menu("DOPESHEET_MT_context_menu", params.context_menu_event),
])
@@ -2333,6 +2337,7 @@ def km_sequencercommon(_params):
items.extend([
*_template_space_region_type_toggle(
+ toolbar_key={"type": 'T', "value": 'PRESS'},
sidebar_key={"type": 'N', "value": 'PRESS'},
),
("wm.context_toggle", {"type": 'O', "value": 'PRESS', "shift": True},
@@ -2340,6 +2345,13 @@ def km_sequencercommon(_params):
("sequencer.view_toggle", {"type": 'TAB', "value": 'PRESS', "ctrl": True}, None),
])
+ if _params.select_mouse == 'LEFTMOUSE' and not _params.legacy:
+ # Quick switch to select tool, since left select can't easily
+ # select with any tool active.
+ items.extend([
+ op_tool_cycle("builtin.select_box", {"type": 'W', "value": 'PRESS'}),
+ ])
+
return keymap
@@ -2918,6 +2930,10 @@ def km_animation_channels(params):
*_template_items_select_actions(params, "anim.channels_select_all"),
("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None),
("anim.channels_select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
+ ("anim.channels_select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True,},
+ {"properties": [("extend", True)]}),
+ ("anim.channels_select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True,},
+ {"properties": [("deselect", True)]}),
# Delete.
("anim.channels_delete", {"type": 'X', "value": 'PRESS'}, None),
("anim.channels_delete", {"type": 'DEL', "value": 'PRESS'}, None),
@@ -5055,7 +5071,7 @@ def km_image_editor_tool_uv_select(params):
return (
"Image Editor Tool: Uv, Tweak",
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "uv.select", "uv.cursor_set")},
+ {"items": _template_items_tool_select(params, "uv.select", "uv.cursor_set", extend="extend")},
)
@@ -5206,7 +5222,7 @@ def km_3d_view_tool_select(params):
return (
"3D View Tool: Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "view3d.select", "view3d.cursor3d")},
+ {"items": _template_items_tool_select(params, "view3d.select", "view3d.cursor3d", extend="toggle")},
)
@@ -5913,7 +5929,7 @@ def km_3d_view_tool_edit_gpencil_select(params):
return (
"3D View Tool: Edit Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d")},
+ {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d", extend="toggle")},
)
@@ -6018,7 +6034,7 @@ def km_3d_view_tool_sculpt_gpencil_select(params):
return (
"3D View Tool: Sculpt Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d")},
+ {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d", extend="toggle")},
)
@@ -6049,6 +6065,39 @@ def km_3d_view_tool_sculpt_gpencil_select_lasso(params):
)
+def km_sequencer_editor_tool_select(params):
+ return (
+ "Sequencer Tool: Select",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items": [
+ ("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'},
+ {"properties": [("extend", False), ("deselect_all", not params.legacy)]}),
+ ]},
+ )
+
+
+def km_sequencer_editor_tool_select_box(params):
+ return (
+ "Sequencer Tool: Select Box",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items": _template_items_tool_select_actions_simple(
+ "sequencer.select_box", type=params.tool_tweak, value='ANY',
+ properties=[("tweak", True)],
+ )},
+ )
+
+
+def km_sequencer_editor_tool_cut(params):
+ return (
+ "Sequencer Tool: Cut",
+ {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
+ {"items":[
+ ("sequencer.cut", {"type": 'LEFTMOUSE', "value": 'PRESS'},
+ {"properties": [("type", 'SOFT'), ("side", 'NO_CHANGE'), ("use_cursor_position", True), ("ignore_selection", True)]}),
+ ]},
+ )
+
+
# ------------------------------------------------------------------------------
# Full Configuration
@@ -6262,6 +6311,9 @@ def generate_keymaps(params=None):
km_3d_view_tool_sculpt_gpencil_select_box(params),
km_3d_view_tool_sculpt_gpencil_select_circle(params),
km_3d_view_tool_sculpt_gpencil_select_lasso(params),
+ km_sequencer_editor_tool_select(params),
+ km_sequencer_editor_tool_select_box(params),
+ km_sequencer_editor_tool_cut(params),
]
# ------------------------------------------------------------------------------
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index ceca4687443..0bffd316f30 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -39,6 +39,9 @@ class Params:
use_mouse_emulate_3_button=False,
):
self.tool_mouse = 'LEFTMOUSE'
+ self.select_mouse = 'LEFTMOUSE'
+ self.select_mouse_value = 'CLICK'
+ self.select_tweak = 'EVT_TWEAK_L'
self.tool_tweak = 'EVT_TWEAK_L'
self.action_tweak = 'EVT_TWEAK_R'
self.use_mouse_emulate_3_button = use_mouse_emulate_3_button
@@ -135,8 +138,13 @@ def _template_items_basic_tools(*, connected=False):
op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
]
-def _template_items_tool_select(params, operator, cursor_operator):
- return [(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'}, None)]
+def _template_items_tool_select(params, operator, *, extend):
+ return [
+ (operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
+ {"properties": [("deselect_all", True)]}),
+ (operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ {"properties": [(extend, True)]}),
+ ]
def _template_items_tool_select_actions(operator, *, type, value):
@@ -622,6 +630,7 @@ def km_view3d(params):
("wm.search_menu", {"type": 'TAB', "value": 'PRESS'}, None),
# Visibility.
("view3d.localview", {"type": 'I', "value": 'PRESS', "shift": True}, None),
+ ("view3d.localview", {"type": 'MOUSESMARTZOOM', "value": 'ANY'}, None),
op_menu_pie("VIEW3D_MT_view_pie", {"type": 'V', "value": 'PRESS'}),
# Navigation.
("view3d.rotate", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
@@ -2182,8 +2191,11 @@ def km_animation_channels(params):
("anim.channels_select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'SELECT')]}),
("anim.channels_select_all", {"type": 'A', "value": 'PRESS', "ctrl": True, "shift": True}, {"properties": [("action", 'DESELECT')]}),
("anim.channels_select_all", {"type": 'I', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'INVERT')]}),
- ("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None),
("anim.channels_select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
+ ("anim.channels_select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True,},
+ {"properties": [("extend", True)]}),
+ ("anim.channels_select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True,},
+ {"properties": [("deselect", True)]}),
# Delete.
("anim.channels_delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
("anim.channels_delete", {"type": 'DEL', "value": 'PRESS'}, None),
@@ -3565,79 +3577,19 @@ def km_transform_modal_map(_params):
# Named are auto-generated based on the tool name and it's toolbar.
-def km_image_editor_tool_uv_move(params):
- return (
- "Image Editor Tool: Uv, Move",
- {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
- {"items": [
- ("transform.translate", {"type": 'EVT_TWEAK_M', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- ]},
- )
-
-
-def km_image_editor_tool_uv_rotate(params):
- return (
- "Image Editor Tool: Uv, Rotate",
- {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
- {"items": [
- ("transform.rotate", {"type": 'EVT_TWEAK_M', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- ]},
- )
-
-
-def km_image_editor_tool_uv_scale(params):
- return (
- "Image Editor Tool: Uv, Scale",
- {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
- {"items": [
- ("transform.resize", {"type": 'EVT_TWEAK_M', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- ]},
- )
-
-
-def km_3d_view_tool_move(params):
- return (
- "3D View Tool: Move",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.translate", {"type": 'EVT_TWEAK_M', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- ]},
- )
-
-
-def km_3d_view_tool_rotate(params):
+def km_3d_view_tool_select(params):
return (
- "3D View Tool: Rotate",
+ "3D View Tool: Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.rotate", {"type": 'EVT_TWEAK_M', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- ]},
+ {"items": _template_items_tool_select(params, "view3d.select", extend="toggle")},
)
-def km_3d_view_tool_scale(params):
+def km_image_editor_tool_uv_select(params):
return (
- "3D View Tool: Scale",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.resize", {"type": 'EVT_TWEAK_M', "value": 'ANY'},
- {"properties": [("release_confirm", True)]}),
- ]},
- )
-
-
-def km_3d_view_tool_transform(params):
- return (
- "3D View Tool: Transform",
- {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": [
- ("transform.from_gizmo", {"type": 'EVT_TWEAK_M', "value": 'ANY'}, None),
- ]},
+ "Image Editor Tool: Uv, Tweak",
+ {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
+ {"items": _template_items_tool_select(params, "uv.select", extend="extend")},
)
@@ -3759,14 +3711,8 @@ def generate_keymaps_impl(params=None):
km_generic_gizmo_maybe_drag(params),
# Tool System.
- km_image_editor_tool_uv_move(params),
- km_image_editor_tool_uv_rotate(params),
- km_image_editor_tool_uv_scale(params),
- km_3d_view_tool_transform(params),
- km_3d_view_tool_move(params),
- km_3d_view_tool_rotate(params),
- km_3d_view_tool_scale(params),
-
+ km_3d_view_tool_select(params),
+ km_image_editor_tool_uv_select(params),
]
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 39d792bd557..a249599b5d7 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -37,6 +37,20 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
from math import acos
import array
+ # We simulate the accumulation of dirt in the creases of geometric surfaces
+ # by comparing the vertex normal to the average direction of all vertices
+ # connected to that vertex. We can also simulate surfaces being buffed or
+ # worn by testing protruding surfaces.
+ #
+ # So if the angle between the normal and geometric direction is:
+ # < 90 - dirt has accumulated in the crease
+ # > 90 - surface has been worn or buffed
+ # ~ 90 - surface is flat and is generally unworn and clean
+ #
+ # This method is limited by the complexity or lack there of in the geometry.
+ #
+ # Original code and method by Keith "Wahooney" Boshoff.
+
vert_tone = array.array("f", [0.0]) * len(me.vertices)
# create lookup table for each vertex's connected vertices (via edges)
diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py
index dc9c170c65b..88fdaae0433 100644
--- a/release/scripts/startup/bl_ui/properties_data_empty.py
+++ b/release/scripts/startup/bl_ui/properties_data_empty.py
@@ -37,7 +37,6 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
- layout.use_property_decorate = False
ob = context.object
@@ -45,12 +44,6 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
layout.prop(ob, "empty_display_size", text="Size")
if ob.empty_display_type == 'IMAGE':
- layout.prop(ob, "use_empty_image_alpha")
-
- col = layout.column()
- col.active = ob.use_empty_image_alpha
- col.prop(ob, "color", text="Opacity", index=3, slider=True)
-
col = layout.column(align=True)
col.prop(ob, "empty_image_offset", text="Offset X", index=0)
col.prop(ob, "empty_image_offset", text="Y", index=1)
@@ -63,6 +56,30 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
col.prop(ob, "show_empty_image_only_axis_aligned")
+class DATA_PT_empty_alpha(DataButtonsPanel, Panel):
+ bl_label = "Transparency"
+ bl_parent_id = "DATA_PT_empty"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.type == 'EMPTY' and ob.empty_display_type == 'IMAGE')
+
+ def draw_header(self, context):
+ ob = context.object
+
+ self.layout.prop(ob, "use_empty_image_alpha", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+
+ layout.active = ob.use_empty_image_alpha
+ layout.prop(ob, "color", text="Opacity", index=3, slider=True)
+
+
class DATA_PT_empty_image(DataButtonsPanel, Panel):
bl_label = "Image"
@@ -81,6 +98,7 @@ class DATA_PT_empty_image(DataButtonsPanel, Panel):
classes = (
DATA_PT_empty,
+ DATA_PT_empty_alpha,
DATA_PT_empty_image,
)
diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py
index 6f730cf3307..cf894b48e1e 100644
--- a/release/scripts/startup/bl_ui/properties_data_light.py
+++ b/release/scripts/startup/bl_ui/properties_data_light.py
@@ -134,17 +134,15 @@ class DATA_PT_EEVEE_light_distance(DataButtonsPanel, Panel):
light = context.light
layout = self.layout
- layout.active = light.use_shadow
layout.prop(light, "use_custom_distance", text="")
def draw(self, context):
layout = self.layout
light = context.light
+ layout.active = light.use_custom_distance
layout.use_property_split = True
- col = layout.column()
-
- col.prop(light, "cutoff_distance", text="Distance")
+ layout.prop(light, "cutoff_distance", text="Distance")
class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
@@ -311,7 +309,8 @@ class DATA_PT_falloff_curve(DataButtonsPanel, Panel):
def draw(self, context):
light = context.light
- self.layout.template_curve_mapping(light, "falloff_curve", use_negative_slope=True)
+ self.layout.template_curve_mapping(
+ light, "falloff_curve", use_negative_slope=True)
class DATA_PT_custom_props_light(DataButtonsPanel, PropertyPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index d4b2c39bd5e..021a4600a73 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -293,7 +293,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.label(text="Vertex Group:")
- col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
col = split.column()
col.label(text="Control Object:")
col.prop(md, "object", text="")
@@ -379,7 +381,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.label(text="Space:")
col.prop(md, "space", text="")
col.label(text="Vertex Group:")
- col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
col = split.column(align=True)
col.active = has_texture
@@ -1135,7 +1139,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.label(text="To:")
col.prop(md, "object_to", text="")
- col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 93bf5eca052..a9e8cae3c8b 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -121,7 +121,7 @@ class UnifiedPaintPanel:
if unified_name and not header:
# NOTE: We don't draw UnifiedPaintSettings in the header to reduce clutter. D5928#136281
- row.prop(ups, unified_name, text="", icon="WORLD")
+ row.prop(ups, unified_name, text="", icon="BRUSHES_ALL")
return row
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 82ed701aa4c..cd65980fc0d 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -92,7 +92,7 @@ class INFO_MT_area(Menu):
layout.separator()
- layout.operator("screen.area_dupli", icon='DUPLICATE')
+ layout.operator("screen.area_dupli", icon='WINDOW')
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 097564444d0..af0c23e7892 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -30,6 +30,9 @@ from bpy.app.translations import (
from bl_ui.properties_grease_pencil_common import (
AnnotationDataPanel,
)
+from bl_ui.space_toolsystem_common import (
+ ToolActivePanelHelper,
+)
from rna_prop_ui import PropertyPanel
@@ -89,6 +92,35 @@ def draw_color_balance(layout, color_balance):
split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)
+class SEQUENCER_PT_active_tool(ToolActivePanelHelper, Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'UI'
+ bl_category = "Tool"
+
+
+class SEQUENCER_HT_tool_header(Header):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'TOOL_HEADER'
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.template_header()
+
+ self.draw_tool_settings(context)
+
+ # TODO: options popover.
+
+ def draw_tool_settings(self, context):
+ layout = self.layout
+
+ # Active Tool
+ # -----------
+ from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+ tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
+ tool_mode = context.mode if tool is None else tool.mode
+
+
class SEQUENCER_HT_header(Header):
bl_space_type = 'SEQUENCE_EDITOR'
@@ -97,7 +129,10 @@ class SEQUENCER_HT_header(Header):
st = context.space_data
- layout.template_header()
+ show_region_tool_header = st.show_region_tool_header
+
+ if not show_region_tool_header:
+ layout.template_header()
layout.prop(st, "view_type", text="")
@@ -226,8 +261,12 @@ class SEQUENCER_MT_view(Menu):
# wm_keymap_item_find_props() (see #32595).
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.prop(st, "show_region_ui")
+ layout.prop(st, "show_region_toolbar")
layout.operator_context = 'INVOKE_DEFAULT'
+ if is_sequencer_view:
+ layout.prop(st, "show_region_hud")
+
if st.view_type == 'SEQUENCER':
layout.prop(st, "show_backdrop", text="Preview as Backdrop")
@@ -268,6 +307,7 @@ class SEQUENCER_MT_view(Menu):
layout.operator_context = 'INVOKE_DEFAULT'
layout.prop(st, "show_seconds")
+ layout.prop(st, "show_locked_time")
layout.prop(st, "show_strip_offset")
layout.separator()
layout.prop(st, "show_markers")
@@ -2128,6 +2168,7 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
classes = (
SEQUENCER_MT_change,
+ SEQUENCER_HT_tool_header,
SEQUENCER_HT_header,
SEQUENCER_MT_editor_menus,
SEQUENCER_MT_range,
@@ -2153,7 +2194,7 @@ classes = (
SEQUENCER_MT_strip_input,
SEQUENCER_MT_strip_lock_mute,
SEQUENCER_MT_context_menu,
-
+ SEQUENCER_PT_active_tool,
SEQUENCER_PT_strip,
SEQUENCER_PT_effect,
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 81ccc9216a1..b7c5dcd5437 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -30,7 +30,7 @@ class TEXT_HT_header(Header):
st = context.space_data
text = st.text
-
+ is_syntax_highlight_supported = st.is_syntax_highlight_supported()
layout.template_header()
TEXT_MT_editor_menus.draw_collapsible(context, layout)
@@ -43,7 +43,18 @@ class TEXT_HT_header(Header):
layout.separator_spacer()
row = layout.row(align=True)
- row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open")
+ row.template_ID(st, "text", new="text.new",
+ unlink="text.unlink", open="text.open")
+
+ if text:
+ is_osl = text.name.endswith((".osl", ".osl"))
+ if is_osl:
+ row.operator("node.shader_script_update",
+ text="", icon='FILE_REFRESH')
+ else:
+ row = layout.row()
+ row.active = is_syntax_highlight_supported
+ row.operator("text.run_script", text="", icon='PLAY')
layout.separator_spacer()
@@ -51,28 +62,10 @@ class TEXT_HT_header(Header):
row.prop(st, "show_line_numbers", text="")
row.prop(st, "show_word_wrap", text="")
- is_syntax_highlight_supported = st.is_syntax_highlight_supported()
syntax = row.row(align=True)
syntax.active = is_syntax_highlight_supported
syntax.prop(st, "show_syntax_highlight", text="")
- if text:
- text_name = text.name
- is_osl = text_name.endswith((".osl", ".oso"))
-
- row = layout.row()
- if is_osl:
- row = layout.row()
- row.operator("node.shader_script_update")
- else:
- row = layout.row()
- row.active = text_name.endswith(".py")
- row.prop(text, "use_module")
-
- row = layout.row()
- row.active = is_syntax_highlight_supported
- row.operator("text.run_script")
-
class TEXT_HT_footer(Header):
bl_space_type = 'TEXT_EDITOR'
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 05785b85dfc..4dc724299f0 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -390,6 +390,14 @@ class ToolSelectPanelHelper:
if tool is not None:
tool.refresh_from_context()
return tool
+ elif space_type == 'SEQUENCE_EDITOR':
+ space_data = context.space_data
+ if mode is None:
+ mode = space_data.view_type
+ tool = context.workspace.tools.from_space_sequencer(mode, create=create)
+ if tool is not None:
+ tool.refresh_from_context()
+ return tool
return None
@staticmethod
@@ -656,6 +664,8 @@ class ToolSelectPanelHelper:
return space_type, space_data.mode
elif space_type == 'NODE_EDITOR':
return space_type, None
+ elif space_type == 'SEQUENCE_EDITOR':
+ return space_type, context.space_data.view_type
else:
return None, None
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 0759d37e2b8..c1ad196b555 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -134,6 +134,7 @@ class _defs_view3d_generic:
idname="builtin.measure",
label="Measure",
description=description,
+ cursor='CROSSHAIR',
icon="ops.view3d.ruler",
widget="VIEW3D_GGT_ruler",
keymap="3D View Tool: Measure",
@@ -375,6 +376,7 @@ class _defs_view3d_select:
label="Select Lasso",
icon="ops.generic.select_lasso",
widget=None,
+ cursor='DEFAULT',
keymap="3D View Tool: Select Lasso",
draw_settings=draw_settings,
)
@@ -399,6 +401,7 @@ class _defs_view3d_select:
label="Select Circle",
icon="ops.generic.select_circle",
widget=None,
+ cursor='DEFAULT',
keymap="3D View Tool: Select Circle",
draw_settings=draw_settings,
draw_cursor=draw_cursor,
@@ -1707,6 +1710,51 @@ class _defs_node_edit:
keymap="Node Tool: Links Cut",
)
+class _defs_sequencer_generic:
+
+ @ToolDef.from_fn
+ def cut():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("sequencer.cut")
+ row = layout.row()
+ row.use_property_split = False
+ row.prop(props, "type", expand=True)
+ return dict(
+ idname="builtin.cut",
+ label="Cut",
+ icon="ops.mesh.knife_tool",
+ widget=None,
+ keymap="Sequencer Tool: Cut",
+ draw_settings=draw_settings,
+ )
+
+class _defs_sequencer_select:
+ @ToolDef.from_fn
+ def select():
+ return dict(
+ idname="builtin.select",
+ label="Select",
+ icon="ops.generic.select",
+ widget=None,
+ keymap="Sequencer Tool: Select",
+ )
+ @ToolDef.from_fn
+ def box():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("sequencer.select_box")
+ row = layout.row()
+ row.use_property_split = False
+ row.prop(props, "mode", text="", expand=True, icon_only=True)
+ pass
+ return dict(
+ idname="builtin.select_box",
+ label="Select Box",
+ icon="ops.generic.select_box",
+ widget=None,
+ keymap="Sequencer Tool: Select Box",
+ draw_settings=draw_settings,
+ )
+
class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
bl_space_type = 'IMAGE_EDITOR'
@@ -2158,12 +2206,71 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
}
+class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'TOOLS'
+ bl_label = "Tools" # not visible
+ bl_options = {'HIDE_HEADER'}
+
+ # Satisfy the 'ToolSelectPanelHelper' API.
+ keymap_prefix = "Sequence Editor Tool:"
+ # Default group to use as a fallback.
+ tool_fallback_id = "builtin.select"
+
+ @classmethod
+ def tools_from_context(cls, context, mode=None):
+ if mode is None:
+ if context.space_data:
+ mode = context.space_data.view_type
+ for tools in (cls._tools[None], cls._tools.get(mode, ())):
+ for item in tools:
+ if not (type(item) is ToolDef) and callable(item):
+ yield from item(context)
+ else:
+ yield item
+
+ @classmethod
+ def tools_all(cls):
+ yield from cls._tools.items()
+
+ _tools_select = (
+ (
+ _defs_sequencer_select.select,
+ _defs_sequencer_select.box,
+ ),
+ )
+ _tools_annotate = (
+ (
+ _defs_annotate.scribble,
+ _defs_annotate.line,
+ _defs_annotate.poly,
+ _defs_annotate.eraser,
+ ),
+ )
+
+ _tools = {
+ None: [
+ ],
+ 'PREVIEW': [
+ *_tools_annotate,
+ ],
+ 'SEQUENCER': [
+ *_tools_select,
+ _defs_sequencer_generic.cut,
+ ],
+ 'SEQUENCER_PREVIEW': [
+ *_tools_select,
+ *_tools_annotate,
+ _defs_sequencer_generic.cut,
+ ],
+ }
classes = (
IMAGE_PT_tools_active,
NODE_PT_tools_active,
VIEW3D_PT_tools_active,
+ SEQUENCER_PT_tools_active,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 4f35bcc29df..ad5e7b5442c 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -997,6 +997,7 @@ class PreferenceThemeSpacePanel:
"freestyle_face_mark",
"split_normal",
"bone_solid",
+ "bone_locked_weight",
"paint_curve_pivot",
},
'GRAPH_EDITOR': {
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 3a3869068b0..6ca6cb7b544 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2937,6 +2937,10 @@ class VIEW3D_MT_sculpt(Menu):
layout.menu("VIEW3D_MT_sculpt_set_pivot", text="Set Pivot")
+ layout.separator()
+
+ layout.operator("sculpt.optimize")
+
class VIEW3D_MT_mask(Menu):
bl_label = "Mask"
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 011c2a8b39a..ff1392d9126 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -560,12 +560,23 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
layout.operator("image.save_all_modified", text="Save All Images", icon='FILE_TICK')
+class VIEW3D_PT_mask(View3DPanel, Panel):
+ bl_category = "Tool"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_label = "Masking"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ pass
+
+
# TODO, move to space_view3d.py
class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
- bl_label = "Mask"
+ bl_label = "Stencil Mask"
bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "VIEW3D_PT_mask"
bl_ui_units_x = 14
@classmethod
@@ -799,38 +810,14 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
sub.prop(sculpt, "detail_refine_method", text="Refine Method")
sub.prop(sculpt, "detail_type_method", text="Detailing")
- col.prop(sculpt, "use_smooth_shading")
-
-
-class VIEW3D_PT_sculpt_dyntopo_remesh(Panel, View3DPaintPanel):
- bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
- bl_label = "Remesh"
- bl_parent_id = "VIEW3D_PT_sculpt_dyntopo"
- bl_options = {'DEFAULT_CLOSED'}
- bl_ui_units_x = 12
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False
+ if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
+ col.operator("sculpt.detail_flood_fill")
- tool_settings = context.tool_settings
- sculpt = tool_settings.sculpt
+ col.prop(sculpt, "use_smooth_shading")
- col = layout.column()
- col.active = context.sculpt_object.use_dynamic_topology_sculpting
- col.prop(sculpt, "symmetrize_direction")
- flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
- col = flow.column()
- col.operator("sculpt.symmetrize")
- col = flow.column()
- col.operator("sculpt.optimize")
- if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
- col = flow.column()
- col.operator("sculpt.detail_flood_fill")
class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
@@ -979,6 +966,13 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
layout.column().prop(sculpt, "radial_symmetry", text="Radial")
layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
+ layout.separator()
+
+ col = layout.column()
+
+ col.prop(sculpt, "symmetrize_direction")
+ col.operator("sculpt.symmetrize")
+
class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
bl_space_type = 'TOPBAR'
@@ -1192,6 +1186,7 @@ class VIEW3D_PT_tools_imagepaint_options_cavity(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Cavity Mask"
bl_parent_id = "VIEW3D_PT_tools_imagepaint_options"
+ bl_parent_id = "VIEW3D_PT_mask"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
@@ -1876,7 +1871,7 @@ classes = (
VIEW3D_PT_tools_curveedit_options_stroke,
VIEW3D_PT_tools_armatureedit_options,
VIEW3D_PT_tools_posemode_options,
-
+
VIEW3D_PT_slots_projectpaint,
VIEW3D_PT_tools_brush_select,
VIEW3D_PT_tools_brush_settings,
@@ -1886,7 +1881,6 @@ classes = (
VIEW3D_PT_tools_brush_clone,
TEXTURE_UL_texpaintslots,
VIEW3D_MT_tools_projectpaint_uvlayer,
- VIEW3D_PT_stencil_projectpaint,
VIEW3D_PT_tools_brush_texture,
VIEW3D_PT_tools_mask_texture,
VIEW3D_PT_tools_brush_stroke,
@@ -1897,7 +1891,6 @@ classes = (
VIEW3D_PT_tools_brush_display,
VIEW3D_PT_sculpt_dyntopo,
- VIEW3D_PT_sculpt_dyntopo_remesh,
VIEW3D_PT_sculpt_voxel_remesh,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_symmetry_for_topbar,
@@ -1912,9 +1905,13 @@ classes = (
VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar,
VIEW3D_PT_tools_vertexpaint_options,
+ VIEW3D_PT_mask,
+ VIEW3D_PT_stencil_projectpaint,
+ VIEW3D_PT_tools_imagepaint_options_cavity,
+
VIEW3D_PT_tools_imagepaint_symmetry,
VIEW3D_PT_tools_imagepaint_options,
- VIEW3D_PT_tools_imagepaint_options_cavity,
+
VIEW3D_PT_tools_imagepaint_options_external,
VIEW3D_MT_tools_projectpaint_stencil,
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_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/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 75e14b7efca..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
@@ -36,7 +36,7 @@
/** Can be left blank, otherwise a,b,c... etc with no quotes. */
#define BLENDER_VERSION_CHAR
/** alpha/beta/rc/release, docs use this. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/** Optionally set to 1,2,... for example to get alpha1 or rc2. */
#define BLENDER_VERSION_CYCLE_NUMBER
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_icons.h b/source/blender/blenkernel/BKE_icons.h
index 417591e03c5..27d7f45e480 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -62,8 +62,8 @@ struct Icon_Geom {
int icon_id;
int coords_len;
int coords_range[2];
- const unsigned char (*coords)[2];
- const unsigned char (*colors)[4];
+ unsigned char (*coords)[2];
+ unsigned char (*colors)[4];
/* when not NULL, the memory of coords and colors is a sub-region of this pointer. */
const void *mem;
};
@@ -160,6 +160,7 @@ struct Icon_Geom *BKE_icon_geom_from_file(const char *filename);
struct ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom,
const unsigned int size_x,
const unsigned int size_y);
+void BKE_icon_geom_invert_lightness(struct Icon_Geom *geom);
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type);
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_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_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index b1186564dbd..bc312c7bb2b 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -507,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/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/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/collision.c b/source/blender/blenkernel/intern/collision.c
index 220b9417a6c..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"
@@ -193,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];
@@ -423,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)
@@ -494,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;
@@ -509,14 +684,32 @@ 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_xnew[collpair->bp1].co,
@@ -526,15 +719,6 @@ static int cloth_collision_response_static(ClothModifierData *clmd,
&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,
@@ -576,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. */
@@ -588,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);
@@ -609,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;
@@ -627,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;
}
@@ -656,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];
+ }
}
}
}
@@ -875,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_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);
+ 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];
@@ -946,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];
@@ -983,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,
@@ -1148,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 = {
@@ -1163,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;
}
@@ -1308,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");
@@ -1474,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, true);
- }
-
- 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/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 33f9b5b1012..85b58da61de 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -81,17 +81,16 @@ static void set_crazy_vertex_quat(float r_quat[4],
sub_qt_qtqt(r_quat, q2, q1);
}
-static int modifiers_disable_subsurf_temporary(Object *ob)
+static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
{
- ModifierData *md;
- int disabled = 0;
+ bool disabled = false;
+ int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
- for (md = ob->modifiers.first; md; md = md->next) {
+ ModifierData *md = ob->modifiers.first;
+ for (int i = 0; md && i <= cageIndex; i++, md = md->next) {
if (md->type == eModifierType_Subsurf) {
- if (md->mode & eModifierMode_OnCage) {
- md->mode ^= eModifierMode_DisableTemporary;
- disabled = 1;
- }
+ md->mode ^= eModifierMode_DisableTemporary;
+ disabled = true;
}
}
@@ -108,7 +107,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object
BMEditMesh *editmesh_eval = mesh_eval->edit_mesh;
/* disable subsurf temporal, get mapped cos, and enable it */
- if (modifiers_disable_subsurf_temporary(obedit_eval)) {
+ if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
/* need to make new derivemesh */
makeDerivedMesh(depsgraph, scene_eval, obedit_eval, editmesh_eval, &CD_MASK_BAREMESH);
}
@@ -122,7 +121,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object
mesh_get_mapped_verts_coords(mesh_eval_cage, vertexcos, nverts);
/* set back the flag, no new cage needs to be built, transform does it */
- modifiers_disable_subsurf_temporary(obedit_eval);
+ modifiers_disable_subsurf_temporary(scene_eval, obedit_eval);
return vertexcos;
}
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/icons.c b/source/blender/blenkernel/intern/icons.c
index 7b8a0a8894f..6363a23de6c 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -842,8 +842,8 @@ struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len)
p += 2;
geom->coords_len = coords_len;
- geom->coords = (const void *)p;
- geom->colors = (const void *)(p + (data_len / 3));
+ geom->coords = (void *)p;
+ geom->colors = (void *)(p + (data_len / 3));
geom->icon_id = 0;
geom->mem = data;
return geom;
diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c
index e87180ce732..f731285e029 100644
--- a/source/blender/blenkernel/intern/icons_rasterize.c
+++ b/source/blender/blenkernel/intern/icons_rasterize.c
@@ -139,3 +139,17 @@ ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom,
IMB_scaleImBuf(ibuf, size_x, size_y);
return ibuf;
}
+
+void BKE_icon_geom_invert_lightness(struct Icon_Geom *geom)
+{
+ const int length = 3 * geom->coords_len;
+
+ for (int i = 0; i < length; i++) {
+ float rgb[3], hsl[3];
+
+ rgb_uchar_to_float(rgb, geom->colors[i]);
+ rgb_to_hsl_v(rgb, hsl);
+ hsl_to_rgb(hsl[0], hsl[1], 1.0f - hsl[2], &rgb[0], &rgb[1], &rgb[2]);
+ rgb_float_to_uchar(geom->colors[i], rgb);
+ }
+}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index fe1f9097562..be354b04157 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -1345,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:
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 974d6328fcb..5fd852ff089 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -340,7 +340,7 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas
FOREACH_FINALIZE_VOID;
}
-/* Used by both real Collection data-blokcs, and the fake horror of master collection from Scene.
+/* 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)
{
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/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/object.c b/source/blender/blenkernel/intern/object.c
index da3986d33df..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");
@@ -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);
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_rect.h b/source/blender/blenlib/BLI_rect.h
index 23a8f775576..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);
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/rct.c b/source/blender/blenlib/intern/rct.c
index 1712738e859..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)
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index f6cf68f7daf..5a834f31528 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3371,6 +3371,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;
@@ -3869,7 +3874,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);
@@ -6215,8 +6220,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);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index afe0d728934..e92ae6e73cc 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) {
@@ -2828,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) {
@@ -3709,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");
@@ -4309,6 +4361,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) {
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 30e7cf476fb..401f0ef6a85 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2066,9 +2066,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;
@@ -2105,16 +2103,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 {
@@ -2133,85 +2122,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/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 07e159b3241..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. */
@@ -1314,7 +1299,10 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, flo
}
/* 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])
+static void project_to_edge(const BMEdge *e,
+ const float co_a[3],
+ const float co_b[3],
+ float projco[3])
{
float otherco[3];
@@ -1330,16 +1318,13 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3],
* 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 start[3], end[3], co3[3], d1[3], d2[3];
- bool do_linear_interp;
+ bool do_linear_interp = true;
+ EdgeHalf *e = bndv->ebev;
+ Profile *pro = &bndv->profile;
copy_v3_v3(start, bndv->nv.co);
copy_v3_v3(end, bndv->next->nv.co);
- pro = &bndv->profile;
- e = bndv->ebev;
- do_linear_interp = true;
if (e) {
do_linear_interp = false;
pro->super_r = bp->pro_super_r;
@@ -1350,23 +1335,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
}
normalize_v3(pro->proj_dir);
project_to_edge(e->e, start, end, pro->middle);
- if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
- /* Put arc endpoints on plane with normal proj_dir, containing middle. */
- add_v3_v3v3(co3, start, pro->proj_dir);
- if (!isect_line_plane_v3(pro->start, start, co3, pro->middle, pro->proj_dir)) {
- /* Shouldn't happen. */
- copy_v3_v3(pro->start, start);
- }
- add_v3_v3v3(co3, end, pro->proj_dir);
- if (!isect_line_plane_v3(pro->end, end, co3, pro->middle, pro->proj_dir)) {
- /* Shouldn't happen. */
- copy_v3_v3(pro->end, end);
- }
- }
- else {
- copy_v3_v3(pro->start, start);
- copy_v3_v3(pro->end, end);
- }
+ 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);
@@ -1384,69 +1354,55 @@ 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, start);
- copy_v3_v3(pro->end, end);
- }
- 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, start, end);
- do_linear_interp = true;
- }
- else {
- 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. */
+ 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, start);
}
else if (bndv->is_arc_start) {
- /* Assume pro->middle was alredy set. */
+ /* Assume pro->middle was already set. */
copy_v3_v3(pro->start, start);
copy_v3_v3(pro->end, end);
pro->super_r = PRO_CIRCLE_R;
@@ -1455,6 +1411,17 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
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, start);
@@ -1467,11 +1434,11 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
}
}
-/* 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;
@@ -1496,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.
@@ -1531,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,
@@ -1748,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.
@@ -1759,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) {
@@ -2321,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);
}
@@ -2357,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) {
@@ -2471,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) {
@@ -2506,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 */
@@ -2831,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);
@@ -3185,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
@@ -3643,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;
@@ -4157,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);
@@ -4359,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);
@@ -4367,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);
@@ -4394,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;
@@ -4418,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++) {
@@ -4456,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
@@ -4479,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;
}
@@ -4922,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);
}
@@ -5105,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;
@@ -5143,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
@@ -5204,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
}
@@ -5226,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
}
@@ -5428,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;
@@ -5455,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);
@@ -5519,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;
@@ -5536,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) {
@@ -5589,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;
@@ -7423,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)) {
@@ -7431,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) {
@@ -7511,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_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index c3687c5d477..ce40256221e 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -57,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;
};
@@ -76,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;
}
@@ -93,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;
}
@@ -111,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;
}
/** \} */
@@ -517,7 +485,8 @@ static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, voi
#define INTERSECT_EDGES
-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)
{
bool ok = false;
@@ -560,6 +529,9 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
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;
@@ -621,6 +593,10 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
/* 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;
}
@@ -631,6 +607,10 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
else {
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);
+ }
}
}
@@ -656,7 +636,7 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
BLI_bvhtree_insert(tree_edges_act, i, co[0], 2);
}
else if (edge_test == EDGE_REMAIN_TO_TEST) {
- BLI_assert(tree_edges_act);
+ 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);
@@ -823,6 +803,11 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
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;
@@ -856,10 +841,148 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas
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;
}
}
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/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 e02a7a014f1..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"
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/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 fb7104e7556..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"
@@ -58,14 +59,14 @@ 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 != NULL;
+ 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;
@@ -113,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,
@@ -133,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_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 b260df6fa06..6382772c8db 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -122,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);
}
@@ -140,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;
@@ -218,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);
}
@@ -263,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);
@@ -276,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,
@@ -324,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) {
@@ -350,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
@@ -377,7 +377,7 @@ void DepsgraphNodeBuilder::end_build()
void DepsgraphNodeBuilder::build_id(ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
switch (GS(id->name)) {
@@ -391,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.
@@ -487,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. */
@@ -501,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;
@@ -518,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;
@@ -531,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);
@@ -554,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 {
@@ -569,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;
@@ -612,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);
}
@@ -658,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);
@@ -666,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);
@@ -674,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. */
@@ -689,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 {
@@ -718,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);
}
@@ -763,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. */
@@ -840,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);
@@ -878,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);
}
}
@@ -938,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);
@@ -956,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;
@@ -966,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)) {
@@ -974,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)
@@ -1053,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;
@@ -1072,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. */
@@ -1120,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);
@@ -1133,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;
}
@@ -1174,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);
@@ -1196,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);
}
}
@@ -1274,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;
@@ -1338,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);
}
}
@@ -1356,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)) {
@@ -1380,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);
@@ -1404,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);
}
@@ -1454,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]);
@@ -1474,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);
}
}
@@ -1552,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);
@@ -1615,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);
}
}
@@ -1637,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);
@@ -1649,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);
}
@@ -1696,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)) {
@@ -1719,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 7cb74ea8bc5..54a4768d12a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -106,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);
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 82a65c3129b..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
@@ -77,10 +77,10 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb)
void DepsgraphNodeBuilder::build_freestyle_lineset(FreestyleLineSet *fls)
{
- if (fls->group != NULL) {
- build_collection(NULL, fls->group);
+ if (fls->group != nullptr) {
+ build_collection(nullptr, fls->group);
}
- if (fls->linestyle != NULL) {
+ if (fls->linestyle != nullptr) {
build_freestyle_linestyle(fls->linestyle);
}
}
@@ -120,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. */
@@ -148,7 +148,7 @@ 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 linesets. */
@@ -170,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 23402c68698..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 */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index d01e8d8eddd..5214fdbd246 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -114,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 {
@@ -126,7 +127,7 @@ namespace {
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;
@@ -194,16 +195,16 @@ 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 == NULL) {
+ if (adt == nullptr) {
return false;
}
return !BLI_listbase_is_empty(&adt->drivers);
@@ -240,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)
{
}
@@ -248,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;
@@ -261,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);
@@ -272,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),
@@ -290,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,
@@ -317,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 {
@@ -332,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 {
@@ -358,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,
@@ -379,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,
@@ -439,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");
}
}
@@ -476,7 +478,7 @@ void DepsgraphRelationBuilder::begin_build()
void DepsgraphRelationBuilder::build_id(ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
return;
}
switch (GS(id->name)) {
@@ -490,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);
@@ -560,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.
*
@@ -570,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");
@@ -601,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;
@@ -623,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);
@@ -658,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");
@@ -686,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);
@@ -708,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");
@@ -720,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);
@@ -733,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(
@@ -749,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;
@@ -778,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 {
@@ -799,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");
@@ -807,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);
}
@@ -1029,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
@@ -1056,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);
}
@@ -1077,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)) {
@@ -1208,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. */
@@ -1226,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) {
@@ -1263,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();
@@ -1297,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);
@@ -1305,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);
}
}
@@ -1314,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);
@@ -1339,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 : "";
@@ -1351,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,
@@ -1427,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. */
@@ -1457,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");
@@ -1494,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");
@@ -1523,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;
@@ -1545,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(
@@ -1566,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;
@@ -1578,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. */
}
}
@@ -1588,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;
@@ -1598,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)) {
@@ -1630,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);
@@ -1660,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);
@@ -1669,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;
@@ -1690,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. */
@@ -1709,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);
@@ -1776,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");
}
@@ -1785,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");
}
@@ -1805,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);
@@ -1819,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);
}
@@ -1861,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);
@@ -1872,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");
}
@@ -1956,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;
@@ -1974,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;
@@ -1993,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;
@@ -2053,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);
@@ -2087,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. */
@@ -2103,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;
}
@@ -2141,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");
}
@@ -2170,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");
@@ -2187,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);
@@ -2198,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)) {
@@ -2210,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);
@@ -2230,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))) {
@@ -2245,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) {
@@ -2296,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);
@@ -2309,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]);
@@ -2329,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);
}
}
@@ -2411,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);
@@ -2463,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);
@@ -2482,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);
@@ -2492,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);
@@ -2533,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);
}
}
@@ -2559,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);
@@ -2567,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);
@@ -2624,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;
}
@@ -2670,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);
@@ -2682,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 **** */
@@ -2693,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);
@@ -2706,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 5c543ce9c23..11eb31c68f6 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -368,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 4a86b16627c..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
@@ -217,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);
@@ -231,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
@@ -257,7 +258,7 @@ void DepsgraphRelationBuilder::build_inter_ik_chains(Object *object,
const bPoseChannel *rootchan,
const RootPChanMap *root_map)
{
- bPoseChannel *deepest_root = NULL;
+ bPoseChannel *deepest_root = nullptr;
const char *root_name = rootchan->name;
/* Find shared IK chain root. */
@@ -267,7 +268,7 @@ void DepsgraphRelationBuilder::build_inter_ik_chains(Object *object,
}
deepest_root = parchan;
}
- if (deepest_root == NULL) {
+ if (deepest_root == nullptr) {
return;
}
@@ -362,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. */
@@ -377,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;
@@ -442,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);
}
}
}
@@ -486,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 e81ed8b410c..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
@@ -70,7 +70,7 @@ 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);
}
@@ -78,10 +78,10 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
void DepsgraphRelationBuilder::build_freestyle_lineset(FreestyleLineSet *fls)
{
- if (fls->group != NULL) {
- build_collection(NULL, NULL, fls->group);
+ if (fls->group != nullptr) {
+ build_collection(nullptr, nullptr, fls->group);
}
- if (fls->linestyle != NULL) {
+ if (fls->linestyle != nullptr) {
build_freestyle_linestyle(fls->linestyle);
}
}
@@ -95,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);
@@ -104,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. */
@@ -128,7 +128,7 @@ 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 linesets. */
@@ -149,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 d092240e665..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,7 +183,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.operation_name = "";
node_identifier.operation_name_tag = -1;
/* Handling of commonly known scenarios. */
- if (prop != NULL && RNA_property_is_idprop(prop)) {
+ 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(
@@ -196,7 +196,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.type = NodeType::BONE;
node_identifier.component_name = pchan->name;
/* However check property name for special handling. */
- if (prop != NULL) {
+ 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. */
@@ -245,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;
}
@@ -260,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;
@@ -299,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") ||
@@ -370,7 +370,7 @@ 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". */
node_identifier.type = NodeType::PARAMETERS;
node_identifier.operation_code = OperationCode::PARAMETERS_EVAL;
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 0acf777e2f0..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 {
@@ -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 ff30bf7571a..df61a1416bd 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -52,6 +52,7 @@
#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 {
@@ -86,7 +87,7 @@ enum class EvaluationStage {
/* Workaround for areas which can not be evaluated in threads.
*
- * For example, metaballs, which are iterating over all bases and are requesting duplilists
+ * For example, metaballs, which are iterating over all bases and are requesting dupli-lists
* to see whether there are metaballs inside. */
SINGLE_THREADED_WORKAROUND,
};
@@ -364,14 +365,15 @@ 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;
@@ -418,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 a1bb0aab029..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);
}
}
@@ -515,7 +515,7 @@ 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;
@@ -535,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 {
@@ -549,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;
@@ -605,12 +605,12 @@ void update_mesh_edit_mode_pointers(const ID *id_orig, ID *id_cow)
* 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->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
@@ -646,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;
@@ -679,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;
}
}
}
@@ -710,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;
@@ -722,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;
@@ -732,11 +732,11 @@ 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);
}
@@ -747,14 +747,14 @@ 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 != nullptr) {
if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy->id)) {
- object_cow->proxy = NULL;
+ object_cow->proxy = nullptr;
}
}
- if (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 = NULL;
+ object_cow->proxy_group = nullptr;
}
}
}
@@ -785,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);
@@ -819,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? */
@@ -906,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);
@@ -926,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);
}
@@ -950,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);
}
@@ -959,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)
{
@@ -1053,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:
@@ -1081,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;
}
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_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 2c29083199a..2e0afc5d8d7 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -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/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index be1ff1753ab..c31e63b2550 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"
@@ -990,6 +991,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,
@@ -1005,6 +1015,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;
}
@@ -1025,7 +1040,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);
}
@@ -1081,6 +1096,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);
@@ -1534,7 +1553,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 {
@@ -2026,6 +2045,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) {
@@ -2070,6 +2091,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) {
@@ -2105,6 +2127,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;
@@ -2136,6 +2180,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/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 15e8e1711dd..26402e66318 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -1138,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 4366c87678f..97bea58f31b 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -757,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/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 1dcc605fc50..22fd22e4818 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -846,25 +846,11 @@ int DRW_cache_object_material_count_get(struct 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)
+ uint gpumat_array_len)
{
- if (auto_layer_names != NULL) {
- *auto_layer_names = NULL;
- *auto_layer_is_srgb = NULL;
- *auto_layer_count = 0;
- }
-
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:
@@ -2757,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). */
@@ -2919,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);
@@ -3060,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);
@@ -3155,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 a77a847409b..508a6f2c46d 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -54,10 +54,7 @@ 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);
@@ -128,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);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 2d10199782b..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;
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index c98494ebdd9..ee0597c6b21 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -1928,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");
@@ -1948,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;
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index e5a363f3115..755f794d201 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -133,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);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index a1eb9b57629..7408c8d0e38 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]);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index f699388c38c..795e7be63b1 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1182,7 +1182,7 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name);
- col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ 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/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_naming.c b/source/blender/editors/armature/armature_naming.c
index 9a1582679a4..4162e92cfea 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -79,6 +79,7 @@ static bool editbone_unique_check(void *arg, const char *name)
return dupli && dupli != data->bone;
}
+/* If bone is already in list, pass it as param to ignore it. */
void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone)
{
struct {
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/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 04b5d8f6d40..5eaf14e361b 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1461,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);
}
/* ------------------------------- */
@@ -1686,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
@@ -1720,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;
+ /* 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 exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
@@ -1758,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;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 91e70e0e089..c2f1e9f091a 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -1977,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;
@@ -1989,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_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 6a91417e7f3..09ff24f05fc 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -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/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 7ac42967dda..40f5cade0d5 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -140,56 +140,45 @@ typedef struct EditBone {
(CHECK_TYPE_INLINE(ebone, EditBone *), \
(((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED)))
-/* used in armature_select_hierarchy_exec() */
+/* used in armature_select.c and pose_select.c */
#define BONE_SELECT_PARENT 0
#define BONE_SELECT_CHILD 1
+/* armature_add.c */
+EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
+EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
+ float length,
+ bool view_aligned);
+
+/* armature_edit.c */
+float ED_armature_ebone_roll_to_vector(const EditBone *bone,
+ const float new_up_axis[3],
+ const bool axis_only);
+void ED_armature_origin_set(
+ struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around);
+void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
+void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
+
+/* armature_naming.c */
+void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone);
+void ED_armature_bone_rename(struct Main *bmain,
+ struct bArmature *arm,
+ const char *oldnamep,
+ const char *newnamep);
+void ED_armature_bones_flip_names(struct Main *bmain,
+ struct bArmature *arm,
+ struct ListBase *bones_names,
+ const bool do_strip_numbers);
+
/* armature_ops.c */
void ED_operatortypes_armature(void);
void ED_operatormacros_armature(void);
void ED_keymap_armature(struct wmKeyConfig *keyconf);
-/* editarmature.c */
-void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm);
-void ED_armature_to_edit(struct bArmature *arm);
-void ED_armature_edit_free(struct bArmature *arm);
-
-bool ED_armature_edit_deselect_all(struct Object *obedit);
-bool ED_armature_edit_deselect_all_visible(struct Object *obedit);
-
-bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len);
-bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len);
-bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C);
-
-bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
- struct View3D *v3d,
- struct Base *base,
- const unsigned int *buffer,
- short hits,
- bool extend,
- bool deselect,
- bool toggle,
- bool do_nearest);
-
-void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
- struct Base *base_select);
-
-bool ED_armature_edit_select_pick(
- struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-
-bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
-
+/* armature_relations.c */
int join_armature_exec(struct bContext *C, struct wmOperator *op);
-float ED_armature_ebone_roll_to_vector(const EditBone *bone,
- const float new_up_axis[3],
- const bool axis_only);
-EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
-EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone *ebo);
-void ED_armature_edit_sync_selection(struct ListBase *edbo);
-void ED_armature_edit_validate_active(struct bArmature *arm);
-
-void ED_armature_edit_refresh_layer_used(struct bArmature *arm);
+/* armature_select.c */
struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -198,63 +187,59 @@ struct Object *ED_armature_object_and_ebone_from_select_buffer(struct Object **o
uint objects_len,
int hit,
struct EditBone **r_ebone);
-
struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
struct Bone **r_bone);
+bool ED_armature_edit_deselect_all(struct Object *obedit);
+bool ED_armature_edit_deselect_all_visible(struct Object *obedit);
+bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len);
+bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len);
+bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C);
+bool ED_armature_edit_select_pick(
+ struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
-EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
- float length,
- bool view_aligned);
-EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
+/* armature_skinning.c */
+#define ARM_GROUPS_NAME 1
+#define ARM_GROUPS_ENVELOPE 2
+#define ARM_GROUPS_AUTO 3
+void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ struct Object *par,
+ const int mode,
+ const bool mirror);
+/* editarmature_undo.c */
+void ED_armature_undosys_type(struct UndoType *ut);
+
+/* armature_utils.c */
+void ED_armature_edit_sync_selection(struct ListBase *edbo);
+void ED_armature_edit_validate_active(struct bArmature *arm);
+void ED_armature_edit_refresh_layer_used(struct bArmature *arm);
void ED_armature_ebone_remove_ex(struct bArmature *arm, EditBone *exBone, bool clear_connected);
void ED_armature_ebone_remove(struct bArmature *arm, EditBone *exBone);
-
bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child);
EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[],
const unsigned int ebone_child_tot);
-
void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3]);
void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4]);
-
void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]);
void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]);
-
+EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
+EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone *ebo);
void ED_armature_ebone_transform_mirror_update(struct bArmature *arm,
EditBone *ebo,
bool check_select);
void ED_armature_edit_transform_mirror_update(struct Object *obedit);
-void ED_armature_origin_set(
- struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around);
-
-void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
-
-void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
-
-#define ARM_GROUPS_NAME 1
-#define ARM_GROUPS_ENVELOPE 2
-#define ARM_GROUPS_AUTO 3
-
-void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
- struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- struct Object *par,
- const int mode,
- const bool mirror);
-
-/* if bone is already in list, pass it as param to ignore it */
-void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone);
-void ED_armature_bone_rename(struct Main *bmain,
- struct bArmature *arm,
- const char *oldnamep,
- const char *newnamep);
-void ED_armature_bones_flip_names(struct Main *bmain,
- struct bArmature *arm,
- struct ListBase *bones_names,
- const bool do_strip_numbers);
+void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm);
+void ED_armature_to_edit(struct bArmature *arm);
+void ED_armature_edit_free(struct bArmature *arm);
+void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
+void ED_armature_ebone_listbase_free(struct ListBase *lb);
+void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src);
/* low level selection functions which handle */
int ED_armature_ebone_selectflag_get(const EditBone *ebone);
@@ -263,27 +248,12 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select);
void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag);
void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag);
-/* editarmature_undo.c */
-void ED_armature_undosys_type(struct UndoType *ut);
-
-/* armature_utils.c */
-void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
-void ED_armature_ebone_listbase_free(struct ListBase *lb);
-void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src);
-
-/* poseobject.c */
+/* pose_edit.c */
+struct Object *ED_pose_object_from_context(struct bContext *C);
bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
-bool ED_pose_deselect_all_multi_ex(struct Base **bases,
- uint bases_len,
- int select_mode,
- const bool ignore_visibility);
-bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
-bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
-void ED_pose_bone_select_tag_update(struct Object *ob);
-void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
/* Corresponds to eAnimvizCalcRange. */
typedef enum ePosePathCalcRange {
@@ -296,7 +266,26 @@ void ED_pose_recalculate_paths(struct bContext *C,
struct Object *ob,
ePosePathCalcRange range);
-struct Object *ED_pose_object_from_context(struct bContext *C);
+/* pose_select.c */
+bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
+ struct View3D *v3d,
+ struct Base *base,
+ const unsigned int *buffer,
+ short hits,
+ bool extend,
+ bool deselect,
+ bool toggle,
+ bool do_nearest);
+void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
+ struct Base *base_select);
+bool ED_pose_deselect_all_multi_ex(struct Base **bases,
+ uint bases_len,
+ int select_mode,
+ const bool ignore_visibility);
+bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
+bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
+void ED_pose_bone_select_tag_update(struct Object *ob);
+void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
/* meshlaplacian.c */
void ED_mesh_deform_bind_callback(struct MeshDeformModifierData *mmd,
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/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_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5dcfcbc88b3..7332f3ee776 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1889,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) {
@@ -2240,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);
@@ -2349,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)) {
@@ -2357,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]'");
@@ -2645,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:
@@ -10602,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) {
@@ -10673,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 4770a85460b..c1018a67fb3 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -119,6 +119,7 @@ typedef struct DrawInfo {
} vector;
struct {
ImBuf *image_cache;
+ bool inverted;
} geom;
struct {
IconImage *image;
@@ -804,45 +805,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 +862,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 +871,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);
}
}
@@ -1830,15 +1834,23 @@ static void icon_draw_size(float x,
}
#endif
+ /* If the theme is light, we will adjust the icon colors. */
+ const bool invert = (rgb_to_grayscale_byte(btheme->tui.wcol_toolbar_item.inner) > 128);
+ const bool geom_inverted = di->data.geom.inverted;
+
/* This could re-generate often if rendered at different sizes in the one interface.
* TODO(campbell): support caching multiple sizes. */
ImBuf *ibuf = di->data.geom.image_cache;
- if ((ibuf == NULL) || (ibuf->x != w) || (ibuf->y != h)) {
+ if ((ibuf == NULL) || (ibuf->x != w) || (ibuf->y != h) || (invert != geom_inverted)) {
if (ibuf) {
IMB_freeImBuf(ibuf);
}
+ if (invert != geom_inverted) {
+ BKE_icon_geom_invert_lightness(icon->obj);
+ }
ibuf = BKE_icon_geom_rasterize(icon->obj, w, h);
di->data.geom.image_cache = ibuf;
+ di->data.geom.inverted = invert;
}
GPU_blend_set_func_separate(
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index b7fd953ed63..9a967c3b8f3 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -74,79 +74,37 @@
#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 +114,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 +142,87 @@ 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 38c17f3c395..7a0c04be356 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -1391,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);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index be9071e75a1..4c86e3252ed 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -6871,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;
@@ -7053,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..92032c3b18c 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1742,9 +1742,8 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
if ((okwidth > 0.0f) && (strwidth > okwidth)) {
- /* utf8 two-dots leader '..' (shorter than ellipsis '...'),
- * some compilers complain with real literal string. */
- const char sep[] = {0xe2, 0x80, 0xA5, 0x0};
+ /* Ellipsis. Some compilers complain with real literal string. */
+ const char sep[] = {0xe2, 0x80, 0xA6, 0x0};
const int sep_len = sizeof(sep) - 1;
const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
float parts_strwidth;
@@ -2662,10 +2661,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/mesh/editmesh_automerge.c b/source/blender/editors/mesh/editmesh_automerge.c
index ffde9f338b4..f9910f01f47 100644
--- a/source/blender/editors/mesh/editmesh_automerge.c
+++ b/source/blender/editors/mesh/editmesh_automerge.c
@@ -123,62 +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) {
- GHashIterator gh_iter;
- BMVert **v_survivors, **v_iter;
- uint v_survivors_len = 0;
- if (split_faces) {
- BMVert *v_src, *v_dst;
- GHASH_ITER (gh_iter, ghash_targetmap) {
- v_src = BLI_ghashIterator_getKey(&gh_iter);
- v_dst = BLI_ghashIterator_getValue(&gh_iter);
- BM_elem_flag_disable(v_src, BM_ELEM_TAG);
- BM_elem_flag_disable(v_dst, BM_ELEM_TAG);
- }
-
- int v_survivors_len_max = BLI_ghash_len(ghash_targetmap);
- GHASH_ITER (gh_iter, ghash_targetmap) {
- v_src = BLI_ghashIterator_getKey(&gh_iter);
- v_dst = BLI_ghashIterator_getValue(&gh_iter);
- if (!BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
- BM_elem_flag_enable(v_src, BM_ELEM_TAG);
- }
- if (BM_elem_flag_test(v_dst, BM_ELEM_TAG)) {
- v_survivors_len_max--;
- }
- }
-
- v_survivors = MEM_mallocN(sizeof(*v_survivors) * v_survivors_len_max, __func__);
- v_iter = &v_survivors[0];
- GHASH_ITER (gh_iter, ghash_targetmap) {
- v_dst = BLI_ghashIterator_getValue(&gh_iter);
- if (!BM_elem_flag_test(v_dst, BM_ELEM_TAG)) {
- *v_iter = v_dst;
- v_iter++;
- v_survivors_len++;
- }
- }
- }
-
BMO_op_exec(bm, &weldop);
-
- BMEdge **edgenet = NULL;
- int edgenet_alloc_len = 0;
- if (split_faces) {
- v_iter = &v_survivors[0];
- for (int i = v_survivors_len; i--; v_iter++) {
- BM_vert_weld_linked_wire_edges_into_linked_faces(
- bm, *v_iter, dist, &edgenet, &edgenet_alloc_len);
- }
-
- MEM_freeN(v_survivors);
- }
-
- if (edgenet) {
- MEM_freeN(edgenet);
- }
}
BMO_op_finish(bm, &weldop);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index f19a988809a..69274f77049 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -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/object/object_add.c b/source/blender/editors/object/object_add.c
index 6c65da3ee48..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));
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_relations.c b/source/blender/editors/object/object_relations.c
index b9c89b9944f..f9e2a2b8a1a 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1758,10 +1758,10 @@ static Collection *single_object_users_collection(Main *bmain,
bmain, scene, child->collection, flag, copy_collections, false);
if (is_master_collection && copy_collections && child->collection != collection_child_new) {
- /* We do not want a collection sync here, our collections are in a complete unsetled state
- * currently. With current code, that would lead to a memory leak - because of reasons.
+ /* 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
- * viewlayers/collections caching at the end. */
+ * 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);
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/screen/area.c b/source/blender/editors/screen/area.c
index ef201603b30..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 {
@@ -1438,9 +1455,8 @@ static void region_rect_recursive(
}
/* Fix any negative dimensions. This can happen when a quad split 3d view gets to small. (see
- * T72200). BLI_rcti_init() sanitizes, making sure min values are <= max values. */
- BLI_rcti_init(
- &ar->winrct, ar->winrct.xmin, ar->winrct.xmax, ar->winrct.ymin, ar->winrct.ymax);
+ * T72200). */
+ BLI_rcti_sanitize(&ar->winrct);
quad++;
}
@@ -1479,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 */
@@ -1501,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. */
@@ -1599,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);
@@ -1624,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);
@@ -1818,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);
@@ -2321,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);
}
/**
@@ -2565,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;
@@ -3327,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;
@@ -3338,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;
@@ -3347,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/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index dd09def2df6..14ea3aca623 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -3643,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);
@@ -3676,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;
}
/** \} */
@@ -3743,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);
}
@@ -3775,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;
}
/** \} */
@@ -4114,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);
@@ -4160,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);
@@ -4186,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);
@@ -4840,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_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 5f3992852f0..2bc36be42ab 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -3725,7 +3725,7 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float ik_target[3];
const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- /* The pose brush applies all enabled symmetry axis in a sigle iteration, so the rest can be
+ /* 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;
@@ -3902,7 +3902,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
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
- * closert to it. */
+ * closer to it. */
float len = len_v3v3(gftd.pos_avg, pose_origin);
if (len < prev_len) {
prev_len = len;
@@ -8308,13 +8308,13 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C)
static void SCULPT_OT_optimize(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Optimize";
+ ot->name = "Rebuild BVH";
ot->idname = "SCULPT_OT_optimize";
ot->description = "Recalculate the sculpt BVH to improve performance";
/* api callbacks */
ot->exec = sculpt_optimize_exec;
- ot->poll = sculpt_and_dynamic_topology_poll;
+ ot->poll = sculpt_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
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..095b30aa57b 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1718,7 +1718,9 @@ static int mouse_action_keys(bAnimContext *ac,
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
- if (wait_to_deselect_others && is_selected) {
+ /* Rather than deselecting others, users may want to drag to box-select (drag from empty space)
+ * or tweak-translate an already selected item. If these cases may apply, delay deselection. */
+ if (wait_to_deselect_others && (!found || is_selected)) {
ret_value = OPERATOR_RUNNING_MODAL;
}
else {
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_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index bf6683ffc33..ac54b1177ba 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/filelist.c b/source/blender/editors/space_file/filelist.c
index a567aeed826..800726c6fb0 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -947,15 +947,16 @@ 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,
+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 +970,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 +1029,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 +1041,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 fc03453a5cc..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);
@@ -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/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_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 64570459532..03ff680a93d 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..c145f5d333f 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,31 @@ 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 +207,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 +335,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 +364,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 +403,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 +416,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 +429,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_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 589375530f5..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)
{
@@ -1066,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);
@@ -1161,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";
@@ -1171,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 20fba7aa919..bef4a7cdd22 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2113,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 ea93ef2e040..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);
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_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 7db1a6123e8..59697c00c9c 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1027,19 +1027,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 a4714249da2..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;
}
}
@@ -859,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;
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_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 441a6eb0ea5..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)) {
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_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/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index d90590bce82..9a9f5885021 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/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 4f88578596f..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"
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/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 5a5c3ace552..a7dd34a5f96 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1042,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",
@@ -1101,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"
@@ -1224,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);
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 201194232db..84328b8dfd4 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1064,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_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_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/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/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/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_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_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 9db993cca59..39efe838bab 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -492,8 +492,15 @@ typedef struct DisplaceModifierData {
char defgrp_name[64];
float midlevel;
int space;
+ short flag;
+ char _pad[6];
} DisplaceModifierData;
+/* DisplaceModifierData->flag */
+enum {
+ MOD_DISP_INVERT_VGROUP = (1 << 0),
+};
+
/* DisplaceModifierData->direction */
enum {
MOD_DISP_DIR_X = 0,
@@ -611,6 +618,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),
@@ -1292,7 +1300,6 @@ typedef struct WarpModifierData {
char defgrp_name[64];
float strength;
float falloff_radius;
- /** Not used yet. */
char flag;
char falloff_type;
char _pad[6];
@@ -1300,6 +1307,11 @@ typedef struct WarpModifierData {
#define MOD_WARP_VOLUME_PRESERVE 1
+/* WarpModifierData->flag */
+enum {
+ MOD_WARP_INVERT_VGROUP = (1 << 0),
+};
+
typedef enum {
eWarp_Falloff_None = 0,
eWarp_Falloff_Curve = 1,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index fbed0754046..cbed2af7df2 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -374,8 +374,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_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_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index f0a852a7a1a..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];
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/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index e900160a653..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},
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_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_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 589ce1414bb..6f2f12ebf98 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1838,6 +1838,11 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WarpModifier_defgrp_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WARP_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
rna_def_modifier_generic_map_info(srna);
}
@@ -2889,6 +2894,11 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Space", "");
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_DISP_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
rna_def_modifier_generic_map_info(srna);
}
@@ -3217,6 +3227,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 ab813f62973..70192198e14 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 \
{ \
@@ -1574,9 +1582,9 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
ModifierData *mod_dst = ED_object_modifier_add(
NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type);
- /* XXX Current handling of 'copy' from particlesystem modifier is *very* bad (it keeps same psys
+ /* 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 Obejct editing area rely on
+ * 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. */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index a5852a30661..29ec968fe2a 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -890,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) */
@@ -909,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;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index ea1fb1eb489..262048e55c2 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -941,8 +941,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);
}
}
@@ -952,8 +952,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);
}
}
@@ -985,10 +985,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)
@@ -1001,10 +1003,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),
@@ -2959,17 +2963,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 67b43cb13df..746f9042dd8 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" \
@@ -2640,7 +2647,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));
@@ -4458,17 +4467,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", ""},
@@ -4528,12 +4526,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 56f19d313fd..b9fb8638c49 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2231,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);
@@ -2508,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");
}
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 249581d22bf..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"},
@@ -2185,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 4d4ab64abb9..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;
}
@@ -335,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/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_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 9cb694be88b..7f65b3bb5ae 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -174,6 +174,7 @@ static void displaceModifier_do_task(void *__restrict userdata,
DisplaceUserdata *data = (DisplaceUserdata *)userdata;
DisplaceModifierData *dmd = data->dmd;
MDeformVert *dvert = data->dvert;
+ const bool invert_vgroup = (dmd->flag & MOD_DISP_INVERT_VGROUP) != 0;
float weight = data->weight;
int defgrp_index = data->defgrp_index;
int direction = data->direction;
@@ -192,7 +193,8 @@ static void displaceModifier_do_task(void *__restrict userdata,
float local_vec[3];
if (dvert) {
- weight = defvert_find_weight(dvert + iter, defgrp_index);
+ weight = invert_vgroup ? 1.0f - defvert_find_weight(dvert + iter, defgrp_index) :
+ defvert_find_weight(dvert + iter, defgrp_index);
if (weight == 0.0f) {
return;
}
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 7155498c942..ba017577004 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -175,7 +175,7 @@ static void warpModifier_do(WarpModifierData *wmd,
int i;
int defgrp_index;
MDeformVert *dvert, *dv = NULL;
-
+ const bool invert_vgroup = (wmd->flag & MOD_WARP_INVERT_VGROUP) != 0;
float(*tex_co)[3] = NULL;
if (!(wmd->object_from && wmd->object_to)) {
@@ -235,7 +235,8 @@ static void warpModifier_do(WarpModifierData *wmd,
/* skip if no vert group found */
if (defgrp_index != -1) {
dv = &dvert[i];
- weight = defvert_find_weight(dv, defgrp_index) * strength;
+ weight = invert_vgroup ? 1.0f - defvert_find_weight(dv, defgrp_index) * strength :
+ defvert_find_weight(dv, defgrp_index) * strength;
if (weight <= 0.0f) {
continue;
}
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/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/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/usd/CMakeLists.txt b/source/blender/usd/CMakeLists.txt
index f4cf53e573f..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
diff --git a/source/blender/usd/intern/usd_capi.cc b/source/blender/usd/intern/usd_capi.cc
index a7c268bf754..83e11cd7bf3 100644
--- a/source/blender/usd/intern/usd_capi.cc
+++ b/source/blender/usd/intern/usd_capi.cc
@@ -24,6 +24,8 @@
#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"
@@ -40,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"
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 73fbde4148e..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
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_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/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 59975080f49..383ca806d35 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -1088,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/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 f5970e8fb61..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,6 +110,8 @@ static int wm_operator_call_internal(bContext *C,
const bool poll_only,
wmEvent *event);
+static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot);
+
/* -------------------------------------------------------------------- */
/** \name Event Management
* \{ */
@@ -126,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);
}
@@ -177,10 +167,6 @@ void wm_event_free(wmEvent *event)
}
}
- if (event->tablet_data) {
- MEM_freeN((void *)event->tablet_data);
- }
-
MEM_freeN(event);
}
@@ -195,9 +181,6 @@ 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);
}
@@ -682,6 +665,82 @@ static void wm_handler_ui_cancel(bContext *C)
/** \} */
/* -------------------------------------------------------------------- */
+/** \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
* \{ */
@@ -762,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)
{
@@ -1301,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->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
-
/**
* Also used for exec when 'event' is NULL.
*/
@@ -1954,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) {
@@ -2011,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;
}
}
@@ -2103,10 +1866,10 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
* 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(const bContext *C,
- wmOperator *op,
- wmEvent *event,
- bool *dbl_click_disabled)
+static void wm_event_modalkeymap_begin(const bContext *C,
+ wmOperator *op,
+ wmEvent *event,
+ bool *dbl_click_disabled)
{
BLI_assert(event->type != EVT_MODAL_MAP);
@@ -2159,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;
@@ -2196,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;
@@ -2221,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++;
@@ -2236,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--;
@@ -2298,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;
@@ -2636,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 */
@@ -2693,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);
@@ -2990,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 {
@@ -4099,91 +3847,6 @@ 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;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -4421,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)
+void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
- 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)
-{
- 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__);
}
}
@@ -4607,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;
@@ -4614,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 */
@@ -4632,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;
}
}
@@ -4646,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;
@@ -4696,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!) */
@@ -4706,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");
@@ -4737,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);
}
@@ -5003,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
@@ -5024,96 +4689,12 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
BKE_spacedata_draw_locks(lock);
}
-#ifdef WITH_INPUT_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;
@@ -5141,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 */
@@ -5167,6 +4748,8 @@ static wmKeyMapItem *wm_kmi_from_event(bContext *C,
return NULL;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Cursor Keymap Status
*
@@ -5379,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;
}
@@ -5475,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_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 1809a233ce1..f5e507fc317 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -1109,12 +1109,13 @@ const char *WM_key_event_string(const short type, const bool compact)
case LEFTCTRLKEY:
case RIGHTCTRLKEY:
if (platform == MACOS) {
- return "^";
+ return key_event_glyph_or_text(font_id, "^", "\xe2\x8c\x83");
}
return IFACE_("Ctrl");
case LEFTALTKEY:
case RIGHTALTKEY: {
if (platform == MACOS) {
+ /* Option symbol on Mac keyboard. */
single_glyph = "\xe2\x8c\xa5";
}
return key_event_glyph_or_text(font_id, IFACE_("Alt"), single_glyph);
@@ -1124,28 +1125,23 @@ const char *WM_key_event_string(const short type, const bool compact)
return key_event_glyph_or_text(font_id, IFACE_("Cmd"), "\xe2\x8c\x98");
}
else if (platform == MSWIN) {
- return key_event_glyph_or_text(font_id, IFACE_("Win"), "\xe2\x8a\x9e");
+ return key_event_glyph_or_text(font_id, IFACE_("Win"), "\xe2\x9d\x96");
}
- return IFACE_("OSkey");
+ return IFACE_("OS");
} break;
- case TABKEY: {
- if (platform == MACOS) {
- single_glyph = "\xe2\x86\xb9";
- }
- return key_event_glyph_or_text(font_id, IFACE_("Tab"), single_glyph);
- }
+ case TABKEY:
+ return key_event_glyph_or_text(font_id, IFACE_("Tab"), "\xe2\xad\xbe");
case BACKSPACEKEY:
return key_event_glyph_or_text(font_id, IFACE_("Bksp"), "\xe2\x8c\xab");
case ESCKEY:
- return key_event_glyph_or_text(font_id, IFACE_("Esc"), NULL /* "\xe2\x8e\x8b" */);
- case RETKEY: {
if (platform == MACOS) {
- single_glyph = "\xe2\x8f\x8e";
+ single_glyph = "\xe2\x8e\x8b";
}
- return key_event_glyph_or_text(font_id, IFACE_("Enter"), single_glyph);
- }
+ return key_event_glyph_or_text(font_id, IFACE_("Esc"), single_glyph);
+ case RETKEY:
+ return key_event_glyph_or_text(font_id, IFACE_("Enter"), "\xe2\x86\xb5");
case SPACEKEY:
- return key_event_glyph_or_text(font_id, IFACE_("Space"), NULL /* "\xe2\x90\xa3" */);
+ return key_event_glyph_or_text(font_id, IFACE_("Space"), "\xe2\x90\xa3");
case LEFTARROWKEY:
return key_event_glyph_or_text(font_id, IFACE_("Left"), "\xe2\x86\x90");
case UPARROWKEY:
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 678b7d9dcee..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
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 3218f8c45e4..8e49e47c492 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -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 583a11f1244..4f70eeefb76 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -548,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) {
@@ -555,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 */
@@ -703,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!) */
@@ -1207,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));
@@ -1292,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 */
@@ -1456,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 */
@@ -1543,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;
@@ -2099,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;
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -2190,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/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 252eb9673ae..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,
@@ -359,7 +361,8 @@ enum {
(((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)
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index e8c6e9251bc..afec54a636c 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -102,15 +102,18 @@ static void sig_handle_crash_backtrace(FILE *fp)
static void sig_handle_crash(int signum)
{
- wmWindowManager *wm = G_MAIN->wm.first;
+ /* Might be called after WM/Main exit, so needs to be careful about NULL-checking before
+ * de-referencing. */
+
+ wmWindowManager *wm = G_MAIN ? G_MAIN->wm.first : NULL;
# ifdef USE_WRITE_CRASH_BLEND
- if (wm->undo_stack) {
+ if (wm && wm->undo_stack) {
struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
if (memfile) {
char fname[FILE_MAX];
- if (!G_MAIN->name[0]) {
+ if (!(G_MAIN && G_MAIN->name[0])) {
BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
}
else {
@@ -131,7 +134,7 @@ static void sig_handle_crash(int signum)
char fname[FILE_MAX];
- if (!G_MAIN->name[0]) {
+ if (!(G_MAIN && G_MAIN->name[0])) {
BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
}
else {
diff --git a/source/tools b/source/tools
-Subproject ce943dad8a21b4784e2dcef12d8f893473cddb7
+Subproject 603f076606f052adc97d937633bfeb9b268ec20
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index 7da65bcc8b9..bcf77fb6de7 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -16,6 +16,9 @@ if(WITH_GTESTS)
add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
add_subdirectory(bmesh)
+ if(WITH_CODEC_FFMPEG)
+ add_subdirectory(ffmpeg)
+ endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()
diff --git a/tests/gtests/blenlib/BLI_array_store_test.cc b/tests/gtests/blenlib/BLI_array_store_test.cc
index 632107c69df..3bca66b613e 100644
--- a/tests/gtests/blenlib/BLI_array_store_test.cc
+++ b/tests/gtests/blenlib/BLI_array_store_test.cc
@@ -2,10 +2,10 @@
#include "testing/testing.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_array_store.h"
-
-#include "MEM_guardedalloc.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
diff --git a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
index 85e8ae3f141..f377d5a8247 100644
--- a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
+++ b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc
@@ -2,8 +2,9 @@
#include "testing/testing.h"
-extern "C" {
#include "MEM_guardedalloc.h"
+
+extern "C" {
#include "BLI_math.h"
#include "BLI_rand.h"
#include "PIL_time.h"
@@ -321,15 +322,20 @@ TEST(delaunay, OnePt)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {{0.0f, 0.0f}};
+ const char *spec = R"(1 0 0
+ 0.0 0.0
+ )";
- fill_input_verts(&in, p, 1);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 1);
EXPECT_EQ(out->edges_len, 0);
EXPECT_EQ(out->faces_len, 0);
- EXPECT_EQ(out->vert_coords[0][0], 0.0f);
- EXPECT_EQ(out->vert_coords[0][1], 0.0f);
+ if (out->verts_len >= 1) {
+ EXPECT_EQ(out->vert_coords[0][0], 0.0f);
+ EXPECT_EQ(out->vert_coords[0][1], 0.0f);
+ }
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -338,9 +344,12 @@ TEST(delaunay, TwoPt)
CDT_input in;
CDT_result *out;
int v0_out, v1_out, e0_out;
- float p[][2] = {{0.0f, -0.75f}, {0.0f, 0.75f}};
+ const char *spec = R"(2 0 0
+ 0.0 -0.75
+ 0.0 0.75
+ )";
- fill_input_verts(&in, p, 2);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 2);
EXPECT_EQ(out->edges_len, 1);
@@ -350,12 +359,15 @@ TEST(delaunay, TwoPt)
EXPECT_NE(v0_out, -1);
EXPECT_NE(v1_out, -1);
EXPECT_NE(v0_out, v1_out);
- EXPECT_NEAR(out->vert_coords[v0_out][0], p[0][0], in.epsilon);
- EXPECT_NEAR(out->vert_coords[v0_out][1], p[0][1], in.epsilon);
- EXPECT_NEAR(out->vert_coords[v1_out][0], p[1][0], in.epsilon);
- EXPECT_NEAR(out->vert_coords[v1_out][1], p[1][1], in.epsilon);
+ if (out->verts_len >= 2) {
+ EXPECT_NEAR(out->vert_coords[v0_out][0], 0.0, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v0_out][1], -0.75, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v1_out][0], 0.0, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v1_out][1], 0.75, in.epsilon);
+ }
e0_out = get_edge(out, v0_out, v1_out);
EXPECT_EQ(e0_out, 0);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -366,9 +378,13 @@ TEST(delaunay, ThreePt)
int v0_out, v1_out, v2_out;
int e0_out, e1_out, e2_out;
int f0_out;
- float p[][2] = {{-0.1f, -0.75f}, {0.1f, 0.75f}, {0.5f, 0.5f}};
+ const char *spec = R"(3 0 0
+ -0.1 -0.75
+ 0.1 0.75
+ 0.5 0.5
+ )";
- fill_input_verts(&in, p, 3);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 3);
EXPECT_EQ(out->edges_len, 3);
@@ -385,6 +401,7 @@ TEST(delaunay, ThreePt)
EXPECT_TRUE(e0_out != e1_out && e0_out != e2_out && e1_out != e2_out);
f0_out = get_face_tri(out, v0_out, v2_out, v1_out);
EXPECT_EQ(f0_out, 0);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -393,11 +410,14 @@ TEST(delaunay, ThreePtsMerge)
CDT_input in;
CDT_result *out;
int v0_out, v1_out, v2_out;
- /* equilateral triangle with side 0.1 */
- float p[][2] = {{-0.05f, -0.05f}, {0.05f, -0.05f}, {0.0f, 0.03660254f}};
+ const char *spec = R"(3 0 0
+ -0.05 -0.05
+ 0.05 -0.05
+ 0.0 0.03660254
+ )";
/* First with epsilon such that points are within that distance of each other */
- fill_input_verts(&in, p, 3);
+ fill_input_from_string(&in, spec);
in.epsilon = 0.21f;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 1);
@@ -421,6 +441,7 @@ TEST(delaunay, ThreePtsMerge)
EXPECT_EQ(out->verts_len, 3);
EXPECT_EQ(out->edges_len, 3);
EXPECT_EQ(out->faces_len, 1);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -428,13 +449,19 @@ TEST(delaunay, MixedPts)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {{0.0f, 0.0f}, {-0.5f, -0.5f}, {-0.4f, -0.25f}, {-0.3f, 0.8}};
- int e[][2] = {{0, 1}, {1, 2}, {2, 3}};
int v0_out, v1_out, v2_out, v3_out;
int e0_out, e1_out, e2_out;
+ const char *spec = R"(4 3 0
+ 0.0 0.0
+ -0.5 -0.5
+ -0.4 -0.25
+ -0.3 0.8
+ 0 1
+ 1 2
+ 2 3
+ )";
- fill_input_verts(&in, p, 4);
- add_input_edges(&in, e, 3);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 6);
@@ -450,6 +477,134 @@ TEST(delaunay, MixedPts)
EXPECT_TRUE(out_edge_has_input_id(out, e0_out, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1_out, 1));
EXPECT_TRUE(out_edge_has_input_id(out, e2_out, 2));
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, Quad0)
+{
+ CDT_input in;
+ CDT_result *out;
+ int e_diag_out;
+ const char *spec = R"(4 0 0
+ 0.0 1.0
+ 1,0. 0.0
+ 2.0 0.1
+ 2.25 0.5
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 4);
+ EXPECT_EQ(out->edges_len, 5);
+ e_diag_out = get_edge(out, 1, 3);
+ EXPECT_NE(e_diag_out, -1);
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, Quad1)
+{
+ CDT_input in;
+ CDT_result *out;
+ int e_diag_out;
+ const char *spec = R"(4 0 0
+ 0.0 0.0
+ 0.9 -1.0
+ 2.0 0.0
+ 0.9 3.0
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 4);
+ EXPECT_EQ(out->edges_len, 5);
+ e_diag_out = get_edge(out, 0, 2);
+ EXPECT_NE(e_diag_out, -1);
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, Quad2)
+{
+ CDT_input in;
+ CDT_result *out;
+ int e_diag_out;
+ const char *spec = R"(4 0 0
+ 0.5 0.0
+ 0.15 0.2
+ 0.3 0.4
+ .45 0.35
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 4);
+ EXPECT_EQ(out->edges_len, 5);
+ e_diag_out = get_edge(out, 1, 3);
+ EXPECT_NE(e_diag_out, -1);
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, Quad3)
+{
+ CDT_input in;
+ CDT_result *out;
+ int e_diag_out;
+ const char *spec = R"(4 0 0
+ 0.5 0.0
+ 0.0 0.0
+ 0.3 0.4
+ .45 0.35
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 4);
+ EXPECT_EQ(out->edges_len, 5);
+ e_diag_out = get_edge(out, 0, 2);
+ EXPECT_NE(e_diag_out, -1);
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, Quad4)
+{
+ CDT_input in;
+ CDT_result *out;
+ int e_diag_out;
+ const char *spec = R"(4 0 0
+ 1.0 1.0
+ 0.0 0.0
+ 1.0 -3.0
+ 0.0 1.0
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ EXPECT_EQ(out->verts_len, 4);
+ EXPECT_EQ(out->edges_len, 5);
+ e_diag_out = get_edge(out, 0, 1);
+ EXPECT_NE(e_diag_out, -1);
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, LineInSquare)
+{
+ CDT_input in;
+ CDT_result *out;
+ const char *spec = R"(6 1 1
+ -0.5 -0.5
+ 0.5 -0.5
+ -0.5 0.5
+ 0.5 0.5
+ -0.25 0.0
+ 0.25 0.0
+ 4 5
+ 0 1 3 2
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out->verts_len, 6);
+ EXPECT_EQ(out->faces_len, 1);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -457,13 +612,18 @@ TEST(delaunay, CrossSegs)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {{-0.5f, 0.0f}, {0.5f, 0.0f}, {-0.4f, -0.5f}, {0.4f, 0.5f}};
- int e[][2] = {{0, 1}, {2, 3}};
int v0_out, v1_out, v2_out, v3_out, v_intersect;
int i;
+ const char *spec = R"(4 2 0
+ -0.5 0.0
+ 0.5 0.0
+ -0.4 -0.5
+ 0.4 0.5
+ 0 1
+ 2 3
+ )";
- fill_input_verts(&in, p, 4);
- add_input_edges(&in, e, 2);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 5);
EXPECT_EQ(out->edges_len, 8);
@@ -481,8 +641,11 @@ TEST(delaunay, CrossSegs)
}
}
EXPECT_NE(v_intersect, -1);
- EXPECT_NEAR(out->vert_coords[v_intersect][0], 0.0f, in.epsilon);
- EXPECT_NEAR(out->vert_coords[v_intersect][1], 0.0f, in.epsilon);
+ if (v_intersect != -1) {
+ EXPECT_NEAR(out->vert_coords[v_intersect][0], 0.0f, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v_intersect][1], 0.0f, in.epsilon);
+ }
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -490,23 +653,27 @@ TEST(delaunay, DiamondCross)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {
- {0.0f, 0.0f},
- {1.0f, 3.0f},
- {2.0f, 0.0f},
- {1.0f, -3.0f},
- {0.0f, 0.0f},
- {1.0f, -3.0f},
- {1.0f, 3.0f},
- };
- int e[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}};
-
- fill_input_verts(&in, p, 7);
- add_input_edges(&in, e, 5);
+ const char *spec = R"(7 5 0
+ 0.0 0.0
+ 1.0 3.0
+ 2.0 0.0
+ 1.0 -3.0
+ 0.0 0.0
+ 1.0 -3.0
+ 1.0 3.0
+ 0 1
+ 1 2
+ 2 3
+ 3 4
+ 5 6
+ )";
+
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
EXPECT_EQ(out->faces_len, 2);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -515,27 +682,35 @@ TEST(delaunay, TwoDiamondsCrossed)
CDT_input in;
CDT_result *out;
/* Input has some repetition of vertices, on purpose */
- float p[][2] = {
- {0.0f, 0.0f},
- {1.0f, 2.0f},
- {2.0f, 0.0f},
- {1.0f, -2.0f},
- {0.0f, 0.0f},
- {3.0f, 0.0f},
- {4.0f, 2.0f},
- {5.0f, 0.0f},
- {4.0f, -2.0f},
- {3.0f, 0.0f},
- {0.0f, 0.0f},
- {5.0f, 0.0f},
- };
int e[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {6, 7}, {7, 8}, {8, 9}, {10, 11}};
int v_out[12];
int e_out[9], e_cross_1, e_cross_2, e_cross_3;
int i;
+ const char *spec = R"(12 9 0
+ 0.0 0.0
+ 1.0 2.0
+ 2.0 0.0
+ 1.0 -2.0
+ 0.0 0.0
+ 3.0 0.0
+ 4.0 2.0
+ 5.0 0.0
+ 4.0 -2.0
+ 3.0 0.0
+ 0.0 0.0
+ 5.0 0.0
+ 0 1
+ 1 2
+ 2 3
+ 3 4
+ 5 6
+ 6 7
+ 7 8
+ 8 9
+ 10 11
+ )";
- fill_input_verts(&in, p, 12);
- add_input_edges(&in, e, 9);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 8);
EXPECT_EQ(out->edges_len, 15);
@@ -561,6 +736,7 @@ TEST(delaunay, TwoDiamondsCrossed)
EXPECT_TRUE(out_edge_has_input_id(out, e_cross_1, 8));
EXPECT_TRUE(out_edge_has_input_id(out, e_cross_2, 8));
EXPECT_TRUE(out_edge_has_input_id(out, e_cross_3, 8));
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -569,53 +745,63 @@ TEST(delaunay, ManyCross)
CDT_input in;
CDT_result *out;
/* Input has some repetition of vertices, on purpose */
- float p[][2] = {
- /* upper: verts 0 to 10 */
- {0.0f, 0.0f},
- {6.0f, 9.0f},
- {15.0f, 18.0f},
- {35.0f, 13.0f},
- {43.0f, 18.0f},
- {57.0f, 12.0f},
- {69.0f, 10.0f},
- {78.0f, 0.0f},
- {91.0f, 0.0f},
- {107.0f, 22.0f},
- {123.0f, 0.0f},
- /* lower part 1: verts 11 to 16 */
- {0.0f, 0.0f},
- {10.0f, -14.0f},
- {35.0f, -8.0f},
- {43.0f, -12.0f},
- {64.0f, -13.0f},
- {78.0f, 0.0f},
- /* lower part 2: verts 17 to 20 */
- {91.0f, 0.0f},
- {102.0f, -9.0f},
- {116.0f, -9.0f},
- {123.0f, 0.0f},
- /* cross 1: verts 21, 22 */
- {43.0f, 18.0f},
- {43.0f, -12.0f},
- /* cross 2: verts 23, 24 */
- {107.0f, 22.0f},
- {102.0f, -9.0f},
- /* cross all: verts 25, 26 */
- {0.0f, 0.0f},
- {123.0f, 0.0f},
- };
- int e[][2] = {
- {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}, {6, 7},
- {7, 8}, {8, 9}, {9, 10}, {11, 12}, {12, 13}, {13, 14}, {14, 15},
- {15, 16}, {17, 18}, {18, 19}, {19, 20}, {21, 22}, {23, 24}, {25, 26},
- };
-
- fill_input_verts(&in, p, 27);
- add_input_edges(&in, e, 21);
+ const char *spec = R"(27 21 0
+ 0.0 0.0
+ 6.0 9.0
+ 15.0 18.0
+ 35.0 13.0
+ 43.0 18.0
+ 57.0 12.0
+ 69.0 10.0
+ 78.0 0.0
+ 91.0 0.0
+ 107.0 22.0
+ 123.0 0.0
+ 0.0 0.0
+ 10.0 -14.0
+ 35.0 -8.0
+ 43.0 -12.0
+ 64.0 -13.0
+ 78.0 0.0
+ 91.0 0.0
+ 102.0 -9.0
+ 116.0 -9.0
+ 123.0 0.0
+ 43.0 18.0
+ 43.0 -12.0
+ 107.0 22.0
+ 102.0 -9.0
+ 0.0 0.0
+ 123.0 0.0
+ 0 1
+ 1 2
+ 2 3
+ 3 4
+ 4 5
+ 5 6
+ 6 7
+ 7 8
+ 8 9
+ 9 10
+ 11 12
+ 12 13
+ 13 14
+ 14 15
+ 15 16
+ 17 18
+ 18 19
+ 19 20
+ 21 22
+ 23 24
+ 25 26
+ )";
+
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 19);
EXPECT_EQ(out->edges_len, 46);
EXPECT_EQ(out->faces_len, 28);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -623,16 +809,20 @@ TEST(delaunay, TwoFace)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {
- {0.0f, 0.0f}, {1.0f, 0.0f}, {0.5f, 1.0f}, {1.1f, 1.0f}, {1.1f, 0.0f}, {1.6f, 1.0f}};
- int f[] = {/* 0 */ 0, 1, 2, /* 1 */ 3, 4, 5};
- int fstart[] = {0, 3};
- int flen[] = {3, 3};
int v_out[6], f0_out, f1_out, e0_out, e1_out, e2_out;
int i;
+ const char *spec = R"(6 0 2
+ 0.0 0.0
+ 1.0 0.0
+ 0.5 1.0
+ 1.1 1.0
+ 1.1 0.0
+ 1.6 1.0
+ 0 1 2
+ 3 4 5
+ )";
- fill_input_verts(&in, p, 6);
- add_input_faces(&in, f, fstart, flen, 2);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->edges_len, 9);
@@ -656,6 +846,7 @@ TEST(delaunay, TwoFace)
EXPECT_TRUE(out_edge_has_input_id(out, e2_out, out->face_edge_offset + 2));
EXPECT_TRUE(out_face_has_input_id(out, f0_out, 0));
EXPECT_TRUE(out_face_has_input_id(out, f1_out, 1));
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -663,28 +854,27 @@ TEST(delaunay, OverlapFaces)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {
- {0.0f, 0.0f},
- {1.0f, 0.0f},
- {1.0f, 1.0f},
- {0.0f, 1.0f},
- {0.5f, 0.5f},
- {1.5f, 0.5f},
- {1.5f, 1.3f},
- {0.5f, 1.3f},
- {0.1f, 0.1f},
- {0.3f, 0.1f},
- {0.3f, 0.3f},
- {0.1f, 0.3f},
- };
- int f[] = {/* 0 */ 0, 1, 2, 3, /* 1 */ 4, 5, 6, 7, /* 2*/ 8, 9, 10, 11};
- int fstart[] = {0, 4, 8};
- int flen[] = {4, 4, 4};
int v_out[12], v_int1, v_int2, f0_out, f1_out, f2_out;
int i;
+ const char *spec = R"(12 0 3
+ 0.0 0.0
+ 1.0 0.0
+ 1.0 1.0
+ 0.0 1.0
+ 0.5 0.5
+ 1.5 0.5
+ 1.5 1.3
+ 0.5 1.3
+ 0.1 0.1
+ 0.3 0.1
+ 0.3 0.3
+ 0.1 0.3
+ 0 1 2 3
+ 4 5 6 7
+ 8 9 10 11
+ )";
- fill_input_verts(&in, p, 12);
- add_input_faces(&in, f, fstart, flen, 3);
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 14);
EXPECT_EQ(out->edges_len, 33);
@@ -695,22 +885,26 @@ TEST(delaunay, OverlapFaces)
}
v_int1 = 12;
v_int2 = 13;
- if (fabsf(out->vert_coords[v_int1][0] - 1.0f) > in.epsilon) {
- v_int1 = 13;
- v_int2 = 12;
+ if (out->verts_len > 13) {
+ if (fabsf(out->vert_coords[v_int1][0] - 1.0f) > in.epsilon) {
+ v_int1 = 13;
+ v_int2 = 12;
+ }
+ EXPECT_NEAR(out->vert_coords[v_int1][0], 1.0, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v_int1][1], 0.5, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v_int2][0], 0.5, in.epsilon);
+ EXPECT_NEAR(out->vert_coords[v_int2][1], 1.0, in.epsilon);
}
- EXPECT_NEAR(out->vert_coords[v_int1][0], 1.0, in.epsilon);
- EXPECT_NEAR(out->vert_coords[v_int1][1], 0.5, in.epsilon);
- EXPECT_NEAR(out->vert_coords[v_int2][0], 0.5, in.epsilon);
- EXPECT_NEAR(out->vert_coords[v_int2][1], 1.0, in.epsilon);
f0_out = get_face_tri(out, v_out[1], v_int1, v_out[4]);
EXPECT_NE(f0_out, -1);
EXPECT_TRUE(out_face_has_input_id(out, f0_out, 0));
f1_out = get_face_tri(out, v_out[4], v_int1, v_out[2]);
EXPECT_NE(f1_out, -1);
EXPECT_TRUE(out_face_has_input_id(out, f1_out, 0));
- EXPECT_TRUE(out_face_has_input_id(out, f1_out, 0));
+ EXPECT_TRUE(out_face_has_input_id(out, f1_out, 1));
f2_out = get_face_tri(out, v_out[8], v_out[9], v_out[10]);
+ if (f2_out == -1)
+ f2_out = get_face_tri(out, v_out[8], v_out[9], v_out[11]);
EXPECT_NE(f2_out, -1);
EXPECT_TRUE(out_face_has_input_id(out, f2_out, 0));
EXPECT_TRUE(out_face_has_input_id(out, f2_out, 2));
@@ -727,6 +921,7 @@ TEST(delaunay, OverlapFaces)
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->faces_len, 5);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -734,52 +929,25 @@ TEST(delaunay, TwoSquaresOverlap)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {
- {1.0f, -1.0f},
- {-1.0f, -1.0f},
- {-1.0f, 1.0f},
- {1.0f, 1.0f},
- {-1.5f, 1.5f},
- {0.5f, 1.5f},
- {0.5f, -0.5f},
- {-1.5f, -0.5f},
- };
- int f[] = {/* 0 */ 7, 6, 5, 4, /* 1 */ 3, 2, 1, 0};
- int fstart[] = {0, 4};
- int flen[] = {4, 4};
-
- fill_input_verts(&in, p, 8);
- add_input_faces(&in, f, fstart, flen, 2);
+ const char *spec = R"(8 0 2
+ 1.0 -1.0
+ -1.0 -1.0
+ -1.0 1.0
+ 1.0 1.0
+ -1.5 1.5
+ 0.5 1.5
+ 0.5 -0.5
+ -1.5 -0.5
+ 7 6 5 4
+ 3 2 1 0
+ )";
+
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->verts_len, 10);
EXPECT_EQ(out->edges_len, 12);
EXPECT_EQ(out->faces_len, 3);
- BLI_delaunay_2d_cdt_free(out);
-}
-
-TEST(delaunay, TriCutoff)
-{
- CDT_input in;
- CDT_result *out;
- float p[][2] = {
- {-3.53009f, 1.29403f},
- {-4.11844f, -1.08375f},
- {1.56893f, 1.29403f},
- {0.621034f, 0.897734f},
- {0.549125f, 1.29403f},
- };
- int f[] = {0, 2, 1};
- int fstart[] = {0};
- int flen[] = {3};
- int e[][2] = {{3, 4}};
-
- fill_input_verts(&in, p, 5);
- add_input_faces(&in, f, fstart, flen, 1);
- add_input_edges(&in, e, 1);
- out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
- EXPECT_EQ(out->verts_len, 5);
- EXPECT_EQ(out->edges_len, 6);
- EXPECT_EQ(out->faces_len, 2);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -787,24 +955,23 @@ TEST(delaunay, TriInTri)
{
CDT_input in;
CDT_result *out;
- float p[][2] = {
- {-5.65685f, 0.0f},
- {1.41421f, -5.83095f},
- {0.0f, 0.0f},
- {-2.47487f, -1.45774f},
- {-0.707107f, -2.91548f},
- {-1.06066f, -1.45774f},
- };
- int f[] = {0, 1, 2, 3, 4, 5};
- int fstart[] = {0, 3};
- int flen[] = {3, 3};
-
- fill_input_verts(&in, p, 6);
- add_input_faces(&in, f, fstart, flen, 2);
+ const char *spec = R"(6 0 2
+ -5.65685 0.0
+ 1.41421 -5.83095
+ 0.0 0.0
+ -2.47487 -1.45774
+ -0.707107 -2.91548
+ -1.06066 -1.45774
+ 0 1 2
+ 3 4 5
+ )";
+
+ fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->edges_len, 8);
EXPECT_EQ(out->faces_len, 3);
+ free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
@@ -830,6 +997,7 @@ TEST(delaunay, DiamondInSquare)
EXPECT_EQ(out->edges_len, 10);
EXPECT_EQ(out->faces_len, 3);
free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, DiamondInSquareWire)
@@ -860,52 +1028,76 @@ TEST(delaunay, DiamondInSquareWire)
EXPECT_EQ(out->edges_len, 8);
EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
}
-TEST(delaunay, ClosePts)
+TEST(delaunay, TinyEdge)
{
CDT_input in;
CDT_result *out;
- const char *spec = R"(7 2 1
- 0.46876350045204163 0.06087132915854454
- 0.46865847706794739 0.03632887825369835
- 0.49176687002182007 0.03632888197898865
- 0.49166208505630493 0.06087132543325424
- 0.49171400070190430 0.04841339960694313
- 0.49171534180641174 0.04839951172471046
- 0.49045535922050476 0.06087132915854454
- 4 5
- 6 4
- 0 1 2 3
+ /* An intersect with triangle would be at (0.8, 0.2). */
+ const char *spec = R"(4 1 1
+ 0.0 0.0
+ 1.0 0.0
+ 0.5 0.5
+ 0.84 0.21
+ 0 3
+ 0 1 2
)";
fill_input_from_string(&in, spec);
- out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
- EXPECT_EQ(out->verts_len, 7);
- EXPECT_EQ(out->edges_len, 12);
- EXPECT_EQ(out->faces_len, 6);
+ in.epsilon = 0.1;
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out->verts_len, 4);
+ EXPECT_EQ(out->edges_len, 5);
+ EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
}
-TEST(delaunay, ClosePts2)
+TEST(delaunay, TinyEdge2)
{
CDT_input in;
CDT_result *out;
+ /* An intersect with triangle would be at (0.8, 0.2). */
const char *spec = R"(6 1 1
- -0.17878936231136322 -0.44374340772628784
- -0.17871695756912231 -0.45601493120193481
- -0.17544384300708771 -0.45601493120193481
- -0.17537136375904083 -0.44374340772628784
- -0.17544738948345184 -0.45602506399154663
- -0.17872454226016998 -0.45472940802574158
- 4 5
- 0 1 2 3
+ 0.0 0.0
+ 0.2 -0.2
+ 1.0 0.0
+ 0.5 0.5
+ 0.2 0.4
+ 0.84 0.21
+ 0 5
+ 0 1 2 3 4
)";
fill_input_from_string(&in, spec);
- out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ in.epsilon = 0.1;
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 6);
- EXPECT_EQ(out->edges_len, 10);
- EXPECT_EQ(out->faces_len, 5);
+ EXPECT_EQ(out->edges_len, 7);
+ EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
+}
+
+TEST(delaunay, repeatededge)
+{
+ CDT_input in;
+ CDT_result *out;
+ const char *spec = R"(5 3 0
+ 0.0 0.0
+ 0.0 1.0
+ 1.0 1.1
+ 0.5 -0.5
+ 0.5 2.5
+ 0 1
+ 2 3
+ 2 3
+ )";
+ fill_input_from_string(&in, spec);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
+ EXPECT_EQ(out->edges_len, 2);
+ free_spec_arrays(&in);
+ BLI_delaunay_2d_cdt_free(out);
}
#endif
@@ -914,67 +1106,216 @@ enum {
RANDOM_PTS,
RANDOM_SEGS,
RANDOM_POLY,
+ RANDOM_TILTED_GRID,
+ RANDOM_CIRCLE,
+ RANDOM_TRI_BETWEEN_CIRCLES,
};
-// #define DO_TIMING
-static void rand_delaunay_test(int test_kind,
- int max_lg_size,
- int reps_per_size,
- CDT_output_type otype)
+# define DO_TIMING
+static void rand_delaunay_test(
+ int test_kind, int max_lg_size, int reps_per_size, double param, CDT_output_type otype)
{
CDT_input in;
CDT_result *out;
- int lg_size, size, rep, i, npts, nedges;
+ int lg_size, size, rep, i, j, size_max, npts_max, nedges_max, nfaces_max, npts, nedges, nfaces;
+ int ia, ib, ic;
float(*p)[2];
int(*e)[2];
+ int *faces, *faces_start_table, *faces_len_table;
+ double start_angle, angle_delta, angle1, angle2, angle3;
+ float orient;
double tstart;
double *times;
RNG *rng;
rng = BLI_rng_new(0);
- npts = (1 << max_lg_size);
- p = (float(*)[2])MEM_malloc_arrayN(npts, 2 * sizeof(float), "delaunay");
+ e = NULL;
+ faces = NULL;
+ faces_start_table = NULL;
+ faces_len_table = NULL;
+ nedges_max = 0;
+ nfaces_max = 0;
+
+ /* Set up npts, nedges, nfaces, and allocate needed arrays at max length needed. */
+ size_max = 1 << max_lg_size;
switch (test_kind) {
case RANDOM_PTS:
- nedges = 0;
- e = NULL;
- break;
-
case RANDOM_SEGS:
case RANDOM_POLY:
- /* TODO: use faces for poly case, but need to deal with winding parity issue */
- nedges = npts - 1 + (test_kind == RANDOM_POLY);
- e = (int(*)[2])MEM_malloc_arrayN(nedges, 2 * sizeof(int), "delaunay");
+ npts_max = size_max;
+ if (test_kind == RANDOM_SEGS) {
+ nedges_max = npts_max - 1;
+ }
+ else if (test_kind == RANDOM_POLY) {
+ nedges_max = npts_max;
+ }
+ break;
+
+ case RANDOM_TILTED_GRID:
+ /* A 'size' x 'size' grid of points, tilted by angle 'param'.
+ * Edges will go from left ends to right ends and tops to bottoms, so 2 x size of them.
+ * Depending on epsilon, the vertical-ish edges may or may not go through the intermediate
+ * vertices, but the horizontal ones always should.
+ */
+ npts_max = size_max * size_max;
+ nedges_max = 2 * size_max;
+ break;
+
+ case RANDOM_CIRCLE:
+ /* A circle with 'size' points, a random start angle, and equal spacing thereafter.
+ * Will be input as one face.
+ */
+ npts_max = size_max;
+ nfaces_max = 1;
+ break;
+
+ case RANDOM_TRI_BETWEEN_CIRCLES:
+ /* A set of 'size' triangles, each has two random points on the unit circle,
+ * and the third point is a random point on the circle with radius 'param'.
+ * Each triangle will be input as a face.
+ */
+ npts_max = 3 * size_max;
+ nfaces_max = size_max;
break;
default:
fprintf(stderr, "unknown random delaunay test kind\n");
return;
}
- times = (double *)MEM_malloc_arrayN(max_lg_size + 1, sizeof(double), "delaunay");
+ fprintf(stderr,
+ "size_max=%d, npts_max=%d, nedges_max=%d, nfaces_max=%d\n",
+ size_max,
+ npts_max,
+ nedges_max,
+ nfaces_max); /*DEBUG!!*/
+ p = (float(*)[2])MEM_malloc_arrayN(npts_max, 2 * sizeof(float), __func__);
+ if (nedges_max > 0) {
+ e = (int(*)[2])MEM_malloc_arrayN(nedges_max, 2 * sizeof(int), __func__);
+ }
+ if (nfaces_max > 0) {
+ faces_start_table = (int *)MEM_malloc_arrayN(nfaces_max, sizeof(int), __func__);
+ faces_len_table = (int *)MEM_malloc_arrayN(nfaces_max, sizeof(int), __func__);
+ faces = (int *)MEM_malloc_arrayN(npts_max, sizeof(int), __func__);
+ }
+
+ times = (double *)MEM_malloc_arrayN(max_lg_size + 1, sizeof(double), __func__);
+
+ /* For powers of 2 sizes up to max_lg_size power of 2. */
for (lg_size = 0; lg_size <= max_lg_size; lg_size++) {
size = 1 << lg_size;
+ nedges = 0;
+ nfaces = 0;
times[lg_size] = 0.0;
- if (size == 1 && test_kind != RANDOM_PTS)
+ if (size == 1 && test_kind != RANDOM_PTS) {
continue;
+ }
+ /* Do 'rep' repetitions. */
for (rep = 0; rep < reps_per_size; rep++) {
- for (i = 0; i < size; i++) {
- p[i][0] = (float)BLI_rng_get_double(rng); /* will be in range in [0,1) */
- p[i][1] = (float)BLI_rng_get_double(rng);
+ /* Make vertices and edges or faces. */
+ switch (test_kind) {
+ case RANDOM_PTS:
+ case RANDOM_SEGS:
+ case RANDOM_POLY:
+ npts = size;
+ if (test_kind == RANDOM_SEGS) {
+ nedges = npts - 1;
+ }
+ else if (test_kind == RANDOM_POLY) {
+ nedges = npts;
+ }
+ for (i = 0; i < size; i++) {
+ p[i][0] = (float)BLI_rng_get_double(rng); /* will be in range in [0,1) */
+ p[i][1] = (float)BLI_rng_get_double(rng);
+ if (test_kind != RANDOM_PTS) {
+ if (i > 0) {
+ e[i - 1][0] = i - 1;
+ e[i - 1][1] = i;
+ }
+ }
+ }
+ if (test_kind == RANDOM_POLY) {
+ e[size - 1][0] = size - 1;
+ e[size - 1][1] = 0;
+ }
+ break;
+
+ case RANDOM_TILTED_GRID:
+ /* 'param' is slope of tilt of vertical lines. */
+ npts = size * size;
+ nedges = 2 * size;
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < size; j++) {
+ p[i * size + j][0] = i * param + j;
+ p[i * size + j][1] = i;
+ }
+ }
+ for (i = 0; i < size; i++) {
+ /* Horizontal edges: connect p(i,0) to p(i,size-1). */
+ e[i][0] = i * size;
+ e[i][1] = i * size + size - 1;
+ /* Vertical edges: conntect p(0,i) to p(size-1,i). */
+ e[size + i][0] = i;
+ e[size + i][1] = (size - 1) * size + i;
+ }
+ break;
+
+ case RANDOM_CIRCLE:
+ npts = size;
+ nfaces = 1;
+ faces_start_table[0] = 0;
+ faces_len_table[0] = npts;
+ start_angle = BLI_rng_get_double(rng) * 2.0 * M_PI;
+ angle_delta = 2.0 * M_PI / size;
+ for (i = 0; i < size; i++) {
+ p[i][0] = (float)cos(start_angle + i * angle_delta);
+ p[i][1] = (float)sin(start_angle + i * angle_delta);
+ faces[i] = i;
+ }
+ break;
+
+ case RANDOM_TRI_BETWEEN_CIRCLES:
+ npts = 3 * size;
+ nfaces = size;
+ for (i = 0; i < size; i++) {
+ /* Get three random angles in [0, 2pi). */
+ angle1 = BLI_rng_get_double(rng) * 2.0 * M_PI;
+ angle2 = BLI_rng_get_double(rng) * 2.0 * M_PI;
+ angle3 = BLI_rng_get_double(rng) * 2.0 * M_PI;
+ ia = 3 * i;
+ ib = 3 * i + 1;
+ ic = 3 * i + 2;
+ p[ia][0] = (float)cos(angle1);
+ p[ia][1] = (float)sin(angle1);
+ p[ib][0] = (float)cos(angle2);
+ p[ib][1] = (float)sin(angle2);
+ p[ic][0] = (float)(param * cos(angle3));
+ p[ic][1] = (float)(param * sin(angle3));
+ faces_start_table[i] = 3 * i;
+ faces_len_table[i] = 3;
+ /* Put the coordinates in ccw order. */
+ faces[ia] = ia;
+ orient = (p[ia][0] - p[ic][0]) * (p[ib][1] - p[ic][1]) -
+ (p[ib][0] - p[ic][0]) * (p[ia][1] - p[ic][1]);
+ if (orient >= 0.0f) {
+ faces[ib] = ib;
+ faces[ic] = ic;
+ }
+ else {
+ faces[ib] = ic;
+ faces[ic] = ib;
+ }
+ }
+ break;
}
- fill_input_verts(&in, p, size);
-
- if (test_kind == RANDOM_SEGS || test_kind == RANDOM_POLY) {
- for (i = 0; i < size - 1; i++) {
- e[i][0] = i;
- e[i][1] = i + 1;
- }
- if (test_kind == RANDOM_POLY) {
- e[size - 1][0] = size - 1;
- e[size - 1][1] = 0;
- }
- add_input_edges(&in, e, size - 1 + (test_kind == RANDOM_POLY));
+ fill_input_verts(&in, p, npts);
+ if (nedges > 0) {
+ add_input_edges(&in, e, nedges);
+ }
+ if (nfaces > 0) {
+ add_input_faces(&in, faces, faces_start_table, faces_len_table, nfaces);
}
+
+ /* Run the test. */
tstart = PIL_check_seconds_timer();
out = BLI_delaunay_2d_cdt_calc(&in, otype);
EXPECT_NE(out->verts_len, 0);
@@ -989,46 +1330,82 @@ static void rand_delaunay_test(int test_kind,
}
# endif
MEM_freeN(p);
- if (e)
+ if (e) {
MEM_freeN(e);
+ }
+ if (faces) {
+ MEM_freeN(faces);
+ MEM_freeN(faces_start_table);
+ MEM_freeN(faces_len_table);
+ }
MEM_freeN(times);
BLI_rng_free(rng);
}
TEST(delaunay, randompts)
{
- rand_delaunay_test(RANDOM_PTS, 7, 100, CDT_FULL);
+ rand_delaunay_test(RANDOM_PTS, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, randomsegs)
{
- rand_delaunay_test(RANDOM_SEGS, 7, 100, CDT_FULL);
+ rand_delaunay_test(RANDOM_SEGS, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, randompoly)
{
- rand_delaunay_test(RANDOM_POLY, 7, 100, CDT_FULL);
+ rand_delaunay_test(RANDOM_POLY, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, randompoly_inside)
{
- rand_delaunay_test(RANDOM_POLY, 7, 1, CDT_INSIDE);
+ rand_delaunay_test(RANDOM_POLY, 7, 1, 0.0, CDT_INSIDE);
}
TEST(delaunay, randompoly_constraints)
{
- rand_delaunay_test(RANDOM_POLY, 7, 1, CDT_CONSTRAINTS);
+ rand_delaunay_test(RANDOM_POLY, 7, 1, 0.0, CDT_CONSTRAINTS);
}
TEST(delaunay, randompoly_validbmesh)
{
- rand_delaunay_test(RANDOM_POLY, 7, 1, CDT_CONSTRAINTS_VALID_BMESH);
+ rand_delaunay_test(RANDOM_POLY, 7, 1, 0.0, CDT_CONSTRAINTS_VALID_BMESH);
+}
+
+TEST(delaunay, grid)
+{
+ rand_delaunay_test(RANDOM_TILTED_GRID, 6, 1, 0.0, CDT_FULL);
+}
+
+TEST(delaunay, tilted_grid_a)
+{
+ rand_delaunay_test(RANDOM_TILTED_GRID, 6, 1, 1.0, CDT_FULL);
+}
+
+TEST(delaunay, tilted_grid_b)
+{
+ rand_delaunay_test(RANDOM_TILTED_GRID, 6, 1, 0.01, CDT_FULL);
+}
+
+TEST(delaunay, randomcircle)
+{
+ rand_delaunay_test(RANDOM_CIRCLE, 7, 1, 0.0, CDT_FULL);
+}
+
+TEST(delaunay, random_tris_circle)
+{
+ rand_delaunay_test(RANDOM_TRI_BETWEEN_CIRCLES, 6, 1, 0.25, CDT_FULL);
+}
+
+TEST(delaunay, random_tris_circle_b)
+{
+ rand_delaunay_test(RANDOM_TRI_BETWEEN_CIRCLES, 6, 1, 1e-4, CDT_FULL);
}
#endif
#if DO_FILE_TESTS
/* For timing large examples of points only.
- * The given file should have one point per line, as a space-separated pair of floats.
+ * See fill_input_from_file for file format.
*/
static void points_from_file_test(const char *filename)
{
@@ -1044,17 +1421,19 @@ static void points_from_file_test(const char *filename)
free_spec_arrays(&in);
}
+# if 0
TEST(delaunay, debug)
{
CDT_input in;
CDT_result *out;
fill_input_from_file(&in, "/tmp/cdtinput.txt");
- out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
+ out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
BLI_delaunay_2d_cdt_free(out);
free_spec_arrays(&in);
}
+# endif
-# if 0
+# if 1
# define POINTFILEROOT "/tmp/"
TEST(delaunay, terrain1)
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
index ba995e5014f..58dd9998733 100644
--- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
@@ -5,8 +5,9 @@
#define GHASH_INTERNAL_API
-extern "C" {
#include "MEM_guardedalloc.h"
+
+extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_rand.h"
diff --git a/tests/gtests/blenlib/BLI_heap_simple_test.cc b/tests/gtests/blenlib/BLI_heap_simple_test.cc
index 16e1ecbf9cf..bad5c40eb66 100644
--- a/tests/gtests/blenlib/BLI_heap_simple_test.cc
+++ b/tests/gtests/blenlib/BLI_heap_simple_test.cc
@@ -3,14 +3,14 @@
#include "testing/testing.h"
#include <string.h>
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_sys_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_heap_simple.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
-
-#include "MEM_guardedalloc.h"
};
#define SIZE 1024
diff --git a/tests/gtests/blenlib/BLI_heap_test.cc b/tests/gtests/blenlib/BLI_heap_test.cc
index 884093435e4..ddec706eb0e 100644
--- a/tests/gtests/blenlib/BLI_heap_test.cc
+++ b/tests/gtests/blenlib/BLI_heap_test.cc
@@ -3,13 +3,13 @@
#include "testing/testing.h"
#include <string.h>
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_compiler_attrs.h"
#include "BLI_heap.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
-
-#include "MEM_guardedalloc.h"
};
#define SIZE 1024
diff --git a/tests/gtests/blenlib/BLI_kdopbvh_test.cc b/tests/gtests/blenlib/BLI_kdopbvh_test.cc
index 7e32c545e75..e0762f22840 100644
--- a/tests/gtests/blenlib/BLI_kdopbvh_test.cc
+++ b/tests/gtests/blenlib/BLI_kdopbvh_test.cc
@@ -4,12 +4,13 @@
/* TODO: ray intersection, overlap ... etc.*/
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_compiler_attrs.h"
#include "BLI_kdopbvh.h"
#include "BLI_rand.h"
#include "BLI_math_vector.h"
-#include "MEM_guardedalloc.h"
}
#include "stubs/bf_intern_eigen_stubs.h"
diff --git a/tests/gtests/blenlib/BLI_listbase_test.cc b/tests/gtests/blenlib/BLI_listbase_test.cc
index e5919c5dfb1..5ecf0533763 100644
--- a/tests/gtests/blenlib/BLI_listbase_test.cc
+++ b/tests/gtests/blenlib/BLI_listbase_test.cc
@@ -2,11 +2,11 @@
#include "testing/testing.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_array_utils.h"
#include "BLI_listbase.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_string.h"
#include "BLI_path_util.h"
#include "BLI_ressource_strings.h"
diff --git a/tests/gtests/blenlib/BLI_memiter_test.cc b/tests/gtests/blenlib/BLI_memiter_test.cc
index d92daefff3b..07ef0745845 100644
--- a/tests/gtests/blenlib/BLI_memiter_test.cc
+++ b/tests/gtests/blenlib/BLI_memiter_test.cc
@@ -2,10 +2,11 @@
#include "testing/testing.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_array_utils.h"
#include "BLI_memiter.h"
-#include "MEM_guardedalloc.h"
#include "BLI_string.h"
#include "BLI_ressource_strings.h"
diff --git a/tests/gtests/blenlib/BLI_polyfill_2d_test.cc b/tests/gtests/blenlib/BLI_polyfill_2d_test.cc
index 5566dced798..264ed8fadbc 100644
--- a/tests/gtests/blenlib/BLI_polyfill_2d_test.cc
+++ b/tests/gtests/blenlib/BLI_polyfill_2d_test.cc
@@ -9,13 +9,14 @@
#define USE_COMBINATIONS_ALL
#define USE_BEAUTIFY
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_array_utils.h"
#include "BLI_polyfill_2d.h"
#include "BLI_edgehash.h"
#include "BLI_math.h"
-#include "MEM_guardedalloc.h"
#ifdef USE_OBJ_PREVIEW
# include "BLI_string.h"
diff --git a/tests/gtests/blenlib/BLI_task_performance_test.cc b/tests/gtests/blenlib/BLI_task_performance_test.cc
index 84b7b8b6439..c5af75f1eb2 100644
--- a/tests/gtests/blenlib/BLI_task_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_task_performance_test.cc
@@ -7,6 +7,8 @@
#define GHASH_INTERNAL_API
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_utildefines.h"
@@ -15,8 +17,6 @@ extern "C" {
#include "BLI_task.h"
#include "PIL_time.h"
-
-#include "MEM_guardedalloc.h"
}
#define NUM_RUN_AVERAGED 100
diff --git a/tests/gtests/blenlib/BLI_task_test.cc b/tests/gtests/blenlib/BLI_task_test.cc
index a682e8aedf6..d4ab9de13c4 100644
--- a/tests/gtests/blenlib/BLI_task_test.cc
+++ b/tests/gtests/blenlib/BLI_task_test.cc
@@ -5,14 +5,14 @@
#include "atomic_ops.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
#include "BLI_task.h"
-
-#include "MEM_guardedalloc.h"
};
#define NUM_ITEMS 10000
diff --git a/tests/gtests/blenloader/CMakeLists.txt b/tests/gtests/blenloader/CMakeLists.txt
index f8457e0164b..332abbfb40b 100644
--- a/tests/gtests/blenloader/CMakeLists.txt
+++ b/tests/gtests/blenloader/CMakeLists.txt
@@ -76,7 +76,9 @@ set(SRC
blendfile_load_test.cc
)
if(WITH_BUILDINFO)
- list(APPEND SRC "$<TARGET_OBJECTS:buildinfoobj>")
+ list(APPEND SRC
+ "$<TARGET_OBJECTS:buildinfoobj>"
+ )
endif()
BLENDER_SRC_GTEST_EX(
diff --git a/tests/gtests/blenloader/blendfile_loading_base_test.cc b/tests/gtests/blenloader/blendfile_loading_base_test.cc
index 7af3293d706..c4e873c255f 100644
--- a/tests/gtests/blenloader/blendfile_loading_base_test.cc
+++ b/tests/gtests/blenloader/blendfile_loading_base_test.cc
@@ -17,6 +17,8 @@
*/
#include "blendfile_loading_base_test.h"
+#include "MEM_guardedalloc.h"
+
extern "C" {
#include "BKE_appdir.h"
#include "BKE_blender.h"
@@ -41,8 +43,6 @@ extern "C" {
#include "IMB_imbuf.h"
-#include "MEM_guardedalloc.h"
-
#include "RNA_define.h"
#include "WM_api.h"
diff --git a/tests/gtests/ffmpeg/CMakeLists.txt b/tests/gtests/ffmpeg/CMakeLists.txt
new file mode 100644
index 00000000000..dbd4f9f1fed
--- /dev/null
+++ b/tests/gtests/ffmpeg/CMakeLists.txt
@@ -0,0 +1,44 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+
+ ${FFMPEG_INCLUDE_DIRS}
+ ${PNG_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(LIB
+ ${PNG_LIBRARIES}
+ ${FFMPEG_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+)
+
+if(WITH_IMAGE_OPENJPEG)
+ set(LIB ${LIB} ${OPENJPEG_LIBRARIES})
+endif()
+
+setup_platform_linker_flags()
+link_directories(${FFMPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH})
+include_directories(${INC})
+
+BLENDER_SRC_GTEST(ffmpeg "ffmpeg_codecs.cc" "${LIB}")
diff --git a/tests/gtests/ffmpeg/ffmpeg_codecs.cc b/tests/gtests/ffmpeg/ffmpeg_codecs.cc
new file mode 100644
index 00000000000..bbf2b3a4111
--- /dev/null
+++ b/tests/gtests/ffmpeg/ffmpeg_codecs.cc
@@ -0,0 +1,147 @@
+#include "testing/testing.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavutil/log.h>
+}
+
+bool test_vcodec(AVCodec *codec, AVPixelFormat pixelformat)
+{
+ av_log_set_level(AV_LOG_QUIET);
+ bool result = false;
+ if (codec) {
+ AVCodecContext *ctx = avcodec_alloc_context3(codec);
+ if (ctx) {
+ ctx->time_base.num = 1;
+ ctx->time_base.den = 25;
+ ctx->pix_fmt = pixelformat;
+ ctx->width = 720;
+ ctx->height = 576;
+ int open = avcodec_open2(ctx, codec, NULL);
+ if (open >= 0) {
+ avcodec_free_context(&ctx);
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+bool test_acodec(AVCodec *codec, AVSampleFormat fmt)
+{
+ av_log_set_level(AV_LOG_QUIET);
+ bool result = false;
+ if (codec) {
+ AVCodecContext *ctx = avcodec_alloc_context3(codec);
+ if (ctx) {
+ ctx->sample_fmt = fmt;
+ ctx->sample_rate = 48000;
+ ctx->channel_layout = AV_CH_LAYOUT_MONO;
+ ctx->bit_rate = 128000;
+ int open = avcodec_open2(ctx, codec, NULL);
+ if (open >= 0) {
+ avcodec_free_context(&ctx);
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+bool test_codec_video_by_codecid(AVCodecID codec_id, AVPixelFormat pixelformat)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder(codec_id);
+ if (codec)
+ result = test_vcodec(codec, pixelformat);
+ return result;
+}
+
+bool test_codec_video_by_name(const char *codecname, AVPixelFormat pixelformat)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder_by_name(codecname);
+ if (codec)
+ result = test_vcodec(codec, pixelformat);
+ return result;
+}
+
+bool test_codec_audio_by_codecid(AVCodecID codec_id, AVSampleFormat fmt)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder(codec_id);
+ if (codec)
+ result = test_acodec(codec, fmt);
+ return result;
+}
+
+bool test_codec_audio_by_name(const char *codecname, AVSampleFormat fmt)
+{
+ bool result = false;
+ AVCodec *codec = avcodec_find_encoder_by_name(codecname);
+ if (codec)
+ result = test_acodec(codec, fmt);
+ return result;
+}
+
+#define str(s) #s
+#define FFMPEG_TEST_VCODEC_ID(codec, fmt) \
+ TEST(CheckCodec, codec##_##fmt) \
+ { \
+ EXPECT_TRUE(test_codec_video_by_codecid(codec, fmt)); \
+ }
+
+#define FFMPEG_TEST_VCODEC_NAME(codec, fmt) \
+ TEST(CheckCodec, codec##_##fmt) \
+ { \
+ EXPECT_TRUE(test_codec_video_by_name(str(codec), fmt)); \
+ }
+
+#define FFMPEG_TEST_ACODEC_ID(codec, fmt) \
+ TEST(CheckCodec, codec##_##fmt) \
+ { \
+ EXPECT_TRUE(test_codec_audio_by_codecid(codec, fmt)); \
+ }
+
+#define FFMPEG_TEST_ACODEC_NAME(codec, fmt) \
+ TEST(CheckCodec, codec) \
+ { \
+ EXPECT_TRUE(test_codec_audio_by_name(str(codec), fmt)); \
+ }
+
+/* generic codec ID's used in blender */
+
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_BGRA)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_RGB32)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FFV1, AV_PIX_FMT_RGB32)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_QTRLE, AV_PIX_FMT_ARGB)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_VP9, AV_PIX_FMT_YUVA420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_PNG, AV_PIX_FMT_RGBA)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H264, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG4, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_THEORA, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG1VIDEO, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG2VIDEO, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FLV1, AV_PIX_FMT_YUV420P)
+
+/* Audio codecs */
+
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_AAC, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_AC3, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_FLAC, AV_SAMPLE_FMT_S16)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_MP2, AV_SAMPLE_FMT_S16)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_MP3, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_OPUS, AV_SAMPLE_FMT_FLT)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_PCM_S16LE, AV_SAMPLE_FMT_S16)
+FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_VORBIS, AV_SAMPLE_FMT_FLTP)
+
+/* Libraries we count on ffmpeg being linked against */
+
+FFMPEG_TEST_VCODEC_NAME(libtheora, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libx264, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libvpx, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libopenjpeg, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_VCODEC_NAME(libxvid, AV_PIX_FMT_YUV420P)
+FFMPEG_TEST_ACODEC_NAME(libvorbis, AV_SAMPLE_FMT_FLTP)
+FFMPEG_TEST_ACODEC_NAME(libopus, AV_SAMPLE_FMT_FLT)
+FFMPEG_TEST_ACODEC_NAME(libmp3lame, AV_SAMPLE_FMT_FLTP)
diff --git a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
index efb29a6088d..4866ac44e3c 100644
--- a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
+++ b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
@@ -34,6 +34,50 @@ void DoBasicAlignmentChecks(const int alignment)
} // namespace
+TEST(guardedalloc, LockfreeAlignedAlloc1)
+{
+ DoBasicAlignmentChecks(1);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc1)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(1);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc2)
+{
+ DoBasicAlignmentChecks(2);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc2)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(2);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc4)
+{
+ DoBasicAlignmentChecks(4);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc4)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(4);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc8)
+{
+ DoBasicAlignmentChecks(8);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc8)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(8);
+}
+
TEST(guardedalloc, LockfreeAlignedAlloc16)
{
DoBasicAlignmentChecks(16);
@@ -45,13 +89,35 @@ TEST(guardedalloc, GuardedAlignedAlloc16)
DoBasicAlignmentChecks(16);
}
-// On Apple we currently support 16 bit alignment only.
-// Harmless for Blender, but would be nice to support
-// eventually.
-#ifndef __APPLE__
+TEST(guardedalloc, LockfreeAlignedAlloc32)
+{
+ DoBasicAlignmentChecks(32);
+}
+
TEST(guardedalloc, GuardedAlignedAlloc32)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(32);
}
-#endif
+
+TEST(guardedalloc, LockfreeAlignedAlloc256)
+{
+ DoBasicAlignmentChecks(256);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc256)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(256);
+}
+
+TEST(guardedalloc, LockfreeAlignedAlloc512)
+{
+ DoBasicAlignmentChecks(512);
+}
+
+TEST(guardedalloc, GuardedAlignedAlloc512)
+{
+ MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(512);
+}
diff --git a/tests/gtests/usd/CMakeLists.txt b/tests/gtests/usd/CMakeLists.txt
index 3850d279b3c..fbf29dc121e 100644
--- a/tests/gtests/usd/CMakeLists.txt
+++ b/tests/gtests/usd/CMakeLists.txt
@@ -76,7 +76,9 @@ set(SRC
if(WITH_BUILDINFO)
- list(APPEND SRC "$<TARGET_OBJECTS:buildinfoobj>")
+ list(APPEND SRC
+ "$<TARGET_OBJECTS:buildinfoobj>"
+ )
endif()
# get_cmake_property(_variableNames VARIABLES)
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 7241c26dfec..b5af3e14237 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -22,6 +22,7 @@
set(USE_EXPERIMENTAL_TESTS FALSE)
set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
+set(TEST_PYTHON_DIR ${CMAKE_SOURCE_DIR}/tests/python)
set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
# ugh, any better way to do this on testing only?
@@ -126,13 +127,17 @@ add_blender_test(
add_blender_test(
bmesh_bevel
${TEST_SRC_DIR}/modeling/bevel_regression.blend
- --python-text run_tests
+ --python ${TEST_PYTHON_DIR}/bevel_operator.py
+ --
+ --run-all-tests
)
add_blender_test(
bmesh_boolean
${TEST_SRC_DIR}/modeling/bool_regression.blend
- --python-text run_tests
+ --python ${TEST_PYTHON_DIR}/boolean_operator.py
+ --
+ --run-all-tests
)
add_blender_test(
@@ -149,6 +154,24 @@ add_blender_test(
--python-text run_tests.py
)
+add_blender_test(
+ modifiers
+ ${TEST_SRC_DIR}/modeling/modifiers.blend
+ --python ${TEST_PYTHON_DIR}/modifiers.py
+ --
+ --run-all-tests
+)
+
+# ------------------------------------------------------------------------------
+# OPERATORS TESTS
+add_blender_test(
+ operators
+ ${TEST_SRC_DIR}/modeling/operators.blend
+ --python ${TEST_PYTHON_DIR}/operators.py
+ --
+ --run-all-tests
+)
+
# ------------------------------------------------------------------------------
# IO TESTS
diff --git a/tests/python/bevel_operator.py b/tests/python/bevel_operator.py
new file mode 100644
index 00000000000..3cdbeb9300b
--- /dev/null
+++ b/tests/python/bevel_operator.py
@@ -0,0 +1,184 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# To run all tests, use
+# BLENDER_VERBOSE=1 blender path/to/bevel_regression.blend --python path/to/bevel_operator.py -- --run-all-tests
+# To run one test, use
+# BLENDER_VERBOSE=1 blender path/to/bevel_regression.blend --python path/to/bevel_operator.py -- --run-test <index>
+# where <index> is the index of the test specified in the list tests.
+
+import bpy
+import os
+import sys
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import OperatorTest
+
+
+def main():
+ tests = [
+ # 0
+ ['EDGE', {10}, 'Cube_test', 'Cube_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_2', 'bevel', {'offset': 0.2, 'offset_type': 'WIDTH'}],
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_3', 'bevel', {'offset': 0.2, 'offset_type': 'DEPTH'}],
+ ['EDGE', {10}, 'Cube_test', 'Cube_result_4', 'bevel', {'offset': 0.4, 'segments': 2}],
+ ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_5', 'bevel', {'offset': 0.4, 'segments': 3}],
+ # 5
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_6', 'bevel', {'offset': 0.4, 'segments': 4}],
+ ['EDGE', {0, 10, 4, 7}, 'Cube_test', 'Cube_result_7', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 0.2}],
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_8', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 0.25}],
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_9', 'bevel', {'offset': 0.4, 'segments': 6, 'profile': 0.9}],
+ ['EDGE', {10, 7}, 'Cube_test', 'Cube_result_10', 'bevel', {'offset': 0.4, 'segments': 4, 'profile': 1.0}],
+ # 10
+ ['EDGE', {8, 10, 7}, 'Cube_test', 'Cube_result_11', 'bevel', {'offset': 0.4, 'segments': 5, 'profile': 1.0}],
+ ['EDGE', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 'Cube_test', 'Cube_result_12', 'bevel',
+ {'offset': 0.4, 'segments': 8}],
+ ['EDGE', {5}, 'Pyr4_test', 'Pyr4_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {2, 5}, 'Pyr4_test', 'Pyr4_result_2', 'bevel', {'offset': 0.2}],
+ ['EDGE', {2, 3, 5}, 'Pyr4_test', 'Pyr4_result_3', 'bevel', {'offset': 0.2}],
+ # 15
+ ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_5', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {2, 3}, 'Pyr4_test', 'Pyr4_result_6', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {1, 2, 3, 5}, 'Pyr4_test', 'Pyr4_result_7', 'bevel', {'offset': 0.2, 'segments': 4, 'profile': 0.15}],
+ ['VERT', {1}, 'Pyr4_test', 'Pyr4_result_8', 'bevel', {'offset': 0.75, 'segments': 4, 'vertex_only': True}],
+ # 20
+ ['VERT', {1}, 'Pyr4_test', 'Pyr4_result_9', 'bevel',
+ {'offset': 0.75, 'segments': 3, 'vertex_only': True, 'profile': 0.25}],
+ ['EDGE', {2, 3}, 'Pyr6_test', 'Pyr6_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {8, 2, 3}, 'Pyr6_test', 'Pyr6_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {0, 2, 3, 4, 6, 7, 9, 10, 11}, 'Pyr6_test', 'Pyr6_result_3', 'bevel',
+ {'offset': 0.2, 'segments': 4, 'profile': 0.8}],
+ ['EDGE', {8, 9, 3, 11}, 'Sept_test', 'Sept_result_1', 'bevel', {'offset': 0.1}],
+ # 25
+ ['EDGE', {8, 9, 11}, 'Sept_test', 'Sept_result_2', 'bevel', {'offset': 0.1, 'offset_type': 'WIDTH'}],
+ ['EDGE', {2, 8, 9, 12, 13, 14}, 'Saddle_test', 'Saddle_result_1', 'bevel', {'offset': 0.3, 'segments': 5}],
+ ['VERT', {4}, 'Saddle_test', 'Saddle_result_2', 'bevel', {'offset': 0.6, 'segments': 6, 'vertex_only': True}],
+ ['EDGE', {2, 5, 8, 11, 14, 18, 21, 24, 27, 30, 34, 37, 40, 43, 46, 50, 53, 56, 59, 62, 112, 113, 114, 115},
+ 'Bent_test', 'Bent_result_1', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {1, 8, 9, 10, 11}, 'Bentlines_test', 'Bentlines_result_1', 'bevel', {'offset': 0.2, 'segments': 3}],
+ # 30
+ ['EDGE', {26, 12, 20}, 'Flaretop_test', 'Flaretop_result_1', 'bevel', {'offset': 0.4, 'segments': 2}],
+ ['EDGE', {26, 12, 20}, 'Flaretop_test', 'Flaretop_result_2', 'bevel',
+ {'offset': 0.4, 'segments': 2, 'profile': 1.0}],
+ ['FACE', {1, 6, 7, 8, 9, 10, 11, 12}, 'Flaretop_test', 'Flaretop_result_3', 'bevel',
+ {'offset': 0.4, 'segments': 4}],
+ ['EDGE', {4, 8, 10, 18, 24}, 'BentL_test', 'BentL_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {0, 1, 2, 10}, 'Wires_test', 'Wires_test_result_1', 'bevel', {'offset': 0.3}],
+ # 35
+ ['VERT', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 'Wires_test', 'Wires_test_result_2', 'bevel',
+ {'offset': 0.3, 'vertex_only': True}],
+ ['EDGE', {3, 4, 5}, 'tri', 'tri_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri', 'tri_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri', 'tri_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4}, 'tri', 'tri_result_4', 'bevel', {'offset': 0.2}],
+ # 40
+ ['EDGE', {3, 4}, 'tri', 'tri_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['VERT', {3}, 'tri', 'tri_result_6', 'bevel', {'offset': 0.2, 'vertex_only': True}],
+ ['VERT', {3}, 'tri', 'tri_result_7', 'bevel', {'offset': 0.2, 'segments': 2, 'vertex_only': True}],
+ ['VERT', {3}, 'tri', 'tri_result_8', 'bevel', {'offset': 0.2, 'segments': 3, 'vertex_only': True}],
+ ['VERT', {1}, 'tri', 'tri_result_9', 'bevel', {'offset': 0.2, 'vertex_only': True}],
+ # 45
+ ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri1gap', 'tri1gap_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ # 50
+ ['EDGE', {3, 4}, 'tri1gap', 'tri1gap_result_6', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_7', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_8', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 5}, 'tri1gap', 'tri1gap_result_9', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['VERT', {3}, 'tri1gap', 'tri1gap_result_10', 'bevel', {'offset': 0.2, 'vertex_only': True}],
+ # 55
+ ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri2gaps', 'tri2gaps_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ # 60
+ ['EDGE', {3, 4}, 'tri2gaps', 'tri2gaps_result_6', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_2', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {3, 4, 5}, 'tri3gaps', 'tri3gaps_result_3', 'bevel', {'offset': 0.2, 'segments': 3}],
+ ['EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, 'cube3', 'cube3_result_1', 'bevel', {'offset': 0.2}],
+ # 65
+ ['EDGE', {32, 33, 34, 35, 24, 25, 26, 27, 28, 29, 30, 31}, 'cube3', 'cube3_result_2', 'bevel',
+ {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {32, 35}, 'cube3', 'cube3_result_3', 'bevel', {'offset': 0.2}],
+ ['EDGE', {24, 35}, 'cube3', 'cube3_result_4', 'bevel', {'offset': 0.2}],
+ ['EDGE', {24, 32, 35}, 'cube3', 'cube3_result_5', 'bevel', {'offset': 0.2, 'segments': 2}],
+ ['EDGE', {24, 32, 35}, 'cube3', 'cube3_result_6', 'bevel', {'offset': 0.2, 'segments': 3}],
+ # 70
+ ['EDGE', {0, 1, 6, 7, 12, 14, 16, 17}, 'Tray', 'Tray_result_1', 'bevel', {'offset': 0.01, 'segments': 2}],
+ ['EDGE', {33, 4, 38, 8, 41, 10, 42, 12, 14, 17, 24, 31}, 'Bumptop', 'Bumptop_result_1', 'bevel',
+ {'offset': 0.1, 'segments': 4}],
+ ['EDGE', {16, 14, 15}, 'Multisegment_test', 'Multisegment_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {16, 14, 15}, 'Multisegment_test', 'Multisegment_result_1', 'bevel', {'offset': 0.2}],
+ ['EDGE', {19, 20, 23, 15}, 'Window_test', 'Window_result_1', 'bevel', {'offset': 0.05, 'segments': 2}],
+ # 75
+ ['EDGE', {8}, 'Cube_hn_test', 'Cube_hn_result_1', 'bevel', {'offset': 0.2, 'harden_normals': True}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_1', 'bevel',
+ {'offset': 0.2, 'miter_outer': 'PATCH'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_2', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_3', 'bevel',
+ {'offset': 0.2, 'segments': 3, 'miter_outer': 'PATCH'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_4', 'bevel',
+ {'offset': 0.2, 'miter_outer': 'ARC'}],
+ # 80
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_5', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_6', 'bevel',
+ {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_7', 'bevel',
+ {'offset': 0.2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps_test', 'Blocksteps_result_8', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'PATCH', 'miter_inner': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps2_test', 'Blocksteps2_result_9', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ # 85
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps3_test', 'Blocksteps3_result_10', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps4_test', 'Blocksteps4_result_11', 'bevel',
+ {'offset': 0.2, 'segments': 2, 'miter_outer': 'ARC'}],
+ ['EDGE', {4, 7, 39, 27, 30, 31}, 'Blocksteps4_test', 'Blocksteps4_result_12', 'bevel',
+ {'offset': 0.2, 'segments': 3, 'miter_outer': 'ARC'}],
+ ['EDGE', {1, 7}, 'Spike_test', 'Spike_result_1', 'bevel', {'offset': 0.2, 'segments': 3}]
+ ]
+
+ operator_test = OperatorTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ operator_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ index = int(command[i + 1])
+ operator_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py
index 5aa95f9a5f7..9dfc6c159cc 100644
--- a/tests/python/bl_pyapi_mathutils.py
+++ b/tests/python/bl_pyapi_mathutils.py
@@ -3,7 +3,7 @@
# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_mathutils.py -- --verbose
import unittest
from mathutils import Matrix, Vector, Quaternion
-from mathutils import kdtree
+from mathutils import kdtree, geometry
import math
# keep globals immutable
@@ -488,6 +488,43 @@ class KDTreeTesting(unittest.TestCase):
k.find((0,) * 3, filter=lambda i: None)
+class TesselatePolygon(unittest.TestCase):
+ def test_empty(self):
+ self.assertEqual([], geometry.tessellate_polygon([]))
+
+ def test_2d(self):
+ polyline = [
+ Vector((-0.14401324093341827, 0.1266411542892456)),
+ Vector((-0.14401324093341827, 0.13)),
+ Vector((0.13532273471355438, 0.1266411542892456)),
+ Vector((0.13532273471355438, 0.13)),
+ ]
+ expect = [(0, 1, 2), (0, 3, 2)]
+ self.assertEqual(expect, geometry.tessellate_polygon([polyline]))
+
+ def test_3d(self):
+ polyline = [
+ Vector((-0.14401324093341827, 0.1266411542892456, -0.13966798782348633)),
+ Vector((-0.14401324093341827, 0.1266411542892456, 0.13966798782348633)),
+ Vector((0.13532273471355438, 0.1266411542892456, 0.13966798782348633)),
+ Vector((0.13532273471355438, 0.1266411542892456, -0.13966798782348633)),
+ ]
+ expect = [(2, 3, 0), (2, 0, 1)]
+ self.assertEqual(expect, geometry.tessellate_polygon([polyline]))
+
+ def test_3d_degenerate(self):
+ polyline = [
+ Vector((-0.14401324093341827, -0.15269476175308228, -0.13966798782348633)),
+ Vector((0.13532273471355438, -0.15269476175308228, -0.13966798782348633)),
+ Vector((0.13532273471355438, -0.15269476175308228, -0.13966798782348633)),
+ Vector((-0.14401324093341827, -0.15269476175308228, -0.13966798782348633)),
+ ]
+ # If this returns a proper result, rather than [(0, 0, 0)], it could mean that
+ # degenerate geometry is handled properly.
+ expect = [(0, 0, 0)]
+ self.assertEqual(expect, geometry.tessellate_polygon([polyline]))
+
+
if __name__ == '__main__':
import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py
new file mode 100644
index 00000000000..b05e60eea6c
--- /dev/null
+++ b/tests/python/boolean_operator.py
@@ -0,0 +1,68 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# To run all tests, use
+# BLENDER_VERBOSE=1 blender path/to/bool_regression.blend --python path/to/boolean_operator.py -- --run-all-tests
+# To run one test, use
+# BLENDER_VERBOSE=1 blender path/to/bool_regression.blend --python path/to/boolean_operator.py -- --run-test <index>
+# where <index> is the index of the test specified in the list tests.
+
+import bpy
+import os
+import sys
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import OperatorTest
+
+
+def main():
+ tests = [
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_2', 'intersect_boolean', {'operation': 'INTERSECT'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_3', 'intersect_boolean', {'operation': 'DIFFERENCE'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_4', 'intersect', {'separate_mode': 'CUT'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_5', 'intersect', {'separate_mode': 'ALL'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_6', 'intersect', {'separate_mode': 'NONE'}],
+ ['FACE', {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 'Cubecube', 'Cubecube_result_7', 'intersect',
+ {'mode': 'SELECT', 'separate_mode': 'NONE'}],
+ ['FACE', {6, 7, 8, 9, 10}, 'Cubecone', 'Cubecone_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecones', 'Cubecones_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ ]
+
+ operator_test = OperatorTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ operator_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ index = int(command[i + 1])
+ operator_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py
new file mode 100644
index 00000000000..f2a42f15b43
--- /dev/null
+++ b/tests/python/modifiers.py
@@ -0,0 +1,236 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import math
+import os
+import sys
+from random import shuffle, seed
+
+import bpy
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import ModifierTest, ModifierSpec
+
+seed(0)
+
+
+def get_generate_modifiers_list(test_object_name, randomize=False):
+ """
+ Construct a list of 'Generate' modifiers with default parameters.
+ :param test_object_name: str - name of test object. Some modifiers like boolean need an extra parameter beside
+ the default one. E.g. boolean needs object, mask needs vertex group etc...
+ The extra parameter name will be <test_object_name>_<modifier_type>
+ :param randomize: bool - if True shuffle the list of modifiers.
+ :return: list of 'Generate' modifiers with default parameters.
+ """
+
+ boolean_test_object = bpy.data.objects[test_object_name + "_boolean"]
+
+ generate_modifiers = [
+ ModifierSpec('array', 'ARRAY', {}),
+ ModifierSpec('bevel', 'BEVEL', {'width': 0.1}),
+ ModifierSpec('boolean', 'BOOLEAN', {'object': boolean_test_object}),
+ ModifierSpec('build', 'BUILD', {'frame_start': 0, 'frame_duration': 1}),
+ ModifierSpec('decimate', 'DECIMATE', {}),
+ ModifierSpec('edge split', 'EDGE_SPLIT', {}),
+
+ # mask can effectively delete the mesh since the vertex group need to be updated after each
+ # applied modifier. Needs to be tested separately.
+ # ModifierSpec('mask', 'MASK', {'vertex_group': mask_vertex_group}, False),
+
+ ModifierSpec('mirror', 'MIRROR', {}),
+ ModifierSpec('multires', 'MULTIRES', {}),
+
+ # remesh can also generate an empty mesh. Skip.
+ # ModifierSpec('remesh', 'REMESH', {}),
+
+ # ModifierSpec('screw', 'SCREW', {}), # screw can make the test very slow. Skipping for now.
+ # ModifierSpec('skin', 'SKIN', {}), # skin is not reproducible .
+
+ ModifierSpec('solidify', 'SOLIDIFY', {}),
+ ModifierSpec('subsurf', 'SUBSURF', {}),
+ ModifierSpec('triangulate', 'TRIANGULATE', {}),
+ ModifierSpec('wireframe', 'WIREFRAME', {})
+
+ ]
+
+ if randomize:
+ shuffle(generate_modifiers)
+
+ return generate_modifiers
+
+
+def main():
+
+ mask_first_list = get_generate_modifiers_list("testCubeMaskFirst", randomize=True)
+ mask_vertex_group = "testCubeMaskFirst" + "_mask"
+ mask_first_list.insert(0, ModifierSpec('mask', 'MASK', {'vertex_group': mask_vertex_group}))
+
+ tests = [
+ ###############################
+ # List of 'Generate' modifiers on a cube
+ ###############################
+ # 0
+ # ["testCube", "expectedCube", get_generate_modifiers_list("testCube")],
+ ["testCubeRandom", "expectedCubeRandom", get_generate_modifiers_list("testCubeRandom", randomize=True)],
+ ["testCubeMaskFirst", "expectedCubeMaskFirst", mask_first_list],
+
+ ["testCollapseDecimate", "expectedCollapseDecimate",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}),
+ ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'COLLAPSE', 'ratio': 0.25, 'use_collapse_triangulate': True})]],
+ ["testPlanarDecimate", "expectedPlanarDecimate",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}),
+ ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'DISSOLVE', 'angle_limit': math.radians(30)})]],
+ ["testUnsubdivideDecimate", "expectedUnsubdivideDecimate",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2}),
+ ModifierSpec('decimate', 'DECIMATE', {'decimate_type': 'UNSUBDIV', 'iterations': 2})]],
+
+ # 5
+ ["testRadialBisectMirror", "expectedRadialBisectMirror",
+ [ModifierSpec('mirror1', 'MIRROR', {'use_bisect_axis': (True, False, False)}),
+ ModifierSpec('mirror2', 'MIRROR', {'use_bisect_axis': (True, False, False), 'mirror_object': bpy.data.objects["testRadialBisectMirrorHelper"]}),
+ ModifierSpec('mirror3', 'MIRROR', {'use_axis': (False, True, False), 'use_bisect_axis': (False, True, False), 'use_bisect_flip_axis': (False, True, False), 'mirror_object': bpy.data.objects["testRadialBisectMirrorHelper"]})]],
+ ["regressT58411Mirror", "expectedT58411Mirror",
+ [ModifierSpec('mirror', 'MIRROR', {}),
+ ModifierSpec('bevel', 'BEVEL', {'segments': 2, 'limit_method': 'WEIGHT'}),
+ ModifierSpec('subd', 'SUBSURF', {'levels': 1})]],
+
+ ["testBasicScrew", "expectedBasicScrew",
+ [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testBasicScrewHelper"]}),
+ ModifierSpec("screw", 'SCREW', {'angle': math.radians(400), 'steps': 20, 'iterations': 2, 'screw_offset': 2, 'use_normal_calculate': True})]],
+ ["testObjectScrew", "expectedObjectScrew",
+ [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testObjectScrewHelper2"]}),
+ ModifierSpec("screw", 'SCREW', {"angle": math.radians(600), 'steps': 32, 'iterations': 1, 'use_object_screw_offset': True, 'use_normal_calculate': True, 'object': bpy.data.objects["testObjectScrewHelper1"]})]],
+
+ # 9
+ ["testMergedScrewWeld", "expectedMergedScrewWeld",
+ [ModifierSpec("screw", 'SCREW', {'angle': math.radians(360), 'steps': 12, 'iterations': 1, 'screw_offset': 1, 'use_normal_calculate': True, 'use_merge_vertices': True}),
+ ModifierSpec("weld", 'WELD', {"merge_threshold": 0.001})]],
+ ["regressT72380Weld", "expectedT72380Weld",
+ [ModifierSpec('vedit', 'VERTEX_WEIGHT_EDIT', {'vertex_group': 'Group', 'use_remove': True, 'remove_threshold': 1}),
+ ModifierSpec("weld", 'WELD', {"merge_threshold": 0.2, "vertex_group": "Group"})]],
+ ["regressT72792Weld", "expectedT72792Weld",
+ [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIXED_COUNT', 'count': 2}),
+ ModifierSpec("weld", 'WELD', {"merge_threshold": 0.1, "vertex_group": "Group"})]],
+
+ ############################################
+ # One 'Generate' modifier on primitive meshes
+ #############################################
+ # 12
+ ["testCubeArray", "expectedCubeArray", [ModifierSpec('array', 'ARRAY', {})]],
+ ["testCapArray", "expectedCapArray",
+ [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIT_LENGTH', 'fit_length': 2.0, 'start_cap': bpy.data.objects["testCapStart"], 'end_cap': bpy.data.objects["testCapEnd"]})]],
+ ["testCurveArray", "expectedCurveArray",
+ [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIT_CURVE', 'curve': bpy.data.objects["testCurveArrayHelper"], 'use_relative_offset': False, 'use_constant_offset': True, 'constant_offset_displace': (0.5, 0, 0)})]],
+ ["testRadialArray", "expectedRadialArray",
+ [ModifierSpec('array', 'ARRAY', {'fit_type': 'FIXED_COUNT', 'count': 3, 'use_merge_vertices': True, 'use_merge_vertices_cap': True, 'use_relative_offset': False, 'use_object_offset': True, 'offset_object': bpy.data.objects["testRadialArrayHelper"]})]],
+
+ ["testCylinderBuild", "expectedCylinderBuild", [ModifierSpec('build', 'BUILD', {'frame_start': 0, 'frame_duration': 1})]],
+
+ # 17
+ ["testConeDecimate", "expectedConeDecimate", [ModifierSpec('decimate', 'DECIMATE', {'ratio': 0.5})]],
+ ["testCubeEdgeSplit", "expectedCubeEdgeSplit", [ModifierSpec('edge split', 'EDGE_SPLIT', {})]],
+
+ ["testSphereMirror", "expectedSphereMirror", [ModifierSpec('mirror', 'MIRROR', {})]],
+ ["testLocalMirror", "expectedLocalMirror",
+ [ModifierSpec('mirror', 'MIRROR', {'use_clip': True})]],
+ ["testObjectOffsetMirror", "expectedObjectOffsetMirror",
+ [ModifierSpec('mirror', 'MIRROR', {'mirror_object': bpy.data.objects["testObjectOffsetMirrorHelper"]})]],
+
+ ["testCylinderMask", "expectedCylinderMask", [ModifierSpec('mask', 'MASK', {'vertex_group': "mask_vertex_group"})]],
+ ["testConeMultiRes", "expectedConeMultiRes", [ModifierSpec('multires', 'MULTIRES', {})]],
+
+ # 24
+ ["testCubeScrew", "expectedCubeScrew", [ModifierSpec('screw', 'SCREW', {})]],
+
+ ["testCubeSolidify", "expectedCubeSolidify", [ModifierSpec('solidify', 'SOLIDIFY', {})]],
+ ["testComplexSolidify", "expectedComplexSolidify",
+ [ModifierSpec('solidify', 'SOLIDIFY', {'solidify_mode': 'NON_MANIFOLD', 'thickness': 0.05, 'offset': 0, 'nonmanifold_thickness_mode': 'CONSTRAINTS'})]],
+ ["regressT63063Solidify", "expectedT63063Solidify",
+ [ModifierSpec('solid', 'SOLIDIFY', {'thickness': 0.1, 'offset': 0.7})]],
+ ["regressT61979Solidify", "expectedT61979Solidify",
+ [ModifierSpec('solid', 'SOLIDIFY', {'thickness': -0.25, 'use_even_offset': True, 'use_quality_normals': True})]],
+
+ ["testMonkeySubsurf", "expectedMonkeySubsurf", [ModifierSpec('subsurf', 'SUBSURF', {})]],
+ ["testCatmullClarkSubdivisionSurface", "expectedCatmullClarkSubdivisionSurface",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]],
+ ["testSimpleSubdivisionSurface", "expectedSimpleSubdivisionSurface",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2, 'subdivision_type': 'SIMPLE'})]],
+ ["testCrease2dSubdivisionSurface", "expectedCrease2dSubdivisionSurface",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]],
+ ["testCrease3dSubdivisionSurface", "expectedCrease3dSubdivisionSurface",
+ [ModifierSpec("subdivision", 'SUBSURF', {"levels": 2})]],
+
+ # 34
+ ["testSphereTriangulate", "expectedSphereTriangulate", [ModifierSpec('triangulate', 'TRIANGULATE', {})]],
+ ["testMonkeyWireframe", "expectedMonkeyWireframe", [ModifierSpec('wireframe', 'WIREFRAME', {})]],
+ #ModifierSpec('skin', 'SKIN', {}), # skin is not reproducible .
+
+ ["testMergedWeld", "expectedMergedWeld",
+ [ModifierSpec("weld", 'WELD', {"merge_threshold": 0.021})]],
+ ["testMergedAllWeld", "expectedMergedAllWeld",
+ [ModifierSpec("weld", 'WELD', {"merge_threshold": 1.1})]],
+ ["testMergedNoneWeld", "expectedMergedNoneWeld",
+ [ModifierSpec("weld", 'WELD', {"merge_threshold": 0.019})]],
+
+ #############################################
+ # One 'Deform' modifier on primitive meshes
+ #############################################
+ # 39
+ ["testMonkeyArmature", "expectedMonkeyArmature",
+ [ModifierSpec('armature', 'ARMATURE', {'object': bpy.data.objects['testArmature'], 'use_vertex_groups': True})]],
+ ["testTorusCast", "expectedTorusCast", [ModifierSpec('cast', 'CAST', {'factor': 2.64})]],
+ ["testCubeCurve", "expectedCubeCurve",
+ [ModifierSpec('curve', 'CURVE', {'object': bpy.data.objects['testBezierCurve']})]],
+ ["testMonkeyDisplace", "expectedMonkeyDisplace", [ModifierSpec('displace', "DISPLACE", {})]],
+
+ # Hook modifier requires moving the hook object to get a mesh change, so can't test it with the current framework
+ # ["testMonkeyHook", "expectedMonkeyHook",
+ # [ModifierSpec('hook', 'HOOK', {'object': bpy.data.objects["EmptyHook"], 'vertex_group': "HookVertexGroup"})]],
+
+ # 43
+ #ModifierSpec('laplacian_deform', 'LAPLACIANDEFORM', {}) Laplacian requires a more complex mesh
+ ["testCubeLattice", "expectedCubeLattice",
+ [ModifierSpec('lattice', 'LATTICE', {'object': bpy.data.objects["testLattice"]})]],
+
+ ]
+
+ modifiers_test = ModifierTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ modifiers_test.apply_modifiers = True
+ modifiers_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ modifiers_test.apply_modifiers = False
+ index = int(command[i + 1])
+ modifiers_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py
new file mode 100644
index 00000000000..9fb487bcef9
--- /dev/null
+++ b/tests/python/modules/mesh_test.py
@@ -0,0 +1,495 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# A framework to run regression tests on mesh modifiers and operators based on howardt's mesh_ops_test.py
+#
+# General idea:
+# A test is:
+# Object mode
+# Select <test_object>
+# Duplicate the object
+# Select the object
+# Apply operation for each operation in <operations_stack> with given parameters
+# (an operation is either a modifier or an operator)
+# test_mesh = <test_object>.data
+# run test_mesh.unit_test_compare(<expected object>.data)
+# delete the duplicate object
+#
+# The words in angle brackets are parameters of the test, and are specified in
+# the main class MeshTest.
+#
+# If the environment variable BLENDER_TEST_UPDATE is set to 1, the <expected_object>
+# is updated with the new test result.
+# Tests are verbose when the environment variable BLENDER_VERBOSE is set.
+
+
+import bpy
+import os
+import inspect
+
+
+class ModifierSpec:
+ """
+ Holds one modifier and its parameters.
+ """
+
+ def __init__(self, modifier_name: str, modifier_type: str, modifier_parameters: dict):
+ """
+ Constructs a modifier spec.
+ :param modifier_name: str - name of object modifier, e.g. "myFirstSubsurfModif"
+ :param modifier_type: str - type of object modifier, e.g. "SUBSURF"
+ :param modifier_parameters: dict - {name : val} dictionary giving modifier parameters, e.g. {"quality" : 4}
+ """
+ self.modifier_name = modifier_name
+ self.modifier_type = modifier_type
+ self.modifier_parameters = modifier_parameters
+
+ def __str__(self):
+ return "Modifier: " + self.modifier_name + " of type " + self.modifier_type + \
+ " with parameters: " + str(self.modifier_parameters)
+
+
+class OperatorSpec:
+ """
+ Holds one operator and its parameters.
+ """
+
+ def __init__(self, operator_name: str, operator_parameters: dict, select_mode: str, selection: set):
+ """
+ Constructs an operatorSpec. Raises ValueError if selec_mode is invalid.
+ :param operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill"
+ :param operator_parameters: dict - {name : val} dictionary containing operator parameters.
+ :param select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE'
+ :param selection: set - set of vertices/edges/faces indices to select, e.g. [0, 9, 10].
+ """
+ self.operator_name = operator_name
+ self.operator_parameters = operator_parameters
+ if select_mode not in ['VERT', 'EDGE', 'FACE']:
+ raise ValueError("select_mode must be either {}, {} or {}".format('VERT', 'EDGE', 'FACE'))
+ self.select_mode = select_mode
+ self.selection = selection
+
+ def __str__(self):
+ return "Operator: " + self.operator_name + " with parameters: " + str(self.operator_parameters) + \
+ " in selection mode: " + self.select_mode + ", selecting " + str(self.selection)
+
+
+class MeshTest:
+ """
+ A mesh testing class targeted at testing modifiers and operators on a single object.
+ It holds a stack of mesh operations, i.e. modifiers or operators. The test is executed using
+ the public method run_test().
+ """
+
+ def __init__(self, test_object_name: str, expected_object_name: str, operations_stack=None, apply_modifiers=False):
+ """
+ Constructs a MeshTest object. Raises a KeyError if objects with names expected_object_name
+ or test_object_name don't exist.
+ :param test_object: str - Name of object of mesh type to run the operations on.
+ :param expected_object: str - Name of object of mesh type that has the expected
+ geometry after running the operations.
+ :param operations_stack: list - stack holding operations to perform on the test_object.
+ :param apply_modifier: bool - True if we want to apply the modifiers right after adding them to the object.
+ This affects operations of type ModifierSpec only.
+ """
+ if operations_stack is None:
+ operations_stack = []
+ for operation in operations_stack:
+ if not (isinstance(operation, ModifierSpec) or isinstance(operation, OperatorSpec)):
+ raise ValueError("Expected operation of type {} or {}. Got {}".
+ format(type(ModifierSpec), type(OperatorSpec),
+ type(operation)))
+ self.operations_stack = operations_stack
+ self.apply_modifier = apply_modifiers
+
+ self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
+ self.update = os.getenv('BLENDER_TEST_UPDATE') is not None
+
+ # Initialize test objects.
+ objects = bpy.data.objects
+ self.test_object = objects[test_object_name]
+ self.expected_object = objects[expected_object_name]
+ if self.verbose:
+ print("Found test object {}".format(test_object_name))
+ print("Found test object {}".format(expected_object_name))
+
+ # Private flag to indicate whether the blend file was updated after the test.
+ self._test_updated = False
+
+ def set_test_object(self, test_object_name):
+ """
+ Set test object for the test. Raises a KeyError if object with given name does not exist.
+ :param test_object_name: name of test object to run operations on.
+ """
+ objects = bpy.data.objects
+ self.test_object = objects[test_object_name]
+
+ def set_expected_object(self, expected_object_name):
+ """
+ Set expected object for the test. Raises a KeyError if object with given name does not exist
+ :param expected_object_name: Name of expected object.
+ """
+ objects = bpy.data.objects
+ self.expected_object = objects[expected_object_name]
+
+ def add_modifier(self, modifier_spec: ModifierSpec):
+ """
+ Add a modifier to the operations stack.
+ :param modifier_spec: modifier to add to the operations stack
+ """
+ self.operations_stack.append(modifier_spec)
+ if self.verbose:
+ print("Added modififier {}".format(modifier_spec))
+
+ def add_operator(self, operator_spec: OperatorSpec):
+ """
+ Adds an operator to the operations stack.
+ :param operator_spec: OperatorSpec - operator to add to the operations stack.
+ """
+ self.operations_stack.append(operator_spec)
+
+ def _on_failed_test(self, compare, evaluated_test_object):
+ if self.update:
+ if self.verbose:
+ print("Test failed expectantly. Updating expected mesh...")
+
+ # Replace expected object with object we ran operations on, i.e. evaluated_test_object.
+ evaluated_test_object.location = self.expected_object.location
+ expected_object_name = self.expected_object.name
+
+ bpy.data.objects.remove(self.expected_object, do_unlink=True)
+ evaluated_test_object.name = expected_object_name
+
+ # Save file
+ blend_file = bpy.data.filepath
+ bpy.ops.wm.save_as_mainfile(filepath=blend_file)
+
+ self._test_updated = True
+
+ # Set new expected object.
+ self.expected_object = evaluated_test_object
+ return True
+
+ else:
+ blender_file = bpy.data.filepath
+ print("Test failed with error: {}. Resulting object mesh '{}' did not match expected object '{}' "
+ "from file blender file {}".
+ format(compare, evaluated_test_object.name, self.expected_object.name, blender_file))
+
+ return False
+
+ def is_test_updated(self):
+ """
+ Check whether running the test with BLENDER_TEST_UPDATE actually modified the .blend test file.
+ :return: Bool - True if blend file has been updated. False otherwise.
+ """
+ return self._test_updated
+
+ def _apply_modifier(self, test_object, modifier_spec: ModifierSpec):
+ """
+ Add modifier to object and apply (if modifier_spec.apply_modifier is True)
+ :param test_object: bpy.types.Object - Blender object to apply modifier on.
+ :param modifier_spec: ModifierSpec - ModifierSpec object with parameters
+ """
+ modifier = test_object.modifiers.new(modifier_spec.modifier_name,
+ modifier_spec.modifier_type)
+ if self.verbose:
+ print("Created modifier '{}' of type '{}'.".
+ format(modifier_spec.modifier_name, modifier_spec.modifier_type))
+
+ for param_name in modifier_spec.modifier_parameters:
+ try:
+ setattr(modifier, param_name, modifier_spec.modifier_parameters[param_name])
+ if self.verbose:
+ print("\t set parameter '{}' with value '{}'".
+ format(param_name, modifier_spec.modifier_parameters[param_name]))
+ except AttributeError:
+ # Clean up first
+ bpy.ops.object.delete()
+ raise AttributeError("Modifier '{}' has no parameter named '{}'".
+ format(modifier_spec.modifier_type, param_name))
+
+ if self.apply_modifier:
+ bpy.ops.object.modifier_apply(modifier=modifier_spec.modifier_name)
+
+ def _apply_operator(self, test_object, operator: OperatorSpec):
+ """
+ Apply operator on test object.
+ :param test_object: bpy.types.Object - Blender object to apply operator on.
+ :param operator: OperatorSpec - OperatorSpec object with parameters.
+ """
+ mesh = test_object.data
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Do selection.
+ bpy.context.tool_settings.mesh_select_mode = (operator.select_mode == 'VERT',
+ operator.select_mode == 'EDGE',
+ operator.select_mode == 'FACE')
+ for index in operator.selection:
+ if operator.select_mode == 'VERT':
+ mesh.vertices[index].select = True
+ elif operator.select_mode == 'EDGE':
+ mesh.edges[index].select = True
+ elif operator.select_mode == 'FACE':
+ mesh.polygons[index].select = True
+ else:
+ raise ValueError("Invalid selection mode")
+
+ # Apply operator in edit mode.
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_mode(type=operator.select_mode)
+ mesh_operator = getattr(bpy.ops.mesh, operator.operator_name)
+ if not mesh_operator:
+ raise AttributeError("No mesh operator {}".format(operator.operator_name))
+ retval = mesh_operator(**operator.operator_parameters)
+ if retval != {'FINISHED'}:
+ raise RuntimeError("Unexpected operator return value: {}".format(retval))
+ if self.verbose:
+ print("Applied operator {}".format(operator))
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ def run_test(self):
+ """
+ Apply operations in self.operations_stack on self.test_object and compare the
+ resulting mesh with self.expected_object.data
+ :return: bool - True if the test passed, False otherwise.
+ """
+ self._test_updated = False
+ bpy.context.view_layer.objects.active = self.test_object
+
+ # Duplicate test object.
+ bpy.ops.object.mode_set(mode="OBJECT")
+ bpy.ops.object.select_all(action="DESELECT")
+ bpy.context.view_layer.objects.active = self.test_object
+
+ self.test_object.select_set(True)
+ bpy.ops.object.duplicate()
+ evaluated_test_object = bpy.context.active_object
+ evaluated_test_object.name = "evaluated_object"
+ if self.verbose:
+ print(evaluated_test_object.name, "is set to active")
+
+ # Add modifiers and operators.
+ for operation in self.operations_stack:
+ if isinstance(operation, ModifierSpec):
+ self._apply_modifier(evaluated_test_object, operation)
+
+ elif isinstance(operation, OperatorSpec):
+ self._apply_operator(evaluated_test_object, operation)
+ else:
+ raise ValueError("Expected operation of type {} or {}. Got {}".
+ format(type(ModifierSpec), type(OperatorSpec),
+ type(operation)))
+
+ # Compare resulting mesh with expected one.
+ if self.verbose:
+ print("Comparing expected mesh with resulting mesh...")
+ evaluated_test_mesh = evaluated_test_object.data
+ expected_mesh = self.expected_object.data
+ compare = evaluated_test_mesh.unit_test_compare(mesh=expected_mesh)
+ success = (compare == 'Same')
+
+ if success:
+ if self.verbose:
+ print("Success!")
+
+ # Clean up.
+ if self.verbose:
+ print("Cleaning up...")
+ # Delete evaluated_test_object.
+ bpy.ops.object.delete()
+ return True
+
+ else:
+ return self._on_failed_test(compare, evaluated_test_object)
+
+
+class OperatorTest:
+ """
+ Helper class that stores and executes operator tests.
+
+ Example usage:
+
+ >>> tests = [
+ >>> ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_1', 'intersect_boolean', {'operation': 'UNION'}],
+ >>> ['FACE', {0, 1, 2, 3, 4, 5}, 'Cubecube', 'Cubecube_result_2', 'intersect_boolean', {'operation': 'INTERSECT'}],
+ >>> ]
+ >>> operator_test = OperatorTest(tests)
+ >>> operator_test.run_all_tests()
+ """
+
+ def __init__(self, operator_tests):
+ """
+ Constructs an operator test.
+ :param operator_tests: list - list of operator test cases. Each element in the list must contain the following
+ in the correct order:
+ 1) select_mode: str - mesh selection mode, must be either 'VERT', 'EDGE' or 'FACE'
+ 2) selection: set - set of vertices/edges/faces indices to select, e.g. [0, 9, 10].
+ 3) test_object_name: bpy.Types.Object - test object
+ 4) expected_object_name: bpy.Types.Object - expected object
+ 5) operator_name: str - name of mesh operator from bpy.ops.mesh, e.g. "bevel" or "fill"
+ 6) operator_parameters: dict - {name : val} dictionary containing operator parameters.
+ """
+ self.operator_tests = operator_tests
+ self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
+ self._failed_tests_list = []
+
+ def run_test(self, index: int):
+ """
+ Run a single test from operator_tests list
+ :param index: int - index of test
+ :return: bool - True if test is successful. False otherwise.
+ """
+ case = self.operator_tests[index]
+ if len(case) != 6:
+ raise ValueError("Expected exactly 6 parameters for each test case, got {}".format(len(case)))
+ select_mode = case[0]
+ selection = case[1]
+ test_object_name = case[2]
+ expected_object_name = case[3]
+ operator_name = case[4]
+ operator_parameters = case[5]
+
+ operator_spec = OperatorSpec(operator_name, operator_parameters, select_mode, selection)
+
+ test = MeshTest(test_object_name, expected_object_name)
+ test.add_operator(operator_spec)
+
+ success = test.run_test()
+ if test.is_test_updated():
+ # Run the test again if the blend file has been updated.
+ success = test.run_test()
+ return success
+
+ def run_all_tests(self):
+ for index, _ in enumerate(self.operator_tests):
+ if self.verbose:
+ print()
+ print("Running test {}...".format(index))
+ success = self.run_test(index)
+
+ if not success:
+ self._failed_tests_list.append(index)
+
+ if len(self._failed_tests_list) != 0:
+ print("Following tests failed: {}".format(self._failed_tests_list))
+
+ blender_path = bpy.app.binary_path
+ blend_path = bpy.data.filepath
+ frame = inspect.stack()[1]
+ module = inspect.getmodule(frame[0])
+ python_path = module.__file__
+
+ print("Run following command to open Blender and run the failing test:")
+ print("{} {} --python {} -- {} {}"
+ .format(blender_path, blend_path, python_path, "--run-test", "<test_index>"))
+
+ raise Exception("Tests {} failed".format(self._failed_tests_list))
+
+
+class ModifierTest:
+ """
+ Helper class that stores and executes modifier tests.
+
+ Example usage:
+
+ >>> modifier_list = [
+ >>> ModifierSpec("firstSUBSURF", "SUBSURF", {"quality": 5}),
+ >>> ModifierSpec("firstSOLIDIFY", "SOLIDIFY", {"thickness_clamp": 0.9, "thickness": 1})
+ >>> ]
+ >>> tests = [
+ >>> ["testCube", "expectedCube", modifier_list],
+ >>> ["testCube_2", "expectedCube_2", modifier_list]
+ >>> ]
+ >>> modifiers_test = ModifierTest(tests)
+ >>> modifiers_test.run_all_tests()
+ """
+
+ def __init__(self, modifier_tests: list, apply_modifiers=False):
+ """
+ Construct a modifier test.
+ :param modifier_tests: list - list of modifier test cases. Each element in the list must contain the following
+ in the correct order:
+ 1) test_object_name: bpy.Types.Object - test object
+ 2) expected_object_name: bpy.Types.Object - expected object
+ 3) modifiers: list - list of mesh_test.ModifierSpec objects.
+ """
+ self.modifier_tests = modifier_tests
+ self.apply_modifiers = apply_modifiers
+ self.verbose = os.environ.get("BLENDER_VERBOSE") is not None
+ self._failed_tests_list = []
+
+ def run_test(self, index: int):
+ """
+ Run a single test from self.modifier_tests list
+ :param index: int - index of test
+ :return: bool - True if test passed, False otherwise.
+ """
+ case = self.modifier_tests[index]
+ if len(case) != 3:
+ raise ValueError("Expected exactly 3 parameters for each test case, got {}".format(len(case)))
+ test_object_name = case[0]
+ expected_object_name = case[1]
+ spec_list = case[2]
+
+ test = MeshTest(test_object_name, expected_object_name)
+ if self.apply_modifiers:
+ test.apply_modifier = True
+
+ for modifier_spec in spec_list:
+ test.add_modifier(modifier_spec)
+
+ success = test.run_test()
+ if test.is_test_updated():
+ # Run the test again if the blend file has been updated.
+ success = test.run_test()
+
+ return success
+
+ def run_all_tests(self):
+ """
+ Run all tests in self.modifiers_tests list. Raises an exception if one the tests fails.
+ """
+ for index, _ in enumerate(self.modifier_tests):
+ if self.verbose:
+ print()
+ print("Running test {}...\n".format(index))
+ success = self.run_test(index)
+
+ if not success:
+ self._failed_tests_list.append(index)
+
+ if len(self._failed_tests_list) != 0:
+ print("Following tests failed: {}".format(self._failed_tests_list))
+
+ blender_path = bpy.app.binary_path
+ blend_path = bpy.data.filepath
+ frame = inspect.stack()[1]
+ module = inspect.getmodule(frame[0])
+ python_path = module.__file__
+
+ print("Run following command to open Blender and run the failing test:")
+ print("{} {} --python {} -- {} {}"
+ .format(blender_path, blend_path, python_path, "--run-test", "<test_index>"))
+
+ raise Exception("Tests {} failed".format(self._failed_tests_list))
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
index 46c1626493f..e31db05ba61 100755
--- a/tests/python/modules/test_utils.py
+++ b/tests/python/modules/test_utils.py
@@ -85,7 +85,6 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
command.append(str(blendfile))
command.extend([
- '-E', 'CYCLES',
'--python-exit-code', '47',
'--python-expr', python_script,
]
diff --git a/tests/python/operators.py b/tests/python/operators.py
new file mode 100644
index 00000000000..c5b3ac745c6
--- /dev/null
+++ b/tests/python/operators.py
@@ -0,0 +1,172 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+import os
+import sys
+from random import shuffle, seed
+
+seed(0)
+
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from modules.mesh_test import OperatorTest, OperatorSpec
+
+# Central vertical loop of Suzanne
+MONKEY_LOOP_VERT = {68, 69, 71, 73, 74, 75, 76, 77, 90, 129, 136, 175, 188, 189, 198, 207,
+ 216, 223, 230, 301, 302, 303, 304, 305, 306, 307, 308}
+MONKEY_LOOP_EDGE = {131, 278, 299, 305, 307, 334, 337, 359, 384, 396, 399, 412, 415, 560,
+ 567, 572, 577, 615, 622, 627, 632, 643, 648, 655, 660, 707}
+
+
+def main():
+ tests = [
+ #### 0
+ # bisect
+ ['FACE', {0, 1, 2, 3, 4, 5}, "testCubeBisect", "expectedCubeBisect", "bisect",
+ {"plane_co": (0, 0, 0), "plane_no": (0, 1, 1), "clear_inner": True, "use_fill": True}],
+
+ # blend from shape
+ ['FACE', {0, 1, 2, 3, 4, 5}, "testCubeBlendFromShape", "expectedCubeBlendFromShape", "blend_from_shape",
+ {"shape": "Key 1"}],
+
+ # bridge edge loops
+ ["FACE", {0, 1}, "testCubeBrigeEdgeLoop", "expectedCubeBridgeEdgeLoop", "bridge_edge_loops", {}],
+
+ # decimate
+ ["FACE", {i for i in range(500)}, "testMonkeyDecimate", "expectedMonkeyDecimate", "decimate", {"ratio": 0.1}],
+
+ ### 4
+ # delete
+ ["VERT", {3}, "testCubeDeleteVertices", "expectedCubeDeleteVertices", "delete", {}],
+ ["FACE", {0}, "testCubeDeleteFaces", "expectedCubeDeleteFaces", "delete", {}],
+ ["EDGE", {0, 1, 2, 3}, "testCubeDeleteEdges", "expectedCubeDeleteEdges", "delete", {}],
+
+ # delete edge loop
+ ["VERT", MONKEY_LOOP_VERT, "testMokneyDeleteEdgeLoopVertices", "expectedMonkeyDeleteEdgeLoopVertices",
+ "delete_edgeloop", {}],
+ ["EDGE", MONKEY_LOOP_EDGE, "testMokneyDeleteEdgeLoopEdges", "expectedMonkeyDeleteEdgeLoopEdges",
+ "delete_edgeloop", {}],
+
+ ### 9
+ # delete loose
+ ["VERT", {i for i in range(12)}, "testCubeDeleteLooseVertices", "expectedCubeDeleteLooseVertices",
+ "delete_loose", {"use_verts": True, "use_edges": False, "use_faces": False}],
+ ["EDGE", {i for i in range(14)}, "testCubeDeleteLooseEdges", "expectedCubeDeleteLooseEdges",
+ "delete_loose", {"use_verts": False, "use_edges": True, "use_faces": False}],
+ ["FACE", {i for i in range(7)}, "testCubeDeleteLooseFaces", "expectedCubeDeleteLooseFaces",
+ "delete_loose", {"use_verts": False, "use_edges": False, "use_faces": True}],
+
+ # dissolve degenerate
+ ["VERT", {i for i in range(8)}, "testCubeDissolveDegenerate", "expectedCubeDissolveDegenerate",
+ "dissolve_degenerate", {}],
+
+ ### 13
+ # dissolve edges
+ ["EDGE", {0, 5, 6, 9}, "testCylinderDissolveEdges", "expectedCylinderDissolveEdges",
+ "dissolve_edges", {}],
+
+ # dissolve faces
+ ["VERT", {5, 34, 47, 49, 83, 91, 95}, "testCubeDissolveFaces", "expectedCubeDissolveFaces", "dissolve_faces",
+ {}],
+
+ ### 15
+ # dissolve verts
+ ["VERT", {16, 20, 22, 23, 25}, "testCubeDissolveVerts", "expectedCubeDissolveVerts", "dissolve_verts", {}],
+
+ # duplicate
+ ["VERT", {i for i in range(33)} - {23}, "testConeDuplicateVertices", "expectedConeDuplicateVertices",
+ "duplicate", {}],
+ ["VERT", {23}, "testConeDuplicateOneVertex", "expectedConeDuplicateOneVertex", "duplicate", {}],
+ ["FACE", {6, 9}, "testConeDuplicateFaces", "expectedConeDuplicateFaces", "duplicate", {}],
+ ["EDGE", {i for i in range(64)}, "testConeDuplicateEdges", "expectedConeDuplicateEdges", "duplicate", {}],
+
+ ### 20
+ # edge collapse
+ ["EDGE", {1, 9, 4}, "testCylinderEdgeCollapse", "expectedCylinderEdgeCollapse", "edge_collapse", {}],
+
+ # edge face add
+ ["VERT", {1, 3, 4, 5, 7}, "testCubeEdgeFaceAddFace", "expectedCubeEdgeFaceAddFace", "edge_face_add", {}],
+ ["VERT", {4, 5}, "testCubeEdgeFaceAddEdge", "expectedCubeEdgeFaceAddEdge", "edge_face_add", {}],
+
+ # edge rotate
+ ["EDGE", {1}, "testCubeEdgeRotate", "expectedCubeEdgeRotate", "edge_rotate", {}],
+
+ # edge split
+ ["EDGE", {2, 5, 8, 11, 14, 17, 20, 23}, "testCubeEdgeSplit", "expectedCubeEdgeSplit", "edge_split", {}],
+
+ ### 25
+ # face make planar
+ ["FACE", {i for i in range(500)}, "testMonkeyFaceMakePlanar", "expectedMonkeyFaceMakePlanar",
+ "face_make_planar", {}],
+
+ # face split by edges
+ ["VERT", {i for i in range(6)}, "testPlaneFaceSplitByEdges", "expectedPlaneFaceSplitByEdges",
+ "face_split_by_edges", {}],
+
+ # fill
+ ["EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49}, "testIcosphereFill", "expectedIcosphereFill",
+ "fill", {}],
+ ["EDGE", {20, 21, 22, 23, 24, 45, 46, 47, 48, 49}, "testIcosphereFillUseBeautyFalse",
+ "expectedIcosphereFillUseBeautyFalse", "fill", {"use_beauty": False}],
+
+ # fill grid
+ ["EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15}, "testPlaneFillGrid", "expectedPlaneFillGrid",
+ "fill_grid", {}],
+ ["EDGE", {1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15}, "testPlaneFillGridSimpleBlending",
+ "expectedPlaneFillGridSimpleBlending", "fill_grid", {"use_interp_simple": True}],
+
+ ### 31
+ # fill holes
+ ["VERT", {i for i in range(481)}, "testSphereFillHoles", "expectedSphereFillHoles", "fill_holes", {"sides": 9}],
+
+ # inset faces
+ ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, "testCubeInset",
+ "expectedCubeInset", "inset", {"thickness": 0.2}],
+ ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95},
+ "testCubeInsetEvenOffsetFalse", "expectedCubeInsetEvenOffsetFalse",
+ "inset", {"thickness": 0.2, "use_even_offset": False}],
+ ["VERT", {5, 16, 17, 19, 20, 22, 23, 34, 47, 49, 50, 52, 59, 61, 62, 65, 83, 91, 95}, "testCubeInsetDepth",
+ "expectedCubeInsetDepth", "inset", {"thickness": 0.2, "depth": 0.2}],
+ ["FACE", {35, 36, 37, 45, 46, 47, 55, 56, 57}, "testGridInsetRelativeOffset", "expectedGridInsetRelativeOffset",
+ "inset", {"thickness": 0.4, "use_relative_offset": True}],
+ ]
+
+ operators_test = OperatorTest(tests)
+
+ command = list(sys.argv)
+ for i, cmd in enumerate(command):
+ if cmd == "--run-all-tests":
+ operators_test.run_all_tests()
+ break
+ elif cmd == "--run-test":
+ operators_test.apply_modifiers = False
+ index = int(command[i + 1])
+ operators_test.run_test(index)
+ break
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except:
+ import traceback
+
+ traceback.print_exc()
+ sys.exit(1)