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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/CMakeLists.txt6
-rw-r--r--source/blender/editors/animation/SConscript7
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c551
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c528
-rw-r--r--source/blender/editors/animation/anim_deps.c6
-rw-r--r--source/blender/editors/animation/anim_draw.c238
-rw-r--r--source/blender/editors/animation/anim_filter.c260
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/anim_markers.c152
-rw-r--r--source/blender/editors/animation/anim_ops.c89
-rw-r--r--source/blender/editors/animation/drivers.c112
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c90
-rw-r--r--source/blender/editors/animation/keyframes_draw.c45
-rw-r--r--source/blender/editors/animation/keyframes_edit.c74
-rw-r--r--source/blender/editors/animation/keyframes_general.c202
-rw-r--r--source/blender/editors/animation/keyframing.c218
-rw-r--r--source/blender/editors/animation/keyingsets.c69
-rw-r--r--source/blender/editors/armature/BIF_retarget.h1
-rw-r--r--source/blender/editors/armature/CMakeLists.txt7
-rw-r--r--source/blender/editors/armature/SConscript8
-rw-r--r--source/blender/editors/armature/armature_add.c348
-rw-r--r--source/blender/editors/armature/armature_edit.c407
-rw-r--r--source/blender/editors/armature/armature_intern.h5
-rw-r--r--source/blender/editors/armature/armature_naming.c13
-rw-r--r--source/blender/editors/armature/armature_ops.c14
-rw-r--r--source/blender/editors/armature/armature_relations.c180
-rw-r--r--source/blender/editors/armature/armature_select.c199
-rw-r--r--source/blender/editors/armature/armature_skinning.c32
-rw-r--r--source/blender/editors/armature/armature_utils.c165
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c22
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c36
-rw-r--r--source/blender/editors/armature/meshlaplacian.c306
-rw-r--r--source/blender/editors/armature/meshlaplacian.h2
-rw-r--r--source/blender/editors/armature/pose_edit.c20
-rw-r--r--source/blender/editors/armature/pose_group.c26
-rw-r--r--source/blender/editors/armature/pose_lib.c56
-rw-r--r--source/blender/editors/armature/pose_select.c110
-rw-r--r--source/blender/editors/armature/pose_slide.c171
-rw-r--r--source/blender/editors/armature/pose_transform.c4
-rw-r--r--source/blender/editors/armature/pose_utils.c4
-rw-r--r--source/blender/editors/armature/reeb.c26
-rw-r--r--source/blender/editors/armature/reeb.h3
-rw-r--r--source/blender/editors/curve/CMakeLists.txt4
-rw-r--r--source/blender/editors/curve/SConscript2
-rw-r--r--source/blender/editors/curve/curve_intern.h55
-rw-r--r--source/blender/editors/curve/curve_ops.c10
-rw-r--r--source/blender/editors/curve/editcurve.c2029
-rw-r--r--source/blender/editors/curve/editcurve_add.c64
-rw-r--r--source/blender/editors/curve/editcurve_select.c1728
-rw-r--r--source/blender/editors/curve/editfont.c77
-rw-r--r--source/blender/editors/curve/lorem.c658
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt10
-rw-r--r--source/blender/editors/gpencil/SConscript5
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c952
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c61
-rw-r--r--source/blender/editors/gpencil/gpencil_buttons.c378
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c1484
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c447
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c2144
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h103
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c222
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c451
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c930
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c61
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c375
-rw-r--r--source/blender/editors/include/BIF_gl.h54
-rw-r--r--source/blender/editors/include/BIF_glutil.h22
-rw-r--r--source/blender/editors/include/ED_anim_api.h33
-rw-r--r--source/blender/editors/include/ED_armature.h26
-rw-r--r--source/blender/editors/include/ED_buttons.h2
-rw-r--r--source/blender/editors/include/ED_curve.h24
-rw-r--r--source/blender/editors/include/ED_fileselect.h49
-rw-r--r--source/blender/editors/include/ED_gpencil.h39
-rw-r--r--source/blender/editors/include/ED_image.h15
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h10
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h21
-rw-r--r--source/blender/editors/include/ED_keyframing.h4
-rw-r--r--source/blender/editors/include/ED_lattice.h1
-rw-r--r--source/blender/editors/include/ED_markers.h5
-rw-r--r--source/blender/editors/include/ED_mask.h3
-rw-r--r--source/blender/editors/include/ED_mball.h1
-rw-r--r--source/blender/editors/include/ED_mesh.h64
-rw-r--r--source/blender/editors/include/ED_node.h3
-rw-r--r--source/blender/editors/include/ED_object.h56
-rw-r--r--source/blender/editors/include/ED_outliner.h36
-rw-r--r--source/blender/editors/include/ED_paint.h7
-rw-r--r--source/blender/editors/include/ED_particle.h7
-rw-r--r--source/blender/editors/include/ED_render.h38
-rw-r--r--source/blender/editors/include/ED_screen.h26
-rw-r--r--source/blender/editors/include/ED_screen_types.h3
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/ED_sequencer.h6
-rw-r--r--source/blender/editors/include/ED_text.h3
-rw-r--r--source/blender/editors/include/ED_transform.h12
-rw-r--r--source/blender/editors/include/ED_util.h12
-rw-r--r--source/blender/editors/include/ED_uvedit.h13
-rw-r--r--source/blender/editors/include/ED_view3d.h104
-rw-r--r--source/blender/editors/include/UI_icons.h44
-rw-r--r--source/blender/editors/include/UI_interface.h520
-rw-r--r--source/blender/editors/include/UI_interface_icons.h19
-rw-r--r--source/blender/editors/include/UI_resources.h26
-rw-r--r--source/blender/editors/include/UI_view2d.h4
-rw-r--r--source/blender/editors/interface/CMakeLists.txt10
-rw-r--r--source/blender/editors/interface/SConscript9
-rw-r--r--source/blender/editors/interface/interface.c1094
-rw-r--r--source/blender/editors/interface/interface_anim.c92
-rw-r--r--source/blender/editors/interface/interface_draw.c153
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c528
-rw-r--r--source/blender/editors/interface/interface_handlers.c2473
-rw-r--r--source/blender/editors/interface/interface_icons.c297
-rw-r--r--source/blender/editors/interface/interface_intern.h223
-rw-r--r--source/blender/editors/interface/interface_layout.c411
-rw-r--r--source/blender/editors/interface/interface_ops.c169
-rw-r--r--source/blender/editors/interface/interface_panel.c361
-rw-r--r--source/blender/editors/interface/interface_regions.c887
-rw-r--r--source/blender/editors/interface/interface_style.c185
-rw-r--r--source/blender/editors/interface/interface_templates.c1026
-rw-r--r--source/blender/editors/interface/interface_utils.c113
-rw-r--r--source/blender/editors/interface/interface_widgets.c766
-rw-r--r--source/blender/editors/interface/resources.c363
-rw-r--r--source/blender/editors/interface/view2d.c235
-rw-r--r--source/blender/editors/interface/view2d_ops.c156
-rw-r--r--source/blender/editors/io/CMakeLists.txt2
-rw-r--r--source/blender/editors/io/SConscript2
-rw-r--r--source/blender/editors/io/io_collada.c130
-rw-r--r--source/blender/editors/io/io_ops.c13
-rw-r--r--source/blender/editors/mask/CMakeLists.txt4
-rw-r--r--source/blender/editors/mask/SConscript5
-rw-r--r--source/blender/editors/mask/mask_add.c34
-rw-r--r--source/blender/editors/mask/mask_draw.c4
-rw-r--r--source/blender/editors/mask/mask_edit.c53
-rw-r--r--source/blender/editors/mask/mask_intern.h9
-rw-r--r--source/blender/editors/mask/mask_ops.c33
-rw-r--r--source/blender/editors/mask/mask_relationships.c1
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt5
-rw-r--r--source/blender/editors/mesh/SConscript6
-rw-r--r--source/blender/editors/mesh/editface.c70
-rw-r--r--source/blender/editors/mesh/editmesh_add.c70
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c51
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c12
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c270
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c10
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c3
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c841
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c60
-rw-r--r--source/blender/editors/mesh/editmesh_path.c24
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c266
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c7
-rw-r--r--source/blender/editors/mesh/editmesh_select.c1330
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c1002
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c255
-rw-r--r--source/blender/editors/mesh/mesh_data.c210
-rw-r--r--source/blender/editors/mesh/mesh_intern.h17
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c7
-rw-r--r--source/blender/editors/mesh/mesh_ops.c26
-rw-r--r--source/blender/editors/mesh/meshtools.c14
-rw-r--r--source/blender/editors/metaball/mball_edit.c8
-rw-r--r--source/blender/editors/metaball/mball_ops.c4
-rw-r--r--source/blender/editors/object/CMakeLists.txt8
-rw-r--r--source/blender/editors/object/SConscript2
-rw-r--r--source/blender/editors/object/object_add.c278
-rw-r--r--source/blender/editors/object/object_bake.c29
-rw-r--r--source/blender/editors/object/object_bake_api.c70
-rw-r--r--source/blender/editors/object/object_constraint.c560
-rw-r--r--source/blender/editors/object/object_data_transfer.c729
-rw-r--r--source/blender/editors/object/object_edit.c167
-rw-r--r--source/blender/editors/object/object_group.c53
-rw-r--r--source/blender/editors/object/object_hook.c21
-rw-r--r--source/blender/editors/object/object_intern.h29
-rw-r--r--source/blender/editors/object/object_lattice.c4
-rw-r--r--source/blender/editors/object/object_lod.c8
-rw-r--r--source/blender/editors/object/object_modifier.c149
-rw-r--r--source/blender/editors/object/object_ops.c18
-rw-r--r--source/blender/editors/object/object_random.c4
-rw-r--r--source/blender/editors/object/object_relations.c669
-rw-r--r--source/blender/editors/object/object_select.c39
-rw-r--r--source/blender/editors/object/object_shapekey.c212
-rw-r--r--source/blender/editors/object/object_transform.c9
-rw-r--r--source/blender/editors/object/object_vgroup.c1416
-rw-r--r--source/blender/editors/object/object_warp.c5
-rw-r--r--source/blender/editors/physics/CMakeLists.txt6
-rw-r--r--source/blender/editors/physics/SConscript7
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c14
-rw-r--r--source/blender/editors/physics/particle_edit.c322
-rw-r--r--source/blender/editors/physics/particle_object.c495
-rw-r--r--source/blender/editors/physics/physics_fluid.c2
-rw-r--r--source/blender/editors/physics/physics_intern.h4
-rw-r--r--source/blender/editors/physics/physics_ops.c8
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c2
-rw-r--r--source/blender/editors/physics/rigidbody_object.c8
-rw-r--r--source/blender/editors/physics/rigidbody_world.c8
-rw-r--r--source/blender/editors/render/CMakeLists.txt5
-rw-r--r--source/blender/editors/render/SConscript5
-rw-r--r--source/blender/editors/render/render_intern.h8
-rw-r--r--source/blender/editors/render/render_internal.c87
-rw-r--r--source/blender/editors/render/render_opengl.c440
-rw-r--r--source/blender/editors/render/render_ops.c4
-rw-r--r--source/blender/editors/render/render_preview.c275
-rw-r--r--source/blender/editors/render/render_shading.c211
-rw-r--r--source/blender/editors/render/render_update.c114
-rw-r--r--source/blender/editors/render/render_view.c39
-rw-r--r--source/blender/editors/screen/CMakeLists.txt4
-rw-r--r--source/blender/editors/screen/SConscript5
-rw-r--r--source/blender/editors/screen/area.c538
-rw-r--r--source/blender/editors/screen/glutil.c98
-rw-r--r--source/blender/editors/screen/screen_context.c145
-rw-r--r--source/blender/editors/screen/screen_edit.c362
-rw-r--r--source/blender/editors/screen/screen_intern.h4
-rw-r--r--source/blender/editors/screen/screen_ops.c424
-rw-r--r--source/blender/editors/screen/screendump.c48
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt5
-rw-r--r--source/blender/editors/sculpt_paint/SConscript6
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c72
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c72
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c115
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c166
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c3275
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h23
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c25
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c56
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c217
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c161
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c283
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1507
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c26
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c44
-rw-r--r--source/blender/editors/sound/CMakeLists.txt7
-rw-r--r--source/blender/editors/sound/SConscript5
-rw-r--r--source/blender/editors/sound/sound_intern.h1
-rw-r--r--source/blender/editors/sound/sound_ops.c43
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_action/SConscript10
-rw-r--r--source/blender/editors/space_action/action_data.c963
-rw-r--r--source/blender/editors/space_action/action_draw.c13
-rw-r--r--source/blender/editors/space_action/action_edit.c213
-rw-r--r--source/blender/editors/space_action/action_intern.h12
-rw-r--r--source/blender/editors/space_action/action_ops.c29
-rw-r--r--source/blender/editors/space_action/action_select.c10
-rw-r--r--source/blender/editors/space_action/space_action.c4
-rw-r--r--source/blender/editors/space_api/spacetypes.c9
-rw-r--r--source/blender/editors/space_buttons/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_buttons/SConscript8
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c43
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h1
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c41
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c26
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c43
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt8
-rw-r--r--source/blender/editors/space_clip/SConscript7
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c73
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c15
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_ops.c1
-rw-r--r--source/blender/editors/space_clip/clip_draw.c63
-rw-r--r--source/blender/editors/space_clip/clip_editor.c116
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c24
-rw-r--r--source/blender/editors/space_clip/clip_ops.c159
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c6
-rw-r--r--source/blender/editors/space_clip/clip_utils.c50
-rw-r--r--source/blender/editors/space_clip/space_clip.c19
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c61
-rw-r--r--source/blender/editors/space_clip/tracking_select.c11
-rw-r--r--source/blender/editors/space_console/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_console/SConscript6
-rw-r--r--source/blender/editors/space_console/console_draw.c1
-rw-r--r--source/blender/editors/space_console/console_intern.h2
-rw-r--r--source/blender/editors/space_console/console_ops.c98
-rw-r--r--source/blender/editors/space_console/space_console.c2
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_file/SConscript7
-rw-r--r--source/blender/editors/space_file/file_draw.c504
-rw-r--r--source/blender/editors/space_file/file_intern.h23
-rw-r--r--source/blender/editors/space_file/file_ops.c949
-rw-r--r--source/blender/editors/space_file/file_panels.c176
-rw-r--r--source/blender/editors/space_file/file_utils.c47
-rw-r--r--source/blender/editors/space_file/filelist.c2919
-rw-r--r--source/blender/editors/space_file/filelist.h93
-rw-r--r--source/blender/editors/space_file/filesel.c263
-rw-r--r--source/blender/editors/space_file/fsmenu.c322
-rw-r--r--source/blender/editors/space_file/fsmenu.h40
-rw-r--r--source/blender/editors/space_file/space_file.c222
-rw-r--r--source/blender/editors/space_graph/CMakeLists.txt13
-rw-r--r--source/blender/editors/space_graph/SConscript12
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c112
-rw-r--r--source/blender/editors/space_graph/graph_draw.c125
-rw-r--r--source/blender/editors/space_graph/graph_edit.c123
-rw-r--r--source/blender/editors/space_graph/graph_intern.h5
-rw-r--r--source/blender/editors/space_graph/graph_ops.c235
-rw-r--r--source/blender/editors/space_graph/graph_select.c145
-rw-r--r--source/blender/editors/space_graph/graph_utils.c10
-rw-r--r--source/blender/editors/space_graph/space_graph.c6
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt8
-rw-r--r--source/blender/editors/space_image/SConscript6
-rw-r--r--source/blender/editors/space_image/image_buttons.c563
-rw-r--r--source/blender/editors/space_image/image_draw.c93
-rw-r--r--source/blender/editors/space_image/image_edit.c46
-rw-r--r--source/blender/editors/space_image/image_intern.h6
-rw-r--r--source/blender/editors/space_image/image_ops.c798
-rw-r--r--source/blender/editors/space_image/space_image.c57
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_info/SConscript6
-rw-r--r--source/blender/editors/space_info/info_draw.c5
-rw-r--r--source/blender/editors/space_info/info_ops.c24
-rw-r--r--source/blender/editors/space_info/info_stats.c35
-rw-r--r--source/blender/editors/space_info/space_info.c15
-rw-r--r--source/blender/editors/space_info/textview.c2
-rw-r--r--source/blender/editors/space_logic/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_logic/SConscript7
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c5
-rw-r--r--source/blender/editors/space_logic/logic_intern.h4
-rw-r--r--source/blender/editors/space_logic/logic_ops.c9
-rw-r--r--source/blender/editors/space_logic/logic_window.c233
-rw-r--r--source/blender/editors/space_logic/space_logic.c2
-rw-r--r--source/blender/editors/space_nla/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_nla/SConscript7
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c35
-rw-r--r--source/blender/editors/space_nla/nla_channels.c71
-rw-r--r--source/blender/editors/space_nla/nla_draw.c66
-rw-r--r--source/blender/editors/space_nla/nla_edit.c83
-rw-r--r--source/blender/editors/space_nla/nla_intern.h5
-rw-r--r--source/blender/editors/space_nla/nla_ops.c16
-rw-r--r--source/blender/editors/space_nla/space_nla.c8
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_node/SConscript7
-rw-r--r--source/blender/editors/space_node/drawnode.c252
-rw-r--r--source/blender/editors/space_node/node_add.c65
-rw-r--r--source/blender/editors/space_node/node_buttons.c21
-rw-r--r--source/blender/editors/space_node/node_draw.c185
-rw-r--r--source/blender/editors/space_node/node_edit.c156
-rw-r--r--source/blender/editors/space_node/node_group.c26
-rw-r--r--source/blender/editors/space_node/node_intern.h12
-rw-r--r--source/blender/editors/space_node/node_ops.c25
-rw-r--r--source/blender/editors/space_node/node_relationships.c472
-rw-r--r--source/blender/editors/space_node/node_select.c22
-rw-r--r--source/blender/editors/space_node/node_templates.c60
-rw-r--r--source/blender/editors/space_node/node_toolbar.c9
-rw-r--r--source/blender/editors/space_node/node_view.c9
-rw-r--r--source/blender/editors/space_node/space_node.c35
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_outliner/SConscript8
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c413
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c284
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h57
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c21
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c506
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c268
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c57
-rw-r--r--source/blender/editors/space_script/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_script/SConscript5
-rw-r--r--source/blender/editors/space_script/script_edit.c3
-rw-r--r--source/blender/editors/space_script/script_ops.c13
-rw-r--r--source/blender/editors/space_script/space_script.c2
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt14
-rw-r--r--source/blender/editors/space_sequencer/SConscript12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c214
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c11
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c706
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c925
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h33
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c67
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c11
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c172
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c64
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c224
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c9
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c46
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_text/SConscript8
-rw-r--r--source/blender/editors/space_text/space_text.c6
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c10
-rw-r--r--source/blender/editors/space_text/text_draw.c128
-rw-r--r--source/blender/editors/space_text/text_header.c33
-rw-r--r--source/blender/editors/space_text/text_intern.h6
-rw-r--r--source/blender/editors/space_text/text_ops.c199
-rw-r--r--source/blender/editors/space_time/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_time/SConscript5
-rw-r--r--source/blender/editors/space_time/space_time.c37
-rw-r--r--source/blender/editors/space_time/time_intern.h1
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c4
-rw-r--r--source/blender/editors/space_userpref/userpref_ops.c1
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt10
-rw-r--r--source/blender/editors/space_view3d/SConscript12
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c2
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c23
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c401
-rw-r--r--source/blender/editors/space_view3d/drawobject.c1106
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c166
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c115
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c137
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c582
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c1195
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c712
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c64
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c27
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h16
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c20
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c43
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c91
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c224
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c291
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c164
-rw-r--r--source/blender/editors/transform/CMakeLists.txt8
-rw-r--r--source/blender/editors/transform/SConscript10
-rw-r--r--source/blender/editors/transform/transform.c2300
-rw-r--r--source/blender/editors/transform/transform.h92
-rw-r--r--source/blender/editors/transform/transform_constraints.c74
-rw-r--r--source/blender/editors/transform/transform_conversions.c1435
-rw-r--r--source/blender/editors/transform/transform_generics.c368
-rw-r--r--source/blender/editors/transform/transform_manipulator.c87
-rw-r--r--source/blender/editors/transform/transform_ops.c109
-rw-r--r--source/blender/editors/transform/transform_orientations.c80
-rw-r--r--source/blender/editors/transform/transform_snap.c469
-rw-r--r--source/blender/editors/util/CMakeLists.txt8
-rw-r--r--source/blender/editors/util/SConscript10
-rw-r--r--source/blender/editors/util/ed_transverts.c10
-rw-r--r--source/blender/editors/util/ed_util.c60
-rw-r--r--source/blender/editors/util/editmode_undo.c19
-rw-r--r--source/blender/editors/util/numinput.c17
-rw-r--r--source/blender/editors/util/undo.c39
-rw-r--r--source/blender/editors/util/util_intern.h12
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt6
-rw-r--r--source/blender/editors/uvedit/SConscript6
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c31
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c39
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h5
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c198
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c22
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c32
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c98
438 files changed, 49222 insertions, 25700 deletions
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index d6030a967d5..473b0e6bc5a 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -20,13 +20,15 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -57,4 +59,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript
index 91d480978c4..fb5ff53cf16 100644
--- a/source/blender/editors/animation/SConscript
+++ b/source/blender/editors/animation/SConscript
@@ -31,17 +31,20 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 7d8e278f0cf..6979850c21a 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -36,7 +36,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -61,6 +61,7 @@
#include "RNA_access.h"
+#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_nla.h"
@@ -109,7 +110,7 @@ static void acf_generic_root_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUS
/* backdrop for top-level widgets (Scene and Object only) */
static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -120,8 +121,8 @@ static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, floa
glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
- uiSetRoundBox((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- uiDrawBox(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
}
@@ -135,7 +136,7 @@ static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem
/* backdrop for data expanders under top-level Scene/Object */
static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -159,14 +160,16 @@ static bool acf_show_channel_colors(bAnimContext *ac)
{
SpaceAction *saction = (SpaceAction *)ac->sl;
showGroupColors = !(saction->flag & SACTION_NODRAWGCOLORS);
- }
+
break;
+ }
case SPACE_IPO:
{
SpaceIpo *sipo = (SpaceIpo *)ac->sl;
showGroupColors = !(sipo->flag & SIPO_NODRAWGCOLORS);
- }
+
break;
+ }
}
}
@@ -176,7 +179,7 @@ static bool acf_show_channel_colors(bAnimContext *ac)
/* get backdrop color for generic channels */
static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3])
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
bActionGroup *grp = NULL;
short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0;
bool showGroupColors = acf_show_channel_colors(ac);
@@ -216,7 +219,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
/* backdrop for generic channels */
static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -268,7 +271,7 @@ static short acf_generic_indention_flexible(bAnimContext *UNUSED(ac), bAnimListE
/* basic offset for channels derived from indention */
static short acf_generic_basic_offset(bAnimContext *ac, bAnimListElem *ale)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
if (acf && acf->get_indent_level)
return acf->get_indent_level(ac, ale) * INDENT_STEP_SIZE;
@@ -408,7 +411,7 @@ static void acf_summary_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(al
/* backdrop for summary widget */
static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float color[3];
@@ -420,8 +423,8 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
* - top and bottom
* - special hack: make the top a bit higher, since we are first...
*/
- uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
- uiDrawBox(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
}
/* name for summary entries */
@@ -789,7 +792,7 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
/* backdrop for group widget */
static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -800,8 +803,8 @@ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc
glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
- uiSetRoundBox(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- uiDrawBox(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
}
/* name for group entries */
@@ -864,7 +867,11 @@ static int acf_group_setting_flag(bAnimContext *ac, eAnimChannel_Settings settin
case ACHANNEL_SETTING_MUTE: /* muted */
return AGRP_MUTED;
-
+
+ case ACHANNEL_SETTING_MOD_OFF: /* muted */
+ *neg = 1;
+ return AGRP_MODIFIERS_OFF;
+
case ACHANNEL_SETTING_PROTECT: /* protected */
return AGRP_PROTECTED;
@@ -945,6 +952,7 @@ static bool acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnim
/* unsupported */
case ACHANNEL_SETTING_SOLO: /* Solo Flag is only for NLA */
case ACHANNEL_SETTING_EXPAND: /* F-Curves are not containers */
+ case ACHANNEL_SETTING_PINNED: /* This is only for NLA Actions */
return false;
/* conditionally available */
@@ -982,6 +990,10 @@ static int acf_fcurve_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */
return FCURVE_VISIBLE;
+ case ACHANNEL_SETTING_MOD_OFF:
+ *neg = 1;
+ return FCURVE_MOD_OFF;
+
default: /* unsupported */
return 0;
}
@@ -1016,6 +1028,149 @@ static bAnimChannelType ACF_FCURVE =
acf_fcurve_setting_ptr /* pointer for setting */
};
+/* NLA Control FCurves Expander ----------------------- */
+
+/* get backdrop color for nla controls widget */
+static void acf_nla_controls_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3])
+{
+ // TODO: give this its own theme setting?
+ UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color);
+}
+
+/* backdrop for nla controls expander widget */
+static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+{
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ View2D *v2d = &ac->ar->v2d;
+ short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
+ short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
+ float color[3];
+
+ /* set backdrop drawing color */
+ acf->get_backdrop_color(ac, ale, color);
+ glColor3fv(color);
+
+ /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
+ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+}
+
+/* name for nla controls expander entries */
+static void acf_nla_controls_name(bAnimListElem *UNUSED(ale), char *name)
+{
+ BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
+}
+
+/* check if some setting exists for this channel */
+static bool acf_nla_controls_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting)
+{
+ /* for now, all settings are supported, though some are only conditionally */
+ switch (setting) {
+ /* supported */
+ case ACHANNEL_SETTING_EXPAND:
+ return true;
+
+ // TOOD: selected?
+
+ default: /* unsupported */
+ return false;
+ }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_nla_controls_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ *neg = true;
+ return ADT_NLA_SKEYS_COLLAPSED;
+
+ default:
+ /* this shouldn't happen */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type)
+{
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* all flags are just in adt->flag for now... */
+ return GET_ACF_FLAG_PTR(adt->flag, type);
+}
+
+static int acf_nla_controls_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_NLA;
+}
+
+/* NLA Control FCurves Expander type define */
+static bAnimChannelType ACF_NLACONTROLS =
+{
+ "NLA Controls Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_nla_controls_color, /* backdrop color */
+ acf_nla_controls_backdrop, /* backdrop */
+ acf_generic_indention_0, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_controls_name, /* name */
+ NULL, /* name prop */
+ acf_nla_controls_icon, /* icon */
+
+ acf_nla_controls_setting_valid, /* has setting */
+ acf_nla_controls_setting_flag, /* flag for setting */
+ acf_nla_controls_setting_ptr /* pointer for setting */
+};
+
+
+/* NLA Control F-Curve -------------------------------- */
+
+/* name for nla control fcurve entries */
+static void acf_nla_curve_name(bAnimListElem *ale, char *name)
+{
+ NlaStrip *strip = ale->owner;
+ FCurve *fcu = ale->data;
+ PropertyRNA *prop;
+
+ /* try to get RNA property that this shortened path (relative to the strip) refers to */
+ prop = RNA_struct_type_find_property(&RNA_NlaStrip, fcu->rna_path);
+ if (prop) {
+ /* "name" of this strip displays the UI identifier + the name of the NlaStrip */
+ BLI_snprintf(name, 256, "%s (%s)", RNA_property_ui_name(prop), strip->name);
+ }
+ else {
+ /* unknown property... */
+ BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index);
+ }
+}
+
+
+/* NLA Control F-Curve type define */
+static bAnimChannelType ACF_NLACURVE =
+{
+ "NLA Control F-Curve", /* type name */
+ ACHANNEL_ROLE_CHANNEL, /* role */
+
+ acf_generic_channel_color, /* backdrop color */
+ acf_generic_channel_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_curve_name, /* name */
+ acf_fcurve_name_prop, /* name prop */
+ NULL, /* icon */
+
+ acf_fcurve_setting_valid, /* has setting */
+ acf_fcurve_setting_flag, /* flag for setting */
+ acf_fcurve_setting_ptr /* pointer for setting */
+};
+
/* Object Action Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -2365,6 +2520,83 @@ static bAnimChannelType ACF_DSSPK =
acf_dsspk_setting_ptr /* pointer for setting */
};
+/* GPencil Expander ------------------------------------------- */
+
+// TODO: just get this from RNA?
+static int acf_dsgpencil_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_GREASEPENCIL;
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_dsgpencil_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GP_DATA_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_dsgpencil_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+{
+ bGPdata *gpd = (bGPdata *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(gpd->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (gpd->adt)
+ return GET_ACF_FLAG_PTR(gpd->adt->flag, type);
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* grease pencil expander type define */
+static bAnimChannelType ACF_DSGPENCIL =
+{
+ "GPencil DS Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idblock_name_prop, /* name prop */
+ acf_dsgpencil_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dsgpencil_setting_flag, /* flag for setting */
+ acf_dsgpencil_setting_ptr /* pointer for setting */
+};
+
/* ShapeKey Entry ------------------------------------------- */
/* name for ShapeKey */
@@ -2985,7 +3217,7 @@ static void acf_nlaaction_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, fl
/* backdrop for nla action channel */
static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
AnimData *adt = ale->adt;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -3010,12 +3242,12 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
/* only on top left corner, to show that this channel sits on top of the preceding ones
* while still linking into the action line strip to the right
*/
- uiSetRoundBox(UI_CNR_TOP_LEFT);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT);
/* draw slightly shifted up vertically to look like it has more separation from other channels,
* but we then need to slightly shorten it so that it doesn't look like it overlaps
*/
- uiDrawBox(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
}
/* name for nla action entries */
@@ -3144,6 +3376,9 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */
animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */
+ animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */
+ animchannelTypeInfo[type++] = &ACF_NLACURVE; /* NLA Control FCurve Channel */
+
animchannelTypeInfo[type++] = &ACF_FILLACTD; /* Object Action Expander */
animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */
@@ -3162,6 +3397,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */
animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */
animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */
+ animchannelTypeInfo[type++] = &ACF_DSGPENCIL; /* GreasePencil Channel */
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
@@ -3177,7 +3413,7 @@ static void ANIM_init_channel_typeinfo_data(void)
}
/* Get type info from given channel type */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* santiy checks */
if (ale == NULL)
@@ -3198,7 +3434,7 @@ bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* print indents */
for (; indent_level > 0; indent_level--)
@@ -3230,7 +3466,7 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
*/
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3303,7 +3539,7 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
*/
void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3348,13 +3584,29 @@ void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel
#define ICON_WIDTH (0.85f * U.widget_unit)
// width of sliders
#define SLIDER_WIDTH (4 * U.widget_unit)
-// width of rename textboxes
-#define RENAME_TEXT_WIDTH (5 * U.widget_unit)
+// min-width of rename textboxes
+#define RENAME_TEXT_MIN_WIDTH (U.widget_unit)
+
+
+/* Helper - Check if a channel needs renaming */
+static bool achannel_is_being_renamed(const bAnimContext *ac, const bAnimChannelType *acf, size_t channel_index)
+{
+ if (acf->name_prop && ac->ads) {
+ /* if rename index matches, this channel is being renamed */
+ if (ac->ads->renameIndex == channel_index + 1) {
+ return true;
+ }
+ }
+
+ /* not being renamed */
+ return false;
+}
+
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short selected, offset;
float y, ymid, ytext;
@@ -3407,11 +3659,12 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
/* step 4) draw special toggles .................................
* - in Graph Editor, checkboxes for visibility in curves area
* - in NLA Editor, glowing dots for solo/not solo...
+ * - in Grease Pencil mode, color swatches for layer color
*/
if (ac->sl) {
if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
/* for F-Curves, draw color-preview of curve behind checkbox */
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
/* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever
@@ -3431,11 +3684,16 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
/* just skip - drawn as widget now */
offset += ICON_WIDTH;
}
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ /* just skip - drawn as a widget */
+ offset += ICON_WIDTH;
+ }
}
/* step 5) draw name ............................................... */
- /* TODO: when renaming, we might not want to draw this, especially if name happens to be longer than channel */
- if (acf->name) {
+ /* Don't draw this if renaming... */
+ if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
/* set text color */
@@ -3449,10 +3707,10 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
acf->name(ale, name);
offset += 3;
- UI_DrawString(offset, ytext, name);
+ UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
/* draw red underline if channel is disabled */
- if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) {
/* FIXME: replace hardcoded color here, and check on extents! */
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
@@ -3519,7 +3777,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* (only only F-Curves really can support them for now)
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
offset += SLIDER_WIDTH;
}
@@ -3601,22 +3859,11 @@ static void achannel_nlatrack_solo_widget_cb(bContext *C, void *adt_poin, void *
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
}
-/* callback for rename widgets - clear rename-in-progress */
-static void achannel_setting_rename_done_cb(bContext *C, void *ads_poin, void *UNUSED(arg2))
-{
- bDopeSheet *ads = (bDopeSheet *)ads_poin;
-
- /* reset rename index so that edit box disappears now that editing is done */
- ads->renameIndex = 0;
-
- /* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
-}
-
/* callback for widget sliders - insert keyframes */
static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poin)
{
ID *id = (ID *)id_poin;
+ AnimData *adt = BKE_animdata_from_id(id);
FCurve *fcu = (FCurve *)fcu_poin;
ReportList *reports = CTX_wm_reports(C);
@@ -3627,9 +3874,8 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
bool done = false;
float cfra;
- /* get current frame */
- // NOTE: this will do for now...
- cfra = (float)CFRA;
+ /* get current frame and apply NLA-mapping to it (if applicable) */
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene, 1);
@@ -3666,9 +3912,8 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
bool done = false;
float cfra;
- /* get current frame */
- // NOTE: this will do for now...
- cfra = (float)CFRA;
+ /* get current frame and apply NLA-mapping to it (if applicable) */
+ cfra = BKE_nla_tweakedit_remap(key->adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene, 1);
@@ -3699,12 +3944,51 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
MEM_freeN(rna_path);
}
+/* callback for NLA Control Curve widget sliders - insert keyframes */
+static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_poin), void *fcu_poin)
+{
+ /* ID *id = (ID *)id_poin; */
+ FCurve *fcu = (FCurve *)fcu_poin;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ ReportList *reports = CTX_wm_reports(C);
+ Scene *scene = CTX_data_scene(C);
+ short flag = 0;
+ bool done = false;
+ float cfra;
+
+ /* get current frame - *no* NLA mapping should be done */
+ cfra = (float)CFRA;
+
+ /* get flags for keyframing */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ /* get pointer and property from the slider - this should all match up with the NlaStrip required... */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (fcu && prop) {
+ /* set the special 'replace' flag if on a keyframe */
+ if (fcurve_frame_has_keyframe(fcu, cfra, 0))
+ flag |= INSERTKEY_REPLACE;
+
+ /* insert a keyframe for this F-Curve */
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+
+ if (done)
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+}
+
/* Draw a widget for some setting */
-static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf,
+static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAnimChannelType *acf,
uiBlock *block, int xpos, int ypos, int setting)
{
short ptrsize, butType;
bool negflag;
+ bool usetoggle = true;
int flag, icon;
void *ptr;
const char *tooltip;
@@ -3721,12 +4005,18 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF);
icon = ICON_VISIBLE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
else
tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
-
+
+ case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
+ icon = ICON_MODIFIER;
+ usetoggle = false;
+ tooltip = TIP_("F-Curve modifiers are disabled");
+ break;
+
case ACHANNEL_SETTING_EXPAND: /* expanded triangle */
//icon = ((enabled) ? ICON_TRIA_DOWN : ICON_TRIA_RIGHT);
icon = ICON_TRIA_RIGHT;
@@ -3756,7 +4046,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
icon = ICON_MUTE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
tooltip = TIP_("Does F-Curve contribute to result");
}
else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) {
@@ -3787,11 +4077,18 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
}
/* type of button */
- if (negflag)
- butType = ICONTOGN;
- else
- butType = ICONTOG;
-
+ if (usetoggle) {
+ if (negflag)
+ butType = UI_BTYPE_ICON_TOGGLE_N;
+ else
+ butType = UI_BTYPE_ICON_TOGGLE;
+ }
+ else {
+ if (negflag)
+ butType = UI_BTYPE_TOGGLE_N;
+ else
+ butType = UI_BTYPE_TOGGLE;
+ }
/* draw button for setting */
if (ptr && flag) {
switch (ptrsize) {
@@ -3819,18 +4116,19 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
case ACHANNEL_SETTING_PROTECT: /* General - protection flags */
case ACHANNEL_SETTING_MUTE: /* General - muting flags */
case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */
- uiButSetNFunc(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting));
+ case ACHANNEL_SETTING_MOD_OFF:
+ UI_but_funcN_set(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting));
break;
/* settings needing special attention */
case ACHANNEL_SETTING_SOLO: /* NLA Tracks - Solo toggle */
- uiButSetFunc(but, achannel_nlatrack_solo_widget_cb, ale->adt, ale->data);
+ UI_but_func_set(but, achannel_nlatrack_solo_widget_cb, ale->adt, ale->data);
break;
/* no flushing */
case ACHANNEL_SETTING_EXPAND: /* expanding - cannot flush, otherwise all would open/close at once */
default:
- uiButSetFunc(but, achannel_setting_widget_cb, NULL, NULL);
+ UI_but_func_set(but, achannel_setting_widget_cb, NULL, NULL);
break;
}
}
@@ -3838,12 +4136,13 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
}
/* Draw UI widgets the given channel */
-void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index)
+void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float y, ymid /*, ytext*/;
short offset;
+ const bool is_being_renamed = achannel_is_being_renamed(ac, acf, channel_index);
/* sanity checks - don't draw anything */
if (ELEM(NULL, acf, ale, block))
@@ -3861,7 +4160,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
ymid = y - 0.5f * ICON_WIDTH;
/* no button backdrop behind icons */
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* step 1) draw expand widget ....................................... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) {
@@ -3878,6 +4177,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
/* step 3) draw special toggles .................................
* - in Graph Editor, checkboxes for visibility in curves area
* - in NLA Editor, glowing dots for solo/not solo...
+ * - in Grease Pencil mode, color swatches for layer color
*/
if (ac->sl) {
if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
@@ -3890,33 +4190,63 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO);
offset += ICON_WIDTH;
}
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ /* color swatch for layer color */
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ PointerRNA ptr;
+ float w = ICON_WIDTH / 2.0f;
+
+ RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
+
+ UI_block_align_begin(block);
+
+ UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH,
+ &ptr, "color", -1,
+ 0, 0, 0, 0, gpl->info);
+
+ UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_fill_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH,
+ &ptr, "fill_color", -1,
+ 0, 0, 0, 0, gpl->info);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ UI_block_align_end(block);
+
+ offset += ICON_WIDTH;
+ }
}
/* step 4) draw text - check if renaming widget is in use... */
- if (acf->name_prop && ac->ads) {
- float channel_height = ymaxc - yminc;
+ if (is_being_renamed) {
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
- /* if rename index matches, add widget for this */
- if (ac->ads->renameIndex == channel_index + 1) {
- PointerRNA ptr = {{NULL}};
- PropertyRNA *prop = NULL;
+ /* draw renaming widget if we can get RNA pointer for it
+ * NOTE: property may only be available in some cases, even if we have
+ * a callback available (e.g. broken F-Curve rename)
+ */
+ if (acf->name_prop(ale, &ptr, &prop)) {
+ const short margin_x = 3 * iroundf(UI_DPI_FAC);
+ const short channel_height = iroundf(ymaxc - yminc);
+ const short width = ac->ar->winx - offset - (margin_x * 2);
+ uiBut *but;
- /* draw renaming widget if we can get RNA pointer for it
- * NOTE: property may only be available in some cases, even if we have
- * a callback available (e.g. broken F-Curve rename)
- */
- if (acf->name_prop(ale, &ptr, &prop)) {
- uiBut *but;
-
- uiBlockSetEmboss(block, UI_EMBOSS);
-
- but = uiDefButR(block, TEX, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
- &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, achannel_setting_rename_done_cb, ac->ads, NULL);
- uiButActiveOnly(C, ac->ar, block, but);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + margin_x, yminc,
+ MAX2(width, RENAME_TEXT_MIN_WIDTH), channel_height,
+ &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
+
+ /* copy what outliner does here, see outliner_buttons */
+ if (UI_but_active_only(C, ac->ar, block, but) == false) {
+ ac->ads->renameIndex = 0;
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ /* send notifiers */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
}
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
}
@@ -3925,7 +4255,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
offset = 0;
// TODO: when drawing sliders, make those draw instead of these toggles if not enough space
- if (v2d) {
+ if (v2d && !is_being_renamed) {
short draw_sliders = 0;
/* check if we need to show the sliders */
@@ -3959,6 +4289,12 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_MUTE);
}
+ /* modifiers disable */
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) {
+ offset += ICON_WIDTH * 1.2f; /* hack: extra spacing, to avoid touching the mute toggle */
+ draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_MOD_OFF);
+ }
+
/* ----------- */
/* pinned... */
@@ -3972,16 +4308,16 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
uiBut *but;
PointerRNA *opptr_b;
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
offset += UI_UNIT_X;
- but = uiDefIconButO(block, BUT, "NLA_OT_action_pushdown", WM_OP_INVOKE_DEFAULT, ICON_NLA_PUSHDOWN,
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "NLA_OT_action_pushdown", WM_OP_INVOKE_DEFAULT, ICON_NLA_PUSHDOWN,
(int)v2d->cur.xmax - offset, ymid, UI_UNIT_X, UI_UNIT_X, NULL);
- opptr_b = uiButGetOperatorPtrRNA(but);
+ opptr_b = UI_but_operator_ptr_get(but);
RNA_int_set(opptr_b, "channel_index", channel_index);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
}
@@ -3993,15 +4329,36 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
* and wouldn't be able to auto-keyframe...
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
// TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough
offset += SLIDER_WIDTH;
/* need backdrop behind sliders... */
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
- if (ale->id) { /* Slider using RNA Access -------------------- */
+ if (ale->owner) { /* Slider using custom RNA Access ---------- */
+ if (ale->type == ANIMTYPE_NLACURVE) {
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers */
+ RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, &ptr);
+ prop = RNA_struct_find_property(&ptr, fcu->rna_path);
+
+ /* create property slider */
+ if (prop) {
+ uiBut *but;
+
+ /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
+ but = uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", ICON_NONE, (int)v2d->cur.xmax - offset, ymid, SLIDER_WIDTH, (int)ymaxc - yminc);
+ UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data);
+ }
+ }
+ }
+ else if (ale->id) { /* Slider using RNA Access --------------- */
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
char *rna_path = NULL;
@@ -4037,9 +4394,9 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
/* assign keyframing function according to slider type */
if (ale->type == ANIMTYPE_SHAPEKEY)
- uiButSetFunc(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data);
+ UI_but_func_set(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data);
else
- uiButSetFunc(but, achannel_setting_slider_cb, ale->id, ale->data);
+ UI_but_func_set(but, achannel_setting_slider_cb, ale->id, ale->data);
}
/* free the path if necessary */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index b6ab0407711..8822c8511de 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "BKE_depsgraph.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -101,6 +102,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -129,6 +131,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSGPENCIL:
{
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -136,6 +139,13 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
}
break;
}
+ case ANIMTYPE_GPLAYER:
+ {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+
+ ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE);
+ break;
+ }
}
}
@@ -149,6 +159,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel_data;
fcu->flag |= FCURVE_ACTIVE;
@@ -176,6 +187,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSNTREE:
case ANIMTYPE_DSTEX:
+ case ANIMTYPE_DSGPENCIL:
{
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
@@ -184,8 +196,14 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
- /* unhandled currently, but may be interesting */
case ANIMTYPE_GPLAYER:
+ {
+ bGPDlayer *gpl = (bGPDlayer *)channel_data;
+ gpl->flag |= GP_LAYER_ACTIVE;
+ break;
+ }
+
+ /* unhandled currently, but may be interesting */
case ANIMTYPE_MASKLAYER:
case ANIMTYPE_SHAPEKEY:
case ANIMTYPE_NLAACTION:
@@ -240,6 +258,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
sel = ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
if (ale->flag & FCURVE_SELECTED)
sel = ACHANNEL_SETFLAG_CLEAR;
break;
@@ -268,6 +287,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSGPENCIL:
{
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
sel = ACHANNEL_SETFLAG_CLEAR;
@@ -323,6 +343,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -361,6 +382,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSGPENCIL:
{
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -427,7 +449,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
return;
}
else {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
if (acf == NULL) {
printf("ERROR: no channel info for the changed channel\n");
@@ -456,7 +478,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go backwards in the list, until the highest-ranking element (by indention has been covered) */
for (ale = match->prev; ale; ale = ale->prev) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -500,7 +522,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
for (ale = match->next; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -830,6 +852,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel;
@@ -843,8 +866,15 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
is_sel = SEL_NLT(nlt);
break;
}
+ case ANIMTYPE_GPLAYER:
+ {
+ bGPDlayer *gpl = (bGPDlayer *)channel;
+
+ is_sel = SEL_GPL(gpl);
+ break;
+ }
default:
- printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
+ printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type);
return;
}
@@ -1167,6 +1197,81 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
/* ------------------- */
+static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
+{
+ ListBase anim_data_visible = {NULL, NULL};
+
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* get rearranging function */
+ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+
+ if (rearrange_func == NULL)
+ return;
+
+ /* skip if these curves aren't being shown */
+ if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
+ return;
+
+ /* Filter visible data. */
+ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
+
+ /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
+ &anim_data_visible);
+ }
+ }
+
+ /* free temp data */
+ BLI_freelistN(&anim_data_visible);
+}
+
+/* ------------------- */
+
+static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* get rearranging function */
+ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+
+ if (rearrange_func == NULL)
+ return;
+
+ /* get Grease Pencil datablocks */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ ListBase anim_data_visible = {NULL, NULL};
+ bGPdata *gpd = ale->data;
+
+ /* only consider layers if this datablock is open */
+ BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK);
+ if ((gpd->flag & GP_DATA_EXPAND) == 0)
+ continue;
+
+ /* Filter visible data. */
+ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER);
+
+ /* rearrange datablock's layers */
+ rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible);
+
+ /* free visible layers data */
+ BLI_freelistN(&anim_data_visible);
+ }
+
+ /* free GPD channel data */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ------------------- */
+
static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -1182,7 +1287,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
/* method to move channels depends on the editor */
if (ac.datatype == ANIMCONT_GPENCIL) {
/* Grease Pencil channels */
- printf("Grease Pencil not supported for moving yet\n");
+ rearrange_gpencil_channels(&ac, mode);
}
else if (ac.datatype == ANIMCONT_MASK) {
/* Grease Pencil channels */
@@ -1213,13 +1318,29 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
rearrange_driver_channels(&ac, adt, mode);
break;
+ case ANIMCONT_ACTION: /* Single Action only... */
case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
- default: /* some collection of actions */
+ {
if (adt->action)
rearrange_action_channels(&ac, adt->action, mode);
else if (G.debug & G_DEBUG)
printf("Animdata has no action\n");
break;
+ }
+
+ default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
+ {
+ /* NLA Control Curves */
+ if (adt->nla_tracks.first)
+ rearrange_nla_control_channels(&ac, adt, mode);
+
+ /* Action */
+ if (adt->action)
+ rearrange_action_channels(&ac, adt->action, mode);
+ else if (G.debug & G_DEBUG)
+ printf("Animdata has no action\n");
+ break;
+ }
}
}
@@ -1275,9 +1396,9 @@ static int animchannels_grouping_poll(bContext *C)
/* dopesheet and action only - all others are for other datatypes or have no groups */
if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0)
return 0;
- }
+
break;
-
+ }
case SPACE_IPO:
{
SpaceIpo *sipo = (SpaceIpo *)sl;
@@ -1285,9 +1406,9 @@ static int animchannels_grouping_poll(bContext *C)
/* drivers can't have groups... */
if (sipo->mode != SIPO_MODE_ANIMATION)
return 0;
- }
+
break;
-
+ }
/* unsupported... */
default:
return 0;
@@ -1537,6 +1658,27 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
break;
}
+ case ANIMTYPE_NLACURVE:
+ {
+ /* NLA Control Curve - Deleting it should disable the corresponding setting... */
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+
+ if (STREQ(fcu->rna_path, "strip_time")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
+ }
+ else if (STREQ(fcu->rna_path, "influence")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
+ }
+ else {
+ printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
+ }
+
+ /* unlink and free the F-Curve */
+ BLI_remlink(&strip->fcurves, fcu);
+ free_fcurve(fcu);
+ break;
+ }
case ANIMTYPE_GPLAYER:
{
/* Grease Pencil layer */
@@ -1566,7 +1708,8 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
+ DAG_relations_tag_update(CTX_data_main(C));
+
return OPERATOR_FINISHED;
}
@@ -1585,175 +1728,6 @@ static void ANIM_OT_channels_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************** Set Channel Visibility Operator *********************** */
-/* NOTE: this operator is only valid in the Graph Editor channels region */
-
-static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- ListBase all_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
- /* get list of all channels that selection may need to be flushed to
- * - hierarchy mustn't affect what we have access to here...
- */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
-
- /* hide all channels not selected
- * - hierarchy matters if we're doing this from the channels region
- * since we only want to apply this to channels we can "see",
- * and have these affect their relatives
- * - but for Graph Editor, this gets used also from main region
- * where hierarchy doesn't apply, as for [#21276]
- */
- if ((ac.spacetype == SPACE_IPO) && (ac.regiontype != RGN_TYPE_CHANNELS)) {
- /* graph editor (case 2) */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
- }
- else {
- /* standard case */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
- }
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* clear setting first */
- ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
-
- /* now also flush selection status as appropriate
- * NOTE: in some cases, this may result in repeat flushing being performed
- */
- ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
- }
-
- ANIM_animdata_freelist(&anim_data);
-
- /* make all the selected channels visible */
- filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
- /* TODO: find out why this is the case, and fix that */
- if (ale->type == ANIMTYPE_OBJECT)
- continue;
-
- /* enable the setting */
- ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
-
- /* now, also flush selection status up/down as appropriate */
- ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
- }
-
- ANIM_animdata_freelist(&anim_data);
- BLI_freelistN(&all_data);
-
-
- /* send notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void ANIM_OT_channels_visibility_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Visibility";
- ot->idname = "ANIM_OT_channels_visibility_set";
- ot->description = "Make only the selected animation channels visible in the Graph Editor";
-
- /* api callbacks */
- ot->exec = animchannels_visibility_set_exec;
- ot->poll = ED_operator_graphedit_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* ******************** Toggle Channel Visibility Operator *********************** */
-/* NOTE: this operator is only valid in the Graph Editor channels region */
-
-static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bAnimContext ac;
- ListBase anim_data = {NULL, NULL};
- ListBase all_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
- short vis = ACHANNEL_SETFLAG_ADD;
-
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
- /* get list of all channels that selection may need to be flushed to
- * - hierarchy mustn't affect what we have access to here...
- */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
-
- /* filter data
- * - restrict this to only applying on settings we can get to in the list
- */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* See if we should be making showing all selected or hiding */
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* set the setting in the appropriate way (if available) */
- if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
- vis = ACHANNEL_SETFLAG_CLEAR;
- break;
- }
- }
-
- /* Now set the flags */
- for (ale = anim_data.first; ale; ale = ale->next) {
- /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
- /* TODO: find out why this is the case, and fix that */
- if (ale->type == ANIMTYPE_OBJECT)
- continue;
-
- /* change the setting */
- ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
-
- /* now, also flush selection status up/down as appropriate */
- ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
- }
-
- /* cleanup */
- ANIM_animdata_freelist(&anim_data);
- BLI_freelistN(&all_data);
-
- /* send notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void ANIM_OT_channels_visibility_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Visibility";
- ot->idname = "ANIM_OT_channels_visibility_toggle";
- ot->description = "Toggle visibility in Graph Editor of all selected animation channels";
-
- /* api callbacks */
- ot->exec = animchannels_visibility_toggle_exec;
- ot->poll = ED_operator_graphedit_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ********************** Set Flags Operator *********************** */
/* defines for setting animation-channel flags */
@@ -2145,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_free_animdata(id);
+ BKE_animdata_free(id);
}
}
@@ -2334,7 +2308,7 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
/* 'standard' behavior - check if selected, then apply relevant selection */
if (RNA_boolean_get(op->ptr, "invert"))
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_TOGGLE);
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
else
ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
@@ -2524,12 +2498,13 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
/* ******************* Rename Operator ***************************** */
/* Allow renaming some channels by clicking on them */
-static void rename_anim_channels(bAnimContext *ac, int channel_index)
+static bool rename_anim_channels(bAnimContext *ac, int channel_index)
{
ListBase anim_data = {NULL, NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
bAnimListElem *ale;
int filter;
+ bool success = false;
/* get the channel that was clicked on */
/* filter channels */
@@ -2544,7 +2519,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
ANIM_animdata_freelist(&anim_data);
- return;
+ return false;
}
/* check that channel can be renamed */
@@ -2564,6 +2539,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
*/
if (ac->ads) {
ac->ads->renameIndex = channel_index + 1;
+ success = true;
}
}
}
@@ -2571,22 +2547,18 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
/* free temp data and tag for refresh */
ANIM_animdata_freelist(&anim_data);
ED_region_tag_redraw(ac->ar);
+ return success;
}
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
{
- bAnimContext ac;
ARegion *ar;
View2D *v2d;
int channel_index;
float x, y;
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
/* get useful pointers from animation context data */
- ar = ac.ar;
+ ar = ac->ar;
v2d = &ar->v2d;
/* figure out which channel user clicked in
@@ -2594,20 +2566,36 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const
* so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
* ACHANNEL_HEIGHT_HALF.
*/
- UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
- if (ac.datatype == ANIMCONT_NLA) {
- SpaceNla *snla = (SpaceNla *)ac.sl;
+ if (ac->datatype == ANIMCONT_NLA) {
+ SpaceNla *snla = (SpaceNla *)ac->sl;
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
}
else {
UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
}
-
+
+ return channel_index;
+}
+
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
/* handle click */
- rename_anim_channels(&ac, channel_index);
-
- return OPERATOR_FINISHED;
+ if (rename_anim_channels(&ac, channel_index))
+ return OPERATOR_FINISHED;
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
}
static void ANIM_OT_channels_rename(wmOperatorType *ot)
@@ -2736,6 +2724,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSGPENCIL:
{
/* sanity checking... */
if (ale->adt) {
@@ -2830,7 +2819,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
- case ANIMTYPE_FCURVE:
+ case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -2847,7 +2837,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
if (fcu->flag & FCURVE_SELECTED)
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
@@ -2870,6 +2860,19 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* toggle expand
+ * - Although the triangle widget already allows this, since there's nothing else that can be done here now,
+ * let's just use it for easier expand/collapse for now
+ */
+ adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
+
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ break;
+ }
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = (bGPdata *)ale->data;
@@ -2897,7 +2900,13 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
gpl->flag |= GP_LAYER_SELECT;
}
- notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ /* change active layer, if this is selected (since we must always have an active layer) */
+ if (gpl->flag & GP_LAYER_SELECT) {
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */
break;
}
case ANIMTYPE_MASKDATABLOCK:
@@ -3015,6 +3024,105 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ bool success = false;
+ FCurve *fcu;
+ int i;
+
+ /* get the channel that was clicked on */
+ /* filter channels */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get channel from index */
+ ale = BLI_findlink(&anim_data, channel_index);
+ if (ale == NULL) {
+ /* channel not found */
+ if (G.debug & G_DEBUG)
+ printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
+
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+
+ fcu = (FCurve *)ale->key_data;
+ success = (fcu != NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ /* F-Curve may not have any keyframes */
+ if (fcu && fcu->bezt) {
+ BezTriple *bezt;
+
+ if (!extend) {
+ filter = (ANIMFILTER_DATA_VISIBLE);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu_inner = (FCurve *)ale->key_data;
+
+ if (fcu_inner) {
+ for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = 0;
+ }
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
+ }
+ }
+
+ /* free temp data and tag for refresh */
+ ED_region_tag_redraw(ac->ar);
+ return success;
+}
+
+static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
+ /* handle click */
+ if (select_anim_channel_keys(&ac, channel_index, extend)) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Channel keyframes";
+ ot->idname = "ANIM_OT_channel_select_keys";
+ ot->description = "Select all keyframes of channel under mouse";
+
+ /* api callbacks */
+ ot->invoke = animchannels_channel_select_keys_invoke;
+ ot->poll = animedit_poll_channels_active;
+
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ************************************************************************** */
/* Operator Registration */
@@ -3024,8 +3132,9 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_select_border);
WM_operatortype_append(ANIM_OT_channels_click);
+ WM_operatortype_append(ANIM_OT_channel_select_keys);
WM_operatortype_append(ANIM_OT_channels_rename);
-
+
WM_operatortype_append(ANIM_OT_channels_find);
WM_operatortype_append(ANIM_OT_channels_setting_enable);
@@ -3042,9 +3151,6 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_expand);
WM_operatortype_append(ANIM_OT_channels_collapse);
- WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
- WM_operatortype_append(ANIM_OT_channels_visibility_set);
-
WM_operatortype_append(ANIM_OT_channels_fcurves_enable);
WM_operatortype_append(ANIM_OT_channels_clean_empty);
@@ -3068,7 +3174,9 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
/* rename */
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
+ WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
@@ -3110,10 +3218,6 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
/* grouping */
WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
-
- /* Graph Editor only */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
}
/* ************************************************************************** */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index f3b47b168e9..a38f5dbc8ea 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -73,8 +73,10 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
/* tag AnimData for refresh so that other views will update in realtime with these changes */
adt = BKE_animdata_from_id(id);
- if (adt)
+ if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
+ DAG_id_tag_update(id, OB_RECALC_TIME);
+ }
/* update data */
fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
@@ -92,7 +94,7 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
RNA_property_update_main(G.main, scene, &ptr, prop);
}
else {
- /* in other case we do standard depsgaph update, ideally
+ /* in other case we do standard depsgraph update, ideally
* we'd be calling property update functions here too ... */
DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 9c3f310a417..ed3d228a93e 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -34,17 +34,25 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "BLI_math.h"
#include "BLI_timecode.h"
+#include "BLI_utildefines.h"
+#include "BLI_rect.h"
+#include "BLI_dlrbTree.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
-#include "BKE_object.h"
+#include "BKE_mask.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_draw.h"
#include "RNA_access.h"
@@ -60,9 +68,10 @@
/* Draw current frame number in a little green box beside the current frame indicator */
static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float xscale, yscale, x, y;
char numstr[32] = " t"; /* t is the character to start replacing from */
- short slen;
+ int slen;
/* because the frame number text is subject to the same scaling as the contents of the view */
UI_view2d_scale_get(v2d, &xscale, &yscale);
@@ -77,9 +86,10 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const
BLI_timecode_string_from_time(&numstr[4], sizeof(numstr) - 4, 0, FRA2TIME(cfra), FPS, U.timecode_style);
}
else {
- BLI_timecode_string_from_time_simple(&numstr[4], sizeof(numstr) - 4, 1, cfra);
+ BLI_timecode_string_from_time_seconds(&numstr[4], sizeof(numstr) - 4, 1, cfra);
}
- slen = (short)UI_GetStringWidth(numstr) - 1;
+
+ slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
/* get starting coordinates for drawing */
x = cfra * xscale;
@@ -91,7 +101,7 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const
/* draw current frame number - black text */
UI_ThemeColor(TH_TEXT);
- UI_DrawString(x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
+ UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
/* restore view transform */
glScalef(xscale, 1.0, 1.0);
@@ -172,10 +182,14 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
if (G.is_rendering) return NULL;
/* handling depends on the type of animation-context we've got */
- if (ale)
- return ale->adt;
- else
- return NULL;
+ if (ale) {
+ /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
+ if (ale->type != ANIMTYPE_NLACURVE)
+ return ale->adt;
+ }
+
+ /* cannot handle... */
+ return NULL;
}
/* ------------------- */
@@ -261,19 +275,36 @@ short ANIM_get_normalization_flags(bAnimContext *ac)
return 0;
}
-static float normalzation_factor_get(FCurve *fcu, short flag)
+static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
{
- float factor = 1.0f;
+ float factor = 1.0f, offset = 0.0f;
if (flag & ANIM_UNITCONV_RESTORE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
+
return 1.0f / fcu->prev_norm_factor;
}
if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
+ if (fcu->prev_norm_factor == 0.0f) {
+ /* Happens when Auto Normalize was disabled before
+ * any curves were displayed.
+ */
+ return 1.0f;
+ }
return fcu->prev_norm_factor;
}
if (G.moving & G_TRANSFORM_FCURVES) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
+ if (fcu->prev_norm_factor == 0.0f) {
+ /* Same as above. */
+ return 1.0f;
+ }
return fcu->prev_norm_factor;
}
@@ -282,32 +313,65 @@ static float normalzation_factor_get(FCurve *fcu, short flag)
BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
+ float min_coord = FLT_MAX;
+ float range;
if (fcu->totvert < 1) {
return 1.0f;
}
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, fabsf(bezt->vec[0][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[1][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[2][1]));
+ if (PRVRANGEON) {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) {
+ max_coord = max_ff(max_coord, bezt->vec[0][1]);
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, bezt->vec[2][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
+ }
+ }
+ else {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ max_coord = max_ff(max_coord, bezt->vec[0][1]);
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, bezt->vec[2][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
}
- if (max_coord > FLT_EPSILON) {
- factor = 1.0f / max_coord;
+ range = max_coord - min_coord;
+
+ if (range > FLT_EPSILON) {
+ factor = 2.0f / range;
}
+ offset = -min_coord - range / 2.0f;
+ }
+ BLI_assert(factor != 0.0f);
+ if (r_offset) {
+ *r_offset = offset;
}
+
fcu->prev_norm_factor = factor;
+ fcu->prev_offset = offset;
return factor;
}
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag)
+float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
- return normalzation_factor_get(fcu, flag);
+ return normalization_factor_get(scene, fcu, flag, r_offset);
}
+ if (r_offset)
+ *r_offset = 0.0f;
+
/* sanity checks */
if (id && fcu && fcu->rna_path) {
PointerRNA ptr, id_ptr;
@@ -335,4 +399,140 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag
return 1.0f;
}
+static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Mask *mask = CTX_data_edit_mask(C);
+ bDopeSheet ads = {NULL};
+ DLRBT_Tree keys;
+ ActKeyColumn *aknext, *akprev;
+ float cfranext, cfraprev;
+ bool donenext = false, doneprev = false;
+ int nextcount = 0, prevcount = 0;
+
+ cfranext = cfraprev = (float)(CFRA);
+
+ /* init binarytree-list for getting keyframes */
+ BLI_dlrbTree_init(&keys);
+
+ /* seed up dummy dopesheet context with flags to perform necessary filtering */
+ if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
+ /* only selected channels are included */
+ ads.filterflag |= ADS_FILTER_ONLYSEL;
+ }
+
+ /* populate tree with keyframe nodes */
+ scene_to_keylist(&ads, scene, &keys, NULL);
+
+ if (ob)
+ ob_to_keylist(&ads, ob, &keys, NULL);
+
+ gpencil_to_keylist(&ads, gpd, &keys);
+
+ if (mask) {
+ MaskLayer *masklay = BKE_mask_layer_active(mask);
+ mask_to_keylist(&ads, masklay, &keys);
+ }
+
+ /* build linked-list for searching */
+ BLI_dlrbTree_linkedlist_sync(&keys);
+
+ /* find matching keyframe in the right direction */
+ do {
+ aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
+
+ if (aknext) {
+ if (CFRA == (int)aknext->cfra) {
+ /* make this the new starting point for the search and ignore */
+ cfranext = aknext->cfra;
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++nextcount == U.view_frame_keyframes)
+ donenext = true;
+ }
+ cfranext = aknext->cfra;
+ }
+ } while ((aknext != NULL) && (donenext == false));
+
+ do {
+ akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev);
+
+ if (akprev) {
+ if (CFRA == (int)akprev->cfra) {
+ /* make this the new starting point for the search */
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++prevcount == U.view_frame_keyframes)
+ doneprev = true;
+ }
+ cfraprev = akprev->cfra;
+ }
+ } while ((akprev != NULL) && (doneprev == false));
+
+ /* free temp stuff */
+ BLI_dlrbTree_free(&keys);
+
+ /* any success? */
+ if (doneprev || donenext) {
+ if (doneprev)
+ *prevfra = cfraprev;
+ else
+ *prevfra = CFRA - (cfranext - CFRA);
+
+ if (donenext)
+ *nextfra = cfranext;
+ else
+ *nextfra = CFRA + (CFRA - cfraprev);
+
+ return true;
+ }
+
+ return false;
+}
+
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+ rctf newrct;
+ int nextfra, prevfra;
+
+ switch (U.view_frame_type) {
+ case ZOOM_FRAME_MODE_SECONDS:
+ {
+ const float fps = FPS;
+ newrct.xmax = scene->r.cfra + U.view_frame_seconds * fps + 1;
+ newrct.xmin = scene->r.cfra - U.view_frame_seconds * fps - 1;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+
+ /* hardest case of all, look for all keyframes around frame and display those */
+ case ZOOM_FRAME_MODE_KEYFRAMES:
+ if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
+ newrct.xmax = nextfra;
+ newrct.xmin = prevfra;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+ /* else drop through, keep range instead */
+
+ case ZOOM_FRAME_MODE_KEEP_RANGE:
+ default:
+ newrct.xmax = scene->r.cfra + (w / 2);
+ newrct.xmin = scene->r.cfra - (w / 2);
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+
+ UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
+}
/* *************************************************** */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index dad25eb04af..8853422df8f 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -216,7 +216,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
/* Get data being edited in Graph Editor (depending on current 'mode') */
static bool graphedit_get_context(bAnimContext *ac, SpaceIpo *sipo)
{
- /* init dopesheet data if non-existant (i.e. for old files) */
+ /* init dopesheet data if non-existent (i.e. for old files) */
if (sipo->ads == NULL) {
sipo->ads = MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
sipo->ads->source = (ID *)ac->scene;
@@ -267,7 +267,7 @@ static bool graphedit_get_context(bAnimContext *ac, SpaceIpo *sipo)
/* Get data being edited in Graph Editor (depending on current 'mode') */
static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
{
- /* init dopesheet data if non-existant (i.e. for old files) */
+ /* init dopesheet data if non-existent (i.e. for old files) */
if (snla->ads == NULL)
snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
ac->ads = snla->ads;
@@ -423,6 +423,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
* - nlaOk: line or block of code to execute for NLA tracks+strips case
* - driversOk: line or block of code to execute for Drivers case
+ * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
* - keysOk: line or block of code for Keyframes case
*
* The checks for the various cases are as follows:
@@ -433,9 +434,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* converted to a new NLA strip, and the filtering options allow this
* 2C) allow non-animated datablocks to be included so that datablocks can be added
* 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
- * 4) normal keyframes: only when there is an active action
+ * 4A) nla strip keyframes: these are the per-strip controls for time and influence
+ * 4B) normal keyframes: only when there is an active action
*/
-#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
+#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
{ \
if ((id)->adt) { \
if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
@@ -456,6 +458,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
} \
} \
else { \
+ if (ANIMDATA_HAS_NLA(id)) { \
+ nlaKeysOk \
+ } \
if (ANIMDATA_HAS_KEYS(id)) { \
keysOk \
} \
@@ -771,6 +776,31 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSGPENCIL:
+ {
+ bGPdata *gpd = (bGPdata *)data;
+ AnimData *adt = gpd->adt;
+
+ /* NOTE: we just reuse the same expand filter for this case */
+ ale->flag = EXPANDED_GPD(gpd);
+
+ // XXX: currently, this is only used for access to its animation data
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)data;
+
+ ale->flag = adt->flag;
+
+ ale->key_data = NULL;
+ ale->datatype = ALE_NONE;
+ break;
+ }
case ANIMTYPE_GROUP:
{
bActionGroup *agrp = (bActionGroup *)data;
@@ -872,7 +902,7 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
{
/* hidden items should be skipped if we only care about visible data, but we aren't interested in hidden stuff */
- short skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN);
+ const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN);
if (GS(owner_id->name) == ID_OB) {
Object *ob = (Object *)owner_id;
@@ -962,7 +992,7 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
{
bAnimListElem ale_dummy = {NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
/* create a dummy wrapper for the F-Curve */
ale_dummy.type = ANIMTYPE_FCURVE;
@@ -1255,7 +1285,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
first = adt->nla_tracks.last;
}
else {
- /* first track to include will the the first one (as per normal) */
+ /* first track to include will the first one (as per normal) */
first = adt->nla_tracks.first;
}
@@ -1271,7 +1301,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
* - active track should still get shown though (even though it has disabled flag set)
*/
// FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
+ if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && (adt->act_track != nlt))
continue;
/* only work with this channel and its subchannels if it is editable */
@@ -1280,6 +1310,30 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
+ /* name based filtering... */
+ if (((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id)) {
+ bool track_ok = false, strip_ok = false;
+
+ /* check if the name of the track, or the strips it has are ok... */
+ track_ok = BLI_strcasestr(nlt->name, ads->searchstr);
+
+ if (track_ok == false) {
+ NlaStrip *strip;
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (BLI_strcasestr(strip->name, ads->searchstr)) {
+ strip_ok = true;
+ break;
+ }
+ }
+ }
+
+ /* skip if both fail this test... */
+ if (!track_ok && !strip_ok) {
+ continue;
+ }
+ }
+
+ /* add the track now that it has passed all our tests */
ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id);
}
}
@@ -1290,6 +1344,80 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
return items;
}
+/* Include the control FCurves per NLA Strip in the channel list
+ * NOTE: This is includes the expander too...
+ */
+static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add control curves from each NLA strip... */
+ /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
+ BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0))
+ {
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ ListBase strip_curves = {NULL, NULL};
+ size_t strip_items = 0;
+
+ /* create the raw items */
+ strip_items += animfilter_fcurves(&strip_curves, ads, strip->fcurves.first, NULL, filter_mode, owner_id);
+
+ /* change their types and add extra data
+ * - There is no point making a separate copy of animfilter_fcurves for this now/yet,
+ * unless we later get per-element control curves for other stuff too
+ */
+ if (strip_items) {
+ bAnimListElem *ale, *ale_n = NULL;
+
+ for (ale = strip_curves.first; ale; ale = ale_n) {
+ ale_n = ale->next;
+
+ /* change the type to being a FCurve for editing NLA strip controls */
+ BLI_assert(ale->type == ANIMTYPE_FCURVE);
+
+ ale->type = ANIMTYPE_NLACURVE;
+ ale->owner = strip;
+
+ ale->adt = NULL; /* XXX: This way, there are no problems with time mapping errors */
+ }
+ }
+
+ /* add strip curves to the set of channels inside the group being collected */
+ BLI_movelisttolist(&tmp_data, &strip_curves);
+ BLI_assert(BLI_listbase_is_empty(&strip_curves));
+ tmp_items += strip_items;
+ }
+ }
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* add the expander as a channel first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* currently these channels cannot be selected, so they should be skipped */
+ if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
+ ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+
+ /* return the numebr of items added to the list */
+ return items;
+}
+
/* determine what animation data from AnimData block should get displayed */
static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
{
@@ -1301,7 +1429,7 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
IdAdtTemplate *iat = (IdAdtTemplate *)id;
/* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed
- * in a few places in he rest of the code still - notably for the few cases where special mode-based
+ * in a few places in the rest of the code still - notably for the few cases where special mode-based
* different types of data expanders are required.
*/
ANIMDATA_FILTER_CASES(iat,
@@ -1317,6 +1445,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
{ /* Drivers */
items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
},
+ { /* NLA Control Keyframes */
+ items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
+ },
{ /* Keyframes */
items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
}
@@ -1413,27 +1544,77 @@ static size_t animdata_filter_gpencil(ListBase *anim_data, void *UNUSED(data), i
/* only show if gpd is used by something... */
if (ID_REAL_USERS(gpd) < 1)
continue;
+
+ /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
+ * for convenience, this will return GP Datablocks instead. This may cause issues down
+ * the track, but for now, this will do...
+ */
+ if (filter_mode & ANIMFILTER_ANIMDATA) {
+ /* just add GPD as a channel - this will add everything needed */
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ }
+ else {
+ /* add gpencil animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
+ {
+ tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
- /* add gpencil animation channels */
- BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
- {
- tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* add gpd as channel too (if for drawing, and it has layers) */
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
}
- END_ANIMFILTER_SUBCHANNELS;
+ }
+
+ /* return the number of items added to the list */
+ return items;
+}
+
+/* Helper for Grease Pencil data integrated with main DopeSheet */
+static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add relevant animation channels for Grease Pencil */
+ BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
+ {
+ /* add animation channels */
+ tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode);
- /* did we find anything? */
- if (tmp_items) {
- /* include data-expand widget first */
- if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
- /* add gpd as channel too (if for drawing, and it has layers) */
- ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ /* add Grease Pencil layers */
+ // TODO: do these need a separate expander?
+ // XXX: what order should these go in?
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* check if filtering by active status */
+ // XXX: active check here needs checking
+ if (ANIMCHANNEL_ACTIVEOK(gpd)) {
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_DSGPENCIL, gpd);
}
-
- /* now add the list of collected channels */
- BLI_movelisttolist(anim_data, &tmp_data);
- BLI_assert(BLI_listbase_is_empty(&tmp_data));
- items += tmp_items;
}
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
}
/* return the number of items added to the list */
@@ -1699,6 +1880,12 @@ static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data,
mtex = (MTex **)(&wo->mtex);
break;
}
+ case ID_PA:
+ {
+ ParticleSettings *part = (ParticleSettings *)owner_id;
+ mtex = (MTex **)(&part->mtex);
+ break;
+ }
default:
{
/* invalid/unsupported option */
@@ -1910,8 +2097,12 @@ static size_t animdata_filter_ds_particles(bAnimContext *ac, ListBase *anim_data
/* add particle-system's animation data to temp collection */
BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part))
{
- /* material's animation data */
+ /* particle system's animation data */
tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
+
+ /* textures */
+ if (!(ads->filterflag & ADS_FILTER_NOTEX))
+ tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
}
END_ANIMFILTER_SUBCHANNELS;
@@ -2139,6 +2330,7 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2215,6 +2407,11 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) {
tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode);
}
+
+ /* grease pencil */
+ if ((ob->gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
+ tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->gpd, filter_mode);
+ }
}
END_ANIMFILTER_SUBCHANNELS;
@@ -2257,7 +2454,7 @@ static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, bD
/* textures for world */
if (!(ads->filterflag & ADS_FILTER_NOTEX))
- items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode);
+ tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode);
/* nodes */
if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE))
@@ -2305,6 +2502,7 @@ static size_t animdata_filter_ds_scene(bAnimContext *ac, ListBase *anim_data, bD
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2349,6 +2547,7 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce))
{
bNodeTree *ntree = sce->nodetree;
+ bGPdata *gpd = sce->gpd;
World *wo = sce->world;
/* Action, Drivers, or NLA for Scene */
@@ -2371,6 +2570,11 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode);
}
+ /* grease pencil */
+ if ((gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
+ tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, gpd, filter_mode);
+ }
+
/* TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here */
}
END_ANIMFILTER_SUBCHANNELS;
@@ -2718,7 +2922,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
/* unhandled */
default:
{
- printf("ANIM_animdata_filter() - Invalid datatype argument %d\n", datatype);
+ printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype);
break;
}
}
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index 57df6d32f03..ae6894ac546 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_anim_types.h"
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 7cd47fab83a..40376c38c3b 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -266,8 +266,20 @@ void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
- if (markers == NULL)
+ if (lb) {
+ /* Clear the list first, since callers have no way of knowing
+ * whether this terminated early otherwise. This may lead
+ * to crashes if the user didn't clear the memory first.
+ */
+ lb->first = lb->last = NULL;
+ }
+ else {
return;
+ }
+
+ if (markers == NULL) {
+ return;
+ }
for (marker = markers->first; marker; marker = marker->next)
add_marker_to_cfra_elem(lb, marker, only_sel);
@@ -316,19 +328,14 @@ void debug_markers_print_list(ListBase *markers)
/* ************* Marker Drawing ************ */
/* function to draw markers */
-static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
+static void draw_marker(
+ View2D *v2d, const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int flag,
+ /* avoid re-calculating each time */
+ const float ypixels, const float xscale, const float yscale)
{
- float xpos, ypixels, xscale, yscale;
- int icon_id = 0;
-
- xpos = marker->frame;
-
- /* no time correction for framelen! space is drawn with old values */
- ypixels = BLI_rcti_size_y(&v2d->mask);
- UI_view2d_scale_get(v2d, &xscale, &yscale);
-
- glScalef(1.0f / xscale, 1.0f, 1.0f);
-
+ const float xpos = marker->frame * xscale;
+ int icon_id;
+
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -347,8 +354,8 @@ static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
glColor4ub(0, 0, 0, 96);
glBegin(GL_LINES);
- glVertex2f((xpos * xscale) + 0.5f, 12.0f);
- glVertex2f((xpos * xscale) + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
+ glVertex2f(xpos + 0.5f, 12.0f);
+ glVertex2f(xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
glEnd();
setlinestyle(0);
@@ -365,7 +372,7 @@ static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
ICON_MARKER;
}
- UI_icon_draw(xpos * xscale - 0.45f * UI_DPI_ICON_SIZE, UI_DPI_ICON_SIZE, icon_id);
+ UI_icon_draw(xpos - 0.45f * UI_DPI_ICON_SIZE, UI_DPI_ICON_SIZE, icon_id);
glDisable(GL_BLEND);
@@ -378,19 +385,19 @@ static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
if (marker->flag & SELECT) {
UI_ThemeColor(TH_TEXT_HI);
- x = xpos * xscale + 4.0f * UI_DPI_FAC;
+ x = xpos + 4.0f * UI_DPI_FAC;
y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
y = max_ii(y, min_y);
}
else {
UI_ThemeColor(TH_TEXT);
if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) {
- x = xpos * xscale + 8.0f * UI_DPI_FAC;
+ x = xpos + 8.0f * UI_DPI_FAC;
y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
y = max_ii(y, min_y);
}
else {
- x = xpos * xscale + 8.0f * UI_DPI_FAC;
+ x = xpos + 8.0f * UI_DPI_FAC;
y = 17.0f * UI_DPI_FAC;
}
}
@@ -404,39 +411,71 @@ static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
}
#endif
- UI_DrawString(x, y, marker->name);
+ UI_fontstyle_draw_simple(fstyle, x, y, marker->name);
}
-
- glScalef(xscale, 1.0f, 1.0f);
}
/* Draw Scene-Markers in time window */
-void draw_markers_time(const bContext *C, int flag)
+void ED_markers_draw(const bContext *C, int flag)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
ListBase *markers = ED_context_get_markers(C);
View2D *v2d;
TimeMarker *marker;
Scene *scene;
+ int select_pass;
+ int v2d_clip_range_x[2];
+ float font_width_max;
- if (markers == NULL)
+ /* cache values */
+ float ypixels, xscale, yscale;
+
+ if (markers == NULL || BLI_listbase_is_empty(markers)) {
return;
+ }
scene = CTX_data_scene(C);
v2d = UI_view2d_fromcontext(C);
- /* unselected markers are drawn at the first time */
- for (marker = markers->first; marker; marker = marker->next) {
- if ((marker->flag & SELECT) == 0) {
- draw_marker(v2d, marker, scene->r.cfra, flag);
- }
+ if (flag & DRAW_MARKERS_MARGIN) {
+ const unsigned char shade[4] = {0, 0, 0, 16};
+ glColor4ubv(shade);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glRectf(v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y);
+
+ glDisable(GL_BLEND);
}
-
- /* selected markers are drawn later */
- for (marker = markers->first; marker; marker = marker->next) {
- if (marker->flag & SELECT) {
- draw_marker(v2d, marker, scene->r.cfra, flag);
+
+ /* no time correction for framelen! space is drawn with old values */
+ ypixels = BLI_rcti_size_y(&v2d->mask);
+ UI_view2d_scale_get(v2d, &xscale, &yscale);
+ glScalef(1.0f / xscale, 1.0f, 1.0f);
+
+ /* x-bounds with offset for text (adjust for long string, avoid checking string width) */
+ font_width_max = (10 * UI_DPI_FAC) / xscale;
+ v2d_clip_range_x[0] = v2d->cur.xmin - (sizeof(marker->name) * font_width_max);
+ v2d_clip_range_x[1] = v2d->cur.xmax + font_width_max;
+
+ /* loop [unselected, selected] */
+ for (select_pass = 0; select_pass <= SELECT; select_pass += SELECT) {
+ /* unselected markers are drawn at the first time */
+ for (marker = markers->first; marker; marker = marker->next) {
+ if ((marker->flag & SELECT) == select_pass) {
+ /* bounds check */
+ if ((marker->frame >= v2d_clip_range_x[0]) &&
+ (marker->frame <= v2d_clip_range_x[1]))
+ {
+ draw_marker(v2d, fstyle, marker, scene->r.cfra, flag,
+ ypixels, xscale, yscale);
+ }
+ }
}
}
+
+ glScalef(xscale, 1.0f, 1.0f);
}
/* ************************ Marker Wrappers API ********************* */
@@ -460,11 +499,32 @@ static int ed_markers_poll_selected_markers(bContext *C)
return ED_markers_get_first_selected(markers) != NULL;
}
+static int ed_markers_poll_selected_no_locked_markers(bContext *C)
+{
+ ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ if (ts->lock_markers)
+ return 0;
+
+ /* first things first: markers can only exist in timeline views */
+ if (ED_operator_animview_active(C) == 0)
+ return 0;
+
+ /* check if some marker is selected */
+ return ED_markers_get_first_selected(markers) != NULL;
+}
+
+
/* special poll() which checks if there are any markers at all first */
static int ed_markers_poll_markers_exist(bContext *C)
{
ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts->lock_markers)
+ return 0;
+
/* first things first: markers can only exist in timeline views */
if (ED_operator_animview_active(C) == 0)
return 0;
@@ -503,8 +563,9 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wm
/* return status modifications - for now, make this spacetype dependent as above */
if (sa->spacetype != SPACE_TIME) {
/* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
- if (retval != OPERATOR_FINISHED)
+ if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) {
retval |= OPERATOR_PASS_THROUGH;
+ }
}
return retval;
@@ -901,11 +962,11 @@ static void MARKER_OT_move(wmOperatorType *ot)
ot->exec = ed_marker_move_exec;
ot->invoke = ed_marker_move_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna storage */
RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
@@ -994,7 +1055,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot)
ot->exec = ed_marker_duplicate_exec;
ot->invoke = ed_marker_duplicate_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
@@ -1029,7 +1090,7 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte
}
BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
- /* this way a not-extend select will allways give 1 selected marker */
+ /* this way a not-extend select will always give 1 selected marker */
if (marker->frame == frame) {
marker->flag ^= SELECT;
break;
@@ -1324,7 +1385,7 @@ static void MARKER_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_delete_invoke_wrapper;
ot->exec = ed_marker_delete_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1372,7 +1433,7 @@ static void MARKER_OT_rename(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_rename_invoke_wrapper;
ot->exec = ed_marker_rename_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1400,6 +1461,11 @@ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (scene_to->toolsettings->lock_markers) {
+ BKE_report(op->reports, RPT_ERROR, "Target scene has locked markers");
+ return OPERATOR_CANCELLED;
+ }
+
/* copy markers */
for (marker = markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
@@ -1475,13 +1541,13 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Bind Camera to Markers";
- ot->description = "Bind the active camera to selected markers(s)";
+ ot->description = "Bind the active camera to selected marker(s)";
ot->idname = "MARKER_OT_camera_bind";
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 0f202003dd8..262ce0b9e23 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -41,6 +41,7 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_sequencer.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_sound.h"
@@ -55,6 +56,7 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
+#include "ED_sequencer.h"
#include "anim_intern.h"
@@ -92,14 +94,20 @@ static void change_frame_apply(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
-
+ int frame = RNA_int_get(op->ptr, "frame");
+ bool do_snap = RNA_boolean_get(op->ptr, "snap");
+
+ if (do_snap && CTX_wm_space_seq(C)) {
+ frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false);
+ }
+
/* set the new frame number */
- CFRA = RNA_int_get(op->ptr, "frame");
+ CFRA = frame;
FRAMENUMBER_MIN_CLAMP(CFRA);
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -136,6 +144,41 @@ static int frame_from_event(bContext *C, const wmEvent *event)
return frame;
}
+static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ if (sa && sa->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = sa->spacedata.first;
+ if (ED_space_sequencer_check_show_strip(sseq)) {
+ ED_sequencer_special_preview_set(C, event->mval);
+ }
+ }
+ if (screen)
+ screen->scrubbing = true;
+}
+
+static void change_frame_seq_preview_end(bContext *C)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ bool notify = false;
+
+ if (screen->scrubbing) {
+ screen->scrubbing = false;
+ notify = true;
+ }
+
+ if (ED_sequencer_special_preview_get() != NULL) {
+ ED_sequencer_special_preview_clear();
+ notify = true;
+ }
+
+ if (notify) {
+ Scene *scene = CTX_data_scene(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+ }
+}
+
/* Modal Operator init */
static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -144,7 +187,9 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
* click-dragging over a range (modal scrubbing).
*/
RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
-
+
+ change_frame_seq_preview_begin(C, event);
+
change_frame_apply(C, op);
/* add temp handler */
@@ -153,14 +198,21 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
return OPERATOR_RUNNING_MODAL;
}
+static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op))
+{
+ change_frame_seq_preview_end(C);
+}
+
/* Modal event handling of frame changing */
static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
switch (event->type) {
case ESCKEY:
- return OPERATOR_FINISHED;
-
+ ret = OPERATOR_FINISHED;
+ break;
+
case MOUSEMOVE:
RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
change_frame_apply(C, op);
@@ -173,15 +225,31 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
* the modal op) doesn't work for some reason
*/
if (event->val == KM_RELEASE)
- return OPERATOR_FINISHED;
+ ret = OPERATOR_FINISHED;
+ break;
+
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ if (event->val == KM_RELEASE) {
+ RNA_boolean_set(op->ptr, "snap", false);
+ }
+ else if (event->val == KM_PRESS) {
+ RNA_boolean_set(op->ptr, "snap", true);
+ }
break;
}
- return OPERATOR_RUNNING_MODAL;
+ if (ret != OPERATOR_RUNNING_MODAL) {
+ change_frame_seq_preview_end(C);
+ }
+
+ return ret;
}
static void ANIM_OT_change_frame(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Change Frame";
ot->idname = "ANIM_OT_change_frame";
@@ -190,14 +258,17 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
/* api callbacks */
ot->exec = change_frame_exec;
ot->invoke = change_frame_invoke;
+ ot->cancel = change_frame_cancel;
ot->modal = change_frame_modal;
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR;
/* rna */
ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
+ prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ****************** set preview range operator ****************************/
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 481912f4d1f..b2a34d7c317 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -39,18 +39,13 @@
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
-#include "DNA_object_types.h"
-#include "DNA_material_types.h"
#include "DNA_texture_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BKE_material.h"
-#include "BKE_texture.h"
#include "ED_keyframing.h"
@@ -90,7 +85,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
return NULL;
@@ -426,74 +421,6 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
/* ************************************************** */
/* UI-Button Interface */
-/**
- * Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * \param C Context pointer - for getting active data
- * \param[in,out] ptr RNA pointer for property's datablock. May be modified as result of path remapping.
- * \param prop RNA definition of property to add for
- * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
- */
-static char *get_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
-{
- ID *id = (ID *)ptr->id.data;
- ScrArea *sa = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- // TODO: watch out for pinned context?
- if ((sa) && (sa->spacetype == SPACE_BUTS)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* only id-types which can be remapped to go through objects should be considered */
- switch (GS(id->name)) {
- case ID_TE: /* textures */
- {
- Material *ma = give_current_material(ob, ob->actcol);
- Tex *tex = give_current_material_texture(ma);
-
- /* assumes: texture will only be shown if it is active material's active texture it's ok */
- if ((ID *)tex == id) {
- char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
- char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
-
- BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
- BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
-
- /* create new path */
- // TODO: use RNA path functions to construct step by step instead?
- // FIXME: maybe this isn't even needed anymore...
- path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s",
- name_esc_ma, name_esc_tex, basepath);
-
- /* free old one */
- MEM_freeN(basepath);
- }
- break;
- }
- }
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
/* Add Driver Button Operator ------------------------ */
static int add_driver_button_exec(bContext *C, wmOperator *op)
@@ -505,13 +432,13 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to create driver using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (all)
index = -1;
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
if (path) {
@@ -523,8 +450,8 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
- uiContextAnimUpdate(C);
-
+ UI_context_update_anim_flag(C);
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -560,22 +487,25 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to find driver using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (all)
index = -1;
if (ptr.id.data && ptr.data && prop) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
- success = ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0);
- MEM_freeN(path);
+ if (path) {
+ success = ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0);
+
+ MEM_freeN(path);
+ }
}
if (success) {
/* send updates */
- uiContextAnimUpdate(C);
-
+ UI_context_update_anim_flag(C);
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -610,16 +540,16 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op)
int index;
/* try to create driver using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
if (path) {
/* only copy the driver for the button that this was involved for */
success = ANIM_copy_driver(op->reports, ptr.id.data, path, index, 0);
- uiContextAnimUpdate(C);
+ UI_context_update_anim_flag(C);
MEM_freeN(path);
}
@@ -654,16 +584,16 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
int index;
/* try to create driver using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
if (path) {
/* only copy the driver for the button that this was involved for */
success = ANIM_paste_driver(op->reports, ptr.id.data, path, index, 0);
- uiContextAnimUpdate(C);
+ UI_context_update_anim_flag(C);
MEM_freeN(path);
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 7ce33e01747..91705d63286 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -45,7 +45,7 @@
#include "MEM_guardedalloc.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -78,7 +78,7 @@
static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
{
FModifier *fcm = (FModifier *)fcm_v;
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
@@ -119,17 +119,18 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
/* basic settings (backdrop + mode selector + some padding) */
/* col = uiLayoutColumn(layout, true); */ /* UNUSED */
block = uiLayoutGetBlock(layout);
- uiBlockBeginAlign(block);
- but = uiDefButR(block, MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
+ UI_block_align_begin(block);
+ but = uiDefButR(block, UI_BTYPE_MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
+ UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
- uiDefButR(block, TOG, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL);
- uiBlockEndAlign(block);
+ uiDefButR(block, UI_BTYPE_TOGGLE, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL);
+ UI_block_align_end(block);
/* now add settings for individual modes */
switch (data->mode) {
case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float *cp = NULL;
char xval[32];
unsigned int i;
@@ -138,20 +139,21 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
/* draw polynomial order selector */
row = uiLayoutRow(layout, false);
block = uiLayoutGetBlock(row);
- but = uiDefButI(block, NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0.5f * UI_UNIT_X, 0, bwidth, UI_UNIT_Y,
+ but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0.5f * UI_UNIT_X, 0, bwidth, UI_UNIT_Y,
&data->poly_order, 1, 100, 0, 0,
TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
+ UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
/* calculate maximum width of label for "x^n" labels */
if (data->arraysize > 2) {
BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize);
- maxXWidth = UI_GetStringWidth(xval) + 0.5 * UI_UNIT_X; /* XXX: UI_GetStringWidth is not accurate */
+ /* XXX: UI_fontstyle_string_width is not accurate */
+ maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X;
}
else {
/* basic size (just "x") */
- maxXWidth = UI_GetStringWidth("x") + 0.5 * UI_UNIT_X;
+ maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X;
}
/* draw controls for each coefficient and a + sign at end of row */
@@ -162,12 +164,12 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
for (i = 0; (i < data->arraysize) && (cp); i++, cp++) {
/* To align with first line... */
if (i)
- uiDefBut(block, LABEL, 1, " ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
else
- uiDefBut(block, LABEL, 1, "y =", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* coefficient */
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, bwidth / 2, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
+ uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, bwidth / 2, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
10, 3, TIP_("Coefficient for polynomial"));
/* 'x' param (and '+' if necessary) */
@@ -177,10 +179,10 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
BLI_strncpy(xval, "x", sizeof(xval));
else
BLI_snprintf(xval, sizeof(xval), "x^%u", i);
- uiDefBut(block, LABEL, 1, xval, 0, 0, maxXWidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Power of x"));
+ uiDefBut(block, UI_BTYPE_LABEL, 1, xval, 0, 0, maxXWidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Power of x"));
if ( (i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2) ) {
- uiDefBut(block, LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* next coefficient on a new row */
row = uiLayoutRow(layout, true);
@@ -188,7 +190,7 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
}
else {
/* For alignment in UI! */
- uiDefBut(block, LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
}
break;
@@ -202,10 +204,10 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
/* draw polynomial order selector */
row = uiLayoutRow(layout, false);
block = uiLayoutGetBlock(row);
- but = uiDefButI(block, NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0, 0, width - 1.5 * UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0, 0, width - 1.5 * UI_UNIT_X, UI_UNIT_Y,
&data->poly_order, 1, 100, 0, 0,
TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
+ UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
/* draw controls for each pair of coefficients */
@@ -216,31 +218,31 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
for (i = 0; (i < data->poly_order) && (cp); i++, cp += 2) {
/* To align with first line */
if (i)
- uiDefBut(block, LABEL, 1, " ", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
else
- uiDefBut(block, LABEL, 1, "y =", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* opening bracket */
- uiDefBut(block, LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* coefficients */
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
+ uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
10, 3, TIP_("Coefficient of x"));
- uiDefBut(block, LABEL, 1, "x +", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, "x +", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp + 1, -UI_FLT_MAX, UI_FLT_MAX,
+ uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp + 1, -UI_FLT_MAX, UI_FLT_MAX,
10, 3, TIP_("Second coefficient"));
/* closing bracket and multiplication sign */
if ( (i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2) ) {
- uiDefBut(block, LABEL, 1, ") \xc3\x97", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, ") \xc3\x97", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* set up new row for the next pair of coefficients */
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
}
else
- uiDefBut(block, LABEL, 1, ") ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, ") ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
break;
}
@@ -439,11 +441,11 @@ static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, sh
row = uiLayoutRow(layout, false);
block = uiLayoutGetBlock(row);
- uiDefBut(block, LABEL, 1, IFACE_("Control Points:"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 1, IFACE_("Control Points:"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
- but = uiDefBut(block, BUT, B_FMODIFIER_REDRAW, IFACE_("Add Point"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, IFACE_("Add Point"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Add a new control-point to the envelope on the current frame"));
- uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
+ UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL);
/* control points list */
for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
@@ -451,20 +453,20 @@ static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, sh
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
- uiBlockBeginAlign(block);
- but = uiDefButF(block, NUM, B_FMODIFIER_REDRAW, IFACE_("Fra:"), 0, 0, 4.5 * UI_UNIT_X, UI_UNIT_Y,
+ UI_block_align_begin(block);
+ but = uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Fra:"), 0, 0, 4.5 * UI_UNIT_X, UI_UNIT_Y,
&fed->time, -MAXFRAMEF, MAXFRAMEF, 10, 1, TIP_("Frame that envelope point occurs"));
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
+ UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, IFACE_("Min:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
+ uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Min:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
&fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Minimum bound of envelope at this point"));
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, IFACE_("Max:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
+ uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Max:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
&fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Maximum bound of envelope at this point"));
- but = uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 0.9 * UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 0.9 * UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete envelope control point"));
- uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
- uiBlockBeginAlign(block);
+ UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
+ UI_block_align_begin(block);
}
}
@@ -553,7 +555,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho
void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
uiLayout *box, *row, *sub, *col;
uiBlock *block;
uiBut *but;
@@ -575,7 +577,7 @@ void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifier
sub = uiLayoutRow(row, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* expand */
uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
@@ -597,14 +599,14 @@ void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifier
/* 'mute' button */
uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* delete button */
- but = uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete F-Curve Modifier"));
- uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm);
+ UI_but_func_set(but, delete_fmodifier_cb, modifiers, fcm);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
/* when modifier is expanded, draw settings */
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index c5e54cc1c7c..6f1883cff55 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -39,7 +39,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
#include "BLI_utildefines.h"
@@ -106,7 +105,7 @@ static DLRBT_Node *nalloc_ak_bezt(void *data)
/* store settings based on state of BezTriple */
ak->cfra = bezt->vec[1][0];
- ak->sel = BEZSELECTED(bezt) ? SELECT : 0;
+ ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
ak->key_type = BEZKEYTYPE(bezt);
/* set 'modified', since this is used to identify long keyframes */
@@ -122,7 +121,7 @@ static void nupdate_ak_bezt(void *node, void *data)
BezTriple *bezt = (BezTriple *)data;
/* set selection status and 'touched' status */
- if (BEZSELECTED(bezt)) ak->sel = SELECT;
+ if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
ak->modified += 1;
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
@@ -155,6 +154,7 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data)
/* store settings based on state of BezTriple */
ak->cfra = gpf->framenum;
ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
+ ak->key_type = gpf->key_type;
/* set 'modified', since this is used to identify long keyframes */
ak->modified = 1;
@@ -171,6 +171,10 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* set selection status and 'touched' status */
if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT;
ak->modified += 1;
+
+ /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
+ if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME)
+ ak->key_type = BEZT_KEYTYPE_KEYFRAME;
}
/* ......... */
@@ -275,7 +279,7 @@ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
ab->end = beztn->vec[1][0];
ab->val = beztn->vec[1][1];
- ab->sel = (BEZSELECTED(prev) || BEZSELECTED(beztn)) ? SELECT : 0;
+ ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
ab->modified = 1;
return ab;
@@ -336,7 +340,7 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
*/
if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
/* set selection status and 'touched' status */
- if (BEZSELECTED(beztn)) ab->sel = SELECT;
+ if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT;
ab->modified++;
/* done... no need to insert */
@@ -524,7 +528,7 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
}
/* NOTE: we don't use the straight alpha from the theme, or else effects such as
- * greying out protected/muted channels doesn't work correctly!
+ * graying out protected/muted channels doesn't work correctly!
*/
inner_col[3] *= alpha;
glColor4fv(inner_col);
@@ -732,6 +736,21 @@ void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
BLI_dlrbTree_free(&blocks);
}
+void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos)
+{
+ DLRBT_Tree keys;
+
+ BLI_dlrbTree_init(&keys);
+
+ gpencil_to_keylist(ads, gpd, &keys);
+
+ BLI_dlrbTree_linkedlist_sync(&keys);
+
+ draw_keylist(v2d, &keys, NULL, ypos, 0);
+
+ BLI_dlrbTree_free(&keys);
+}
+
void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
{
DLRBT_Tree keys;
@@ -924,6 +943,20 @@ void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree
}
+void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
+{
+ bGPDlayer *gpl;
+
+ if (gpd && keys) {
+ /* for now, just aggregate out all the frames, but only for visible layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & GP_LAYER_HIDE) == 0) {
+ gpl_to_keylist(ads, gpl, keys);
+ }
+ }
+ }
+}
+
void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
{
bGPDframe *gpf;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 83593faff22..bd34f32dda8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -41,9 +41,7 @@
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
-#include "DNA_node_types.h"
#include "DNA_scene_types.h"
-#include "DNA_space_types.h"
#include "BKE_fcurve.h"
@@ -457,7 +455,7 @@ static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
/* this macro checks all beztriple handles for selection...
* only one of the verts has to be selected for this to be ok...
*/
- if (BEZSELECTED(bezt))
+ if (BEZT_ISSEL_ANY(bezt))
return KEYFRAME_OK_ALL;
else
return 0;
@@ -548,6 +546,44 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+/**
+ * only called from #ok_bezier_region_circle
+ */
+static bool bezier_region_circle_test(
+ const struct KeyframeEdit_CircleData *data_circle,
+ const float xy[2])
+{
+ if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
+ float xy_view[2];
+
+ BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy);
+
+ xy_view[0] = xy_view[0] - data_circle->mval[0];
+ xy_view[1] = xy_view[1] - data_circle->mval[1];
+ return len_squared_v2(xy_view) < data_circle->radius_squared;
+ }
+
+ return false;
+}
+
+
+static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* rect is stored in data property (it's of type rectf, but may not be set) */
+ if (ked->data) {
+ short ok = 0;
+
+#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
+ KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
+#undef KEY_CHECK_OK
+
+ /* return ok flags */
+ return ok;
+ }
+ else
+ return 0;
+}
+
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
@@ -567,6 +603,8 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region;
case BEZT_OK_REGION_LASSO: /* only if the point falls within KeyframeEdit_LassoData defined data */
return ok_bezier_region_lasso;
+ case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_LassoData defined data */
+ return ok_bezier_region_circle;
default: /* nothing was ok */
return NULL;
}
@@ -643,7 +681,7 @@ static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
const float secf = (float)FPS;
if (bezt->f2 & SELECT)
- bezt->vec[1][0] = ((float)floor(bezt->vec[1][0] / secf + 0.5f) * secf);
+ bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf);
return 0;
}
@@ -747,7 +785,8 @@ static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
if (bezt->f2 & SELECT) {
- mirror_bezier_yaxis_ex(bezt, 0.0f);
+ /* Yes, names are inverted, we are mirroring accross y axis, hence along x axis... */
+ mirror_bezier_xaxis_ex(bezt, 0.0f);
}
return 0;
@@ -756,7 +795,8 @@ static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
if (bezt->f2 & SELECT) {
- mirror_bezier_xaxis_ex(bezt, 0.0f);
+ /* Yes, names are inverted, we are mirroring accross x axis, hence along y axis... */
+ mirror_bezier_yaxis_ex(bezt, 0.0f);
}
return 0;
@@ -776,7 +816,7 @@ static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
{
/* value to mirror over is stored in the custom data -> first float value slot */
if (bezt->f2 & SELECT) {
- mirror_bezier_xaxis_ex(bezt, ked->f1);
+ mirror_bezier_yaxis_ex(bezt, ked->f1);
}
return 0;
@@ -1141,7 +1181,7 @@ static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
bezt->f3 |= SELECT;
}
else {
- BEZ_SEL(bezt);
+ BEZT_SEL_ALL(bezt);
}
return 0;
@@ -1159,7 +1199,7 @@ static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
bezt->f3 &= ~SELECT;
}
else {
- BEZ_DESEL(bezt);
+ BEZT_DESEL_ALL(bezt);
}
return 0;
@@ -1212,7 +1252,7 @@ static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
int i = ked->curIndex;
/* if current is selected, just make sure it stays this way */
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
map[i] = 1;
return 0;
}
@@ -1221,7 +1261,7 @@ static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
if (i > 0) {
BezTriple *prev = bezt - 1;
- if (BEZSELECTED(prev)) {
+ if (BEZT_ISSEL_ANY(prev)) {
map[i] = 1;
return 0;
}
@@ -1231,7 +1271,7 @@ static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
if (i < (fcu->totvert - 1)) {
BezTriple *next = bezt + 1;
- if (BEZSELECTED(next)) {
+ if (BEZT_ISSEL_ANY(next)) {
map[i] = 1;
return 0;
}
@@ -1249,12 +1289,12 @@ static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
/* if current is selected, check the left/right keyframes
* since it might need to be deselected (but otherwise no)
*/
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
/* if previous is not selected, we're on the tip of an iceberg */
if (i > 0) {
BezTriple *prev = bezt - 1;
- if (BEZSELECTED(prev) == 0)
+ if (BEZT_ISSEL_ANY(prev) == 0)
return 0;
}
else if (i == 0) {
@@ -1266,7 +1306,7 @@ static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
if (i < (fcu->totvert - 1)) {
BezTriple *next = bezt + 1;
- if (BEZSELECTED(next) == 0)
+ if (BEZT_ISSEL_ANY(next) == 0)
return 0;
}
else if (i == (fcu->totvert - 1)) {
@@ -1304,10 +1344,10 @@ short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
/* select or deselect based on whether the map allows it or not */
if (on) {
- BEZ_SEL(bezt);
+ BEZT_SEL_ALL(bezt);
}
else {
- BEZ_DESEL(bezt);
+ BEZT_DESEL_ALL(bezt);
}
return 0;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 56165c36efa..3642c07b758 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -43,13 +43,14 @@
#include "DNA_scene_types.h"
+#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
#include "BKE_library.h"
#include "BKE_global.h"
+#include "BKE_deform.h"
#include "RNA_access.h"
-#include "RNA_enum_types.h"
#include "ED_anim_api.h"
#include "ED_keyframing.h"
@@ -166,11 +167,11 @@ void duplicate_fcurve_keys(FCurve *fcu)
fcu->bezt = newbezt;
/* Unselect the current key */
- BEZ_DESEL(&fcu->bezt[i]);
+ BEZT_DESEL_ALL(&fcu->bezt[i]);
i++;
/* Select the copied key */
- BEZ_SEL(&fcu->bezt[i]);
+ BEZT_SEL_ALL(&fcu->bezt[i]);
}
}
}
@@ -178,17 +179,22 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* **************************************************** */
/* Various Tools */
-/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
-void clean_fcurve(FCurve *fcu, float thresh)
+/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only
+ * optionally clears up curve if one keyframe with default value remains */
+void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
+ FCurve *fcu = (FCurve *)ale->key_data;
BezTriple *old_bezts, *bezt, *beztn;
BezTriple *lastb;
int totCount, i;
/* check if any points */
- if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert <= 1))
+ if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
+ (!cleardefault && fcu->totvert == 1))
+ {
return;
-
+ }
+
/* make a copy of the old BezTriples, and clear F-Curve */
old_bezts = fcu->bezt;
totCount = fcu->totvert;
@@ -198,13 +204,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
+ if (!(bezt->f2 & SELECT)) {
+ lastb = fcu->bezt;
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ }
/* Loop through BezTriples, comparing them. Skip any that do
* not fit the criteria for "ok" points.
*/
for (i = 1; i < totCount; i++) {
float prev[2], cur[2], next[2];
-
+
/* get BezTriples and their values */
if (i < (totCount - 1)) {
beztn = (old_bezts + (i + 1));
@@ -216,10 +226,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
}
lastb = (fcu->bezt + (fcu->totvert - 1));
bezt = (old_bezts + i);
-
+
/* get references for quicker access */
prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
+
+ if (!(bezt->f2 & SELECT)) {
+ insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ lastb = (fcu->bezt + (fcu->totvert - 1));
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ continue;
+ }
/* check if current bezt occurs at same time as last ok */
if (IS_EQT(cur[0], prev[0], thresh)) {
@@ -227,7 +244,7 @@ void clean_fcurve(FCurve *fcu, float thresh)
* if there is a considerable distance between the points, and also if the
* current is further away than the next one is to the previous.
*/
- if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
+ if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
(IS_EQT(next[1], prev[1], thresh) == 0))
{
/* only add if current is further away from previous */
@@ -272,6 +289,34 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* now free the memory used by the old BezTriples */
if (old_bezts)
MEM_freeN(old_bezts);
+
+ /* final step, if there is just one key in fcurve, check if it's
+ * the default value and if is, remove fcurve completely. */
+ if (cleardefault && fcu->totvert == 1) {
+ float default_value = 0.0f;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ RNA_id_pointer_create(ale->id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
+ if (RNA_property_type(prop) == PROP_FLOAT)
+ default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
+ }
+
+ if (fcu->bezt->vec[1][1] == default_value) {
+ clear_fcurve_keys(fcu);
+
+ /* check if curve is really unused and if it is, return signal for deletion */
+ if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
+ (fcu->driver == NULL))
+ {
+ AnimData *adt = ale->adt;
+ ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
+ ale->key_data = NULL;
+ }
+ }
+ }
}
/* ---------------- */
@@ -296,7 +341,7 @@ void smooth_fcurve(FCurve *fcu)
/* first loop through - count how many verts are selected */
bezt = fcu->bezt;
for (i = 0; i < fcu->totvert; i++, bezt++) {
- if (BEZSELECTED(bezt))
+ if (BEZT_ISSEL_ANY(bezt))
totSel++;
}
@@ -310,7 +355,7 @@ void smooth_fcurve(FCurve *fcu)
/* populate tarray with data of selected points */
bezt = fcu->bezt;
for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
/* tsb simply needs pointer to vec, and index */
tsb->h1 = &bezt->vec[0][1];
tsb->h2 = &bezt->vec[1][1];
@@ -399,7 +444,7 @@ void sample_fcurve(FCurve *fcu)
/* find selected keyframes... once pair has been found, add keyframes */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* check if selected, and which end this is */
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
if (start) {
/* set end */
end = bezt;
@@ -478,6 +523,7 @@ typedef struct tAnimCopybufItem {
BezTriple *bezt; /* keyframes in buffer */
short id_type; /* Result of GS(id->name)*/
+ bool is_bone; /* special flag for armature bones */
} tAnimCopybufItem;
@@ -541,13 +587,29 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
aci->grp = fcu->grp;
aci->rna_path = MEM_dupallocN(fcu->rna_path);
aci->array_index = fcu->array_index;
+
+ /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo.
+ * storing the relevant information here helps avoiding crashes if we undo-repaste */
+ if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
+ Object *ob = (Object *)aci->id;
+ bPoseChannel *pchan;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan) {
+ aci->is_bone = true;
+ }
+ if (bone_name) MEM_freeN(bone_name);
+ }
+
BLI_addtail(&animcopybuf, aci);
/* add selected keyframes to buffer */
/* TODO: currently, we resize array every time we add a new vert -
* this works ok as long as it is assumed only a few keys are copied */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
/* add to buffer */
newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
@@ -560,7 +622,7 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
*nbezt = *bezt;
/* ensure copy buffer is selected so pasted keys are selected */
- BEZ_SEL(nbezt);
+ BEZT_SEL_ALL(nbezt);
/* free old array and set the new */
if (aci->bezt) MEM_freeN(aci->bezt);
@@ -588,19 +650,65 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
return 0;
}
+static void flip_names(tAnimCopybufItem *aci, char **name)
+{
+ if (aci->is_bone) {
+ char *str_start;
+ if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
+ /* ninja coding, try to change the name */
+ char bname_new[MAX_VGROUP_NAME];
+ char *str_iter, *str_end;
+ int length, prefix_l, postfix_l;
+
+ str_start += 12;
+ prefix_l = str_start - aci->rna_path;
+
+ str_end = strchr(str_start, '\"');
+
+ length = str_end - str_start;
+ postfix_l = strlen(str_end);
+
+ /* more ninja stuff, temporary substitute with NULL terminator */
+ str_start[length] = 0;
+ BKE_deform_flip_side_name(bname_new, str_start, false);
+ str_start[length] = '\"';
+
+ str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
+
+ BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
+ str_iter += prefix_l;
+ BLI_strncpy(str_iter, bname_new, length + 1);
+ str_iter += length;
+ BLI_strncpy(str_iter, str_end, postfix_l + 1);
+ str_iter[postfix_l] = '\0';
+ }
+ }
+}
+
/* ------------------- */
/* most strict method: exact matches only */
-static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple)
+static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple, bool flip)
{
tAnimCopybufItem *aci;
for (aci = animcopybuf.first; aci; aci = aci->next) {
- /* check that paths exist */
if (to_simple || (aci->rna_path && fcu->rna_path)) {
- if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) {
- if ((from_single) || (aci->array_index == fcu->array_index))
+ if (!to_simple && flip && aci->is_bone && fcu->rna_path) {
+ if ((from_single) || (aci->array_index == fcu->array_index)) {
+ char *name = NULL;
+ flip_names(aci, &name);
+ if (STREQ(name, fcu->rna_path)) {
+ MEM_freeN(name);
+ break;
+ }
+ MEM_freeN(name);
+ }
+ }
+ else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) {
+ if ((from_single) || (aci->array_index == fcu->array_index)) {
break;
+ }
}
}
}
@@ -638,7 +746,7 @@ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short f
int len_path = strlen(fcu->rna_path);
if (len_id <= len_path) {
/* note, paths which end with "] will fail with this test - Animated ID Props */
- if (strcmp(identifier, fcu->rna_path + (len_path - len_id)) == 0) {
+ if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) {
if ((from_single) || (aci->array_index == fcu->array_index))
break;
}
@@ -671,15 +779,37 @@ static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from
/* ................ */
+static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt)
+{
+ if (aci->is_bone) {
+ const size_t slength = strlen(aci->rna_path);
+ bool flip = false;
+ if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0)
+ flip = true;
+ else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) && ELEM(aci->array_index, 2, 3))
+ flip = true;
+ else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) && ELEM(aci->array_index, 1, 2))
+ flip = true;
+ else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) && ELEM(aci->array_index, 2, 3))
+ flip = true;
+
+ if (flip) {
+ bezt->vec[0][1] = -bezt->vec[0][1];
+ bezt->vec[1][1] = -bezt->vec[1][1];
+ bezt->vec[2][1] = -bezt->vec[2][1];
+ }
+ }
+}
+
/* helper for paste_animedit_keys() - performs the actual pasting */
-static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode)
+static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip)
{
BezTriple *bezt;
int i;
/* First de-select existing FCurve's keyframes */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- bezt->f2 &= ~SELECT;
+ BEZT_DESEL_ALL(bezt);
}
/* mix mode with existing data */
@@ -724,9 +854,12 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
}
}
- /* just start pasting, with the the first keyframe on the current frame, and so on */
+ /* just start pasting, with the first keyframe on the current frame, and so on */
for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) {
/* temporarily apply offset to src beztriple while copying */
+ if (flip)
+ do_curve_mirror_flippping(aci, bezt);
+
bezt->vec[0][0] += offset;
bezt->vec[1][0] += offset;
bezt->vec[2][0] += offset;
@@ -734,12 +867,16 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
/* insert the keyframe
* NOTE: we do not want to inherit handles from existing keyframes in this case!
*/
+
insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
/* un-apply offset from src beztriple after copying */
bezt->vec[0][0] -= offset;
bezt->vec[1][0] -= offset;
bezt->vec[2][0] -= offset;
+
+ if (flip)
+ do_curve_mirror_flippping(aci, bezt);
}
/* recalculate F-Curve's handles? */
@@ -769,7 +906,7 @@ EnumPropertyItem keyframe_paste_merge_items[] = {
* \return Status code is whether the method FAILED to do anything
*/
short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
- const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
+ const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
{
bAnimListElem *ale;
@@ -817,7 +954,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
fcu = (FCurve *)ale->data; /* destination F-Curve */
aci = animcopybuf.first;
- paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
+ paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
}
else {
/* from selected channels
@@ -834,13 +971,14 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
* - if names do matter, only check if id-type is ok for now (group check is not that important)
* - most importantly, rna-paths should match (array indices are unimportant for now)
*/
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */
tAnimCopybufItem *aci = NULL;
switch (pass) {
case 0:
/* most strict, must be exact path match data_path & index */
- aci = pastebuf_match_path_full(fcu, from_single, to_simple);
+ aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip);
break;
case 1:
@@ -857,9 +995,17 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
/* copy the relevant data from the matching buffer curve */
if (aci) {
totmatch++;
- paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
+
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
+ }
}
-
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 4c2d90179a7..479b4272755 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -130,7 +130,7 @@ bAction *verify_adt_action(ID *id, short add)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>");
@@ -152,6 +152,10 @@ bAction *verify_adt_action(ID *id, short add)
* to the wrong places
*/
adt->action->idroot = GS(id->name);
+
+ /* tag depsgraph to be rebuilt to include time dependency */
+ /* XXX: we probably should have bmain passed down, but that involves altering too many API's */
+ DAG_relations_tag_update(G.main);
}
/* return the action */
@@ -658,7 +662,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
/* validate data */
if (ELEM(NULL, ptr, ptr->data, prop))
- return 0;
+ return false;
/* get first constraint and determine type of keyframe constraints to check for
* - constraints can be on either Objects or PoseChannels, so we only check if the
@@ -880,7 +884,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
/* no F-Curve to add keyframe to? */
if (fcu == NULL) {
BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to");
- return 0;
+ return false;
}
/* F-Curve not editable? */
if (fcurve_is_keyframable(fcu) == 0) {
@@ -888,13 +892,13 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
"F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, "
"and try removing F-Modifiers",
fcu->rna_path, fcu->array_index);
- return 0;
+ return false;
}
/* if no property given yet, try to validate from F-Curve info */
if ((ptr.id.data == NULL) && (ptr.data == NULL)) {
BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from");
- return 0;
+ return false;
}
if (prop == NULL) {
PointerRNA tmp_ptr;
@@ -907,7 +911,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
BKE_reportf(reports, RPT_ERROR,
"Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
idname, fcu->rna_path);
- return 0;
+ return false;
}
else {
/* property found, so overwrite 'ptr' to make later code easier */
@@ -956,18 +960,18 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
/* only return success if keyframe added */
if (insert_mode)
- return 1;
+ return true;
}
else {
/* just insert keyframe */
insert_vert_fcurve(fcu, cfra, curval, flag);
/* return success */
- return 1;
+ return true;
}
/* failed */
- return 0;
+ return false;
}
/* Main Keyframing API call:
@@ -1284,10 +1288,10 @@ static int modify_key_op_poll(bContext *C)
/* if no area or active scene */
if (ELEM(NULL, sa, scene))
- return 0;
+ return false;
/* should be fine */
- return 1;
+ return true;
}
/* Insert Key Operator ------------------------ */
@@ -1402,12 +1406,12 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UN
uiLayout *layout;
/* call the menu, which will call this operator again, hence the canceled */
- pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
else {
/* just call the exec() on the active keyingset */
@@ -1696,7 +1700,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
short flag = 0;
@@ -1704,36 +1708,38 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
flag = ANIM_get_keyframing_flags(scene, 1);
/* try to insert keyframe using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
- }
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, flag);
-
- MEM_freeN(path);
- }
- else if (ptr.type == &RNA_NlaStrip) {
- /* handle special vars for NLA-strips */
+ if (ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
NlaStrip *strip = (NlaStrip *)ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), flag);
+ FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
- success += insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
}
else {
- BKE_report(op->reports, RPT_WARNING,
- "Failed to resolve path to property, try manually specifying this using a Keying Set instead");
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, flag);
+
+ MEM_freeN(path);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING,
+ "Failed to resolve path to property, "
+ "try manually specifying this using a Keying Set instead");
+ }
}
}
else {
@@ -1751,7 +1757,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
- uiContextAnimUpdate(C);
+ UI_context_update_anim_flag(C);
/* send notifiers that keyframes have been changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
@@ -1788,32 +1794,62 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
+ if (ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
+ ID *id = ptr.id.data;
+ NlaStrip *strip = (NlaStrip *)ptr.data;
+ FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
+
+ BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
+
+ if (BKE_fcurve_is_protected(fcu)) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
+ strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2);
+ }
+ else {
+ /* remove the keyframe directly
+ * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
+ * and delete_keyframe() expects the FCurve to be part of an action
+ */
+ bool found = false;
+ int i;
- if (length) index = 0;
- else length = 1;
+ /* try to find index of beztriple to get rid of */
+ i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
+ if (found) {
+ /* delete the key at the index (will sanity check + do recalc afterwards) */
+ delete_fcurve_key(fcu, i, 1);
+ success = true;
+ }
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, 0);
+ }
+ else {
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
- MEM_freeN(path);
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
+ MEM_freeN(path);
+ }
+ else if (G.debug & G_DEBUG)
+ printf("Button Delete-Key: no path to property\n");
}
- else if (G.debug & G_DEBUG)
- printf("Button Delete-Key: no path to property\n");
}
else if (G.debug & G_DEBUG) {
printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop);
@@ -1822,7 +1858,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
- uiContextAnimUpdate(C);
+ UI_context_update_anim_flag(C);
/* send notifiers that keyframes have been changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
@@ -1858,28 +1894,22 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
PropertyRNA *prop = NULL;
char *path;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, 0);
+ success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
@@ -1892,7 +1922,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
- uiContextAnimUpdate(C);
+ UI_context_update_anim_flag(C);
/* send notifiers that keyframes have been changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
@@ -1922,17 +1952,17 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot)
/* ******************************************* */
/* AUTO KEYFRAME */
-int autokeyframe_cfra_can_key(Scene *scene, ID *id)
+bool autokeyframe_cfra_can_key(Scene *scene, ID *id)
{
float cfra = (float)CFRA; // XXX for now, this will do
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_ON(scene) == 0)
- return 0;
+ return false;
if (IS_AUTOKEY_MODE(scene, NORMAL)) {
/* can insert anytime we like... */
- return 1;
+ return true;
}
else { /* REPLACE */
/* for whole block - only key if there's a keyframe on that frame already
@@ -1952,7 +1982,7 @@ bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter)
{
/* quick sanity check */
if (ELEM(NULL, fcu, fcu->bezt))
- return 0;
+ return false;
/* we either include all regardless of muting, or only non-muted */
if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) {
@@ -1965,11 +1995,11 @@ bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter)
if (replace) {
/* sanity check: 'i' may in rare cases exceed arraylen */
if ((i >= 0) && (i < fcu->totvert))
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
/* Checks whether an Action has a keyframe for a given frame
@@ -1981,11 +2011,11 @@ static bool action_frame_has_keyframe(bAction *act, float frame, short filter)
/* can only find if there is data */
if (act == NULL)
- return 0;
+ return false;
/* if only check non-muted, check if muted */
if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
- return 0;
+ return false;
/* loop over F-Curves, using binary-search to try to find matches
* - this assumes that keyframes are only beztriples
@@ -1994,12 +2024,12 @@ static bool action_frame_has_keyframe(bAction *act, float frame, short filter)
/* only check if there are keyframes (currently only of type BezTriple) */
if (fcu->bezt && fcu->totvert) {
if (fcurve_frame_has_keyframe(fcu, frame, filter))
- return 1;
+ return true;
}
}
/* nothing found */
- return 0;
+ return false;
}
/* Checks whether an Object has a keyframe for a given frame */
@@ -2007,12 +2037,18 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
{
/* error checking */
if (ob == NULL)
- return 0;
+ return false;
/* check own animation data - specifically, the action it contains */
if ((ob->adt) && (ob->adt->action)) {
- if (action_frame_has_keyframe(ob->adt->action, frame, filter))
- return 1;
+ /* T41525 - When the active action is a NLA strip being edited,
+ * we need to correct the frame number to "look inside" the
+ * remapped action
+ */
+ float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP);
+
+ if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter))
+ return true;
}
/* try shapekey keyframes (if available, and allowed by filter) */
@@ -2025,7 +2061,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
/* 1. test for relative (with keyframes) */
if (id_frame_has_keyframe((ID *)key, frame, filter))
- return 1;
+ return true;
/* 2. test for time */
/* TODO... yet to be implemented (this feature may evolve before then anyway) */
@@ -2039,7 +2075,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
/* we only retrieve the active material... */
if (id_frame_has_keyframe((ID *)ma, frame, filter))
- return 1;
+ return true;
}
else {
int a;
@@ -2049,13 +2085,13 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
Material *ma = give_current_material(ob, a + 1);
if (id_frame_has_keyframe((ID *)ma, frame, filter))
- return 1;
+ return true;
}
}
}
/* nothing found */
- return 0;
+ return false;
}
/* --------------- API ------------------- */
@@ -2065,7 +2101,7 @@ bool id_frame_has_keyframe(ID *id, float frame, short filter)
{
/* sanity checks */
if (id == NULL)
- return 0;
+ return false;
/* perform special checks for 'macro' types */
switch (GS(id->name)) {
@@ -2089,7 +2125,7 @@ bool id_frame_has_keyframe(ID *id, float frame, short filter)
/* no keyframe found */
- return 0;
+ return false;
}
/* ************************************************** */
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index ad2db0d9c66..4b9a629183e 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -127,7 +127,7 @@ static int add_default_keyingset_exec(bContext *C, wmOperator *UNUSED(op))
/* call the API func, and set the active keyingset index */
BKE_keyingset_add(&scene->keyingsets, NULL, NULL, flag, keyingflag);
- scene->active_keyingset = BLI_countlist(&scene->keyingsets);
+ scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
/* send notifiers */
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
@@ -216,7 +216,7 @@ static int add_empty_ks_path_exec(bContext *C, wmOperator *op)
/* don't use the API method for this, since that checks on values... */
ksp = MEM_callocN(sizeof(KS_Path), "KeyingSetPath Empty");
BLI_addtail(&ks->paths, ksp);
- ks->active_path = BLI_countlist(&ks->paths);
+ ks->active_path = BLI_listbase_count(&ks->paths);
ksp->groupmode = KSP_GROUP_KSNAME; // XXX?
ksp->idtype = ID_OB;
@@ -316,7 +316,7 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
/* call the API func, and set the active keyingset index */
ks = BKE_keyingset_add(&scene->keyingsets, "ButtonKeyingSet", "Button Keying Set", flag, keyingflag);
- scene->active_keyingset = BLI_countlist(&scene->keyingsets);
+ scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
}
else if (scene->active_keyingset < 0) {
BKE_report(op->reports, RPT_ERROR, "Cannot add property to built in keying set");
@@ -327,7 +327,7 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
}
/* try to add to keyingset using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* check if property is able to be added */
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
@@ -347,7 +347,7 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
/* add path to this setting */
BKE_keyingset_add_path(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME);
- ks->active_path = BLI_countlist(&ks->paths);
+ ks->active_path = BLI_listbase_count(&ks->paths);
success = 1;
/* free the temp path created */
@@ -413,7 +413,7 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
}
/* try to add to keyingset using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -472,12 +472,12 @@ static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, const wmEve
uiLayout *layout;
/* call the menu, which will call this operator again, hence the canceled */
- pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
static int keyingset_active_menu_exec(bContext *C, wmOperator *op)
@@ -556,7 +556,7 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[]
/* loop over KeyingSets checking names */
for (ks = first; ks; ks = ks->next) {
- if (strcmp(name, ks->idname) == 0)
+ if (STREQ(name, ks->idname))
return ks;
}
@@ -603,7 +603,7 @@ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
ksn = ks->next;
/* remove if matching typeinfo name */
- if (strcmp(ks->typeinfo, ksi->idname) == 0) {
+ if (STREQ(ks->typeinfo, ksi->idname)) {
Scene *scene;
BKE_keyingset_free(ks);
BLI_remlink(&builtin_keyingsets, ks);
@@ -914,6 +914,37 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
return 0;
}
+/* Determine which keying flags apply based on the override flags */
+static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags)
+{
+ short result = 0;
+
+ /* The logic for whether a keying flag applies is as follows:
+ * - If the flag in question is set in "overrides", that means that the
+ * status of that flag in "own_flags" is used
+ * - If however the flag isn't set, then its value in "base_flags" is used
+ * instead (i.e. no override)
+ */
+#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \
+ if (overrides & kflag) { \
+ result |= (own_flags & kflag); \
+ } \
+ else { \
+ result |= (base_flags & kflag); \
+ }
+
+ /* Apply the flags one by one...
+ * (See rna_def_common_keying_flags() for the supported flags)
+ */
+ APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED)
+ APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX)
+ APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_XYZ2RGB)
+
+#undef APPLY_KEYINGFLAG_OVERRIDE
+
+ return result;
+}
+
/* Given a KeyingSet and context info (if required), modify keyframes for the channels specified
* by the KeyingSet. This takes into account many of the different combinations of using KeyingSets.
* Returns the number of channels that keyframes were added to
@@ -923,7 +954,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
Scene *scene = CTX_data_scene(C);
ReportList *reports = CTX_wm_reports(C);
KS_Path *ksp;
- int kflag = 0, success = 0;
+ const short base_kflags = ANIM_get_keyframing_flags(scene, 1);
+ short kflag = 0, success = 0;
const char *groupname = NULL;
/* sanity checks */
@@ -932,11 +964,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
/* get flags to use */
if (mode == MODIFYKEY_MODE_INSERT) {
- /* use KeyingSet's flags as base */
- kflag = ks->keyingflag;
-
- /* supplement with info from the context */
- kflag |= ANIM_get_keyframing_flags(scene, 1);
+ /* use context settings as base */
+ kflag = keyingset_apply_keying_flags(base_kflags, ks->keyingoverride, ks->keyingflag);
}
else if (mode == MODIFYKEY_MODE_DELETE)
kflag = 0;
@@ -962,8 +991,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
continue;
}
- /* since keying settings can be defined on the paths too, extend the path before using it */
- kflag2 = (kflag | ksp->keyingflag);
+ /* since keying settings can be defined on the paths too, apply the settings for this path first */
+ kflag2 = keyingset_apply_keying_flags(kflag, ksp->keyingoverride, ksp->keyingflag);
/* get pointer to name of group to add channels to */
if (ksp->groupmode == KSP_GROUP_NONE)
diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h
index 21e85b6fe89..aa56f847f00 100644
--- a/source/blender/editors/armature/BIF_retarget.h
+++ b/source/blender/editors/armature/BIF_retarget.h
@@ -40,7 +40,6 @@ struct bContext;
struct EditBone;
-struct RigJoint;
struct RigGraph;
struct RigNode;
struct RigArc;
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 9aa17f1e503..1ed70b3cd98 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -20,14 +20,15 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
- ../../gpu
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -74,4 +75,6 @@ if(WITH_OPENNL)
)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_armature "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript
index c68045c9398..9c3959ecb5b 100644
--- a/source/blender/editors/armature/SConscript
+++ b/source/blender/editors/armature/SConscript
@@ -31,20 +31,22 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/opennl/extern',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
- '../../gpu',
'../../windowmanager',
]
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index eba1bc4d78d..59453f0ac71 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -43,6 +43,7 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
+#include "BKE_deform.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -89,7 +90,7 @@ EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length,
bArmature *arm = obedit_arm->data;
EditBone *bone;
- ED_armature_deselect_all(obedit_arm, 0);
+ ED_armature_deselect_all(obedit_arm);
/* Create a bone */
bone = ED_armature_edit_bone_add(arm, "Bone");
@@ -144,7 +145,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
to_root = 1;
}
- ED_armature_deselect_all(obedit, 0);
+ ED_armature_deselect_all(obedit);
/* we re-use code for mirror editing... */
flipbone = NULL;
@@ -270,7 +271,7 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
if (name) {
for (eBone = edbo->first; eBone; eBone = eBone->next) {
- if (!strcmp(name, eBone->name))
+ if (STREQ(name, eBone->name))
return eBone;
}
}
@@ -282,12 +283,8 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
* */
void preEditBoneDuplicate(ListBase *editbones)
{
- EditBone *eBone;
-
/* clear temp */
- for (eBone = editbones->first; eBone; eBone = eBone->next) {
- eBone->temp = NULL;
- }
+ ED_armature_ebone_listbase_temp_clear(editbones);
}
/*
@@ -311,7 +308,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
/* does this constraint have a subtarget in
* this armature?
*/
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -327,8 +324,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
* so, update the constraint to point at the
* duplicate of the old subtarget.
*/
- if (oldtarget->temp) {
- newtarget = (EditBone *) oldtarget->temp;
+ if (oldtarget->temp.ebone) {
+ newtarget = oldtarget->temp.ebone;
BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
}
}
@@ -357,8 +354,8 @@ EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase
/* Copy data from old bone to new bone */
memcpy(eBone, curBone, sizeof(EditBone));
- curBone->temp = eBone;
- eBone->temp = curBone;
+ curBone->temp.ebone = eBone;
+ eBone->temp.ebone = curBone;
if (name != NULL) {
BLI_strncpy(eBone->name, name, sizeof(eBone->name));
@@ -398,13 +395,11 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb
return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
}
-/* previously adduplicate_armature */
static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
bArmature *arm;
- EditBone *eBone = NULL;
- EditBone *curBone;
- EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */
Object *obedit = CTX_data_edit_object(C);
arm = obedit->data;
@@ -419,77 +414,80 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (eBone)
- eBone->flag |= BONE_SELECTED;
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_get_mirrored(arm->edbo, ebone_iter);
+ if (ebone) {
+ ebone->flag |= BONE_SELECTED;
}
}
}
}
- /* Find the selected bones and duplicate them as needed */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
-
- eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
-
- if (!firstDup)
- firstDup = eBone;
+ /* Find the selected bones and duplicate them as needed */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+ ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
}
}
}
- /* Run though the list and fix the pointers */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = (EditBone *) curBone->temp;
-
- if (!curBone->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- eBone->parent = NULL;
- }
- else if (curBone->parent->temp) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
- */
- eBone->parent = (EditBone *)curBone->parent->temp;
- }
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- eBone->parent = (EditBone *) curBone->parent;
- eBone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ if (!ebone_iter->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ }
+ else if (ebone_iter->parent->temp.ebone) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ ebone->parent = ebone_iter->parent->temp.ebone;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
*/
- updateDuplicateSubtarget(eBone, arm->edbo, obedit);
+ ebone->parent = (EditBone *) ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
}
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
}
}
/* correct the active bone */
- if (arm->act_edbone) {
- eBone = arm->act_edbone;
- if (eBone->temp)
- arm->act_edbone = eBone->temp;
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
}
- /* Deselect the old bones and select the new ones */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone))
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
ED_armature_validate_active(arm);
@@ -515,6 +513,214 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/**
+ * near duplicate of #armature_duplicate_selected_exec,
+ * except for parenting part (keep in sync)
+ */
+static int armature_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ bArmature *arm;
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */
+
+ Object *obedit = CTX_data_edit_object(C);
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const int axis = 0;
+
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ char name_flip[MAX_VGROUP_NAME];
+
+ BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+
+ if (STREQ(name_flip, ebone_iter->name)) {
+ /* if the name matches, we don't have the potential to be mirrored, just skip */
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone = ED_armature_bone_find_name(arm->edbo, name_flip);
+
+ if (ebone) {
+ if ((ebone->flag & BONE_SELECTED) == 0) {
+ /* simple case, we're selected, the other bone isn't! */
+ ebone_iter->temp.ebone = ebone;
+ }
+ else {
+ /* complicated - choose which direction to copy */
+ float axis_delta;
+
+ axis_delta = ebone->head[axis] - ebone_iter->head[axis];
+ if (axis_delta == 0.0f) {
+ axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
+ }
+
+ if (axis_delta == 0.0f) {
+ /* both mirrored bones exist and point to eachother and overlap exactly.
+ *
+ * in this case theres no well defined solution, so de-select both and skip.
+ */
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone_src, *ebone_dst;
+ if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
+ ebone_src = ebone;
+ ebone_dst = ebone_iter;
+ }
+ else {
+ ebone_src = ebone_iter;
+ ebone_dst = ebone;
+ }
+
+ ebone_src->temp.ebone = ebone_dst;
+ ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Find the selected bones and duplicate them as needed, with mirrored name */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED) &&
+ /* will be set if the mirror bone already exists (no need to make a new one) */
+ (ebone_iter->temp.ebone == NULL))
+ {
+ char name_flip[MAX_VGROUP_NAME];
+
+ BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+
+ /* bones must have a side-suffix */
+ if (!STREQ(name_flip, ebone_iter->name)) {
+ EditBone *ebone;
+
+ ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
+ }
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->temp.ebone) {
+ /* copy all flags except for ... */
+ const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ /* copy flags incase bone is pre-existing data */
+ ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
+
+ if (ebone_iter->parent == NULL) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ else {
+ /* the parent may have been duplicated, if not lookup the mirror parent */
+ EditBone *ebone_parent =
+ (ebone_iter->parent->temp.ebone ?
+ ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent));
+
+ if (ebone_parent == NULL) {
+ /* If the mirror lookup failed, (but the current bone has a parent)
+ * then we can assume the parent has no L/R but is a center bone.
+ * So just use the same parent for both.
+ */
+ ebone_parent = ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+
+ ebone->parent = ebone_parent;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ }
+ }
+
+ transform_armature_mirror_update(obedit);
+
+ /* Selected bones now have their 'temp' pointer set,
+ * so we don't need this anymore */
+
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ /* New bones will be selected, but some of the bones may already exist */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ EditBone *ebone = ebone_iter->temp.ebone;
+ if (ebone && EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
+
+ ED_armature_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+/* following conventions from #MESH_OT_symmetrize */
+void ARMATURE_OT_symmetrize(wmOperatorType *ot)
+{
+ /* subset of 'symmetrize_direction_items' */
+ static EnumPropertyItem arm_symmetrize_direction_items[] = {
+ {-1, "NEGATIVE_X", 0, "-X to +X", ""},
+ {+1, "POSITIVE_X", 0, "+X to -X", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "ARMATURE_OT_symmetrize";
+ ot->description = "Enforce symmetry, make copies of the selection or use existing";
+
+ /* api callbacks */
+ ot->exec = armature_symmetrize_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(
+ ot->srna, "direction", arm_symmetrize_direction_items, -1,
+ "Direction", "Which sides to copy from and to (when both are selected)");
+}
+
/* ------------------------------------------ */
/* previously extrude_armature */
@@ -704,7 +910,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
mul_m3_m3m3(totmat, obmat, viewmat);
invert_m3_m3(imat, totmat);
- ED_armature_deselect_all(obedit, 0);
+ ED_armature_deselect_all(obedit);
/* Create a bone */
bone = ED_armature_edit_bone_add(obedit->data, name);
@@ -830,7 +1036,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* Properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 1e4d9bac246..5a0e70dc5dd 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -38,8 +38,11 @@
#include "MEM_guardedalloc.h"
+#include "BLT_translation.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -70,7 +73,7 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4])
/* Put the armature into editmode */
ED_armature_to_edit(arm);
- /* Transform the bones*/
+ /* Transform the bones */
ED_armature_transform_bones(arm, mat);
/* Turn the list into an armature */
@@ -100,7 +103,7 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4])
mul_m4_v3(mat, ebone->head);
mul_m4_v3(mat, ebone->tail);
- /* apply the transfiormed roll back */
+ /* apply the transformed roll back */
mat3_to_vec_roll(tmat, NULL, &ebone->roll);
ebone->rad_head *= scale;
@@ -190,7 +193,7 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente
/* Adjust object location for new centerpoint */
if (centermode && obedit == NULL) {
- mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
+ mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
add_v3_v3(ob->loc, cent);
}
}
@@ -236,28 +239,49 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool
return roll;
}
-
+/* note, ranges arithmatic is used below */
typedef enum eCalcRollTypes {
- CALC_ROLL_X = 0,
- CALC_ROLL_Y = 1,
- CALC_ROLL_Z = 2,
-
- CALC_ROLL_TAN_X = 3,
- CALC_ROLL_TAN_Z = 4,
-
- CALC_ROLL_ACTIVE = 5,
- CALC_ROLL_VIEW = 6,
- CALC_ROLL_CURSOR = 7,
+ /* pos */
+ CALC_ROLL_POS_X = 0,
+ CALC_ROLL_POS_Y,
+ CALC_ROLL_POS_Z,
+
+ CALC_ROLL_TAN_POS_X,
+ CALC_ROLL_TAN_POS_Z,
+
+ /* neg */
+ CALC_ROLL_NEG_X,
+ CALC_ROLL_NEG_Y,
+ CALC_ROLL_NEG_Z,
+
+ CALC_ROLL_TAN_NEG_X,
+ CALC_ROLL_TAN_NEG_Z,
+
+ /* no sign */
+ CALC_ROLL_ACTIVE,
+ CALC_ROLL_VIEW,
+ CALC_ROLL_CURSOR,
} eCalcRollTypes;
static EnumPropertyItem prop_calc_roll_types[] = {
- {CALC_ROLL_TAN_X, "X", 0, "Local X Tangent", ""},
- {CALC_ROLL_TAN_Z, "Z", 0, "Local Z Tangent", ""},
+ {0, "", 0, N_("Positive"), ""},
+ {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
+ {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
+
+ {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
+ {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
+ {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
- {CALC_ROLL_X, "GLOBAL_X", 0, "Global X Axis", ""},
- {CALC_ROLL_Y, "GLOBAL_Y", 0, "Global Y Axis", ""},
- {CALC_ROLL_Z, "GLOBAL_Z", 0, "Global Z Axis", ""},
+ {0, "", 0, N_("Negative"), ""},
+ {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
+ {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
+
+ {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
+ {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
+ {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
+
+ {0, "", 0, N_("Other"), ""},
{CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
{CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
{CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
@@ -268,15 +292,22 @@ static EnumPropertyItem prop_calc_roll_types[] = {
static int armature_calc_roll_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
- const short type = RNA_enum_get(op->ptr, "type");
+ eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
- const bool axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
+ /* axis_flip when matching the active bone never makes sense */
+ bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
+ (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
float imat[3][3];
bArmature *arm = ob->data;
EditBone *ebone;
+ if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
+ type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
+ axis_flip = true;
+ }
+
copy_m3_m4(imat, ob->obmat);
invert_m3(imat);
@@ -296,11 +327,13 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
float cursor_rel[3];
sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
if (axis_flip) negate_v3(cursor_rel);
- ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+ if (normalize_v3(cursor_rel) != 0.0f) {
+ ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+ }
}
}
}
- else if (ELEM(type, CALC_ROLL_TAN_X, CALC_ROLL_TAN_Z)) {
+ else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (ebone->parent) {
bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
@@ -321,7 +354,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
normalize_v3(dir_b);
- if (type == CALC_ROLL_TAN_Z) {
+ if (type == CALC_ROLL_TAN_POS_Z) {
cross_v3_v3v3(vec, dir_a, dir_b);
}
else {
@@ -372,7 +405,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
copy_v3_v3(vec, mat[2]);
}
else { /* Axis */
- assert(type >= 0 && type <= 5);
+ assert(type <= 5);
if (type < 3) vec[type] = 1.0f;
else vec[type - 2] = -1.0f;
mul_m3_v3(imat, vec);
@@ -421,7 +454,7 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_X, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
}
@@ -546,6 +579,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
+ EditBone *newbone = NULL;
int count;
/* sanity checks */
@@ -567,7 +601,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
* 2) between the two joints (order is dependent on active-bone/hierarchy)
* 3+) error (a smarter method involving finding chains needs to be worked out
*/
- count = BLI_countlist(&points);
+ count = BLI_listbase_count(&points);
if (count == 0) {
BKE_report(op->reports, RPT_ERROR, "No joints selected");
@@ -578,94 +612,97 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
float curs[3];
/* Get Points - selected joint */
- ebp = (EditBonePoint *)points.first;
+ ebp = points.first;
/* Get points - cursor (tail) */
invert_m4_m4(obedit->imat, obedit->obmat);
mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
/* Create a bone */
- /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
+ newbone = add_points_bone(obedit, ebp->vec, curs);
}
else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
+ EditBonePoint *ebp_a, *ebp_b;
float head[3], tail[3];
short headtail = 0;
/* check that the points don't belong to the same bone */
- ebp = (EditBonePoint *)points.first;
- ebp2 = ebp->next;
+ ebp_a = (EditBonePoint *)points.first;
+ ebp_b = ebp_a->next;
- if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
- if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
+ if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
+ ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
+ {
BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
/* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
-
- /* get distances */
- sub_v3_v3v3(vecA, ebp->vec, curs);
- sub_v3_v3v3(vecB, ebp2->vec, curs);
- distA = len_v3(vecA);
- distB = len_v3(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (distA < distB) ? 2 : 1;
+ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
+ /* use active, nice predictable */
+ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
+ headtail = 1;
+ }
+ else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
+ headtail = 2;
+ }
+ else {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float dist_sq_a, dist_sq_b;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
+
+ /* get distances */
+ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
+ dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
+ }
}
- else if (ebp->head_owner) {
+ else if (ebp_a->head_owner) {
headtail = 1;
}
- else if (ebp2->head_owner) {
+ else if (ebp_b->head_owner) {
headtail = 2;
}
/* assign head/tail combinations */
if (headtail == 2) {
- copy_v3_v3(head, ebp->vec);
- copy_v3_v3(tail, ebp2->vec);
+ copy_v3_v3(head, ebp_a->vec);
+ copy_v3_v3(tail, ebp_b->vec);
}
else if (headtail == 1) {
- copy_v3_v3(head, ebp2->vec);
- copy_v3_v3(tail, ebp->vec);
+ copy_v3_v3(head, ebp_b->vec);
+ copy_v3_v3(tail, ebp_a->vec);
}
/* add new bone and parent it to the appropriate end */
if (headtail) {
- EditBone *newbone = add_points_bone(obedit, head, tail);
+ newbone = add_points_bone(obedit, head, tail);
/* do parenting (will need to set connected flag too) */
if (headtail == 2) {
/* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent = ebp->tail_owner;
+ if (ebp_a->tail_owner)
+ newbone->parent = ebp_a->tail_owner;
else
- newbone->parent = ebp->head_owner;
+ newbone->parent = ebp_a->head_owner;
}
else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent = ebp2->tail_owner;
+ /* ebp_b tail or head - tail gets priority */
+ if (ebp_b->tail_owner)
+ newbone->parent = ebp_b->tail_owner;
else
- newbone->parent = ebp2->head_owner;
+ newbone->parent = ebp_b->head_owner;
}
/* don't set for bone connecting two head points of bones */
- if (ebp->tail_owner || ebp2->tail_owner) {
+ if (ebp_a->tail_owner || ebp_b->tail_owner) {
newbone->flag |= BONE_CONNECTED;
}
}
@@ -676,6 +713,12 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
+
+ if (newbone) {
+ ED_armature_deselect_all(obedit);
+ arm->act_edbone = newbone;
+ newbone->flag |= BONE_TIPSEL;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
@@ -945,9 +988,7 @@ static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
/* only if selected and editable */
if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
/* swap head and tail coordinates */
- SWAP(float, ebo->head[0], ebo->tail[0]);
- SWAP(float, ebo->head[1], ebo->tail[1]);
- SWAP(float, ebo->head[2], ebo->tail[2]);
+ swap_v3_v3(ebo->head, ebo->tail);
/* do parent swapping:
* - use 'child' as new parent
@@ -1191,13 +1232,21 @@ void ARMATURE_OT_split(wmOperatorType *ot)
/* ********************************* Delete ******************************* */
+static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
+{
+ bArmature *arm = arm_p;
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
+}
+
/* previously delete_armature */
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
bArmature *arm;
EditBone *curBone, *ebone_next;
- bConstraint *con;
Object *obedit = CTX_data_edit_object(C); // XXX get from context
bool changed = false;
arm = obedit->data;
@@ -1208,48 +1257,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
armature_select_mirrored(arm);
- /* First erase any associated pose channel */
- if (obedit->pose) {
- bPoseChannel *pchan, *pchan_next;
- for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
- pchan_next = pchan->next;
- curBone = ED_armature_bone_find_name(arm->edbo, pchan->name);
-
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(obedit->pose);
- BLI_freelinkN(&obedit->pose->chanbase, pchan);
- }
- else {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == obedit) {
- if (ct->subtarget[0]) {
- curBone = ED_armature_bone_find_name(arm->edbo, ct->subtarget);
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0] = 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
-
+ BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+
for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
ebone_next = curBone->next;
if (arm->layer & curBone->layer) {
@@ -1287,6 +1296,170 @@ void ARMATURE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
+{
+ bArmature *arm = arm_p;
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_DONE));
+}
+
+static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *ebone, *ebone_next;
+ Object *obedit = CTX_data_edit_object(C);
+ bool changed = false;
+
+ /* store for mirror */
+ GHash *ebone_flag_orig = NULL;
+ int ebone_num = 0;
+
+ arm = obedit->data;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->temp.p = NULL;
+ ebone->flag &= ~BONE_DONE;
+ ebone_num++;
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ GHashIterator gh_iter;
+
+ ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } val = {0};
+ val.flag = ebone->flag;
+ BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
+ }
+
+ armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ GHASH_ITER (gh_iter, ebone_flag_orig) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
+ ebone = BLI_ghashIterator_getKey(&gh_iter);
+ val_p->flag = ebone->flag & ~val_p->flag;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->flag & BONE_CONNECTED) {
+ if (ebone->parent->temp.ebone == ebone->parent) {
+ /* ignore */
+ }
+ else if (ebone->parent->temp.ebone) {
+ /* set ignored */
+ ebone->parent->temp.ebone = ebone->parent;
+ }
+ else {
+ /* set child */
+ ebone->parent->temp.ebone = ebone;
+ }
+ }
+ }
+
+ /* cleanup multiple used bones */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.ebone == ebone) {
+ ebone->temp.ebone = NULL;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* break connections for unseen bones */
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
+ {
+ ebone->temp.ebone = NULL;
+ }
+
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
+ {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->parent->temp.ebone = NULL;
+ }
+
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ if (ebone->parent &&
+ (ebone->parent->temp.ebone == ebone))
+ {
+ ebone->flag |= BONE_DONE;
+ }
+ }
+
+ BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
+
+ if (ebone->flag & BONE_DONE) {
+ copy_v3_v3(ebone->parent->tail, ebone->tail);
+ ebone->parent->rad_tail = ebone->rad_tail;
+
+ ED_armature_edit_bone_remove(arm, ebone);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent &&
+ ebone->parent->temp.ebone &&
+ (ebone->flag & BONE_CONNECTED) == 0)
+ {
+ ebone->flag |= BONE_CONNECTED;
+ ebone->rad_head = ebone->parent->rad_head;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
+ if (val_p && val_p->flag) {
+ ebone->flag &= ~val_p->flag;
+ }
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ }
+
+ if (!changed) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_dissolve(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dissolve Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_dissolve";
+ ot->description = "Dissolve selected bones from the armature";
+
+ /* api callbacks */
+ ot->exec = armature_dissolve_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+
/* ********************************* Show/Hide ******************************* */
static int armature_hide_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 6d616384b9a..2968851f2eb 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -71,7 +71,9 @@ void ARMATURE_OT_select_similar(struct wmOperatorType *ot);
void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
void ARMATURE_OT_delete(struct wmOperatorType *ot);
+void ARMATURE_OT_dissolve(struct wmOperatorType *ot);
void ARMATURE_OT_duplicate(struct wmOperatorType *ot);
+void ARMATURE_OT_symmetrize(struct wmOperatorType *ot);
void ARMATURE_OT_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_hide(struct wmOperatorType *ot);
void ARMATURE_OT_reveal(struct wmOperatorType *ot);
@@ -215,7 +217,7 @@ void POSE_OT_propagate(struct wmOperatorType *ot);
*/
EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct EditBone *parent, struct Bone *actBone);
-void BIF_sk_selectStroke(struct bContext *C, const int mval[2], short extend);
+bool BIF_sk_selectStroke(struct bContext *C, const int mval[2], const bool extend);
/* duplicate method */
void preEditBoneDuplicate(struct ListBase *editbones);
@@ -233,6 +235,7 @@ EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
void armature_tag_select_mirrored(struct bArmature *arm);
+void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 9afc45955bd..56dbdb3a639 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -38,7 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
@@ -104,7 +104,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char *
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
@@ -141,7 +141,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
char oldname[MAXBONENAME];
/* names better differ! */
- if (strncmp(oldnamep, newnamep, MAXBONENAME)) {
+ if (!STREQLEN(oldnamep, newnamep, MAXBONENAME)) {
/* we alter newname string... so make copy */
BLI_strncpy(newname, newnamep, MAXBONENAME);
@@ -219,7 +219,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
if (ob->parent && (ob->parent->data == arm)) {
if (ob->partype == PARBONE) {
/* bone name in object */
- if (!strcmp(ob->parsubstr, oldname))
+ if (STREQ(ob->parsubstr, oldname))
BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
}
}
@@ -267,9 +267,10 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
/* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
* other ID-blocks may have drivers referring to this bone [#29822]
*/
+ // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
{
- BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
+ BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname);
}
/* correct view locking */
@@ -284,7 +285,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->ob_centre && v3d->ob_centre->data == arm) {
- if (!strcmp(v3d->ob_centre_bone, oldname)) {
+ if (STREQ(v3d->ob_centre_bone, oldname)) {
BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
}
}
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index b7e38546ca2..e7f036f6911 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -28,8 +28,6 @@
* \ingroup edarmature
*/
-#include "BLI_math.h"
-
#include "RNA_access.h"
#include "WM_api.h"
@@ -67,7 +65,9 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
WM_operatortype_append(ARMATURE_OT_delete);
+ WM_operatortype_append(ARMATURE_OT_dissolve);
WM_operatortype_append(ARMATURE_OT_duplicate);
+ WM_operatortype_append(ARMATURE_OT_symmetrize);
WM_operatortype_append(ARMATURE_OT_extrude);
WM_operatortype_append(ARMATURE_OT_hide);
WM_operatortype_append(ARMATURE_OT_reveal);
@@ -267,8 +267,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_forked", EKEY, KM_PRESS, KM_SHIFT, 0);
@@ -277,7 +278,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_split", YKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, 0, 0);
/* set flags */
WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
@@ -368,7 +369,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "POSE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "POSE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_select_mirror", FKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "POSE_OT_select_mirror", FKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
WM_keymap_add_item(keymap, "POSE_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_add_item(keymap, "POSE_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
@@ -413,5 +414,6 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
/* menus */
WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_propagate", PKEY, KM_PRESS, KM_ALT, 0);
}
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 75fa4a5433f..1c342657eec 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -29,20 +29,26 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -72,7 +78,7 @@ static void joined_armature_fix_links_constraints(
bConstraint *con;
for (con = lb->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -98,33 +104,122 @@ static void joined_armature_fix_links_constraints(
/* action constraint? (pose constraints only) */
if (con->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = con->data; // XXX old animation system
- bAction *act;
- bActionChannel *achan;
+ bActionConstraint *data = con->data;
if (data->act) {
- act = data->act;
+ BKE_action_fix_paths_rename(&tarArm->id, data->act, "pose.bones[",
+ pchan->name, curbone->name, 0, 0, false);
+ }
+ }
+
+ }
+}
- for (achan = act->chanbase.first; achan; achan = achan->next) {
- if (STREQ(achan->name, pchan->name)) {
- BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
+/* userdata for joined_armature_fix_animdata_cb() */
+typedef struct tJoinArmature_AdtFixData {
+ Object *srcArm;
+ Object *tarArm;
+
+ GHash *names_map;
+} tJoinArmature_AdtFixData;
+
+/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */
+/* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation
+ * on the rigs being edited already, so it should be safe to skip these.
+ */
+static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data)
+{
+ tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data;
+ ID *src_id = &afd->srcArm->id;
+ ID *dst_id = &afd->tarArm->id;
+
+ GHashIterator gh_iter;
+ FCurve *fcu;
+
+ /* Fix paths - If this is the target object, it will have some "dirty" paths */
+ if (id == src_id) {
+ /* Fix drivers */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ /* skip driver if it doesn't affect the bones */
+ if (strstr(fcu->rna_path, "pose.bones[") == NULL) {
+ continue;
+ }
+
+ // FIXME: this is too crude... it just does everything!
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */
+ if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
+ fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones",
+ old_name, new_name, 0, 0, false);
+
+ /* we don't want to apply a second remapping on this driver now,
+ * so stop trying names, but keep fixing drivers
+ */
+ break;
+ }
+ }
+ }
+ }
+
+
+ /* Driver targets */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ /* Fix driver references to invalid ID's */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ /* change the ID's used... */
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+
+ /* also check on the subtarget...
+ * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
+ */
+ if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) {
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed */
+ if (!STREQ(old_name, new_name)) {
+ if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
+ /* Fix up path */
+ dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "pose.bones",
+ old_name, new_name, 0, 0, false);
+ break; /* no need to try any more names for bone path */
+ }
+ else if (STREQ(dtar->pchan_name, old_name)) {
+ /* Change target bone name */
+ BLI_strncpy(dtar->pchan_name, new_name, sizeof(dtar->pchan_name));
+ break; /* no need to try any more names for bone subtarget */
+ }
+ }
+ }
}
}
}
+ DRIVER_TARGETS_LOOPER_END
}
-
}
}
/* Helper function for armature joining - link fixing */
-static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
+static void joined_armature_fix_links(Main *bmain, Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
{
Object *ob;
bPose *pose;
bPoseChannel *pchant;
/* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* do some object-type specific things */
if (ob->type == OB_ARMATURE) {
pose = ob->pose;
@@ -198,8 +293,17 @@ int join_armature_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
{
if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
+ tJoinArmature_AdtFixData afd = {NULL};
bArmature *curarm = base->object->data;
+ /* we assume that each armature datablock is only used in a single place */
+ BLI_assert(ob->data != base->object->data);
+
+ /* init callback data for fixing up AnimData links later */
+ afd.srcArm = base->object;
+ afd.tarArm = ob;
+ afd.names_map = BLI_ghash_str_new("join_armature_adt_fix");
+
/* Make a list of editbones in current armature */
ED_armature_to_edit(base->object->data);
@@ -219,6 +323,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
/* Get new name */
unique_editbone_name(arm->edbo, curbone->name, NULL);
+ BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name);
/* Transform the bone */
{
@@ -249,7 +354,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
}
/* Fix Constraints and Other Links to this Bone and Armature */
- joined_armature_fix_links(ob, base->object, pchan, curbone);
+ joined_armature_fix_links(bmain, ob, base->object, pchan, curbone);
/* Rename pchan */
BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
@@ -264,6 +369,37 @@ int join_armature_exec(bContext *C, wmOperator *op)
BKE_pose_channels_hash_free(pose);
}
+ /* Fix all the drivers (and animation data) */
+ BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
+ BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
+
+ /* Only copy over animdata now, after all the remapping has been done,
+ * so that we don't have to worry about ambiguities re which armature
+ * a bone came from!
+ */
+ if (base->object->adt) {
+ if (ob->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ ob->adt = BKE_animdata_copy(base->object->adt, false);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(&ob->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ if (curarm->adt) {
+ if (arm->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ arm->adt = BKE_animdata_copy(curarm->adt, false);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(&arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ /* Free the old object data */
ED_base_object_free_and_unlink(bmain, scene, base);
}
}
@@ -299,7 +435,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -337,7 +473,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -412,7 +548,7 @@ static void separate_armature_bones(Object *ob, short sel)
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
- ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
+ ebo->temp.p = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
ebo->flag &= ~BONE_CONNECTED;
}
}
@@ -505,6 +641,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
ED_armature_to_edit(obedit->data);
+ /* parents tips remain selected when connected children are removed. */
+ ED_armature_deselect_all(obedit);
+
BKE_report(op->reports, RPT_INFO, "Separated bones");
/* note, notifier might evolve */
@@ -524,6 +663,7 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
ot->description = "Isolate selected bones into a separate armature";
/* callbacks */
+ ot->invoke = WM_operator_confirm;
ot->exec = separate_armature_exec;
ot->poll = ED_operator_editarmature;
@@ -673,8 +813,8 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
EditBone *actbone = CTX_data_active_bone(C);
- uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
int allchildbones = 0;
CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
@@ -691,9 +831,9 @@ static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const
if (allchildbones)
uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
void ARMATURE_OT_parent_set(wmOperatorType *ot)
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index d85a730c88e..dbbdae280f2 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -54,9 +54,9 @@
#include "armature_intern.h"
-/* utility macros fro storing a temp int in the bone (selection flag) */
-#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (GET_INT_FROM_POINTER((ebone)->temp)))
-#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp = SET_INT_IN_POINTER(val))
+/* utility macros for storing a temp int in the bone (selection flag) */
+#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
+#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
@@ -126,7 +126,7 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
if (sel) {
if (do_nearest) {
if (minsel > buffer[4 * i + 1]) {
- firstSel = bone;
+ firstSel = data;
minsel = buffer[4 * i + 1];
}
}
@@ -138,12 +138,11 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
else {
if (do_nearest) {
if (minunsel > buffer[4 * i + 1]) {
- firstunSel = bone;
+ firstunSel = data;
minunsel = buffer[4 * i + 1];
}
}
- else
- {
+ else {
if (!firstunSel) firstunSel = data;
if (takeNext) return data;
}
@@ -175,7 +174,6 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
rect.xmin = rect.xmax = x;
rect.ymin = rect.ymax = y;
- glInitNames();
hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
if (hits > 0)
@@ -255,7 +253,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
static int armature_select_linked_poll(bContext *C)
{
- return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) );
+ return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
}
void ARMATURE_OT_select_linked(wmOperatorType *ot)
@@ -289,11 +287,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
rcti rect;
unsigned int buffer[MAXPICKBUF];
unsigned int hitresult, besthitresult = BONESEL_NOSEL;
- int i, mindep = 4;
+ int i, mindep = 5;
short hits;
- glInitNames();
-
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
if (ebone_next_act &&
@@ -346,16 +342,16 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
dep = 2;
}
else {
- dep = 2;
+ dep = 1;
}
}
else {
/* bone found */
if (findunsel) {
if ((ebone->flag & BONE_SELECTED) == 0)
- dep = 2;
- else
dep = 3;
+ else
+ dep = 4;
}
else {
dep = 3;
@@ -392,61 +388,14 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
return NULL;
}
-
-
-/* toggle==0: deselect
- * toggle==1: swap (based on test)
- * toggle==2: swap (no test), CURRENTLY UNUSED
- */
-void ED_armature_deselect_all(Object *obedit, int toggle)
+void ED_armature_deselect_all(Object *obedit)
{
bArmature *arm = obedit->data;
- EditBone *eBone;
- int sel = 1;
-
- if (toggle == 1) {
- /* Determine if there are any selected bones
- * and therefore whether we are selecting or deselecting */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- // if (arm->layer & eBone->layer) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- sel = 0;
- break;
- }
- // }
- }
- }
- else {
- sel = toggle;
- }
+ EditBone *ebone;
- /* Set the flags */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (sel == 2) {
- /* invert selection of bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
- else if (sel == 1) {
- /* select bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (eBone->parent)
- eBone->parent->flag |= (BONE_TIPSEL);
- }
- }
- else {
- /* deselect bone */
- eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
-
- ED_armature_sync_selection(arm->edbo);
}
void ED_armature_deselect_all_visible(Object *obedit)
@@ -486,13 +435,16 @@ bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect,
view3d_set_viewcontext(C, &vc);
- BIF_sk_selectStroke(C, mval, extend);
+ if (BIF_sk_selectStroke(C, mval, extend)) {
+ return true;
+ }
nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
if (nearBone) {
- if (!extend && !deselect && !toggle)
- ED_armature_deselect_all(obedit, 0);
+ if (!extend && !deselect && !toggle) {
+ ED_armature_deselect_all(obedit);
+ }
/* by definition the non-root connected bones have no root point drawn,
* so a root selection needs to be delivered to the parent tip */
@@ -733,7 +685,7 @@ static void armature_select_more_less(Object *ob, bool more)
}
}
}
- ebone->temp = NULL;
+ ebone->temp.p = NULL;
}
ED_armature_sync_selection(arm->edbo);
@@ -958,81 +910,84 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", "");
RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
/* ********************* select hierarchy operator ************** */
-/* Get the first available child of an editbone */
-static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
-{
- EditBone *curbone, *chbone = NULL;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- if (curbone->parent == pabone) {
- if (use_visibility) {
- if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
- chbone = curbone;
- }
- }
- else
- chbone = curbone;
- }
- }
-
- return chbone;
-}
-
static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Object *ob;
bArmature *arm;
- EditBone *curbone, *pabone, *chbone;
+ EditBone *ebone_active;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
ob = obedit;
arm = (bArmature *)ob->data;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- /* only work on bone if it is visible and its selection can change */
- if (EBONE_SELECTABLE(arm, curbone)) {
- if (curbone == arm->act_edbone) {
- if (direction == BONE_SELECT_PARENT) {
- if (curbone->parent == NULL) continue;
- else pabone = curbone->parent;
-
- if (EBONE_VISIBLE(arm, pabone)) {
- pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = pabone;
- if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
-
- if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- }
-
+
+ ebone_active = arm->act_edbone;
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (ebone_active->parent) {
+ EditBone *ebone_parent;
+
+ ebone_parent = ebone_active->parent;
+
+ if (EBONE_SELECTABLE(arm, ebone_parent)) {
+ arm->act_edbone = ebone_parent;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
}
- else { // BONE_SELECT_CHILD
- chbone = editbone_get_child(arm, curbone, 1);
- if (chbone == NULL) continue;
-
- if (EBONE_SELECTABLE(arm, chbone)) {
- chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = chbone;
-
- if (!add_to_sel) {
- curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
- if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+ ED_armature_ebone_select_set(ebone_parent, true);
+
+ changed = true;
+ }
+ }
+
+ }
+ else { /* BONE_SELECT_CHILD */
+ EditBone *ebone_iter, *ebone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (EBONE_SELECTABLE(arm, ebone_iter)) {
+ if (ebone_iter->parent == ebone_active) {
+ if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
+ ebone_child = ebone_iter;
+ break;
}
- break;
}
}
}
}
+
+ if (ebone_child) {
+ arm->act_edbone = ebone_child;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
+ }
+ ED_armature_ebone_select_set(ebone_child, true);
+
+ changed = true;
+ }
}
+ if (changed == false) {
+ return OPERATOR_CANCELLED;
+ }
+
ED_armature_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index fbc18e977ce..ea1a94fbba6 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -43,6 +43,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_deform.h"
+#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "BKE_subsurf.h"
#include "BKE_modifier.h"
@@ -52,7 +53,10 @@
#include "armature_intern.h"
-#include "meshlaplacian.h"
+
+#ifdef WITH_OPENNL
+# include "meshlaplacian.h"
+#endif
#if 0
#include "reeb.h"
@@ -117,7 +121,7 @@ static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
*/
if (!(bone->flag & BONE_NO_DEFORM)) {
if (!defgroup_find_name(ob, bone->name)) {
- ED_vgroup_add_name(ob, bone->name);
+ BKE_object_defgroup_add_name(ob, bone->name);
return 1;
}
}
@@ -162,9 +166,15 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
else
segments = 1;
- if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)))
- if (!(defgroup = defgroup_find_name(ob, bone->name)))
- defgroup = ED_vgroup_add_name(ob, bone->name);
+ if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) {
+ if (!(defgroup = defgroup_find_name(ob, bone->name))) {
+ defgroup = BKE_object_defgroup_add_name(ob, bone->name);
+ }
+ else if (defgroup->flag & DG_LOCK_WEIGHT) {
+ /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
+ defgroup = NULL;
+ }
+ }
if (data->list != NULL) {
hgroup = (bDeformGroup ***) &data->list;
@@ -238,7 +248,8 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
}
}
-static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, bool mirror)
+static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par,
+ int heat, const bool mirror)
{
/* This functions implements the automatic computation of vertex group
* weights, either through envelopes or using a heat equilibrium.
@@ -275,7 +286,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if (numbones == 0)
return;
- if (ED_vgroup_data_create(ob->data) == false)
+ if (BKE_object_defgroup_data_create(ob->data) == NULL)
return;
/* create an array of pointer to bones that are skinnable
@@ -418,7 +429,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
MEM_freeN(verts);
}
-void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, bool mirror)
+void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par,
+ const int mode, const bool mirror)
{
/* Lets try to create some vertex groups
* based on the bones of the parent armature.
@@ -426,7 +438,7 @@ void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob,
bArmature *arm = par->data;
if (mode == ARM_GROUPS_NAME) {
- const int defbase_tot = BLI_countlist(&ob->defbase);
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
int defbase_add;
/* Traverse the bone list, trying to create empty vertex
* groups corresponding to the bone.
@@ -439,7 +451,7 @@ void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob,
ED_vgroup_data_clamp_range(ob->data, defbase_tot);
}
}
- else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) {
+ else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
/* Traverse the bone list, trying to create vertex groups
* that are populated with the vertices for which the
* bone is closest.
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 97f69d86aee..61ed7fdc41b 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -276,18 +276,19 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo)
/* helper function for tools to work on mirrored parts.
* it leaves mirrored bones selected then too, which is a good indication of what happened */
-void armature_select_mirrored(bArmature *arm)
+void armature_select_mirrored_ex(bArmature *arm, const int flag)
{
+ BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {
EditBone *curBone, *ebone_mirr;
for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
+ if (curBone->flag & flag) {
ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
if (ebone_mirr)
- ebone_mirr->flag |= BONE_SELECTED;
+ ebone_mirr->flag |= (curBone->flag & flag);
}
}
}
@@ -295,6 +296,11 @@ void armature_select_mirrored(bArmature *arm)
}
+void armature_select_mirrored(bArmature *arm)
+{
+ armature_select_mirrored_ex(arm, BONE_SELECTED);
+}
+
void armature_tag_select_mirrored(bArmature *arm)
{
EditBone *curBone;
@@ -471,48 +477,78 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
return eBoneAct;
}
-/* nasty stuff for converting roll in editbones into bones */
-/* also sets restposition in armature (arm_mat) */
-static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
+/* This function:
+ * - sets local head/tail rest locations using parent bone's arm_mat.
+ * - calls BKE_armature_where_is_bone() which uses parent's transform (arm_mat) to define this bone's transform.
+ * - fixes (converts) EditBone roll into Bone roll.
+ * - calls again BKE_armature_where_is_bone(), since roll fiddling may have changed things for our bone...
+ * Note that order is crucial here, we can only handle child if all its parents in chain have already been handled
+ * (this is ensured by recursive process). */
+static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelist)
{
Bone *curBone;
EditBone *ebone;
- float premat[3][3];
- float postmat[3][3];
- float difmat[3][3];
- float imat[3][3];
-
+
for (curBone = bonelist->first; curBone; curBone = curBone->next) {
- /* sets local matrix and arm_mat (restpos) */
- BKE_armature_where_is_bone(curBone, curBone->parent);
-
+ /* Set bone's local head/tail.
+ * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values
+ * from editbone's matrix (see T46010). */
+ if (curBone->parent) {
+ float parmat_inv[4][4];
+
+ invert_m4_m4(parmat_inv, curBone->parent->arm_mat);
+
+ /* Get the new head and tail */
+ sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail);
+ sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail);
+
+ mul_mat3_m4_v3(parmat_inv, curBone->head);
+ mul_mat3_m4_v3(parmat_inv, curBone->tail);
+ }
+ else {
+ copy_v3_v3(curBone->head, curBone->arm_head);
+ copy_v3_v3(curBone->tail, curBone->arm_tail);
+ }
+
+ /* Set local matrix and arm_mat (restpose).
+ * Do not recurse into children here, armature_finalize_restpose() is already recursive. */
+ BKE_armature_where_is_bone(curBone, curBone->parent, false);
+
/* Find the associated editbone */
- for (ebone = editbonelist->first; ebone; ebone = ebone->next)
- if ((Bone *)ebone->temp == curBone)
- break;
-
- if (ebone) {
- /* Get the ebone premat */
- ED_armature_ebone_to_mat3(ebone, premat);
-
- /* Get the bone postmat */
- copy_m3_m4(postmat, curBone->arm_mat);
-
- invert_m3_m3(imat, premat);
- mul_m3_m3m3(difmat, imat, postmat);
+ for (ebone = editbonelist->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.bone == curBone) {
+ float premat[3][3];
+ float postmat[3][3];
+ float difmat[3][3];
+ float imat[3][3];
+
+ /* Get the ebone premat and its inverse. */
+ ED_armature_ebone_to_mat3(ebone, premat);
+ invert_m3_m3(imat, premat);
+
+ /* Get the bone postmat. */
+ copy_m3_m4(postmat, curBone->arm_mat);
+
+ mul_m3_m3m3(difmat, imat, postmat);
+
#if 0
- printf("Bone %s\n", curBone->name);
- print_m4("premat", premat);
- print_m4("postmat", postmat);
- print_m4("difmat", difmat);
- printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
+ printf("Bone %s\n", curBone->name);
+ print_m4("premat", premat);
+ print_m4("postmat", postmat);
+ print_m4("difmat", difmat);
+ printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
#endif
- curBone->roll = -atan2f(difmat[2][0], difmat[2][2]);
-
- /* and set restposition again */
- BKE_armature_where_is_bone(curBone, curBone->parent);
+
+ curBone->roll = -atan2f(difmat[2][0], difmat[2][2]);
+
+ /* and set restposition again */
+ BKE_armature_where_is_bone(curBone, curBone->parent, false);
+ break;
+ }
}
- fix_bonelist_roll(&curBone->childbase, editbonelist);
+
+ /* Recurse into children... */
+ armature_finalize_restpose(&curBone->childbase, editbonelist);
}
}
@@ -529,9 +565,9 @@ void ED_armature_from_edit(bArmature *arm)
/* remove zero sized bones, this gives unstable restposes */
for (eBone = arm->edbo->first; eBone; eBone = neBone) {
- float len = len_v3v3(eBone->head, eBone->tail);
+ float len_sq = len_squared_v3v3(eBone->head, eBone->tail);
neBone = eBone->next;
- if (len <= 0.000001f) { /* FLT_EPSILON is too large? */
+ if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */
EditBone *fBone;
/* Find any bones that refer to this bone */
@@ -548,7 +584,7 @@ void ED_armature_from_edit(bArmature *arm)
/* Copy the bones from the editData into the armature */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
newBone = MEM_callocN(sizeof(Bone), "bone");
- eBone->temp = newBone; /* Associate the real Bones with the EditBones */
+ eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
copy_v3_v3(newBone->arm_head, eBone->head);
@@ -581,48 +617,29 @@ void ED_armature_from_edit(bArmature *arm)
newBone->prop = IDP_CopyProperty(eBone->prop);
}
- /* Fix parenting in a separate pass to ensure ebone->bone connections
- * are valid at this point */
+ /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point.
+ * Do not set bone->head/tail here anymore, using EditBone data for that is not OK since our later fiddling
+ * with parent's arm_mat (for roll conversion) may have some small but visible impact on locations (T46010). */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = (Bone *)eBone->temp;
+ newBone = eBone->temp.bone;
if (eBone->parent) {
- newBone->parent = (Bone *)eBone->parent->temp;
+ newBone->parent = eBone->parent->temp.bone;
BLI_addtail(&newBone->parent->childbase, newBone);
-
- {
- float M_parentRest[3][3];
- float iM_parentRest[3][3];
-
- /* Get the parent's matrix (rotation only) */
- ED_armature_ebone_to_mat3(eBone->parent, M_parentRest);
-
- /* Invert the parent matrix */
- invert_m3_m3(iM_parentRest, M_parentRest);
-
- /* Get the new head and tail */
- sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail);
- sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail);
-
- mul_m3_v3(iM_parentRest, newBone->head);
- mul_m3_v3(iM_parentRest, newBone->tail);
- }
}
/* ...otherwise add this bone to the armature's bonebase */
else {
- copy_v3_v3(newBone->head, eBone->head);
- copy_v3_v3(newBone->tail, eBone->tail);
BLI_addtail(&arm->bonebase, newBone);
}
}
- /* Make a pass through the new armature to fix rolling */
- /* also builds restposition again (like BKE_armature_where_is) */
- fix_bonelist_roll(&arm->bonebase, arm->edbo);
+ /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */
+ armature_finalize_restpose(&arm->bonebase, arm->edbo);
/* so all users of this armature should get rebuilt */
for (obt = G.main->object.first; obt; obt = obt->id.next) {
- if (obt->data == arm)
+ if (obt->data == arm) {
BKE_pose_rebuild(obt, arm);
+ }
}
DAG_id_tag_update(&arm->id, 0);
@@ -695,24 +712,24 @@ static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
if (ebone_dst->prop) {
ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop);
}
- ebone_src->temp = ebone_dst;
+ ebone_src->temp.ebone = ebone_dst;
BLI_addtail(lb_dst, ebone_dst);
}
/* set pointers */
for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) {
if (ebone_dst->parent) {
- ebone_dst->parent = ebone_dst->parent->temp;
+ ebone_dst->parent = ebone_dst->parent->temp.ebone;
}
}
}
-static void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
+void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
{
EditBone *ebone;
/* be sure they don't hang ever */
for (ebone = lb->first; ebone; ebone = ebone->next) {
- ebone->temp = NULL;
+ ebone->temp.p = NULL;
}
}
@@ -733,7 +750,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
/* active bone */
if (uarm->act_edbone) {
ebone = uarm->act_edbone;
- arm->act_edbone = ebone->temp;
+ arm->act_edbone = ebone->temp.ebone;
}
else {
arm->act_edbone = NULL;
@@ -755,7 +772,7 @@ static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
/* active bone */
if (arm->act_edbone) {
ebone = arm->act_edbone;
- uarm->act_edbone = ebone->temp;
+ uarm->act_edbone = ebone->temp.ebone;
}
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 647b640ee61..2235f9f92cc 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -707,7 +707,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* DO SOME MAGIC HERE */
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -718,7 +718,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
cti->get_constraint_targets(con, &targets);
for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) {
- if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) {
+ if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
/* SET bone link to bone corresponding to pchan */
EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
@@ -832,7 +832,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* DO SOME MAGIC HERE */
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -841,7 +841,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
cti->get_constraint_targets(con, &targets);
for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) {
+ if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
/* SET bone link to ctrl corresponding to pchan */
RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name);
@@ -1160,7 +1160,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
last_bone = bone;
- if (strcmp(bone->name, "head") == 0) {
+ if (STREQ(bone->name, "head")) {
contain_head = 1;
}
}
@@ -1205,7 +1205,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
static void RIG_findHead(RigGraph *rg)
{
if (rg->head == NULL) {
- if (BLI_countlist(&rg->arcs) == 1) {
+ if (BLI_listbase_is_single(&rg->arcs)) {
RigArc *arc = rg->arcs.first;
rg->head = (RigNode *)arc->head;
@@ -1958,7 +1958,7 @@ static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc,
#endif
float *vec0, *vec1;
int *best_positions;
- int nb_edges = BLI_countlist(&iarc->edges);
+ int nb_edges = BLI_listbase_count(&iarc->edges);
int nb_joints = nb_edges - 1;
RetargetMethod method = METHOD_MEMOIZE;
int i;
@@ -2152,7 +2152,7 @@ void exec_retargetArctoArc(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(th
RigNode *inode_start = p->inode_start;
ReebArc *earc = iarc->link_mesh;
- if (BLI_countlist(&iarc->edges) == 1) {
+ if (BLI_listbase_is_single(&iarc->edges)) {
RigEdge *edge = iarc->edges.first;
if (testFlipArc(iarc, inode_start)) {
@@ -2454,7 +2454,7 @@ const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index)
return "None";
}
- if (bone_index == BLI_countlist(&arc->edges)) {
+ if (bone_index == BLI_listbase_count(&arc->edges)) {
return "Last joint";
}
@@ -2476,10 +2476,10 @@ int RIG_nbJoints(RigGraph *rg)
RigArc *arc;
int total = 0;
- total += BLI_countlist(&rg->nodes);
+ total += BLI_listbase_count(&rg->nodes);
for (arc = rg->arcs.first; arc; arc = arc->next) {
- total += BLI_countlist(&arc->edges) - 1; /* -1 because end nodes are already counted */
+ total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */
}
return total;
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index d75a23a6322..e4c3f73dd94 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -31,8 +31,6 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
-
#include "BKE_context.h"
#include "BKE_sketch.h"
@@ -335,11 +333,11 @@ static void sk_autoname(bContext *C, ReebArc *arc)
if (side[0] == '\0') {
valid = 1;
}
- else if (strcmp(side, "R") == 0 || strcmp(side, "L") == 0) {
+ else if (STREQ(side, "R") || STREQ(side, "L")) {
valid = 1;
caps = 1;
}
- else if (strcmp(side, "r") == 0 || strcmp(side, "l") == 0) {
+ else if (STREQ(side, "r") || STREQ(side, "l")) {
valid = 1;
caps = 0;
}
@@ -403,9 +401,7 @@ static void sk_retargetStroke(bContext *C, SK_Stroke *stk)
RigGraph *rg;
invert_m4_m4(imat, obedit->obmat);
-
- copy_m3_m4(tmat, obedit->obmat);
- transpose_m3(tmat);
+ transpose_m3_m4(tmat, obedit->obmat);
arc = sk_strokeToArc(stk, imat, tmat);
@@ -440,7 +436,7 @@ static float sk_clampPointSize(SK_Point *pt, float size)
static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size)
{
- glTranslatef(pt->p[0], pt->p[1], pt->p[2]);
+ glTranslate3fv(pt->p);
gluSphere(quad, sk_clampPointSize(pt, size), 8, 8);
}
@@ -459,7 +455,7 @@ static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float si
angle = angle_normalized_v3v3(vec2, vec1);
- glRotatef(angle * (float)(180.0 / M_PI) + 180.0f, axis[0], axis[1], axis[2]);
+ glRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis);
gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
}
@@ -479,7 +475,7 @@ static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float heig
angle = angle_normalized_v3v3(vec2, pt->no);
- glRotatef(angle * (float)(180.0 / M_PI), axis[0], axis[1], axis[2]);
+ glRotate3fv(angle * (float)(180.0 / M_PI), axis);
glColor3f(0, 1, 1);
gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
@@ -1358,9 +1354,7 @@ static void sk_convertStroke(bContext *C, SK_Stroke *stk)
head = NULL;
invert_m4_m4(invmat, obedit->obmat);
-
- copy_m3_m4(tmat, obedit->obmat);
- transpose_m3(tmat);
+ transpose_m3_m4(tmat, obedit->obmat);
for (i = 0; i < stk->nb_points; i++) {
SK_Point *pt = stk->points + i;
@@ -1579,7 +1573,7 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S
added = MAX2(s_added, added);
}
- BLI_sortlist(list, cmpIntersections);
+ BLI_listbase_sort(list, cmpIntersections);
return added;
}
@@ -1698,7 +1692,7 @@ int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UN
if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) {
SK_Intersection *isect, *self_isect;
- /* get the the last intersection of the first pair */
+ /* get the last intersection of the first pair */
for (isect = gest->intersections.first; isect; isect = isect->next) {
if (isect->stroke == isect->next->stroke) {
isect = isect->next;
@@ -1957,7 +1951,7 @@ static void sk_applyGesture(bContext *C, SK_Sketch *sketch)
/********************************************/
-static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], int extend)
+static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], const bool extend)
{
ViewContext vc;
rcti rect;
@@ -2118,7 +2112,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch,
glColor3fv(colors[index]);
glPushMatrix();
- glTranslatef(p->p[0], p->p[1], p->p[2]);
+ glTranslate3fv(p->p);
gluSphere(quad, 0.02, 8, 8);
glPopMatrix();
}
@@ -2245,15 +2239,19 @@ static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNU
return OPERATOR_FINISHED;
}
-void BIF_sk_selectStroke(bContext *C, const int mval[2], short extend)
+bool BIF_sk_selectStroke(bContext *C, const int mval[2], const bool extend)
{
ToolSettings *ts = CTX_data_tool_settings(C);
SK_Sketch *sketch = contextSketch(C, 0);
if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING) {
- if (sk_selectStroke(C, sketch, mval, extend))
+ if (sk_selectStroke(C, sketch, mval, extend)) {
ED_area_tag_redraw(CTX_wm_area(C));
+ return true;
+ }
}
+
+ return false;
}
void BIF_convertSketch(bContext *C)
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 49650fcadbf..b8dc4e1e7ab 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -35,8 +35,9 @@
#include "BLI_edgehash.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
+#include "BLI_alloca.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_DerivedMesh.h"
#include "BKE_modifier.h"
@@ -84,9 +85,10 @@ struct LaplacianSystem {
EdgeHash *edgehash; /* edge hash for construction */
struct HeatWeighting {
- MFace *mface;
+ const MLoopTri *mlooptri;
+ const MLoop *mloop; /* needed to find vertices by index */
int totvert;
- int totface;
+ int tottri;
float (*verts)[3]; /* vertex coordinates */
float (*vnors)[3]; /* vertex normals */
@@ -100,7 +102,7 @@ struct LaplacianSystem {
float *mindist; /* minimum distance to a bone for all vertices */
BVHTree *bvhtree; /* ray tracing acceleration structure */
- MFace **vface; /* a face that the vertex belongs to */
+ const MLoopTri **vltree; /* a looptri that the vertex belongs to */
} heat;
#ifdef RIGID_DEFORM
@@ -127,12 +129,12 @@ struct LaplacianSystem {
static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
{
- void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
+ void **p;
- if (p)
+ if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p))
*p = (void *)((intptr_t)*p + (intptr_t)1);
else
- BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1);
+ *p = (void *)((intptr_t)1);
}
static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
@@ -377,30 +379,33 @@ typedef struct BVHCallbackUserData {
LaplacianSystem *sys;
} BVHCallbackUserData;
-static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit)
+static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
BVHCallbackUserData *data = (struct BVHCallbackUserData *)userdata;
- MFace *mf = data->sys->heat.mface + index;
+ const MLoopTri *lt = &data->sys->heat.mlooptri[index];
+ const MLoop *mloop = data->sys->heat.mloop;
float (*verts)[3] = data->sys->heat.verts;
- float lambda, uv[2], n[3], dir[3];
+ const float *vtri_co[3];
+ float dist_test;
- mul_v3_v3fl(dir, data->vec, hit->dist);
+ vtri_co[0] = verts[mloop[lt->tri[0]].v];
+ vtri_co[1] = verts[mloop[lt->tri[1]].v];
+ vtri_co[2] = verts[mloop[lt->tri[2]].v];
- if (isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) {
- normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]);
- if (lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
- hit->index = index;
- hit->dist *= lambda;
- }
- }
-
- mul_v3_v3fl(dir, data->vec, hit->dist);
-
- if (isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) {
- normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]);
- if (lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
- hit->index = index;
- hit->dist *= lambda;
+#ifdef USE_KDOPBVH_WATERTIGHT
+ if (isect_ray_tri_watertight_v3(data->start, ray->isect_precalc, UNPACK3(vtri_co), &dist_test, NULL))
+#else
+ UNUSED_VARS(ray);
+ if (isect_ray_tri_v3(data->start, data->vec, UNPACK3(vtri_co), &dist_test, NULL))
+#endif
+ {
+ if (dist_test < hit->dist) {
+ float n[3];
+ normal_tri_v3(n, UNPACK3(vtri_co));
+ if (dot_v3v3(n, data->vec) < -1e-5f) {
+ hit->index = index;
+ hit->dist = dist_test;
+ }
}
}
}
@@ -408,34 +413,36 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray
/* Raytracing for vertex to bone/vertex visibility */
static void heat_ray_tree_create(LaplacianSystem *sys)
{
- MFace *mface = sys->heat.mface;
+ const MLoopTri *looptri = sys->heat.mlooptri;
+ const MLoop *mloop = sys->heat.mloop;
float (*verts)[3] = sys->heat.verts;
- int totface = sys->heat.totface;
+ int tottri = sys->heat.tottri;
int totvert = sys->heat.totvert;
int a;
- sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6);
- sys->heat.vface = MEM_callocN(sizeof(MFace *) * totvert, "HeatVFaces");
+ sys->heat.bvhtree = BLI_bvhtree_new(tottri, 0.0f, 4, 6);
+ sys->heat.vltree = MEM_callocN(sizeof(MLoopTri *) * totvert, "HeatVFaces");
- for (a = 0; a < totface; a++) {
- MFace *mf = mface + a;
+ for (a = 0; a < tottri; a++) {
+ const MLoopTri *lt = &looptri[a];
float bb[6];
+ int vtri[3];
+
+ vtri[0] = mloop[lt->tri[0]].v;
+ vtri[1] = mloop[lt->tri[1]].v;
+ vtri[2] = mloop[lt->tri[2]].v;
INIT_MINMAX(bb, bb + 3);
- minmax_v3v3_v3(bb, bb + 3, verts[mf->v1]);
- minmax_v3v3_v3(bb, bb + 3, verts[mf->v2]);
- minmax_v3v3_v3(bb, bb + 3, verts[mf->v3]);
- if (mf->v4) {
- minmax_v3v3_v3(bb, bb + 3, verts[mf->v4]);
- }
+ minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]);
+ minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]);
+ minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]);
BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
//Setup inverse pointers to use on isect.orig
- sys->heat.vface[mf->v1] = mf;
- sys->heat.vface[mf->v2] = mf;
- sys->heat.vface[mf->v3] = mf;
- if (mf->v4) sys->heat.vface[mf->v4] = mf;
+ sys->heat.vltree[vtri[0]] = lt;
+ sys->heat.vltree[vtri[1]] = lt;
+ sys->heat.vltree[vtri[2]] = lt;
}
BLI_bvhtree_balance(sys->heat.bvhtree);
@@ -445,12 +452,12 @@ static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
{
BVHTreeRayHit hit;
BVHCallbackUserData data;
- MFace *mface;
+ const MLoopTri *lt;
float end[3];
int visible;
- mface = sys->heat.vface[vertex];
- if (!mface)
+ lt = sys->heat.vltree[vertex];
+ if (lt == NULL)
return 1;
data.sys = sys;
@@ -568,8 +575,9 @@ static void heat_calc_vnormals(LaplacianSystem *sys)
static void heat_laplacian_create(LaplacianSystem *sys)
{
- MFace *mface = sys->heat.mface, *mf;
- int totface = sys->heat.totface;
+ const MLoopTri *mlooptri = sys->heat.mlooptri, *lt;
+ const MLoop *mloop = sys->heat.mloop;
+ int tottri = sys->heat.tottri;
int totvert = sys->heat.totvert;
int a;
@@ -582,10 +590,12 @@ static void heat_laplacian_create(LaplacianSystem *sys)
for (a = 0; a < totvert; a++)
laplacian_add_vertex(sys, sys->heat.verts[a], 0);
- for (a = 0, mf = mface; a < totface; a++, mf++) {
- laplacian_add_triangle(sys, mf->v1, mf->v2, mf->v3);
- if (mf->v4)
- laplacian_add_triangle(sys, mf->v1, mf->v3, mf->v4);
+ for (a = 0, lt = mlooptri; a < tottri; a++, lt++) {
+ int vtri[3];
+ vtri[0] = mloop[lt->tri[0]].v;
+ vtri[1] = mloop[lt->tri[1]].v;
+ vtri[2] = mloop[lt->tri[2]].v;
+ laplacian_add_triangle(sys, UNPACK3(vtri));
}
/* for distance computation in set_H */
@@ -598,7 +608,8 @@ static void heat_laplacian_create(LaplacianSystem *sys)
static void heat_system_free(LaplacianSystem *sys)
{
BLI_bvhtree_free(sys->heat.bvhtree);
- MEM_freeN(sys->heat.vface);
+ MEM_freeN(sys->heat.vltree);
+ MEM_freeN((void *)sys->heat.mlooptri);
MEM_freeN(sys->heat.mindist);
MEM_freeN(sys->heat.H);
@@ -626,9 +637,9 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
{
LaplacianSystem *sys;
+ MLoopTri *mlooptri;
MPoly *mp;
MLoop *ml;
- MFace *mf;
float solution, weight;
int *vertsflipped = NULL, *mask = NULL;
int a, tottri, j, bbone, firstsegment, lastsegment;
@@ -641,15 +652,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
*err_str = NULL;
/* bone heat needs triangulated faces */
- BKE_mesh_tessface_ensure(me);
-
- for (tottri = 0, a = 0, mf = me->mface; a < me->totface; mf++, a++) {
- tottri++;
- if (mf->v4) tottri++;
- }
-
- if (tottri == 0)
- return;
+ tottri = poly_to_tri_count(me->totpoly, me->totloop);
/* count triangles and create mask */
if (ob->mode & OB_MODE_WEIGHT_PAINT &&
@@ -679,8 +682,17 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
/* create laplacian */
sys = laplacian_system_construct_begin(me->totvert, tottri, 1);
- sys->heat.mface = me->mface;
- sys->heat.totface = me->totface;
+ sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__);
+
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ mlooptri);
+
+ sys->heat.mlooptri = mlooptri;
+ sys->heat.mloop = me->mloop;
sys->heat.totvert = me->totvert;
sys->heat.verts = verts;
sys->heat.root = root;
@@ -1041,18 +1053,26 @@ void rigid_deform_end(int cancel)
#define MESHDEFORM_TAG_INTERIOR 2
#define MESHDEFORM_TAG_EXTERIOR 3
+/** minimum length for #MDefBoundIsect.len */
#define MESHDEFORM_LEN_THRESHOLD 1e-6f
#define MESHDEFORM_MIN_INFLUENCE 0.0005f
-static int MESHDEFORM_OFFSET[7][3] = {
+static const int MESHDEFORM_OFFSET[7][3] = {
{0, 0, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}
};
typedef struct MDefBoundIsect {
- float co[3], uvw[4];
- int nvert, v[4], facing;
+ /* intersection on the cage 'cagecos' */
+ float co[3];
+ /* non-facing intersections are considered interior */
+ bool facing;
+ /* ray-cast index aligned with MPoly (ray-hit-triangle isn't needed) */
+ int poly_index;
+ /* distance from 'co' to the ray-cast start (clamped to avoid zero division) */
float len;
+ /* weights aligned with the MPoly's loop indices */
+ float poly_weights[0];
} MDefBoundIsect;
typedef struct MDefBindInfluence {
@@ -1091,15 +1111,23 @@ typedef struct MeshDeformBind {
BVHTree *bvhtree;
BVHTreeFromMesh bvhdata;
+
+ /* avoid DM function calls during intersections */
+ struct {
+ const MPoly *mpoly;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ const float (*poly_nors)[3];
+ } cagedm_cache;
} MeshDeformBind;
typedef struct MeshDeformIsect {
float start[3];
float vec[3];
+ float vec_length;
float lambda;
- void *face;
- int isect;
+ bool isect;
float u, v;
} MeshDeformIsect;
@@ -1169,34 +1197,41 @@ static int meshdeform_tri_intersect(const float orig[3], const float end[3], con
return 1;
}
+struct MeshRayCallbackData {
+ MeshDeformBind *mdb;
+ MeshDeformIsect *isec;
+};
+
static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
- void **data = userdata;
- MeshDeformBind *mdb = data[1];
- MFace *mface = data[0], *mf;
- MeshDeformIsect *isec = data[2];
- float no[3], co[3], end[3], uvw[3], dist, face[4][3];
+ struct MeshRayCallbackData *data = userdata;
+ MeshDeformBind *mdb = data->mdb;
+ const MLoop *mloop = mdb->cagedm_cache.mloop;
+ const MLoopTri *looptri = mdb->cagedm_cache.looptri, *lt;
+ const float (*poly_nors)[3] = mdb->cagedm_cache.poly_nors;
+ MeshDeformIsect *isec = data->isec;
+ float no[3], co[3], end[3], uvw[3], dist;
+ float *face[3];
- mf = mface + index;
+ lt = &looptri[index];
- copy_v3_v3(face[0], mdb->cagecos[mf->v1]);
- copy_v3_v3(face[1], mdb->cagecos[mf->v2]);
- copy_v3_v3(face[2], mdb->cagecos[mf->v3]);
- if (mf->v4)
- copy_v3_v3(face[3], mdb->cagecos[mf->v4]);
+ face[0] = mdb->cagecos[mloop[lt->tri[0]].v];
+ face[1] = mdb->cagecos[mloop[lt->tri[1]].v];
+ face[2] = mdb->cagecos[mloop[lt->tri[2]].v];
add_v3_v3v3(end, isec->start, isec->vec);
- if (!meshdeform_tri_intersect(ray->origin, end, face[0], face[1], face[2], co, uvw))
- if (!mf->v4 || !meshdeform_tri_intersect(ray->origin, end, face[0], face[2], face[3], co, uvw))
- return;
-
- if (!mf->v4)
- normal_tri_v3(no, face[0], face[1], face[2]);
- else
- normal_quad_v3(no, face[0], face[1], face[2], face[3]);
-
- dist = len_v3v3(ray->origin, co) / len_v3(isec->vec);
+ if (!meshdeform_tri_intersect(ray->origin, end, UNPACK3(face), co, uvw))
+ return;
+
+ if (poly_nors) {
+ copy_v3_v3(no, poly_nors[lt->poly]);
+ }
+ else {
+ normal_tri_v3(no, UNPACK3(face));
+ }
+
+ dist = len_v3v3(ray->origin, co) / isec->vec_length;
if (dist < hit->dist) {
hit->index = index;
hit->dist = dist;
@@ -1204,19 +1239,18 @@ static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *r
isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f);
isec->lambda = dist;
- isec->face = mf;
}
}
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3])
{
- MDefBoundIsect *isect;
BVHTreeRayHit hit;
MeshDeformIsect isect_mdef;
- float (*cagecos)[3];
- void *data[3] = {mdb->cagedm->getTessFaceArray(mdb->cagedm), mdb, &isect_mdef};
- MFace *mface1 = data[0], *mface;
- float vert[4][3], len, end[3];
+ struct MeshRayCallbackData data = {
+ mdb,
+ &isect_mdef,
+ };
+ float end[3], vec_normal[3];
// static float epsilon[3] = {1e-4, 1e-4, 1e-4};
/* happens binding when a cage has no faces */
@@ -1235,42 +1269,41 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const
copy_v3_v3(end, co2);
#endif
sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
+ isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);
hit.index = -1;
hit.dist = FLT_MAX;
- if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, isect_mdef.vec,
- 0.0, &hit, harmonic_ray_callback, data) != -1)
+ if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, vec_normal,
+ 0.0, &hit, harmonic_ray_callback, &data) != -1)
{
- len = isect_mdef.lambda;
- isect_mdef.face = mface = mface1 + hit.index;
+ const MLoop *mloop = mdb->cagedm_cache.mloop;
+ const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index];
+ const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly];
+ const float (*cagecos)[3] = mdb->cagecos;
+ const float len = isect_mdef.lambda;
+ MDefBoundIsect *isect;
- /* create MDefBoundIsect */
- isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect));
+ float (*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop);
+ int i;
+
+ /* create MDefBoundIsect, and extra for 'poly_weights[]' */
+ isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop));
/* compute intersection coordinate */
- isect->co[0] = co1[0] + isect_mdef.vec[0] * len;
- isect->co[1] = co1[1] + isect_mdef.vec[1] * len;
- isect->co[2] = co1[2] + isect_mdef.vec[2] * len;
+ madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);
- isect->len = len_v3v3(co1, isect->co);
- if (isect->len < MESHDEFORM_LEN_THRESHOLD)
- isect->len = MESHDEFORM_LEN_THRESHOLD;
+ isect->facing = isect_mdef.isect;
- isect->v[0] = mface->v1;
- isect->v[1] = mface->v2;
- isect->v[2] = mface->v3;
- isect->v[3] = mface->v4;
- isect->nvert = (mface->v4) ? 4 : 3;
+ isect->poly_index = lt->poly;
- isect->facing = isect_mdef.isect;
+ isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);
/* compute mean value coordinates for interpolation */
- cagecos = mdb->cagecos;
- copy_v3_v3(vert[0], cagecos[mface->v1]);
- copy_v3_v3(vert[1], cagecos[mface->v2]);
- copy_v3_v3(vert[2], cagecos[mface->v3]);
- if (mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]);
- interp_weights_poly_v3(isect->uvw, vert, isect->nvert, isect->co);
+ for (i = 0; i < mp->totloop; i++) {
+ copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]);
+ }
+
+ interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co);
return isect;
}
@@ -1303,7 +1336,7 @@ static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
/* solving */
-static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
+BLI_INLINE int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
{
int size = mdb->size;
@@ -1321,7 +1354,7 @@ static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
return x + y * size + z * size * size;
}
-static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
+BLI_INLINE void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
{
x += MESHDEFORM_OFFSET[n][0];
y += MESHDEFORM_OFFSET[n][1];
@@ -1418,14 +1451,18 @@ static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
MEM_freeN(stack);
}
-static float meshdeform_boundary_phi(MeshDeformBind *UNUSED(mdb), MDefBoundIsect *isect, int cagevert)
+static float meshdeform_boundary_phi(const MeshDeformBind *mdb, const MDefBoundIsect *isect, int cagevert)
{
- int a;
+ const MLoop *mloop = mdb->cagedm_cache.mloop;
+ const MPoly *mp = &mdb->cagedm_cache.mpoly[isect->poly_index];
+ int i;
+
+ for (i = 0; i < mp->totloop; i++) {
+ if (mloop[mp->loopstart + i].v == cagevert) {
+ return isect->poly_weights[i];
+ }
+ }
- for (a = 0; a < isect->nvert; a++)
- if (isect->v[a] == cagevert)
- return isect->uvw[a];
-
return 0.0f;
}
@@ -1719,7 +1756,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
/* sanity check */
for (b = 0; b < mdb->size3; b++)
if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
- if (fabs(mdb->totalphi[b] - 1.0f) > 1e-4)
+ if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f)
printf("totalphi deficiency [%s|%d] %d: %.10f\n",
(mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
#endif
@@ -1752,7 +1789,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi");
mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect");
mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound");
- mdb->bvhtree = bvhtree_from_mesh_faces(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON * 100, 4, 6);
+ mdb->bvhtree = bvhtree_from_mesh_looptri(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON * 100, 4, 6);
mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside");
if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
@@ -1763,6 +1800,15 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
BLI_memarena_use_calloc(mdb->memarena);
+ /* initialize data from 'cagedm' for reuse */
+ {
+ DerivedMesh *dm = mdb->cagedm;
+ mdb->cagedm_cache.mpoly = dm->getPolyArray(dm);
+ mdb->cagedm_cache.mloop = dm->getLoopArray(dm);
+ mdb->cagedm_cache.looptri = dm->getLoopTriArray(dm);
+ mdb->cagedm_cache.poly_nors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
+ }
+
/* make bounding box equal size in all directions, add padding, and compute
* width of the cells */
maxwidth = -1.0f;
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index 820aedc5467..1412136c1a8 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -29,11 +29,9 @@
//#define RIGID_DEFORM
-struct Scene;
struct Object;
struct Mesh;
struct bDeformGroup;
-struct MeshDeformModifierData;
#ifdef RIGID_DEFORM
struct EditMesh;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index da68108285f..e87c324d7ec 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -381,14 +381,14 @@ static void pose_copy_menu(Scene *scene)
* but for constraints (just add local constraints)
*/
if (pose_has_protected_selected(ob, 0)) {
- i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ i = BLI_listbase_count(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
if (i < 25)
nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5");
else
nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4");
}
else {
- i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ i = BLI_listbase_count(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
if (i < 25)
nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
else
@@ -436,7 +436,7 @@ static void pose_copy_menu(Scene *scene)
pchan->constflag |= pchanact->constflag;
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
break;
case 6: /* Transform Locks */
@@ -503,7 +503,7 @@ static void pose_copy_menu(Scene *scene)
/* build the puplist of constraints */
for (con = pchanact->constraints.first, i = 0; con; con = con->next, i++) {
const_toggle[i] = 1;
-// add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
+// add_numbut(i, UI_BTYPE_TOGGLE|INT, con->name, 0, 0, &(const_toggle[i]), "");
}
// if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
@@ -550,7 +550,7 @@ static void pose_copy_menu(Scene *scene)
BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
@@ -595,7 +595,7 @@ void POSE_OT_flip_names(wmOperatorType *ot)
/* identifiers */
ot->name = "Flip Names";
ot->idname = "POSE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the the names of selected bones";
+ ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
/* api callbacks */
ot->exec = pose_flip_names_exec;
@@ -853,7 +853,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot)
/* Present a popup to get the layers that should be used */
static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
/* get layers that are active already */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
@@ -862,8 +862,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* loop over the bits for this pchan's layers, adding layers where they're needed */
for (bit = 0; bit < 32; bit++) {
- if (pchan->bone->layer & (1 << bit))
- layers[bit] = 1;
+ layers[bit] = (pchan->bone->layer & (1u << bit)) != 0;
}
}
CTX_DATA_END;
@@ -937,8 +936,9 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
/* loop over the bits for this pchan's layers, adding layers where they're needed */
for (bit = 0; bit < 32; bit++) {
- if (ebone->layer & (1 << bit))
+ if (ebone->layer & (1u << bit)) {
layers[bit] = 1;
+ }
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 50d9d300d15..4d9df06f33f 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -130,6 +130,7 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
{
Object *ob = ED_pose_object_from_context(C);
bPose *pose;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
uiPopupMenu *pup;
uiLayout *layout;
@@ -140,12 +141,23 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
pose = ob->pose;
+
+ /* If group index is set, try to use it! */
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int num_groups = BLI_listbase_count(&pose->agroups);
+ const int group = RNA_property_int_get(op->ptr, prop);
+
+ /* just use the active group index, and call the exec callback for the calling operator */
+ if (group > 0 && group <= num_groups) {
+ return op->type->exec(C, op);
+ }
+ }
/* if there's no active group (or active is invalid), create a new menu to find it */
if (pose->active_group <= 0) {
/* create a new menu, and start populating it with group names */
- pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
/* special entry - allow to create new group, then use that
* (not to be used for removing though)
@@ -160,9 +172,9 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
/* finish building the menu, and process it (should result in calling self again) */
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
else {
/* just use the active group index, and call the exec callback for the calling operator */
@@ -365,8 +377,8 @@ typedef struct tSortActionGroup {
/* compare bone groups by name */
static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
{
- tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr;
- tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr;
+ const tSortActionGroup *sgrp_a = sgrp_a_ptr;
+ const tSortActionGroup *sgrp_b = sgrp_b_ptr;
return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
}
@@ -387,7 +399,7 @@ static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* create temporary array with bone groups and indices */
- agrp_count = BLI_countlist(&pose->agroups);
+ agrp_count = BLI_listbase_count(&pose->agroups);
agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
BLI_assert(i < agrp_count);
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 0609fcc29e8..a984e5d1ccd 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -35,7 +35,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -177,6 +177,15 @@ static int has_poselib_pose_data_poll(bContext *C)
return (ob && ob->poselib);
}
+/* Poll callback for operators that require existing PoseLib data (with poses)
+ * as they need to do some editing work on those poses (i.e. not on lib-linked actions)
+ */
+static int has_poselib_pose_data_for_editing_poll(bContext *C)
+{
+ Object *ob = get_poselib_object(C);
+ return (ob && ob->poselib && !ob->poselib->id.lib);
+}
+
/* ----------------------------------- */
/* Initialize a new poselib (whether it is needed or not) */
@@ -357,7 +366,7 @@ void POSELIB_OT_action_sanitize(wmOperatorType *ot)
/* callbacks */
ot->exec = poselib_sanitize_exec;
- ot->poll = has_poselib_pose_data_poll;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -365,6 +374,25 @@ void POSELIB_OT_action_sanitize(wmOperatorType *ot)
/* ------------------------------------------ */
+/* Poll callback for adding poses to a PoseLib */
+static int poselib_add_poll(bContext *C)
+{
+ /* There are 2 cases we need to be careful with:
+ * 1) When this operator is invoked from a hotkey, there may be no PoseLib yet
+ * 2) If a PoseLib already exists, we can't edit the action if it is a lib-linked
+ * actions, as data will be lost when saving the file
+ */
+ if (ED_operator_posemode(C)) {
+ Object *ob = get_poselib_object(C);
+ if (ob) {
+ if ((ob->poselib == NULL) || (ob->poselib->id.lib == 0)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
static void poselib_add_menu_invoke__replacemenu(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
Object *ob = get_poselib_object(C);
@@ -404,8 +432,8 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
return OPERATOR_CANCELLED;
/* start building */
- pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
/* add new (adds to the first unoccupied frame) */
@@ -420,10 +448,10 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
uiItemMenuF(layout, IFACE_("Replace Existing..."), 0, poselib_add_menu_invoke__replacemenu, NULL);
}
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
/* this operator is only for a menu, not used further */
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
@@ -472,7 +500,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op)
ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
/* store new 'active' pose number */
- act->active_marker = BLI_countlist(&act->markers);
+ act->active_marker = BLI_listbase_count(&act->markers);
/* done */
return OPERATOR_FINISHED;
@@ -488,7 +516,7 @@ void POSELIB_OT_pose_add(wmOperatorType *ot)
/* api callbacks */
ot->invoke = poselib_add_menu_invoke;
ot->exec = poselib_add_exec;
- ot->poll = ED_operator_posemode;
+ ot->poll = poselib_add_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -604,7 +632,7 @@ void POSELIB_OT_pose_remove(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = poselib_remove_exec;
- ot->poll = has_poselib_pose_data_poll;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -692,7 +720,7 @@ void POSELIB_OT_pose_rename(wmOperatorType *ot)
/* api callbacks */
ot->invoke = poselib_rename_invoke;
ot->exec = poselib_rename_exec;
- ot->poll = has_poselib_pose_data_poll;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -916,7 +944,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
ListBase dsources = {NULL, NULL};
- short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
+ bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
/* start tagging/keying */
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
@@ -1050,7 +1078,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
LinkData *ld, *ldn, *ldc;
/* free and rebuild if needed (i.e. if search-str changed) */
- if (strcmp(pld->searchstr, pld->searchold)) {
+ if (!STREQ(pld->searchstr, pld->searchold)) {
/* free list of temporary search matches */
BLI_freelistN(&pld->searchp);
@@ -1196,7 +1224,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
/* only accept 'press' event, and ignore 'release', so that we don't get double actions */
if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) {
- //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type), event->val);
+ //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type, false), event->val);
return ret;
}
@@ -1348,7 +1376,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
else {
/* change to last pose */
pld->marker = pld->act->markers.last;
- pld->act->active_marker = BLI_countlist(&pld->act->markers);
+ pld->act->active_marker = BLI_listbase_count(&pld->act->markers);
pld->redraw = PL_PREVIEW_REDRAWALL;
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index ba5ef4f3b5d..44470c1f827 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -62,7 +62,7 @@
#include "armature_intern.h"
-/* utility macros fro storing a temp int in the bone (selection flag) */
+/* utility macros for storing a temp int in the bone (selection flag) */
#define PBONE_PREV_FLAG_GET(pchan) ((void)0, (GET_INT_FROM_POINTER((pchan)->temp)))
#define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = SET_INT_IN_POINTER(val))
@@ -458,7 +458,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
{
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -518,71 +518,67 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = ob->data;
- Bone *curbone, *pabone, *chbone;
+ bPoseChannel *pchan_act;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
- bool found = false;
+ bool changed = false;
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- curbone = pchan->bone;
-
- if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
- if (curbone == arm->act_bone) {
- if (direction == BONE_SELECT_PARENT) {
- if (pchan->parent == NULL) continue;
- else pabone = pchan->parent->bone;
-
- if (PBONE_SELECTABLE(arm, pabone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- pabone->flag |= BONE_SELECTED;
- arm->act_bone = pabone;
-
- found = 1;
- break;
- }
+ pchan_act = BKE_pose_channel_active(ob);
+ if (pchan_act == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (pchan_act->parent) {
+ Bone *bone_parent;
+ bone_parent = pchan_act->parent->bone;
+
+ if (PBONE_SELECTABLE(arm, bone_parent)) {
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
}
- else { /* direction == BONE_SELECT_CHILD */
- /* the child member is only assigned to connected bones, see [#30340] */
-#if 0
- if (pchan->child == NULL) continue;
- else chbone = pchan->child->bone;
-#else
- /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
- chbone = pchan->child ? pchan->child->bone : NULL;
- if (chbone == NULL) {
- bPoseChannel *pchan_child;
-
- for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
- /* possible we have multiple children, some invisible */
- if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
- if (pchan_child->parent == pchan) {
- chbone = pchan_child->bone;
- break;
- }
- }
- }
- }
+ bone_parent->flag |= BONE_SELECTED;
+ arm->act_bone = bone_parent;
- if (chbone == NULL) continue;
-#endif
-
- if (PBONE_SELECTABLE(arm, chbone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- chbone->flag |= BONE_SELECTED;
- arm->act_bone = chbone;
-
- found = 1;
- break;
+ changed = true;
+ }
+ }
+ }
+ else { /* direction == BONE_SELECT_CHILD */
+ bPoseChannel *pchan_iter;
+ Bone *bone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
+ for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
+ if (pchan_iter->parent == pchan_act) {
+ if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
+ bone_child = pchan_iter->bone;
+ break;
+ }
}
}
}
}
+
+ if (bone_child) {
+ arm->act_bone = bone_child;
+
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
+ }
+ bone_child->flag |= BONE_SELECTED;
+
+ changed = true;
+ }
}
- CTX_DATA_END;
- if (found == 0)
+ if (changed == false) {
return OPERATOR_CANCELLED;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
@@ -642,7 +638,7 @@ static bool pose_select_same_group(bContext *C, Object *ob, bool extend)
return 0;
/* count the number of groups */
- numGroups = BLI_countlist(&pose->agroups);
+ numGroups = BLI_listbase_count(&pose->agroups);
if (numGroups == 0)
return 0;
@@ -825,7 +821,7 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
break;
default:
- printf("pose_select_grouped() - Unknown selection type %d\n", type);
+ printf("pose_select_grouped() - Unknown selection type %u\n", type);
break;
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 5f9f24d23a4..40328e0c06e 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -43,6 +43,7 @@
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_unit.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -53,6 +54,7 @@
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
+#include "ED_numinput.h"
#include "ED_screen.h"
#include "armature_intern.h"
@@ -98,6 +100,8 @@ typedef struct tPoseSlideOp {
int flag; /* unused for now, but can later get used for storing runtime settings.... */
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
+
+ NumInput num; /* numeric input */
} tPoseSlideOp;
/* Pose Sliding Modes */
@@ -154,6 +158,12 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
*/
BLI_dlrbTree_init(&pso->keys);
+ /* initialise numeric input */
+ initNumInput(&pso->num);
+ pso->num.idx_max = 0; /* one axis */
+ pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
+ pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
+
/* return status is whether we've got all the data we were requested to get */
return 1;
}
@@ -201,6 +211,12 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
/* next/end */
eVal = evaluate_fcurve(fcu, (float)pso->nextFrame);
+ /* if both values are equal, don't do anything */
+ if (IS_EQF(sVal, eVal)) {
+ (*val) = sVal;
+ return;
+ }
+
/* calculate the relative weights of the endpoints */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* get weights from the percentage control */
@@ -234,7 +250,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
* - perform this weighting a number of times given by the percentage...
*/
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
while (iters-- > 0) {
(*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f;
}
@@ -247,7 +263,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
* - perform this weighting a number of times given by the percentage...
*/
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
while (iters-- > 0) {
(*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f;
}
@@ -320,6 +336,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
if (prop) {
switch (RNA_property_type(prop)) {
+ /* continuous values that can be smoothly interpolated... */
case PROP_FLOAT:
{
float tval = RNA_property_float_get(&ptr, prop);
@@ -327,8 +344,6 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
RNA_property_float_set(&ptr, prop, tval);
break;
}
- case PROP_BOOLEAN:
- case PROP_ENUM:
case PROP_INT:
{
float tval = (float)RNA_property_int_get(&ptr, prop);
@@ -336,6 +351,23 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
RNA_property_int_set(&ptr, prop, (int)tval);
break;
}
+
+ /* values which can only take discrete values */
+ case PROP_BOOLEAN:
+ {
+ float tval = (float)RNA_property_boolean_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, &tval);
+ RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
+ break;
+ }
+ case PROP_ENUM:
+ {
+ /* don't handle this case - these don't usually represent interchangeable
+ * set of values which should be interpolated between
+ */
+ break;
+ }
+
default:
/* cannot handle */
//printf("Cannot Pose Slide non-numerical property\n");
@@ -404,11 +436,11 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
}
else if (pso->mode == POSESLIDE_PUSH) {
float quat_diff[4], quat_orig[4];
-
+
/* calculate the delta transform from the previous to the current */
/* TODO: investigate ways to favour one transform more? */
sub_qt_qtqt(quat_diff, pchan->quat, quat_prev);
-
+
/* make a copy of the original rotation */
copy_qt_qt(quat_orig, pchan->quat);
@@ -418,7 +450,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
else {
float quat_interp[4], quat_orig[4];
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
/* perform this blending several times until a satisfactory result is reached */
while (iters-- > 0) {
/* calculate the interpolation between the endpoints */
@@ -512,7 +544,7 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* draw percentage indicator in header */
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[32];
+ char status_str[256];
char mode_str[32];
switch (pso->mode) {
@@ -532,7 +564,18 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
break;
}
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ if (hasNumInput(&pso->num)) {
+ Scene *scene = pso->scene;
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&pso->num, str_offs, &scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ }
+
ED_area_headerprint(pso->sa, status_str);
}
@@ -617,6 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
wmWindow *win = CTX_wm_window(C);
+ const bool has_numinput = hasNumInput(&pso->num);
switch (event->type) {
case LEFTMOUSE: /* confirm */
@@ -656,25 +700,54 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE: /* calculate new position */
{
- /* calculate percentage based on position of mouse (we only use x-axis for now.
- * since this is more convenient for users to do), and store new percentage value
- */
- pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
-
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* calculate percentage based on position of mouse (we only use x-axis for now.
+ * since this is more convenient for users to do), and store new percentage value
+ */
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
+ }
break;
}
- default: /* unhandled event (maybe it was some view manip? */
- /* allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ default:
+ if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
+ float value;
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float
+ */
+ value = pso->percentage * 100.0f;
+ applyNumInput(&pso->num, &value);
+
+ pso->percentage = value / 100.0f;
+ CLAMP(pso->percentage, 0.0f, 1.0f);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
+ break;
+ }
+ else {
+ /* unhandled event - maybe it was some view manip? */
+ /* allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
}
/* still running... */
@@ -898,6 +971,8 @@ typedef enum ePosePropagate_Termination {
/* stop when we run out of keyframes */
POSE_PROPAGATE_BEFORE_END,
+ /* only do on keyframes that are selected */
+ POSE_PROPAGATE_SELECTED_KEYS,
/* only do on the frames where markers are selected */
POSE_PROPAGATE_SELECTED_MARKERS
} ePosePropagate_Termination;
@@ -1098,13 +1173,20 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
* since it may be as of yet unkeyed
* - if starting before the starting frame, don't touch the key, as it may have had some valid
* values
+ * - if only doing selected keyframes, start from the first one
*/
- match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
-
- if (fcu->bezt[match].vec[1][0] < startFrame)
- i = match + 1;
- else
- i = match;
+ if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
+ match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
+
+ if (fcu->bezt[match].vec[1][0] < startFrame)
+ i = match + 1;
+ else
+ i = match;
+ }
+ else {
+ /* selected - start from first keyframe */
+ i = 0;
+ }
for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
/* additional termination conditions based on the operator 'mode' property go here... */
@@ -1137,6 +1219,11 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
if (ce == NULL)
continue;
}
+ else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
+ /* only allow if this keyframe is already selected - skip otherwise */
+ if (BEZT_ISSEL_ANY(bezt) == 0)
+ continue;
+ }
/* just flatten handles, since values will now be the same either side... */
/* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
@@ -1219,12 +1306,20 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
void POSE_OT_propagate(wmOperatorType *ot)
{
static EnumPropertyItem terminate_items[] = {
- {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
- {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", "Propagate pose to first keyframe following the current frame only"},
- {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
- {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", "Propagate pose to all keyframes between current frame and 'Frame' property"},
- {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", "Propagate pose to all keyframes from current frame until no more are found"},
- {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
+ {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held",
+ "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
+ {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe",
+ "Propagate pose to first keyframe following the current frame only"},
+ {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe",
+ "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
+ {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame",
+ "Propagate pose to all keyframes between current frame and 'Frame' property"},
+ {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe",
+ "Propagate pose to all keyframes from current frame until no more are found"},
+ {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes",
+ "Propagate pose to all selected keyframes"},
+ {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers",
+ "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 0cde8f30ace..01e16df9f08 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -320,7 +320,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
if (selOnly)
paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
else
- paste_ok = ((pchan != NULL));
+ paste_ok = (pchan != NULL);
/* continue? */
if (paste_ok) {
@@ -811,7 +811,7 @@ void POSE_OT_transforms_clear(wmOperatorType *ot)
static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
float cframe = (float)CFRA;
const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 380a3fffc6d..2ba1eedd33b 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -49,8 +49,6 @@
#include "WM_api.h"
#include "WM_types.h"
-
-
#include "ED_armature.h"
#include "ED_keyframing.h"
@@ -261,7 +259,7 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con
FCurve *fcu = (FCurve *)ld->data;
/* check if paths match */
- if (strcmp(path, fcu->rna_path) == 0)
+ if (STREQ(path, fcu->rna_path))
return ld;
}
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 8cc6059e87b..f29d15ff416 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -107,7 +107,7 @@ static VertexData *allocVertexData(EditMesh *em)
EditVert *eve;
int totvert, index;
- totvert = BLI_countlist(&em->verts);
+ totvert = BLI_listbase_count(&em->verts);
data = MEM_callocN(sizeof(VertexData) * totvert, "VertexData");
@@ -1141,7 +1141,7 @@ static int compareNodesWeight(void *vnode1, void *vnode2)
void sortNodes(ReebGraph *rg)
{
- BLI_sortlist(&rg->nodes, compareNodesWeight);
+ BLI_listbase_sort(&rg->nodes, compareNodesWeight);
}
static int compareArcsWeight(void *varc1, void *varc2)
@@ -1166,7 +1166,7 @@ static int compareArcsWeight(void *varc1, void *varc2)
void sortArcs(ReebGraph *rg)
{
- BLI_sortlist(&rg->arcs, compareArcsWeight);
+ BLI_listbase_sort(&rg->arcs, compareArcsWeight);
}
/******************************************* JOINING ***************************************************/
@@ -1512,7 +1512,7 @@ static int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_intern
ReebArc *arc = NULL, *nextArc = NULL;
int value = 0;
- BLI_sortlist(&rg->arcs, compareArcs);
+ BLI_listbase_sort(&rg->arcs, compareArcs);
for (arc = rg->arcs.first; arc; arc = nextArc) {
nextArc = arc->next;
@@ -1632,7 +1632,7 @@ int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold))
#if 0 //XXX
ReebArc *arc = NULL, *nextArc = NULL;
- BLI_sortlist(&rg->arcs, compareArcs);
+ BLI_listbase_sort(&rg->arcs, compareArcs);
#ifdef DEBUG_REEB
{
@@ -1867,7 +1867,7 @@ static void spreadWeight(EditMesh *em)
{
EditVert **verts, *eve;
float lastWeight = 0.0f;
- int totvert = BLI_countlist(&em->verts);
+ int totvert = BLI_listbase_count(&em->verts);
int i;
int work_needed = 1;
@@ -2399,9 +2399,9 @@ ReebGraph *generateReebGraph(EditMesh *em, int subdivisions)
rg->resolution = subdivisions;
- /*totvert = BLI_countlist(&em->verts);*/ /*UNUSED*/
+ /*totvert = BLI_listbase_count(&em->verts);*/ /*UNUSED*/
#ifdef DEBUG_REEB
- totfaces = BLI_countlist(&em->faces);
+ totfaces = BLI_listbase_count(&em->faces);
#endif
renormalizeWeight(em, 1.0f);
@@ -2460,7 +2460,7 @@ void renormalizeWeight(EditMesh *em, float newmax)
EditVert *eve;
float minimum, maximum, range;
- if (em == NULL || BLI_countlist(&em->verts) == 0)
+ if (em == NULL || BLI_listbase_is_empty(&em->verts))
return;
/* First pass, determine maximum and minimum */
@@ -2486,7 +2486,7 @@ int weightFromLoc(EditMesh *em, int axis)
{
EditVert *eve;
- if (em == NULL || BLI_countlist(&em->verts) == 0 || axis < 0 || axis > 2)
+ if (em == NULL || BLI_listbase_is_empty(&em->verts) || axis < 0 || axis > 2)
return 0;
/* Copy coordinate in weight */
@@ -2738,7 +2738,7 @@ static void buildIndexedEdges(EditMesh *em, EdgeIndex *indexed_edges)
int tot_indexed = 0;
int offset = 0;
- totvert = BLI_countlist(&em->verts);
+ totvert = BLI_listbase_count(&em->verts);
indexed_edges->offset = MEM_callocN(totvert * sizeof(int), "EdgeIndex offset");
@@ -2791,13 +2791,13 @@ int weightFromDistance(EditMesh *em, EdgeIndex *indexed_edges)
int totvert = 0;
int vCount = 0;
- totvert = BLI_countlist(&em->verts);
+ totvert = BLI_listbase_count(&em->verts);
if (em == NULL || totvert == 0) {
return 0;
}
- totedge = BLI_countlist(&em->edges);
+ totedge = BLI_listbase_count(&em->edges);
if (totedge == 0) {
return 0;
diff --git a/source/blender/editors/armature/reeb.h b/source/blender/editors/armature/reeb.h
index b0e1fd3ae34..a6ef16fed67 100644
--- a/source/blender/editors/armature/reeb.h
+++ b/source/blender/editors/armature/reeb.h
@@ -140,6 +140,7 @@ typedef struct ReebArcIterator {
int stride;
} ReebArcIterator;
+#if 0
struct EditMesh;
struct EdgeIndex;
@@ -152,6 +153,8 @@ void arcToVCol(struct ReebGraph *rg, struct EditMesh *em, int index);
void renormalizeWeight(struct EditMesh *em, float newmax);
ReebGraph *generateReebGraph(struct EditMesh *me, int subdivisions);
+#endif
+
ReebGraph *newReebGraph(void);
void initArcIterator(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head);
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 0b449c4334d..83346e9550c 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -20,9 +20,9 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../makesdna
../../makesrna
../../windowmanager
@@ -37,8 +37,8 @@ set(SRC
curve_ops.c
editcurve.c
editcurve_add.c
+ editcurve_select.c
editfont.c
- lorem.c
curve_intern.h
)
diff --git a/source/blender/editors/curve/SConscript b/source/blender/editors/curve/SConscript
index 4760a212a8a..eadec4f65b6 100644
--- a/source/blender/editors/curve/SConscript
+++ b/source/blender/editors/curve/SConscript
@@ -34,9 +34,9 @@ defs = []
incs = [
'#/intern/guardedalloc',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../makesdna',
'../../makesrna',
'../../render/extern/include',
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index d54db77754f..29904bf2344 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -37,9 +37,7 @@ struct ListBase;
struct EditNurb;
struct Object;
struct wmOperatorType;
-
-/* lorem.c */
-extern const char ED_lorem[];
+struct ViewContext;
/* editfont.c */
enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
@@ -47,6 +45,25 @@ enum { CASE_LOWER, CASE_UPPER };
enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD,
PREV_LINE, NEXT_LINE, PREV_PAGE, NEXT_PAGE };
+typedef enum eVisible_Types {
+ HIDDEN = true,
+ VISIBLE = false,
+} eVisible_Types;
+
+typedef enum eEndPoint_Types {
+ FIRST = true,
+ LAST = false,
+} eEndPoint_Types;
+
+typedef enum eCurveElem_Types {
+ CURVE_VERTEX = 0,
+ CURVE_SEGMENT,
+} eCurveElem_Types;
+
+/* internal select utils */
+bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden);
+bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden);
+
void FONT_OT_text_insert(struct wmOperatorType *ot);
void FONT_OT_line_break(struct wmOperatorType *ot);
void FONT_OT_insert_lorem(struct wmOperatorType *ot);
@@ -101,19 +118,6 @@ void CURVE_OT_smooth_weight(struct wmOperatorType *ot);
void CURVE_OT_smooth_radius(struct wmOperatorType *ot);
void CURVE_OT_smooth_tilt(struct wmOperatorType *ot);
-void CURVE_OT_de_select_first(struct wmOperatorType *ot);
-void CURVE_OT_de_select_last(struct wmOperatorType *ot);
-void CURVE_OT_select_all(struct wmOperatorType *ot);
-void CURVE_OT_select_linked(struct wmOperatorType *ot);
-void CURVE_OT_select_linked_pick(struct wmOperatorType *ot);
-void CURVE_OT_select_row(struct wmOperatorType *ot);
-void CURVE_OT_select_next(struct wmOperatorType *ot);
-void CURVE_OT_select_previous(struct wmOperatorType *ot);
-void CURVE_OT_select_more(struct wmOperatorType *ot);
-void CURVE_OT_select_less(struct wmOperatorType *ot);
-void CURVE_OT_select_random(struct wmOperatorType *ot);
-void CURVE_OT_select_nth(struct wmOperatorType *ot);
-
void CURVE_OT_switch_direction(struct wmOperatorType *ot);
void CURVE_OT_subdivide(struct wmOperatorType *ot);
void CURVE_OT_make_segment(struct wmOperatorType *ot);
@@ -124,11 +128,30 @@ void CURVE_OT_cyclic_toggle(struct wmOperatorType *ot);
void CURVE_OT_match_texture_space(struct wmOperatorType *ot);
+bool ED_curve_pick_vert(
+ struct ViewContext *vc, short sel, const int mval[2],
+ struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle);
+
/* helper functions */
void ed_editnurb_translate_flag(struct ListBase *editnurb, short flag, const float vec[3]);
bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, short flag);
bool ed_editnurb_spin(float viewmat[4][4], struct Object *obedit, const float axis[3], const float cent[3]);
+/* editcurve_select.c */
+void CURVE_OT_de_select_first(struct wmOperatorType *ot);
+void CURVE_OT_de_select_last(struct wmOperatorType *ot);
+void CURVE_OT_select_all(struct wmOperatorType *ot);
+void CURVE_OT_select_linked(struct wmOperatorType *ot);
+void CURVE_OT_select_linked_pick(struct wmOperatorType *ot);
+void CURVE_OT_select_row(struct wmOperatorType *ot);
+void CURVE_OT_select_next(struct wmOperatorType *ot);
+void CURVE_OT_select_previous(struct wmOperatorType *ot);
+void CURVE_OT_select_more(struct wmOperatorType *ot);
+void CURVE_OT_select_less(struct wmOperatorType *ot);
+void CURVE_OT_select_random(struct wmOperatorType *ot);
+void CURVE_OT_select_nth(struct wmOperatorType *ot);
+void CURVE_OT_select_similar(struct wmOperatorType *ot);
+void CURVE_OT_shortest_path_pick(struct wmOperatorType *ot);
/* editcurve_add.c */
void CURVE_OT_primitive_bezier_curve_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index f1b34182439..4828fb3ec5f 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -36,10 +36,6 @@
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-
-
#include "RNA_access.h"
#include "WM_api.h"
@@ -58,7 +54,6 @@ void ED_operatortypes_curve(void)
{
WM_operatortype_append(FONT_OT_text_insert);
WM_operatortype_append(FONT_OT_line_break);
- WM_operatortype_append(FONT_OT_insert_lorem);
WM_operatortype_append(FONT_OT_case_toggle);
WM_operatortype_append(FONT_OT_case_set);
@@ -133,6 +128,8 @@ void ED_operatortypes_curve(void)
WM_operatortype_append(CURVE_OT_select_less);
WM_operatortype_append(CURVE_OT_select_random);
WM_operatortype_append(CURVE_OT_select_nth);
+ WM_operatortype_append(CURVE_OT_select_similar);
+ WM_operatortype_append(CURVE_OT_shortest_path_pick);
WM_operatortype_append(CURVE_OT_switch_direction);
WM_operatortype_append(CURVE_OT_subdivide);
@@ -246,12 +243,15 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "CURVE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "CURVE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "CURVE_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "CURVE_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
+ WM_keymap_add_item(keymap, "CURVE_OT_shortest_path_pick", SELECTMOUSE, KM_CLICK, KM_CTRL, 0);
+
WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index a52b2a619dc..f7dab0c0935 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -37,12 +37,10 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
-#include "BLI_bitmap.h"
#include "BLI_math.h"
-#include "BLI_rand.h"
#include "BLI_ghash.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -85,6 +83,7 @@ typedef struct {
GHash *undoIndex;
ListBase fcurves, drivers;
int actnu;
+ int flag;
} UndoCurve;
/* Definitions needed for shape keys */
@@ -95,23 +94,7 @@ typedef struct {
Nurb *orig_nu;
} CVKeyIndex;
-typedef enum eVisible_Types {
- HIDDEN = true,
- VISIBLE = false,
-} eVisible_Types;
-
-typedef enum eEndPoint_Types {
- FIRST = true,
- LAST = false,
-} eEndPoint_Types;
-
-typedef enum eCurveElem_Types {
- CURVE_VERTEX = 0,
- CURVE_SEGMENT,
-} eCurveElem_Types;
-
void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
-static void select_adjacent_cp(ListBase *editnurb, short next, const bool cont, const bool selstatus);
static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split);
static int curve_delete_segments(Object *obedit, const bool split);
@@ -124,115 +107,9 @@ ListBase *object_editcurve_get(Object *ob)
return NULL;
}
-/* ******************* SELECTION FUNCTIONS ********************* */
-
-
-/* returns 1 in case (de)selection was successful */
-static bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden)
-{
- if ((bezt->hide == 0) || (hidden == HIDDEN)) {
- if (selstatus == SELECT) { /* selects */
- bezt->f1 |= flag;
- bezt->f2 |= flag;
- bezt->f3 |= flag;
- return true;
- }
- else { /* deselects */
- bezt->f1 &= ~flag;
- bezt->f2 &= ~flag;
- bezt->f3 &= ~flag;
- return true;
- }
- }
-
- return false;
-}
-
-/* returns 1 in case (de)selection was successful */
-static bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden)
-{
- if ((bp->hide == 0) || (hidden == 1)) {
- if (selstatus == SELECT) {
- bp->f1 |= flag;
- return true;
- }
- else {
- bp->f1 &= ~flag;
- return true;
- }
- }
-
- return false;
-}
-
-static bool swap_selection_beztriple(BezTriple *bezt)
-{
- if (bezt->f2 & SELECT)
- return select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
- else
- return select_beztriple(bezt, SELECT, SELECT, VISIBLE);
-}
-
-static bool swap_selection_bpoint(BPoint *bp)
-{
- if (bp->f1 & SELECT)
- return select_bpoint(bp, DESELECT, SELECT, VISIBLE);
- else
- return select_bpoint(bp, SELECT, SELECT, VISIBLE);
-}
-
-int isNurbsel(Nurb *nu)
-{
- BezTriple *bezt;
- BPoint *bp;
- int a;
-
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if ( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
- bezt++;
- }
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- if (bp->f1 & SELECT) return 1;
- bp++;
- }
- }
- return 0;
-}
-
-static int isNurbsel_count(Curve *cu, Nurb *nu)
-{
- BezTriple *bezt;
- BPoint *bp;
- int a, sel = 0;
-
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) sel++;
- bezt++;
- }
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- if ( (bp->f1 & SELECT) ) sel++;
- bp++;
- }
- }
- return sel;
-}
-
/* ******************* PRINTS ********************* */
+#if 0
void printknots(Object *obedit)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -240,7 +117,7 @@ void printknots(Object *obedit)
int a, num;
for (nu = editnurb->first; nu; nu = nu->next) {
- if (isNurbsel(nu) && nu->type == CU_NURBS) {
+ if (ED_curve_nurb_select_check(nu) && nu->type == CU_NURBS) {
if (nu->knotsu) {
num = KNOTSU(nu);
for (a = 0; a < num; a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
@@ -252,6 +129,7 @@ void printknots(Object *obedit)
}
}
}
+#endif
/* ********************* Shape keys *************** */
@@ -324,17 +202,17 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
editnurb->keyindex = gh;
}
-static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, void *cv)
+static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, const void *cv)
{
return BLI_ghash_lookup(editnurb->keyindex, cv);
}
-static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, void *cv)
+static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, const void *cv)
{
return BLI_ghash_popkey(editnurb->keyindex, cv, NULL);
}
-static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, BezTriple *bezt)
+static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
{
CVKeyIndex *index = getCVKeyIndex(editnurb, bezt);
@@ -367,7 +245,7 @@ static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
return index->key_index;
}
-static void keyIndex_delCV(EditNurb *editnurb, void *cv)
+static void keyIndex_delCV(EditNurb *editnurb, const void *cv)
{
if (!editnurb->keyindex) {
return;
@@ -395,7 +273,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
}
if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
+ const BezTriple *bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
@@ -404,7 +282,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
}
}
else {
- BPoint *bp = nu->bp;
+ const BPoint *bp = nu->bp;
a = nu->pntsu * nu->pntsv;
while (a--) {
@@ -642,25 +520,20 @@ static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
static GHash *dupli_keyIndexHash(GHash *keyindex)
{
GHash *gh;
- GHashIterator *hashIter;
+ GHashIterator gh_iter;
gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex));
- for (hashIter = BLI_ghashIterator_new(keyindex);
- BLI_ghashIterator_done(hashIter) == false;
- BLI_ghashIterator_step(hashIter))
- {
- void *cv = BLI_ghashIterator_getKey(hashIter);
- CVKeyIndex *index = BLI_ghashIterator_getValue(hashIter);
- CVKeyIndex *newIndex = MEM_callocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
+ GHASH_ITER (gh_iter, keyindex) {
+ void *cv = BLI_ghashIterator_getKey(&gh_iter);
+ CVKeyIndex *index = BLI_ghashIterator_getValue(&gh_iter);
+ CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
memcpy(newIndex, index, sizeof(CVKeyIndex));
BLI_ghash_insert(gh, cv, newIndex);
}
- BLI_ghashIterator_free(hashIter);
-
return gh;
}
@@ -766,16 +639,7 @@ static void calc_shapeKeys(Object *obedit)
/* editing the base key should update others */
if (cu->key->type == KEY_RELATIVE) {
- int act_is_basis = 0;
- /* find if this key is a basis for any others */
- for (currkey = cu->key->block.first; currkey; currkey = currkey->next) {
- if (editnurb->shapenr - 1 == currkey->relative) {
- act_is_basis = 1;
- break;
- }
- }
-
- if (act_is_basis) { /* active key is a base */
+ if (BKE_keyblock_is_basis(cu->key, editnurb->shapenr - 1)) { /* active key is a base */
int totvec = 0;
/* Calculate needed memory to store offset */
@@ -1007,7 +871,7 @@ static void fcurve_path_rename(AnimData *adt, const char *orig_rna_path, char *r
for (fcu = orig_curves->first; fcu; fcu = nextfcu) {
nextfcu = fcu->next;
- if (!strncmp(fcu->rna_path, orig_rna_path, len)) {
+ if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
char *spath, *suffix = fcu->rna_path + len;
nfcu = copy_fcurve(fcu);
spath = nfcu->rna_path;
@@ -1110,10 +974,10 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
for (fcu = orig_curves->first; fcu; fcu = next) {
next = fcu->next;
- if (!strncmp(fcu->rna_path, "splines", 7)) {
+ if (STREQLEN(fcu->rna_path, "splines", 7)) {
const char *ch = strchr(fcu->rna_path, '.');
- if (ch && (!strncmp(ch, ".bezier_points", 14) || !strncmp(ch, ".points", 7)))
+ if (ch && (STREQLEN(ch, ".bezier_points", 14) || STREQLEN(ch, ".points", 7)))
fcurve_remove(adt, orig_curves, fcu);
}
}
@@ -1137,7 +1001,7 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
for (fcu = orig_curves->first; fcu; fcu = next) {
next = fcu->next;
- if (!strncmp(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu);
+ if (STREQLEN(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu);
else BLI_addtail(&curves, fcu);
}
@@ -1199,7 +1063,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert)
while (a--) {
keyIndex = getCVKeyIndex(editnurb, bezt);
- if (keyIndex) {
+ if (keyIndex && keyIndex->vertex_index + 2 < old_totvert) {
if (keyIndex->switched) {
old_to_new_map[keyIndex->vertex_index] = vertex_index + 2;
old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
@@ -1358,7 +1222,7 @@ void make_editNurb(Object *obedit)
if (actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
undo_editmode_clear();
- BKE_key_convert_to_curve(actkey, cu, &cu->nurb);
+ BKE_keyblock_convert_to_curve(actkey, cu, &cu->nurb);
}
if (editnurb) {
@@ -1395,87 +1259,6 @@ void free_editNurb(Object *obedit)
BKE_curve_editNurb_free(cu);
}
-void ED_curve_deselect_all(EditNurb *editnurb)
-{
- Nurb *nu;
- int a;
-
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- if (nu->bezt) {
- BezTriple *bezt;
- for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
- bezt->f1 &= ~SELECT;
- bezt->f2 &= ~SELECT;
- bezt->f3 &= ~SELECT;
- }
- }
- else if (nu->bp) {
- BPoint *bp;
- for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
- bp->f1 &= ~SELECT;
- }
- }
- }
-}
-
-void ED_curve_select_all(EditNurb *editnurb)
-{
- Nurb *nu;
- int a;
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- if (nu->bezt) {
- BezTriple *bezt;
- for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- bezt->f1 |= SELECT;
- bezt->f2 |= SELECT;
- bezt->f3 |= SELECT;
- }
- }
- }
- else if (nu->bp) {
- BPoint *bp;
- for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
- if (bp->hide == 0)
- bp->f1 |= SELECT;
- }
- }
- }
-}
-
-void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
-{
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int a;
-
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (bezt->hide == 0) {
- bezt->f2 ^= SELECT; /* always do the center point */
- if (!hide_handles) {
- bezt->f1 ^= SELECT;
- bezt->f3 ^= SELECT;
- }
- }
- bezt++;
- }
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- swap_selection_bpoint(bp);
- bp++;
- }
- }
- }
-}
-
/******************** separate operator ***********************/
static int separate_exec(bContext *C, wmOperator *op)
@@ -1549,6 +1332,7 @@ void CURVE_OT_separate(wmOperatorType *ot)
ot->description = "Separate selected points from connected unselected points into a new object";
/* api callbacks */
+ ot->invoke = WM_operator_confirm;
ot->exec = separate_exec;
ot->poll = ED_operator_editsurfcurve;
@@ -1893,7 +1677,7 @@ static void ed_curve_delete_selected(Object *obedit)
a = nu->pntsu;
if (a) {
while (a) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
/* pass */
}
else {
@@ -1955,7 +1739,7 @@ static void ed_curve_delete_selected(Object *obedit)
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
for (a = 0; a < nu->pntsu; a++) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple));
keyIndex_delBezt(editnurb, bezt);
keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1);
@@ -2015,7 +1799,7 @@ static void ed_curve_delete_selected(Object *obedit)
}
/* only for OB_SURF */
-bool ed_editnurb_extrude_flag(EditNurb *editnurb, short flag)
+bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag)
{
Nurb *nu;
BPoint *bp, *bpn, *newbp;
@@ -2244,7 +2028,7 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
}
else {
- if (isNurbsel(nu)) {
+ if (ED_curve_nurb_select_check(cu, nu)) {
/* a rectangular area in nurb has to be selected and if splitting must be in U or V direction */
usel = MEM_callocN(nu->pntsu, "adduplicateN3");
bp = nu->bp;
@@ -2376,7 +2160,6 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
else {
/* knots done after duplicate as pntsu may change */
- nu->knotsu = nu->knotsv = NULL;
BKE_nurb_order_clamp_u(nu);
BKE_nurb_knot_calc_u(nu);
@@ -2404,7 +2187,7 @@ static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
int i;
for (nu = editnurb->nurbs.first, i = 0; nu; nu = nu->next, i++) {
- if (isNurbsel(nu)) {
+ if (ED_curve_nurb_select_check(cu, nu)) {
BKE_nurb_direction_switch(nu);
keyData_switchDirectionNurb(cu, nu);
if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
@@ -2538,7 +2321,7 @@ void CURVE_OT_radius_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
}
/********************* smooth operator ********************/
@@ -2711,7 +2494,7 @@ static void curve_smooth_value(ListBase *editnurb,
for (nu = editnurb->first; nu; nu = nu->next) {
if (nu->bezt) {
-#define BEZT_VALUE(bezt) (*((float *)((char *)bezt + bezt_offsetof)))
+#define BEZT_VALUE(bezt) (*((float *)((char *)(bezt) + bezt_offsetof)))
for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
/* loop over selection segments of a curve, smooth each */
@@ -2780,7 +2563,7 @@ static void curve_smooth_value(ListBase *editnurb,
#undef BEZT_VALUE
}
else if (nu->bp) {
-#define BP_VALUE(bp) (*((float *)((char *)bp + bp_offset)))
+#define BP_VALUE(bp) (*((float *)((char *)(bp) + bp_offset)))
/* Same as above, keep these the same! */
for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
@@ -2936,274 +2719,6 @@ void CURVE_OT_smooth_tilt(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/***************** selection utility *************************/
-
-/* next == 1 -> select next */
-/* next == -1 -> select previous */
-/* cont == 1 -> select continuously */
-/* selstatus, inverts behavior */
-static void select_adjacent_cp(ListBase *editnurb, short next,
- const bool cont, const bool selstatus)
-{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
- bool lastsel = false;
-
- if (next == 0) return;
-
- for (nu = editnurb->first; nu; nu = nu->next) {
- lastsel = false;
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt = nu->bezt;
- if (next < 0) bezt = &nu->bezt[a - 1];
- while (a--) {
- if (a - abs(next) < 0) break;
- if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
- bezt += next;
- if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
- short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = true;
- }
- }
- else {
- bezt += next;
- lastsel = false;
- }
- /* move around in zigzag way so that we go through each */
- bezt -= (next - next / abs(next));
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- if (next < 0) bp = &nu->bp[a - 1];
- while (a--) {
- if (a - abs(next) < 0) break;
- if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
- bp += next;
- if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
- short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = true;
- }
- }
- else {
- bp += next;
- lastsel = false;
- }
- /* move around in zigzag way so that we go through each */
- bp -= (next - next / abs(next));
- }
- }
- }
-}
-
-/**************** select start/end operators **************/
-
-/* (de)selects first or last of visible part of each Nurb depending on selFirst
- * selFirst: defines the end of which to select
- * doswap: defines if selection state of each first/last control point is swapped
- * selstatus: selection status in case doswap is false
- */
-void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus)
-{
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- Curve *cu;
- int a;
-
- if (obedit == NULL) return;
-
- cu = (Curve *)obedit->data;
- cu->actvert = CU_ACT_NONE;
-
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
-
- /* which point? */
- if (selfirst == LAST) { /* select last */
- bezt = &nu->bezt[a - 1];
- }
- else { /* select first */
- bezt = nu->bezt;
- }
-
- while (a--) {
- bool sel;
- if (doswap) sel = swap_selection_beztriple(bezt);
- else sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
-
- if (sel == true) break;
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
-
- /* which point? */
- if (selfirst == LAST) { /* select last */
- bp = &nu->bp[a - 1];
- }
- else { /* select first */
- bp = nu->bp;
- }
-
- while (a--) {
- if (bp->hide == 0) {
- bool sel;
- if (doswap) sel = swap_selection_bpoint(bp);
- else sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
-
- if (sel == true) break;
- }
- }
- }
- }
-}
-
-static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
-
- selectend_nurb(obedit, FIRST, true, DESELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_de_select_first(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select First";
- ot->idname = "CURVE_OT_de_select_first";
- ot->description = "(De)select first of visible part of each NURBS";
-
- /* api cfirstbacks */
- ot->exec = de_select_first_exec;
- ot->poll = ED_operator_editcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
-
- selectend_nurb(obedit, LAST, true, DESELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_de_select_last(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select Last";
- ot->idname = "CURVE_OT_de_select_last";
- ot->description = "(De)select last of visible part of each NURBS";
-
- /* api clastbacks */
- ot->exec = de_select_last_exec;
- ot->poll = ED_operator_editcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/******************* de select all operator ***************/
-
-static bool nurb_has_selected_cps(ListBase *editnurb)
-{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
-
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- if (bezt->hide == 0) {
- if ((bezt->f1 & SELECT) ||
- (bezt->f2 & SELECT) ||
- (bezt->f3 & SELECT))
- {
- return 1;
- }
- }
- bezt++;
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- if ((bp->hide == 0) && (bp->f1 & SELECT)) return 1;
- bp++;
- }
- }
- }
-
- return 0;
-}
-
-static int de_select_all_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
- int action = RNA_enum_get(op->ptr, "action");
-
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- if (nurb_has_selected_cps(editnurb))
- action = SEL_DESELECT;
- }
-
- switch (action) {
- case SEL_SELECT:
- ED_curve_select_all(cu->editnurb);
- break;
- case SEL_DESELECT:
- ED_curve_deselect_all(cu->editnurb);
- break;
- case SEL_INVERT:
- ED_curve_select_swap(cu->editnurb, (cu->drawflag & CU_HIDE_HANDLES) != 0);
- break;
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(cu);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "CURVE_OT_select_all";
- ot->description = "(De)select all control points";
-
- /* api callbacks */
- ot->exec = de_select_all_exec;
- ot->poll = ED_operator_editsurfcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_select_all(ot);
-}
-
/********************** hide operator *********************/
static int hide_exec(bContext *C, wmOperator *op)
@@ -3223,11 +2738,11 @@ static int hide_exec(bContext *C, wmOperator *op)
a = nu->pntsu;
sel = 0;
while (a--) {
- if (invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ if (invert == 0 && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
bezt->hide = 1;
}
- else if (invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ else if (invert && !BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
bezt->hide = 1;
}
@@ -3377,7 +2892,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
break;
}
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt) && BEZSELECTED_HIDDENHANDLES(cu, nextbezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt) && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nextbezt)) {
amount += number_cuts;
}
bezt++;
@@ -3399,7 +2914,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
break;
}
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt) && BEZSELECTED_HIDDENHANDLES(cu, nextbezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt) && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nextbezt)) {
float prevvec[3][3];
memcpy(prevvec, bezt->vec, sizeof(float) * 9);
@@ -3758,14 +3273,14 @@ void CURVE_OT_subdivide(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/******************** find nearest ************************/
-static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void ED_curve_pick_vert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; float dist; int hpoint, select; float mval_fl[2]; } *data = userData;
@@ -3801,7 +3316,9 @@ static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp,
}
}
-static short findnearestNurbvert(ViewContext *vc, short sel, const int mval[2], Nurb **nurb, BezTriple **bezt, BPoint **bp)
+bool ED_curve_pick_vert(
+ ViewContext *vc, short sel, const int mval[2],
+ Nurb **r_nurb, BezTriple **r_bezt, BPoint **r_bp, short *r_handle)
{
/* (sel == 1): selected gets a disadvantage */
/* in nurb and bezt or bp the nearest is written */
@@ -3815,46 +3332,54 @@ static short findnearestNurbvert(ViewContext *vc, short sel, const int mval[2],
data.mval_fl[1] = mval[1];
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- nurbs_foreachScreenVert(vc, findnearestNurbvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ nurbs_foreachScreenVert(vc, ED_curve_pick_vert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
- *nurb = data.nurb;
- *bezt = data.bezt;
- *bp = data.bp;
+ *r_nurb = data.nurb;
+ *r_bezt = data.bezt;
+ *r_bp = data.bp;
+
+ if (r_handle) {
+ *r_handle = data.hpoint;
+ }
- return data.hpoint;
+ return (data.bezt || data.bp);
}
-static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt, BPoint **bp)
+static void findselectedNurbvert(
+ Curve *cu,
+ Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
{
/* in nu and (bezt or bp) selected are written if there's 1 sel. */
/* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
+ ListBase *editnurb = &cu->editnurb->nurbs;
Nurb *nu1;
BezTriple *bezt1;
BPoint *bp1;
int a;
- *nu = NULL;
- *bezt = NULL;
- *bp = NULL;
+ *r_nu = NULL;
+ *r_bezt = NULL;
+ *r_bp = NULL;
+
for (nu1 = editnurb->first; nu1; nu1 = nu1->next) {
if (nu1->type == CU_BEZIER) {
bezt1 = nu1->bezt;
a = nu1->pntsu;
while (a--) {
- if ((bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT)) {
- if (*nu != NULL && *nu != nu1) {
- *nu = NULL;
- *bp = NULL;
- *bezt = NULL;
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1)) {
+ if (*r_nu != NULL && *r_nu != nu1) {
+ *r_nu = NULL;
+ *r_bp = NULL;
+ *r_bezt = NULL;
return;
}
- else if (*bezt || *bp) {
- *bp = NULL;
- *bezt = NULL;
+ else if (*r_bezt || *r_bp) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
}
else {
- *bezt = bezt1;
- *nu = nu1;
+ *r_bezt = bezt1;
+ *r_nu = nu1;
}
}
bezt1++;
@@ -3865,19 +3390,19 @@ static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt
a = nu1->pntsu * nu1->pntsv;
while (a--) {
if (bp1->f1 & SELECT) {
- if (*nu != NULL && *nu != nu1) {
- *bp = NULL;
- *bezt = NULL;
- *nu = NULL;
+ if (*r_nu != NULL && *r_nu != nu1) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ *r_nu = NULL;
return;
}
- else if (*bezt || *bp) {
- *bp = NULL;
- *bezt = NULL;
+ else if (*r_bezt || *r_bp) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
}
else {
- *bp = bp1;
- *nu = nu1;
+ *r_bp = bp1;
+ *r_nu = nu1;
}
}
bp1++;
@@ -3904,7 +3429,7 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
}
for (nu = editnurb->first; nu; nu = nu->next) {
- if (isNurbsel(nu)) {
+ if (ED_curve_nurb_select_check(obedit->data, nu)) {
const int pntsu_prev = nu->pntsu;
if (BKE_nurb_type_convert(nu, type, use_handles)) {
changed = true;
@@ -4066,15 +3591,17 @@ static void switchdirection_knots(float *base, int tot)
fp1++;
fp2--;
}
+
/* and make in increasing order again */
- a = tot;
+ a = tot - 1;
fp1 = base;
- fp2 = tempf = MEM_mallocN(sizeof(float) * a, "switchdirect");
+ fp2 = tempf = MEM_mallocN(sizeof(float) * tot, "switchdirect");
while (a--) {
fp2[0] = fabsf(fp1[1] - fp1[0]);
fp1++;
fp2++;
}
+ fp2[0] = 0.0f;
a = tot - 1;
fp1 = base;
@@ -4139,7 +3666,7 @@ typedef struct NurbSort {
static ListBase nsortbase = {NULL, NULL};
/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
-static void make_selection_list_nurb(ListBase *editnurb)
+static void make_selection_list_nurb(Curve *cu, ListBase *editnurb)
{
ListBase nbase = {NULL, NULL};
NurbSort *nus, *nustest, *headdo, *taildo;
@@ -4149,7 +3676,7 @@ static void make_selection_list_nurb(ListBase *editnurb)
int a;
for (nu = editnurb->first; nu; nu = nu->next) {
- if (isNurbsel(nu)) {
+ if (ED_curve_nurb_select_check(cu, nu)) {
nus = (NurbSort *)MEM_callocN(sizeof(NurbSort), "sort");
BLI_addhead(&nbase, nus);
@@ -4353,7 +3880,7 @@ static int merge_nurb(bContext *C, wmOperator *op)
NurbSort *nus1, *nus2;
bool ok = true;
- make_selection_list_nurb(editnurb);
+ make_selection_list_nurb(cu, editnurb);
if (nsortbase.first == nsortbase.last) {
BLI_freelistN(&nsortbase);
@@ -4428,11 +3955,17 @@ static int make_segment_exec(bContext *C, wmOperator *op)
else nu = NULL;
while (nu) {
- if (isNurbsel(nu)) {
-
- if (nu->pntsu > 1 && nu->pntsv > 1) break;
- if (isNurbsel_count(cu, nu) > 1) break;
- if (isNurbsel_count(cu, nu) == 1) {
+ const int nu_select_num = ED_curve_nurb_select_count(cu, nu);
+ if (nu_select_num) {
+
+ if (nu->pntsu > 1 && nu->pntsv > 1) {
+ break;
+ }
+
+ if (nu_select_num > 1) {
+ break;
+ }
+ else {
/* only 1 selected, not first or last, a little complex, but intuitive */
if (nu->pntsv == 1) {
if ((nu->bp->f1 & SELECT) || (nu->bp[nu->pntsu - 1].f1 & SELECT)) {
@@ -4457,7 +3990,7 @@ static int make_segment_exec(bContext *C, wmOperator *op)
if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic */
if (nu->type == CU_BEZIER) {
- if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) {
/* Last point is selected, preferred for nu2 */
if (nu2 == NULL) {
nu2 = nu;
@@ -4468,13 +4001,13 @@ static int make_segment_exec(bContext *C, wmOperator *op)
/* Just in case both of first/last CV are selected check
* whether we really need to switch the direction.
*/
- if (!BEZSELECTED_HIDDENHANDLES(cu, nu1->bezt)) {
+ if (!BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nu1->bezt)) {
BKE_nurb_direction_switch(nu1);
keyData_switchDirectionNurb(cu, nu1);
}
}
}
- else if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt)) {
+ else if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nu->bezt)) {
/* First point is selected, preferred for nu1 */
if (nu1 == NULL) {
nu1 = nu;
@@ -4485,7 +4018,7 @@ static int make_segment_exec(bContext *C, wmOperator *op)
/* Just in case both of first/last CV are selected check
* whether we really need to switch the direction.
*/
- if (!BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu2->pntsu - 1]))) {
+ if (!BEZT_ISSEL_ANY_HIDDENHANDLES(cu, &(nu->bezt[nu2->pntsu - 1]))) {
BKE_nurb_direction_switch(nu2);
keyData_switchDirectionNurb(cu, nu2);
}
@@ -4584,8 +4117,8 @@ static int make_segment_exec(bContext *C, wmOperator *op)
}
if (!(nu1->flagu & CU_NURB_CYCLIC) && nu1->pntsu > 1) {
- if (nu1->type == CU_BEZIER && BEZSELECTED_HIDDENHANDLES(cu, nu1->bezt) &&
- BEZSELECTED_HIDDENHANDLES(cu, &nu1->bezt[nu1->pntsu - 1]))
+ if (nu1->type == CU_BEZIER && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nu1->bezt) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, &nu1->bezt[nu1->pntsu - 1]))
{
nu1->flagu |= CU_NURB_CYCLIC;
BKE_nurb_handles_calc(nu1);
@@ -4648,25 +4181,22 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool
location[0] = mval[0];
location[1] = mval[1];
- hand = findnearestNurbvert(&vc, 1, location, &nu, &bezt, &bp);
- if (bezt || bp) {
+ if (ED_curve_pick_vert(&vc, 1, location, &nu, &bezt, &bp, &hand)) {
if (extend) {
if (bezt) {
if (hand == 1) {
select_beztriple(bezt, SELECT, SELECT, HIDDEN);
- BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
if (hand == 0) bezt->f1 |= SELECT;
else bezt->f3 |= SELECT;
-
- cu->actvert = CU_ACT_NONE;
}
+ BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
- BKE_curve_nurb_vert_active_set(cu, nu, bp);
select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
}
else if (deselect) {
@@ -4724,18 +4254,16 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool
if (hand == 1) {
select_beztriple(bezt, SELECT, SELECT, HIDDEN);
- BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
if (hand == 0) bezt->f1 |= SELECT;
else bezt->f3 |= SELECT;
-
- cu->actvert = CU_ACT_NONE;
}
+ BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
- BKE_curve_nurb_vert_active_set(cu, nu, bp);
select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
}
@@ -4799,7 +4327,7 @@ bool ed_editnurb_spin(float viewmat[4][4], Object *obedit, const float axis[3],
ok = true;
for (a = 0; a < 7; a++) {
- ok = ed_editnurb_extrude_flag(cu->editnurb, 1);
+ ok = ed_editnurb_extrude_flag(cu->editnurb, SELECT);
if (ok == false)
return changed;
@@ -4820,7 +4348,7 @@ bool ed_editnurb_spin(float viewmat[4][4], Object *obedit, const float axis[3],
if (ok) {
for (nu = editnurb->first; nu; nu = nu->next) {
- if (isNurbsel(nu)) {
+ if (ED_curve_nurb_select_check(cu, nu)) {
nu->orderv = 4;
nu->flagv |= CU_NURB_CYCLIC;
BKE_nurb_knot_calc_v(nu);
@@ -4893,289 +4421,414 @@ void CURVE_OT_spin(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX, "Axis", "Axis in global view space", -1.0f, 1.0f);
+ RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Center", "Center in global view space", -1000.0f, 1000.0f);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
-/***************** add vertex operator **********************/
+/***************** extrude vertex operator **********************/
-static int addvert_Nurb(bContext *C, short mode, float location[3])
+static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
- EditNurb *editnurb = cu->editnurb;
- Nurb *nu, *newnu = NULL;
- BezTriple *bezt, *newbezt = NULL;
- BPoint *bp, *newbp = NULL;
- float imat[4][4], temp[3];
- bool ok = false;
- BezTriple *bezt_recalc[3] = {NULL};
+ Nurb *nu = NULL;
+ Nurb *nu_last = NULL;
- invert_m4_m4(imat, obedit->obmat);
+ bool changed = false;
- findselectedNurbvert(&editnurb->nurbs, &nu, &bezt, &bp);
-
- if ((nu == NULL) || (nu->type == CU_BEZIER && bezt == NULL) || (nu->type != CU_BEZIER && bp == NULL)) {
- if (mode != 'e') {
- if (cu->actnu != CU_ACT_NONE)
- nu = BLI_findlink(&editnurb->nurbs, cu->actnu);
-
- if (!nu || nu->type == CU_BEZIER) {
- newbezt = (BezTriple *)MEM_callocN(sizeof(BezTriple), "addvert_Nurb");
- newbezt->radius = 1;
- newbezt->alfa = 0;
- BEZ_SEL(newbezt);
- newbezt->h2 = newbezt->h1 = HD_AUTO;
-
- newnu = (Nurb *)MEM_callocN(sizeof(Nurb), "addvert_Nurb newnu");
- if (!nu) {
- /* no selected segment -- create new one which is BEZIER type
- * type couldn't be determined from Curve bt could be changed
- * in the future, so shouldn't make much headache */
- newnu->type = CU_BEZIER;
- newnu->resolu = cu->resolu;
- newnu->flag |= CU_SMOOTH;
- }
- else {
- memcpy(newnu, nu, sizeof(Nurb));
- }
+ Nurb *cu_actnu;
+ union {
+ BezTriple *bezt;
+ BPoint *bp;
+ void *p;
+ } cu_actvert;
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bezt = newbezt;
- newnu->pntsu = 1;
+ if (BLI_listbase_is_empty(&editnurb->nurbs)) {
+ return changed;
+ }
- temp[0] = 1;
- temp[1] = 0;
- temp[2] = 0;
+ BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
+ BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
- copy_v3_v3(newbezt->vec[1], location);
- sub_v3_v3v3(newbezt->vec[0], newbezt->vec[1], temp);
- add_v3_v3v3(newbezt->vec[2], newbezt->vec[1], temp);
+ /* first pass (endpoints) */
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- mul_m4_v3(imat, newbezt->vec[0]);
- mul_m4_v3(imat, newbezt->vec[1]);
- mul_m4_v3(imat, newbezt->vec[2]);
+ if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
+ continue;
+ }
- ok = 1;
- nu = newnu;
- }
- else if (nu->pntsv == 1) {
- newbp = (BPoint *)MEM_callocN(sizeof(BPoint), "addvert_Nurb5");
- newbp->radius = 1;
- newbp->alfa = 0;
- newbp->f1 |= SELECT;
+ if (nu->type == CU_BEZIER) {
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
- memcpy(newnu, nu, sizeof(Nurb));
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bp = newbp;
- newnu->orderu = 2;
- newnu->pntsu = 1;
+ /* Check to see if the first bezier point is selected */
+ if (nu->pntsu > 0 && nu->bezt != NULL) {
+ BezTriple *nu_bezt_old = nu->bezt;
+ BezTriple *bezt = nu->bezt;
- mul_v3_m4v3(newbp->vec, imat, location);
- newbp->vec[3] = 1.0;
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ BezTriple *bezt_new;
+ BEZT_DESEL_ALL(bezt);
- newnu->knotsu = newnu->knotsv = NULL;
- BKE_nurb_knot_calc_u(newnu);
+ bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
+ ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu);
+ *bezt_new = *bezt;
- ok = 1;
- nu = newnu;
+
+ MEM_freeN(nu->bezt);
+ nu->bezt = bezt_new;
+
+ nu->pntsu += 1;
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
+ cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
+ bezt_new : &nu->bezt[(cu_actvert.bezt - nu_bezt_old) + 1];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
+ }
+
+ BEZT_SEL_ALL(bezt_new);
+ changed = true;
+ }
}
+ /* Check to see if the last bezier point is selected */
+ if (nu->pntsu > 1) {
+ BezTriple *nu_bezt_old = nu->bezt;
+ BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
+
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ BezTriple *bezt_new;
+ BEZT_DESEL_ALL(bezt);
+
+ bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
+ ED_curve_beztcpy(editnurb, bezt_new, nu->bezt, nu->pntsu);
+ bezt_new[nu->pntsu] = *bezt;
+
+ MEM_freeN(nu->bezt);
+ nu->bezt = bezt_new;
+
+ bezt_new += nu->pntsu;
+ nu->pntsu += 1;
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
+ cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
+ bezt_new : &nu->bezt[cu_actvert.bezt - nu_bezt_old];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
+ }
+
+ BEZT_SEL_ALL(bezt_new);
+ changed = true;
+ }
+ }
}
+ else {
- if (!ok)
- return OPERATOR_CANCELLED;
- }
+ /* Check to see if the first bpoint is selected */
+ if (nu->pntsu > 0 && nu->bp != NULL) {
+ BPoint *nu_bp_old = nu->bp;
+ BPoint *bp = nu->bp;
- if (!ok && nu->type == CU_BEZIER) {
- /* which bezpoint? */
- if (bezt == &nu->bezt[nu->pntsu - 1]) { /* last */
- BEZ_DESEL(bezt);
- newbezt = (BezTriple *)MEM_callocN((nu->pntsu + 1) * sizeof(BezTriple), "addvert_Nurb");
- ED_curve_beztcpy(editnurb, newbezt, nu->bezt, nu->pntsu);
- newbezt[nu->pntsu] = *bezt;
- copy_v3_v3(temp, bezt->vec[1]);
- MEM_freeN(nu->bezt);
- nu->bezt = newbezt;
- newbezt += nu->pntsu;
- BEZ_SEL(newbezt);
- newbezt->h1 = newbezt->h2;
- bezt = &nu->bezt[nu->pntsu - 1];
- ok = 1;
+ if (bp->f1 & SELECT) {
+ BPoint *bp_new;
+ bp->f1 &= ~SELECT;
- if (nu->pntsu > 1) {
- bezt_recalc[1] = newbezt;
- bezt_recalc[0] = newbezt - 1;
- }
- }
- else if (bezt == nu->bezt) { /* first */
- BEZ_DESEL(bezt);
- newbezt = (BezTriple *)MEM_callocN((nu->pntsu + 1) * sizeof(BezTriple), "addvert_Nurb");
- ED_curve_beztcpy(editnurb, newbezt + 1, bezt, nu->pntsu);
- *newbezt = *bezt;
- BEZ_SEL(newbezt);
- newbezt->h2 = newbezt->h1;
- copy_v3_v3(temp, bezt->vec[1]);
- MEM_freeN(nu->bezt);
- nu->bezt = newbezt;
- bezt = newbezt + 1;
- ok = 1;
+ bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
+ ED_curve_bpcpy(editnurb, bp_new + 1, bp, nu->pntsu);
+ *bp_new = *bp;
+
+ MEM_freeN(nu->bp);
+ nu->bp = bp_new;
+
+ nu->pntsu += 1;
+ BKE_nurb_knot_calc_u(nu);
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
+ cu_actvert.bp = (cu_actvert.bp == bp) ?
+ bp_new : &nu->bp[(cu_actvert.bp - nu_bp_old) + 1];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
+ }
+ bp_new->f1 |= SELECT;
+ changed = true;
+ }
+ }
+
+ /* Check to see if the last bpoint is selected */
if (nu->pntsu > 1) {
- bezt_recalc[1] = newbezt;
- bezt_recalc[2] = newbezt + 1;
+ BPoint *nu_bp_old = nu->bp;
+ BPoint *bp = &nu->bp[nu->pntsu - 1];
+
+ if (bp->f1 & SELECT) {
+ BPoint *bp_new;
+ bp->f1 &= ~SELECT;
+
+ bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
+ ED_curve_bpcpy(editnurb, bp_new, nu->bp, nu->pntsu);
+ bp_new[nu->pntsu] = *bp;
+
+ MEM_freeN(nu->bp);
+ nu->bp = bp_new;
+
+ bp_new += nu->pntsu;
+ nu->pntsu += 1;
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
+ cu_actvert.bp = (cu_actvert.bp == bp) ?
+ bp_new : &nu->bp[cu_actvert.bp - nu_bp_old];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+
+ bp_new->f1 |= SELECT;
+ changed = true;
+ }
}
}
- else if (mode != 'e') {
- BEZ_DESEL(bezt);
- newbezt = (BezTriple *)MEM_callocN(sizeof(BezTriple), "addvert_Nurb");
- *newbezt = *bezt;
- BEZ_SEL(newbezt);
- newbezt->h2 = newbezt->h1;
- copy_v3_v3(temp, bezt->vec[1]);
+ }
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
- memcpy(newnu, nu, sizeof(Nurb));
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bezt = newbezt;
- newnu->pntsu = 1;
+ /* second pass (interior points) */
+ nu_last = editnurb->nurbs.last;
+ for (nu = editnurb->nurbs.first; (nu != nu_last->next); nu = nu->next) {
+ int i, i_end;
- nu = newnu;
- bezt = newbezt;
- ok = 1;
+ if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
+ /* all points are interior */
+ i = 0;
+ i_end = nu->pntsu;
}
else {
- bezt = NULL;
+ /* skip endpoints */
+ i = 1;
+ i_end = nu->pntsu - 1;
}
- if (bezt) {
- if (!newnu) nu->pntsu++;
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
- if (mode == 'e') {
- copy_v3_v3(newbezt->vec[0], bezt->vec[0]);
- copy_v3_v3(newbezt->vec[1], bezt->vec[1]);
- copy_v3_v3(newbezt->vec[2], bezt->vec[2]);
- }
- else {
- mul_v3_m4v3(newbezt->vec[1], imat, location);
- sub_v3_v3v3(temp, newbezt->vec[1], temp);
+ for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ Nurb *nurb_new;
+ BezTriple *bezt_new;
+
+ BEZT_DESEL_ALL(bezt);
+ nurb_new = BKE_nurb_copy(nu, 1, 1);
+ nurb_new->flagu &= ~CU_NURB_CYCLIC;
+ BLI_addtail(&editnurb->nurbs, nurb_new);
+ bezt_new = nurb_new->bezt;
+ ED_curve_beztcpy(editnurb, bezt_new, bezt, 1);
+ BEZT_SEL_ALL(bezt_new);
+
+ if (cu_actvert.bezt == bezt || cu_actnu == NULL) {
+ BKE_curve_nurb_vert_active_set(cu, nurb_new, bezt_new);
+ }
- if (bezt_recalc[1]) {
- const char h1 = bezt_recalc[1]->h1, h2 = bezt_recalc[1]->h2;
- bezt_recalc[1]->h1 = bezt_recalc[1]->h2 = HD_AUTO;
- BKE_nurb_handle_calc(bezt_recalc[1], bezt_recalc[0], bezt_recalc[2], 0);
- bezt_recalc[1]->h1 = h1;
- bezt_recalc[1]->h2 = h2;
- }
- else {
- add_v3_v3v3(newbezt->vec[0], bezt->vec[0], temp);
- add_v3_v3v3(newbezt->vec[2], bezt->vec[2], temp);
+ changed = true;
}
-
+ }
+ }
+ else {
+ BPoint *bp;
+
+ for (bp = &nu->bp[i]; i < i_end; i++, bp++) {
+ if (bp->f1 & SELECT) {
+ Nurb *nurb_new;
+ BPoint *bp_new;
+
+ bp->f1 &= ~SELECT;
+ nurb_new = BKE_nurb_copy(nu, 1, 1);
+ nurb_new->flagu &= ~CU_NURB_CYCLIC;
+ BLI_addtail(&editnurb->nurbs, nurb_new);
+ bp_new = nurb_new->bp;
+ ED_curve_bpcpy(editnurb, bp_new, bp, 1);
+ bp_new->f1 |= SELECT;
+
+ if (cu_actvert.bp == bp || cu_actnu == NULL) {
+ BKE_curve_nurb_vert_active_set(cu, nurb_new, bp_new);
+ }
- if (newnu) BKE_nurb_handles_calc(newnu);
- else BKE_nurb_handles_calc(nu);
+ changed = true;
+ }
}
}
}
- else if (!ok && nu->pntsv == 1) {
- /* which b-point? */
- if (bp == &nu->bp[nu->pntsu - 1]) { /* last */
- bp->f1 = 0;
- newbp = (BPoint *)MEM_callocN((nu->pntsu + 1) * sizeof(BPoint), "addvert_Nurb4");
- ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
- newbp[nu->pntsu] = *bp;
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- newbp += nu->pntsu;
- newbp->f1 |= SELECT;
- bp = newbp - 1;
- ok = 1;
- }
- else if (bp == nu->bp) { /* first */
- bp->f1 = 0;
- newbp = (BPoint *)MEM_callocN((nu->pntsu + 1) * sizeof(BPoint), "addvert_Nurb3");
- ED_curve_bpcpy(editnurb, newbp + 1, bp, nu->pntsu);
- *newbp = *bp;
- newbp->f1 |= SELECT;
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- bp = newbp + 1;
- ok = 1;
- }
- else if (mode != 'e') {
- bp->f1 = 0;
- newbp = (BPoint *)MEM_callocN(sizeof(BPoint), "addvert_Nurb5");
- *newbp = *bp;
- newbp->f1 |= SELECT;
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
- memcpy(newnu, nu, sizeof(Nurb));
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bp = newbp;
- newnu->orderu = 2;
- newnu->pntsu = 1;
- newnu->knotsu = newnu->knotsv = NULL;
+ if (changed == false) {
+ BKE_curve_nurb_vert_active_set(cu, cu_actnu, cu_actvert.p);
+ }
- nu = newnu;
- bp = newbp;
- ok = 1;
+ return changed;
+}
+
+/***************** add vertex operator **********************/
+
+static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float location[3])
+{
+ Nurb *nu;
+
+ float minmax[2][3];
+ float temp[3];
+ bool nu_has_select = false;
+
+ bool changed = false;
+
+ INIT_MINMAX(minmax[0], minmax[1]);
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ int i;
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+
+ for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ minmax_v3v3_v3(UNPACK2(minmax), bezt->vec[1]);
+ nu_has_select = true;
+ }
+ }
}
else {
- bp = NULL;
+ BPoint *bp;
+
+ for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
+ if (bp->f1 & SELECT) {
+ minmax_v3v3_v3(UNPACK2(minmax), bp->vec);
+ nu_has_select = true;
+ }
+ }
}
+ }
+
+ if (nu_has_select && ed_editcurve_extrude(cu, editnurb)) {
+ float ofs[3], center[3];
+ int i;
+
+ mid_v3_v3v3(center, minmax[0], minmax[1]);
+ sub_v3_v3v3(ofs, location, center);
- if (bp) {
- if (mode == 'e') {
- copy_v3_v3(newbp->vec, bp->vec);
+ if ((cu->flag & CU_3D) == 0) {
+ ofs[2] = 0.0f;
+ }
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ add_v3_v3(bezt->vec[0], ofs);
+ add_v3_v3(bezt->vec[1], ofs);
+ add_v3_v3(bezt->vec[2], ofs);
+
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) &&
+ (i == 0 || i == nu->pntsu - 1))
+ {
+ BKE_nurb_handle_calc_simple_auto(nu, bezt);
+ }
+ }
+ }
}
else {
- mul_v3_m4v3(newbp->vec, imat, location);
- newbp->vec[3] = 1.0;
+ BPoint *bp;
- if (!newnu && nu->orderu < 4 && nu->orderu <= nu->pntsu)
- nu->orderu++;
+ for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
+ if (bp->f1 & SELECT) {
+ add_v3_v3(bp->vec, ofs);
+ }
+ }
}
+ }
+ changed = true;
+ }
+ else {
+ /* nothing selected: create a new curve */
+ nu = BKE_curve_nurb_active_get(cu);
- if (!newnu) {
- nu->pntsu++;
- BKE_nurb_knot_calc_u(nu);
+ if (!nu || nu->type == CU_BEZIER) {
+ Nurb *nurb_new;
+ BezTriple *bezt_new;
+
+ if (nu) {
+ nurb_new = BKE_nurb_copy(nu, 1, 1);
}
else {
- BKE_nurb_knot_calc_u(newnu);
+ nurb_new = MEM_callocN(sizeof(Nurb), "BLI_editcurve_addvert new_bezt_nurb 2");
+ nurb_new->type = CU_BEZIER;
+ nurb_new->resolu = cu->resolu;
+ nurb_new->orderu = 4;
+ nurb_new->flag |= CU_SMOOTH;
+ BKE_nurb_bezierPoints_add(nurb_new, 1);
}
- }
- }
+ BLI_addtail(&editnurb->nurbs, nurb_new);
- if (ok) {
- if (nu->bezt) {
- BKE_curve_nurb_vert_active_set(cu, nu, newbezt);
+ bezt_new = nurb_new->bezt;
+
+ BEZT_SEL_ALL(bezt_new);
+
+ bezt_new->h1 = HD_AUTO;
+ bezt_new->h2 = HD_AUTO;
+
+ temp[0] = 1.0f;
+ temp[1] = 0.0f;
+ temp[2] = 0.0f;
+
+ copy_v3_v3(bezt_new->vec[1], location);
+ sub_v3_v3v3(bezt_new->vec[0], bezt_new->vec[1], temp);
+ add_v3_v3v3(bezt_new->vec[2], bezt_new->vec[1], temp);
+
+ changed = true;
}
else {
- BKE_curve_nurb_vert_active_set(cu, nu, newbp);
- }
+ Nurb *nurb_new;
+ BPoint *bp_new;
- BKE_nurb_test2D(nu);
+ {
+ nurb_new = MEM_callocN(sizeof(Nurb), __func__);
+ nurb_new->type = CU_POLY;
+ nurb_new->resolu = cu->resolu;
+ nurb_new->flag |= CU_SMOOTH;
+ nurb_new->orderu = 4;
+ BKE_nurb_points_add(nurb_new, 1);
+ }
+ BLI_addtail(&editnurb->nurbs, nurb_new);
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ bp_new = nurb_new->bp;
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ bp_new->f1 |= SELECT;
- return OPERATOR_FINISHED;
+ copy_v3_v3(bp_new->vec, location);
+ bp_new->vec[3] = 1.0f;
+
+ BKE_nurb_knot_calc_u(nurb_new);
+
+ changed = true;
+ }
}
- return OPERATOR_CANCELLED;
+ return changed;
}
static int add_vertex_exec(bContext *C, wmOperator *op)
{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = obedit->data;
+ EditNurb *editnurb = cu->editnurb;
float location[3];
+ float imat[4][4];
RNA_float_get_array(op->ptr, "location", location);
- return addvert_Nurb(C, 0, location);
+
+ invert_m4_m4(imat, obedit->obmat);
+ mul_m4_v3(imat, location);
+
+ if (ed_editcurve_addvert(cu, editnurb, location)) {
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -5196,7 +4849,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cu = vc.obedit->data;
- findselectedNurbvert(&cu->editnurb->nurbs, &nu, &bezt, &bp);
+ findselectedNurbvert(cu, &nu, &bezt, &bp);
if (bezt) {
mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]);
@@ -5239,34 +4892,47 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Location to add new vertex at", -1e4, 1e4);
+ RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Location", "Location to add new vertex at", -1.0e4f, 1.0e4f);
}
/***************** extrude operator **********************/
-static int extrude_exec(bContext *C, wmOperator *UNUSED(op))
+static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
- Nurb *nu;
+ bool changed = false;
+ bool as_curve = false;
/* first test: curve? */
- for (nu = editnurb->nurbs.first; nu; nu = nu->next)
- if (nu->pntsv == 1 && isNurbsel_count(cu, nu) == 1)
- break;
+ if (obedit->type != OB_CURVE) {
+ Nurb *nu;
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if ((nu->pntsv == 1) &&
+ (ED_curve_nurb_select_count(cu, nu) == 1))
+ {
+ as_curve = true;
+ break;
+ }
+ }
+ }
- if (obedit->type == OB_CURVE || nu) {
- addvert_Nurb(C, 'e', NULL);
+ if (obedit->type == OB_CURVE || as_curve) {
+ changed = ed_editcurve_extrude(cu, editnurb);
}
else {
- if (ed_editnurb_extrude_flag(editnurb, 1)) { /* '1'= flag */
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ changed = ed_editnurb_extrude_flag(editnurb, SELECT);
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ if (changed) {
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
}
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
@@ -5280,7 +4946,7 @@ void CURVE_OT_extrude(wmOperatorType *ot)
ot->idname = "CURVE_OT_extrude";
/* api callbacks */
- ot->exec = extrude_exec;
+ ot->exec = curve_extrude_exec;
ot->poll = ED_operator_editsurfcurve;
/* flags */
@@ -5319,7 +4985,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
nu->flagu ^= CU_NURB_CYCLIC;
break;
}
@@ -5382,11 +5048,11 @@ static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
for (nu = editnurb->first; nu; nu = nu->next) {
if (nu->pntsu > 1 || nu->pntsv > 1) {
if (nu->type == CU_NURBS) {
- pup = uiPupMenuBegin(C, IFACE_("Direction"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Direction"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, op->type->idname, "direction");
- uiPupMenuEnd(C, pup);
- return OPERATOR_CANCELLED;
+ UI_popup_menu_end(C, pup);
+ return OPERATOR_INTERFACE;
}
}
}
@@ -5420,708 +5086,6 @@ void CURVE_OT_cyclic_toggle(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to make surface cyclic in");
}
-/***************** select linked operator ******************/
-
-static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
- EditNurb *editnurb = cu->editnurb;
- ListBase *nurbs = &editnurb->nurbs;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
-
- for (nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if ((bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT)) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- select_beztriple(bezt, SELECT, SELECT, VISIBLE);
- bezt++;
- }
- break;
- }
- bezt++;
- }
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- if (bp->f1 & SELECT) {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
- bp++;
- }
- break;
- }
- bp++;
- }
- }
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- return select_linked_exec(C, op);
-}
-
-void CURVE_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked All";
- ot->idname = "CURVE_OT_select_linked";
- ot->description = "Select all control points linked to active one";
-
- /* api callbacks */
- ot->exec = select_linked_exec;
- ot->invoke = select_linked_invoke;
- ot->poll = ED_operator_editsurfcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
-}
-
-
-/***************** select linked pick operator ******************/
-
-static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *obedit = CTX_data_edit_object(C);
- ViewContext vc;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
- const bool select = !RNA_boolean_get(op->ptr, "deselect");
-
- view3d_operator_needs_opengl(C);
- view3d_set_viewcontext(C, &vc);
-
- findnearestNurbvert(&vc, 1, event->mval, &nu, &bezt, &bp);
-
- if (bezt) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- select_beztriple(bezt, select, SELECT, VISIBLE);
- bezt++;
- }
- }
- else if (bp) {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- select_bpoint(bp, select, SELECT, VISIBLE);
- bp++;
- }
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- if (!select) {
- BKE_curve_nurb_vert_active_validate(obedit->data);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_linked_pick(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked";
- ot->idname = "CURVE_OT_select_linked_pick";
- ot->description = "Select all control points linked to already selected ones";
-
- /* api callbacks */
- ot->invoke = select_linked_pick_invoke;
- ot->poll = ED_operator_editsurfcurve_region_view3d;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked control points rather than selecting them");
-}
-
-/***************** select row operator **********************/
-
-static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
- static BPoint *last = NULL;
- static int direction = 0;
- Nurb *nu = NULL;
- BPoint *bp = NULL;
- int u = 0, v = 0, a, b;
-
- if (!BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bp))
- return OPERATOR_CANCELLED;
-
- if (last == bp) {
- direction = 1 - direction;
- BKE_nurbList_flag_set(editnurb, 0);
- }
- last = bp;
-
- u = cu->actvert % nu->pntsu;
- v = cu->actvert / nu->pntsu;
- bp = nu->bp;
- for (a = 0; a < nu->pntsv; a++) {
- for (b = 0; b < nu->pntsu; b++, bp++) {
- if (direction) {
- if (a == v) select_bpoint(bp, SELECT, SELECT, VISIBLE);
- }
- else {
- if (b == u) select_bpoint(bp, SELECT, SELECT, VISIBLE);
- }
- }
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_row(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Control Point Row";
- ot->idname = "CURVE_OT_select_row";
- ot->description = "Select a row of control points including active one";
-
- /* api callbacks */
- ot->exec = select_row_exec;
- ot->poll = ED_operator_editsurf;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/***************** select next operator **********************/
-
-static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
-
- select_adjacent_cp(editnurb, 1, 0, SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_next(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Next";
- ot->idname = "CURVE_OT_select_next";
- ot->description = "Select control points following already selected ones along the curves";
-
- /* api callbacks */
- ot->exec = select_next_exec;
- ot->poll = ED_operator_editcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/***************** select previous operator **********************/
-
-static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
-
- select_adjacent_cp(editnurb, -1, 0, SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_previous(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Previous";
- ot->idname = "CURVE_OT_select_previous";
- ot->description = "Select control points preceding already selected ones along the curves";
-
- /* api callbacks */
- ot->exec = select_previous_exec;
- ot->poll = ED_operator_editcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/***************** select more operator **********************/
-
-static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
- BPoint *bp, *tempbp;
- int a;
- short sel = 0;
-
- /* note that NURBS surface is a special case because we mimic */
- /* the behavior of "select more" of mesh tools. */
- /* The algorithm is designed to work in planar cases so it */
- /* may not be optimal always (example: end of NURBS sphere) */
- if (obedit->type == OB_SURF) {
- for (nu = editnurb->first; nu; nu = nu->next) {
- BLI_bitmap *selbpoints;
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- selbpoints = BLI_BITMAP_NEW(a, "selectlist");
- while (a > 0) {
- if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
- /* upper control point */
- if (a % nu->pntsu != 0) {
- tempbp = bp - 1;
- if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
- }
-
- /* left control point. select only if it is not selected already */
- if (a - nu->pntsu > 0) {
- sel = 0;
- tempbp = bp + nu->pntsu;
- if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
- /* make sure selected bpoint is discarded */
- if (sel == 1) BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu);
- }
-
- /* right control point */
- if (a + nu->pntsu < nu->pntsu * nu->pntsv) {
- tempbp = bp - nu->pntsu;
- if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
- }
-
- /* lower control point. skip next bp in case selection was made */
- if (a % nu->pntsu != 1) {
- sel = 0;
- tempbp = bp + 1;
- if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
- if (sel) {
- bp++;
- a--;
- }
- }
- }
-
- bp++;
- a--;
- }
-
- MEM_freeN(selbpoints);
- }
- }
- else {
- select_adjacent_cp(editnurb, 1, 0, SELECT);
- select_adjacent_cp(editnurb, -1, 0, SELECT);
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_more(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select More";
- ot->idname = "CURVE_OT_select_more";
- ot->description = "Select control points directly linked to already selected ones";
-
- /* api callbacks */
- ot->exec = select_more_exec;
- ot->poll = ED_operator_editsurfcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/******************** select less operator *****************/
-
-/* basic method: deselect if control point doesn't have all neighbors selected */
-static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int a;
- int sel = 0;
- short lastsel = false;
-
- if (obedit->type == OB_SURF) {
- for (nu = editnurb->first; nu; nu = nu->next) {
- BLI_bitmap *selbpoints;
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- selbpoints = BLI_BITMAP_NEW(a, "selectlist");
- while (a--) {
- if ((bp->hide == 0) && (bp->f1 & SELECT)) {
- sel = 0;
-
- /* check if neighbors have been selected */
- /* edges of surface are an exception */
- if ((a + 1) % nu->pntsu == 0) {
- sel++;
- }
- else {
- bp--;
- if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
- bp++;
- }
-
- if ((a + 1) % nu->pntsu == 1) {
- sel++;
- }
- else {
- bp++;
- if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
- bp--;
- }
-
- if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) {
- sel++;
- }
- else {
- bp -= nu->pntsu;
- if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
- bp += nu->pntsu;
- }
-
- if (a < nu->pntsu) {
- sel++;
- }
- else {
- bp += nu->pntsu;
- if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
- bp -= nu->pntsu;
- }
-
- if (sel != 4) {
- select_bpoint(bp, DESELECT, SELECT, VISIBLE);
- BLI_BITMAP_ENABLE(selbpoints, a);
- }
- }
- else {
- lastsel = false;
- }
-
- bp++;
- }
-
- MEM_freeN(selbpoints);
- }
- }
- else {
- for (nu = editnurb->first; nu; nu = nu->next) {
- lastsel = false;
- /* check what type of curve/nurb it is */
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
- sel = (lastsel == 1);
-
- /* check if neighbors have been selected */
- /* first and last are exceptions */
- if (a == nu->pntsu - 1) {
- sel++;
- }
- else {
- bezt--;
- if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
- bezt++;
- }
-
- if (a == 0) {
- sel++;
- }
- else {
- bezt++;
- if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
- bezt--;
- }
-
- if (sel != 2) {
- select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
- lastsel = true;
- }
- else {
- lastsel = false;
- }
- }
- else {
- lastsel = false;
- }
-
- bezt++;
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) {
- if (lastsel != 0) sel = 1;
- else sel = 0;
-
- /* first and last are exceptions */
- if (a == nu->pntsu * nu->pntsv - 1) {
- sel++;
- }
- else {
- bp--;
- if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
- bp++;
- }
-
- if (a == 0) {
- sel++;
- }
- else {
- bp++;
- if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
- bp--;
- }
-
- if (sel != 2) {
- select_bpoint(bp, DESELECT, SELECT, VISIBLE);
- lastsel = true;
- }
- else {
- lastsel = false;
- }
- }
- else {
- lastsel = false;
- }
-
- bp++;
- }
- }
- }
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_less(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Less";
- ot->idname = "CURVE_OT_select_less";
- ot->description = "Reduce current selection by deselecting boundary elements";
-
- /* api callbacks */
- ot->exec = select_less_exec;
- ot->poll = ED_operator_editsurfcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** select random *********************/
-
-static void curve_select_random(ListBase *editnurb, float randfac, bool select)
-{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
-
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (!bezt->hide) {
- if (BLI_frand() < randfac) {
- select_beztriple(bezt, select, SELECT, VISIBLE);
- }
- }
- bezt++;
- }
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
-
- while (a--) {
- if (!bp->hide) {
- if (BLI_frand() < randfac) {
- select_bpoint(bp, select, SELECT, VISIBLE);
- }
- }
- bp++;
- }
- }
- }
-}
-
-static int curve_select_random_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
- const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
-
- curve_select_random(editnurb, randfac, select);
- BKE_curve_nurb_vert_active_validate(obedit->data);
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_random(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Random";
- ot->idname = "CURVE_OT_select_random";
- ot->description = "Randomly select some control points";
-
- /* api callbacks */
- ot->exec = curve_select_random_exec;
- ot->poll = ED_operator_editsurfcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
- WM_operator_properties_select_action_simple(ot, SEL_SELECT);
-}
-
-/********************* every nth number of point *******************/
-
-static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
-{
- int a, start;
-
- start = bezt - nu->bezt;
- a = nu->pntsu;
- bezt = &nu->bezt[a - 1];
-
- while (a--) {
- if (abs(start - a) % nth) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
- }
-
- bezt--;
- }
-}
-
-static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
-{
- int a, startrow, startpnt;
- int dist, row, pnt;
-
- startrow = (bp - nu->bp) / nu->pntsu;
- startpnt = (bp - nu->bp) % nu->pntsu;
-
- a = nu->pntsu * nu->pntsv;
- bp = &nu->bp[a - 1];
- row = nu->pntsv - 1;
- pnt = nu->pntsu - 1;
-
- while (a--) {
- dist = abs(pnt - startpnt) + abs(row - startrow);
- if (dist % nth) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
- }
-
- pnt--;
- if (pnt < 0) {
- pnt = nu->pntsu - 1;
- row--;
- }
-
- bp--;
- }
-}
-
-bool ED_curve_select_nth(Curve *cu, int nth)
-{
- Nurb *nu = NULL;
- void *vert = NULL;
-
- if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert))
- return false;
-
- if (nu->bezt) {
- select_nth_bezt(nu, vert, nth);
- }
- else {
- select_nth_bp(nu, vert, nth);
- }
-
- return true;
-}
-
-static int select_nth_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- int nth = RNA_int_get(op->ptr, "nth");
-
- if (!ED_curve_select_nth(obedit->data, nth)) {
- if (obedit->type == OB_SURF) {
- BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Curve has not got active point");
- }
-
- return OPERATOR_CANCELLED;
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void CURVE_OT_select_nth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Checker Deselect";
- ot->description = "Deselect every other vertex";
- ot->idname = "CURVE_OT_select_nth";
-
- /* api callbacks */
- ot->exec = select_nth_exec;
- ot->poll = ED_operator_editsurfcurve;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
-}
-
/********************** add duplicate operator *********************/
static int duplicate_exec(bContext *C, wmOperator *op)
@@ -6189,12 +5153,12 @@ static int curve_delete_segments(Object *obedit, const bool split)
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (!BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ if (!BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
enda = a;
if (starta == -1) starta = a;
if (a < nu->pntsu - 1) continue;
}
- else if (a < nu->pntsu - 1 && !BEZSELECTED_HIDDENHANDLES(cu, bezt + 1)) {
+ else if (a < nu->pntsu - 1 && !BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt + 1)) {
/* if just single selected point then continue */
continue;
}
@@ -6218,8 +5182,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt2 = &nu->bezt[nu->pntsu - 2];
if ((nu->flagu & CU_NURB_CYCLIC) &&
- BEZSELECTED_HIDDENHANDLES(cu, bezt1) &&
- BEZSELECTED_HIDDENHANDLES(cu, bezt2))
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
{
/* check if need to join start of spline to end */
nu1 = BKE_nurb_copy(nu, cut + 1, 1);
@@ -6240,8 +5204,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt2 = &nu->bezt[1];
if ((nu->flagu & CU_NURB_CYCLIC) &&
- BEZSELECTED_HIDDENHANDLES(cu, bezt1) &&
- BEZSELECTED_HIDDENHANDLES(cu, bezt2))
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
{
/* check if need to join start of spline to end */
nu1 = BKE_nurb_copy(nu, cut + 1, 1);
@@ -6281,8 +5245,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt1 = nu->bezt;
bezt2 = &nu->bezt[1];
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt1) &&
- BEZSELECTED_HIDDENHANDLES(cu, bezt2))
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
{
nu1 = BKE_nurb_copy(nu, 1, 1);
ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1);
@@ -6292,8 +5256,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt1 = &nu->bezt[nu->pntsu - 1];
bezt2 = &nu->bezt[nu->pntsu - 2];
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt1) &&
- BEZSELECTED_HIDDENHANDLES(cu, bezt2))
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
{
nu1 = BKE_nurb_copy(nu, 1, 1);
ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1);
@@ -6551,7 +5515,6 @@ static int curve_delete_segments(Object *obedit, const bool split)
}
}
- nu->knotsu = nu->knotsv = NULL;
BKE_nurb_order_clamp_u(nu);
BKE_nurb_knot_calc_u(nu);
@@ -6648,13 +5611,13 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
- int clear = (strcmp(op->idname, "CURVE_OT_shade_flat") == 0);
+ int clear = (STREQ(op->idname, "CURVE_OT_shade_flat"));
if (obedit->type != OB_CURVE)
return OPERATOR_CANCELLED;
for (nu = editnurb->first; nu; nu = nu->next) {
- if (isNurbsel(nu)) {
+ if (ED_curve_nurb_select_check(obedit->data, nu)) {
if (!clear) nu->flag |= CU_SMOOTH;
else nu->flag &= ~CU_SMOOTH;
}
@@ -6812,7 +5775,7 @@ static int clear_tilt_exec(bContext *C, wmOperator *UNUSED(op))
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) bezt->alfa = 0.0;
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) bezt->alfa = 0.0;
bezt++;
}
}
@@ -6889,6 +5852,7 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
cu->actvert = undoCurve->actvert;
cu->actnu = undoCurve->actnu;
+ cu->flag = undoCurve->flag;
ED_curve_updateAnimPaths(cu);
}
@@ -6928,6 +5892,7 @@ static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v)
undoCurve->actvert = cu->actvert;
undoCurve->actnu = cu->actnu;
+ undoCurve->flag = cu->flag;
return undoCurve;
}
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 8a3d4f3f4f5..5347ef05105 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -38,7 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -71,20 +71,20 @@ static const char *get_curve_defname(int type)
if ((type & CU_TYPE) == CU_BEZIER) {
switch (stype) {
- case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "BezierCurve");
- case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "BezierCircle");
- case CU_PRIM_PATH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "CurvePath");
+ case CU_PRIM_CURVE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "BezierCurve");
+ case CU_PRIM_CIRCLE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "BezierCircle");
+ case CU_PRIM_PATH: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "CurvePath");
default:
- return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Curve");
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "Curve");
}
}
else {
switch (stype) {
- case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsCurve");
- case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsCircle");
- case CU_PRIM_PATH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsPath");
+ case CU_PRIM_CURVE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "NurbsCurve");
+ case CU_PRIM_CIRCLE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "NurbsCircle");
+ case CU_PRIM_PATH: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "NurbsPath");
default:
- return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Curve");
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "Curve");
}
}
}
@@ -94,13 +94,13 @@ static const char *get_surf_defname(int type)
int stype = type & CU_PRIMITIVE;
switch (stype) {
- case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfCurve");
- case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfCircle");
- case CU_PRIM_PATCH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfPatch");
- case CU_PRIM_SPHERE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfSphere");
- case CU_PRIM_DONUT: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfTorus");
+ case CU_PRIM_CURVE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "SurfCurve");
+ case CU_PRIM_CIRCLE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "SurfCircle");
+ case CU_PRIM_PATCH: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "SurfPatch");
+ case CU_PRIM_SPHERE: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "SurfSphere");
+ case CU_PRIM_DONUT: return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "SurfTorus");
default:
- return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Surface");
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE, "Surface");
}
}
@@ -121,7 +121,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
const float grid = 1.0f;
const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc
const int stype = (type & CU_PRIMITIVE);
- const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */
+ const bool force_3d = (((Curve *)obedit->data)->flag & CU_3D) != 0; /* could be adding to an existing 3D curve */
unit_m4(umat);
unit_m4(viewmat);
@@ -355,10 +355,10 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
mul_mat3_m4_v3(mat, vec);
- ed_editnurb_translate_flag(editnurb, 1, vec);
- ed_editnurb_extrude_flag(cu->editnurb, 1);
+ ed_editnurb_translate_flag(editnurb, SELECT, vec);
+ ed_editnurb_extrude_flag(cu->editnurb, SELECT);
mul_v3_fl(vec, -2.0f);
- ed_editnurb_translate_flag(editnurb, 1, vec);
+ ed_editnurb_translate_flag(editnurb, SELECT, vec);
BLI_remlink(editnurb, nu);
@@ -460,7 +460,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
if (nu) { /* should always be set */
nu->flag |= CU_SMOOTH;
- cu->actnu = BLI_countlist(editnurb);
+ cu->actnu = BLI_listbase_count(editnurb);
cu->actvert = CU_ACT_NONE;
BKE_nurb_test2D(nu);
@@ -488,9 +488,10 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
if (!isSurf) { /* adding curve */
if (obedit == NULL || obedit->type != OB_CURVE) {
+ const char *name = get_curve_defname(type);
Curve *cu;
- obedit = ED_object_add_type(C, OB_CURVE, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_CURVE, name, loc, rot, true, layer);
newob = true;
cu = (Curve *)obedit->data;
@@ -505,7 +506,8 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
else { /* adding surface */
if (obedit == NULL || obedit->type != OB_SURF) {
- obedit = ED_object_add_type(C, OB_SURF, loc, rot, true, layer);
+ const char *name = get_surf_defname(type);
+ obedit = ED_object_add_type(C, OB_SURF, name, loc, rot, true, layer);
newob = true;
}
else {
@@ -513,27 +515,13 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
}
- /* rename here, the undo stack checks name for valid undo pushes */
- if (newob) {
- if (obedit->type == OB_CURVE) {
- rename_id((ID *)obedit, get_curve_defname(type));
- rename_id((ID *)obedit->data, get_curve_defname(type));
- }
- else {
- rename_id((ID *)obedit, get_surf_defname(type));
- rename_id((ID *)obedit->data, get_surf_defname(type));
- }
- }
-
/* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */
if (newob && enter_editmode)
ED_undo_push(C, "Enter Editmode");
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
dia = RNA_float_get(op->ptr, "radius");
- mat[0][0] *= dia;
- mat[1][1] *= dia;
- mat[2][2] *= dia;
+ mul_mat3_m4_fl(mat, dia);
nu = add_nurbs_primitive(C, obedit, mat, type, newob);
editnurb = object_editcurve_get(obedit);
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
new file mode 100644
index 00000000000..0f3942b0c90
--- /dev/null
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -0,0 +1,1728 @@
+/*
+ * ***** 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): John Roper
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editcurve_select.c
+ * \ingroup edcurve
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_heap.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_types.h"
+#include "ED_view3d.h"
+#include "ED_curve.h"
+
+#include "curve_intern.h"
+
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+
+/* returns 1 in case (de)selection was successful */
+bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden)
+{
+ if ((bezt->hide == 0) || (hidden == HIDDEN)) {
+ if (selstatus == SELECT) { /* selects */
+ bezt->f1 |= flag;
+ bezt->f2 |= flag;
+ bezt->f3 |= flag;
+ return true;
+ }
+ else { /* deselects */
+ bezt->f1 &= ~flag;
+ bezt->f2 &= ~flag;
+ bezt->f3 &= ~flag;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* returns 1 in case (de)selection was successful */
+bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden)
+{
+ if ((bp->hide == 0) || (hidden == 1)) {
+ if (selstatus == SELECT) {
+ bp->f1 |= flag;
+ return true;
+ }
+ else {
+ bp->f1 &= ~flag;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool swap_selection_beztriple(BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ return select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
+ else
+ return select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+}
+
+static bool swap_selection_bpoint(BPoint *bp)
+{
+ if (bp->f1 & SELECT)
+ return select_bpoint(bp, DESELECT, SELECT, VISIBLE);
+ else
+ return select_bpoint(bp, SELECT, SELECT, VISIBLE);
+}
+
+bool ED_curve_nurb_select_check(Curve *cu, Nurb *nu)
+{
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ return true;
+ }
+ }
+ }
+ else {
+ BPoint *bp;
+ int i;
+
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (bp->f1 & SELECT) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+int ED_curve_nurb_select_count(Curve *cu, Nurb *nu)
+{
+ int sel = 0;
+
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ sel++;
+ }
+ }
+ }
+ else {
+ BPoint *bp;
+ int i;
+
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (bp->f1 & SELECT) {
+ sel++;
+ }
+ }
+ }
+
+ return sel;
+}
+
+void ED_curve_nurb_select_all(Nurb *nu)
+{
+ int i;
+
+ if (nu->bezt) {
+ BezTriple *bezt;
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (bezt->hide == 0) {
+ BEZT_SEL_ALL(bezt);
+ }
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp;
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (bp->hide == 0) {
+ bp->f1 |= SELECT;
+ }
+ }
+ }
+}
+
+void ED_curve_select_all(EditNurb *editnurb)
+{
+ Nurb *nu;
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ ED_curve_nurb_select_all(nu);
+ }
+}
+
+void ED_curve_nurb_deselect_all(Nurb *nu)
+{
+ int i;
+
+ if (nu->bezt) {
+ BezTriple *bezt;
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ BEZT_DESEL_ALL(bezt);
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp;
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ bp->f1 &= ~SELECT;
+ }
+ }
+}
+
+bool ED_curve_select_check(Curve *cu, struct EditNurb *editnurb)
+{
+ Nurb *nu;
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if (ED_curve_nurb_select_check(cu, nu)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ED_curve_deselect_all(EditNurb *editnurb)
+{
+ Nurb *nu;
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ ED_curve_nurb_deselect_all(nu);
+ }
+}
+
+void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if (bezt->hide == 0) {
+ bezt->f2 ^= SELECT; /* always do the center point */
+ if (!hide_handles) {
+ bezt->f1 ^= SELECT;
+ bezt->f3 ^= SELECT;
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ swap_selection_bpoint(bp);
+ bp++;
+ }
+ }
+ }
+}
+
+/**
+ * \param next: -1/1 for prev/next
+ * \param cont: when true select continuously
+ * \param selstatus: inverts behavior
+ */
+static void select_adjacent_cp(
+ ListBase *editnurb, short next,
+ const bool cont, const bool selstatus)
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ bool lastsel = false;
+
+ if (next == 0) return;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ lastsel = false;
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ if (next < 0) bezt = &nu->bezt[a - 1];
+ while (a--) {
+ if (a - abs(next) < 0) break;
+ if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
+ bezt += next;
+ if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
+ short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
+ if ((sel == 1) && (cont == 0)) lastsel = true;
+ }
+ }
+ else {
+ bezt += next;
+ lastsel = false;
+ }
+ /* move around in zigzag way so that we go through each */
+ bezt -= (next - next / abs(next));
+ }
+ }
+ else {
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ if (next < 0) bp = &nu->bp[a - 1];
+ while (a--) {
+ if (a - abs(next) < 0) break;
+ if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
+ bp += next;
+ if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
+ short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
+ if ((sel == 1) && (cont == 0)) lastsel = true;
+ }
+ }
+ else {
+ bp += next;
+ lastsel = false;
+ }
+ /* move around in zigzag way so that we go through each */
+ bp -= (next - next / abs(next));
+ }
+ }
+ }
+}
+
+/**************** select start/end operators **************/
+
+/* (de)selects first or last of visible part of each Nurb depending on selFirst
+ * selFirst: defines the end of which to select
+ * doswap: defines if selection state of each first/last control point is swapped
+ * selstatus: selection status in case doswap is false
+ */
+static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus)
+{
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ Curve *cu;
+ int a;
+
+ if (obedit == NULL) return;
+
+ cu = (Curve *)obedit->data;
+ cu->actvert = CU_ACT_NONE;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+
+ /* which point? */
+ if (selfirst == LAST) { /* select last */
+ bezt = &nu->bezt[a - 1];
+ }
+ else { /* select first */
+ bezt = nu->bezt;
+ }
+
+ while (a--) {
+ bool sel;
+ if (doswap) sel = swap_selection_beztriple(bezt);
+ else sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
+
+ if (sel == true) break;
+ }
+ }
+ else {
+ a = nu->pntsu * nu->pntsv;
+
+ /* which point? */
+ if (selfirst == LAST) { /* select last */
+ bp = &nu->bp[a - 1];
+ }
+ else { /* select first */
+ bp = nu->bp;
+ }
+
+ while (a--) {
+ if (bp->hide == 0) {
+ bool sel;
+ if (doswap) sel = swap_selection_bpoint(bp);
+ else sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
+
+ if (sel == true) break;
+ }
+ }
+ }
+ }
+}
+
+static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+
+ selectend_nurb(obedit, FIRST, true, DESELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_de_select_first(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select First";
+ ot->idname = "CURVE_OT_de_select_first";
+ ot->description = "(De)select first of visible part of each NURBS";
+
+ /* api cfirstbacks */
+ ot->exec = de_select_first_exec;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+
+ selectend_nurb(obedit, LAST, true, DESELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_de_select_last(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select Last";
+ ot->idname = "CURVE_OT_de_select_last";
+ ot->description = "(De)select last of visible part of each NURBS";
+
+ /* api clastbacks */
+ ot->exec = de_select_last_exec;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int de_select_all_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = obedit->data;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ if (ED_curve_select_check(cu, cu->editnurb)) {
+ action = SEL_DESELECT;
+ }
+ }
+
+ switch (action) {
+ case SEL_SELECT:
+ ED_curve_select_all(cu->editnurb);
+ break;
+ case SEL_DESELECT:
+ ED_curve_deselect_all(cu->editnurb);
+ break;
+ case SEL_INVERT:
+ ED_curve_select_swap(cu->editnurb, (cu->drawflag & CU_HIDE_HANDLES) != 0);
+ break;
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(cu);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "CURVE_OT_select_all";
+ ot->description = "(De)select all control points";
+
+ /* api callbacks */
+ ot->exec = de_select_all_exec;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_select_all(ot);
+}
+
+
+
+/***************** select linked operator ******************/
+
+static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = (Curve *)obedit->data;
+ EditNurb *editnurb = cu->editnurb;
+ ListBase *nurbs = &editnurb->nurbs;
+ Nurb *nu;
+
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ if (ED_curve_nurb_select_check(cu, nu)) {
+ ED_curve_nurb_select_all(nu);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return select_linked_exec(C, op);
+}
+
+void CURVE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked All";
+ ot->idname = "CURVE_OT_select_linked";
+ ot->description = "Select all control points linked to active one";
+
+ /* api callbacks */
+ ot->exec = select_linked_exec;
+ ot->invoke = select_linked_invoke;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+}
+
+
+/***************** select linked pick operator ******************/
+
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ViewContext vc;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ const bool select = !RNA_boolean_get(op->ptr, "deselect");
+
+ view3d_operator_needs_opengl(C);
+ view3d_set_viewcontext(C, &vc);
+
+ if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu, &bezt, &bp, NULL)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (bezt) {
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ while (a--) {
+ select_beztriple(bezt, select, SELECT, VISIBLE);
+ bezt++;
+ }
+ }
+ else if (bp) {
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ while (a--) {
+ select_bpoint(bp, select, SELECT, VISIBLE);
+ bp++;
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ if (!select) {
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_linked_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->idname = "CURVE_OT_select_linked_pick";
+ ot->description = "Select all control points linked to already selected ones";
+
+ /* api callbacks */
+ ot->invoke = select_linked_pick_invoke;
+ ot->poll = ED_operator_editsurfcurve_region_view3d;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked control points rather than selecting them");
+}
+
+/***************** select row operator **********************/
+
+static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = obedit->data;
+ ListBase *editnurb = object_editcurve_get(obedit);
+ static BPoint *last = NULL;
+ static int direction = 0;
+ Nurb *nu = NULL;
+ BPoint *bp = NULL;
+ int u = 0, v = 0, a, b;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bp))
+ return OPERATOR_CANCELLED;
+
+ if (last == bp) {
+ direction = 1 - direction;
+ BKE_nurbList_flag_set(editnurb, 0);
+ }
+ last = bp;
+
+ u = cu->actvert % nu->pntsu;
+ v = cu->actvert / nu->pntsu;
+ bp = nu->bp;
+ for (a = 0; a < nu->pntsv; a++) {
+ for (b = 0; b < nu->pntsu; b++, bp++) {
+ if (direction) {
+ if (a == v) select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ }
+ else {
+ if (b == u) select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_row(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Control Point Row";
+ ot->idname = "CURVE_OT_select_row";
+ ot->description = "Select a row of control points including active one";
+
+ /* api callbacks */
+ ot->exec = select_row_exec;
+ ot->poll = ED_operator_editsurf;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/***************** select next operator **********************/
+
+static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ListBase *editnurb = object_editcurve_get(obedit);
+
+ select_adjacent_cp(editnurb, 1, 0, SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_next(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Next";
+ ot->idname = "CURVE_OT_select_next";
+ ot->description = "Select control points following already selected ones along the curves";
+
+ /* api callbacks */
+ ot->exec = select_next_exec;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/***************** select previous operator **********************/
+
+static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ListBase *editnurb = object_editcurve_get(obedit);
+
+ select_adjacent_cp(editnurb, -1, 0, SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_previous(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Previous";
+ ot->idname = "CURVE_OT_select_previous";
+ ot->description = "Select control points preceding already selected ones along the curves";
+
+ /* api callbacks */
+ ot->exec = select_previous_exec;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/***************** select more operator **********************/
+
+static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+ BPoint *bp, *tempbp;
+ int a;
+ short sel = 0;
+
+ /* note that NURBS surface is a special case because we mimic */
+ /* the behavior of "select more" of mesh tools. */
+ /* The algorithm is designed to work in planar cases so it */
+ /* may not be optimal always (example: end of NURBS sphere) */
+ if (obedit->type == OB_SURF) {
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ BLI_bitmap *selbpoints;
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ selbpoints = BLI_BITMAP_NEW(a, "selectlist");
+ while (a > 0) {
+ if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
+ /* upper control point */
+ if (a % nu->pntsu != 0) {
+ tempbp = bp - 1;
+ if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ }
+
+ /* left control point. select only if it is not selected already */
+ if (a - nu->pntsu > 0) {
+ sel = 0;
+ tempbp = bp + nu->pntsu;
+ if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ /* make sure selected bpoint is discarded */
+ if (sel == 1) BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu);
+ }
+
+ /* right control point */
+ if (a + nu->pntsu < nu->pntsu * nu->pntsv) {
+ tempbp = bp - nu->pntsu;
+ if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ }
+
+ /* lower control point. skip next bp in case selection was made */
+ if (a % nu->pntsu != 1) {
+ sel = 0;
+ tempbp = bp + 1;
+ if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
+ if (sel) {
+ bp++;
+ a--;
+ }
+ }
+ }
+
+ bp++;
+ a--;
+ }
+
+ MEM_freeN(selbpoints);
+ }
+ }
+ else {
+ select_adjacent_cp(editnurb, 1, 0, SELECT);
+ select_adjacent_cp(editnurb, -1, 0, SELECT);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select More";
+ ot->idname = "CURVE_OT_select_more";
+ ot->description = "Select control points directly linked to already selected ones";
+
+ /* api callbacks */
+ ot->exec = select_more_exec;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/******************** select less operator *****************/
+
+/* basic method: deselect if control point doesn't have all neighbors selected */
+static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+ int sel = 0;
+ short lastsel = false;
+
+ if (obedit->type == OB_SURF) {
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ BLI_bitmap *selbpoints;
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ selbpoints = BLI_BITMAP_NEW(a, "selectlist");
+ while (a--) {
+ if ((bp->hide == 0) && (bp->f1 & SELECT)) {
+ sel = 0;
+
+ /* check if neighbors have been selected */
+ /* edges of surface are an exception */
+ if ((a + 1) % nu->pntsu == 0) {
+ sel++;
+ }
+ else {
+ bp--;
+ if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
+ bp++;
+ }
+
+ if ((a + 1) % nu->pntsu == 1) {
+ sel++;
+ }
+ else {
+ bp++;
+ if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
+ bp--;
+ }
+
+ if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) {
+ sel++;
+ }
+ else {
+ bp -= nu->pntsu;
+ if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
+ bp += nu->pntsu;
+ }
+
+ if (a < nu->pntsu) {
+ sel++;
+ }
+ else {
+ bp += nu->pntsu;
+ if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
+ bp -= nu->pntsu;
+ }
+
+ if (sel != 4) {
+ select_bpoint(bp, DESELECT, SELECT, VISIBLE);
+ BLI_BITMAP_ENABLE(selbpoints, a);
+ }
+ }
+ else {
+ lastsel = false;
+ }
+
+ bp++;
+ }
+
+ MEM_freeN(selbpoints);
+ }
+ }
+ else {
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ lastsel = false;
+ /* check what type of curve/nurb it is */
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ while (a--) {
+ if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
+ sel = (lastsel == 1);
+
+ /* check if neighbors have been selected */
+ /* first and last are exceptions */
+ if (a == nu->pntsu - 1) {
+ sel++;
+ }
+ else {
+ bezt--;
+ if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
+ bezt++;
+ }
+
+ if (a == 0) {
+ sel++;
+ }
+ else {
+ bezt++;
+ if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++;
+ bezt--;
+ }
+
+ if (sel != 2) {
+ select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
+ lastsel = true;
+ }
+ else {
+ lastsel = false;
+ }
+ }
+ else {
+ lastsel = false;
+ }
+
+ bezt++;
+ }
+ }
+ else {
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ while (a--) {
+ if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) {
+ if (lastsel != 0) sel = 1;
+ else sel = 0;
+
+ /* first and last are exceptions */
+ if (a == nu->pntsu * nu->pntsv - 1) {
+ sel++;
+ }
+ else {
+ bp--;
+ if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
+ bp++;
+ }
+
+ if (a == 0) {
+ sel++;
+ }
+ else {
+ bp++;
+ if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++;
+ bp--;
+ }
+
+ if (sel != 2) {
+ select_bpoint(bp, DESELECT, SELECT, VISIBLE);
+ lastsel = true;
+ }
+ else {
+ lastsel = false;
+ }
+ }
+ else {
+ lastsel = false;
+ }
+
+ bp++;
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->idname = "CURVE_OT_select_less";
+ ot->description = "Reduce current selection by deselecting boundary elements";
+
+ /* api callbacks */
+ ot->exec = select_less_exec;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** select random *********************/
+
+static void curve_select_random(ListBase *editnurb, float randfac, bool select)
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if (!bezt->hide) {
+ if (BLI_frand() < randfac) {
+ select_beztriple(bezt, select, SELECT, VISIBLE);
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+
+ while (a--) {
+ if (!bp->hide) {
+ if (BLI_frand() < randfac) {
+ select_bpoint(bp, select, SELECT, VISIBLE);
+ }
+ }
+ bp++;
+ }
+ }
+ }
+}
+
+static int curve_select_random_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ListBase *editnurb = object_editcurve_get(obedit);
+ const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+
+ curve_select_random(editnurb, randfac, select);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_random(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Random";
+ ot->idname = "CURVE_OT_select_random";
+ ot->description = "Randomly select some control points";
+
+ /* api callbacks */
+ ot->exec = curve_select_random_exec;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
+ "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
+ WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+}
+
+/********************* every nth number of point *******************/
+
+static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int offset)
+{
+ int a, start;
+
+ start = bezt - nu->bezt;
+ a = nu->pntsu;
+ bezt = &nu->bezt[a - 1];
+
+ while (a--) {
+ const int depth = abs(start - a);
+ if ((offset + depth) % (skip + nth) >= skip) {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ }
+
+ bezt--;
+ }
+}
+
+static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
+{
+ int a, startrow, startpnt;
+ int row, pnt;
+
+ startrow = (bp - nu->bp) / nu->pntsu;
+ startpnt = (bp - nu->bp) % nu->pntsu;
+
+ a = nu->pntsu * nu->pntsv;
+ bp = &nu->bp[a - 1];
+ row = nu->pntsv - 1;
+ pnt = nu->pntsu - 1;
+
+ while (a--) {
+ const int depth = abs(pnt - startpnt) + abs(row - startrow);
+ if ((offset + depth) % (skip + nth) >= skip) {
+ select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ }
+
+ pnt--;
+ if (pnt < 0) {
+ pnt = nu->pntsu - 1;
+ row--;
+ }
+
+ bp--;
+ }
+}
+
+bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
+{
+ Nurb *nu = NULL;
+ void *vert = NULL;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert))
+ return false;
+
+ if (nu->bezt) {
+ select_nth_bezt(nu, vert, nth, skip, offset);
+ }
+ else {
+ select_nth_bp(nu, vert, nth, skip, offset);
+ }
+
+ return true;
+}
+
+static int select_nth_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
+ int offset = RNA_int_get(op->ptr, "offset");
+
+ /* so input of offset zero ends up being (nth - 1) */
+ offset = mod_i(offset, nth + skip);
+
+ if (!ED_curve_select_nth(obedit->data, nth, skip, offset)) {
+ if (obedit->type == OB_SURF) {
+ BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Curve has not got active point");
+ }
+
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_select_nth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Checker Deselect";
+ ot->description = "Deselect every other vertex";
+ ot->idname = "CURVE_OT_select_nth";
+
+ /* api callbacks */
+ ot->exec = select_nth_exec;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
+ RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Select Similar */
+
+/** \name Select Similar
+ * \{ */
+
+enum {
+ SIM_CMP_EQ = 0,
+ SIM_CMP_GT,
+ SIM_CMP_LT,
+};
+
+static EnumPropertyItem curve_prop_similar_compare_types[] = {
+ {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
+ {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
+ {SIM_CMP_LT, "LESS", 0, "Less", ""},
+
+ {0, NULL, 0, NULL, NULL}
+};
+
+enum {
+ SIMCURHAND_TYPE = 0,
+ SIMCURHAND_RADIUS,
+ SIMCURHAND_WEIGHT,
+ SIMCURHAND_DIRECTION,
+};
+
+static EnumPropertyItem curve_prop_similar_types[] = {
+ {SIMCURHAND_TYPE, "TYPE", 0, "Type", ""},
+ {SIMCURHAND_RADIUS, "RADIUS", 0, "Radius", ""},
+ {SIMCURHAND_WEIGHT, "WEIGHT", 0, "Weight", ""},
+ {SIMCURHAND_DIRECTION, "DIRECTION", 0, "Direction", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int curve_select_similar_cmp_fl(const float delta, const float thresh, const int compare)
+{
+ switch (compare) {
+ case SIM_CMP_EQ:
+ return (fabsf(delta) <= thresh);
+ case SIM_CMP_GT:
+ return ((delta + thresh) >= 0.0f);
+ case SIM_CMP_LT:
+ return ((delta - thresh) <= 0.0f);
+ default:
+ BLI_assert(0);
+ return 0;
+ }
+}
+
+
+static void curve_select_similar_direction__bezt(Nurb *nu, const float dir_ref[3], float angle_cos)
+{
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (!bezt->hide) {
+ float dir[3];
+ BKE_nurb_bezt_calc_normal(nu, bezt, dir);
+ if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
+ select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+}
+
+static void curve_select_similar_direction__bp(Nurb *nu, const float dir_ref[3], float angle_cos)
+{
+ BPoint *bp;
+ int i;
+
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (!bp->hide) {
+ float dir[3];
+ BKE_nurb_bpoint_calc_normal(nu, bp, dir);
+ if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
+ select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+}
+
+static bool curve_select_similar_direction(ListBase *editnurb, Curve *cu, float thresh)
+{
+ Nurb *nu, *act_nu;
+ void *act_vert;
+ float dir[3];
+ float angle_cos;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
+ return false;
+ }
+
+ if (act_nu->type == CU_BEZIER) {
+ BKE_nurb_bezt_calc_normal(act_nu, act_vert, dir);
+ }
+ else {
+ BKE_nurb_bpoint_calc_normal(act_nu, act_vert, dir);
+ }
+
+ /* map 0-1 to radians, 'cos' for comparison */
+ angle_cos = cosf(thresh * (float)M_PI_2);
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ curve_select_similar_direction__bezt(nu, dir, angle_cos);
+ }
+ else {
+ curve_select_similar_direction__bp(nu, dir, angle_cos);
+ }
+ }
+
+ return true;
+}
+
+static void curve_select_similar_radius__bezt(Nurb *nu, float radius_ref, int compare, float thresh)
+{
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (!bezt->hide) {
+ if (curve_select_similar_cmp_fl(bezt->radius - radius_ref, thresh, compare)) {
+ select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+}
+
+static void curve_select_similar_radius__bp(Nurb *nu, float radius_ref, int compare, float thresh)
+{
+ BPoint *bp;
+ int i;
+
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (!bp->hide) {
+ if (curve_select_similar_cmp_fl(bp->radius - radius_ref, thresh, compare)) {
+ select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+}
+
+static bool curve_select_similar_radius(ListBase *editnurb, Curve *cu, float compare, float thresh)
+{
+ Nurb *nu, *act_nu;
+ void *act_vert;
+ float radius_ref;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
+ return false;
+ }
+
+ if (act_nu->type == CU_BEZIER) {
+ radius_ref = ((BezTriple *)act_vert)->radius;
+ }
+ else {
+ radius_ref = ((BPoint *)act_vert)->radius;
+ }
+
+ /* make relative */
+ thresh *= radius_ref;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ curve_select_similar_radius__bezt(nu, radius_ref, compare, thresh);
+ }
+ else {
+ curve_select_similar_radius__bp(nu, radius_ref, compare, thresh);
+ }
+ }
+
+ return true;
+}
+
+static void curve_select_similar_weight__bezt(Nurb *nu, float weight_ref, int compare, float thresh)
+{
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (!bezt->hide) {
+ if (curve_select_similar_cmp_fl(bezt->weight - weight_ref, thresh, compare)) {
+ select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+}
+
+static void curve_select_similar_weight__bp(Nurb *nu, float weight_ref, int compare, float thresh)
+{
+ BPoint *bp;
+ int i;
+
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (!bp->hide) {
+ if (curve_select_similar_cmp_fl(bp->weight - weight_ref, thresh, compare)) {
+ select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ }
+ }
+ }
+}
+
+static bool curve_select_similar_weight(ListBase *editnurb, Curve *cu, float compare, float thresh)
+{
+ Nurb *nu, *act_nu;
+ void *act_vert;
+ float weight_ref;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert))
+ return false;
+
+ if (act_nu->type == CU_BEZIER) {
+ weight_ref = ((BezTriple *)act_vert)->weight;
+ }
+ else {
+ weight_ref = ((BPoint *)act_vert)->weight;
+ }
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ curve_select_similar_weight__bezt(nu, weight_ref, compare, thresh);
+ }
+ else {
+ curve_select_similar_weight__bp(nu, weight_ref, compare, thresh);
+ }
+ }
+
+ return true;
+}
+
+static bool curve_select_similar_type(ListBase *editnurb, Curve *cu)
+{
+ Nurb *nu, *act_nu;
+ int type_ref;
+
+ /* Get active nurb type */
+ act_nu = BKE_curve_nurb_active_get(cu);
+
+ if (!act_nu)
+ return false;
+
+ /* Get the active nurb type */
+ type_ref = act_nu->type;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == type_ref) {
+ ED_curve_nurb_select_all(nu);
+ }
+ }
+
+ return true;
+}
+
+static int curve_select_similar_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = obedit->data;
+ ListBase *editnurb = object_editcurve_get(obedit);
+ bool changed = false;
+
+ /* Get props */
+ const int type = RNA_enum_get(op->ptr, "type");
+ const float thresh = RNA_float_get(op->ptr, "threshold");
+ const int compare = RNA_enum_get(op->ptr, "compare");
+
+ switch (type) {
+ case SIMCURHAND_TYPE:
+ changed = curve_select_similar_type(editnurb, cu);
+ break;
+ case SIMCURHAND_RADIUS:
+ changed = curve_select_similar_radius(editnurb, cu, compare, thresh);
+ break;
+ case SIMCURHAND_WEIGHT:
+ changed = curve_select_similar_weight(editnurb, cu, compare, thresh);
+ break;
+ case SIMCURHAND_DIRECTION:
+ changed = curve_select_similar_direction(editnurb, cu, thresh);
+ break;
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void CURVE_OT_select_similar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->idname = "CURVE_OT_select_similar";
+ ot->description = "Select similar curve points by property type";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = curve_select_similar_exec;
+ ot->poll = ED_operator_editsurfcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", curve_prop_similar_types, SIMCURHAND_WEIGHT, "Type", "");
+ RNA_def_enum(ot->srna, "compare", curve_prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+ RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.0, 100.0);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Select Shortest Path */
+
+/** \name Select Path
+ * \{ */
+
+static float curve_calc_dist_pair(const Nurb *nu, int a, int b)
+{
+ const float *a_fl, *b_fl;
+
+ if (nu->type == CU_BEZIER) {
+ a_fl = nu->bezt[a].vec[1];
+ b_fl = nu->bezt[b].vec[1];
+ }
+ else {
+ a_fl = nu->bp[a].vec;
+ b_fl = nu->bp[b].vec;
+ }
+
+ return len_v3v3(a_fl, b_fl);
+}
+
+static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
+{
+ const int u = nu->pntsu;
+ int i_prev, i;
+ float dist = 0.0f;
+
+ BLI_assert(nu->pntsv == 1);
+
+ i_prev = vert_src;
+ i = (i_prev + 1) % u;
+
+ while (true) {
+ dist += curve_calc_dist_pair(nu, i_prev, i);
+
+ if (i == vert_dst) {
+ break;
+ }
+ i = (i + 1) % u;
+ }
+ return dist;
+}
+
+static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_dst)
+{
+ const int u = nu->pntsu;
+ int i;
+
+ if (vert_src > vert_dst) {
+ SWAP(int, vert_src, vert_dst);
+ }
+
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ if (curve_calc_dist_span(nu, vert_src, vert_dst) >
+ curve_calc_dist_span(nu, vert_dst, vert_src))
+ {
+ SWAP(int, vert_src, vert_dst);
+ }
+ }
+
+ i = vert_src;
+ while (true) {
+ if (nu->type & CU_BEZIER) {
+ select_beztriple(&nu->bezt[i], SELECT, SELECT, HIDDEN);
+ }
+ else {
+ select_bpoint(&nu->bp[i], SELECT, SELECT, HIDDEN);
+ }
+
+ if (i == vert_dst) {
+ break;
+ }
+ i = (i + 1) % u;
+ }
+}
+
+static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst)
+{
+ Heap *heap;
+
+ int i, vert_curr;
+
+ int totu = nu->pntsu;
+ int totv = nu->pntsv;
+ int vert_num = totu * totv;
+
+ /* custom data */
+ struct PointAdj {
+ int vert, vert_prev;
+ float cost;
+ } *data;
+
+ /* init connectivity data */
+ data = MEM_mallocN(sizeof(*data) * vert_num, __func__);
+ for (i = 0; i < vert_num; i++) {
+ data[i].vert = i;
+ data[i].vert_prev = -1;
+ data[i].cost = FLT_MAX;
+ }
+
+ /* init heap */
+ heap = BLI_heap_new();
+
+ BLI_heap_insert(heap, 0.0f, &data[vert_src].vert);
+ data[vert_src].cost = 0.0f;
+ data[vert_src].vert_prev = vert_src; /* nop */
+
+ while (!BLI_heap_is_empty(heap)) {
+ int axis, sign;
+ int u, v;
+
+ vert_curr = *((int *)BLI_heap_popmin(heap));
+ if (vert_curr == vert_dst) {
+ break;
+ }
+
+ BKE_nurb_index_to_uv(nu, vert_curr, &u, &v);
+
+ /* loop over 4 adjacent verts */
+ for (sign = -1; sign != 3; sign += 2) {
+ for (axis = 0; axis != 2; axis += 1) {
+ int uv_other[2] = {u, v};
+ int vert_other;
+
+ uv_other[axis] += sign;
+
+ vert_other = BKE_nurb_index_from_uv(nu, uv_other[0], uv_other[1]);
+ if (vert_other != -1) {
+ const float dist = data[vert_curr].cost + curve_calc_dist_pair(nu, vert_curr, vert_other);
+
+ if (data[vert_other].cost > dist) {
+ data[vert_other].cost = dist;
+ if (data[vert_other].vert_prev == -1) {
+ BLI_heap_insert(heap, data[vert_other].cost, &data[vert_other].vert);
+ }
+ data[vert_other].vert_prev = vert_curr;
+ }
+ }
+
+ }
+ }
+
+ }
+
+ BLI_heap_free(heap, NULL);
+
+ if (vert_curr == vert_dst) {
+ i = 0;
+ while (vert_curr != vert_src && i++ < vert_num) {
+ if (nu->type == CU_BEZIER) {
+ select_beztriple(&nu->bezt[vert_curr], SELECT, SELECT, HIDDEN);
+ }
+ else {
+ select_bpoint(&nu->bp[vert_curr], SELECT, SELECT, HIDDEN);
+ }
+ vert_curr = data[vert_curr].vert_prev;
+ }
+ }
+
+ MEM_freeN(data);
+}
+
+static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = obedit->data;
+ Nurb *nu_src = BKE_curve_nurb_active_get(cu);
+ int vert_src = cu->actvert;
+
+ ViewContext vc;
+ Nurb *nu_dst;
+ BezTriple *bezt_dst;
+ BPoint *bp_dst;
+ int vert_dst;
+ void *vert_dst_p;
+
+ if (vert_src == CU_ACT_NONE) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ view3d_operator_needs_opengl(C);
+ view3d_set_viewcontext(C, &vc);
+
+ if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu_dst, &bezt_dst, &bp_dst, NULL)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ if (nu_src != nu_dst) {
+ BKE_report(op->reports, RPT_ERROR, "Control point belongs to another spline");
+ return OPERATOR_CANCELLED;
+ }
+
+ vert_dst_p = bezt_dst ? (void *)bezt_dst : (void *)bp_dst;
+ vert_dst = BKE_curve_nurb_vert_index_get(nu_dst, vert_dst_p);
+ if (vert_src == vert_dst) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if ((obedit->type == OB_SURF) && (nu_src->pntsv > 1)) {
+ curve_select_shortest_path_surf(nu_src, vert_src, vert_dst);
+ }
+ else {
+ curve_select_shortest_path_curve(nu_src, vert_src, vert_dst);
+ }
+
+ BKE_curve_nurb_vert_active_set(cu, nu_dst, vert_dst_p);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_shortest_path_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Pick Shortest Path";
+ ot->idname = "CURVE_OT_shortest_path_pick";
+ ot->description = "Select shortest path between two selections";
+
+ /* api callbacks */
+ ot->invoke = edcu_shortest_path_pick_invoke;
+ ot->poll = ED_operator_editsurfcurve_region_view3d;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 4655deec4c4..ea6b6154be8 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -275,57 +275,6 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
-/********************** insert lorem operator *********************/
-
-static int insert_lorem_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- const char *p, *p2;
- int i;
- static const char *lastlorem = NULL;
-
- if (lastlorem)
- p = lastlorem;
- else
- p = ED_lorem;
-
- i = rand() / (RAND_MAX / 6) + 4;
-
- for (p2 = p; *p2 && i; p2++) {
- insert_into_textbuf(obedit, *p2);
-
- if (*p2 == '.')
- i--;
- }
-
- lastlorem = p2 + 1;
- if (strlen(lastlorem) < 5)
- lastlorem = ED_lorem;
-
- insert_into_textbuf(obedit, '\n');
- insert_into_textbuf(obedit, '\n');
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void FONT_OT_insert_lorem(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Insert Lorem";
- ot->description = "Insert placeholder text";
- ot->idname = "FONT_OT_insert_lorem";
-
- /* api callbacks */
- ot->exec = insert_lorem_exec;
- ot->poll = ED_operator_editfont;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* -------------------------------------------------------------------- */
/* Generic Paste Functions */
@@ -500,8 +449,8 @@ void FONT_OT_text_paste_from_file(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
@@ -558,8 +507,8 @@ void FONT_OT_text_paste_from_clipboard(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************* text to object operator ********************/
@@ -577,7 +526,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
int a;
float rot[3] = {0.f, 0.f, 0.f};
- obedit = BKE_object_add(bmain, scene, OB_FONT);
+ obedit = BKE_object_add(bmain, scene, OB_FONT, NULL);
base = scene->basact;
/* seems to assume view align ? TODO - look into this, could be an operator option */
@@ -668,7 +617,7 @@ void ED_text_to_object(bContext *C, Text *text, const bool split_lines)
offset[1] = 0.0f;
offset[2] = 0.0f;
- txt_add_object(C, text->lines.first, BLI_countlist(&text->lines), offset);
+ txt_add_object(C, text->lines.first, BLI_listbase_count(&text->lines), offset);
}
}
@@ -1417,7 +1366,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
accentcode = 0;
}
else if (event->utf8_buf[0]) {
- BLI_strncpy_wchar_from_utf8(inserted_text, event->utf8_buf, 2);
+ inserted_text[0] = BLI_str_utf8_as_unicode(event->utf8_buf);
ascii = inserted_text[0];
insert_into_textbuf(obedit, ascii);
accentcode = 0;
@@ -1744,7 +1693,7 @@ static void font_ui_template_init(bContext *C, wmOperator *op)
PropertyPointerRNA *pprop;
op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
- uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
+ UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
}
static void font_open_cancel(bContext *UNUSED(C), wmOperator *op)
@@ -1835,8 +1784,8 @@ void FONT_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | FTFONTFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_FTFONT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************* delete operator *********************/
@@ -1848,7 +1797,7 @@ static int font_unlink_exec(bContext *C, wmOperator *op)
PointerRNA idptr;
PropertyPointerRNA pprop;
- uiIDContextProperty(C, &pprop.ptr, &pprop.prop);
+ UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop);
if (pprop.prop == NULL) {
BKE_report(op->reports, RPT_ERROR, "Incorrect context for running font unlink");
@@ -1884,8 +1833,8 @@ static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata))
EditFont *ef = cu->editfont;
const char *str = strv;
- ef->pos = *((short *)str);
- ef->len = *((short *)(str + 2));
+ ef->pos = *((const short *)str);
+ ef->len = *((const short *)(str + 2));
memcpy(ef->textbuf, str + 4, (ef->len + 1) * sizeof(wchar_t));
memcpy(ef->textbufinfo, str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->len * sizeof(CharInfo));
diff --git a/source/blender/editors/curve/lorem.c b/source/blender/editors/curve/lorem.c
deleted file mode 100644
index 59bf3f50dbc..00000000000
--- a/source/blender/editors/curve/lorem.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/curve/lorem.c
- * \ingroup edcurve
- */
-
-
-#include "BLI_sys_types.h"
-#include "curve_intern.h"
-
-const char ED_lorem[] = {
-76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99,
-111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 101, 108, 105, 116, 46, 32, 65, 108, 105,
-113, 117, 97, 109, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 115, 101, 109, 46, 32, 78, 117, 108,
-108, 97, 109, 32, 112, 114, 101, 116, 105, 117, 109, 44, 32, 116, 111, 114, 116, 111, 114, 32, 110, 111, 110, 32, 101, 117, 105, 115, 109, 111, 100, 32,
-118, 97, 114, 105, 117, 115, 44, 32, 110, 117, 108, 108, 97, 32, 111, 100, 105, 111, 32, 115, 111, 100, 97, 108, 101, 115, 32, 110, 117, 108, 108, 97,
-44, 32, 97, 116, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 108, 111, 114, 101, 109, 32, 109, 101, 116, 117, 115, 32, 115, 101, 100, 32, 110, 117,
-108, 108, 97, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 97, 116, 32, 112, 101, 100,
-101, 32, 98, 108, 97, 110, 100, 105, 116, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 70, 117, 115, 99, 101, 32, 115, 99, 101, 108, 101, 114, 105,
-115, 113, 117, 101, 32, 105, 112, 115, 117, 109, 32, 110, 101, 99, 32, 101, 110, 105, 109, 46, 32, 70, 117, 115, 99, 101, 32, 101, 117, 105, 115, 109,
-111, 100, 32, 110, 117, 110, 99, 32, 105, 100, 32, 101, 110, 105, 109, 46, 32, 73, 110, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 99, 117,
-114, 115, 117, 115, 32, 97, 114, 99, 117, 46, 32, 65, 101, 110, 101, 97, 110, 32, 113, 117, 105, 115, 32, 100, 117, 105, 46, 32, 77, 97, 101, 99,
-101, 110, 97, 115, 32, 108, 97, 111, 114, 101, 101, 116, 46, 32, 78, 117, 108, 108, 97, 32, 116, 101, 109, 112, 111, 114, 44, 32, 97, 114, 99, 117,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 112, 114, 101, 116, 105, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 44, 32, 116, 111, 114, 116,
-111, 114, 32, 119, 105, 115, 105, 32, 100, 97, 112, 105, 98, 117, 115, 32, 108, 105, 98, 101, 114, 111, 44, 32, 105, 100, 32, 111, 114, 110, 97, 114,
-101, 32, 102, 101, 108, 105, 115, 32, 105, 112, 115, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 112, 117, 114, 117, 115, 46, 32, 77, 97,
-101, 99, 101, 110, 97, 115, 32, 105, 112, 115, 117, 109, 46, 32, 77, 111, 114, 98, 105, 32, 99, 117, 114, 115, 117, 115, 46, 32, 86, 101, 115, 116,
-105, 98, 117, 108, 117, 109, 32, 100, 105, 97, 109, 32, 112, 117, 114, 117, 115, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 116, 44, 32, 99,
-111, 110, 118, 97, 108, 108, 105, 115, 32, 101, 117, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32, 97, 116, 44, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 78, 117, 108, 108, 97, 32, 97, 108, 105, 113, 117, 97, 109, 32, 97, 108, 105, 113, 117, 101, 116, 32, 108, 111, 114, 101, 109, 46, 32, 78, 117,
-110, 99, 32, 101, 116, 32, 109, 97, 117, 114, 105, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 101, 115, 116, 32, 98, 105, 98, 101, 110,
-100, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 46, 32, 68, 111, 110, 101, 99, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101,
-32, 108, 105, 98, 101, 114, 111, 32, 101, 117, 32, 110, 105, 115, 108, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 103,
-101, 116, 32, 108, 105, 98, 101, 114, 111, 46, 32, 68, 111, 110, 101, 99, 32, 116, 101, 109, 112, 117, 115, 32, 105, 112, 115, 117, 109, 32, 115, 101,
-100, 32, 113, 117, 97, 109, 46, 32, 83, 101, 100, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 117, 110, 99, 32, 113, 117, 105, 115, 32, 101, 110,
-105, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 101, 99, 116, 117, 115, 32, 100, 105, 97, 109, 44, 32, 97, 100, 105, 112, 105, 115, 99,
-105, 110, 103, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 110, 111, 110, 44, 32, 112, 117, 108,
-118, 105, 110, 97, 114, 32, 105, 100, 44, 32, 102, 101, 108, 105, 115, 46, 32, 73, 110, 32, 99, 111, 110, 103, 117, 101, 32, 109, 97, 103, 110, 97,
-32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 117, 114, 110, 97, 46, 32, 78, 117, 110, 99, 32, 110, 111, 110, 32, 97, 117, 103, 117, 101, 32, 115,
-101, 100, 32, 110, 105, 115, 108, 32, 100, 105, 99, 116, 117, 109, 32, 108, 97, 111, 114, 101, 101, 116, 46, 32, 67, 117, 109, 32, 115, 111, 99, 105,
-105, 115, 32, 110, 97, 116, 111, 113, 117, 101, 32, 112, 101, 110, 97, 116, 105, 98, 117, 115, 32, 101, 116, 32, 109, 97, 103, 110, 105, 115, 32, 100,
-105, 115, 32, 112, 97, 114, 116, 117, 114, 105, 101, 110, 116, 32, 109, 111, 110, 116, 101, 115, 44, 32, 110, 97, 115, 99, 101, 116, 117, 114, 32, 114,
-105, 100, 105, 99, 117, 108, 117, 115, 32, 109, 117, 115, 46, 32, 73, 110, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 100, 97, 112, 105, 98,
-117, 115, 32, 109, 97, 115, 115, 97, 46, 32, 78, 117, 108, 108, 97, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 115, 97, 112, 105, 101, 110,
-32, 101, 116, 32, 113, 117, 97, 109, 46, 32, 78, 117, 110, 99, 32, 97, 99, 32, 109, 97, 103, 110, 97, 32, 108, 111, 98, 111, 114, 116, 105, 115,
-32, 116, 101, 108, 108, 117, 115, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 67, 114, 97, 115, 32,
-97, 117, 103, 117, 101, 32, 109, 97, 117, 114, 105, 115, 44, 32, 109, 97, 116, 116, 105, 115, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 102,
-101, 114, 109, 101, 110, 116, 117, 109, 32, 97, 116, 44, 32, 115, 101, 109, 112, 101, 114, 32, 97, 99, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32,
-67, 114, 97, 115, 32, 118, 105, 116, 97, 101, 32, 108, 105, 103, 117, 108, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 115, 101, 109, 32, 112,
-111, 115, 117, 101, 114, 101, 32, 105, 97, 99, 117, 108, 105, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 99, 111, 110, 100, 105, 109, 101, 110,
-116, 117, 109, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 102, 101, 108, 105, 115, 46, 32, 85, 116, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32,
-115, 97, 112, 105, 101, 110, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 77, 97, 117,
-114, 105, 115, 32, 117, 114, 110, 97, 46, 32, 85, 116, 32, 101, 117, 32, 101, 110, 105, 109, 32, 101, 117, 32, 97, 110, 116, 101, 32, 112, 111, 114,
-116, 97, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 46, 32, 65, 101, 110, 101, 97, 110, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117,
-101, 32, 101, 115, 116, 32, 97, 99, 32, 102, 101, 108, 105, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 97, 117, 99, 116,
-111, 114, 46, 32, 78, 117, 110, 99, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 46, 32, 77, 111, 114, 98, 105, 32, 108, 97, 111,
-114, 101, 101, 116, 32, 97, 110, 116, 101, 32, 101, 116, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 102, 101, 117, 103, 105, 97, 116,
-32, 97, 114, 99, 117, 32, 101, 103, 101, 116, 32, 101, 110, 105, 109, 46, 32, 77, 111, 114, 98, 105, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32,
-116, 111, 114, 116, 111, 114, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 97, 99, 117, 115, 32, 97,
-114, 99, 117, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 97, 99, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 118, 101, 108, 44,
-32, 112, 111, 115, 117, 101, 114, 101, 32, 105, 100, 44, 32, 101, 115, 116, 46, 32, 80, 114, 111, 105, 110, 32, 99, 111, 109, 109, 111, 100, 111, 32,
-103, 114, 97, 118, 105, 100, 97, 32, 115, 101, 109, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 118,
-101, 104, 105, 99, 117, 108, 97, 32, 108, 105, 98, 101, 114, 111, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 119, 105, 115, 105, 46, 32,
-77, 97, 101, 99, 101, 110, 97, 115, 32, 112, 114, 101, 116, 105, 117, 109, 32, 116, 101, 108, 108, 117, 115, 32, 101, 117, 32, 115, 97, 112, 105, 101,
-110, 46, 32, 78, 117, 110, 99, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 110, 117, 110, 99, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97,
-98, 105, 116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 65, 101, 110, 101, 97, 110, 32,
-100, 105, 99, 116, 117, 109, 32, 110, 101, 113, 117, 101, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 68, 111, 110, 101, 99, 32, 101,
-116, 32, 101, 114, 97, 116, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114,
-105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32,
-83, 101, 100, 32, 106, 117, 115, 116, 111, 32, 116, 117, 114, 112, 105, 115, 44, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 117, 116,
-44, 32, 109, 97, 116, 116, 105, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 111, 114, 110, 97, 114, 101, 32, 114, 117, 116, 114, 117, 109,
-44, 32, 109, 97, 115, 115, 97, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 101, 110, 105,
-109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 118, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 116, 101, 108, 108, 117, 115,
-32, 105, 112, 115, 117, 109, 44, 32, 108, 117, 99, 116, 117, 115, 32, 117, 116, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32,
-118, 105, 116, 97, 101, 44, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 111, 110, 44, 32, 108, 105, 103, 117, 108, 97, 46, 32, 80, 104,
-97, 115, 101, 108, 108, 117, 115, 32, 108, 97, 99, 105, 110, 105, 97, 32, 119, 105, 115, 105, 32, 97, 116, 32, 101, 115, 116, 46, 32, 68, 111, 110,
-101, 99, 32, 101, 108, 105, 116, 32, 119, 105, 115, 105, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 110, 111, 110, 44, 32, 112, 108, 97, 99, 101,
-114, 97, 116, 32, 105, 110, 44, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 105, 100, 44, 32, 101, 108, 105, 116, 46, 32, 78, 117, 110, 99,
-32, 100, 111, 108, 111, 114, 32, 100, 111, 108, 111, 114, 44, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 100, 44, 32, 98, 105, 98,
-101, 110, 100, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 108, 97, 99, 105, 110, 105, 97, 32, 105, 100, 44, 32, 101, 114, 97, 116, 46, 32, 67,
-114, 97, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 114, 111, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 115,
-117, 115, 99, 105, 112, 105, 116, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 67, 108, 97, 115, 115, 32, 97,
-112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32,
-116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114,
-32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 67, 114, 97, 115, 32, 111, 114, 99, 105, 46, 32,
-80, 114, 97, 101, 115, 101, 110, 116, 32, 109, 97, 115, 115, 97, 32, 117, 114, 110, 97, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 115, 101,
-109, 112, 101, 114, 44, 32, 97, 117, 99, 116, 111, 114, 32, 97, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 116,
-101, 108, 108, 117, 115, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 116, 32, 112, 117, 114, 117, 115, 46, 32, 77, 111, 114, 98, 105,
-32, 116, 111, 114, 116, 111, 114, 32, 113, 117, 97, 109, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 118, 101, 110, 101, 110, 97, 116, 105,
-115, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 97, 44, 32, 99, 117, 114, 115, 117, 115, 32, 101, 117, 44, 32, 101, 115, 116, 46, 32, 78, 117,
-110, 99, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 108, 101, 99, 116, 117, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 108, 105, 98, 101,
-114, 111, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 108,
-105, 103, 117, 108, 97, 46, 32, 78, 117, 110, 99, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 112, 111, 115, 117, 101, 114, 101, 32, 97, 114,
-99, 117, 46, 32, 77, 97, 117, 114, 105, 115, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 113, 117, 97, 109, 32, 97, 116, 32, 109, 97, 115, 115,
-97, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 108, 105, 113, 117, 101, 116, 32, 109, 97, 117, 114, 105,
-115, 46, 32, 73, 110, 32, 105, 100, 32, 97, 110, 116, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 97, 114, 105,
-117, 115, 32, 105, 112, 115, 117, 109, 32, 105, 110, 32, 97, 114, 99, 117, 46, 32, 70, 117, 115, 99, 101, 32, 109, 97, 117, 114, 105, 115, 32, 108,
-97, 99, 117, 115, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 97, 99, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 113, 117, 105,
-115, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 108, 117, 99, 116, 117, 115, 44, 32, 112, 101, 100, 101, 46, 32, 83, 101, 100, 32, 119, 105,
-115, 105, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 109, 97, 116, 116, 105, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32,
-104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 115, 101, 109, 32, 110, 101, 99, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 105,
-100, 32, 113, 117, 97, 109, 46, 32, 67, 114, 97, 115, 32, 110, 101, 99, 32, 109, 97, 117, 114, 105, 115, 46, 32, 73, 110, 116, 101, 103, 101, 114,
-32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 100, 117, 105, 32, 115, 101, 109, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32,
-115, 101, 100, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 99, 117, 114, 115, 117, 115, 32, 105, 110, 44, 32, 109, 97,
-103, 110, 97, 46, 32, 77, 97, 117, 114, 105, 115, 32, 110, 101, 113, 117, 101, 32, 108, 97, 99, 117, 115, 44, 32, 99, 111, 110, 115, 101, 99, 116,
-101, 116, 117, 101, 114, 32, 110, 101, 99, 44, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 101, 117, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111,
-114, 32, 101, 103, 101, 116, 44, 32, 100, 117, 105, 46, 32, 70, 117, 115, 99, 101, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 46,
-32, 68, 111, 110, 101, 99, 32, 110, 101, 99, 32, 116, 101, 108, 108, 117, 115, 32, 113, 117, 105, 115, 32, 108, 101, 111, 32, 108, 111, 98, 111, 114,
-116, 105, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 46, 32, 69, 116, 105, 97, 109, 32, 109, 101, 116, 117, 115, 32, 117, 114, 110,
-97, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 112, 114, 101, 116, 105, 117, 109, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 44,
-32, 99, 117, 114, 115, 117, 115, 32, 117, 116, 44, 32, 116, 117, 114, 112, 105, 115, 46, 32, 77, 111, 114, 98, 105, 32, 98, 105, 98, 101, 110, 100,
-117, 109, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 108, 101, 99, 116, 117, 115, 46, 32, 83, 101, 100, 32, 110, 111, 110, 32, 97, 110, 116, 101,
-32, 118, 105, 116, 97, 101, 32, 97, 114, 99, 117, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 116, 101, 109, 112, 111, 114, 46,
-32, 70, 117, 115, 99, 101, 32, 115, 101, 100, 32, 108, 105, 103, 117, 108, 97, 32, 105, 110, 32, 115, 101, 109, 32, 116, 101, 109, 112, 111, 114, 32,
-105, 109, 112, 101, 114, 100, 105, 101, 116, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 118, 101, 108, 32, 101, 115, 116, 46, 32, 80, 104, 97, 115,
-101, 108, 108, 117, 115, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32,
-110, 105, 98, 104, 46, 32, 67, 108, 97, 115, 115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115,
-113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105,
-97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115,
-46, 32, 83, 101, 100, 32, 118, 101, 108, 32, 108, 101, 111, 32, 110, 101, 99, 32, 101, 114, 111, 115, 32, 98, 108, 97, 110, 100, 105, 116, 32, 105,
-109, 112, 101, 114, 100, 105, 101, 116, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 100, 117, 105, 32, 117, 116, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97,
-32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 44, 32, 106, 117, 115, 116, 111, 32, 112, 117, 114, 117, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114,
-112, 101, 114, 32, 108, 105, 103, 117, 108, 97, 44, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 100,
-111, 108, 111, 114, 32, 101, 110, 105, 109, 32, 105, 110, 32, 108, 105, 98, 101, 114, 111, 46, 32, 83, 101, 100, 32, 101, 108, 101, 109, 101, 110, 116,
-117, 109, 44, 32, 112, 101, 100, 101, 32, 101, 103, 101, 116, 32, 112, 111, 114, 116, 97, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 44, 32, 100,
-117, 105, 32, 110, 117, 108, 108, 97, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 112, 101, 100, 101, 44, 32, 101, 103, 101, 116, 32, 118, 101,
-104, 105, 99, 117, 108, 97, 32, 111, 100, 105, 111, 32, 97, 110, 116, 101, 32, 97, 116, 32, 115, 101, 109, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 83, 101, 100, 32, 117, 108, 108, 97, 109,
-99, 111, 114, 112, 101, 114, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 105, 112, 115, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 114, 105,
-115, 117, 115, 32, 110, 105, 98, 104, 44, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 116, 101, 109,
-112, 117, 115, 32, 101, 103, 101, 116, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 97, 99, 44, 32, 110, 101, 113, 117, 101, 46, 32, 83,
-101, 100, 32, 113, 117, 105, 115, 32, 108, 111, 114, 101, 109, 32, 117, 116, 32, 116, 111, 114, 116, 111, 114, 32, 102, 97, 99, 105, 108, 105, 115, 105,
-115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 113, 117, 97, 109,
-32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 105, 112, 115, 117, 109, 46, 32, 77, 111, 114, 98, 105, 32, 97, 99, 32, 101, 108, 105, 116, 32, 113,
-117, 105, 115, 32, 116, 101, 108, 108, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 98, 108, 97, 110, 100, 105, 116, 46, 32, 77, 97,
-101, 99, 101, 110, 97, 115, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 115, 101, 109,
-46, 32, 78, 97, 109, 32, 115, 101, 100, 32, 101, 114, 111, 115, 32, 118, 101, 108, 32, 108, 97, 99, 117, 115, 32, 108, 111, 98, 111, 114, 116, 105,
-115, 32, 99, 111, 110, 103, 117, 101, 46, 32, 80, 114, 111, 105, 110, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 110, 117, 110, 99, 32, 108, 111,
-98, 111, 114, 116, 105, 115, 32, 111, 114, 99, 105, 46, 32, 68, 111, 110, 101, 99, 32, 101, 103, 101, 115, 116, 97, 115, 32, 101, 110, 105, 109, 32,
-101, 117, 32, 111, 100, 105, 111, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 100, 32, 109, 101, 116, 117, 115, 46, 32, 80, 101,
-108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 99, 116, 111, 114, 44, 32, 115, 101, 109, 32, 118, 97, 114, 105, 117, 115, 32, 108, 117,
-99, 116, 117, 115, 32, 116, 101, 109, 112, 117, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 109, 97, 103, 110, 97, 32, 99, 117, 114, 115, 117, 115,
-32, 110, 101, 113, 117, 101, 44, 32, 101, 116, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 100, 105, 97, 109, 32, 100, 105, 97, 109, 32, 113,
-117, 105, 115, 32, 112, 117, 114, 117, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 100,
-111, 108, 111, 114, 46, 32, 78, 117, 108, 108, 97, 32, 105, 110, 32, 109, 97, 103, 110, 97, 46, 32, 67, 114, 97, 115, 32, 105, 100, 32, 100, 105,
-97, 109, 32, 97, 116, 32, 108, 101, 99, 116, 117, 115, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32,
-78, 117, 110, 99, 32, 112, 111, 114, 116, 97, 32, 112, 111, 115, 117, 101, 114, 101, 32, 115, 97, 112, 105, 101, 110, 46, 32, 69, 116, 105, 97, 109,
-32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 46, 32, 67, 108, 97, 115, 115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116,
-105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101,
-114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104,
-121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109,
-105, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32,
-100, 105, 97, 109, 32, 110, 111, 110, 32, 117, 114, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 108, 117, 99, 116, 117, 115, 32, 112, 104, 97, 114,
-101, 116, 114, 97, 32, 116, 101, 108, 108, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 97, 99, 32, 105, 112, 115, 117, 109, 32, 101, 103, 101, 116,
-32, 108, 105, 98, 101, 114, 111, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 67, 114, 97, 115, 32,
-105, 100, 32, 116, 101, 108, 108, 117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 110, 111, 110, 32, 114, 105, 115, 117, 115, 46, 32, 73, 110, 32, 100,
-111, 108, 111, 114, 46, 32, 70, 117, 115, 99, 101, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 113, 117, 97, 109, 32, 105, 110, 32,
-109, 97, 115, 115, 97, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 114, 116, 97, 46, 32, 77, 111, 114, 98, 105, 32, 117, 116, 32, 100,
-111, 108, 111, 114, 32, 101, 117, 32, 109, 97, 115, 115, 97, 32, 101, 103, 101, 115, 116, 97, 115, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117,
-109, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105,
-116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115,
-115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 108, 101, 111, 32,
-105, 110, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 101, 114, 97, 116, 32, 97, 32, 117, 114, 110,
-97, 32, 108, 97, 111, 114, 101, 101, 116, 32, 115, 101, 109, 112, 101, 114, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 117,
-116, 32, 109, 101, 116, 117, 115, 32, 97, 99, 32, 116, 101, 108, 108, 117, 115, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 108, 101, 105, 102, 101,
-110, 100, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 113, 117, 105, 115, 32, 117, 114, 110, 97, 46, 32, 67, 117, 114, 97, 98,
-105, 116, 117, 114, 32, 108, 97, 99, 105, 110, 105, 97, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 100, 117, 105, 46, 32, 78, 97, 109, 32,
-110, 101, 99, 32, 97, 110, 116, 101, 46, 32, 73, 110, 32, 105, 100, 32, 101, 110, 105, 109, 46, 32, 65, 101, 110, 101, 97, 110, 32, 109, 97, 116,
-116, 105, 115, 32, 101, 110, 105, 109, 46, 32, 73, 110, 32, 117, 116, 32, 110, 101, 113, 117, 101, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32,
-114, 105, 115, 117, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 85, 116, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 101,
-99, 116, 117, 115, 32, 118, 105, 116, 97, 101, 32, 116, 111, 114, 116, 111, 114, 46, 32, 68, 117, 105, 115, 32, 118, 101, 108, 105, 116, 46, 32, 78,
-117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32,
-117, 114, 110, 97, 46, 32, 67, 114, 97, 115, 32, 118, 97, 114, 105, 117, 115, 32, 116, 111, 114, 116, 111, 114, 32, 105, 110, 32, 112, 101, 100, 101,
-46, 32, 83, 101, 100, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 108, 97, 99, 105, 110, 105,
-97, 32, 108, 105, 98, 101, 114, 111, 32, 110, 101, 99, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 97, 108, 105, 113, 117, 97, 109,
-32, 114, 105, 115, 117, 115, 32, 110, 111, 110, 32, 110, 105, 115, 108, 46, 32, 78, 97, 109, 32, 97, 32, 110, 117, 110, 99, 32, 101, 116, 32, 102,
-101, 108, 105, 115, 32, 116, 101, 109, 112, 111, 114, 32, 102, 101, 117, 103, 105, 97, 116, 46, 32, 78, 117, 110, 99, 32, 109, 101, 116, 117, 115, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 109, 101, 116, 117, 115, 32, 105, 110, 32, 115, 101,
-109, 112, 101, 114, 32, 108, 97, 111, 114, 101, 101, 116, 44, 32, 117, 114, 110, 97, 32, 105, 112, 115, 117, 109, 32, 112, 104, 97, 114, 101, 116, 114,
-97, 32, 108, 111, 114, 101, 109, 44, 32, 115, 101, 100, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 109, 97, 103, 110, 97, 32, 108, 111, 114,
-101, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 119, 105, 115, 105, 46, 32, 83, 101, 100, 32, 119, 105, 115, 105, 46, 32, 78, 117, 108, 108,
-97, 109, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 101, 108, 105, 116, 32, 115, 101, 100, 32, 110, 105, 115, 108, 46, 32, 80, 104, 97, 115,
-101, 108, 108, 117, 115, 32, 109, 97, 116, 116, 105, 115, 32, 108, 101, 111, 32, 110, 101, 99, 32, 109, 97, 115, 115, 97, 46, 32, 65, 101, 110, 101,
-97, 110, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 67, 114, 97, 115, 32, 119, 105, 115, 105, 32, 101, 114, 97, 116, 44, 32, 108, 111,
-98, 111, 114, 116, 105, 115, 32, 110, 101, 99, 44, 32, 99, 117, 114, 115, 117, 115, 32, 101, 103, 101, 116, 44, 32, 108, 111, 98, 111, 114, 116, 105,
-115, 32, 97, 116, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 73, 110, 32, 109, 97, 115, 115, 97, 32, 110, 105, 115, 108, 44, 32, 114, 117, 116,
-114, 117, 109, 32, 110, 111, 110, 44, 32, 99, 117, 114, 115, 117, 115, 32, 110, 101, 99, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 115, 101,
-100, 44, 32, 108, 97, 99, 117, 115, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97,
-46, 32, 67, 114, 97, 115, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 110, 101, 113, 117, 101, 32, 97, 99, 32, 115, 117, 115, 99, 105, 112, 105,
-116, 32, 116, 101, 109, 112, 117, 115, 44, 32, 118, 101, 108, 105, 116, 32, 108, 111, 114, 101, 109, 32, 108, 117, 99, 116, 117, 115, 32, 101, 108, 105,
-116, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 114, 104, 111, 110, 99, 117, 115, 32, 119, 105, 115, 105, 32, 101, 115, 116, 32, 117, 116, 32, 115,
-101, 109, 46, 32, 80, 114, 111, 105, 110, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 101, 110, 105, 109, 32, 105, 110, 32, 101, 114, 111, 115,
-32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 97, 99, 99, 117, 109, 115, 97, 110, 46, 32, 85, 116, 32, 108, 111, 114, 101, 109, 32, 110, 105,
-115, 108, 44, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 101, 116, 44, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 110, 101, 99, 44, 32,
-108, 97, 99, 105, 110, 105, 97, 32, 105, 110, 44, 32, 100, 111, 108, 111, 114, 46, 32, 68, 117, 105, 115, 32, 110, 101, 99, 32, 113, 117, 97, 109,
-46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 101, 108, 105, 116, 32, 102, 101, 108, 105, 115, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32,
-105, 100, 44, 32, 108, 117, 99, 116, 117, 115, 32, 113, 117, 105, 115, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 117, 116, 44, 32, 105, 112, 115,
-117, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 101, 103, 101, 116, 32, 97, 114, 99, 117, 46, 32, 77, 97, 117, 114, 105, 115, 32, 109,
-97, 115, 115, 97, 32, 102, 101, 108, 105, 115, 44, 32, 111, 114, 110, 97, 114, 101, 32, 110, 111, 110, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115,
-32, 105, 100, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 105, 110, 44, 32, 101, 108, 105, 116, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115,
-32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 109, 105, 32, 97, 99, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 102, 97, 99, 105, 108,
-105, 115, 105, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 101, 110, 105, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 108, 101, 111, 44, 32,
-110, 111, 110, 32, 110, 111, 110, 117, 109, 109, 121, 32, 112, 101, 100, 101, 32, 100, 105, 97, 109, 32, 101, 103, 101, 116, 32, 110, 105, 98, 104, 46,
-32, 83, 101, 100, 32, 116, 101, 109, 112, 117, 115, 46, 32, 65, 101, 110, 101, 97, 110, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 115, 117, 115,
-99, 105, 112, 105, 116, 32, 100, 117, 105, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116,
-46, 32, 85, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 78, 97, 109, 32, 99, 111, 109, 109, 111, 100, 111, 44, 32, 110, 117, 108,
-108, 97, 32, 117, 116, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 114, 117, 116, 114, 117, 109, 44, 32, 111, 114, 99, 105, 32, 101, 108, 105,
-116, 32, 118, 105, 118, 101, 114, 114, 97, 32, 100, 105, 97, 109, 44, 32, 118, 105, 116, 97, 101, 32, 109, 111, 108, 108, 105, 115, 32, 111, 100, 105,
-111, 32, 111, 100, 105, 111, 32, 101, 116, 32, 112, 117, 114, 117, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111,
-108, 117, 116, 112, 97, 116, 46, 32, 83, 101, 100, 32, 97, 108, 105, 113, 117, 101, 116, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 105, 112, 115,
-117, 109, 46, 32, 73, 110, 32, 117, 116, 32, 101, 115, 116, 46, 32, 69, 116, 105, 97, 109, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109,
-46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 116, 111, 114, 116, 111, 114,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 108, 97, 99, 117, 115, 46, 32, 65, 101, 110, 101, 97, 110, 32, 111, 114, 99, 105, 46, 32, 83, 117,
-115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 108, 97, 99, 117, 115, 32, 110, 117, 108, 108, 97, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 97,
-44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 101, 114,
-111, 115, 46, 32, 68, 111, 110, 101, 99, 32, 97, 117, 99, 116, 111, 114, 32, 103, 114, 97, 118, 105, 100, 97, 32, 110, 105, 115, 108, 46, 32, 67,
-114, 97, 115, 32, 97, 99, 32, 101, 115, 116, 32, 114, 117, 116, 114, 117, 109, 32, 97, 117, 103, 117, 101, 32, 112, 117, 108, 118, 105, 110, 97, 114,
-32, 111, 114, 110, 97, 114, 101, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 109, 97, 117, 114, 105, 115, 32, 110, 105, 98, 104, 44, 32,
-118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 105, 110, 44, 32, 114, 104, 111, 110, 99, 117, 115, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44,
-32, 100, 97, 112, 105, 98, 117, 115, 32, 101, 103, 101, 116, 44, 32, 108, 97, 99, 117, 115, 46, 32, 78, 97, 109, 32, 110, 117, 110, 99, 32, 109,
-97, 117, 114, 105, 115, 44, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 97, 116, 44, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 97, 44,
-32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 97, 116, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32, 78, 97, 109, 32, 97, 99, 99, 117, 109,
-115, 97, 110, 32, 109, 111, 108, 108, 105, 115, 32, 108, 105, 98, 101, 114, 111, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 99, 111, 110, 100, 105,
-109, 101, 110, 116, 117, 109, 32, 109, 97, 116, 116, 105, 115, 32, 101, 115, 116, 46, 32, 68, 111, 110, 101, 99, 32, 108, 97, 99, 117, 115, 46, 32,
-78, 117, 108, 108, 97, 109, 32, 97, 99, 32, 115, 97, 112, 105, 101, 110, 32, 105, 100, 32, 109, 97, 115, 115, 97, 32, 108, 111, 98, 111, 114, 116,
-105, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 108, 101, 109, 101, 110,
-116, 117, 109, 46, 32, 80, 114, 111, 105, 110, 32, 117, 116, 32, 112, 117, 114, 117, 115, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 101, 116, 32,
-115, 97, 112, 105, 101, 110, 32, 113, 117, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 99, 111, 109, 109, 111, 100, 111, 32, 109, 111, 108, 108, 105,
-115, 46, 32, 78, 117, 108, 108, 97, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 46, 32, 80, 114, 111, 105, 110, 32, 97, 32, 119, 105, 115, 105,
-32, 117, 116, 32, 116, 101, 108, 108, 117, 115, 32, 98, 108, 97, 110, 100, 105, 116, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 46, 32, 65, 108,
-105, 113, 117, 97, 109, 32, 110, 117, 108, 108, 97, 32, 108, 111, 114, 101, 109, 44, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 97, 99, 44, 32,
-109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 118, 101, 108, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 101, 116, 44, 32, 109, 101, 116,
-117, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 101, 103, 101, 115, 116, 97, 115, 32, 110, 105, 98, 104, 32, 101, 116, 32, 108, 105,
-103, 117, 108, 97, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 100, 105, 97, 109, 32, 111, 100, 105, 111, 44, 32, 108, 97, 99, 105, 110, 105, 97,
-32, 113, 117, 105, 115, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 113, 117, 105, 115, 44, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117,
-100, 105, 110, 32, 117, 116, 44, 32, 101, 114, 111, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 108, 105, 113, 117, 101, 116, 32,
-108, 111, 114, 101, 109, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 83, 101, 100, 32, 99, 117, 114, 115, 117, 115, 32, 116, 101, 108, 108, 117,
-115, 32, 97, 99, 32, 111, 114, 99, 105, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 116, 32, 110, 117, 108, 108, 97, 46, 32, 68,
-111, 110, 101, 99, 32, 112, 111, 114, 116, 97, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 110, 116, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 83, 101, 100, 32, 105, 100, 32, 108, 101,
-99, 116, 117, 115, 32, 97, 116, 32, 109, 97, 115, 115, 97, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 116, 114, 105, 115, 116, 105,
-113, 117, 101, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 108, 97, 99, 117, 115,
-46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105, 116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109,
-115, 116, 46, 32, 78, 117, 110, 99, 32, 110, 111, 110, 32, 116, 117, 114, 112, 105, 115, 46, 32, 83, 101, 100, 32, 115, 97, 103, 105, 116, 116, 105,
-115, 46, 32, 77, 111, 114, 98, 105, 32, 108, 97, 111, 114, 101, 101, 116, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 100, 117, 105,
-46, 32, 78, 97, 109, 32, 97, 114, 99, 117, 32, 116, 101, 108, 108, 117, 115, 44, 32, 116, 101, 109, 112, 111, 114, 32, 118, 105, 116, 97, 101, 44,
-32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 116, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 117, 116, 44, 32, 118, 101,
-108, 105, 116, 46, 32, 73, 110, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 97, 117, 103, 117, 101, 32, 97, 32, 97, 114, 99, 117, 32, 118, 111,
-108, 117, 116, 112, 97, 116, 32, 115, 117, 115, 99, 105, 112, 105, 116, 46, 32, 68, 111, 110, 101, 99, 32, 100, 105, 99, 116, 117, 109, 32, 117, 108,
-116, 114, 105, 99, 101, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 32, 112, 117, 114, 117, 115,
-32, 101, 116, 32, 111, 114, 99, 105, 32, 100, 105, 99, 116, 117, 109, 32, 108, 97, 99, 105, 110, 105, 97, 46, 32, 85, 116, 32, 108, 101, 111, 46,
-32, 67, 114, 97, 115, 32, 115, 101, 109, 112, 101, 114, 44, 32, 108, 111, 114, 101, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 116, 105, 110,
-99, 105, 100, 117, 110, 116, 32, 99, 111, 110, 103, 117, 101, 44, 32, 106, 117, 115, 116, 111, 32, 101, 114, 111, 115, 32, 118, 97, 114, 105, 117, 115,
-32, 112, 101, 100, 101, 44, 32, 105, 110, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 116, 117, 114, 112, 105, 115, 32, 108, 101, 99, 116, 117, 115,
-32, 110, 111, 110, 32, 101, 114, 111, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 113, 117, 97, 109, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 109, 97, 116, 116, 105, 115, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 109, 97, 103, 110, 97,
-46, 32, 65, 101, 110, 101, 97, 110, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 100, 105, 97, 109, 32, 118, 101, 108, 32, 110, 105, 115, 108,
-32, 110, 111, 110, 117, 109, 109, 121, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115,
-101, 32, 118, 101, 108, 32, 100, 111, 108, 111, 114, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 110, 111, 110, 117, 109, 109, 121, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 115, 101, 109, 112, 101, 114, 32, 97, 110, 116, 101, 46, 32, 77,
-97, 101, 99, 101, 110, 97, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 101, 114, 111, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108,
-117, 109, 32, 97, 99, 32, 100, 111, 108, 111, 114, 46, 32, 70, 117, 115, 99, 101, 32, 114, 105, 115, 117, 115, 32, 109, 101, 116, 117, 115, 44, 32,
-97, 108, 105, 113, 117, 101, 116, 32, 101, 103, 101, 116, 44, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 101, 116, 44, 32, 102, 101, 117, 103,
-105, 97, 116, 32, 118, 101, 108, 44, 32, 111, 114, 99, 105, 46, 32, 85, 116, 32, 97, 116, 32, 110, 117, 110, 99, 32, 105, 100, 32, 97, 110, 116,
-101, 32, 115, 111, 100, 97, 108, 101, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 46, 32, 68, 117, 105, 115, 32, 116, 114, 105, 115, 116, 105,
-113, 117, 101, 32, 109, 97, 116, 116, 105, 115, 32, 97, 110, 116, 101, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 110, 101, 113, 117,
-101, 32, 109, 97, 117, 114, 105, 115, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 105, 100, 44, 32, 99, 111, 110, 103, 117, 101, 32, 105, 110, 116,
-101, 114, 100, 117, 109, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 117, 116, 44, 32, 100, 105, 97, 109, 46, 32, 78, 117, 108, 108, 97, 32, 118,
-111, 108, 117, 116, 112, 97, 116, 32, 98, 108, 97, 110, 100, 105, 116, 32, 109, 97, 103, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 99,
-117, 109, 115, 97, 110, 32, 99, 111, 110, 103, 117, 101, 32, 100, 105, 97, 109, 46, 32, 69, 116, 105, 97, 109, 32, 118, 101, 108, 32, 100, 117, 105,
-32, 101, 103, 101, 116, 32, 110, 105, 115, 108, 32, 116, 101, 109, 112, 111, 114, 32, 118, 97, 114, 105, 117, 115, 46, 32, 67, 114, 97, 115, 32, 100,
-105, 99, 116, 117, 109, 32, 109, 97, 115, 115, 97, 32, 115, 101, 100, 32, 101, 110, 105, 109, 46, 32, 67, 114, 97, 115, 32, 117, 114, 110, 97, 32,
-116, 111, 114, 116, 111, 114, 44, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 97, 99, 44, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101,
-114, 32, 105, 110, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 118, 101, 108, 44, 32, 97, 114, 99, 117, 46, 32, 77, 111, 114, 98, 105, 32, 112,
-111, 115, 117, 101, 114, 101, 32, 108, 117, 99, 116, 117, 115, 32, 97, 117, 103, 117, 101, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 100, 117, 105,
-32, 100, 117, 105, 44, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 105, 110, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 101, 117,
-44, 32, 108, 117, 99, 116, 117, 115, 32, 101, 117, 44, 32, 110, 117, 108, 108, 97, 46, 32, 67, 114, 97, 115, 32, 118, 101, 108, 105, 116, 32, 112,
-101, 100, 101, 44, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 102, 101, 117, 103, 105,
-97, 116, 32, 105, 110, 44, 32, 97, 117, 99, 116, 111, 114, 32, 118, 105, 116, 97, 101, 44, 32, 97, 110, 116, 101, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 100, 105, 99, 116, 117, 109, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 109, 97, 117, 114, 105, 115, 46, 32,
-73, 110, 32, 97, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 32, 108, 105, 103, 117, 108, 97, 46, 32, 73, 110, 32, 113,
-117, 97, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 105, 116, 97, 101, 32, 117, 114, 110, 97, 32, 117, 108, 116, 114, 105, 99, 105,
-101, 115, 32, 115, 101, 109, 32, 97, 108, 105, 113, 117, 97, 109, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32, 65, 108, 105, 113, 117, 97, 109,
-32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 78, 97, 109, 32, 101, 115, 116, 46, 32, 68, 111, 110, 101, 99, 32, 102,
-97, 117, 99, 105, 98, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 109, 101, 116, 117, 115, 46, 32, 85, 116, 32, 99, 111, 110, 103, 117, 101,
-46, 32, 68, 111, 110, 101, 99, 32, 97, 114, 99, 117, 32, 116, 101, 108, 108, 117, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 97, 99,
-44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 97, 99, 44, 32, 109, 111, 108, 108, 105, 115, 32, 115, 101, 100, 44, 32, 108, 101, 99, 116,
-117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 118, 111, 108, 117, 116,
-112, 97, 116, 32, 110, 117, 110, 99, 32, 101, 116, 32, 102, 101, 108, 105, 115, 46, 32, 83, 101, 100, 32, 112, 101, 100, 101, 32, 111, 100, 105, 111,
-44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 105, 110, 44, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 109, 97, 108, 101, 115, 117, 97,
-100, 97, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 103, 114, 97, 118, 105, 100, 97, 44, 32, 110, 117, 108, 108, 97, 46, 32, 78, 117, 108, 108,
-97, 32, 97, 108, 105, 113, 117, 97, 109, 32, 112, 101, 100, 101, 32, 118, 105, 116, 97, 101, 32, 97, 114, 99, 117, 46, 32, 80, 114, 111, 105, 110,
-32, 118, 101, 108, 105, 116, 32, 101, 108, 105, 116, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 101,
-108, 101, 109, 101, 110, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 118, 97, 114, 105, 117, 115, 32, 118, 105, 116, 97, 101, 44, 32, 100, 111,
-108, 111, 114, 46, 32, 68, 111, 110, 101, 99, 32, 114, 117, 116, 114, 117, 109, 32, 105, 112, 115, 117, 109, 32, 101, 117, 32, 109, 105, 46, 32, 65,
-108, 105, 113, 117, 97, 109, 32, 101, 116, 32, 115, 101, 109, 46, 32, 73, 110, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 114, 104, 111,
-110, 99, 117, 115, 32, 118, 101, 108, 105, 116, 46, 32, 78, 97, 109, 32, 118, 105, 118, 101, 114, 114, 97, 32, 115, 99, 101, 108, 101, 114, 105, 115,
-113, 117, 101, 32, 97, 114, 99, 117, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 115, 101, 109, 46, 32, 83, 101, 100, 32, 116, 105, 110, 99, 105,
-100, 117, 110, 116, 32, 110, 117, 108, 108, 97, 32, 113, 117, 105, 115, 32, 109, 97, 115, 115, 97, 46, 32, 77, 97, 117, 114, 105, 115, 32, 102, 97,
-117, 99, 105, 98, 117, 115, 32, 116, 101, 109, 112, 117, 115, 32, 110, 117, 110, 99, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 99, 111,
-110, 100, 105, 109, 101, 110, 116, 117, 109, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 108, 105, 113, 117, 101, 116, 32, 105, 97, 99,
-117, 108, 105, 115, 32, 115, 97, 112, 105, 101, 110, 46, 32, 78, 117, 110, 99, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 111, 100, 105, 111, 32,
-118, 105, 116, 97, 101, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 44, 32, 116, 101, 108, 108, 117, 115,
-32, 108, 105, 98, 101, 114, 111, 32, 99, 111, 109, 109, 111, 100, 111, 32, 105, 112, 115, 117, 109, 44, 32, 117, 116, 32, 115, 111, 108, 108, 105, 99,
-105, 116, 117, 100, 105, 110, 32, 110, 105, 115, 108, 32, 110, 105, 115, 108, 32, 118, 101, 108, 32, 106, 117, 115, 116, 111, 46, 32, 78, 117, 108, 108,
-97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 98, 108, 97, 110, 100, 105, 116, 32, 101, 110, 105,
-109, 32, 117, 116, 32, 106, 117, 115, 116, 111, 46, 32, 80, 114, 111, 105, 110, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 44, 32, 101, 108, 105,
-116, 32, 101, 103, 101, 116, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 112, 117, 108, 118, 105, 110, 97, 114, 44, 32, 111, 114, 99, 105, 32, 113,
-117, 97, 109, 32, 97, 117, 99, 116, 111, 114, 32, 110, 101, 113, 117, 101, 44, 32, 115, 101, 100, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32,
-100, 105, 97, 109, 32, 112, 117, 114, 117, 115, 32, 118, 101, 108, 32, 102, 101, 108, 105, 115, 46, 32, 83, 101, 100, 32, 111, 114, 99, 105, 32, 108,
-101, 111, 44, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 118, 101, 108, 44, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 111, 110, 44, 32, 115,
-101, 109, 112, 101, 114, 32, 101, 117, 44, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44,
-32, 108, 105, 98, 101, 114, 111, 32, 97, 99, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 99, 111, 109, 109, 111, 100, 111, 44,
-32, 101, 114, 111, 115, 32, 115, 97, 112, 105, 101, 110, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 105, 115, 108, 44, 32, 101, 117, 32, 101, 108,
-101, 105, 102, 101, 110, 100, 32, 110, 105, 98, 104, 32, 110, 105, 98, 104, 32, 118, 101, 108, 32, 108, 101, 99, 116, 117, 115, 46, 32, 86, 105, 118,
-97, 109, 117, 115, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 111, 100, 105, 111, 32, 100, 111, 108, 111,
-114, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 110, 111, 110, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 105, 100, 44, 32, 118, 105, 118,
-101, 114, 114, 97, 32, 101, 103, 101, 116, 44, 32, 100, 105, 97, 109, 46, 32, 78, 117, 110, 99, 32, 109, 97, 117, 114, 105, 115, 32, 109, 97, 103,
-110, 97, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 105, 100, 44, 32, 102, 101,
-114, 109, 101, 110, 116, 117, 109, 32, 118, 105, 118, 101, 114, 114, 97, 44, 32, 109, 105, 46, 32, 65, 101, 110, 101, 97, 110, 32, 115, 117, 115, 99,
-105, 112, 105, 116, 32, 110, 105, 115, 108, 32, 110, 111, 110, 32, 110, 117, 110, 99, 46, 32, 80, 114, 111, 105, 110, 32, 113, 117, 105, 115, 32, 108,
-101, 99, 116, 117, 115, 32, 97, 99, 32, 116, 101, 108, 108, 117, 115, 32, 110, 111, 110, 117, 109, 109, 121, 32, 99, 111, 109, 109, 111, 100, 111, 46,
-32, 78, 117, 110, 99, 32, 101, 103, 101, 116, 32, 100, 105, 97, 109, 32, 97, 99, 32, 101, 108, 105, 116, 32, 118, 101, 115, 116, 105, 98, 117, 108,
-117, 109, 32, 97, 117, 99, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 111, 100, 105, 111,
-32, 115, 101, 100, 32, 108, 97, 99, 105, 110, 105, 97, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 44, 32, 106, 117, 115, 116, 111, 32, 109, 105,
-32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 112, 117, 114, 117, 115, 44, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 117, 105, 115, 109,
-111, 100, 32, 108, 105, 98, 101, 114, 111, 32, 109, 101, 116, 117, 115, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 101, 99,
-101, 110, 97, 115, 32, 97, 99, 32, 101, 108, 105, 116, 32, 115, 101, 100, 32, 108, 111, 114, 101, 109, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101,
-32, 103, 114, 97, 118, 105, 100, 97, 46, 32, 80, 114, 111, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 101, 114, 111, 115, 44, 32, 117, 108, 108,
-97, 109, 99, 111, 114, 112, 101, 114, 32, 105, 100, 44, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 113, 117, 105, 115, 44, 32, 99, 111, 110, 100,
-105, 109, 101, 110, 116, 117, 109, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 44, 32, 115, 97, 112, 105, 101, 110, 46, 32, 83, 101, 100, 32, 101,
-116, 32, 109, 97, 115, 115, 97, 32, 101, 103, 101, 116, 32, 108, 111, 114, 101, 109, 32, 97, 108, 105, 113, 117, 101, 116, 32, 116, 101, 109, 112, 117,
-115, 46, 32, 68, 117, 105, 115, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 110, 105, 115, 108, 32, 110, 111, 110, 32, 114, 105, 115, 117, 115,
-46, 32, 78, 97, 109, 32, 105, 100, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 109, 32, 101, 115, 116, 46, 32, 80, 114, 111, 105, 110,
-32, 111, 114, 99, 105, 32, 100, 105, 97, 109, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32, 101, 116, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97,
-32, 99, 111, 109, 109, 111, 100, 111, 44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 101, 108, 44, 32, 101, 110, 105, 109, 46, 32, 80, 114, 111, 105,
-110, 32, 101, 103, 101, 116, 32, 101, 114, 97, 116, 46, 32, 68, 111, 110, 101, 99, 32, 110, 105, 115, 108, 46, 32, 77, 97, 101, 99, 101, 110, 97,
-115, 32, 97, 117, 99, 116, 111, 114, 32, 118, 101, 108, 105, 116, 32, 117, 116, 32, 112, 101, 100, 101, 46, 32, 78, 117, 110, 99, 32, 118, 105, 116,
-97, 101, 32, 108, 101, 99, 116, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101, 114, 111, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 104,
-101, 110, 100, 114, 101, 114, 105, 116, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 118, 97, 114, 105, 117, 115, 44, 32, 101, 114, 97, 116, 32, 117,
-108, 116, 114, 105, 99, 101, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 112, 117, 114, 117, 115, 32,
-108, 97, 99, 117, 115, 32, 100, 105, 99, 116, 117, 109, 32, 101, 114, 111, 115, 44, 32, 97, 116, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117,
-109, 32, 101, 110, 105, 109, 32, 100, 117, 105, 32, 110, 101, 99, 32, 109, 97, 103, 110, 97, 46, 32, 77, 111, 114, 98, 105, 32, 100, 105, 97, 109,
-46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 115, 101, 100, 32, 101, 115, 116, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 110,
-101, 99, 32, 108, 105, 98, 101, 114, 111, 32, 105, 110, 32, 97, 114, 99, 117, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 115, 111, 108, 108,
-105, 99, 105, 116, 117, 100, 105, 110, 46, 32, 73, 110, 32, 114, 117, 116, 114, 117, 109, 32, 110, 105, 115, 108, 32, 97, 116, 32, 97, 114, 99, 117,
-46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 100, 105, 103, 110, 105, 115, 115,
-105, 109, 46, 32, 69, 116, 105, 97, 109, 32, 101, 115, 116, 32, 109, 97, 117, 114, 105, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 115,
-101, 100, 44, 32, 118, 105, 118, 101, 114, 114, 97, 32, 101, 116, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 115, 101, 100, 44, 32, 110,
-101, 113, 117, 101, 46, 32, 85, 116, 32, 97, 116, 32, 108, 101, 99, 116, 117, 115, 32, 105, 100, 32, 110, 105, 98, 104, 32, 108, 117, 99, 116, 117,
-115, 32, 111, 114, 110, 97, 114, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 97, 114, 105, 117, 115, 32, 112, 111, 114, 116, 116, 105, 116, 111,
-114, 32, 114, 105, 115, 117, 115, 46, 32, 85, 116, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 97, 108, 105, 113, 117, 101, 116, 32, 114, 105,
-115, 117, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 117, 99, 116, 117, 115, 32, 110, 101, 113, 117, 101, 32, 115, 105, 116,
-32, 97, 109, 101, 116, 32, 110, 117, 110, 99, 46, 32, 68, 117, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 110, 105, 98, 104, 46,
-32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 100, 97, 112, 105, 98, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 101, 114, 111,
-115, 32, 108, 105, 98, 101, 114, 111, 44, 32, 97, 108, 105, 113, 117, 97, 109, 32, 110, 111, 110, 44, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116,
-117, 109, 32, 97, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 117, 116, 44, 32, 116, 117, 114, 112, 105, 115, 46, 32, 73, 110, 116, 101, 103, 101,
-114, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 109, 105, 32, 115, 101, 100, 32, 108, 111, 114, 101, 109, 46, 32, 86, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 115, 111, 100, 97, 108, 101, 115, 32, 110, 105, 115, 108, 46, 32, 78,
-117, 108, 108, 97, 32, 101, 117, 32, 106, 117, 115, 116, 111, 32, 113, 117, 105, 115, 32, 100, 117, 105, 32, 112, 114, 101, 116, 105, 117, 109, 32, 114,
-104, 111, 110, 99, 117, 115, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 105, 118, 101, 114, 114, 97, 32, 99, 111, 109, 109, 111, 100, 111,
-32, 109, 105, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 100, 111, 108, 111, 114, 32, 108, 105, 98, 101, 114, 111, 44, 32, 118, 105, 118, 101,
-114, 114, 97, 32, 97, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32,
-118, 105, 116, 97, 101, 44, 32, 100, 117, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 108, 101, 99,
-116, 117, 115, 32, 101, 116, 32, 109, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 115, 97, 103, 105, 116, 116, 105, 115, 46, 32, 83, 101, 100, 32,
-97, 114, 99, 117, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 99, 116, 111, 114, 46, 32, 68, 111, 110, 101, 99,
-32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 112, 117, 114, 117, 115, 32, 110, 111, 110, 32, 116, 101, 108, 108, 117, 115, 46, 32,
-85, 116, 32, 108, 101, 111, 32, 119, 105, 115, 105, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 44, 32, 103, 114, 97, 118, 105, 100, 97, 32, 97, 99, 44, 32, 108, 105, 98, 101, 114, 111, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 100, 97, 112, 105, 98, 117, 115, 32, 100, 105, 97, 109, 46, 32,
-73, 110, 116, 101, 103, 101, 114, 32, 113, 117, 105, 115, 32, 108, 97, 99, 117, 115, 32, 100, 97, 112, 105, 98, 117, 115, 32, 111, 100, 105, 111, 32,
-112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 97, 114, 105, 117, 115, 46, 32, 70, 117, 115, 99, 101, 32, 112, 101, 100, 101, 32,
-113, 117, 97, 109, 44, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 117, 116, 44, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 101, 116, 44, 32,
-116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 115, 101, 100, 44, 32, 102, 101, 108, 105, 115, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32,
-101, 114, 111, 115, 32, 101, 110, 105, 109, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 115, 101, 100, 44, 32, 97, 108, 105, 113, 117, 97,
-109, 32, 97, 99, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 97, 99, 44, 32, 101, 114, 97, 116, 46, 32, 85, 116, 32, 100, 105, 103, 110, 105,
-115, 115, 105, 109, 44, 32, 108, 97, 99, 117, 115, 32, 97, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 105, 97, 99, 117, 108, 105, 115, 44, 32,
-101, 110, 105, 109, 32, 111, 114, 99, 105, 32, 112, 111, 115, 117, 101, 114, 101, 32, 110, 117, 110, 99, 44, 32, 110, 101, 99, 32, 117, 108, 116, 114,
-105, 99, 105, 101, 115, 32, 108, 101, 99, 116, 117, 115, 32, 114, 105, 115, 117, 115, 32, 105, 110, 32, 111, 100, 105, 111, 46, 32, 69, 116, 105, 97,
-109, 32, 101, 116, 32, 109, 97, 115, 115, 97, 32, 105, 100, 32, 100, 117, 105, 32, 99, 111, 109, 109, 111, 100, 111, 32, 118, 101, 104, 105, 99, 117,
-108, 97, 46, 32, 78, 117, 110, 99, 32, 98, 108, 97, 110, 100, 105, 116, 32, 116, 111, 114, 116, 111, 114, 32, 113, 117, 105, 115, 32, 100, 117, 105,
-46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 110, 105, 115, 108, 46, 32, 83, 101, 100, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 98, 108,
-97, 110, 100, 105, 116, 32, 108, 105, 103, 117, 108, 97, 46, 32, 70, 117, 115, 99, 101, 32, 118, 105, 118, 101, 114, 114, 97, 32, 105, 109, 112, 101,
-114, 100, 105, 101, 116, 32, 109, 97, 103, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 101, 103, 101, 116, 32, 110, 117, 110, 99, 32, 113, 117, 105,
-115, 32, 101, 115, 116, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 108, 111, 98, 111, 114, 116, 105, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 32, 113, 117, 105, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 111, 114, 99, 105,
-32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 110, 117, 110, 99, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 98, 105, 98, 101, 110, 100, 117,
-109, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 103, 101, 116, 32, 108, 101, 111, 46, 32, 77, 111, 114, 98, 105, 32,
-118, 101, 108, 32, 117, 114, 110, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 114, 97, 116, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109,
-32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 46, 32, 83, 101, 100, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 108, 105, 98, 101, 114,
-111, 32, 101, 116, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 99, 111, 110, 103, 117, 101, 44, 32, 119, 105, 115, 105, 32, 108,
-101, 99, 116, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 100, 111, 108, 111, 114, 44, 32, 101, 103, 101, 116, 32, 109, 111, 108, 101, 115, 116,
-105, 101, 32, 109, 97, 103, 110, 97, 32, 111, 114, 99, 105, 32, 118, 101, 108, 32, 116, 101, 108, 108, 117, 115, 46, 32, 83, 101, 100, 32, 116, 101,
-109, 112, 111, 114, 32, 97, 110, 116, 101, 32, 101, 116, 32, 101, 110, 105, 109, 46, 32, 77, 97, 117, 114, 105, 115, 32, 101, 108, 105, 116, 46, 32,
-67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 109,
-97, 115, 115, 97, 46, 32, 83, 101, 100, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 68, 117, 105, 115, 32, 110, 117, 108, 108, 97, 46, 32, 78,
-97, 109, 32, 98, 105, 98, 101, 110, 100, 117, 109, 46, 32, 78, 97, 109, 32, 116, 111, 114, 116, 111, 114, 32, 108, 111, 114, 101, 109, 44, 32, 117,
-108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 118, 105, 116, 97, 101, 44, 32, 100, 105, 99, 116, 117, 109, 32, 115, 101, 100, 44, 32, 112, 111,
-115, 117, 101, 114, 101, 32, 101, 117, 44, 32, 106, 117, 115, 116, 111, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 97, 100, 105, 112, 105, 115, 99,
-105, 110, 103, 32, 97, 114, 99, 117, 32, 118, 105, 116, 97, 101, 32, 116, 117, 114, 112, 105, 115, 46, 32, 68, 111, 110, 101, 99, 32, 109, 97, 108,
-101, 115, 117, 97, 100, 97, 32, 112, 111, 115, 117, 101, 114, 101, 32, 108, 105, 98, 101, 114, 111, 46, 32, 85, 116, 32, 115, 101, 100, 32, 116, 101,
-108, 108, 117, 115, 46, 32, 70, 117, 115, 99, 101, 32, 115, 101, 100, 32, 110, 117, 110, 99, 32, 101, 103, 101, 116, 32, 110, 105, 115, 108, 32, 100,
-97, 112, 105, 98, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111,
-116, 101, 110, 116, 105, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 108, 105, 98, 101, 114, 111, 32,
-101, 116, 32, 109, 101, 116, 117, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 77, 97, 101, 99, 101,
-110, 97, 115, 32, 110, 111, 110, 32, 115, 101, 109, 32, 110, 111, 110, 32, 113, 117, 97, 109, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 98,
-108, 97, 110, 100, 105, 116, 46, 32, 68, 117, 105, 115, 32, 114, 105, 115, 117, 115, 32, 116, 101, 108, 108, 117, 115, 44, 32, 114, 117, 116, 114, 117,
-109, 32, 118, 105, 116, 97, 101, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 110, 101, 99, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100,
-97, 32, 110, 101, 99, 44, 32, 105, 112, 115, 117, 109, 46, 32, 78, 117, 110, 99, 32, 113, 117, 97, 109, 32, 100, 111, 108, 111, 114, 44, 32, 108,
-117, 99, 116, 117, 115, 32, 101, 103, 101, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 110, 111, 110, 44, 32, 114, 104, 111, 110, 99, 117,
-115, 32, 97, 116, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32, 68, 117, 105, 115, 32, 112, 101, 100, 101, 32, 108, 101, 99, 116, 117, 115, 44, 32,
-109, 97, 116, 116, 105, 115, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 44, 32, 116, 101, 109, 112, 111, 114, 32, 117, 116, 44, 32, 112, 111,
-114, 116, 97, 32, 97, 116, 44, 32, 109, 105, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 114, 105, 115, 117, 115, 32, 110,
-117, 108, 108, 97, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 115, 101, 100, 44, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 105, 100, 44, 32,
-110, 111, 110, 117, 109, 109, 121, 32, 118, 105, 116, 97, 101, 44, 32, 108, 105, 103, 117, 108, 97, 46, 32, 77, 111, 114, 98, 105, 32, 112, 117, 108,
-118, 105, 110, 97, 114, 32, 112, 101, 100, 101, 32, 117, 116, 32, 109, 97, 115, 115, 97, 46, 32, 78, 117, 110, 99, 32, 114, 105, 115, 117, 115, 32,
-109, 97, 117, 114, 105, 115, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 101, 116, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 101,
-117, 44, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 118, 101, 108, 44, 32, 111, 114, 99, 105, 46, 32, 73, 110, 32, 102, 97, 117, 99, 105, 98,
-117, 115, 32, 102, 101, 108, 105, 115, 32, 105, 110, 32, 97, 114, 99, 117, 46, 32, 78, 117, 108, 108, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116,
-32, 101, 108, 105, 116, 46, 32, 78, 117, 108, 108, 97, 32, 101, 114, 97, 116, 32, 115, 97, 112, 105, 101, 110, 44, 32, 115, 97, 103, 105, 116, 116,
-105, 115, 32, 101, 103, 101, 116, 44, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 101, 103, 101, 116, 44, 32, 118, 105, 118, 101, 114, 114, 97,
-32, 101, 117, 44, 32, 102, 101, 108, 105, 115, 46, 32, 78, 97, 109, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 116, 117, 114, 112, 105, 115, 32, 118, 101, 108, 32, 115, 101, 109, 32, 108,
-97, 99, 105, 110, 105, 97, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 46, 32, 77, 97, 117, 114, 105, 115, 32, 111, 114, 110, 97, 114,
-101, 32, 105, 112, 115, 117, 109, 32, 115, 101, 100, 32, 108, 105, 103, 117, 108, 97, 46, 32, 68, 117, 105, 115, 32, 102, 97, 99, 105, 108, 105, 115,
-105, 115, 32, 110, 101, 113, 117, 101, 32, 113, 117, 105, 115, 32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 101, 116, 32, 101, 114,
-97, 116, 32, 101, 116, 32, 111, 114, 99, 105, 32, 108, 97, 99, 105, 110, 105, 97, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 46,
-32, 68, 111, 110, 101, 99, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 68, 117, 105, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 105,
-112, 115, 117, 109, 32, 97, 99, 32, 97, 114, 99, 117, 46, 32, 65, 101, 110, 101, 97, 110, 32, 99, 111, 110, 103, 117, 101, 32, 97, 99, 99, 117,
-109, 115, 97, 110, 32, 97, 110, 116, 101, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44, 32, 108, 101, 111,
-32, 117, 116, 32, 111, 114, 110, 97, 114, 101, 32, 97, 108, 105, 113, 117, 97, 109, 44, 32, 110, 117, 110, 99, 32, 101, 114, 97, 116, 32, 99, 111,
-110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 97, 114, 99, 117, 44, 32, 117, 116, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 109, 105, 32, 97,
-117, 103, 117, 101, 32, 101, 116, 32, 110, 117, 108, 108, 97, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 97, 99, 105, 110, 105, 97, 32, 97,
-108, 105, 113, 117, 101, 116, 32, 119, 105, 115, 105, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 100, 117, 105, 46, 32, 69, 116,
-105, 97, 109, 32, 119, 105, 115, 105, 32, 108, 101, 111, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 118, 105, 116, 97, 101, 44, 32, 118, 117, 108,
-112, 117, 116, 97, 116, 101, 32, 97, 44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 113, 117, 97, 109, 46, 32, 81, 117,
-105, 115, 113, 117, 101, 32, 113, 117, 105, 115, 32, 116, 111, 114, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 105, 110, 116, 101, 114, 100, 117,
-109, 46, 32, 73, 110, 32, 109, 97, 115, 115, 97, 32, 101, 114, 97, 116, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 101, 100, 44,
-32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 118, 101, 108, 44, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 102, 114, 105, 110, 103, 105, 108,
-108, 97, 44, 32, 97, 117, 103, 117, 101, 46, 32, 78, 117, 108, 108, 97, 32, 118, 101, 108, 32, 117, 114, 110, 97, 46, 32, 73, 110, 32, 108, 105,
-98, 101, 114, 111, 32, 109, 105, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 115, 101, 100, 44, 32, 109, 97, 116, 116, 105, 115, 32, 116, 101, 109,
-112, 117, 115, 44, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 115, 101, 100, 44, 32, 109, 97, 115, 115, 97, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 113, 117, 97, 109, 32, 119, 105, 115, 105, 44, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 113, 117, 105, 115, 44,
-32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 97, 116, 44, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 32, 101, 103, 101, 116, 44, 32, 111, 100,
-105, 111, 46, 32, 78, 117, 108, 108, 97, 109, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44, 32, 112, 117, 114, 117, 115, 32, 113, 117, 105, 115,
-32, 97, 108, 105, 113, 117, 97, 109, 32, 99, 117, 114, 115, 117, 115, 44, 32, 116, 117, 114, 112, 105, 115, 32, 111, 100, 105, 111, 32, 101, 103, 101,
-115, 116, 97, 115, 32, 106, 117, 115, 116, 111, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 103, 114, 97, 118, 105, 100, 97, 32, 116, 117, 114,
-112, 105, 115, 32, 119, 105, 115, 105, 32, 118, 101, 108, 32, 116, 111, 114, 116, 111, 114, 46, 32, 78, 117, 110, 99, 32, 117, 108, 116, 114, 105, 99,
-105, 101, 115, 32, 112, 111, 114, 116, 97, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109,
-32, 101, 114, 97, 116, 32, 97, 99, 32, 111, 114, 99, 105, 46, 32, 85, 116, 32, 118, 101, 108, 32, 109, 97, 103, 110, 97, 32, 110, 101, 99, 32,
-109, 105, 32, 102, 101, 117, 103, 105, 97, 116, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 46, 32, 85, 116, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110,
-32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101,
-115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32, 68, 111, 110, 101, 99, 32, 101,
-116, 32, 109, 97, 103, 110, 97, 32, 105, 110, 32, 100, 105, 97, 109, 32, 112, 111, 114, 116, 97, 32, 110, 111, 110, 117, 109, 109, 121, 46, 32, 77,
-97, 101, 99, 101, 110, 97, 115, 32, 117, 116, 32, 115, 101, 109, 32, 105, 110, 32, 116, 117, 114, 112, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116,
-117, 109, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 97, 116, 32, 111, 114, 99, 105, 46,
-32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105,
-115, 116, 105, 113, 117, 101, 32, 115, 101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101,
-115, 117, 97, 100, 97, 32, 102, 97, 109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 86,
-101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102,
-97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32,
-112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115,
-113, 117, 101, 32, 114, 117, 116, 114, 117, 109, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 106, 117, 115, 116, 111, 46, 32, 78, 117, 108, 108, 97,
-109, 32, 118, 105, 116, 97, 101, 32, 112, 101, 100, 101, 46, 32, 68, 111, 110, 101, 99, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32,
-110, 105, 98, 104, 32, 101, 116, 32, 111, 100, 105, 111, 46, 32, 83, 101, 100, 32, 101, 116, 32, 109, 101, 116, 117, 115, 46, 32, 67, 108, 97, 115,
-115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111,
-114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32,
-112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 78, 97, 109, 32, 116, 101, 109, 112,
-117, 115, 46, 32, 83, 101, 100, 32, 97, 99, 32, 119, 105, 115, 105, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105, 116, 97, 115, 115,
-101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 83, 101, 100, 32, 115, 101, 100, 32, 119, 105, 115, 105, 46,
-32, 85, 116, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 116, 101, 108, 108, 117, 115, 32, 110, 111, 110, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 73, 110, 116, 101, 103, 101, 114, 32, 109, 101, 116, 117, 115, 46, 32, 73, 110, 32, 108, 97, 99, 105, 110, 105, 97, 32, 100, 117, 105, 46, 32,
-67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 111, 114, 110, 97, 114, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 117, 114, 110,
-97, 46, 32, 78, 97, 109, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 117, 114,
-110, 97, 46, 32, 78, 117, 110, 99, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 101, 114, 97,
-116, 46, 32, 83, 101, 100, 32, 98, 108, 97, 110, 100, 105, 116, 44, 32, 114, 105, 115, 117, 115, 32, 110, 111, 110, 32, 99, 111, 109, 109, 111, 100,
-111, 32, 110, 111, 110, 117, 109, 109, 121, 44, 32, 108, 105, 103, 117, 108, 97, 32, 101, 114, 97, 116, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109,
-32, 110, 105, 98, 104, 44, 32, 101, 117, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 97, 110, 116, 101, 32, 110, 101, 113, 117, 101, 32, 115,
-101, 100, 32, 115, 101, 109, 46, 32, 69, 116, 105, 97, 109, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 106, 117, 115, 116, 111, 32,
-101, 103, 101, 116, 32, 119, 105, 115, 105, 46, 32, 78, 117, 110, 99, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 46, 32, 80, 114, 111, 105, 110,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 113, 117, 97, 109, 32, 110, 111, 110, 32, 108, 101, 99, 116, 117, 115, 46, 32, 80, 114, 111, 105, 110,
-32, 117, 116, 32, 116, 117, 114, 112, 105, 115, 32, 113, 117, 105, 115, 32, 97, 117, 103, 117, 101, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113,
-117, 101, 32, 100, 105, 99, 116, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 101, 116, 32, 108, 111, 114, 101, 109, 46, 32, 65, 108, 105, 113, 117,
-97, 109, 32, 117, 114, 110, 97, 32, 108, 97, 99, 117, 115, 44, 32, 98, 108, 97, 110, 100, 105, 116, 32, 115, 101, 100, 44, 32, 118, 101, 115, 116,
-105, 98, 117, 108, 117, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 101, 116, 44, 32, 100, 111,
-108, 111, 114, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 117, 99, 116, 111, 114, 32, 101, 114, 97, 116, 32, 110, 101, 99, 32, 108,
-111, 114, 101, 109, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 117, 114, 110, 97, 32, 119, 105, 115, 105, 44, 32, 108, 97, 99, 105, 110,
-105, 97, 32, 117, 116, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 44, 32, 99, 111, 110, 100, 105,
-109, 101, 110, 116, 117, 109, 32, 105, 100, 44, 32, 111, 100, 105, 111, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 99, 111, 110, 118, 97,
-108, 108, 105, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 106, 117, 115, 116, 111, 46, 32, 68, 111, 110, 101, 99, 32, 118, 101,
-115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 115, 116, 32, 97, 99, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 109, 32, 118, 105, 116,
-97, 101, 32, 101, 108, 105, 116, 32, 101, 117, 32, 109, 97, 115, 115, 97, 32, 118, 97, 114, 105, 117, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116,
-101, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112,
-111, 116, 101, 110, 116, 105, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 110, 111, 110, 32, 108, 105, 98, 101, 114, 111, 46, 32, 78, 117, 108,
-108, 97, 109, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 109, 97, 115, 115, 97, 32, 105, 100, 32, 109, 97, 103, 110, 97, 32, 118, 105, 118,
-101, 114, 114, 97, 32, 99, 111, 109, 109, 111, 100, 111, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 105, 98, 101, 114, 111, 32,
-116, 111, 114, 116, 111, 114, 44, 32, 108, 117, 99, 116, 117, 115, 32, 97, 99, 44, 32, 118, 105, 118, 101, 114, 114, 97, 32, 99, 111, 110, 103, 117,
-101, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 118, 101, 108, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 65, 101, 110,
-101, 97, 110, 32, 97, 114, 99, 117, 32, 97, 117, 103, 117, 101, 44, 32, 108, 117, 99, 116, 117, 115, 32, 105, 100, 44, 32, 108, 97, 111, 114, 101,
-101, 116, 32, 112, 117, 108, 118, 105, 110, 97, 114, 44, 32, 100, 105, 99, 116, 117, 109, 32, 115, 101, 100, 44, 32, 108, 101, 99, 116, 117, 115, 46,
-32, 68, 111, 110, 101, 99, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 100, 111, 108, 111, 114,
-46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114,
-105, 115, 116, 105, 113, 117, 101, 32, 115, 101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108,
-101, 115, 117, 97, 100, 97, 32, 102, 97, 109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32,
-80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 103, 117, 101, 32, 116, 117, 114, 112, 105, 115, 44, 32, 108, 97, 111, 114, 101,
-101, 116, 32, 110, 101, 99, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 97, 116, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 118, 105,
-116, 97, 101, 44, 32, 110, 105, 98, 104, 46, 32, 69, 116, 105, 97, 109, 32, 111, 114, 99, 105, 32, 115, 97, 112, 105, 101, 110, 44, 32, 99, 111,
-110, 103, 117, 101, 32, 105, 110, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 114, 117, 116,
-114, 117, 109, 32, 118, 101, 108, 44, 32, 110, 105, 98, 104, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 101, 117, 32, 108, 111, 114, 101, 109, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 112, 114, 101, 116, 105, 117, 109, 32, 108, 101, 111, 32, 101, 116, 32, 101, 108, 105, 116, 46, 32, 73, 110, 32,
-110, 111, 110, 117, 109, 109, 121, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 115, 97, 112, 105, 101, 110, 46, 32, 77, 97, 117, 114, 105, 115,
-32, 118, 97, 114, 105, 117, 115, 46, 32, 77, 97, 117, 114, 105, 115, 32, 115, 101, 100, 32, 108, 105, 98, 101, 114, 111, 46, 32, 67, 117, 114, 97,
-98, 105, 116, 117, 114, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 101, 108, 105, 116, 32, 101, 117, 32, 112, 117, 114, 117, 115, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 118, 101, 108, 105, 116, 32, 112, 101, 100, 101, 44, 32, 115, 101, 109, 112, 101, 114, 32, 115,
-105, 116, 32, 97, 109, 101, 116, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 118, 105, 116, 97, 101, 44, 32, 116, 105, 110, 99, 105, 100, 117,
-110, 116, 32, 118, 101, 108, 44, 32, 100, 117, 105, 46, 32, 78, 117, 108, 108, 97, 32, 110, 101, 113, 117, 101, 32, 97, 110, 116, 101, 44, 32, 115,
-97, 103, 105, 116, 116, 105, 115, 32, 101, 117, 44, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 116, 44, 32, 108, 97, 99, 105, 110,
-105, 97, 32, 97, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 77, 111, 114, 98, 105, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 119, 105, 115,
-105, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 110, 111, 110, 32, 102, 101, 108, 105, 115, 32, 113, 117, 105, 115, 32, 97,
-114, 99, 117, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 111, 114, 110, 97, 114, 101, 46, 32, 65, 101, 110, 101, 97, 110, 32, 101, 110, 105, 109,
-32, 109, 101, 116, 117, 115, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 117, 44, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 110, 111,
-110, 117, 109, 109, 121, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 117, 116, 44, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 32, 101,
-108, 101, 105, 102, 101, 110, 100, 32, 110, 105, 115, 108, 32, 113, 117, 105, 115, 32, 100, 111, 108, 111, 114, 46, 32, 67, 108, 97, 115, 115, 32, 97,
-112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32,
-116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114,
-32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 112, 101,
-108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109, 97, 115, 115, 97, 32, 105, 110, 32, 101, 114, 97, 116, 32, 109, 111, 108, 101, 115, 116, 105,
-101, 32, 109, 111, 108, 101, 115, 116, 105, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 100, 97, 112,
-105, 98, 117, 115, 32, 108, 105, 98, 101, 114, 111, 46, 32, 83, 101, 100, 32, 115, 101, 100, 32, 114, 105, 115, 117, 115, 32, 105, 100, 32, 110, 101,
-113, 117, 101, 32, 100, 105, 99, 116, 117, 109, 32, 111, 114, 110, 97, 114, 101, 46, 32, 83, 101, 100, 32, 101, 117, 32, 108, 105, 103, 117, 108, 97,
-32, 97, 116, 32, 102, 101, 108, 105, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 99, 99, 117, 109, 115, 97, 110, 46, 32, 83, 101, 100, 32,
-105, 110, 116, 101, 114, 100, 117, 109, 44, 32, 117, 114, 110, 97, 32, 110, 111, 110, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 104, 101, 110, 100,
-114, 101, 114, 105, 116, 44, 32, 113, 117, 97, 109, 32, 109, 105, 32, 111, 114, 110, 97, 114, 101, 32, 108, 105, 98, 101, 114, 111, 44, 32, 105, 100,
-32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 116, 111, 114, 116, 111, 114, 32, 111, 114, 99, 105, 32, 110, 111, 110, 32, 118, 101, 108, 105, 116,
-46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 110, 101, 99, 32, 114, 105, 115, 117, 115, 46, 32, 68, 111, 110, 101, 99, 32, 97, 116, 32, 110, 117,
-110, 99, 32, 118, 105, 116, 97, 101, 32, 116, 101, 108, 108, 117, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 118, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 101, 108, 32, 106, 117, 115, 116, 111, 46, 32, 68, 117, 105,
-115, 32, 108, 105, 103, 117, 108, 97, 32, 108, 105, 98, 101, 114, 111, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 113, 117, 105, 115, 44,
-32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 118, 105,
-116, 97, 101, 44, 32, 118, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 101, 116, 32, 97, 114, 99, 117, 46, 32, 70, 117, 115,
-99, 101, 32, 101, 103, 101, 116, 32, 113, 117, 97, 109, 46, 32, 85, 116, 32, 97, 110, 116, 101, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115,
-115, 101, 32, 102, 101, 117, 103, 105, 97, 116, 32, 109, 101, 116, 117, 115, 32, 110, 111, 110, 32, 105, 112, 115, 117, 109, 46, 32, 78, 117, 108, 108,
-97, 32, 116, 101, 109, 112, 117, 115, 32, 108, 101, 111, 32, 117, 116, 32, 109, 105, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 118, 105,
-116, 97, 101, 32, 110, 105, 115, 108, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 46, 32, 69, 116, 105,
-97, 109, 32, 97, 32, 111, 114, 99, 105, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109,
-32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32,
-101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97,
-101, 59, 32, 86, 105, 118, 97, 109, 117, 115, 32, 117, 114, 110, 97, 32, 113, 117, 97, 109, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32,
-97, 116, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 118, 101, 108, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 101, 103, 101, 116, 44, 32,
-110, 117, 108, 108, 97, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 108, 97, 99, 117, 115, 32, 109, 97, 103, 110, 97, 44, 32, 110, 111, 110,
-117, 109, 109, 121, 32, 101, 117, 44, 32, 105, 97, 99, 117, 108, 105, 115, 32, 115, 101, 100, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117,
-101, 114, 32, 113, 117, 105, 115, 44, 32, 101, 110, 105, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 97, 32, 101, 114, 111, 115, 46, 32,
-65, 108, 105, 113, 117, 97, 109, 32, 110, 111, 110, 117, 109, 109, 121, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 101, 113, 117, 101, 46,
-32, 78, 117, 108, 108, 97, 32, 101, 110, 105, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 109, 111, 108, 101, 115, 116, 105, 101, 44, 32,
-111, 114, 99, 105, 32, 113, 117, 105, 115, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 118, 111, 108, 117, 116, 112, 97, 116, 44, 32, 108, 97,
-99, 117, 115, 32, 109, 101, 116, 117, 115, 32, 108, 117, 99, 116, 117, 115, 32, 115, 97, 112, 105, 101, 110, 44, 32, 101, 116, 32, 102, 97, 99, 105,
-108, 105, 115, 105, 115, 32, 101, 114, 111, 115, 32, 110, 101, 113, 117, 101, 32, 105, 100, 32, 115, 97, 112, 105, 101, 110, 46, 32, 78, 117, 110, 99,
-32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 100, 111, 108, 111, 114, 32, 118, 101, 108, 32, 111, 114, 99, 105, 46, 32, 73, 110, 116,
-101, 103, 101, 114, 32, 119, 105, 115, 105, 32, 100, 105, 97, 109, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 105, 116, 32, 97, 109,
-101, 116, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 105, 110, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 105, 110, 44, 32, 108, 101, 99, 116,
-117, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 81, 117, 105, 115, 113,
-117, 101, 32, 109, 111, 108, 108, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 118, 105, 116, 97, 101, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77,
-97, 117, 114, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 109, 105, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 117, 116, 44, 32, 117, 108, 116,
-114, 105, 99, 101, 115, 32, 115, 101, 100, 44, 32, 112, 111, 114, 116, 97, 32, 105, 110, 44, 32, 106, 117, 115, 116, 111, 46, 32, 83, 117, 115, 112,
-101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 117, 108, 116, 114, 105, 99, 105,
-101, 115, 32, 108, 97, 99, 117, 115, 32, 118, 105, 116, 97, 101, 32, 101, 110, 105, 109, 46, 32, 68, 111, 110, 101, 99, 32, 108, 97, 99, 117, 115,
-46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 68, 111, 110, 101, 99, 32, 109, 111, 108,
-101, 115, 116, 105, 101, 44, 32, 109, 97, 103, 110, 97, 32, 115, 101, 100, 32, 101, 117, 105, 115, 109, 111, 100, 32, 100, 105, 99, 116, 117, 109, 44,
-32, 109, 97, 103, 110, 97, 32, 109, 97, 103, 110, 97, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 100, 105, 97, 109, 44, 32, 118, 105, 116, 97,
-101, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 108, 101, 111, 32, 108, 111, 114, 101, 109, 32, 97, 99, 32, 110, 101, 113, 117, 101, 46, 32, 67,
-114, 97, 115, 32, 109, 101, 116, 117, 115, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 110, 117, 110, 99, 46, 32, 68, 117, 105, 115, 32, 99, 111,
-110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 103, 114, 97, 118, 105, 100, 97, 32, 115,
-111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 117, 114, 110, 97, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 118, 111, 108, 117, 116, 112,
-97, 116, 44, 32, 109, 97, 115, 115, 97, 32, 113, 117, 105, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 117, 108, 118, 105, 110, 97, 114,
-44, 32, 101, 114, 111, 115, 32, 112, 117, 114, 117, 115, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 117, 110, 99, 44, 32, 101, 103, 101,
-116, 32, 114, 104, 111, 110, 99, 117, 115, 32, 101, 110, 105, 109, 32, 108, 101, 99, 116, 117, 115, 32, 113, 117, 105, 115, 32, 116, 111, 114, 116, 111,
-114, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 108, 97, 99, 105, 110, 105, 97, 32, 113, 117, 97, 109, 32, 113, 117, 105, 115, 32, 101, 114, 97,
-116, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 109, 97, 116, 116, 105, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32,
-105, 97, 99, 117, 108, 105, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 118, 101, 108, 105, 116, 46, 32, 69, 116, 105, 97, 109, 32, 116, 101, 108,
-108, 117, 115, 32, 101, 110, 105, 109, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 110, 101, 99, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 97,
-44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 110, 111, 110, 44, 32, 118, 101, 108, 105, 116, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108,
-97, 99, 117, 115, 32, 118, 101, 108, 105, 116, 44, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44, 32,
-102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 105, 100, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117,
-101, 44, 32, 108, 101, 99, 116, 117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 113, 117, 105, 115, 32, 108, 111, 114, 101, 109, 46, 32, 78, 117, 108,
-108, 97, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 110, 101, 113, 117, 101, 32, 101, 116, 32, 100, 117, 105, 46, 32, 80, 104, 97, 115, 101,
-108, 108, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 111, 100, 105, 111, 46, 32, 80,
-104, 97, 115, 101, 108, 108, 117, 115, 32, 118, 105, 116, 97, 101, 32, 108, 105, 103, 117, 108, 97, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115,
-113, 117, 101, 32, 102, 101, 117, 103, 105, 97, 116, 32, 97, 114, 99, 117, 32, 97, 116, 32, 101, 114, 97, 116, 46, 32, 86, 105, 118, 97, 109, 117,
-115, 32, 117, 116, 32, 101, 114, 111, 115, 32, 117, 116, 32, 108, 111, 114, 101, 109, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 105, 97, 99, 117,
-108, 105, 115, 46, 32, 80, 114, 111, 105, 110, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 105, 112, 115, 117, 109, 32, 105, 100, 32, 110, 117, 110,
-99, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 118, 101, 108, 32, 109, 97, 115, 115, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105,
-115, 115, 101, 32, 110, 117, 108, 108, 97, 32, 105, 112, 115, 117, 109, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 118, 101, 108, 44, 32,
-112, 111, 115, 117, 101, 114, 101, 32, 101, 103, 101, 116, 44, 32, 109, 111, 108, 108, 105, 115, 32, 97, 116, 44, 32, 114, 105, 115, 117, 115, 46, 32,
-86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 105, 100, 32, 101, 115, 116, 32, 100, 97, 112, 105, 98,
-117, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 46, 32, 80, 114, 111, 105, 110, 32, 116, 101, 109, 112, 117, 115, 44, 32, 101, 114, 111, 115, 32,
-97, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 44, 32, 105, 112, 115, 117, 109, 32,
-97, 114, 99, 117, 32, 97, 108, 105, 113, 117, 97, 109, 32, 109, 105, 44, 32, 117, 116, 32, 102, 101, 117, 103, 105, 97, 116, 32, 108, 105, 98, 101,
-114, 111, 32, 111, 100, 105, 111, 32, 105, 110, 32, 110, 105, 115, 108, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 101, 116, 32, 109, 97, 115, 115,
-97, 32, 97, 32, 109, 97, 117, 114, 105, 115, 32, 108, 117, 99, 116, 117, 115, 32, 99, 111, 110, 103, 117, 101, 46, 32, 85, 116, 32, 105, 100, 32,
-101, 114, 111, 115, 46, 32, 70, 117, 115, 99, 101, 32, 97, 110, 116, 101, 32, 101, 114, 111, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32,
-110, 111, 110, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 44, 32, 98, 105, 98, 101, 110, 100, 117,
-109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 119, 105, 115, 105, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 114, 117, 116, 114,
-117, 109, 44, 32, 100, 111, 108, 111, 114, 32, 101, 116, 32, 115, 101, 109, 112, 101, 114, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 44, 32, 101,
-114, 111, 115, 32, 97, 110, 116, 101, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 109, 97, 115, 115, 97, 44, 32, 115, 101, 100, 32, 115, 111,
-108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 118, 101, 108, 105, 116, 32, 101, 116, 32, 109, 97, 115, 115, 97,
-46, 32, 73, 110, 32, 97, 117, 99, 116, 111, 114, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112,
-97, 116, 46, 32, 69, 116, 105, 97, 109, 32, 114, 105, 115, 117, 115, 32, 108, 101, 111, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 115,
-117, 115, 99, 105, 112, 105, 116, 44, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 101, 116, 44, 32, 115, 111, 100, 97, 108, 101,
-115, 32, 101, 103, 101, 116, 44, 32, 110, 105, 115, 108, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112,
-115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116,
-117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67,
-117, 114, 97, 101, 59, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 108, 105, 98, 101, 114, 111,
-32, 97, 99, 32, 108, 97, 111, 114, 101, 101, 116, 32, 109, 111, 108, 108, 105, 115, 44, 32, 108, 105, 103, 117, 108, 97, 32, 108, 101, 111, 32, 112,
-111, 114, 116, 97, 32, 119, 105, 115, 105, 44, 32, 117, 116, 32, 101, 117, 105, 115, 109, 111, 100, 32, 102, 101, 108, 105, 115, 32, 108, 105, 103, 117,
-108, 97, 32, 105, 100, 32, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 110, 117,
-108, 108, 97, 32, 101, 117, 32, 101, 110, 105, 109, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 102, 97, 117, 99,
-105, 98, 117, 115, 32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 32, 108, 97, 99, 105, 110, 105, 97, 32, 97, 110, 116, 101, 46, 32, 80,
-114, 97, 101, 115, 101, 110, 116, 32, 97, 116, 32, 110, 105, 98, 104, 46, 32, 77, 97, 117, 114, 105, 115, 32, 112, 111, 114, 116, 97, 32, 100, 105,
-103, 110, 105, 115, 115, 105, 109, 32, 119, 105, 115, 105, 46, 32, 85, 116, 32, 108, 97, 99, 105, 110, 105, 97, 32, 116, 111, 114, 116, 111, 114, 32,
-110, 101, 99, 32, 110, 117, 110, 99, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 101, 116, 32, 97, 117, 103, 117, 101, 46, 32, 73, 110,
-116, 101, 103, 101, 114, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 97, 32, 112, 101, 108, 108, 101, 110, 116, 101,
-115, 113, 117, 101, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 116, 111, 114, 116, 111, 114, 32, 115, 97, 112, 105, 101, 110, 32, 108, 111, 98, 111,
-114, 116, 105, 115, 32, 112, 101, 100, 101, 44, 32, 101, 103, 101, 116, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 115, 97, 112, 105,
-101, 110, 32, 114, 105, 115, 117, 115, 32, 118, 105, 116, 97, 101, 32, 101, 108, 105, 116, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101,
-32, 115, 101, 100, 32, 116, 117, 114, 112, 105, 115, 32, 117, 116, 32, 100, 111, 108, 111, 114, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 100, 105,
-103, 110, 105, 115, 115, 105, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 113, 117, 105, 115, 32, 108, 101, 111, 46, 32, 67, 114, 97, 115, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 97, 117, 99,
-116, 111, 114, 32, 116, 111, 114, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 97, 114, 99, 117, 46,
-0};
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 904ad4892ed..83a13abb33f 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -23,11 +23,14 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -37,11 +40,14 @@ set(INC_SYS
set(SRC
drawgpencil.c
editaction_gpencil.c
- gpencil_buttons.c
+ gpencil_convert.c
+ gpencil_data.c
gpencil_edit.c
gpencil_ops.c
gpencil_paint.c
+ gpencil_select.c
gpencil_undo.c
+ gpencil_utils.c
gpencil_intern.h
)
@@ -50,4 +56,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_gpencil "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/gpencil/SConscript b/source/blender/editors/gpencil/SConscript
index 8b891fcb8cf..3830a164b7b 100644
--- a/source/blender/editors/gpencil/SConscript
+++ b/source/blender/editors/gpencil/SConscript
@@ -31,12 +31,14 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/elbeem/extern',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../imbuf',
@@ -47,6 +49,7 @@ incs = [
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 5a838d7bc39..6b71c0ac053 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -27,6 +27,7 @@
* \ingroup edgpencil
*/
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -39,6 +40,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_api.h"
+#include "BLT_translation.h"
+
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -56,9 +60,11 @@
#include "BIF_glutil.h"
#include "ED_gpencil.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
-#include "gpencil_intern.h"
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
/* ************************************************** */
/* GREASE PENCIL DRAWING */
@@ -73,6 +79,9 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */
GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */
GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */
+ GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
+ GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */
+ GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */
} eDrawStrokeFlags;
@@ -111,22 +120,22 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
/* draw stroke curve */
if (G.debug & G_DEBUG) setlinestyle(2);
-
- glLineWidth(oldpressure * thickness);
+
+ glLineWidth(max_ff(oldpressure * thickness, 1.0));
glBegin(GL_LINE_STRIP);
-
+
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
* and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
*/
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
glEnd();
- glLineWidth(pt->pressure * thickness);
+ glLineWidth(max_ff(pt->pressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
if (i != 0) glVertex2iv(&(pt - 1)->x);
-
+
/* now the point we want... */
glVertex2iv(&pt->x);
@@ -136,20 +145,230 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
glVertex2iv(&pt->x);
}
glEnd();
-
+
/* reset for predictable OpenGL context */
glLineWidth(1.0f);
-
+
if (G.debug & G_DEBUG) setlinestyle(0);
}
}
+/* --------- 2D Stroke Drawing Helpers --------- */
+
+/* helper function to calculate x-y drawing coordinates for 2D points */
+static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+{
+ if (sflag & GP_STROKE_2DSPACE) {
+ r_co[0] = pt->x;
+ r_co[1] = pt->y;
+ }
+ else if (sflag & GP_STROKE_2DIMAGE) {
+ const float x = (float)((pt->x * winx) + offsx);
+ const float y = (float)((pt->y * winy) + offsy);
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+ else {
+ const float x = (float)(pt->x / 100 * winx) + offsx;
+ const float y = (float)(pt->y / 100 * winy) + offsy;
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+}
+
+/* ----------- Volumetric Strokes --------------- */
+
+/* draw a 2D buffer stroke in "volumetric" style
+ * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
+ */
+static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness,
+ short dflag, short UNUSED(sflag))
+{
+ GLUquadricObj *qobj = gluNewQuadric();
+ float modelview[4][4];
+
+ tGPspoint *pt;
+ int i;
+
+ /* error checking */
+ if ((points == NULL) || (totpoints <= 0))
+ return;
+
+ /* check if buffer can be drawn */
+ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
+ return;
+
+ /* get basic matrix - should be camera space (i.e "identity") */
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
+
+ /* draw points */
+ glPushMatrix();
+
+ for (i = 0, pt = points; i < totpoints; i++, pt++) {
+ /* set the transformed position */
+ // TODO: scale should change based on zoom level, which requires proper translation mult too!
+ modelview[3][0] = pt->x;
+ modelview[3][1] = pt->y;
+
+ glLoadMatrixf((float *)modelview);
+
+ /* draw the disk using the current state... */
+ gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
+
+
+ modelview[3][0] = modelview[3][1] = 0.0f;
+ }
+
+ glPopMatrix();
+ gluDeleteQuadric(qobj);
+}
+
+/* draw a 2D strokes in "volumetric" style */
+static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness,
+ short dflag, short sflag,
+ int offsx, int offsy, int winx, int winy)
+{
+ GLUquadricObj *qobj = gluNewQuadric();
+ float modelview[4][4];
+ float baseloc[3];
+ float scalefac = 1.0f;
+
+ bGPDspoint *pt;
+ int i;
+
+
+ /* HACK: We need a scale factor for the drawing in the image editor,
+ * which seems to use 1 unit as it's maximum size, whereas everything
+ * else assumes 1 unit = 1 pixel. Otherwise, we only get a massive blob.
+ */
+ if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
+ scalefac = 0.001f;
+ }
+
+ /* get basic matrix */
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
+ copy_v3_v3(baseloc, modelview[3]);
+
+ /* draw points */
+ glPushMatrix();
+
+ for (i = 0, pt = points; i < totpoints; i++, pt++) {
+ /* set the transformed position */
+ float co[2];
+
+ gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ translate_m4(modelview, co[0], co[1], 0.0f);
+
+ glLoadMatrixf((float *)modelview);
+
+ /* draw the disk using the current state... */
+ gluDisk(qobj, 0.0, pt->pressure * thickness * scalefac, 32, 1);
+
+ /* restore matrix */
+ copy_v3_v3(modelview[3], baseloc);
+ }
+
+ glPopMatrix();
+ gluDeleteQuadric(qobj);
+}
+
+/* draw a 3D stroke in "volumetric" style */
+static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness,
+ short UNUSED(dflag), short UNUSED(sflag))
+{
+ GLUquadricObj *qobj = gluNewQuadric();
+
+ float base_modelview[4][4], modelview[4][4];
+ float base_loc[3];
+
+ bGPDspoint *pt;
+ int i;
+
+
+ /* Get the basic modelview matrix we use for performing calculations */
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
+ copy_v3_v3(base_loc, base_modelview[3]);
+
+ /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with:
+ * - We need to knock out the rotation so that we are
+ * simply left with a camera-facing billboard
+ * - The scale factors here are chosen so that the thickness
+ * is relatively reasonable. Otherwise, it gets far too
+ * large!
+ */
+ scale_m4_fl(modelview, 0.1f);
+
+ /* draw each point as a disk... */
+ glPushMatrix();
+
+ for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ /* apply translation to base_modelview, so that the translated point is put in the right place */
+ translate_m4(base_modelview, pt->x, pt->y, pt->z);
+
+ /* copy the translation component to the billboard matrix we're going to use,
+ * then reset the base matrix to the original values so that we can do the same
+ * for the next point without accumulation/pollution effects
+ */
+ copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */
+ copy_v3_v3(base_modelview[3], base_loc); /* restore */
+
+ /* apply our billboard matrix for drawing... */
+ glLoadMatrixf((float *)modelview);
+
+ /* draw the disk using the current state... */
+ gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
+ }
+
+ glPopMatrix();
+ gluDeleteQuadric(qobj);
+}
+
+
+/* --------------- Stroke Fills ----------------- */
+
+/* draw fills for shapes */
+static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short UNUSED(thickness),
+ short UNUSED(dflag), short sflag,
+ int offsx, int offsy, int winx, int winy)
+{
+ bGPDspoint *pt;
+ int i;
+
+ BLI_assert(totpoints >= 3);
+
+ /* As an initial implementation, we use the OpenGL filled polygon drawing
+ * here since it's the easiest option to implement for this case. It does
+ * come with limitations (notably for concave shapes), though it shouldn't
+ * be much of an issue in most cases.
+ */
+ glBegin(GL_POLYGON);
+
+ for (i = 0, pt = points; i < totpoints; i++, pt++) {
+ if (sflag & GP_STROKE_3DSPACE) {
+ glVertex3fv(&pt->x);
+ }
+ else {
+ float co[2];
+
+ gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+ }
+ }
+
+ glEnd();
+}
+
/* ----- Existing Strokes Drawing (3D and Point) ------ */
/* draw a given stroke - just a single dot (only one point) */
static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dflag, short sflag,
int offsx, int offsy, int winx, int winy)
{
+ /* set point thickness (since there's only one of these) */
+ glPointSize((float)(thickness + 2) * points->pressure);
+
/* draw point */
if (sflag & GP_STROKE_3DSPACE) {
glBegin(GL_POINTS);
@@ -160,18 +379,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
float co[2];
/* get coordinates of point */
- if (sflag & GP_STROKE_2DSPACE) {
- co[0] = points->x;
- co[1] = points->y;
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- co[0] = (points->x * winx) + offsx;
- co[1] = (points->y * winy) + offsy;
- }
- else {
- co[0] = (points->x / 100 * winx) + offsx;
- co[1] = (points->y / 100 * winy) + offsy;
- }
+ gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co);
/* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
* - also mandatory in if Image Editor 'image-based' dot
@@ -185,13 +393,13 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
}
else {
/* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
- GLUquadricObj *qobj = gluNewQuadric();
+ GLUquadricObj *qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
+ gluQuadricDrawStyle(qobj, GLU_FILL);
/* need to translate drawing position, but must reset after too! */
- glTranslatef(co[0], co[1], 0.0);
- gluDisk(qobj, 0.0, thickness, 32, 1);
+ glTranslate2fv(co);
+ gluDisk(qobj, 0.0, thickness, 32, 1);
glTranslatef(-co[0], -co[1], 0.0);
gluDeleteQuadric(qobj);
@@ -200,14 +408,14 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
}
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, short debug)
+static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short UNUSED(sflag))
{
bGPDspoint *pt;
float curpressure = points[0].pressure;
int i;
/* draw stroke curve */
- glLineWidth(curpressure * thickness);
+ glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
@@ -217,7 +425,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
glEnd();
curpressure = pt->pressure;
- glLineWidth(curpressure * thickness);
+ glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
@@ -231,9 +439,12 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
}
}
glEnd();
-
+
/* draw debug points of curve on top? */
+ /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
if (debug) {
+ glPointSize((float)(thickness + 2));
+
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
glVertex3fv(&pt->x);
@@ -244,46 +455,22 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
/* ----- Fancy 2D-Stroke Drawing ------ */
/* draw a given stroke in 2d */
-static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
- short debug, int offsx, int offsy, int winx, int winy)
+static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
+ bool debug, int offsx, int offsy, int winx, int winy)
{
/* otherwise thickness is twice that of the 3D view */
float thickness = (float)thickness_s * 0.5f;
-
- /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better
- * - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke
- */
- if ((thickness < GP_DRAWTHICKNESS_SPECIAL) ||
- ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)))
- {
- bGPDspoint *pt;
- int i;
-
- glBegin(GL_LINE_STRIP);
- for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
- if (sflag & GP_STROKE_2DSPACE) {
- glVertex2f(pt->x, pt->y);
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (pt->x * winx) + offsx;
- const float y = (pt->y * winy) + offsy;
-
- glVertex2f(x, y);
- }
- else {
- const float x = (pt->x / 100 * winx) + offsx;
- const float y = (pt->y / 100 * winy) + offsy;
-
- glVertex2f(x, y);
- }
- }
- glEnd();
+
+ /* strokes in Image Editor need a scale factor, since units there are not pixels! */
+ float scalefac = 1.0f;
+ if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
+ scalefac = 0.001f;
}
/* tessellation code - draw stroke as series of connected quads with connection
* edges rotated to minimize shrinking artifacts, and rounded endcaps
*/
- else {
+ {
bGPDspoint *pt1, *pt2;
float pm[2];
int i;
@@ -299,22 +486,8 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
float pthick; /* thickness at segment point */
/* get x and y coordinates from points */
- if (sflag & GP_STROKE_2DSPACE) {
- s0[0] = pt1->x; s0[1] = pt1->y;
- s1[0] = pt2->x; s1[1] = pt2->y;
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- s0[0] = (pt1->x * winx) + offsx;
- s0[1] = (pt1->y * winy) + offsy;
- s1[0] = (pt2->x * winx) + offsx;
- s1[1] = (pt2->y * winy) + offsy;
- }
- else {
- s0[0] = (pt1->x / 100 * winx) + offsx;
- s0[1] = (pt1->y / 100 * winy) + offsy;
- s1[0] = (pt2->x / 100 * winx) + offsx;
- s1[1] = (pt2->y / 100 * winy) + offsy;
- }
+ gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
+ gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
/* calculate gradient and normal - 'angle'=(ny/nx) */
m1[1] = s1[1] - s0[1];
@@ -324,12 +497,12 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
m2[0] = m1[1];
/* always use pressure from first point here */
- pthick = (pt1->pressure * thickness);
+ pthick = (pt1->pressure * thickness * scalefac);
/* if the first segment, start of segment is segment's normal */
if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
+ /* draw start cap first
+ * - make points slightly closer to center (about halfway across)
*/
mt[0] = m2[0] * pthick * 0.5f;
mt[1] = m2[1] * pthick * 0.5f;
@@ -369,7 +542,7 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
mb[1] = (pm[1] + m2[1]) / 2;
normalize_v2(mb);
- /* calculate gradient to apply
+ /* calculate gradient to apply
* - as basis, use just pthick * bisector gradient
* - if cross-section not as thick as it should be, add extra padding to fix it
*/
@@ -399,7 +572,7 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
/* if last segment, also draw end of segment (defined as segment's normal) */
if (i == totpoints - 2) {
/* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness);
+ pthick = (pt2->pressure * thickness * scalefac);
/* calculate points for end of segment */
mt[0] = m2[0] * pthick;
@@ -417,8 +590,8 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
glVertex2fv(t1);
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
+ /* draw end cap as last step
+ * - make points slightly closer to center (about halfway across)
*/
mt[0] = m2[0] * pthick * 0.5f;
mt[1] = m2[1] * pthick * 0.5f;
@@ -446,54 +619,61 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
bGPDspoint *pt;
int i;
+ glPointSize((float)(thickness_s + 2));
+
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
- if (sflag & GP_STROKE_2DSPACE) {
- glVertex2fv(&pt->x);
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt->x * winx) + offsx);
- const float y = (float)((pt->y * winy) + offsy);
-
- glVertex2f(x, y);
- }
- else {
- const float x = (float)(pt->x / 100 * winx) + offsx;
- const float y = (float)(pt->y / 100 * winy) + offsy;
-
- glVertex2f(x, y);
- }
+ float co[2];
+
+ gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
}
glEnd();
}
}
-/* ----- General Drawing ------ */
+/* ----- Strokes Drawing ------ */
+
+/* Helper for doing all the checks on whether a stroke can be drawn */
+static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
+{
+ /* skip stroke if it isn't in the right display space for this drawing context */
+ /* 1) 3D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
+ return false;
+
+ /* 2) Screen Space 2D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
+ return false;
+
+ /* 3) Image Space (2D) */
+ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+
+
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1))
+ return false;
+
+ /* stroke can be drawn */
+ return true;
+}
/* draw a set of strokes */
static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
- short debug, short lthick, const float color[4])
+ bool debug, short lthick, const float color[4], const float fill_color[4])
{
bGPDstroke *gps;
- /* set color first (may need to reset it again later too) */
- glColor4fv(color);
-
for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* check if stroke can be drawn - checks here generally fall into pairs */
- if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
- continue;
- if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
- continue;
- if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
- continue;
- if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
- continue;
- if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
- continue;
- if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
- continue;
- if ((gps->points == NULL) || (gps->totpoints < 1))
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false)
continue;
/* check which stroke-drawer to use */
@@ -515,11 +695,27 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
#endif
}
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ /* 3D Fill */
+ if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
+ glColor4fv(fill_color);
+ gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ }
+
+ /* 3D Stroke */
+ glColor4fv(color);
+
+ if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+ /* volumetric stroke drawing */
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
}
else {
- gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug);
+ /* 3D Lines - OpenGL primitives-based */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ }
+ else {
+ gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
+ }
}
if (no_xray) {
@@ -534,116 +730,301 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
}
}
else {
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ /* 2D - Fill */
+ if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
+ glColor4fv(fill_color);
+ gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ }
+
+ /* 2D Strokes... */
+ glColor4fv(color);
+
+ if (dflag & GP_DRAWDATA_VOLUMETRIC) {
+ /* blob/disk-based "volumetric" drawing */
+ gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
}
else {
- gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
+ /* normal 2D strokes */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
+ }
+ else {
+ gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
+ }
}
}
}
}
-/* draw grease-pencil datablock */
-static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+/* Draw selected verts for strokes being edited */
+static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
{
- bGPDlayer *gpl;
+ bGPDstroke *gps;
- /* reset line drawing style (in case previous user didn't reset) */
- setlinestyle(0);
+ const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
+ int mask_orig = 0;
- /* turn on smooth lines (i.e. anti-aliasing) */
- glEnable(GL_LINE_SMOOTH);
+ /* set up depth masks... */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+#if 0
+ glEnable(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(-1.0f, -1.0f);
+#endif
+ }
+ }
- /* turn on alpha-blending */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+
+ /* draw stroke verts */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ float vsize, bsize;
+ int i;
+
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false)
+ continue;
+
+ /* Optimisation: only draw points for selected strokes
+ * We assume that selected points can only occur in
+ * strokes that are selected too.
+ */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ /* Get size of verts:
+ * - The selected state needs to be larger than the unselected state so that
+ * they stand out more.
+ * - We use the theme setting for size of the unselected verts
+ */
+ bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
+ if ((int)bsize > 8) {
+ vsize = 10.0f;
+ bsize = 8.0f;
+ }
+ else {
+ vsize = bsize + 2;
+ }
+
+ /* First Pass: Draw all the verts (i.e. these become the unselected state) */
+ if (tcolor != NULL) {
+ /* for now, we assume that the base color of the points is not too close to the real color */
+ glColor3fv(tcolor);
+ }
+ else {
+ /* this doesn't work well with the default theme and black strokes... */
+ UI_ThemeColor(TH_GP_VERTEX);
+ }
+ glPointSize(bsize);
+
+ glBegin(GL_POINTS);
+ for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ glVertex3fv(&pt->x);
+ }
+ else {
+ float co[2];
+
+ gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+ }
+ }
+ glEnd();
- /* loop over layers, drawing them */
+
+ /* Second Pass: Draw only verts which are selected */
+ UI_ThemeColor(TH_GP_VERTEX_SELECT);
+ glPointSize(vsize);
+
+ glBegin(GL_POINTS);
+ for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ glVertex3fv(&pt->x);
+ }
+ else {
+ float co[2];
+
+ gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
+ glVertex2fv(co);
+ }
+ }
+ }
+ glEnd();
+ }
+
+
+ /* clear depth mask */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ glDisable(GL_DEPTH_TEST);
+
+ bglPolygonOffset(0.0, 0.0);
+#if 0
+ glDisable(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(0, 0);
+#endif
+ }
+ }
+}
+
+/* ----- General Drawing ------ */
+
+/* draw onion-skinning for a layer */
+static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int UNUSED(cfra), int dflag, bool debug, short lthick)
+{
+ const float alpha = gpl->color[3];
+ float color[4];
+
+ /* 1) Draw Previous Frames First */
+ if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
+ copy_v3_v3(color, gpl->gcolor_prev);
+ }
+ else {
+ copy_v3_v3(color, gpl->color);
+ }
+
+ if (gpl->gstep) {
+ bGPDframe *gf;
+ float fac;
+
+ /* draw previous frames first */
+ for (gf = gpf->prev; gf; gf = gf->prev) {
+ /* check if frame is drawable */
+ if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
+ /* alpha decreases with distance from curframe index */
+ fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
+ color[3] = alpha * fac * 0.66f;
+ gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ }
+ else
+ break;
+ }
+ }
+ else {
+ /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+ if (gpf->prev) {
+ color[3] = (alpha / 7);
+ gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ }
+ }
+
+
+ /* 2) Now draw next frames */
+ if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
+ copy_v3_v3(color, gpl->gcolor_next);
+ }
+ else {
+ copy_v3_v3(color, gpl->color);
+ }
+
+ if (gpl->gstep_next) {
+ bGPDframe *gf;
+ float fac;
+
+ /* now draw next frames */
+ for (gf = gpf->next; gf; gf = gf->next) {
+ /* check if frame is drawable */
+ if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
+ /* alpha decreases with distance from curframe index */
+ fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
+ color[3] = alpha * fac * 0.66f;
+ gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ }
+ else
+ break;
+ }
+ }
+ else {
+ /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+ if (gpf->next) {
+ color[3] = (alpha / 4);
+ gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
+ }
+ }
+
+ /* 3) restore alpha */
+ glColor4fv(gpl->color);
+}
+
+/* loop over gpencil data layers, drawing them */
+static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+{
+ bGPDlayer *gpl;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
bGPDframe *gpf;
- short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
+ bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
short lthick = gpl->thickness;
- float color[4], tcolor[4];
/* don't draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE)
+ if (gpl->flag & GP_LAYER_HIDE)
continue;
/* get frame to draw */
gpf = gpencil_layer_getframe(gpl, cfra, 0);
- if (gpf == NULL)
+ if (gpf == NULL)
continue;
- /* set color, stroke thickness, and point size */
+ /* set basic stroke thickness */
glLineWidth(lthick);
- copy_v4_v4(color, gpl->color); // just for copying 4 array elements
- copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting)
- glColor4fv(color);
- glPointSize((float)(gpl->thickness + 2));
- /* apply xray layer setting */
- if (gpl->flag & GP_LAYER_NO_XRAY) dflag |= GP_DRAWDATA_NO_XRAY;
- else dflag &= ~GP_DRAWDATA_NO_XRAY;
+ /* Add layer drawing settings to the set of "draw flags"
+ * NOTE: If the setting doesn't apply, it *must* be cleared,
+ * as dflag's carry over from the previous layer
+ */
+#define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \
+ if (condition) dflag |= (draw_flag_value); \
+ else dflag &= ~(draw_flag_value); \
+ } (void)0
+
+ /* xray... */
+ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
+
+ /* volumetric strokes... */
+ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
+
+ /* fill strokes... */
+ // XXX: this is not a very good limit
+ GP_DRAWFLAG_APPLY((gpl->fill[3] > 0.001f), GP_DRAWDATA_FILL);
+#undef GP_DRAWFLAG_APPLY
/* draw 'onionskins' (frame left + right) */
- if (gpl->flag & GP_LAYER_ONIONSKIN) {
- /* drawing method - only immediately surrounding (gstep = 0),
- * or within a frame range on either side (gstep > 0)*/
- if (gpl->gstep) {
- bGPDframe *gf;
- float fac;
-
- /* draw previous frames first */
- for (gf = gpf->prev; gf; gf = gf->prev) {
- /* check if frame is drawable */
- if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
- /* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
- tcolor[3] = color[3] * fac * 0.66f;
- gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
- }
- else
- break;
- }
-
- /* now draw next frames */
- for (gf = gpf->next; gf; gf = gf->next) {
- /* check if frame is drawable */
- if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
- /* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1));
- tcolor[3] = color[3] * fac * 0.66f;
- gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
- }
- else
- break;
- }
-
- /* restore alpha */
- glColor4fv(color);
- }
- else {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->prev) {
- tcolor[3] = (color[3] / 7);
- gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
- }
-
- if (gpf->next) {
- tcolor[3] = (color[3] / 4);
- gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
- }
-
- /* restore alpha */
- glColor4fv(color);
- }
+ if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
+ /* Drawing method - only immediately surrounding (gstep = 0),
+ * or within a frame range on either side (gstep > 0)
+ */
+ gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
}
/* draw the strokes already in active frame */
- tcolor[3] = color[3];
- gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
+ gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
+
+ /* Draw verts of selected strokes
+ * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
+ * - locked layers can't be edited, so there's no point showing these verts
+ * as they will have no bearings on what gets edited
+ * - only show when in editmode, since operators shouldn't work otherwise
+ * (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
+ */
+ /* XXX: perhaps we don't want to show these when users are drawing... */
+ if ((G.f & G_RENDER_OGL) == 0 &&
+ (gpl->flag & GP_LAYER_LOCKED) == 0 &&
+ (gpd->flag & GP_DATA_STROKE_EDITMODE))
+ {
+ gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag,
+ (gpl->color[3] < 0.95f) ? gpl->color : NULL);
+ }
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
@@ -651,22 +1032,135 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
(gpf->flag & GP_FRAME_PAINT))
{
+ /* Set color for drawing buffer stroke - since this may not be set yet */
+ glColor4fv(gpl->color);
+
/* Buffer stroke needs to be drawn with a different linestyle
- * to help differentiate them from normal strokes. */
- gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ * to help differentiate them from normal strokes.
+ *
+ * It should also be noted that sbuffer contains temporary point types
+ * i.e. tGPspoints NOT bGPDspoints
+ */
+ if (gpl->flag & GP_LAYER_VOLUMETRIC) {
+ gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ }
+ else {
+ gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
+ }
}
}
+}
+
+/* draw a short status message in the top-right corner */
+static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
+{
+ rcti rect;
+
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_RENDER_OGL)
+ return;
+
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
+
+ /* for now, this should only be used to indicate when we are in stroke editmode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ const char *printable = IFACE_("GPencil Stroke Editing");
+ float printable_size[2];
+ int xco, yco;
+
+ BLF_width_and_height_default(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);
+
+ /* text label */
+ UI_ThemeColor(TH_TEXT_HI);
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#else
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#endif
+
+ /* grease pencil icon... */
+ // XXX: is this too intrusive?
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
+
+ UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
+
+ glDisable(GL_BLEND);
+ }
+}
+
+/* draw grease-pencil datablock */
+static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
+{
+ /* reset line drawing style (in case previous user didn't reset) */
+ setlinestyle(0);
+
+ /* turn on smooth lines (i.e. anti-aliasing) */
+ glEnable(GL_LINE_SMOOTH);
+
+ /* XXX: turn on some way of ensuring that the polygon edges get smoothed
+ * GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up
+ * creating internal white rays due to the ways it accumulates stuff
+ */
+
+ /* turn on alpha-blending */
+ if (GLEW_VERSION_1_4) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ glEnable(GL_BLEND);
+
+ /* draw! */
+ gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
glDisable(GL_BLEND); // alpha blending
glDisable(GL_LINE_SMOOTH); // smooth lines
-
+
/* restore initial gl conditions */
glLineWidth(1.0);
glPointSize(1.0);
glColor4f(0, 0, 0, 1);
}
+/* if we have strokes for scenes (3d view)/clips (movie clip editor)
+ * and objects/tracks, multiple data blocks have to be drawn */
+static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, const char spacetype)
+{
+ bGPdata *gpd_source = NULL;
+
+ if (scene) {
+ if (spacetype == SPACE_VIEW3D) {
+ gpd_source = (scene->gpd ? scene->gpd : NULL);
+ }
+ else if (spacetype == SPACE_CLIP && scene->clip) {
+ /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
+ gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
+ }
+
+ if (gpd_source) {
+ gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
+ }
+ }
+
+ /* scene/clip data has already been drawn, only object/track data is drawn here
+ * if gpd_source == gpd, we don't have any object/track data and we can skip */
+ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
+ gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag);
+ }
+}
+
/* ----- Grease Pencil Sketches Drawing API ------ */
/* ............................
@@ -693,7 +1187,7 @@ void ED_gpencil_draw_2dimage(const bContext *C)
case SPACE_IMAGE: /* image */
case SPACE_CLIP: /* clip */
{
-
+
/* just draw using standard scaling (settings here are currently ignored anyways) */
/* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
offsx = 0;
@@ -714,8 +1208,8 @@ void ED_gpencil_draw_2dimage(const bContext *C)
sizex = ar->winx;
sizey = ar->winy;
- /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
- * and everything moved to standard View2d
+ /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
+ * and everything moved to standard View2d
*/
dflag |= GP_DRAWDATA_ONLYV2D;
break;
@@ -732,10 +1226,10 @@ void ED_gpencil_draw_2dimage(const bContext *C)
/* draw it! */
- gp_draw_data(gpd, offsx, offsy, sizex, sizey, CFRA, dflag);
+ gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
}
-/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
+/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
* Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
* second time with onlyv2d=0 for screen-aligned strokes */
void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
@@ -758,10 +1252,15 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
/* draw it! */
if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
- gp_draw_data(gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag);
+ gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (onlyv2d == false) {
+ gp_draw_status_text(gpd, ar);
+ }
}
-/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
+/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
* Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
* second time with only3d=0 for screen-aligned strokes */
void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
@@ -770,17 +1269,17 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
int dflag = 0;
RegionView3D *rv3d = ar->regiondata;
int offsx, offsy, winx, winy;
-
+
/* check that we have grease-pencil stuff to draw */
gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
if (gpd == NULL) return;
-
+
/* when rendering to the offscreen buffer we don't want to
* deal with the camera border, otherwise map the coords to the camera border. */
if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
rctf rectf;
ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
-
+
offsx = iroundf(rectf.xmin);
offsy = iroundf(rectf.ymin);
winx = iroundf(rectf.xmax - rectf.xmin);
@@ -793,17 +1292,34 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
winy = ar->winy;
}
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+
/* draw it! */
- if (only3d) dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
-
- gp_draw_data(gpd, offsx, offsy, winx, winy, CFRA, dflag);
+ gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (only3d == false) {
+ gp_draw_status_text(gpd, ar);
+ }
}
-void ED_gpencil_draw_ex(bGPdata *gpd, int winx, int winy, const int cfra)
+void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
{
int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
-
- gp_draw_data(gpd, 0, 0, winx, winy, cfra, dflag);
+
+ gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
}
/* ************************************************** */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index dba80164e93..a2ba6216f9c 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -27,7 +27,7 @@
* \ingroup edgpencil
*/
-
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -49,8 +49,6 @@
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
-#include "gpencil_intern.h"
-
/* ***************************************** */
/* NOTE ABOUT THIS FILE:
* This file contains code for editing Grease Pencil data in the Action Editor
@@ -75,7 +73,7 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPD
if (gpf_cb(gpf, scene))
return true;
}
-
+
/* nothing to return */
return false;
}
@@ -115,7 +113,7 @@ bool ED_gplayer_frame_select_check(bGPDlayer *gpl)
bGPDframe *gpf;
/* error checking */
- if (gpl == NULL)
+ if (gpl == NULL)
return false;
/* stop at the first one found */
@@ -153,9 +151,9 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
bGPDframe *gpf;
/* error checking */
- if (gpl == NULL)
+ if (gpl == NULL)
return;
-
+
/* handle according to mode */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
gpframe_select(gpf, select_mode);
@@ -166,7 +164,7 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
void ED_gplayer_frame_select_set(bGPDlayer *gpl, short mode)
{
/* error checking */
- if (gpl == NULL)
+ if (gpl == NULL)
return;
/* now call the standard function */
@@ -178,11 +176,11 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
{
bGPDframe *gpf;
- if (gpl == NULL)
+ if (gpl == NULL)
return;
-
+
gpf = BKE_gpencil_layer_find_frame(gpl, selx);
-
+
if (gpf) {
gpframe_select(gpf, select_mode);
}
@@ -215,7 +213,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
/* error checking */
if (gpl == NULL)
return false;
-
+
/* check for frames to delete */
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
gpfn = gpf->next;
@@ -223,7 +221,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
if (gpf->flag & GP_FRAME_SELECT)
changed |= gpencil_layer_delframe(gpl, gpf);
}
-
+
return changed;
}
@@ -242,7 +240,7 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
/* duplicate this frame */
if (gpf->flag & GP_FRAME_SELECT) {
- bGPDframe *gpfd;
+ bGPDframe *gpfd;
/* duplicate frame, and deselect self */
gpfd = gpencil_frame_duplicate(gpf);
@@ -253,6 +251,23 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
}
}
+/* Set keyframe type for selected frames from given gp-layer
+ * \param type The type of keyframe (eBezTriple_KeyframeType) to set selected frames to
+ */
+void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
+{
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ gpf->key_type = type;
+ }
+ }
+}
+
#if 0 // XXX disabled until grease pencil code stabilises again
/* -------------------------------------- */
/* Copy and Paste Tools */
@@ -263,7 +278,7 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
* the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
* - The earliest frame is calculated per copy operation.
*/
-
+
/* globals for copy/paste data (like for other copy/paste buffers) */
ListBase gpcopybuf = {NULL, NULL};
static int gpcopy_firstframe = 999999999;
@@ -271,7 +286,7 @@ static int gpcopy_firstframe = 999999999;
/* This function frees any MEM_calloc'ed copy/paste buffer data */
void free_gpcopybuf()
{
- free_gpencil_layers(&gpcopybuf);
+ free_gpencil_layers(&gpcopybuf);
BLI_listbase_clear(&gpcopybuf);
gpcopy_firstframe = 999999999;
@@ -375,7 +390,7 @@ void paste_gpdata(Scene *scene)
/* find suitable layer from buffer to use to paste from */
for (gpls = gpcopybuf.first; gpls; gpls = gpls->next) {
/* check if layer name matches */
- if ((no_name) || (strcmp(gpls->info, gpld->info) == 0))
+ if ((no_name) || STREQ(gpls->info, gpld->info))
break;
}
@@ -398,8 +413,8 @@ void paste_gpdata(Scene *scene)
//sa = gpencil_data_findowner((bGPdata *)ale->owner);
sa = NULL;
- /* this should be the right frame... as it may be a pre-existing frame,
- * must make sure that only compatible stroke types get copied over
+ /* this should be the right frame... as it may be a pre-existing frame,
+ * must make sure that only compatible stroke types get copied over
* - we cannot just add a duplicate frame, as that would cause errors
* - need to check for compatible types to minimize memory usage (copying 'junk' over)
*/
@@ -418,14 +433,14 @@ void paste_gpdata(Scene *scene)
if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE))
stroke_ok = 1;
break;
-
+
case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */
case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */
case SPACE_CLIP: /* Image Editor: either screen-aligned or view\image-aligned */
if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE))
stroke_ok = 1;
break;
-
+
case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */
if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE))
stroke_ok = 1;
@@ -567,9 +582,9 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene)
/* In order for this mirror function to work without
* any extra arguments being added, we use the case
- * of bezt==NULL to denote that we should find the
+ * of bezt==NULL to denote that we should find the
* marker to mirror over. The static pointer is safe
- * to use this way, as it will be set to null after
+ * to use this way, as it will be set to null after
* each cycle in which this is called.
*/
diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c
deleted file mode 100644
index 0acff8fc0a5..00000000000
--- a/source/blender/editors/gpencil/gpencil_buttons.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * ***** 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) 2008, Blender Foundation, Joshua Leung
- * This is a new part of Blender
- *
- * Contributor(s): Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/gpencil/gpencil_buttons.c
- * \ingroup edgpencil
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stddef.h>
-
-#include "BLI_blenlib.h"
-
-#include "BLF_translation.h"
-
-#include "DNA_gpencil_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_gpencil.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-
-#include "ED_gpencil.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "gpencil_intern.h"
-
-/* ************************************************** */
-/* GREASE PENCIL PANEL-UI DRAWING */
-
-/* Every space which implements Grease-Pencil functionality should have a panel
- * for the settings. All of the space-dependent parts should be coded in the panel
- * code for that space, but the rest is all handled by generic panel here.
- */
-
-/* ------- Callbacks ----------- */
-/* These are just 'dummy wrappers' around gpencil api calls */
-
-/* make layer active one after being clicked on */
-static void gp_ui_activelayer_cb(bContext *C, void *gpd, void *gpl)
-{
- /* make sure the layer we want to remove is the active one */
- gpencil_layer_setactive(gpd, gpl);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-/* delete 'active' layer */
-static void gp_ui_dellayer_cb(bContext *C, void *gpd, void *gpl)
-{
- gpencil_layer_delete((bGPdata *)gpd, (bGPDlayer *)gpl);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-/* move layer up */
-static void gp_ui_layer_up_cb(bContext *C, void *gpd_v, void *gpl_v)
-{
- bGPdata *gpd = gpd_v;
- bGPDlayer *gpl = gpl_v;
-
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-/* move layer down */
-static void gp_ui_layer_down_cb(bContext *C, void *gpd_v, void *gpl_v)
-{
- bGPdata *gpd = gpd_v;
- bGPDlayer *gpl = gpl_v;
-
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
-
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-/* ------- Drawing Code ------- */
-
-/* draw the controls for a given layer */
-static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, const bool is_v3d)
-{
- uiLayout *box = NULL, *split = NULL;
- uiLayout *col = NULL;
- uiLayout *row = NULL, *sub = NULL;
- uiBlock *block;
- uiBut *but;
- PointerRNA ptr;
- int icon;
-
- /* make pointer to layer data */
- RNA_pointer_create((ID *)gpd, &RNA_GPencilLayer, gpl, &ptr);
-
- /* unless button has own callback, it adds this callback to button */
- block = uiLayoutGetBlock(layout);
- uiBlockSetFunc(block, gp_ui_activelayer_cb, gpd, gpl);
-
- /* draw header ---------------------------------- */
- /* get layout-row + UI-block for header */
- box = uiLayoutBox(layout);
-
- row = uiLayoutRow(box, false);
- uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
- block = uiLayoutGetBlock(row); /* err... */
-
- uiBlockSetEmboss(block, UI_EMBOSSN);
-
- /* left-align ............................... */
- sub = uiLayoutRow(row, false);
-
- /* active */
- block = uiLayoutGetBlock(sub);
- icon = (gpl->flag & GP_LAYER_ACTIVE) ? ICON_RADIOBUT_ON : ICON_RADIOBUT_OFF;
- but = uiDefIconButBitI(block, TOG, GP_LAYER_ACTIVE, 0, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- &gpl->flag, 0.0, 0.0, 0.0, 0.0, TIP_("Set active layer"));
- uiButSetFunc(but, gp_ui_activelayer_cb, gpd, gpl);
-
- /* locked */
- icon = (gpl->flag & GP_LAYER_LOCKED) ? ICON_LOCKED : ICON_UNLOCKED;
- uiItemR(sub, &ptr, "lock", 0, "", icon);
-
- /* when layer is locked or hidden, only draw header */
- if (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE)) {
- char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */
-
- /* visibility button (only if hidden but not locked!) */
- if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
- uiItemR(sub, &ptr, "hide", 0, "", ICON_RESTRICT_VIEW_ON);
-
- /* name */
- if (gpl->flag & GP_LAYER_HIDE)
- BLI_snprintf(name, sizeof(name), IFACE_("%s (Hidden)"), gpl->info);
- else
- BLI_snprintf(name, sizeof(name), IFACE_("%s (Locked)"), gpl->info);
- uiItemL(sub, name, ICON_NONE);
-
- /* delete button (only if hidden but not locked!) */
- if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED)) {
- /* right-align ............................... */
- sub = uiLayoutRow(row, true);
- uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- block = uiLayoutGetBlock(sub); /* XXX... err... */
-
- but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete layer"));
- uiButSetFunc(but, gp_ui_dellayer_cb, gpd, gpl);
- }
- uiBlockSetEmboss(block, UI_EMBOSS);
- }
- else {
- /* draw rest of header -------------------------------- */
- /* visibility button */
- uiItemR(sub, &ptr, "hide", 0, "", ICON_RESTRICT_VIEW_OFF);
-
- /* frame locking */
- /* TODO: this needs its own icons... */
- icon = (gpl->flag & GP_LAYER_FRAMELOCK) ? ICON_RENDER_STILL : ICON_RENDER_ANIMATION;
- uiItemR(sub, &ptr, "lock_frame", 0, "", icon);
-
- uiBlockSetEmboss(block, UI_EMBOSS);
-
- /* name */
- uiItemR(sub, &ptr, "info", 0, "", ICON_NONE);
-
- /* move up/down */
- uiBlockBeginAlign(block);
-
- if (gpl->prev) {
- but = uiDefIconBut(block, BUT, 0, ICON_TRIA_UP, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer up"));
- uiButSetFunc(but, gp_ui_layer_up_cb, gpd, gpl);
- }
- if (gpl->next) {
- but = uiDefIconBut(block, BUT, 0, ICON_TRIA_DOWN, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer down"));
- uiButSetFunc(but, gp_ui_layer_down_cb, gpd, gpl);
- }
-
- uiBlockEndAlign(block);
-
- /* delete 'button' */
- uiBlockSetEmboss(block, UI_EMBOSSN);
- /* right-align ............................... */
- sub = uiLayoutRow(row, true);
- uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- block = uiLayoutGetBlock(sub); /* XXX... err... */
-
- but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete layer"));
- uiButSetFunc(but, gp_ui_dellayer_cb, gpd, gpl);
- uiBlockSetEmboss(block, UI_EMBOSS);
-
- /* new backdrop ----------------------------------- */
- box = uiLayoutBox(layout);
- split = uiLayoutSplit(box, 0.5f, false);
-
- /* draw settings ---------------------------------- */
- /* left column ..................... */
- col = uiLayoutColumn(split, false);
-
- /* color */
- sub = uiLayoutColumn(col, true);
- uiItemR(sub, &ptr, "color", 0, "", ICON_NONE);
- uiItemR(sub, &ptr, "alpha", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-
- /* stroke thickness */
- uiItemR(col, &ptr, "line_width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-
- /* debugging options */
- if (G.debug & G_DEBUG) {
- uiItemR(col, &ptr, "show_points", 0, NULL, ICON_NONE);
- }
-
- /* right column ................... */
- col = uiLayoutColumn(split, false);
-
- /* onion-skinning */
- sub = uiLayoutColumn(col, true);
- uiItemR(sub, &ptr, "use_onion_skinning", 0, NULL, ICON_NONE);
- uiItemR(sub, &ptr, "ghost_range_max", 0, IFACE_("Frames"), ICON_NONE);
-
- /* 3d-view specific drawing options */
- if (is_v3d) {
- uiItemR(col, &ptr, "show_x_ray", 0, NULL, ICON_NONE);
- }
- }
-}
-
-/* stroke drawing options available */
-typedef enum eGP_Stroke_Ops {
- STROKE_OPTS_NORMAL = 0,
- STROKE_OPTS_V3D_OFF,
- STROKE_OPTS_V3D_ON,
-} eGP_Stroke_Ops;
-
-static void draw_gpencil_space_specials(const bContext *C, uiLayout *layout)
-{
- uiLayout *col, *row;
- SpaceClip *sc = CTX_wm_space_clip(C);
-
- col = uiLayoutColumn(layout, false);
-
- if (sc) {
- bScreen *screen = CTX_wm_screen(C);
- PointerRNA sc_ptr;
-
- RNA_pointer_create(&screen->id, &RNA_SpaceClipEditor, sc, &sc_ptr);
- row = uiLayoutRow(col, true);
- uiItemR(row, &sc_ptr, "grease_pencil_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- }
-}
-
-/* Draw the contents for a grease-pencil panel*/
-static void draw_gpencil_panel(bContext *C, uiLayout *layout, bGPdata *gpd, PointerRNA *ctx_ptr)
-{
- PointerRNA gpd_ptr;
- bGPDlayer *gpl;
- uiLayout *col, *row;
- SpaceClip *sc = CTX_wm_space_clip(C);
- short v3d_stroke_opts = STROKE_OPTS_NORMAL;
- const bool is_v3d = CTX_wm_view3d(C) != NULL;
-
- /* make new PointerRNA for Grease Pencil block */
- RNA_id_pointer_create((ID *)gpd, &gpd_ptr);
-
- /* draw gpd settings first ------------------------------------- */
- col = uiLayoutColumn(layout, false);
-
- /* current Grease Pencil block */
- /* TODO: show some info about who owns this? */
- uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_add", NULL, "GPENCIL_OT_data_unlink");
-
- /* add new layer button - can be used even when no data, since it can add a new block too */
- uiItemO(col, IFACE_("New Layer"), ICON_NONE, "GPENCIL_OT_layer_add");
- row = uiLayoutRow(col, true);
- uiItemO(row, IFACE_("Delete Frame"), ICON_NONE, "GPENCIL_OT_active_frame_delete");
- uiItemO(row, IFACE_("Convert"), ICON_NONE, "GPENCIL_OT_convert");
-
- /* sanity checks... */
- if (gpd == NULL)
- return;
-
- /* draw each layer --------------------------------------------- */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- col = uiLayoutColumn(layout, true);
- gp_drawui_layer(col, gpd, gpl, is_v3d);
- }
-
- /* draw gpd drawing settings first ------------------------------------- */
- col = uiLayoutColumn(layout, true);
- /* label */
- uiItemL(col, IFACE_("Drawing Settings:"), ICON_NONE);
-
- /* check whether advanced 3D-View drawing space options can be used */
- if (is_v3d) {
- if (gpd->flag & (GP_DATA_DEPTH_STROKE | GP_DATA_DEPTH_VIEW))
- v3d_stroke_opts = STROKE_OPTS_V3D_ON;
- else
- v3d_stroke_opts = STROKE_OPTS_V3D_OFF;
- }
-
- /* drawing space options */
- row = uiLayoutRow(col, true);
- uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "VIEW", NULL, ICON_NONE);
- uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "CURSOR", NULL, ICON_NONE);
-
- if (sc == NULL) {
- row = uiLayoutRow(col, true);
- uiLayoutSetActive(row, v3d_stroke_opts);
- uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "SURFACE", NULL, ICON_NONE);
- uiItemEnumR_string(row, &gpd_ptr, "draw_mode", "STROKE", NULL, ICON_NONE);
-
- row = uiLayoutRow(col, false);
- uiLayoutSetActive(row, v3d_stroke_opts == STROKE_OPTS_V3D_ON);
- uiItemR(row, &gpd_ptr, "use_stroke_endpoints", 0, NULL, ICON_NONE);
- }
-}
-
-void ED_gpencil_panel_standard_header(const bContext *C, Panel *pa)
-{
- PointerRNA ptr;
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, CTX_wm_space_data(C), &ptr);
-
- uiItemR(pa->layout, &ptr, "show_grease_pencil", 0, "", ICON_NONE);
-}
-
-/* Standard panel to be included wherever Grease Pencil is used... */
-void ED_gpencil_panel_standard(const bContext *C, Panel *pa)
-{
- bGPdata **gpd_ptr = NULL;
- PointerRNA ptr;
-
- /* if (v3d->flag2 & V3D_DISPGP)... etc. */
-
- draw_gpencil_space_specials(C, pa->layout);
-
- /* get pointer to Grease Pencil Data */
- gpd_ptr = ED_gpencil_data_get_pointers((bContext *)C, &ptr);
-
- if (gpd_ptr)
- draw_gpencil_panel((bContext *)C, pa->layout, *gpd_ptr, &ptr);
-}
-
-/* ************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
new file mode 100644
index 00000000000..e8d73eaffdf
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -0,0 +1,1484 @@
+/*
+ * ***** 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) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operator for converting Grease Pencil data to geometry
+ */
+
+/** \file blender/editors/gpencil/gpencil_convert.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_tracking.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+#include "ED_clip.h"
+#include "ED_keyframing.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* Grease Pencil to Data Operator */
+
+/* defines for possible modes */
+enum {
+ GP_STROKECONVERT_PATH = 1,
+ GP_STROKECONVERT_CURVE,
+ GP_STROKECONVERT_POLY,
+};
+
+/* Defines for possible timing modes */
+enum {
+ GP_STROKECONVERT_TIMING_NONE = 1,
+ GP_STROKECONVERT_TIMING_LINEAR = 2,
+ GP_STROKECONVERT_TIMING_FULL = 3,
+ GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
+};
+
+/* RNA enum define */
+static EnumPropertyItem prop_gpencil_convertmodes[] = {
+ {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
+ {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
+ {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
+ {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
+ "Use the original timing, but with custom gap lengths (in frames)"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ if (RNA_boolean_get(ptr, "use_timing_data")) {
+ return prop_gpencil_convert_timingmodes;
+ }
+ return prop_gpencil_convert_timingmodes_restricted;
+}
+
+/* --- */
+
+/* convert the coordinates from the given stroke point into 3d-coordinates
+ * - assumes that the active space is the 3D-View
+ */
+static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* directly use 3d-coordinates */
+ copy_v3_v3(p3d, &pt->x);
+ }
+ else {
+ const float *fp = ED_view3d_cursor3d_get(scene, v3d);
+ float mvalf[2];
+
+ /* get screen coordinate */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = &ar->v2d;
+ UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
+ }
+ else {
+ if (subrect) {
+ mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ else {
+ mvalf[0] = (float)pt->x / 100.0f * ar->winx;
+ mvalf[1] = (float)pt->y / 100.0f * ar->winy;
+ }
+ }
+
+ ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
+ }
+}
+
+/* --- */
+
+/* temp struct for gp_stroke_path_animation() */
+typedef struct tGpTimingData {
+ /* Data set from operator settings */
+ int mode;
+ int frame_range; /* Number of frames evaluated for path animation */
+ int start_frame, end_frame;
+ bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
+ float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
+ int seed;
+
+ /* Data set from points, used to compute final timing FCurve */
+ int num_points, cur_point;
+
+ /* Distances */
+ float *dists;
+ float tot_dist;
+
+ /* Times */
+ float *times; /* Note: Gap times will be negative! */
+ float tot_time, gap_tot_time;
+ double inittime;
+
+ /* Only used during creation of dists & times lists. */
+ float offset_time;
+} tGpTimingData;
+
+/* Init point buffers for timing data.
+ * Note this assumes we only grow those arrays!
+ */
+static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
+{
+ float *tmp;
+
+ BLI_assert(nbr > gtd->num_points);
+
+ /* distances */
+ tmp = gtd->dists;
+ gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ /* times */
+ tmp = gtd->times;
+ gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ gtd->num_points = nbr;
+}
+
+/* add stroke point to timing buffers */
+static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
+ const float delta_dist)
+{
+ float delta_time = 0.0f;
+ const int cur_point = gtd->cur_point;
+
+ if (!cur_point) {
+ /* Special case, first point, if time is not 0.0f we have to compensate! */
+ gtd->offset_time = -time;
+ gtd->times[cur_point] = 0.0f;
+ }
+ else if (time < 0.0f) {
+ /* This is a gap, negative value! */
+ gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
+
+ gtd->gap_tot_time += delta_time;
+ }
+ else {
+ gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
+ }
+
+ gtd->tot_time += delta_time;
+ gtd->tot_dist += delta_dist;
+ gtd->dists[cur_point] = gtd->tot_dist;
+
+ gtd->cur_point++;
+}
+
+/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
+ * arbitrarily close points - this is esp. important with NoGaps mode!
+ */
+#define MIN_TIME_DELTA 0.02f
+
+/* Loop over next points to find the end of the stroke, and compute */
+static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
+ int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
+ float *next_delta_time)
+{
+ int j;
+
+ for (j = idx + 1; j < gtd->num_points; j++) {
+ if (gtd->times[j] < 0) {
+ gtd->times[j] = -gtd->times[j];
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* In this mode, gap time between this stroke and the next should be 0 currently...
+ * So we have to compute its final duration!
+ */
+ if (gtd->gap_randomness > 0.0f) {
+ /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
+ * and which sum to exactly tot_gaps_time...
+ */
+ int rem_gaps = nbr_gaps - (*nbr_done_gaps);
+ if (rem_gaps < 2) {
+ /* Last gap, just give remaining time! */
+ *next_delta_time = tot_gaps_time;
+ }
+ else {
+ float delta, min, max;
+
+ /* This code ensures that if the first gaps have been shorter than average gap_duration,
+ * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
+ */
+ delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
+
+ /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
+ min = -gtd->gap_randomness - delta;
+ CLAMP(min, -gtd->gap_randomness, 0.0f);
+
+ /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
+ max = gtd->gap_randomness - delta;
+ CLAMP(max, 0.0f, gtd->gap_randomness);
+ *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
+ }
+ }
+ else {
+ *next_delta_time += gtd->gap_duration;
+ }
+ }
+ (*nbr_done_gaps)++;
+ break;
+ }
+ }
+
+ return j - 1;
+}
+
+static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
+{
+ int i;
+ float delta_time = 0.0f;
+
+ for (i = 0; i < gtd->num_points; i++) {
+ if (gtd->times[i] < 0 && i) {
+ (*nbr_gaps)++;
+ gtd->times[i] = -gtd->times[i] - delta_time;
+ delta_time += gtd->times[i] - gtd->times[i - 1];
+ gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
+ }
+ else {
+ gtd->times[i] -= delta_time;
+ }
+ }
+ gtd->tot_time -= delta_time;
+
+ *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
+ gtd->tot_time += *tot_gaps_time;
+ if (G.debug & G_DEBUG) {
+ printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
+ }
+ if (gtd->gap_randomness > 0.0f) {
+ BLI_rng_srandom(rng, gtd->seed);
+ }
+}
+
+static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
+ Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
+ const int nbr_gaps, const float tot_gaps_time)
+{
+ /* Use actual recorded timing! */
+ const float time_start = (float)gtd->start_frame;
+
+ float last_valid_time = 0.0f;
+ int end_stroke_idx = -1, start_stroke_idx = 0;
+ float end_stroke_time = 0.0f;
+
+ /* CustomGaps specific */
+ float delta_time = 0.0f, next_delta_time = 0.0f;
+ int nbr_done_gaps = 0;
+
+ int i;
+ float cfra;
+
+ /* This is a bit tricky, as:
+ * - We can't add arbitrarily close points on FCurve (in time).
+ * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
+ */
+ for (i = 0; i < gtd->num_points; i++) {
+ /* If new stroke... */
+ if (i > end_stroke_idx) {
+ start_stroke_idx = i;
+ delta_time = next_delta_time;
+ /* find end of that new stroke */
+ end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
+ tot_gaps_time, delta_time, &next_delta_time);
+ /* This one should *never* be negative! */
+ end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
+ }
+
+ /* Simple proportional stuff... */
+ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
+ cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
+
+ /* And now, the checks about timing... */
+ if (i == start_stroke_idx) {
+ /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
+ * that the end point of the stroke is far enough!
+ * In case it is not, we keep the end point...
+ * Note that with CustomGaps mode, this is here we set the actual gap timing!
+ */
+ if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
+ }
+ }
+ else if (i == end_stroke_idx) {
+ /* Always try to insert end point of a curve (should be safe enough, anyway...) */
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else {
+ /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
+ * and also far enough from (not yet added!) end_stroke keyframe!
+ */
+ if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
+ i, end_stroke_idx);
+ }
+ }
+ }
+}
+
+static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
+{
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+ FCurve *fcu;
+ PointerRNA ptr;
+ PropertyRNA *prop = NULL;
+ int nbr_gaps = 0, i;
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
+ return;
+
+ /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
+ gtd->gap_duration = FRA2TIME(gtd->gap_duration);
+ gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
+
+ /* Enable path! */
+ cu->flag |= CU_PATH;
+ cu->pathlen = gtd->frame_range;
+
+ /* Get RNA pointer to read/write path time values */
+ RNA_id_pointer_create((ID *)cu, &ptr);
+ prop = RNA_struct_find_property(&ptr, "eval_time");
+
+ /* Ensure we have an F-Curve to add keyframes to */
+ act = verify_adt_action((ID *)cu, true);
+ fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ }
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
+ float cfra;
+
+ /* Linear extrapolation! */
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+
+ cu->ctime = 0.0f;
+ cfra = (float)gtd->start_frame;
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+
+ cu->ctime = cu->pathlen;
+ if (gtd->realtime) {
+ cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ cfra = (float)gtd->end_frame;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ }
+ else {
+ /* Use actual recorded timing! */
+ RNG *rng = BLI_rng_new(0);
+ float time_range;
+
+ /* CustomGaps specific */
+ float tot_gaps_time = 0.0f;
+
+ /* Pre-process gaps, in case we don't want to keep their original timing */
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
+ }
+
+ if (gtd->realtime) {
+ time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ time_range = (float)(gtd->end_frame - gtd->start_frame);
+ }
+
+ if (G.debug & G_DEBUG) {
+ printf("GP Stroke Path Conversion: Starting keying!\n");
+ }
+
+ gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
+ nbr_gaps, tot_gaps_time);
+
+ BLI_rng_free(rng);
+ }
+
+ /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
+ calchandles_fcurve(fcu);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ printf("\n\n");
+ }
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ /* send updates */
+ DAG_id_tag_update(&cu->id, 0);
+}
+
+#undef MIN_TIME_DELTA
+
+#define GAP_DFAC 0.01f
+#define WIDTH_CORR_FAC 0.1f
+#define BEZT_HANDLE_FAC 0.3f
+
+/* convert stroke to 3d path */
+
+/* helper */
+static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
+{
+ copy_v3_v3(bp->vec, p);
+ bp->vec[3] = 1.0f;
+
+ /* set settings */
+ bp->f1 = SELECT;
+ bp->radius = width * rad_fac;
+ bp->weight = width;
+ CLAMP(bp->weight, 0.0f, 1.0f);
+ if (bp->weight < minmax_weights[0]) {
+ minmax_weights[0] = bp->weight;
+ }
+ else if (bp->weight > minmax_weights[1]) {
+ minmax_weights[1] = bp->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
+}
+
+static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
+{
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BPoint *bp, *prev_bp = NULL;
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ int i, old_nbp = 0;
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbp = nu->pntsu;
+
+ /* If stitch, the first point of this stroke is already present in current nu.
+ * Else, we have to add two additional points to make the zero-radius link between strokes.
+ */
+ BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->pntsv = 1;
+ nu->orderu = 2; /* point-to-point! */
+ nu->type = CU_NURBS;
+ nu->flagu = CU_NURB_ENDPOINT;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->knotsu = NULL;
+
+ nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ if (curnu && !stitch && old_nbp) {
+ float p1[3], p2[3], p[3], next_p[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ BLI_assert(gps->prev != NULL);
+
+ prev_bp = NULL;
+ if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bp = &nu->bp[old_nbp - 2];
+ }
+ bp = &nu->bp[old_nbp - 1];
+
+ /* First point */
+ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ if (prev_bp) {
+ interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp += 2;
+ }
+ else if (add_start_point) {
+ float p[3], next_p[3];
+ float dt = 0.0f;
+
+ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ bp = &nu->bp[old_nbp];
+ /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
+ * would not work (it would be *before* gtd->inittime, which is not supported currently).
+ */
+ gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp++;
+ }
+
+ if (old_nbp) {
+ prev_bp = &nu->bp[old_nbp - 1];
+ }
+
+ /* add points */
+ for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
+ i < gps->totpoints;
+ i++, pt++, bp++)
+ {
+ float p[3];
+ float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+
+ /* get coordinates to add at */
+ gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
+
+ gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
+ width, rad_fac, minmax_weights);
+
+ prev_bp = bp;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bp->vec);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+ /* Note bp has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* add nurb to curve */
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+}
+
+/* convert stroke to 3d bezier */
+
+/* helper */
+static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
+ const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
+{
+ copy_v3_v3(bezt->vec[0], h1);
+ copy_v3_v3(bezt->vec[1], p);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* set settings */
+ bezt->h1 = bezt->h2 = HD_FREE;
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->radius = width * rad_fac;
+ bezt->weight = width;
+ CLAMP(bezt->weight, 0.0f, 1.0f);
+ if (bezt->weight < minmax_weights[0]) {
+ minmax_weights[0] = bezt->weight;
+ }
+ else if (bezt->weight > minmax_weights[1]) {
+ minmax_weights[1] = bezt->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
+}
+
+static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
+{
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BezTriple *bezt, *prev_bezt = NULL;
+ int i, tot, old_nbezt = 0;
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbezt = nu->pntsu;
+ /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
+ * so no need to add it.
+ * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
+ */
+ BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->resolu = 12;
+ nu->resolv = 12;
+ nu->type = CU_BEZIER;
+ nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ tot = gps->totpoints;
+
+ /* get initial coordinates */
+ pt = gps->points;
+ if (tot) {
+ gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ if (tot > 1) {
+ gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ }
+ if (stitch && tot > 2) {
+ gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ }
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ if (curnu && old_nbezt) {
+ BLI_assert(gps->prev != NULL);
+
+ /* Update last point's second handle */
+ if (stitch) {
+ bezt = &nu->bezt[old_nbezt - 1];
+ interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+ pt++;
+ }
+
+ /* Create "link points" */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ else {
+ float p1[3], p2[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ prev_bezt = NULL;
+ if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bezt = &nu->bezt[old_nbezt - 2];
+ }
+ bezt = &nu->bezt[old_nbezt - 1];
+
+ /* First point */
+ if (prev_bezt) {
+ interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (tot > 1) {
+ interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second handle of last point of previous stroke. */
+ interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* First point */
+ interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
+
+ /* Second point */
+ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
+ 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt += 2;
+ copy_v3_v3(p3d_prev, p2);
+ }
+ }
+ else if (add_start_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, p3d_cur);
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
+ bezt = &nu->bezt[old_nbezt];
+ gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt++;
+ copy_v3_v3(p3d_prev, p);
+ }
+
+ if (old_nbezt) {
+ prev_bezt = &nu->bezt[old_nbezt - 1];
+ }
+
+ /* add points */
+ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
+ float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+
+ if (i || old_nbezt) {
+ interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
+ }
+
+ if (i < tot - 1) {
+ interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
+ }
+
+ gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
+ do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
+
+ /* shift coord vects */
+ copy_v3_v3(p3d_prev, p3d_cur);
+ copy_v3_v3(p3d_cur, p3d_next);
+
+ if (i + 2 < tot) {
+ gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ }
+
+ prev_bezt = bezt;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bezt->vec[1]);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+
+ /* Second handle of last point of this stroke. */
+ interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
+ copy_v3_v3(prev_bezt->vec[2], h2);
+
+ /* The end point */
+ interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
+ /* Note bezt has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* must calculate handles or else we crash */
+ BKE_nurb_handles_calc(nu);
+
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+}
+
+#undef GAP_DFAC
+#undef WIDTH_CORR_FAC
+#undef BEZT_HANDLE_FAC
+
+static void gp_stroke_finalize_curve_endpoints(Curve *cu)
+{
+ /* start */
+ Nurb *nu = cu->nurb.first;
+ int i = 0;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+
+ /* end */
+ nu = cu->nurb.last;
+ i = nu->pntsu - 1;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+}
+
+static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
+{
+ Nurb *nu;
+ const float delta = minmax_weights[0];
+ float fac;
+ int i;
+
+ /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
+ if (IS_EQF(delta, minmax_weights[1]))
+ fac = 1.0f;
+ else
+ fac = 1.0f / (minmax_weights[1] - delta);
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ bezt->weight = (bezt->weight - delta) * fac;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ for (i = 0; i < nu->pntsu; i++, bp++) {
+ bp->weight = (bp->weight - delta) * fac;
+ }
+ }
+ }
+}
+
+static int gp_camera_view_subrect(bContext *C, rctf *subrect)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (v3d) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ Scene *scene = CTX_data_scene(C);
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
+static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
+ const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
+{
+ struct Main *bmain = CTX_data_main(C);
+ View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDstroke *gps, *prev_gps = NULL;
+ Object *ob;
+ Curve *cu;
+ Nurb *nu = NULL;
+ Base *base_orig = BASACT, *base_new = NULL;
+ float minmax_weights[2] = {1.0f, 0.0f};
+
+ /* camera framing */
+ rctf subrect, *subrect_ptr = NULL;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpl, gpf))
+ return;
+
+ /* only convert if there are any strokes on this layer's frame to convert */
+ if (BLI_listbase_is_empty(&gpf->strokes))
+ return;
+
+ /* initialize camera framing */
+ if (gp_camera_view_subrect(C, &subrect)) {
+ subrect_ptr = &subrect;
+ }
+
+ /* init the curve object (remove rotation and get curve data from it)
+ * - must clear transforms set on object, as those skew our results
+ */
+ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
+ cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
+ base_new = BKE_scene_base_add(scene, ob);
+
+ cu->flag |= CU_3D;
+
+ gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
+
+ /* add points to curve */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ const bool add_start_point = (link_strokes && !(prev_gps));
+ const bool add_end_point = (link_strokes && !(gps->next));
+
+ /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */
+ bool stitch = false;
+ if (prev_gps) {
+ bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
+ bGPDspoint *pt2 = &gps->points[0];
+
+ if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
+ stitch = true;
+ }
+ }
+
+ /* Decide whether we connect this stroke to previous one */
+ if (!(stitch || link_strokes)) {
+ nu = NULL;
+ }
+
+ switch (mode) {
+ case GP_STROKECONVERT_PATH:
+ gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
+ break;
+ case GP_STROKECONVERT_CURVE:
+ case GP_STROKECONVERT_POLY: /* convert after */
+ gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
+ break;
+ default:
+ BLI_assert(!"invalid mode");
+ break;
+ }
+ prev_gps = gps;
+ }
+
+ /* If link_strokes, be sure first and last points have a zero weight/size! */
+ if (link_strokes) {
+ gp_stroke_finalize_curve_endpoints(cu);
+ }
+
+ /* Update curve's weights, if needed */
+ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
+ gp_stroke_norm_curve_weights(cu, minmax_weights);
+ }
+
+ /* Create the path animation, if needed */
+ gp_stroke_path_animation(C, reports, cu, gtd);
+
+ if (mode == GP_STROKECONVERT_POLY) {
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ BKE_nurb_type_convert(nu, CU_POLY, false);
+ }
+ }
+
+ /* set the layer and select */
+ base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
+ base_new->flag = ob->flag = base_new->flag | SELECT;
+}
+
+/* --- */
+
+/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
+ * op may be NULL.
+ */
+static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = NULL;
+ bGPDstroke *gps = NULL;
+ bGPDspoint *pt;
+ double base_time, cur_time, prev_time = -1.0;
+ int i;
+ bool valid = true;
+
+ if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
+ return false;
+
+ do {
+ base_time = cur_time = gps->inittime;
+ if (cur_time <= prev_time) {
+ valid = false;
+ break;
+ }
+
+ prev_time = cur_time;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ cur_time = base_time + (double)pt->time;
+ /* First point of a stroke should have the same time as stroke's inittime,
+ * so it's the only case where equality is allowed!
+ */
+ if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
+ valid = false;
+ break;
+ }
+ prev_time = cur_time;
+ }
+
+ if (!valid) {
+ break;
+ }
+ } while ((gps = gps->next));
+
+ if (op) {
+ RNA_boolean_set(op->ptr, "use_timing_data", valid);
+ }
+ return valid;
+}
+
+/* Check end_frame is always > start frame! */
+static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
+{
+ int start_frame = RNA_int_get(ptr, "start_frame");
+ int end_frame = RNA_int_get(ptr, "end_frame");
+
+ if (end_frame <= start_frame) {
+ RNA_int_set(ptr, "end_frame", start_frame + 1);
+ }
+}
+
+static int gp_convert_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = NULL;
+ bGPDframe *gpf = NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+
+ /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
+ * and if we are not in edit mode!
+ */
+ return ((sa && sa->spacetype == SPACE_VIEW3D) &&
+ (gpl = gpencil_layer_getactive(gpd)) &&
+ (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpf->strokes.first) &&
+ (scene->obedit == NULL));
+}
+
+static int gp_convert_layer_exec(bContext *C, wmOperator *op)
+{
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ Scene *scene = CTX_data_scene(C);
+ const int mode = RNA_enum_get(op->ptr, "type");
+ const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
+ const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
+ const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
+ bool valid_timing;
+ tGpTimingData gtd;
+
+ /* check if there's data to work with */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
+ BKE_report(op->reports, RPT_WARNING,
+ "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
+ }
+ valid_timing = RNA_property_boolean_get(op->ptr, prop);
+
+ gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
+ /* Check for illegal timing mode! */
+ if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
+ gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
+ RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
+ }
+ if (!link_strokes) {
+ gtd.mode = GP_STROKECONVERT_TIMING_NONE;
+ }
+
+ /* grab all relevant settings */
+ gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
+ gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
+ gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
+ gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
+ gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
+ gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
+ gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
+ gtd.seed = RNA_int_get(op->ptr, "seed");
+ gtd.num_points = gtd.cur_point = 0;
+ gtd.dists = gtd.times = NULL;
+ gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
+ gtd.inittime = 0.0;
+ gtd.offset_time = 0.0f;
+
+ /* perform conversion */
+ gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
+
+ /* free temp memory */
+ if (gtd.dists) {
+ MEM_freeN(gtd.dists);
+ gtd.dists = NULL;
+ }
+ if (gtd.times) {
+ MEM_freeN(gtd.times);
+ gtd.times = NULL;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
+ int timing_mode = RNA_enum_get(ptr, "timing_mode");
+ bool realtime = RNA_boolean_get(ptr, "use_realtime");
+ float gap_duration = RNA_float_get(ptr, "gap_duration");
+ float gap_randomness = RNA_float_get(ptr, "gap_randomness");
+ const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
+
+ /* Always show those props */
+ if (STREQ(prop_id, "type") ||
+ STREQ(prop_id, "use_normalize_weights") ||
+ STREQ(prop_id, "radius_multiplier") ||
+ STREQ(prop_id, "use_link_strokes"))
+ {
+ return true;
+ }
+
+ /* Never show this prop */
+ if (STREQ(prop_id, "use_timing_data"))
+ return false;
+
+ if (link_strokes) {
+ /* Only show when link_stroke is true */
+ if (STREQ(prop_id, "timing_mode"))
+ return true;
+
+ if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
+ /* Only show when link_stroke is true and stroke timing is enabled */
+ if (STREQ(prop_id, "frame_range") ||
+ STREQ(prop_id, "start_frame"))
+ {
+ return true;
+ }
+
+ /* Only show if we have valid timing data! */
+ if (valid_timing && STREQ(prop_id, "use_realtime"))
+ return true;
+
+ /* Only show if realtime or valid_timing is false! */
+ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
+ return true;
+
+ if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* Only show for custom gaps! */
+ if (STREQ(prop_id, "gap_duration"))
+ return true;
+
+ /* Only show randomness for non-null custom gaps! */
+ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
+ return true;
+
+ /* Only show seed for randomize action! */
+ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
+ return true;
+ }
+ }
+ }
+
+ /* Else, hidden! */
+ return false;
+}
+
+static void gp_convert_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0');
+}
+
+void GPENCIL_OT_convert(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Convert Grease Pencil";
+ ot->idname = "GPENCIL_OT_convert";
+ ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_convert_layer_exec;
+ ot->poll = gp_convert_poll;
+ ot->ui = gp_convert_ui;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
+
+ RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
+ "Normalize weight (set from stroke width)");
+ RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
+ "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes",
+ "Whether to link strokes with zero-radius sections of curves");
+
+ prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
+ "Timing Mode", "How to use timing data stored in strokes");
+ RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
+
+ RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
+ "The duration of evaluation of the path control curve", 1, 1000);
+ RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
+ "The start frame of the path control curve", 1, 100000);
+ RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
+ "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
+ prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
+ "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
+ RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
+
+ RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
+ "Custom Gap mode: (Average) length of gaps, in frames "
+ "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
+ "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
+ "Custom Gap mode: Random generator seed", 0, 100);
+
+ /* Note: Internal use, this one will always be hidden by UI code... */
+ prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
+ "Whether the converted Grease Pencil layer has valid timing data (internal use)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
new file mode 100644
index 00000000000..de966776645
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -0,0 +1,447 @@
+/*
+ * ***** 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) 2008, Blender Foundation, Joshua Leung
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for dealing with GP datablocks and layers
+ */
+
+/** \file blender/editors/gpencil/gpencil_data.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_gpencil.h"
+
+#include "gpencil_intern.h"
+
+
+/* ************************************************ */
+/* Datablock Operators */
+
+/* ******************* Add New Data ************************ */
+
+/* add new datablock - wrapper around API */
+static int gp_data_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* decrement user count and add new datablock */
+ bGPdata *gpd = (*gpd_ptr);
+
+ id_us_min(&gpd->id);
+ *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_data_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Add New";
+ ot->idname = "GPENCIL_OT_data_add";
+ ot->description = "Add new Grease Pencil datablock";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_data_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Unlink Data ************************ */
+
+/* poll callback for adding data/layers - special */
+static int gp_data_unlink_poll(bContext *C)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if we have access to some active data, make sure there's a datablock before enabling this */
+ return (gpd_ptr && *gpd_ptr);
+}
+
+
+/* unlink datablock - wrapper around API */
+static int gp_data_unlink_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* just unlink datablock now, decreasing its user count */
+ bGPdata *gpd = (*gpd_ptr);
+
+ id_us_min(&gpd->id);
+ *gpd_ptr = NULL;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_data_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Unlink";
+ ot->idname = "GPENCIL_OT_data_unlink";
+ ot->description = "Unlink active Grease Pencil datablock";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_data_unlink_exec;
+ ot->poll = gp_data_unlink_poll;
+}
+
+
+/* ************************************************ */
+/* Layer Operators */
+
+/* ******************* Add New Layer ************************ */
+
+/* add new layer - wrapper around API */
+static int gp_layer_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ if (*gpd_ptr == NULL)
+ *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+
+ /* add new layer now */
+ gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Layer";
+ ot->idname = "GPENCIL_OT_layer_add";
+ ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Layer ************************* */
+
+static int gp_layer_remove_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* make the layer before this the new active layer
+ * - use the one after if this is the first
+ * - if this is the only layer, this naturally becomes NULL
+ */
+ if (gpl->prev)
+ gpencil_layer_setactive(gpd, gpl->prev);
+ else
+ gpencil_layer_setactive(gpd, gpl->next);
+
+ /* delete the layer now... */
+ gpencil_layer_delete(gpd, gpl);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Layer";
+ ot->idname = "GPENCIL_OT_layer_remove";
+ ot->description = "Remove active Grease Pencil layer";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_remove_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Move Layer Up/Down ************************** */
+
+enum {
+ GP_LAYER_MOVE_UP = -1,
+ GP_LAYER_MOVE_DOWN = 1
+};
+
+static int gp_layer_move_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ /* up or down? */
+ if (direction == GP_LAYER_MOVE_UP) {
+ /* up */
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
+ }
+ else {
+ /* down */
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Grease Pencil Layer";
+ ot->idname = "GPENCIL_OT_layer_move";
+ ot->description = "Move the active Grease Pencil layer up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gp_layer_move_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
+
+/* ********************* Duplicate Layer ************************** */
+
+static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *new_layer;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ /* make copy of layer, and add it immediately after the existing layer */
+ new_layer = gpencil_layer_duplicate(gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
+
+ /* ensure new layer has a unique name, and is now the active layer */
+ BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
+ gpencil_layer_setactive(gpd, new_layer);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Layer";
+ ot->idname = "GPENCIL_OT_layer_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil layer";
+
+ /* callbacks */
+ ot->exec = gp_layer_copy_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *********************** Hide Layers ******************************** */
+
+static int gp_hide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, layer))
+ return OPERATOR_CANCELLED;
+
+ if (unselected) {
+ bGPDlayer *gpl;
+
+ /* hide unselected */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl != layer) {
+ gpl->flag |= GP_LAYER_HIDE;
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ layer->flag |= GP_LAYER_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Layer(s)";
+ ot->idname = "GPENCIL_OT_hide";
+ ot->description = "Hide selected/unselected Grease Pencil layers";
+
+ /* callbacks */
+ ot->exec = gp_hide_exec;
+ ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
+}
+
+/* ********************** Show All Layers ***************************** */
+
+/* poll callback for showing layers */
+static int gp_reveal_poll(bContext *C)
+{
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gp_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* make all layers visible */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "GPENCIL_OT_reveal";
+ ot->description = "Show all Grease Pencil layers";
+
+ /* callbacks */
+ ot->exec = gp_reveal_exec;
+ ot->poll = gp_reveal_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 13334448941..5c37a0a5b60 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -21,12 +21,15 @@
* Contributor(s): Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for editing Grease Pencil strokes
*/
/** \file blender/editors/gpencil/gpencil_edit.c
* \ingroup edgpencil
*/
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -37,15 +40,10 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_rand.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
-#include "DNA_anim_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_object_types.h"
-#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -53,17 +51,11 @@
#include "DNA_gpencil_types.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_tracking.h"
#include "UI_interface.h"
@@ -77,261 +69,369 @@
#include "ED_gpencil.h"
#include "ED_view3d.h"
-#include "ED_clip.h"
-#include "ED_keyframing.h"
#include "gpencil_intern.h"
-
/* ************************************************ */
-/* Context Wrangling... */
+/* Stroke Editing Operators */
-/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
-bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+/* poll callback for all stroke editing operators */
+static int gp_stroke_edit_poll(bContext *C)
{
- ID *screen_id = (ID *)CTX_wm_screen(C);
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
-
- /* if there's an active area, check if the particular editor may
- * have defined any special Grease Pencil context for editing...
- */
- if (sa) {
- switch (sa->spacetype) {
- case SPACE_VIEW3D: /* 3D-View */
- {
- Object *ob = CTX_data_active_object(C);
-
- /* TODO: we can include other data-types such as bones later if need be... */
-
- /* just in case no active/selected object */
- if (ob && (ob->flag & SELECT)) {
- /* for now, as long as there's an object, default to using that in 3D-View */
- if (ptr) RNA_id_pointer_create(&ob->id, ptr);
- return &ob->gpd;
- }
- break;
- }
- case SPACE_NODE: /* Nodes Editor */
- {
- SpaceNode *snode = (SpaceNode *)CTX_wm_space_data(C);
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+}
- /* return the GP data for the active node block/node */
- if (snode && snode->nodetree) {
- /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
- if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
- return &snode->nodetree->gpd;
- }
+/* ************** Duplicate Selected Strokes **************** */
- /* even when there is no node-tree, don't allow this to flow to scene */
- return NULL;
+/* Make copies of selected point segments in a selected stroke */
+static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes)
+{
+ bGPDspoint *pt;
+ int i;
+
+ int start_idx = -1;
+
+
+ /* Step through the original stroke's points:
+ * - We accumulate selected points (from start_idx to current index)
+ * and then convert that to a new stroke
+ */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* searching for start, are waiting for end? */
+ if (start_idx == -1) {
+ /* is this the first selected point for a new island? */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ start_idx = i;
}
- case SPACE_SEQ: /* Sequencer */
- {
- SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
-
- /* for now, Grease Pencil data is associated with the space (actually preview region only) */
- /* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
- return &sseq->gpd;
+ }
+ else {
+ size_t len = 0;
+
+ /* is this the end of current island yet?
+ * 1) Point i-1 was the last one that was selected
+ * 2) Point i is the last in the array
+ */
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ len = i - start_idx;
}
- case SPACE_IMAGE: /* Image/UV Editor */
- {
- SpaceImage *sima = (SpaceImage *)CTX_wm_space_data(C);
-
- /* for now, Grease Pencil data is associated with the space... */
- /* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
- return &sima->gpd;
+ else if (i == gps->totpoints - 1) {
+ len = i - start_idx + 1;
}
- case SPACE_CLIP: /* Nodes Editor */
- {
- SpaceClip *sc = (SpaceClip *)CTX_wm_space_data(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
-
- if (!track)
- return NULL;
-
- if (ptr)
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
-
- return &track->gpd;
- }
- else {
- if (ptr)
- RNA_id_pointer_create(&clip->id, ptr);
-
- return &clip->gpd;
- }
- }
- break;
+ //printf("copying from %d to %d = %d\n", start_idx, i, len);
+
+ /* make copies of the relevant data */
+ if (len) {
+ bGPDstroke *gpsd;
+
+ /* make a stupid copy first of the entire stroke (to get the flags too) */
+ gpsd = MEM_dupallocN(gps);
+
+ /* now, make a new points array, and copy of the relevant parts */
+ gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
+ memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
+ gpsd->totpoints = len;
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(new_strokes, gpsd);
+
+ /* cleanup + reset for next */
+ start_idx = -1;
}
- default: /* unsupported space */
- return NULL;
}
}
-
- /* just fall back on the scene's GP data */
- if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
- return (scene) ? &scene->gpd : NULL;
-}
-
-/* Get the active Grease Pencil datablock */
-bGPdata *ED_gpencil_data_get_active(const bContext *C)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
-}
-
-bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
-{
- Base *base = scene->basact;
- bGPdata *gpd = NULL;
- /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
- * to be consistent with ED_gpencil_data_get_active's behavior.
- */
-
- if (base && TESTBASE(v3d, base)) {
- gpd = base->object->gpd;
- }
- return gpd ? gpd : scene->gpd;
-}
-
-/* ************************************************ */
-/* Panel Operators */
-
-/* poll callback for adding data/layers - special */
-static int gp_add_poll(bContext *C)
-{
- /* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
}
-/* ******************* Add New Data ************************ */
-
-/* add new datablock - wrapper around API */
-static int gp_data_add_exec(bContext *C, wmOperator *op)
+static int gp_duplicate_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
return OPERATOR_CANCELLED;
}
- else {
- /* decrement user count and add new datablock */
- bGPdata *gpd = (*gpd_ptr);
-
- id_us_min(&gpd->id);
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+
+ /* for each visible (and editable) layer's selected strokes,
+ * copy the strokes into a temporary buffer, then append
+ * once all done
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ ListBase new_strokes = {NULL, NULL};
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ if (gpf == NULL)
+ continue;
+
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (gps->totpoints == 1) {
+ /* Special Case: If there's just a single point in this stroke... */
+ bGPDstroke *gpsd;
+
+ /* make direct copies of the stroke and its points */
+ gpsd = MEM_dupallocN(gps);
+ gpsd->points = MEM_dupallocN(gps->points);
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(&new_strokes, gpsd);
+ }
+ else {
+ /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+ gp_duplicate_points(gps, &new_strokes);
+ }
+
+ /* deselect original stroke, or else the originals get moved too
+ * (when using the copy + move macro)
+ */
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+
+ /* add all new strokes in temp buffer to the frame (preventing double-copies) */
+ BLI_movelisttolist(&gpf->strokes, &new_strokes);
+ BLI_assert(new_strokes.first == NULL);
}
-
- /* notifiers */
+ CTX_DATA_END;
+
+ /* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
+
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_data_add(wmOperatorType *ot)
+void GPENCIL_OT_duplicate(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Grease Pencil Add New";
- ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+ ot->name = "Duplicate Strokes";
+ ot->idname = "GPENCIL_OT_duplicate";
+ ot->description = "Duplicate the selected Grease Pencil strokes";
+
/* callbacks */
- ot->exec = gp_data_add_exec;
- ot->poll = gp_add_poll;
+ ot->exec = gp_duplicate_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Unlink Data ************************ */
+/* ******************* Copy/Paste Strokes ************************* */
+/* Grease Pencil stroke data copy/paste buffer:
+ * - The copy operation collects all segments of selected strokes,
+ * dumping "ready to be copied" copies of the strokes into the buffer.
+ * - The paste operation makes a copy of those elements, and adds them
+ * to the active layer. This effectively flattens down the strokes
+ * from several different layers into a single layer.
+ */
-/* poll callback for adding data/layers - special */
-static int gp_data_unlink_poll(bContext *C)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+/* list of bGPDstroke instances */
+static ListBase gp_strokes_copypastebuf = {NULL, NULL};
- /* if we have access to some active data, make sure there's a datablock before enabling this */
- return (gpd_ptr && *gpd_ptr);
+/* Free copy/paste buffer data */
+void ED_gpencil_strokes_copybuf_free(void)
+{
+ bGPDstroke *gps, *gpsn;
+
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ MEM_freeN(gps->points);
+ BLI_freelinkN(&gp_strokes_copypastebuf, gps);
+ }
+
+ BLI_listbase_clear(&gp_strokes_copypastebuf);
}
+/* --------------------- */
+/* Copy selected strokes */
-/* unlink datablock - wrapper around API */
-static int gp_data_unlink_exec(bContext *C, wmOperator *op)
+static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
return OPERATOR_CANCELLED;
}
- else {
- /* just unlink datablock now, decreasing its user count */
- bGPdata *gpd = (*gpd_ptr);
-
- id_us_min(&gpd->id);
- *gpd_ptr = NULL;
+
+ /* clear the buffer first */
+ ED_gpencil_strokes_copybuf_free();
+
+ /* for each visible (and editable) layer's selected strokes,
+ * copy the strokes into a temporary buffer, then append
+ * once all done
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ if (gpf == NULL)
+ continue;
+
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (gps->totpoints == 1) {
+ /* Special Case: If there's just a single point in this stroke... */
+ bGPDstroke *gpsd;
+
+ /* make direct copies of the stroke and its points */
+ gpsd = MEM_dupallocN(gps);
+ gpsd->points = MEM_dupallocN(gps->points);
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(&gp_strokes_copypastebuf, gpsd);
+ }
+ else {
+ /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+ gp_duplicate_points(gps, &gp_strokes_copypastebuf);
+ }
+ }
+ }
}
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
+ CTX_DATA_END;
+
+ /* done - no updates needed */
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_data_unlink(wmOperatorType *ot)
+void GPENCIL_OT_copy(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Grease Pencil Unlink";
- ot->idname = "GPENCIL_OT_data_unlink";
- ot->description = "Unlink active Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+ ot->name = "Copy Strokes";
+ ot->idname = "GPENCIL_OT_copy";
+ ot->description = "Copy selected Grease Pencil points and strokes";
+
/* callbacks */
- ot->exec = gp_data_unlink_exec;
- ot->poll = gp_data_unlink_poll;
+ ot->exec = gp_strokes_copy_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ //ot->flag = OPTYPE_REGISTER;
}
-/* ******************* Add New Layer ************************ */
+/* --------------------- */
+/* Paste selected strokes */
-/* add new layer - wrapper around API */
-static int gp_layer_add_exec(bContext *C, wmOperator *op)
+static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *gpf;
+
+ /* check for various error conditions */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
return OPERATOR_CANCELLED;
}
- if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
-
- /* add new layer now */
- gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
-
- /* notifiers */
+ else if (gp_strokes_copypastebuf.first == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again");
+ return OPERATOR_CANCELLED;
+ }
+ else if (gpl == NULL) {
+ /* no active layer - let's just create one */
+ gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), 1);
+ }
+ else if (gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) {
+ BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* Check that some of the strokes in the buffer can be used */
+ bGPDstroke *gps;
+ bool ok = false;
+
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false) {
+ /* XXX: this check is not 100% accurate (i.e. image editor is incompatible with normal 2D strokes),
+ * but should be enough to give users a good idea of what's going on
+ */
+ if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D)
+ BKE_report(op->reports, RPT_ERROR, "Cannot paste 2D strokes in 3D View");
+ else
+ BKE_report(op->reports, RPT_ERROR, "Cannot paste 3D strokes in 2D editors");
+
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Deselect all strokes first */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+
+ /* Ensure we have a frame to draw into
+ * NOTE: Since this is an op which creates strokes,
+ * we are obliged to add a new frame if one
+ * doesn't exist already
+ */
+ gpf = gpencil_layer_getframe(gpl, CFRA, true);
+
+ if (gpf) {
+ bGPDstroke *gps;
+
+ /* Copy each stroke into the layer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+ new_stroke->next = new_stroke->prev = NULL;
+
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
+
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_layer_add(wmOperatorType *ot)
+void GPENCIL_OT_paste(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add New Layer";
- ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+ ot->name = "Paste Strokes";
+ ot->idname = "GPENCIL_OT_paste";
+ ot->description = "Paste previously copied strokes into active layer";
+
/* callbacks */
- ot->exec = gp_layer_add_exec;
- ot->poll = gp_add_poll;
+ ot->exec = gp_strokes_paste_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************* Delete Active Frame ************************ */
@@ -340,7 +440,7 @@ static int gp_actframe_delete_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
+
/* only if there's an active layer with an active frame */
return (gpl && gpl->actframe);
}
@@ -352,7 +452,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
-
+
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No grease pencil data");
@@ -362,13 +462,13 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No active frame to delete");
return OPERATOR_CANCELLED;
}
-
+
/* delete it... */
gpencil_layer_delframe(gpl, gpf);
-
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -378,1406 +478,338 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->name = "Delete Active Frame";
ot->idname = "GPENCIL_OT_active_frame_delete";
ot->description = "Delete the active frame for the active Grease Pencil datablock";
+
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* callbacks */
ot->exec = gp_actframe_delete_exec;
ot->poll = gp_actframe_delete_poll;
}
-/* ************************************************ */
-/* Grease Pencil to Data Operator */
-
-/* defines for possible modes */
-enum {
- GP_STROKECONVERT_PATH = 1,
- GP_STROKECONVERT_CURVE,
- GP_STROKECONVERT_POLY,
-};
-
-/* Defines for possible timing modes */
-enum {
- GP_STROKECONVERT_TIMING_NONE = 1,
- GP_STROKECONVERT_TIMING_LINEAR = 2,
- GP_STROKECONVERT_TIMING_FULL = 3,
- GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
-};
+/* ******************* Delete Operator ************************ */
-/* RNA enum define */
-static EnumPropertyItem prop_gpencil_convertmodes[] = {
- {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
- {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
- {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
- {0, NULL, 0, NULL, NULL}
-};
+typedef enum eGP_DeleteMode {
+ /* delete selected stroke points */
+ GP_DELETEOP_POINTS = 0,
+ /* delete selected strokes */
+ GP_DELETEOP_STROKES = 1,
+ /* delete active frame */
+ GP_DELETEOP_FRAME = 2,
+} eGP_DeleteMode;
-static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {0, NULL, 0, NULL, NULL},
-};
-static EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
- {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
- "Use the original timing, but with custom gap lengths (in frames)"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
- bool *UNUSED(r_free))
+/* Delete selected strokes */
+static int gp_delete_selected_strokes(bContext *C)
{
- if (RNA_boolean_get(ptr, "use_timing_data")) {
- return prop_gpencil_convert_timingmodes;
- }
- return prop_gpencil_convert_timingmodes_restricted;
-}
-
-/* --- */
-
-/* convert the coordinates from the given stroke point into 3d-coordinates
- * - assumes that the active space is the 3D-View
- */
-static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* directly use 3d-coordinates */
- copy_v3_v3(p3d, &pt->x);
- }
- else {
- const float *fp = ED_view3d_cursor3d_get(scene, v3d);
- float mvalf[2];
-
- /* get screen coordinate */
- if (gps->flag & GP_STROKE_2DSPACE) {
- View2D *v2d = &ar->v2d;
- UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
- }
- else {
- if (subrect) {
- mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- else {
- mvalf[0] = (float)pt->x / 100.0f * ar->winx;
- mvalf[1] = (float)pt->y / 100.0f * ar->winy;
- }
- }
-
- ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
- }
-}
-
-/* --- */
-
-/* temp struct for gp_stroke_path_animation() */
-typedef struct tGpTimingData {
- /* Data set from operator settings */
- int mode;
- int frame_range; /* Number of frames evaluated for path animation */
- int start_frame, end_frame;
- bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
- float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
- int seed;
-
- /* Data set from points, used to compute final timing FCurve */
- int num_points, cur_point;
-
- /* Distances */
- float *dists;
- float tot_dist;
-
- /* Times */
- float *times; /* Note: Gap times will be negative! */
- float tot_time, gap_tot_time;
- double inittime;
-
- /* Only used during creation of dists & times lists. */
- float offset_time;
-} tGpTimingData;
-
-/* Init point buffers for timing data.
- * Note this assumes we only grow those arrays!
- */
-static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
-{
- float *tmp;
-
- BLI_assert(nbr > gtd->num_points);
-
- /* distances */
- tmp = gtd->dists;
- gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- /* times */
- tmp = gtd->times;
- gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- gtd->num_points = nbr;
-}
-
-/* add stroke point to timing buffers */
-static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
- const float delta_dist)
-{
- float delta_time = 0.0f;
- const int cur_point = gtd->cur_point;
-
- if (!cur_point) {
- /* Special case, first point, if time is not 0.0f we have to compensate! */
- gtd->offset_time = -time;
- gtd->times[cur_point] = 0.0f;
- }
- else if (time < 0.0f) {
- /* This is a gap, negative value! */
- gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
-
- gtd->gap_tot_time += delta_time;
+ bool changed = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) MEM_freeN(gps->points);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
}
else {
- gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
+ return OPERATOR_CANCELLED;
}
-
- gtd->tot_time += delta_time;
- gtd->tot_dist += delta_dist;
- gtd->dists[cur_point] = gtd->tot_dist;
-
- gtd->cur_point++;
}
-/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
- * arbitrarily close points - this is esp. important with NoGaps mode!
- */
-#define MIN_TIME_DELTA 0.02f
-
-/* Loop over next points to find the end of the stroke, and compute */
-static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
- int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
- float *next_delta_time)
+/* Delete selected points but keep the stroke */
+static int gp_dissolve_selected_points(bContext *C)
{
- int j;
-
- for (j = idx + 1; j < gtd->num_points; j++) {
- if (gtd->times[j] < 0) {
- gtd->times[j] = -gtd->times[j];
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* In this mode, gap time between this stroke and the next should be 0 currently...
- * So we have to compute its final duration!
- */
- if (gtd->gap_randomness > 0.0f) {
- /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
- * and which sum to exactly tot_gaps_time...
- */
- int rem_gaps = nbr_gaps - (*nbr_done_gaps);
- if (rem_gaps < 2) {
- /* Last gap, just give remaining time! */
- *next_delta_time = tot_gaps_time;
- }
- else {
- float delta, min, max;
-
- /* This code ensures that if the first gaps have been shorter than average gap_duration,
- * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
- */
- delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
-
- /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
- min = -gtd->gap_randomness - delta;
- CLAMP(min, -gtd->gap_randomness, 0.0f);
-
- /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
- max = gtd->gap_randomness - delta;
- CLAMP(max, 0.0f, gtd->gap_randomness);
- *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
+ bool changed = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete points from selected strokes
+ * NOTE: we may still have to remove the stroke if it ends up having no points!
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ int tot = gps->totpoints; /* number of points in new buffer */
+
+ /* First Pass: Count how many points are selected (i.e. how many to remove) */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected point - one of the points to remove */
+ tot--;
}
}
- else {
- *next_delta_time += gtd->gap_duration;
+
+ /* if no points are left, we simply delete the entire stroke */
+ if (tot <= 0) {
+ /* remove the entire stroke */
+ MEM_freeN(gps->points);
+ BLI_freelinkN(&gpf->strokes, gps);
}
- }
- (*nbr_done_gaps)++;
- break;
- }
- }
-
- return j - 1;
-}
-
-static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
-{
- int i;
- float delta_time = 0.0f;
-
- for (i = 0; i < gtd->num_points; i++) {
- if (gtd->times[i] < 0 && i) {
- (*nbr_gaps)++;
- gtd->times[i] = -gtd->times[i] - delta_time;
- delta_time += gtd->times[i] - gtd->times[i - 1];
- gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
- }
- else {
- gtd->times[i] -= delta_time;
- }
- }
- gtd->tot_time -= delta_time;
-
- *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
- gtd->tot_time += *tot_gaps_time;
- if (G.debug & G_DEBUG) {
- printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
- }
- if (gtd->gap_randomness > 0.0f) {
- BLI_rng_srandom(rng, gtd->seed);
- }
-}
-
-static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
- Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
- const int nbr_gaps, const float tot_gaps_time)
-{
- /* Use actual recorded timing! */
- const float time_start = (float)gtd->start_frame;
-
- float last_valid_time = 0.0f;
- int end_stroke_idx = -1, start_stroke_idx = 0;
- float end_stroke_time = 0.0f;
-
- /* CustomGaps specific */
- float delta_time = 0.0f, next_delta_time = 0.0f;
- int nbr_done_gaps = 0;
-
- int i;
- float cfra;
-
- /* This is a bit tricky, as:
- * - We can't add arbitrarily close points on FCurve (in time).
- * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
- */
- for (i = 0; i < gtd->num_points; i++) {
- /* If new stroke... */
- if (i > end_stroke_idx) {
- start_stroke_idx = i;
- delta_time = next_delta_time;
- /* find end of that new stroke */
- end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
- tot_gaps_time, delta_time, &next_delta_time);
- /* This one should *never* be negative! */
- end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
- }
-
- /* Simple proportional stuff... */
- cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
- cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
-
- /* And now, the checks about timing... */
- if (i == start_stroke_idx) {
- /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
- * that the end point of the stroke is far enough!
- * In case it is not, we keep the end point...
- * Note that with CustomGaps mode, this is here we set the actual gap timing!
- */
- if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
+ else {
+ /* just copy all unselected into a smaller buffer */
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
+ bGPDspoint *npt = new_points;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ *npt = *pt;
+ npt++;
+ }
+ }
+
+ /* free the old buffer */
+ MEM_freeN(gps->points);
+
+ /* save the new buffer */
+ gps->points = new_points;
+ gps->totpoints = tot;
+
+ /* deselect the stroke, since none of its selected points will still be selected */
+ gps->flag &= ~GP_STROKE_SELECT;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
- }
- }
- else if (i == end_stroke_idx) {
- /* Always try to insert end point of a curve (should be safe enough, anyway...) */
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else {
- /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
- * and also far enough from (not yet added!) end_stroke keyframe!
- */
- if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
- i, end_stroke_idx);
+
+ changed = true;
}
}
}
-}
-
-static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
-{
- Scene *scene = CTX_data_scene(C);
- bAction *act;
- FCurve *fcu;
- PointerRNA ptr;
- PropertyRNA *prop = NULL;
- int nbr_gaps = 0, i;
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
- return;
-
- /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
- gtd->gap_duration = FRA2TIME(gtd->gap_duration);
- gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
-
- /* Enable path! */
- cu->flag |= CU_PATH;
- cu->pathlen = gtd->frame_range;
-
- /* Get RNA pointer to read/write path time values */
- RNA_id_pointer_create((ID *)cu, &ptr);
- prop = RNA_struct_find_property(&ptr, "eval_time");
-
- /* Ensure we have an F-Curve to add keyframes to */
- act = verify_adt_action((ID *)cu, true);
- fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
-
- if (G.debug & G_DEBUG) {
- printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- }
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
- float cfra;
-
- /* Linear extrapolation! */
- fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
-
- cu->ctime = 0.0f;
- cfra = (float)gtd->start_frame;
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
-
- cu->ctime = cu->pathlen;
- if (gtd->realtime) {
- cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- cfra = (float)gtd->end_frame;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ CTX_DATA_END;
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
}
else {
- /* Use actual recorded timing! */
- RNG *rng = BLI_rng_new(0);
- float time_range;
-
- /* CustomGaps specific */
- float tot_gaps_time = 0.0f;
-
- /* Pre-process gaps, in case we don't want to keep their original timing */
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
- }
-
- if (gtd->realtime) {
- time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- time_range = (float)(gtd->end_frame - gtd->start_frame);
- }
-
- if (G.debug & G_DEBUG) {
- printf("GP Stroke Path Conversion: Starting keying!\n");
- }
-
- gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
- nbr_gaps, tot_gaps_time);
-
- BLI_rng_free(rng);
- }
-
- /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
- calchandles_fcurve(fcu);
-
- if (G.debug & G_DEBUG) {
- printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- printf("\n\n");
- }
-
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- /* send updates */
- DAG_id_tag_update(&cu->id, 0);
-}
-
-#undef MIN_TIME_DELTA
-
-#define GAP_DFAC 0.01f
-#define WIDTH_CORR_FAC 0.1f
-#define BEZT_HANDLE_FAC 0.3f
-
-/* convert stroke to 3d path */
-
-/* helper */
-static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
-{
- copy_v3_v3(bp->vec, p);
- bp->vec[3] = 1.0f;
-
- /* set settings */
- bp->f1 = SELECT;
- bp->radius = width * rad_fac;
- bp->weight = width;
- CLAMP(bp->weight, 0.0f, 1.0f);
- if (bp->weight < minmax_weights[0]) {
- minmax_weights[0] = bp->weight;
- }
- else if (bp->weight > minmax_weights[1]) {
- minmax_weights[1] = bp->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ return OPERATOR_CANCELLED;
}
}
-static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
+/* Split selected strokes into segments, splitting on selected points */
+static int gp_delete_selected_points(bContext *C)
{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BPoint *bp, *prev_bp = NULL;
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- int i, old_nbp = 0;
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbp = nu->pntsu;
-
- /* If stitch, the first point of this stroke is already present in current nu.
- * Else, we have to add two additional points to make the zero-radius link between strokes.
- */
- BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->pntsv = 1;
- nu->orderu = 2; /* point-to-point! */
- nu->type = CU_NURBS;
- nu->flagu = CU_NURB_ENDPOINT;
- nu->resolu = cu->resolu;
- nu->resolv = cu->resolv;
- nu->knotsu = NULL;
-
- nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- if (curnu && !stitch && old_nbp) {
- float p1[3], p2[3], p[3], next_p[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- BLI_assert(gps->prev != NULL);
-
- prev_bp = NULL;
- if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bp = &nu->bp[old_nbp - 2];
- }
- bp = &nu->bp[old_nbp - 1];
-
- /* First point */
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
- if (prev_bp) {
- interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
-
- old_nbp += 2;
- }
- else if (add_start_point) {
- float p[3], next_p[3];
- float dt = 0.0f;
-
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- bp = &nu->bp[old_nbp];
- /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
- * would not work (it would be *before* gtd->inittime, which is not supported currently).
- */
- gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
-
- old_nbp++;
- }
-
- if (old_nbp) {
- prev_bp = &nu->bp[old_nbp - 1];
- }
-
- /* add points */
- for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
- i < gps->totpoints;
- i++, pt++, bp++)
+ bool changed = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- float p[3];
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
-
- /* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
-
- gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
- width, rad_fac, minmax_weights);
-
- prev_bp = bp;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bp->vec);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
- /* Note bp has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
- }
-
- /* add nurb to curve */
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-
- BKE_nurb_knot_calc_u(nu);
-}
-
-/* convert stroke to 3d bezier */
-
-/* helper */
-static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
- const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
-{
- copy_v3_v3(bezt->vec[0], h1);
- copy_v3_v3(bezt->vec[1], p);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* set settings */
- bezt->h1 = bezt->h2 = HD_FREE;
- bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
- bezt->radius = width * rad_fac;
- bezt->weight = width;
- CLAMP(bezt->weight, 0.0f, 1.0f);
- if (bezt->weight < minmax_weights[0]) {
- minmax_weights[0] = bezt->weight;
- }
- else if (bezt->weight > minmax_weights[1]) {
- minmax_weights[1] = bezt->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
-}
-
-static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
-{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BezTriple *bezt, *prev_bezt = NULL;
- int i, tot, old_nbezt = 0;
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbezt = nu->pntsu;
- /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
- * so no need to add it.
- * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
- */
- BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->resolu = 12;
- nu->resolv = 12;
- nu->type = CU_BEZIER;
- nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- tot = gps->totpoints;
-
- /* get initial coordinates */
- pt = gps->points;
- if (tot) {
- gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
- if (tot > 1) {
- gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
- }
- if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
- }
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- if (curnu && old_nbezt) {
- BLI_assert(gps->prev != NULL);
-
- /* Update last point's second handle */
- if (stitch) {
- bezt = &nu->bezt[old_nbezt - 1];
- interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
- pt++;
- }
-
- /* Create "link points" */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- else {
- float p1[3], p2[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- prev_bezt = NULL;
- if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bezt = &nu->bezt[old_nbezt - 2];
- }
- bezt = &nu->bezt[old_nbezt - 1];
-
- /* First point */
- if (prev_bezt) {
- interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (tot > 1) {
- interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-selected points
+ * which will all end up being in new strokes.
+ * - In the most extreme case (i.e. every other vert is a 1-vert island),
+ * we have at most n / 2 islands
+ * - Once we start having larger islands than that, the number required
+ * becomes much less
+ * 2) Each island gets converted to a new stroke
+ */
+ typedef struct tGPDeleteIsland {
+ int start_idx;
+ int end_idx;
+ } tGPDeleteIsland;
+
+ tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
+ bool in_island = false;
+ int num_islands = 0;
+
+ /* First Pass: Identify start/end of islands */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected - stop accumulating to island */
+ in_island = false;
+ }
+ else {
+ /* unselected - start of a new island? */
+ int idx;
+
+ if (in_island) {
+ /* extend existing island */
+ idx = num_islands - 1;
+ islands[idx].end_idx = i;
+ }
+ else {
+ /* start of new island */
+ in_island = true;
+ num_islands++;
+
+ idx = num_islands - 1;
+ islands[idx].start_idx = islands[idx].end_idx = i;
+ }
+ }
}
- }
- else {
- interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+
+ /* Watch out for special case where No islands = All points selected = Delete Stroke only */
+ if (num_islands) {
+ /* there are islands, so create a series of new strokes, adding them before the "next" stroke */
+ int idx;
+
+ /* deselect old stroke, since it will be used as template for the new strokes */
+ gps->flag &= ~GP_STROKE_SELECT;
+
+ /* create each new stroke... */
+ for (idx = 0; idx < num_islands; idx++) {
+ tGPDeleteIsland *island = &islands[idx];
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+
+ /* compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
+ new_stroke->totpoints = island->end_idx - island->start_idx + 1;
+ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
+
+ /* copy over the relevant points */
+ memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints);
+
+ /* add new stroke to the frame */
+ if (gpsn) {
+ BLI_insertlinkbefore(&gpf->strokes, gpsn, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+ }
}
- }
-
- /* Second handle of last point of previous stroke. */
- interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* First point */
- interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt += 2;
- copy_v3_v3(p3d_prev, p2);
- }
- }
- else if (add_start_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+
+ /* free islands */
+ MEM_freeN(islands);
+
+ /* Delete the old stroke */
+ MEM_freeN(gps->points);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
}
}
- else {
- copy_v3_v3(p, p3d_cur);
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
- bezt = &nu->bezt[old_nbezt];
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt++;
- copy_v3_v3(p3d_prev, p);
}
-
- if (old_nbezt) {
- prev_bezt = &nu->bezt[old_nbezt - 1];
+ CTX_DATA_END;
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
}
-
- /* add points */
- for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
-
- if (i || old_nbezt) {
- interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
- }
-
- if (i < tot - 1) {
- interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
- }
-
- gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
- do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
-
- /* shift coord vects */
- copy_v3_v3(p3d_prev, p3d_cur);
- copy_v3_v3(p3d_cur, p3d_next);
-
- if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
- }
-
- prev_bezt = bezt;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bezt->vec[1]);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
-
- /* Second handle of last point of this stroke. */
- interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
- copy_v3_v3(prev_bezt->vec[2], h2);
-
- /* The end point */
- interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
- /* Note bezt has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
- }
-
- /* must calculate handles or else we crash */
- BKE_nurb_handles_calc(nu);
-
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-}
-
-#undef GAP_DFAC
-#undef WIDTH_CORR_FAC
-#undef BEZT_HANDLE_FAC
-
-static void gp_stroke_finalize_curve_endpoints(Curve *cu)
-{
- /* start */
- Nurb *nu = cu->nurb.first;
- int i = 0;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-
- /* end */
- nu = cu->nurb.last;
- i = nu->pntsu - 1;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-}
-
-static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
-{
- Nurb *nu;
- const float delta = minmax_weights[0];
- float fac;
- int i;
-
- /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
- if (IS_EQF(delta, minmax_weights[1]))
- fac = 1.0f;
- else
- fac = 1.0f / (minmax_weights[1] - delta);
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- bezt->weight = (bezt->weight - delta) * fac;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- for (i = 0; i < nu->pntsu; i++, bp++) {
- bp->weight = (bp->weight - delta) * fac;
- }
- }
- }
-}
-
-static int gp_camera_view_subrect(bContext *C, rctf *subrect)
-{
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (v3d) {
- RegionView3D *rv3d = ar->regiondata;
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- Scene *scene = CTX_data_scene(C);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
- return 1;
- }
- }
-
- return 0;
-}
-
-/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
-static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
- const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
-{
- struct Main *bmain = CTX_data_main(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
- bGPDstroke *gps, *prev_gps = NULL;
- Object *ob;
- Curve *cu;
- Nurb *nu = NULL;
- Base *base_orig = BASACT, *base_new = NULL;
- float minmax_weights[2] = {1.0f, 0.0f};
-
- /* camera framing */
- rctf subrect, *subrect_ptr = NULL;
-
- /* error checking */
- if (ELEM(NULL, gpd, gpl, gpf))
- return;
-
- /* only convert if there are any strokes on this layer's frame to convert */
- if (BLI_listbase_is_empty(&gpf->strokes))
- return;
-
- /* initialize camera framing */
- if (gp_camera_view_subrect(C, &subrect)) {
- subrect_ptr = &subrect;
- }
-
- /* init the curve object (remove rotation and get curve data from it)
- * - must clear transforms set on object, as those skew our results
- */
- ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
- cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
- base_new = BKE_scene_base_add(scene, ob);
-
- cu->flag |= CU_3D;
-
- gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
-
- /* add points to curve */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- const bool add_start_point = (link_strokes && !(prev_gps));
- const bool add_end_point = (link_strokes && !(gps->next));
-
- /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */
- bool stitch = false;
- if (prev_gps) {
- bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
- bGPDspoint *pt2 = &gps->points[0];
-
- if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
- stitch = true;
- }
- }
-
- /* Decide whether we connect this stroke to previous one */
- if (!(stitch || link_strokes)) {
- nu = NULL;
- }
-
- switch (mode) {
- case GP_STROKECONVERT_PATH:
- gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- case GP_STROKECONVERT_CURVE:
- case GP_STROKECONVERT_POLY: /* convert after */
- gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- default:
- BLI_assert(!"invalid mode");
- break;
- }
- prev_gps = gps;
- }
-
- /* If link_strokes, be sure first and last points have a zero weight/size! */
- if (link_strokes) {
- gp_stroke_finalize_curve_endpoints(cu);
- }
-
- /* Update curve's weights, if needed */
- if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
- gp_stroke_norm_curve_weights(cu, minmax_weights);
- }
-
- /* Create the path animation, if needed */
- gp_stroke_path_animation(C, reports, cu, gtd);
-
- if (mode == GP_STROKECONVERT_POLY) {
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- BKE_nurb_type_convert(nu, CU_POLY, false);
- }
+ else {
+ return OPERATOR_CANCELLED;
}
-
- /* set the layer and select */
- base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
- base_new->flag = ob->flag = base_new->flag | SELECT;
}
-/* --- */
-/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
- * op may be NULL.
- */
-static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
+static int gp_delete_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = NULL;
- bGPDstroke *gps = NULL;
- bGPDspoint *pt;
- double base_time, cur_time, prev_time = -1.0;
- int i;
- bool valid = true;
-
- if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
- return false;
-
- do {
- base_time = cur_time = gps->inittime;
- if (cur_time <= prev_time) {
- valid = false;
+ eGP_DeleteMode mode = RNA_enum_get(op->ptr, "type");
+ int result = OPERATOR_CANCELLED;
+
+ switch (mode) {
+ case GP_DELETEOP_STROKES: /* selected strokes */
+ result = gp_delete_selected_strokes(C);
break;
- }
-
- prev_time = cur_time;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- cur_time = base_time + (double)pt->time;
- /* First point of a stroke should have the same time as stroke's inittime,
- * so it's the only case where equality is allowed!
- */
- if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
- valid = false;
- break;
- }
- prev_time = cur_time;
- }
-
- if (!valid) {
+
+ case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
+ result = gp_delete_selected_points(C);
break;
- }
- } while ((gps = gps->next));
- if (op) {
- RNA_boolean_set(op->ptr, "use_timing_data", valid);
- }
- return valid;
-}
-
-/* Check end_frame is always > start frame! */
-static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
-{
- int start_frame = RNA_int_get(ptr, "start_frame");
- int end_frame = RNA_int_get(ptr, "end_frame");
-
- if (end_frame <= start_frame) {
- RNA_int_set(ptr, "end_frame", start_frame + 1);
+ case GP_DELETEOP_FRAME: /* active frame */
+ result = gp_actframe_delete_exec(C, op);
+ break;
}
+
+ return result;
}
-static int gp_convert_poll(bContext *C)
+void GPENCIL_OT_delete(wmOperatorType *ot)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = NULL;
- bGPDframe *gpf = NULL;
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
-
- /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
- * and if we are not in edit mode!
- */
- return ((sa && sa->spacetype == SPACE_VIEW3D) &&
- (gpl = gpencil_layer_getactive(gpd)) &&
- (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
- (gpf->strokes.first) &&
- (scene->obedit == NULL));
-}
-
-static int gp_convert_layer_exec(bContext *C, wmOperator *op)
-{
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- Scene *scene = CTX_data_scene(C);
- const int mode = RNA_enum_get(op->ptr, "type");
- const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
- const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
- const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
- bool valid_timing;
- tGpTimingData gtd;
-
- /* check if there's data to work with */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
- return OPERATOR_CANCELLED;
- }
-
- if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
- BKE_report(op->reports, RPT_WARNING,
- "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
- }
- valid_timing = RNA_property_boolean_get(op->ptr, prop);
-
- gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
- /* Check for illegal timing mode! */
- if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
- gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
- RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
- }
- if (!link_strokes) {
- gtd.mode = GP_STROKECONVERT_TIMING_NONE;
- }
-
- /* grab all relevant settings */
- gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
- gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
- gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
- gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
- gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
- gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
- gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
- gtd.seed = RNA_int_get(op->ptr, "seed");
- gtd.num_points = gtd.cur_point = 0;
- gtd.dists = gtd.times = NULL;
- gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
- gtd.inittime = 0.0;
- gtd.offset_time = 0.0f;
-
- /* perform conversion */
- gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
-
- /* free temp memory */
- if (gtd.dists) {
- MEM_freeN(gtd.dists);
- gtd.dists = NULL;
- }
- if (gtd.times) {
- MEM_freeN(gtd.times);
- gtd.times = NULL;
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- /* done */
- return OPERATOR_FINISHED;
-}
-
-static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
-{
- const char *prop_id = RNA_property_identifier(prop);
- const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
- int timing_mode = RNA_enum_get(ptr, "timing_mode");
- bool realtime = RNA_boolean_get(ptr, "use_realtime");
- float gap_duration = RNA_float_get(ptr, "gap_duration");
- float gap_randomness = RNA_float_get(ptr, "gap_randomness");
- const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
-
- /* Always show those props */
- if (strcmp(prop_id, "type") == 0 ||
- strcmp(prop_id, "use_normalize_weights") == 0 ||
- strcmp(prop_id, "radius_multiplier") == 0 ||
- strcmp(prop_id, "use_link_strokes") == 0)
- {
- return true;
- }
-
- /* Never show this prop */
- if (strcmp(prop_id, "use_timing_data") == 0)
- return false;
-
- if (link_strokes) {
- /* Only show when link_stroke is true */
- if (strcmp(prop_id, "timing_mode") == 0)
- return true;
-
- if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
- /* Only show when link_stroke is true and stroke timing is enabled */
- if (strcmp(prop_id, "frame_range") == 0 ||
- strcmp(prop_id, "start_frame") == 0)
- {
- return true;
- }
-
- /* Only show if we have valid timing data! */
- if (valid_timing && strcmp(prop_id, "use_realtime") == 0)
- return true;
-
- /* Only show if realtime or valid_timing is false! */
- if ((!realtime || !valid_timing) && strcmp(prop_id, "end_frame") == 0)
- return true;
-
- if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* Only show for custom gaps! */
- if (strcmp(prop_id, "gap_duration") == 0)
- return true;
-
- /* Only show randomness for non-null custom gaps! */
- if (strcmp(prop_id, "gap_randomness") == 0 && (gap_duration > 0.0f))
- return true;
-
- /* Only show seed for randomize action! */
- if (strcmp(prop_id, "seed") == 0 && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
- return true;
- }
- }
- }
-
- /* Else, hidden! */
- return false;
+ static EnumPropertyItem prop_gpencil_delete_types[] = {
+ {GP_DELETEOP_POINTS, "POINTS", 0, "Points", "Delete selected points and split strokes into segments"},
+ {GP_DELETEOP_STROKES, "STROKES", 0, "Strokes", "Delete selected strokes"},
+ {GP_DELETEOP_FRAME, "FRAME", 0, "Frame", "Delete active frame"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Delete...";
+ ot->idname = "GPENCIL_OT_delete";
+ ot->description = "Delete selected Grease Pencil strokes, vertices, or frames";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_delete_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data");
}
-static void gp_convert_ui(bContext *C, wmOperator *op)
+static int gp_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
{
- uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- /* Main auto-draw call */
- uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0');
+ return gp_dissolve_selected_points(C);
}
-void GPENCIL_OT_convert(wmOperatorType *ot)
+void GPENCIL_OT_dissolve(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
- ot->name = "Convert Grease Pencil";
- ot->idname = "GPENCIL_OT_convert";
- ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
+ ot->name = "Dissolve";
+ ot->idname = "GPENCIL_OT_dissolve";
+ ot->description = "Delete selected points without splitting strokes";
/* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_convert_layer_exec;
- ot->poll = gp_convert_poll;
- ot->ui = gp_convert_ui;
+ ot->exec = gp_dissolve_exec;
+ ot->poll = gp_stroke_edit_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
-
- RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
- "Normalize weight (set from stroke width)");
- RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
- "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes",
- "Whether to link strokes with zero-radius sections of curves");
-
- prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
- "Timing Mode", "How to use timing data stored in strokes");
- RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
-
- RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
- "The duration of evaluation of the path control curve", 1, 1000);
- RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
- "The start frame of the path control curve", 1, 100000);
- RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
- "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
- prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
- "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
- RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
-
- RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
- "Custom Gap mode: (Average) length of gaps, in frames "
- "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
- "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
- "Custom Gap mode: Random generator seed", 0, 100);
-
- /* Note: Internal use, this one will always be hidden by UI code... */
- prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
- "Whether the converted Grease Pencil layer has valid timing data (internal use)");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 28eb1355caf..290935a06cf 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -31,15 +31,80 @@
#ifndef __GPENCIL_INTERN_H__
#define __GPENCIL_INTERN_H__
-/* internal exports only */
+#include "DNA_vec_types.h"
-/* ***************************************************** */
-/* Operator Defines */
+/* internal exports only */
struct bGPdata;
+struct bGPDstroke;
+struct bGPDspoint;
+
+struct ARegion;
+struct View2D;
struct wmOperatorType;
+
+/* ***************************************************** */
+/* Internal API */
+
+/* Stroke Coordinates API ------------------------------ */
+/* gpencil_utils.c */
+
+typedef struct GP_SpaceConversion {
+ struct bGPdata *gpd;
+ struct bGPDlayer *gpl;
+
+ struct ScrArea *sa;
+ struct ARegion *ar;
+ struct View2D *v2d;
+
+ rctf *subrect; /* for using the camera rect within the 3d view */
+ rctf subrect_data;
+
+ float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
+} GP_SpaceConversion;
+
+
+/**
+ * Check whether a given stroke segment is inside a circular brush
+ *
+ * \param mval The current screen-space coordinates (midpoint) of the brush
+ * \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
+ * \param rad The radius of the brush
+ *
+ * \param x0, y0 The screen-space x and y coordinates of the start of the stroke segment
+ * \param x1, y1 The screen-space x and y coordinates of the end of the stroke segment
+ */
+bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
+ int rad, int x0, int y0, int x1, int y1);
+
+
+/**
+ * Init settings for stroke point space conversions
+ *
+ * \param[out] r_gsc The space conversion settings struct, populated with necessary params
+ */
+void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
+
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * \param[out] r_x The screen-space x-coordinate of the point
+ * \param[out] r_y The screen-space y-coordinate of the point
+ */
+void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
+ int *r_x, int *r_y);
+
+/* Poll Callbacks ------------------------------------ */
+/* gpencil_utils.c */
+
+int gp_add_poll(struct bContext *C);
+int gp_active_layer_poll(struct bContext *C);
+
+/* ***************************************************** */
+/* Operator Defines */
+
/* drawing ---------- */
void GPENCIL_OT_draw(struct wmOperatorType *ot);
@@ -52,12 +117,36 @@ typedef enum eGPencil_PaintModes {
GP_PAINTMODE_DRAW_POLY
} eGPencil_PaintModes;
+/* stroke editing ----- */
+
+void GPENCIL_OT_select(struct wmOperatorType *ot);
+void GPENCIL_OT_select_all(struct wmOperatorType *ot);
+void GPENCIL_OT_select_circle(struct wmOperatorType *ot);
+void GPENCIL_OT_select_border(struct wmOperatorType *ot);
+void GPENCIL_OT_select_lasso(struct wmOperatorType *ot);
+
+void GPENCIL_OT_select_linked(struct wmOperatorType *ot);
+void GPENCIL_OT_select_more(struct wmOperatorType *ot);
+void GPENCIL_OT_select_less(struct wmOperatorType *ot);
+
+void GPENCIL_OT_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_dissolve(struct wmOperatorType *ot);
+void GPENCIL_OT_copy(struct wmOperatorType *ot);
+void GPENCIL_OT_paste(struct wmOperatorType *ot);
+
/* buttons editing --- */
void GPENCIL_OT_data_add(struct wmOperatorType *ot);
void GPENCIL_OT_data_unlink(struct wmOperatorType *ot);
void GPENCIL_OT_layer_add(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
+
+void GPENCIL_OT_hide(struct wmOperatorType *ot);
+void GPENCIL_OT_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
@@ -76,17 +165,17 @@ void gpencil_undo_finish(void);
/* This struct defines a structure used for quick access */
typedef struct bActListElem {
struct bActListElem *next, *prev;
-
+
void *data; /* source data this elem represents */
int type; /* one of the ACTTYPE_* values */
int flag; /* copy of elem's flags for quick access */
int index; /* copy of adrcode where applicable */
-
+
void *key_data; /* motion data - ipo or ipo-curve */
short datatype; /* type of motion data to expect */
-
+
struct bActionGroup *grp; /* action group that owns the channel */
-
+
void *owner; /* will either be an action channel or fake ipo-channel (for keys) */
short ownertype; /* type of owner */
} bActListElem;
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 75ff0895931..ab56565f4ca 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -34,7 +34,9 @@
#include "BLI_sys_types.h"
-#include "BLI_blenlib.h"
+#include "BKE_context.h"
+
+#include "DNA_gpencil_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -42,34 +44,199 @@
#include "RNA_access.h"
#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_transform.h"
#include "gpencil_intern.h"
/* ****************************************** */
-/* Generic Editing Keymap */
+/* Grease Pencil Keymaps */
-void ED_keymap_gpencil(wmKeyConfig *keyconf)
+/* Generic Drawing Keymap */
+static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil", 0, 0);
wmKeyMapItem *kmi;
- /* Draw */
-
+ /* Draw --------------------------------------- */
/* draw */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
-
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
/* draw - straight lines */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT);
-
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
/* draw - poly lines */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY);
-
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
/* erase */
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY);
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* Viewport Tools ------------------------------- */
+
+ /* Enter EditMode */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, DKEY);
+ RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode");
+
+ /* Pie Menu - For standard tools */
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY);
+}
+
+/* ==================== */
+
+/* Poll callback for stroke editing mode */
+static int gp_stroke_editmode_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
+}
+
+/* Stroke Editing Keymap - Only when editmode is enabled */
+static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
+ wmKeyMapItem *kmi;
+
+ /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
+ keymap->poll = gp_stroke_editmode_poll;
+
+ /* ----------------------------------------------- */
+
+ /* Exit EditMode */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode");
+
+ /* Brush Settings */
+ /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys
+ * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain
+ * that the only data being edited is that of the Grease Pencil strokes
+ */
+
+ /* FKEY = Eraser Radius */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
+
+ /* Selection ------------------------------------- */
+ /* select all */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
+
+ /* circle select */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
+ /* border select */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0);
+
+ /* lasso select */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ /* normal select */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "toggle", true);
+
+ /* whole stroke select */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "entire_strokes", true);
+
+ /* select linked */
+ /* NOTE: While LKEY is redundant, not having it breaks the mode illusion too much */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
+
+ /* select more/less */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
+
+
+ /* Editing ----------------------------------------- */
+
+ /* duplicate and move selected points */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
+
+ /* delete */
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", DELKEY, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
+
+ /* copy + paste */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+
+#ifdef __APPLE__
+ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
+#endif
+
+ /* Show/Hide */
+ /* NOTE: These are available only in EditMode now, since they clash with general-purpose hotkeys */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", true);
+
+
+ /* Transform Tools */
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_bend", WKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_tosphere", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_shear", SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "mode", TFM_GPENCIL_SHRINKFATTEN);
+ RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
+
+ /* Proportional Editing */
+ ED_keymap_proportional_cycle(keyconf, keymap);
+ ED_keymap_proportional_editmode(keyconf, keymap, true);
+}
+
+/* ==================== */
+
+void ED_keymap_gpencil(wmKeyConfig *keyconf)
+{
+ ed_keymap_gpencil_general(keyconf);
+ ed_keymap_gpencil_editing(keyconf);
}
/* ****************************************** */
@@ -80,18 +247,55 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_draw);
+ /* Editing (Strokes) ------------ */
+
+ WM_operatortype_append(GPENCIL_OT_select);
+ WM_operatortype_append(GPENCIL_OT_select_all);
+ WM_operatortype_append(GPENCIL_OT_select_circle);
+ WM_operatortype_append(GPENCIL_OT_select_border);
+ WM_operatortype_append(GPENCIL_OT_select_lasso);
+
+ WM_operatortype_append(GPENCIL_OT_select_linked);
+ WM_operatortype_append(GPENCIL_OT_select_more);
+ WM_operatortype_append(GPENCIL_OT_select_less);
+
+ WM_operatortype_append(GPENCIL_OT_duplicate);
+ WM_operatortype_append(GPENCIL_OT_delete);
+ WM_operatortype_append(GPENCIL_OT_dissolve);
+ WM_operatortype_append(GPENCIL_OT_copy);
+ WM_operatortype_append(GPENCIL_OT_paste);
+
/* Editing (Buttons) ------------ */
WM_operatortype_append(GPENCIL_OT_data_add);
WM_operatortype_append(GPENCIL_OT_data_unlink);
WM_operatortype_append(GPENCIL_OT_layer_add);
+ WM_operatortype_append(GPENCIL_OT_layer_remove);
+ WM_operatortype_append(GPENCIL_OT_layer_move);
+ WM_operatortype_append(GPENCIL_OT_layer_duplicate);
+
+ WM_operatortype_append(GPENCIL_OT_hide);
+ WM_operatortype_append(GPENCIL_OT_reveal);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_convert);
-
+
/* Editing (Time) --------------- */
}
+void ED_operatormacros_gpencil(void)
+{
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("GPENCIL_OT_duplicate_move", "Duplicate Strokes",
+ "Make copies of the selected Grease Pencil strokes and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "GPENCIL_OT_duplicate");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true);
+}
+
/* ****************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index afecdd91599..df88da073ca 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -27,6 +27,7 @@
* \ingroup edgpencil
*/
+
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@@ -39,7 +40,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "PIL_time.h"
@@ -47,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "BKE_tracking.h"
#include "DNA_object_types.h"
@@ -86,11 +88,13 @@ typedef struct tGPsdata {
rctf *subrect; /* for using the camera rect within the 3d view */
rctf subrect_data;
+ GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */
+
PointerRNA ownerPtr; /* pointer to owner of gp-datablock */
bGPdata *gpd; /* gp-datablock layer comes from */
bGPDlayer *gpl; /* layer we're working on */
bGPDframe *gpf; /* frame we're working on */
-
+
short status; /* current status of painting */
short paintmode; /* mode for painting */
@@ -110,9 +114,10 @@ typedef struct tGPsdata {
double inittime; /* Used when converting to path */
double curtime; /* Used when converting to path */
double ocurtime; /* Used when converting to path */
-
+
float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space
* to region space */
+ float mat[4][4];
float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
@@ -218,7 +223,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3])
if (p->ownerPtr.type == &RNA_Object) {
Object *ob = (Object *)p->ownerPtr.data;
- /* active Object
+ /* active Object
* - use relative distance of 3D-cursor from object center
*/
sub_v3_v3v3(vec, fp, ob->loc);
@@ -243,13 +248,13 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
if (p->gpd->sbuffer_size == 0)
return true;
- /* check if mouse moved at least certain distance on both axes (best case)
+ /* check if mouse moved at least certain distance on both axes (best case)
* - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
*/
else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
return true;
- /* check if the distance since the last point is significant enough
+ /* check if the distance since the last point is significant enough
* - prevents points being added too densely
* - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
*/
@@ -279,7 +284,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
float rvec[3], dvec[3];
float mval_f[2] = {UNPACK2(mval)};
float zfac;
-
+
/* Current method just converts each point in screen-coordinates to
* 3D-coordinates using the 3D-cursor as reference. In general, this
* works OK, but it could of course be improved.
@@ -291,7 +296,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
gp_get_3d_reference(p, rvec);
zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
-
+
if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
sub_v2_v2v2(mval_f, mval_prj, mval_f);
ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
@@ -327,7 +332,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
{
bGPdata *gpd = p->gpd;
tGPspoint *pt;
-
+
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only - i.e. only store start and end point in buffer */
@@ -337,29 +342,25 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* store settings */
copy_v2_v2_int(&pt->x, mval);
- pt->pressure = pressure;
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
pt->time = (float)(curtime - p->inittime);
/* increment buffer size */
gpd->sbuffer_size++;
}
else {
- /* normally, we just reset the endpoint to the latest value
+ /* just reset the endpoint to the latest value
* - assume that pointers for this are always valid...
*/
pt = ((tGPspoint *)(gpd->sbuffer) + 1);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
- pt->pressure = pressure;
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
pt->time = (float)(curtime - p->inittime);
- /* if this is just the second point we've added, increment the buffer size
- * so that it will be drawn properly...
- * otherwise, just leave it alone, otherwise we get problems
- */
- if (gpd->sbuffer_size != 2)
- gpd->sbuffer_size = 2;
+ /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
+ gpd->sbuffer_size = 2;
}
/* can keep carrying on this way :) */
@@ -393,7 +394,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* store settings */
copy_v2_v2_int(&pt->x, mval);
- pt->pressure = pressure;
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
pt->time = (float)(curtime - p->inittime);
/* if there's stroke for this poly line session add (or replace last) point
@@ -438,7 +439,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
return GP_STROKEADD_NORMAL;
}
-
+
/* return invalid state for now... */
return GP_STROKEADD_INVALID;
}
@@ -458,12 +459,12 @@ static void gp_stroke_smooth(tGPsdata *p)
if ((cmx <= 2) || (gpd->sbuffer == NULL))
return;
- /* Calculate smoothing coordinates using weighted-averages
+ /* Calculate smoothing coordinates using weighted-averages
* WARNING: we do NOT smooth first and last points (to avoid shrinkage)
*/
spt = (tGPspoint *)gpd->sbuffer;
- /* This (tmp_spt) small array stores the last two points' original coordinates,
+ /* This (tmp_spt) small array stores the last two points' original coordinates,
* as we don't want to use already averaged ones! It is used as a cyclic buffer...
*/
tmp_spt[0] = *spt;
@@ -482,7 +483,7 @@ static void gp_stroke_smooth(tGPsdata *p)
}
}
-/* simplify a stroke (in buffer) before storing it
+/* simplify a stroke (in buffer) before storing it
* - applies a reverse Chaikin filter
* - code adapted from etch-a-ton branch (editarmature_sketch.c)
*/
@@ -502,7 +503,7 @@ static void gp_stroke_simplify(tGPsdata *p)
if ((num_points <= 4) || (old_points == NULL))
return;
- /* clear buffer (but don't free mem yet) so that we can write to it
+ /* clear buffer (but don't free mem yet) so that we can write to it
* - firstly set sbuffer to NULL, so a new one is allocated
* - secondly, reset flag after, as it gets cleared auto
*/
@@ -569,7 +570,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
- /* get total number of points to allocate space for
+ /* get total number of points to allocate space for
* - drawing straight-lines only requires the endpoints
*/
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
@@ -625,7 +626,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt++;
}
-
+
if (totelem == 2) {
/* last point if applicable */
ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
@@ -746,7 +747,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
/* free stroke points, then stroke */
MEM_freeN(pt_tmp);
BLI_freelinkN(&gpf->strokes, gps);
-
+
/* nothing left in stroke, so stop */
return 1;
}
@@ -755,7 +756,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
else if (i == gps->totpoints - 2) {
/* allocate new points array, and assign most of the old stroke there */
gps->totpoints--;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->points = MEM_mallocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * gps->totpoints);
/* free temp buffer */
@@ -769,7 +770,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
else if (i == 0) {
/* allocate new points array, and assign most of the old stroke there */
gps->totpoints--;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->points = MEM_mallocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint) * gps->totpoints);
/* We must adjust timings!
@@ -806,7 +807,7 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
BLI_insertlinkafter(&gpf->strokes, gps, gsn);
gsn->totpoints = gps->totpoints - i;
- gsn->points = MEM_callocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points");
+ gsn->points = MEM_mallocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points");
memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint) * gsn->totpoints);
/* We must adjust timings of this new stroke!
@@ -830,8 +831,8 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
/* adjust existing stroke */
gps->totpoints = i;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * i);
+ gps->points = MEM_mallocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * gps->totpoints);
/* free temp buffer */
MEM_freeN(pt_tmp);
@@ -852,8 +853,7 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
}
}
-static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
- const bGPDspoint *pt, const int x, const int y)
+static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
{
if ((p->sa->spacetype == SPACE_VIEW3D) &&
(p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
@@ -861,11 +861,11 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
RegionView3D *rv3d = p->ar->regiondata;
const int mval[2] = {x, y};
float mval_3d[3];
-
+
if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
const float depth_pt = view3d_point_depth(rv3d, &pt->x);
-
+
if (depth_pt > depth_mval) {
return true;
}
@@ -874,53 +874,6 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
return false;
}
-/* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
-static short gp_stroke_eraser_strokeinside(const int mval[2], const int UNUSED(mvalo[2]),
- int rad, int x0, int y0, int x1, int y1)
-{
- /* simple within-radius check for now */
- const float mval_fl[2] = {mval[0], mval[1]};
- const float screen_co_a[2] = {x0, y0};
- const float screen_co_b[2] = {x1, y1};
-
- if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) {
- return true;
- }
-
- /* not inside */
- return false;
-}
-
-static void gp_point_to_xy(ARegion *ar, View2D *v2d, rctf *subrect, bGPDstroke *gps, bGPDspoint *pt,
- int *r_x, int *r_y)
-{
- int xyval[2];
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- *r_x = xyval[0];
- *r_y = xyval[1];
- }
- else {
- *r_x = V2D_IS_CLIPPED;
- *r_y = V2D_IS_CLIPPED;
- }
- }
- else if (gps->flag & GP_STROKE_2DSPACE) {
- UI_view2d_view_to_region_clip(v2d, pt->x, pt->y, r_x, r_y);
- }
- else {
- if (subrect == NULL) { /* normal 3D view */
- *r_x = (int)(pt->x / 100 * ar->winx);
- *r_y = (int)(pt->y / 100 * ar->winy);
- }
- else { /* camera view, use subrect */
- *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- }
-}
-
/* eraser tool - evaluation per stroke */
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
@@ -934,12 +887,12 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
if (gps->totpoints == 0) {
/* just free stroke */
- if (gps->points)
+ if (gps->points)
MEM_freeN(gps->points);
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, gps->points, &x0, &y0);
+ gp_point_to_xy(&p->gsc, gps, gps->points, &x0, &y0);
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -952,7 +905,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
}
}
else {
- /* loop over the points in the stroke, checking for intersections
+ /* loop over the points in the stroke, checking for intersections
* - an intersection will require the stroke to be split
*/
for (i = 0; (i + 1) < gps->totpoints; i++) {
@@ -960,8 +913,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
- gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, pt1, &x0, &y0);
- gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, pt2, &x1, &y1);
+ gp_point_to_xy(&p->gsc, gps, pt1, &x0, &y0);
+ gp_point_to_xy(&p->gsc, gps, pt2, &x1, &y1);
/* check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
@@ -971,7 +924,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
+ if (gp_stroke_inside_circle(mval, mvalo, rad, x0, y0, x1, y1)) {
if ((gp_stroke_eraser_is_occluded(p, pt1, x0, y0) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, x1, y1) == false))
{
@@ -997,16 +950,16 @@ static void gp_stroke_doeraser(tGPsdata *p)
rect.ymin = p->mval[1] - p->radius;
rect.xmax = p->mval[0] + p->radius;
rect.ymax = p->mval[1] + p->radius;
-
+
if (p->sa->spacetype == SPACE_VIEW3D) {
if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
View3D *v3d = p->sa->spacedata.first;
-
+
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->ar, v3d, 0);
}
}
-
+
/* loop over strokes, checking segments for intersections */
for (gps = gpf->strokes.first; gps; gps = gpn) {
gpn = gps->next;
@@ -1037,13 +990,13 @@ static void gp_session_validatebuffer(tGPsdata *p)
/* reset flags */
gpd->sbuffer_sflag = 0;
-
+
/* reset inittime */
p->inittime = 0.0;
}
/* (re)init new painting data */
-static int gp_session_initdata(bContext *C, tGPsdata *p)
+static bool gp_session_initdata(bContext *C, tGPsdata *p)
{
bGPdata **gpd_ptr = NULL;
ScrArea *curarea = CTX_wm_area(C);
@@ -1060,8 +1013,9 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
/* pass on current scene and window */
p->scene = CTX_data_scene(C);
p->win = CTX_wm_window(C);
-
+
unit_m4(p->imat);
+ unit_m4(p->mat);
switch (curarea->spacetype) {
/* supported views first */
@@ -1070,9 +1024,10 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
/* View3D *v3d = curarea->spacedata.first; */
/* RegionView3D *rv3d = ar->regiondata; */
- /* set current area
+ /* set current area
* - must verify that region data is 3D-view (and not something else)
*/
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
p->sa = curarea;
p->ar = ar;
@@ -1125,7 +1080,13 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
case SPACE_CLIP:
{
SpaceClip *sc = curarea->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip == NULL) {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+
/* set the current area */
p->sa = curarea;
p->ar = ar;
@@ -1140,14 +1101,22 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
p->custom_color[3] = 0.9f;
if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
int framenr = ED_space_clip_get_clip_frame_number(sc);
MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- p->imat[3][0] -= marker->pos[0];
- p->imat[3][1] -= marker->pos[1];
+ MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
+
+ if (marker) {
+ p->imat[3][0] -= marker->pos[0];
+ p->imat[3][1] -= marker->pos[1];
+ }
+ else {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
}
+
+ invert_m4_m4(p->mat, p->imat);
+ copy_m4_m4(p->gsc.mat, p->mat);
break;
}
/* unsupported views */
@@ -1192,10 +1161,10 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
static tGPsdata *gp_session_initpaint(bContext *C)
{
tGPsdata *p = NULL;
-
+
/* create new context data */
p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
-
+
gp_session_initdata(C, p);
/* return context data for running paint operator */
@@ -1226,7 +1195,7 @@ static void gp_session_cleanup(tGPsdata *p)
/* init new stroke */
static void gp_paint_initstroke(tGPsdata *p, short paintmode)
-{
+{
/* get active layer (or add a new one if non-existent) */
p->gpl = gpencil_layer_getactive(p->gpd);
if (p->gpl == NULL) {
@@ -1241,7 +1210,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
printf("Error: Cannot paint on locked layer\n");
return;
}
-
+
/* get active frame (add a new one if not matching frame) */
p->gpf = gpencil_layer_getframe(p->gpl, p->scene->r.cfra, 1);
if (p->gpf == NULL) {
@@ -1257,7 +1226,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
p->paintmode = paintmode;
if (p->paintmode == GP_PAINTMODE_ERASER) {
p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
-
+
/* check if we should respect depth while erasing */
if (p->sa->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
@@ -1265,12 +1234,23 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
}
}
}
-
+ else {
+ /* disable eraser flags - so that we can switch modes during a session */
+ p->gpd->sbuffer_sflag &= ~GP_STROKE_ERASER;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+
/* set 'initial run' flag, which is only used to denote when a new stroke is starting */
p->flags |= GP_PAINTFLAG_FIRSTRUN;
-
+
/* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) {
if (p->sa->spacetype == SPACE_VIEW3D) {
View3D *v3d = p->sa->spacedata.first;
@@ -1283,7 +1263,21 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
}
}
}
-
+
+ /* init stroke point space-conversion settings... */
+ p->gsc.gpd = p->gpd;
+ p->gsc.gpl = p->gpl;
+
+ p->gsc.sa = p->sa;
+ p->gsc.ar = p->ar;
+ p->gsc.v2d = p->v2d;
+
+ p->gsc.subrect_data = p->subrect_data;
+ p->gsc.subrect = p->subrect;
+
+ copy_m4_m4(p->gsc.mat, p->mat);
+
+
/* check if points will need to be made in view-aligned space */
if (p->gpd->flag & GP_DATA_VIEWALIGN) {
switch (p->sa->spacetype) {
@@ -1333,7 +1327,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
static void gp_paint_strokeend(tGPsdata *p)
{
- /* for surface sketching, need to set the right OpenGL context stuff so that
+ /* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
@@ -1388,13 +1382,18 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
glTranslatef((float)x, (float)y, 0.0f);
- glColor4ub(255, 255, 255, 128);
-
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
+ glColor4ub(255, 100, 100, 20);
+ glutil_draw_filled_arc(0.0, M_PI * 2.0, p->radius, 40);
+
+ setlinestyle(6);
+
+ glColor4ub(255, 100, 100, 200);
glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40);
+ setlinestyle(0);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -1410,9 +1409,9 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
p->erasercursor = NULL;
}
- else if (enable) {
+ else if (enable && !p->erasercursor) {
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
NULL, /* XXX */
gpencil_draw_eraser, p);
}
@@ -1437,12 +1436,14 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
gpencil_draw_toggle_eraser_cursor(C, p, false);
-
- /* if successful, store the new eraser size to be used again next time */
- if (p->status == GP_STATUS_DONE)
- U.gp_eraser = p->radius;
}
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ U.gp_eraser = p->radius;
+
/* cleanup */
gp_paint_cleanup(p);
gp_session_cleanup(p);
@@ -1493,6 +1494,15 @@ static int gpencil_draw_init(bContext *C, wmOperator *op)
/* ------------------------------- */
+/* ensure that the correct cursor icon is set */
+static void gpencil_draw_cursor_set(tGPsdata *p)
+{
+ if (p->paintmode == GP_PAINTMODE_ERASER)
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ else
+ WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+}
+
/* update UI indicators of status, including cursor and header prints */
static void gpencil_draw_status_indicators(tGPsdata *p)
{
@@ -1519,13 +1529,13 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
"ESC/Enter to end"));
break;
-
+
default: /* unhandled future cases */
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end"));
break;
}
break;
-
+
case GP_STATUS_ERROR:
case GP_STATUS_DONE:
/* clear status string */
@@ -1608,7 +1618,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
/* handle pressure sensitivity (which is supplied by tablets) */
if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
+ const wmTabletData *wmtab = event->tablet_data;
tablet = (wmtab->Active != EVT_TABLET_NONE);
p->pressure = wmtab->Pressure;
@@ -1619,15 +1629,6 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
else
p->pressure = 1.0f;
- /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
-
- mousef[0] = p->mval[0];
- mousef[1] = p->mval[1];
- RNA_float_set_array(&itemptr, "mouse", mousef);
- RNA_float_set(&itemptr, "pressure", p->pressure);
- RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN));
-
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
@@ -1644,6 +1645,15 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
return;
}
+ /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ mousef[0] = p->mval[0];
+ mousef[1] = p->mval[1];
+ RNA_float_set_array(&itemptr, "mouse", mousef);
+ RNA_float_set(&itemptr, "pressure", p->pressure);
+ RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
+
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
@@ -1714,7 +1724,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
gpencil_draw_apply(op, p);
}
RNA_END;
-
+
/* printf("\tGP - done\n"); */
/* cleanup */
@@ -1733,14 +1743,13 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = NULL;
- wmWindow *win = CTX_wm_window(C);
if (G.debug & G_DEBUG)
printf("GPencil - Starting Drawing\n");
/* try to initialize context data needed while drawing */
if (!gpencil_draw_init(C, op)) {
- if (op->customdata)
+ if (op->customdata)
MEM_freeN(op->customdata);
if (G.debug & G_DEBUG)
printf("\tGP - no valid data\n");
@@ -1748,28 +1757,25 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
else
p = op->customdata;
-
+
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
-
+
/* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
-
+
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
- /* set cursor */
- if (p->paintmode == GP_PAINTMODE_ERASER)
- WM_cursor_modal_set(win, BC_CROSSCURSOR); /* XXX need a better cursor */
- else
- WM_cursor_modal_set(win, BC_PAINTBRUSHCURSOR);
-
- /* special hack: if there was an initial event, then we were invoked via a hotkey, and
- * painting should start immediately. Otherwise, this was called from a toolbar, in which
- * case we should wait for the mouse to be clicked.
+ /* set cursor
+ * NOTE: This may change later (i.e. intentionally via brush toggle,
+ * or unintentionally if the user scrolls outside the area)...
*/
- if (event->val == KM_PRESS) {
+ gpencil_draw_cursor_set(p);
+
+ /* only start drawing immediately if we're allowed to do so... */
+ if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
/* hotkey invoked - start drawing */
/* printf("\tGP - set first spot\n"); */
p->status = GP_STATUS_PAINTING;
@@ -1780,6 +1786,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
/* toolbar invoked - don't start drawing yet... */
/* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@@ -1817,8 +1824,10 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
if (gp_session_initdata(C, p))
gp_paint_initstroke(p, p->paintmode);
- if (p->status != GP_STATUS_ERROR)
+ if (p->status != GP_STATUS_ERROR) {
p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
return op->customdata;
}
@@ -1826,15 +1835,16 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
static void gpencil_stroke_end(wmOperator *op)
{
tGPsdata *p = op->customdata;
-
+
gp_paint_cleanup(p);
-
+
gpencil_undo_push(p->gpd);
-
+
gp_session_cleanup(p);
-
+
p->status = GP_STATUS_IDLING;
-
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
p->gpd = NULL;
p->gpl = NULL;
p->gpf = NULL;
@@ -1858,11 +1868,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* better in tools that immediately apply
* in 3D space.
*/
+
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
/* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
if (ISKEYBOARD(event->type)) {
- if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
- /* allow some keys - for frame changing: [#33412] */
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
+ /* allow some keys:
+ * - for frame changing [#33412]
+ * - for undo (during sketching sessions)
+ */
}
else {
estate = OPERATOR_RUNNING_MODAL;
@@ -1871,7 +1889,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
//printf("\tGP - handle modal event...\n");
- /* exit painting mode (and/or end current stroke)
+ /* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
@@ -1881,17 +1899,18 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
estate = OPERATOR_FINISHED;
}
- /* toggle painting mode upon mouse-button movement
+ /* toggle painting mode upon mouse-button movement
* - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
+ * also making sure we have a valid event value, to not exit too early
*/
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE)) {
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (event->val != KM_NOTHING)) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
int sketch = 0;
- /* basically, this should be mouse-button up = end stroke
+ /* basically, this should be mouse-button up = end stroke
* BUT what happens next depends on whether we 'painting sessions' is enabled
*/
sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene);
@@ -1903,6 +1922,27 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* printf("\t\tGP - end stroke only\n"); */
gpencil_stroke_end(op);
+ /* If eraser mode is on, turn it off after the stroke finishes
+ * NOTE: This just makes it nicer to work with drawing sessions
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* if the original mode was *still* eraser,
+ * we'll let it say for now, since this gives
+ * users an opportunity to have visual feedback
+ * when adjusting eraser size
+ */
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ /* turn off cursor...
+ * NOTE: this should be enough for now
+ * Just hiding this makes it seem like
+ * you can paint again...
+ */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+ }
+
/* we've just entered idling state, so this event was processed (but no others yet) */
estate = OPERATOR_RUNNING_MODAL;
@@ -1916,15 +1956,88 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event->val == KM_PRESS) {
- /* not painting, so start stroke (this should be mouse-button down) */
- p = gpencil_stroke_begin(C, op);
+ bool in_bounds = false;
- if (p->status == GP_STATUS_ERROR) {
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
+ */
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region, p->ar, event->x, event->y,
+ p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ }
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
+ }
+
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+ else if (event->type == RIGHTMOUSE) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else if (p->status != GP_STATUS_ERROR) {
+ /* User clicked outside bounds of window while idling, so exit paintmode
+ * NOTE: Don't eter this case if an error occurred while finding the
+ * region (as above)
+ */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
}
}
else {
p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
}
@@ -1960,12 +2073,12 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
case PADPLUSKEY:
p->radius += 5;
break;
-
+
case WHEELUPMOUSE: /* smaller */
case PADMINUS:
p->radius -= 5;
- if (p->radius < 0)
+ if (p->radius < 0)
p->radius = 0;
break;
}
@@ -1976,7 +2089,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* event handled, so just tag as running modal */
estate = OPERATOR_RUNNING_MODAL;
}
- /* there shouldn't be any other events, but just in case there are, let's swallow them
+ /* there shouldn't be any other events, but just in case there are, let's swallow them
* (i.e. to prevent problems with undo)
*/
else {
@@ -1988,9 +2101,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
if (0 == gpencil_area_exists(C, p->sa))
estate = OPERATOR_CANCELLED;
- else
+ else {
/* update status indicators - cursor, header, etc. */
gpencil_draw_status_indicators(p);
+ gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
+ }
/* process last operations before exiting */
switch (estate) {
@@ -1999,7 +2114,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
gpencil_draw_exit(C, op);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
break;
-
+
case OPERATOR_CANCELLED:
gpencil_draw_exit(C, op);
break;
@@ -2046,6 +2161,8 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
/* settings for drawing */
ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
-
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+
+ /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */
+ RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
new file mode 100644
index 00000000000..0dd91019a8c
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -0,0 +1,930 @@
+/*
+ * ***** 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
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/gpencil_select.c
+ * \ingroup edgpencil
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_lasso.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_report.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+
+#include "gpencil_intern.h"
+
+/* ********************************************** */
+/* Polling callbacks */
+
+static int gpencil_select_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ /* only if there's an active layer with an active frame */
+ return (gpl && gpl->actframe);
+}
+
+/* ********************************************** */
+/* Select All Operator */
+
+static int gpencil_select_all_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* for "toggle", test for existing selected strokes */
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ action = SEL_DESELECT;
+ break; // XXX: this only gets out of the inner loop...
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* if deselecting, we need to deselect strokes across all frames
+ * - Currently, an exception is only given for deselection
+ * Selecting and toggling should only affect what's visible,
+ * while deselecting helps clean up unintended/forgotten
+ * stuff on other frames
+ */
+ if (action == SEL_DESELECT) {
+ /* deselect strokes across editable layers
+ * NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
+ * nothing should be able to touch it
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf;
+
+ /* deselect all strokes on all frames */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ bGPDstroke *gps;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ /* only edit strokes that are valid in this view... */
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ else {
+ /* select or deselect all strokes */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+ bool selected = false;
+
+ /* Change selection status of all points, then make the stroke match */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ switch (action) {
+ case SEL_SELECT:
+ pt->flag |= GP_SPOINT_SELECT;
+ break;
+ //case SEL_DESELECT:
+ // pt->flag &= ~GP_SPOINT_SELECT;
+ // break;
+ case SEL_INVERT:
+ pt->flag ^= GP_SPOINT_SELECT;
+ break;
+ }
+
+ if (pt->flag & GP_SPOINT_SELECT)
+ selected = true;
+ }
+
+ /* Change status of stroke */
+ if (selected)
+ gps->flag |= GP_STROKE_SELECT;
+ else
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All Strokes";
+ ot->idname = "GPENCIL_OT_select_all";
+ ot->description = "Change selection of all Grease Pencil strokes currently visible";
+
+ /* callbacks */
+ ot->exec = gpencil_select_all_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/* ********************************************** */
+/* Select Linked */
+
+static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* select all points in selected strokes */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->idname = "GPENCIL_OT_select_linked";
+ ot->description = "Select all points in same strokes as already selected points";
+
+ /* callbacks */
+ ot->exec = gpencil_select_linked_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Select More */
+
+static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ bool prev_sel;
+
+ /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)...
+ * - This pass covers the "after" edges of selection islands
+ */
+ prev_sel = false;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected point - just set flag for next point */
+ prev_sel = true;
+ }
+ else {
+ /* unselected point - expand selection if previous was selected... */
+ if (prev_sel) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ prev_sel = false;
+ }
+ }
+
+ /* Second Pass: Go in reverse order, doing the same as before (except in opposite order)
+ * - This pass covers the "before" edges of selection islands
+ */
+ prev_sel = false;
+ for (pt -= 1; i > 0; i--, pt--) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ prev_sel = true;
+ }
+ else {
+ /* unselected point - expand selection if previous was selected... */
+ if (prev_sel) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ prev_sel = false;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select More";
+ ot->idname = "GPENCIL_OT_select_more";
+ ot->description = "Grow sets of selected Grease Pencil points";
+
+ /* callbacks */
+ ot->exec = gpencil_select_more_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Select Less */
+
+static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ bool prev_sel;
+
+ /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)...
+ * - This pass covers the "after" edges of selection islands
+ */
+ prev_sel = false;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* shrink if previous wasn't selected */
+ if (prev_sel == false) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ prev_sel = true;
+ }
+ else {
+ /* mark previous as being unselected - and hence, is trigger for shrinking */
+ prev_sel = false;
+ }
+ }
+
+ /* Second Pass: Go in reverse order, doing the same as before (except in opposite order)
+ * - This pass covers the "before" edges of selection islands
+ */
+ prev_sel = false;
+ for (pt -= 1; i > 0; i--, pt--) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* shrink if previous wasn't selected */
+ if (prev_sel == false) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ prev_sel = true;
+ }
+ else {
+ /* mark previous as being unselected - and hence, is trigger for shrinking */
+ prev_sel = false;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->idname = "GPENCIL_OT_select_less";
+ ot->description = "Shrink sets of selected Grease Pencil points";
+
+ /* callbacks */
+ ot->exec = gpencil_select_less_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Circle Select Operator */
+
+/* Helper to check if a given stroke is within the area */
+/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
+ * It would be great to de-duplicate the logic here sometime, but that can wait...
+ */
+static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
+ const int mx, const int my, const int radius,
+ const bool select, rcti *rect)
+{
+ bGPDspoint *pt1, *pt2;
+ int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
+ int i;
+ bool changed = false;
+
+ if (gps->totpoints == 1) {
+ gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
+ /* only check if point is inside */
+ if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
+ /* change selection */
+ if (select) {
+ gps->points->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ else {
+ gps->points->flag &= ~GP_SPOINT_SELECT;
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+
+ return true;
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
+ gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
+
+ /* check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
+ ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1)))
+ {
+ int mval[2] = {mx, my};
+ int mvalo[2] = {mx, my}; /* dummy - this isn't used... */
+
+ /* check if point segment of stroke had anything to do with
+ * eraser region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) {
+ /* change selection of stroke, and then of both points
+ * (as the last point otherwise wouldn't get selected
+ * as we only do n-1 loops through)
+ */
+ if (select) {
+ pt1->flag |= GP_SPOINT_SELECT;
+ pt2->flag |= GP_SPOINT_SELECT;
+
+ changed = true;
+ }
+ else {
+ pt1->flag &= ~GP_SPOINT_SELECT;
+ pt2->flag &= ~GP_SPOINT_SELECT;
+
+ changed = true;
+ }
+ }
+ }
+ }
+
+ /* Ensure that stroke selection is in sync with its points */
+ gpencil_stroke_sync_selection(gps);
+ }
+
+ return changed;
+}
+
+
+static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ const int mx = RNA_int_get(op->ptr, "x");
+ const int my = RNA_int_get(op->ptr, "y");
+ const int radius = RNA_int_get(op->ptr, "radius");
+
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const bool select = (gesture_mode == GESTURE_MODAL_SELECT);
+
+ GP_SpaceConversion gsc = {NULL};
+ rcti rect = {0}; /* for bounding rect around circle (for quicky intersection testing) */
+
+ bool changed = false;
+
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+
+ /* rect is rectangle of selection circle */
+ rect.xmin = mx - radius;
+ rect.ymin = my - radius;
+ rect.xmax = mx + radius;
+ rect.ymax = my + radius;
+
+
+ /* find visible strokes, and select if hit */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ changed |= gp_stroke_do_circle_sel(gps, &gsc, mx, my, radius, select, &rect);
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_circle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Circle Select";
+ ot->description = "Select Grease Pencil strokes using brush selection";
+ ot->idname = "GPENCIL_OT_select_circle";
+
+ /* callbacks */
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = gpencil_circle_select_exec;
+ ot->poll = gpencil_select_poll;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
+}
+
+/* ********************************************** */
+/* Box Selection */
+
+static int gpencil_border_select_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const bool select = (gesture_mode == GESTURE_MODAL_SELECT);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ GP_SpaceConversion gsc = {NULL};
+ rcti rect = {0};
+
+ bool changed = false;
+
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+
+ /* deselect all strokes first? */
+ if (select && !extend) {
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+ }
+
+ /* get settings from operator */
+ WM_operator_properties_border_to_rcti(op, &rect);
+
+ /* select/deselect points */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ int x0, y0;
+
+ /* convert point coords to screenspace */
+ gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
+
+ /* test if in selection rect */
+ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
+ if (select) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ changed = true;
+ }
+ }
+
+ /* Ensure that stroke selection is in sync with its points */
+ gpencil_stroke_sync_selection(gps);
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Border Select";
+ ot->description = "Select Grease Pencil strokes within a rectangular region";
+ ot->idname = "GPENCIL_OT_select_border";
+
+ /* callbacks */
+ ot->invoke = WM_border_select_invoke;
+ ot->exec = gpencil_border_select_exec;
+ ot->modal = WM_border_select_modal;
+ ot->cancel = WM_border_select_cancel;
+
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* rna */
+ WM_operator_properties_gesture_border(ot, true);
+}
+
+/* ********************************************** */
+/* Lasso */
+
+static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
+{
+ GP_SpaceConversion gsc = {NULL};
+ rcti rect = {0};
+
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool select = !RNA_boolean_get(op->ptr, "deselect");
+
+ int mcords_tot;
+ const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+
+ bool changed = false;
+
+ /* sanity check */
+ if (mcords == NULL)
+ return OPERATOR_PASS_THROUGH;
+
+ /* compute boundbox of lasso (for faster testing later) */
+ BLI_lasso_boundbox(&rect, mcords, mcords_tot);
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* deselect all strokes first? */
+ if (select && !extend) {
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ CTX_DATA_END;
+ }
+
+ /* select/deselect points */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ int x0, y0;
+
+ /* convert point coords to screenspace */
+ gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
+
+ /* test if in lasso boundbox + within the lasso noose */
+ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) &&
+ BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
+ {
+ if (select) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ changed = true;
+ }
+ }
+
+ /* Ensure that stroke selection is in sync with its points */
+ gpencil_stroke_sync_selection(gps);
+ }
+ CTX_DATA_END;
+
+ /* cleanup */
+ MEM_freeN((void *)mcords);
+
+ /* updates */
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_lasso(wmOperatorType *ot)
+{
+ ot->name = "Lasso Select Strokes";
+ ot->description = "Select Grease Pencil strokes using lasso selection";
+ ot->idname = "GPENCIL_OT_select_lasso";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = gpencil_lasso_select_exec;
+ ot->poll = gpencil_select_poll;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* ********************************************** */
+/* Mouse Click to Select */
+
+static int gpencil_select_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
+ const float radius = 0.75f * U.widget_unit;
+ const int radius_squared = (int)(radius * radius);
+
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ bool deselect = RNA_boolean_get(op->ptr, "deselect");
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool whole = RNA_boolean_get(op->ptr, "entire_strokes");
+
+ int mval[2] = {0};
+
+ GP_SpaceConversion gsc = {NULL};
+
+ bGPDstroke *hit_stroke = NULL;
+ bGPDspoint *hit_point = NULL;
+ int hit_distance = radius_squared;
+
+ /* sanity checks */
+ if (sa == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* get mouse location */
+ RNA_int_get_array(op->ptr, "location", mval);
+
+ /* First Pass: Find stroke point which gets hit */
+ /* XXX: maybe we should go from the top of the stack down instead... */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ /* firstly, check for hit-point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ int xy[2];
+
+ gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
+
+ /* do boundbox check first */
+ if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
+ const int pt_distance = len_manhattan_v2v2_int(mval, xy);
+
+ /* check if point is inside */
+ if (pt_distance <= radius_squared) {
+ /* only use this point if it is a better match than the current hit - T44685 */
+ if (pt_distance < hit_distance) {
+ hit_stroke = gps;
+ hit_point = pt;
+ hit_distance = pt_distance;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* Abort if nothing hit... */
+ if (ELEM(NULL, hit_stroke, hit_point)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* adjust selection behaviour - for toggle option */
+ if (toggle) {
+ deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0;
+ }
+
+ /* If not extending selection, deselect everything else */
+ if (extend == false) {
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ /* deselect stroke and its points if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* deselect points */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ /* deselect stroke itself too */
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* Perform selection operations... */
+ if (whole) {
+ bGPDspoint *pt;
+ int i;
+
+ /* entire stroke's points */
+ for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
+ if (deselect == false)
+ pt->flag |= GP_SPOINT_SELECT;
+ else
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ /* stroke too... */
+ if (deselect == false)
+ hit_stroke->flag |= GP_STROKE_SELECT;
+ else
+ hit_stroke->flag &= ~GP_STROKE_SELECT;
+ }
+ else {
+ /* just the point (and the stroke) */
+ if (deselect == false) {
+ /* we're adding selection, so selection must be true */
+ hit_point->flag |= GP_SPOINT_SELECT;
+ hit_stroke->flag |= GP_STROKE_SELECT;
+ }
+ else {
+ /* deselect point */
+ hit_point->flag &= ~GP_SPOINT_SELECT;
+
+ /* ensure that stroke is selected correctly */
+ gpencil_stroke_sync_selection(hit_stroke);
+ }
+ }
+
+ /* updates */
+ if (hit_point != NULL) {
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ return gpencil_select_exec(C, op);
+}
+
+void GPENCIL_OT_select(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select";
+ ot->description = "Select Grease Pencil strokes and/or stroke points";
+ ot->idname = "GPENCIL_OT_select";
+
+ /* callbacks */
+ ot->invoke = gpencil_select_invoke;
+ ot->exec = gpencil_select_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_mouse_select(ot);
+
+ prop = RNA_def_boolean(ot->srna, "entire_strokes", false, "Entire Strokes", "Select entire strokes instead of just the nearest stroke vertex");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+/* ********************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index ff92d69f39d..34e640a4b7b 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -29,6 +29,7 @@
* \ingroup edgpencil
*/
+
#include <stdlib.h>
#include <string.h>
@@ -53,7 +54,7 @@
typedef struct bGPundonode {
struct bGPundonode *next, *prev;
-
+
char name[BKE_UNDO_STR_MAX];
struct bGPdata *gpd;
} bGPundonode;
@@ -69,13 +70,13 @@ int ED_gpencil_session_active(void)
int ED_undo_gpencil_step(bContext *C, int step, const char *name)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
-
+
gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+
if (step == 1) { /* undo */
//printf("\t\tGP - undo step\n");
if (cur_node->prev) {
- if (!name || strcmp(cur_node->name, name) == 0) {
+ if (!name || STREQ(cur_node->name, name)) {
cur_node = cur_node->prev;
new_gpd = cur_node->gpd;
}
@@ -84,24 +85,24 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
else if (step == -1) {
//printf("\t\tGP - redo step\n");
if (cur_node->next) {
- if (!name || strcmp(cur_node->name, name) == 0) {
+ if (!name || STREQ(cur_node->name, name)) {
cur_node = cur_node->next;
new_gpd = cur_node->gpd;
}
}
}
-
+
if (new_gpd) {
if (gpd_ptr) {
if (*gpd_ptr) {
bGPdata *gpd = *gpd_ptr;
bGPDlayer *gpl, *gpld;
-
+
free_gpencil_layers(&gpd->layers);
-
+
/* copy layers */
BLI_listbase_clear(&gpd->layers);
-
+
for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) {
/* make a copy of source layer and its data */
gpld = gpencil_layer_duplicate(gpl);
@@ -110,9 +111,9 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
}
}
}
-
+
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -124,46 +125,56 @@ void gpencil_undo_init(bGPdata *gpd)
void gpencil_undo_push(bGPdata *gpd)
{
bGPundonode *undo_node;
-
+
//printf("\t\tGP - undo push\n");
-
+
if (cur_node) {
/* remove all un-done nodes from stack */
undo_node = cur_node->next;
-
+
while (undo_node) {
bGPundonode *next_node = undo_node->next;
-
+
+ /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
+ * or else the real copy will segfault when accessed
+ */
+ undo_node->gpd->adt = NULL;
+
BKE_gpencil_free(undo_node->gpd);
MEM_freeN(undo_node->gpd);
-
+
BLI_freelinkN(&undo_nodes, undo_node);
-
+
undo_node = next_node;
}
}
-
+
/* create new undo node */
undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
- undo_node->gpd = gpencil_data_duplicate(gpd);
-
+ undo_node->gpd = gpencil_data_duplicate(gpd, true);
+
cur_node = undo_node;
-
+
BLI_addtail(&undo_nodes, undo_node);
}
void gpencil_undo_finish(void)
{
bGPundonode *undo_node = undo_nodes.first;
-
+
while (undo_node) {
+ /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
+ * or else the real copy will segfault when accessed
+ */
+ undo_node->gpd->adt = NULL;
+
BKE_gpencil_free(undo_node->gpd);
MEM_freeN(undo_node->gpd);
-
+
undo_node = undo_node->next;
}
-
+
BLI_freelistN(&undo_nodes);
-
+
cur_node = NULL;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
new file mode 100644
index 00000000000..0d7aac7f48f
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -0,0 +1,375 @@
+/*
+ * ***** 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
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/gpencil_utils.c
+ * \ingroup edgpencil
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_tracking.h"
+
+#include "WM_api.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_clip.h"
+#include "ED_view3d.h"
+
+#include "gpencil_intern.h"
+
+/* ******************************************************** */
+/* Context Wrangling... */
+
+/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
+bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
+{
+ /* if there's an active area, check if the particular editor may
+ * have defined any special Grease Pencil context for editing...
+ */
+ if (sa) {
+ SpaceLink *sl = sa->spacedata.first;
+
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D: /* 3D-View */
+ case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
+ case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
+ {
+ BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
+ GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
+
+ if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
+ /* legacy behaviour for usage with old addons requiring object-linked to objects */
+
+ /* just in case no active/selected object... */
+ if (ob && (ob->flag & SELECT)) {
+ /* for now, as long as there's an object, default to using that in 3D-View */
+ if (ptr) RNA_id_pointer_create(&ob->id, ptr);
+ return &ob->gpd;
+ }
+ /* else: defaults to scene... */
+ }
+ else {
+ if (ptr) RNA_id_pointer_create(&scene->id, ptr);
+ return &scene->gpd;
+ }
+ break;
+ }
+ case SPACE_NODE: /* Nodes Editor */
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ /* return the GP data for the active node block/node */
+ if (snode && snode->nodetree) {
+ /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
+ if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
+ return &snode->nodetree->gpd;
+ }
+
+ /* even when there is no node-tree, don't allow this to flow to scene */
+ return NULL;
+ }
+ case SPACE_SEQ: /* Sequencer */
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* for now, Grease Pencil data is associated with the space (actually preview region only) */
+ /* XXX our convention for everything else is to link to data though... */
+ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
+ return &sseq->gpd;
+ }
+ case SPACE_IMAGE: /* Image/UV Editor */
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ /* for now, Grease Pencil data is associated with the space... */
+ /* XXX our convention for everything else is to link to data though... */
+ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
+ return &sima->gpd;
+ }
+ case SPACE_CLIP: /* Nodes Editor */
+ {
+ SpaceClip *sc = (SpaceClip *)sl;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip) {
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+
+ if (!track)
+ return NULL;
+
+ if (ptr)
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
+
+ return &track->gpd;
+ }
+ else {
+ if (ptr)
+ RNA_id_pointer_create(&clip->id, ptr);
+
+ return &clip->gpd;
+ }
+ }
+ break;
+ }
+ default: /* unsupported space */
+ return NULL;
+ }
+ }
+
+ /* just fall back on the scene's GP data */
+ if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
+ return (scene) ? &scene->gpd : NULL;
+}
+
+/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
+bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+{
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
+
+ return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
+}
+
+/* -------------------------------------------------------- */
+
+/* Get the active Grease Pencil datablock, when context is not available */
+bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
+}
+
+/* Get the active Grease Pencil datablock */
+bGPdata *ED_gpencil_data_get_active(const bContext *C)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
+}
+
+/* -------------------------------------------------------- */
+
+// XXX: this should be removed... We really shouldn't duplicate logic like this!
+bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
+{
+ Base *base = scene->basact;
+ bGPdata *gpd = NULL;
+ /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
+ * to be consistent with ED_gpencil_data_get_active's behavior.
+ */
+
+ if (base && TESTBASE(v3d, base)) {
+ gpd = base->object->gpd;
+ }
+ return gpd ? gpd : scene->gpd;
+}
+
+/* ******************************************************** */
+/* Poll Callbacks */
+
+/* poll callback for adding data/layers - special */
+int gp_add_poll(bContext *C)
+{
+ /* the base line we have is that we have somewhere to add Grease Pencil data */
+ return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+}
+
+/* poll callback for checking if there is an active layer */
+int gp_active_layer_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ return (gpl != NULL);
+}
+
+/* ******************************************************** */
+/* Brush Tool Core */
+
+/* Check if part of stroke occurs within last segment drawn by eraser */
+bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
+ int rad, int x0, int y0, int x1, int y1)
+{
+ /* simple within-radius check for now */
+ const float mval_fl[2] = {mval[0], mval[1]};
+ const float screen_co_a[2] = {x0, y0};
+ const float screen_co_b[2] = {x1, y1};
+
+ if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) {
+ return true;
+ }
+
+ /* not inside */
+ return false;
+}
+
+/* ******************************************************** */
+/* Stroke Validity Testing */
+
+/* Check whether given stroke can be edited given the supplied context */
+// XXX: do we need additional flags for screenspace vs dataspace?
+bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
+{
+ /* sanity check */
+ if (ELEM(NULL, sa, gps))
+ return false;
+
+ /* filter stroke types by flags + spacetype */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D strokes - only in 3D view */
+ return (sa->spacetype == SPACE_VIEW3D);
+ }
+ else if (gps->flag & GP_STROKE_2DIMAGE) {
+ /* Special "image" strokes - only in Image Editor */
+ return (sa->spacetype == SPACE_IMAGE);
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
+ return (sa->spacetype != SPACE_VIEW3D);
+ }
+ else {
+ /* view aligned - anything goes */
+ return true;
+ }
+}
+
+/* Check whether given stroke can be edited in the current context */
+bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ return ED_gpencil_stroke_can_use_direct(sa, gps);
+}
+
+/* ******************************************************** */
+/* Space Conversion */
+
+/* Init handling for space-conversion function (from passed-in parameters) */
+void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* zero out the storage (just in case) */
+ memset(r_gsc, 0, sizeof(GP_SpaceConversion));
+ unit_m4(r_gsc->mat);
+
+ /* store settings */
+ r_gsc->sa = sa;
+ r_gsc->ar = ar;
+ r_gsc->v2d = &ar->v2d;
+
+ /* init region-specific stuff */
+ if (sa->spacetype == SPACE_VIEW3D) {
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = (View3D *)CTX_wm_space_data(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* init 3d depth buffers */
+ view3d_operator_needs_opengl(C);
+
+ view3d_region_operator_needs_opengl(win, ar);
+ ED_view3d_autodist_init(scene, ar, v3d, 0);
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */
+ r_gsc->subrect = &r_gsc->subrect_data;
+ }
+ }
+}
+
+
+/* Convert Grease Pencil points to screen-space values
+ * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+ */
+void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
+ int *r_x, int *r_y)
+{
+ ARegion *ar = gsc->ar;
+ View2D *v2d = gsc->v2d;
+ rctf *subrect = gsc->subrect;
+ int xyval[2];
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ *r_x = xyval[0];
+ *r_y = xyval[1];
+ }
+ else {
+ *r_x = V2D_IS_CLIPPED;
+ *r_y = V2D_IS_CLIPPED;
+ }
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ *r_x = (int)(pt->x / 100 * ar->winx);
+ *r_y = (int)(pt->y / 100 * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
+}
+
+/* ******************************************************** */
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index 9fa603966b6..e2a24b9fed7 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -33,18 +33,8 @@
#ifndef __BIF_GL_H__
#define __BIF_GL_H__
-#include "GL/glew.h"
-
-#ifdef __APPLE__
-
-/* hacking pointsize and linewidth */
-# define glPointSize(f) glPointSize(U.pixelsize * (f))
-# define glLineWidth(f) glLineWidth(U.pixelsize * (f))
-#else
- /* avoid include mismatch by referencing 'U' from both */
-# define glPointSize(f) glPointSize(((void)U.pixelsize, (f)))
-# define glLineWidth(f) glLineWidth(((void)U.pixelsize, (f)))
-#endif
+#include "GPU_glew.h"
+#include "BLI_utildefines.h"
/*
* these should be phased out. cpack should be replaced in
@@ -58,26 +48,58 @@
* */
void cpack(unsigned int x);
-
+#ifdef WITH_GL_PROFILE_COMPAT
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define glMultMatrixf(x) \
glMultMatrixf(_Generic((x), \
float *: (float *)(x), \
+ float [16]: (float *)(x), \
float (*)[4]: (float *)(x), \
+ float [4][4]: (float *)(x), \
const float *: (float *)(x), \
- const float (*)[4]: (float *)(x)) \
+ const float [16]: (float *)(x), \
+ const float (*)[4]: (float *)(x), \
+ const float [4][4]: (float *)(x)) \
)
# define glLoadMatrixf(x) \
glLoadMatrixf(_Generic((x), \
float *: (float *)(x), \
- float (*)[4]: (float *)(x)) \
+ float [16]: (float *)(x), \
+ float (*)[4]: (float *)(x), \
+ float [4][4]: (float *)(x)) \
)
#else
# define glMultMatrixf(x) glMultMatrixf((float *)(x))
# define glLoadMatrixf(x) glLoadMatrixf((float *)(x))
-#endif
+#endif /* C11 */
+#endif /* WITH_GL_PROFILE_COMPAT */
+
+
+/* hacking pointsize and linewidth */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define glPointSize(f) glPointSize(U.pixelsize * _Generic((f), double: (float)(f), default: (f)))
+# define glLineWidth(f) glLineWidth(U.pixelsize * _Generic((f), double: (float)(f), default: (f)))
+#else
+# define glPointSize(f) glPointSize(U.pixelsize * (f))
+# define glLineWidth(f) glLineWidth(U.pixelsize * (f))
+#endif /* C11 */
#define GLA_PIXEL_OFS 0.375f
+
+BLI_INLINE void glTranslate3fv(const float vec[3]) { glTranslatef(UNPACK3(vec)); }
+BLI_INLINE void glTranslate2fv(const float vec[2]) { glTranslatef(UNPACK2(vec), 0.0f); }
+BLI_INLINE void glTranslate3dv(const double vec[3]) { glTranslated(UNPACK3(vec)); }
+BLI_INLINE void glTranslate2dv(const double vec[2]) { glTranslated(UNPACK2(vec), 0.0f); }
+
+BLI_INLINE void glScale3fv(const float vec[3]) { glScalef(UNPACK3(vec)); }
+BLI_INLINE void glScale2fv(const float vec[2]) { glScalef(UNPACK2(vec), 0.0); }
+BLI_INLINE void glScale3dv(const double vec[3]) { glScaled(UNPACK3(vec)); }
+BLI_INLINE void glScale2dv(const double vec[2]) { glScaled(UNPACK2(vec), 0.0); }
+
+/* v2 versions don't make much sense for rotation */
+BLI_INLINE void glRotate3fv(const float angle, const float vec[3]) { glRotatef(angle, UNPACK3(vec)); }
+BLI_INLINE void glRotate3dv(const double angle, const double vec[3]) { glRotated(angle, UNPACK3(vec)); }
+
#endif /* #ifdef __BIF_GL_H__ */
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index b401f06f484..b904417cfcb 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -41,10 +41,12 @@ struct ColorManagedDisplaySettings;
void fdrawbezier(float vec[4][3]);
void fdrawline(float x1, float y1, float x2, float y2);
void fdrawbox(float x1, float y1, float x2, float y2);
-void sdrawline(short x1, short y1, short x2, short y2);
-void sdrawtri(short x1, short y1, short x2, short y2);
-void sdrawtrifill(short x1, short y1, short x2, short y2);
-void sdrawbox(short x1, short y1, short x2, short y2);
+void sdrawline(int x1, int y1, int x2, int y2);
+#if 0
+void sdrawtri(int x1, int y1, int x2, int y2);
+void sdrawtrifill(int x1, int y1, int x2, int y2);
+#endif
+void sdrawbox(int x1, int y1, int x2, int y2);
void sdrawXORline(int x0, int y0, int x1, int y1);
void sdrawXORline4(int nr, int x0, int y0, int x1, int y1);
@@ -88,13 +90,13 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments
void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments);
/**
- * Routines an integer value as obtained by glGetIntegerv.
+ * Returns an integer value as obtained by glGetIntegerv.
* The param must cause only one value to be gotten from GL.
*/
int glaGetOneInteger(int param);
/**
- * Routines a float value as obtained by glGetIntegerv.
+ * Returns a float value as obtained by glGetFloatv.
* The param must cause only one value to be gotten from GL.
*/
float glaGetOneFloat(int param);
@@ -162,8 +164,8 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
/** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering.
*
- * glwDefine2DArea and glaBegin2DDraw set up an OpenGL state appropriate
- * for drawing using both vertice (Vertex, etc) and raster (RasterPos, Rect)
+ * glaDefine2DArea and glaBegin2DDraw set up an OpenGL state appropriate
+ * for drawing using both vertex (Vertex, etc) and raster (RasterPos, Rect)
* commands. All coordinates should be at integer positions. There is little
* to no reason to use glVertex2f etc. functions during 2D rendering, and
* thus no reason to +-0.5 the coordinates or perform other silly
@@ -179,8 +181,8 @@ typedef struct gla2DDrawInfo gla2DDrawInfo;
#if 0
gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect);
-void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r);
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2]);
+void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y);
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]);
void glaEnd2DDraw(gla2DDrawInfo *di);
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 956ec308daa..3c8442218be 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -49,7 +49,6 @@ struct Object;
struct bDopeSheet;
struct bAction;
-struct bActionGroup;
struct FCurve;
struct FModifier;
@@ -115,13 +114,17 @@ typedef struct bAnimListElem {
int flag; /* copy of elem's flags for quick access */
int index; /* for un-named data, the index of the data in its collection */
- short update; /* (eAnim_Update_Flags) tag the element for updating */
+ char update; /* (eAnim_Update_Flags) tag the element for updating */
+ char tag; /* tag the included data. Temporary always */
+
short datatype; /* (eAnim_KeyType) type of motion data to expect */
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
struct ID *id; /* ID block that channel is attached to */
struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */
+
+ void *owner; /* for per-element F-Curves (e.g. NLA Control Curves), the element that this represents (e.g. NlaStrip) */
} bAnimListElem;
@@ -141,6 +144,9 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_GROUP,
ANIMTYPE_FCURVE,
+ ANIMTYPE_NLACONTROLS,
+ ANIMTYPE_NLACURVE,
+
ANIMTYPE_FILLACTD,
ANIMTYPE_FILLDRIVERS,
@@ -159,6 +165,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSLAT,
ANIMTYPE_DSLINESTYLE,
ANIMTYPE_DSSPK,
+ ANIMTYPE_DSGPENCIL,
ANIMTYPE_SHAPEKEY,
@@ -405,7 +412,8 @@ typedef enum eAnimChannel_Settings {
ACHANNEL_SETTING_EXPAND = 3,
ACHANNEL_SETTING_VISIBLE = 4, /* only for Graph Editor */
ACHANNEL_SETTING_SOLO = 5, /* only for NLA Tracks */
- ACHANNEL_SETTING_PINNED = 6 /* only for NLA Actions */
+ ACHANNEL_SETTING_PINNED = 6, /* only for NLA Actions */
+ ACHANNEL_SETTING_MOD_OFF = 7
} eAnimChannel_Settings;
@@ -449,15 +457,15 @@ typedef struct bAnimChannelType {
/* ------------------------ Drawing API -------------------------- */
/* Get typeinfo for the given channel */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
/* Print debugging info about a given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level);
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc);
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index);
/* Draw the widgets for the given channel */
-void ANIM_channel_draw_widgets(struct bContext *C, bAnimContext *ac, bAnimListElem *ale, struct uiBlock *block, float yminc, float ymaxc, size_t channel_index);
+void ANIM_channel_draw_widgets(const struct bContext *C, bAnimContext *ac, bAnimListElem *ale, struct uiBlock *block, float yminc, float ymaxc, size_t channel_index);
/* ------------------------ Editing API -------------------------- */
@@ -610,7 +618,7 @@ typedef enum eAnimUnitConv_Flags {
short ANIM_get_normalization_flags(bAnimContext *ac);
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag);
+float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag, float *r_offset);
/* ------------- Utility macros ----------------------- */
@@ -652,6 +660,7 @@ void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
/* ************************************************* */
/* OPERATORS */
@@ -669,6 +678,16 @@ void ED_operatormacros_graph(void);
void ED_operatormacros_action(void);
/* ************************************************ */
+/* Animation Editor Exports */
+/* XXX: Should we be doing these here, or at all? */
+
+/* Action Editor - Action Management */
+struct AnimData *ED_actedit_animdata_from_context(struct bContext *C);
+void ED_animedit_unlink_action(struct bContext *C, struct ID *id,
+ struct AnimData *adt, struct bAction *act,
+ struct ReportList *reports, bool force_delete);
+
+/* ************************************************ */
#endif /* __ED_ANIM_API_H__ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 24c80cbf005..35bb12ddaad 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -39,16 +39,12 @@ struct Base;
struct bContext;
struct Bone;
struct bPoseChannel;
-struct DerivedMesh;
struct IDProperty;
struct ListBase;
struct MeshDeformModifierData;
struct Object;
-struct RegionView3D;
struct ReportList;
struct Scene;
-struct SK_Sketch;
-struct View3D;
struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
@@ -59,8 +55,6 @@ typedef struct EditBone {
struct EditBone *parent; /* Editbones have a one-way link (i.e. children refer
* to parents. This is converted to a two-way link for
* normal bones when leaving editmode. */
- void *temp; /* Used to store temporary data */
-
char name[64]; /* MAXBONENAME */
float roll; /* Roll along axis. We'll ultimately use the axis/angle method
* for determining the transformation matrix of the bone. The axis
@@ -83,6 +77,14 @@ typedef struct EditBone {
float oldlength; /* for envelope scaling */
short segments;
+
+ /* Used to store temporary data */
+ union {
+ struct EditBone *ebone;
+ struct Bone *bone;
+ void *p;
+ int i;
+ } temp;
} EditBone;
#define BONESEL_ROOT (1 << 28)
@@ -119,10 +121,12 @@ void ED_keymap_armature(struct wmKeyConfig *keyconf);
void ED_armature_from_edit(struct bArmature *arm);
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
-void ED_armature_deselect_all(struct Object *obedit, int toggle);
+void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
+
+void ED_armature_deselect_all(struct Object *obedit);
void ED_armature_deselect_all_visible(struct Object *obedit);
-int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
+int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
short hits, bool extend, bool deselect, bool toggle, bool do_nearest);
bool mouse_armature(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
@@ -157,9 +161,11 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4]);
#define ARM_GROUPS_ENVELOPE 2
#define ARM_GROUPS_AUTO 3
-void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct Object *par, int mode, bool mirror);
+void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob,
+ struct Object *par, const int mode, const bool mirror);
-void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone); /* if bone is already in list, pass it as param to ignore it */
+/* if bone is already in list, pass it as param to ignore it */
+void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
void undo_push_armature(struct bContext *C, const char *name);
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 64c16605dec..9a987d7618c 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -37,4 +37,6 @@ bool ED_texture_context_check_particles(const struct bContext *C);
bool ED_texture_context_check_linestyle(const struct bContext *C);
bool ED_texture_context_check_others(const struct bContext *C);
+void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id);
+
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 58e64f30b05..6d53209688d 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -31,13 +31,10 @@
#ifndef __ED_CURVE_H__
#define __ED_CURVE_H__
-struct Base;
struct bContext;
struct Nurb;
struct Object;
-struct Scene;
struct Text;
-struct View3D;
struct wmOperator;
struct wmKeyConfig;
struct Curve;
@@ -51,11 +48,6 @@ void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
-void ED_curve_deselect_all(struct EditNurb *editnurb);
-void ED_curve_select_all(struct EditNurb *editnurb);
-void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
-
-
void undo_push_curve(struct bContext *C, const char *name);
ListBase *object_editcurve_get(struct Object *ob);
@@ -67,10 +59,20 @@ bool mouse_nurb(struct bContext *C, const int mval[2], bool extend, bool dese
struct Nurb *add_nurbs_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob);
-int isNurbsel(struct Nurb *nu);
+bool ED_curve_nurb_select_check(struct Curve *cu, struct Nurb *nu);
+int ED_curve_nurb_select_count(struct Curve *cu, struct Nurb *nu);
+void ED_curve_nurb_select_all(struct Nurb *nu);
+void ED_curve_nurb_deselect_all(struct Nurb *nu);
int join_curve_exec(struct bContext *C, struct wmOperator *op);
+/* editcurve_select.c */
+bool ED_curve_select_check(struct Curve *cu, struct EditNurb *editnurb);
+void ED_curve_deselect_all(struct EditNurb *editnurb);
+void ED_curve_select_all(struct EditNurb *editnurb);
+void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
+bool ED_curve_select_nth(struct Curve *cu, int nth, int skip, int offset);
+
/* editfont.h */
void undo_push_font(struct bContext *C, const char *name);
void make_editText(struct Object *obedit);
@@ -79,8 +81,6 @@ void free_editText(struct Object *obedit);
void ED_text_to_object(struct bContext *C, struct Text *text, const bool split_lines);
-bool ED_curve_select_nth(struct Curve *cu, int nth);
-
void ED_curve_beztcpy(struct EditNurb *editnurb, struct BezTriple *dst, struct BezTriple *src, int count);
void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count);
@@ -90,7 +90,9 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]);
bool mouse_font(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+#if 0
/* debug only */
void printknots(struct Object *obedit);
+#endif
#endif /* __ED_CURVE_H__ */
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index f2a6ce0b129..186a2a26825 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -33,6 +33,7 @@
struct ARegion;
struct FileSelectParams;
+struct ScrArea;
struct SpaceFile;
struct bContext;
struct wmWindowManager;
@@ -40,17 +41,13 @@ struct wmWindowManager;
#define FILE_LAYOUT_HOR 1
#define FILE_LAYOUT_VER 2
-#define MAX_FILE_COLUMN 8
+#define MAX_FILE_COLUMN 4
typedef enum FileListColumns {
COLUMN_NAME = 0,
COLUMN_DATE,
COLUMN_TIME,
COLUMN_SIZE,
- COLUMN_MODE1,
- COLUMN_MODE2,
- COLUMN_MODE3,
- COLUMN_OWNER
} FileListColumns;
typedef struct FileLayout {
@@ -71,6 +68,9 @@ typedef struct FileLayout {
int dirty;
int textheight;
float column_widths[MAX_FILE_COLUMN];
+
+ /* When we change display size, we may have to update static strings like size of files... */
+ short curr_size;
} FileLayout;
typedef struct FileSelection {
@@ -100,13 +100,48 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
-void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile);
+void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
-void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
+void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
int ED_file_extension_icon(const char *relname);
void ED_file_read_bookmarks(void);
+void ED_file_change_dir(struct bContext *C, const bool checkdir);
+
+/* File menu stuff */
+
+typedef enum FSMenuCategory {
+ FS_CATEGORY_SYSTEM,
+ FS_CATEGORY_SYSTEM_BOOKMARKS,
+ FS_CATEGORY_BOOKMARKS,
+ FS_CATEGORY_RECENT
+} FSMenuCategory;
+
+typedef enum FSMenuInsert {
+ FS_INSERT_SORTED = (1 << 0),
+ FS_INSERT_SAVE = (1 << 1),
+ FS_INSERT_FIRST = (1 << 2), /* moves the item to the front of the list when its not already there */
+ FS_INSERT_LAST = (1 << 3), /* just append to preseve delivered order */
+} FSMenuInsert;
+
+struct FSMenu;
+struct FSMenuEntry;
+
+struct FSMenu *ED_fsmenu_get(void);
+struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category);
+void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, struct FSMenuEntry *fsm_head);
+
+int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category);
+
+struct FSMenuEntry *ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index);
+
+char *ED_fsmenu_entry_get_path(struct FSMenuEntry *fsentry);
+void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path);
+
+char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry);
+void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name);
+
#endif /* __ED_FILESELECT_H__ */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 05fb76b7aea..448f2c83aad 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,20 +30,18 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
+struct ID;
struct ListBase;
struct bContext;
-struct bScreen;
struct ScrArea;
struct ARegion;
struct View3D;
-struct SpaceNode;
-struct SpaceSeq;
+struct Object;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDstroke;
struct PointerRNA;
-struct Panel;
-struct ImBuf;
struct wmKeyConfig;
@@ -65,14 +63,37 @@ typedef struct tGPspoint {
/* ----------- Grease Pencil Tools/Context ------------- */
+/* Context-dependent */
struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr);
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+
+/* Context independent (i.e. each required part is passed in instead) */
+struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ID *screen_id, struct Scene *scene,
+ struct ScrArea *sa, struct Object *ob,
+ struct PointerRNA *ptr);
+struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct Scene *scene,
+ struct ScrArea *sa, struct Object *ob);
+
+/* 3D View */
struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d);
+/* ----------- Stroke Editing Utilities ---------------- */
+
+bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+
/* ----------- Grease Pencil Operators ----------------- */
void ED_keymap_gpencil(struct wmKeyConfig *keyconf);
+
void ED_operatortypes_gpencil(void);
+void ED_operatormacros_gpencil(void);
+
+/* ------------- Copy-Paste Buffers -------------------- */
+
+/* Strokes copybuf */
+void ED_gpencil_strokes_copybuf_free(void);
+
/* ------------ Grease-Pencil Drawing API ------------------ */
/* drawgpencil.c */
@@ -80,10 +101,8 @@ void ED_operatortypes_gpencil(void);
void ED_gpencil_draw_2dimage(const struct bContext *C);
void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
void ED_gpencil_draw_view3d(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
-void ED_gpencil_draw_ex(struct bGPdata *gpd, int winx, int winy, const int cfra);
-
-void ED_gpencil_panel_standard_header(const struct bContext *C, struct Panel *pa);
-void ED_gpencil_panel_standard(const struct bContext *C, struct Panel *pa);
+void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
+ const int cfra, const char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
@@ -99,6 +118,8 @@ void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode
bool ED_gplayer_frames_delete(struct bGPDlayer *gpl);
void ED_gplayer_frames_duplicate(struct bGPDlayer *gpl);
+void ED_gplayer_frames_keytype_set(struct bGPDlayer *gpl, short type);
+
void ED_gplayer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
#if 0
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index db13c628ade..4c4cec2ee29 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -31,12 +31,11 @@
#define __ED_IMAGE_H__
struct SpaceImage;
-struct Main;
struct bContext;
struct Image;
struct ImageUser;
+struct ImBuf;
struct ToolSettings;
-struct uiBlock;
struct wmWindowManager;
struct ARegion;
struct Scene;
@@ -48,7 +47,7 @@ struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
bool ED_space_image_color_sample(struct Scene *scene, struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
-struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **lock_r);
+struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
@@ -58,8 +57,10 @@ void ED_space_image_get_aspect(struct SpaceImage *sima, float *aspx, float *aspy
void ED_space_image_get_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoomx, float *zoomy);
void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *aspx, float *aspy);
-void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings);
-void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings);
+void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings);
+
+void ED_space_image_paint_update(struct wmWindowManager *wm, struct Scene *scene);
+void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct Scene *scene);
void ED_image_get_uv_aspect(struct Image *ima, struct ImageUser *iuser, float *aspx, float *aspy);
void ED_image_mouse_pos(struct SpaceImage *sima, struct ARegion *ar, const int mval[2], float co[2]);
@@ -69,8 +70,6 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, co
bool ED_space_image_show_render(struct SpaceImage *sima);
bool ED_space_image_show_paint(struct SpaceImage *sima);
bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit);
-bool ED_space_image_show_texpaint(struct SpaceImage *sima, struct Object *ob);
-bool ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit);
bool ED_space_image_paint_curve(const struct bContext *C);
@@ -81,5 +80,7 @@ int ED_space_image_maskedit_mask_poll(struct bContext *C);
void ED_image_draw_info(struct Scene *scene, struct ARegion *ar, bool color_manage, bool use_default_view, int channels, int x, int y,
const unsigned char cp[4], const float fp[4], const float linearcol[4], int *zp, float *zpf);
+bool ED_space_image_show_cache(struct SpaceImage *sima);
+
#endif /* __ED_IMAGE_H__ */
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 58a262e150a..7d163da0db0 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -34,7 +34,6 @@
struct bAnimContext;
struct AnimData;
-struct BezTriple;
struct FCurve;
struct bDopeSheet;
struct bAction;
@@ -120,8 +119,9 @@ void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Obje
void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos);
/* DopeSheet Summary */
void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos);
-/* Grease Pencil Layer */
-// XXX not restored
+/* Grease Pencil datablock summary */
+void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos);
+/* Grease Pencil Layer */
void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos);
/* Mask Layer */
void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos);
@@ -139,11 +139,11 @@ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
/* DopeSheet Summary */
void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+/* Grease Pencil datablock summary */
+void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys);
/* Grease Pencil Layer */
-// XXX not restored
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
/* Mask */
-// XXX not restored
void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay, struct DLRBT_Tree *keys);
/* ActKeyColumn API ---------------- */
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index c8365689803..c6ef303b694 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -41,12 +41,6 @@ struct Scene;
/* ************************************************ */
/* Common Macros and Defines */
-/* --------- BezTriple Selection ------------- */
-
-#define BEZ_SEL(bezt) { (bezt)->f1 |= SELECT; (bezt)->f2 |= SELECT; (bezt)->f3 |= SELECT; } (void)0
-#define BEZ_DESEL(bezt) { (bezt)->f1 &= ~SELECT; (bezt)->f2 &= ~SELECT; (bezt)->f3 &= ~SELECT; } (void)0
-#define BEZ_INVSEL(bezt) { (bezt)->f1 ^= SELECT; (bezt)->f2 ^= SELECT; (bezt)->f3 ^= SELECT; } (void)0
-
/* --------- Tool Flags ------------ */
/* bezt validation */
@@ -58,6 +52,7 @@ typedef enum eEditKeyframes_Validate {
BEZT_OK_VALUERANGE,
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
+ BEZT_OK_REGION_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -107,6 +102,14 @@ struct KeyframeEdit_LassoData {
int mcords_tot;
};
+/* use with BEZT_OK_REGION_CIRCLE */
+struct KeyframeEdit_CircleData {
+ const rctf *rectf_scaled;
+ const rctf *rectf_view;
+ float mval[2];
+ float radius_squared;
+};
+
/* ************************************************ */
/* Non-Destuctive Editing API (keyframes_edit.c) */
@@ -233,7 +236,7 @@ short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt);
/* ----------- BezTriple Callback (Assorted Utilities) ---------- */
-/* used to calculate the the average location of all relevant BezTriples by summing their locations */
+/* used to calculate the average location of all relevant BezTriples by summing their locations */
short bezt_calc_average(KeyframeEditData *ked, struct BezTriple *bezt);
/* used to extract a set of cfra-elems from the keyframes */
@@ -252,7 +255,7 @@ bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
-void clean_fcurve(struct FCurve *fcu, float thresh);
+void clean_fcurve(struct bAnimContext *ac, struct bAnimListElem *ale, float thresh, bool cleardefault);
void smooth_fcurve(struct FCurve *fcu);
void sample_fcurve(struct FCurve *fcu);
@@ -261,7 +264,7 @@ void sample_fcurve(struct FCurve *fcu);
void free_anim_copybuf(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data,
- const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode);
+ const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 5c7b3c531be..5d76c9e0f6f 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -46,10 +46,8 @@ struct FCurve;
struct BezTriple;
struct bPoseChannel;
-struct bConstraint;
struct bContext;
-struct wmOperatorType;
struct ReportList;
struct PointerRNA;
@@ -293,7 +291,7 @@ bool ANIM_paste_driver(struct ReportList *reports, struct ID *id, const char rna
(U.autokey_flag & AUTOKEY_FLAG_##flag))
/* auto-keyframing feature - checks for whether anything should be done for the current frame */
-int autokeyframe_cfra_can_key(struct Scene *scene, struct ID *id);
+bool autokeyframe_cfra_can_key(struct Scene *scene, struct ID *id);
/* ************ Keyframe Checking ******************** */
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6636319dc9b..6fe1524cb6d 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -32,7 +32,6 @@
#define __ED_LATTICE_H__
struct Object;
-struct Lattice;
void free_editLatt(struct Object *ob);
void make_editLatt(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h
index 76d36623b60..5eaf459a4e1 100644
--- a/source/blender/editors/include/ED_markers.h
+++ b/source/blender/editors/include/ED_markers.h
@@ -43,10 +43,11 @@ struct TimeMarker;
/* flags for drawing markers */
enum {
DRAW_MARKERS_LINES = (1 << 0),
- DRAW_MARKERS_LOCAL = (1 << 1)
+ DRAW_MARKERS_LOCAL = (1 << 1),
+ DRAW_MARKERS_MARGIN = (1 << 2),
};
-void draw_markers_time(const struct bContext *C, int flag);
+void ED_markers_draw(const struct bContext *C, int flag);
/* Backend API ----------------------------- */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 97fd553ea19..1f13b46ff2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -31,10 +31,10 @@
#ifndef __ED_MASK_H__
#define __ED_MASK_H__
+struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
-struct wmEvent;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -49,6 +49,7 @@ void ED_mask_point_pos__reverse(struct ScrArea *sa, struct ARegion *ar,
float x, float y, float *xr, float *yr);
void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]);
+bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]);
void ED_operatortypes_mask(void);
void ED_keymap_mask(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 5e774c63841..05a4ccabd1b 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -32,7 +32,6 @@
#define __ED_MBALL_H__
struct bContext;
-struct MetaBall;
struct Object;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 6a562da0a0e..8e19ec839d8 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -40,39 +40,27 @@ struct View3D;
struct ARegion;
struct bContext;
struct wmOperator;
-struct wmWindowManager;
struct wmKeyConfig;
struct ReportList;
-struct EditSelection;
struct ViewContext;
struct bDeformGroup;
-struct MDeformWeight;
struct MDeformVert;
struct Scene;
struct Mesh;
-struct MFace;
-struct MEdge;
-struct MVert;
-struct MCol;
struct UvVertMap;
struct UvMapVert;
-struct CustomData;
struct BMEditMesh;
-struct BMEditSelection;
struct BMesh;
struct BMVert;
struct BMLoop;
struct BMBVHTree;
-struct MLoopCol;
struct BMEdge;
struct BMFace;
struct UvVertMap;
struct UvMapVert;
struct ToolSettings;
-struct Material;
struct Object;
struct rcti;
-struct MeshStatVis;
/* editmesh_utils.c */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis,
@@ -101,8 +89,8 @@ struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
* verts select/deselect edges and faces, if in edge select mode,
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
* edges and vertices.*/
-void EDBM_select_more(struct BMEditMesh *em);
-void EDBM_select_less(struct BMEditMesh *em);
+void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step);
+void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step);
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode);
void EDBM_selectmode_flush(struct BMEditMesh *em);
@@ -119,7 +107,9 @@ void EDBM_mesh_reveal(struct BMEditMesh *em);
void EDBM_update_generic(struct BMEditMesh *em, const bool do_tessface, const bool is_destructive);
-struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const bool selected, const bool do_islands);
+struct UvElementMap *BM_uv_element_map_create(
+ struct BMesh *bm,
+ const bool selected, const bool use_winding, const bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *vmap);
struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l);
@@ -128,7 +118,9 @@ struct MTexPoly *EDBM_mtexpoly_active_get(struct BMEditMesh *em, struct BMFace *
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
-struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, const float limit[2]);
+struct UvVertMap *BM_uv_vert_map_create(
+ struct BMesh *bm,
+ const float limit[2], const bool use_select, const bool use_winding);
void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
@@ -149,9 +141,27 @@ bool EDBM_backbuf_border_mask_init(struct ViewContext *vc, const int mcords[][2]
short xmin, short ymin, short xmax, short ymax);
bool EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads);
-struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *r_dist, const bool sel, const bool strict);
-struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *r_dist);
-struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *r_dist);
+struct BMVert *EDBM_vert_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ const bool use_select_bias, bool use_cycle);
+struct BMVert *EDBM_vert_find_nearest(
+ struct ViewContext *vc, float *r_dist);
+
+struct BMEdge *EDBM_edge_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ struct BMEdge **r_eed_zbuf);
+struct BMEdge *EDBM_edge_find_nearest(
+ struct ViewContext *vc, float *r_dist);
+
+struct BMFace *EDBM_face_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ struct BMFace **r_efa_zbuf);
+struct BMFace *EDBM_face_find_nearest(
+ struct ViewContext *vc, float *r_dist);
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
@@ -220,14 +230,8 @@ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
#define WEIGHT_SUBTRACT 3
bool ED_vgroup_sync_from_pose(struct Object *ob);
-struct bDeformGroup *ED_vgroup_add(struct Object *ob);
-struct bDeformGroup *ED_vgroup_add_name(struct Object *ob, const char *name);
-void ED_vgroup_delete(struct Object *ob, struct bDeformGroup *defgroup);
-void ED_vgroup_clear(struct Object *ob);
void ED_vgroup_select_by_name(struct Object *ob, const char *name);
-bool ED_vgroup_data_create(struct ID *id);
void ED_vgroup_data_clamp_range(struct ID *id, const int total);
-bool ED_vgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot);
bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from);
bool ED_vgroup_parray_alloc(struct ID *id, struct MDeformVert ***dvert_arr, int *dvert_tot,
const bool use_vert_sel);
@@ -239,13 +243,16 @@ void ED_vgroup_parray_mirror_assign(struct Object *ob,
void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array, const int dvert_tot,
const bool *vgroup_validmap, const int vgroup_tot,
const float epsilon, const bool keep_single);
+void ED_vgroup_parray_to_weight_array(const struct MDeformVert **dvert_array, const int dvert_tot,
+ float *dvert_weights, const int def_nr);
+void ED_vgroup_parray_from_weight_array(struct MDeformVert **dvert_array, const int dvert_tot,
+ const float *dvert_weights, const int def_nr,
+ const bool remove_zero);
void ED_vgroup_mirror(struct Object *ob,
const bool mirror_weights, const bool flip_vgroups,
const bool all_vgroups, const bool use_topology,
int *r_totmirr, int *r_totfail);
-bool ED_vgroup_object_is_edit_mode(struct Object *ob);
-
void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode);
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
@@ -264,9 +271,10 @@ void ED_mesh_faces_remove(struct Mesh *mesh, struct ReportList *reports, int cou
void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count);
-void ED_mesh_calc_tessface(struct Mesh *mesh);
+void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface);
+void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
int ED_mesh_uv_texture_add(struct Mesh *me, const char *name, const bool active_set);
bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 824c82a0069..1445308c485 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -33,7 +33,6 @@
struct ID;
struct Main;
-struct Material;
struct Scene;
struct Tex;
struct bContext;
@@ -104,6 +103,8 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod
void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner);
+void ED_node_id_unref(struct SpaceNode *snode, const ID *id);
+
/* node_ops.c */
void ED_operatormacros_node(void);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 2328f7d5135..c62bdc1ba87 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -35,33 +35,17 @@
extern "C" {
#endif
-struct BMEdge;
-struct BMFace;
-struct BMVert;
-struct BPoint;
struct Base;
-struct BezTriple;
-struct Curve;
-struct EditBone;
struct EnumPropertyItem;
struct ID;
-struct KeyBlock;
-struct Lattice;
struct Main;
-struct Mesh;
-struct MetaElem;
struct ModifierData;
-struct HookModifierData;
-struct Nurb;
struct Object;
struct ReportList;
struct Scene;
-struct View3D;
-struct ViewContext;
struct bConstraint;
struct bContext;
struct bPoseChannel;
-struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
@@ -93,7 +77,7 @@ typedef enum eParentType {
PAR_PATH_CONST,
PAR_LATTICE,
PAR_VERTEX,
- PAR_VERTEX_TRI
+ PAR_VERTEX_TRI,
} eParentType;
#ifdef __RNA_TYPES_H__
@@ -101,9 +85,10 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-int ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob,
- struct Object *par, int partype, bool xmirror, bool keep_transform, const int vert_par[3]);
-void ED_object_parent_clear(struct Object *ob, int type);
+bool ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob,
+ struct Object *par, int partype, const bool xmirror, const bool keep_transform,
+ const int vert_par[3]);
+void ED_object_parent_clear(struct Object *ob, const int type);
struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob);
void ED_keymap_proportional_cycle(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap);
@@ -122,7 +107,7 @@ void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, str
/* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */
struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct Base *base, int dupflag);
-void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr);
+void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr);
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, int mode, struct ReportList *reports);
void ED_object_toggle_modes(struct bContext *C, int mode);
@@ -137,12 +122,18 @@ void ED_object_editmode_exit(struct bContext *C, int flag);
void ED_object_editmode_enter(struct bContext *C, int flag);
bool ED_object_editmode_load(struct Object *obedit);
+bool ED_object_editmode_calc_active_center(struct Object *obedit, const bool select_only, float r_center[3]);
+
void ED_object_location_from_view(struct bContext *C, float loc[3]);
void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
void ED_object_base_init_transform(struct bContext *C, struct Base *base, const float loc[3], const float rot[3]);
-float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob,
- const float loc[3], const float rot[3], float primmat[4][4],
- bool apply_diameter);
+float ED_object_new_primitive_matrix(
+ struct bContext *C, struct Object *editob,
+ const float loc[3], const float rot[3], float primmat[4][4]);
+
+
+/* Avoid allowing too much insane values even by typing (typos can hang/crash Blender otherwise). */
+#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
@@ -151,10 +142,12 @@ bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, c
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned);
struct Object *ED_object_add_type(
- struct bContext *C, int type, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer) ATTR_RETURNS_NONNULL;
+ struct bContext *C,
+ int type, const char *name, const float loc[3], const float rot[3],
+ bool enter_editmode, unsigned int layer)
+ ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
-void ED_object_single_users(struct Main *bmain, struct Scene *scene, bool full, bool copy_groups);
+void ED_object_single_users(struct Main *bmain, struct Scene *scene, const bool full, const bool copy_groups);
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* object motion paths */
@@ -172,6 +165,9 @@ void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con)
void ED_object_constraint_update(struct Object *ob);
void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob);
+void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con);
+void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con);
+
/* object_lattice.c */
bool mouse_lattice(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
void undo_push_lattice(struct bContext *C, const char *name);
@@ -208,12 +204,6 @@ bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v)
/* object_select.c */
void ED_object_select_linked_by_id(struct bContext *C, struct ID *id);
-
-bool *ED_vgroup_subset_from_select_type(struct Object *ob, enum eVGroupSelect subset_type,
- int *r_vgroup_tot, int *r_subset_count);
-void ED_vgroup_subset_to_index_array(const bool *vgroup_validmap, const int vgroup_tot,
- int *r_vgroup_subset_map);
-
struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
const struct bContext *C,
struct PointerRNA *ptr,
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
new file mode 100644
index 00000000000..af4af8e2f5d
--- /dev/null
+++ b/source/blender/editors/include/ED_outliner.h
@@ -0,0 +1,36 @@
+/*
+ * ***** 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) 2015, Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_outliner.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_OUTLINER_H__
+#define __ED_OUTLINER_H__
+
+struct ID;
+struct SpaceOops;
+
+/* Used to check whether a given texture context is valid in current context. */
+void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id);
+
+#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index decd79fcc7b..e46f4b966c0 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -26,7 +26,6 @@
#define __ED_PAINT_H__
struct bContext;
-struct RegionView3D;
struct wmKeyConfig;
struct wmOperator;
@@ -47,9 +46,9 @@ typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb);
int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
void ED_undo_paint_step_num(struct bContext *C, int type, int num);
-const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *active);
+const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, bool *r_active);
void ED_undo_paint_free(void);
-int ED_undo_paint_valid(int type, const char *name);
+bool ED_undo_paint_is_valid(int type, const char *name);
bool ED_undo_paint_empty(int type);
void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup);
void ED_undo_paint_push_end(int type);
@@ -59,7 +58,7 @@ void ED_undo_paint_push_end(int type);
void ED_image_undo_restore(struct bContext *C, struct ListBase *lb);
void ED_image_undo_free(struct ListBase *lb);
void ED_imapaint_clear_partial_redraw(void);
-void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
#endif /* __ED_PAINT_H__ */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index f9516f255cf..6cb8c0cfb19 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -35,10 +35,7 @@
struct bContext;
struct Object;
struct ParticleEditSettings;
-struct ParticleSystem;
-struct RadialControl;
struct rcti;
-struct wmKeyConfig;
struct PTCacheEdit;
struct Scene;
@@ -69,9 +66,9 @@ void PE_undo_push(struct Scene *scene, const char *str);
void PE_undo_step(struct Scene *scene, int step);
void PE_undo(struct Scene *scene);
void PE_redo(struct Scene *scene);
-int PE_undo_valid(struct Scene *scene);
+bool PE_undo_is_valid(struct Scene *scene);
void PE_undo_number(struct Scene *scene, int nr);
-const char *PE_undo_get_name(struct Scene *scene, int nr, int *active);
+const char *PE_undo_get_name(struct Scene *scene, int nr, bool *r_active);
#endif /* __ED_PARTICLE_H__ */
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 14595a4c668..707d7c6c693 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -35,12 +35,9 @@ struct ID;
struct Main;
struct MTex;
struct Render;
-struct RenderInfo;
struct Scene;
struct ScrArea;
-struct RegionView3D;
-struct RenderEngine;
-struct View3D;
+struct wmWindowManager;
/* render_ops.c */
@@ -50,23 +47,13 @@ void ED_operatortypes_render(void);
void ED_render_id_flush_update(struct Main *bmain, struct ID *id);
void ED_render_engine_changed(struct Main *bmain);
-void ED_render_engine_area_exit(struct ScrArea *sa);
+void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
+void ED_render_scene_update_pre(struct Main *bmain, struct Scene *scene, bool time);
-void ED_viewport_render_kill_jobs(const struct bContext *C, bool free_database);
+void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
-
-/* render_preview.c */
-
-/* stores rendered preview - is also used for icons */
-typedef struct RenderInfo {
- int pr_rectx;
- int pr_recty;
- short curtile, tottile;
- rcti disprect; /* storage for view3d preview rect */
- unsigned int *rect;
- struct Render *re; /* persistent render */
-} RenderInfo;
+struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
/* Render the preview
*
@@ -74,18 +61,23 @@ typedef struct RenderInfo {
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
* - PR_NODE_RENDER: preview is rendered for node editor
+ * - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
-#define PR_BUTS_RENDER 0
-#define PR_ICON_RENDER 1
-#define PR_NODE_RENDER 2
+enum {
+ PR_BUTS_RENDER = 0,
+ PR_ICON_RENDER = 1,
+ PR_NODE_RENDER = 2,
+ PR_ICON_DEFERRED = 3,
+};
-void ED_preview_init_dbase(void);
+void ED_preview_ensure_dbase(void);
void ED_preview_free_dbase(void);
void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey, int method);
+void ED_preview_icon_render(struct Main *bmain, struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey);
void ED_preview_icon_job(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey);
-void ED_preview_kill_jobs(const struct bContext *C);
+void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain);
void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d31be3e961f..5bc606ca725 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -42,7 +42,6 @@ struct wmNotifier;
struct wmEvent;
struct wmKeyConfig;
struct bContext;
-struct SpaceType;
struct Scene;
struct bScreen;
struct ARegion;
@@ -58,15 +57,19 @@ void ED_region_set(const struct bContext *C, struct ARegion *ar);
void ED_region_update_rect(struct bContext *C, struct ARegion *ar);
void ED_region_init(struct bContext *C, struct ARegion *ar);
void ED_region_tag_redraw(struct ARegion *ar);
-void ED_region_tag_redraw_partial(struct ARegion *ar, struct rcti *rct);
+void ED_region_tag_redraw_partial(struct ARegion *ar, const struct rcti *rct);
void ED_region_tag_redraw_overlay(struct ARegion *ar);
void ED_region_tag_refresh_ui(struct ARegion *ar);
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *ar);
-void ED_region_panels(const struct bContext *C, struct ARegion *ar, int vertical, const char *context, int contextnr);
+void ED_region_panels(
+ const struct bContext *C, struct ARegion *ar,
+ const char *context, int contextnr,
+ const bool vertical);
void ED_region_header_init(struct ARegion *ar);
void ED_region_header(const struct bContext *C, struct ARegion *ar);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar);
-void ED_region_info_draw(struct ARegion *ar, const char *text, int block, float fill_color[4]);
+void ED_region_info_draw(struct ARegion *ar, const char *text, float fill_color[4], const bool full_redraw);
+void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, rctf frame, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
float ED_region_blend_factor(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
@@ -76,7 +79,6 @@ void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
-
/* areas */
void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
void ED_area_exit(struct bContext *C, struct ScrArea *sa);
@@ -86,6 +88,7 @@ void ED_area_tag_redraw(ScrArea *sa);
void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
void ED_area_tag_refresh(ScrArea *sa);
void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
+void ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
void ED_area_headerprint(ScrArea *sa, const char *str);
void ED_area_newspace(struct bContext *C, ScrArea *sa, int type);
void ED_area_prevspace(struct bContext *C, ScrArea *sa);
@@ -99,19 +102,21 @@ void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
bScreen *ED_screen_duplicate(struct wmWindow *win, struct bScreen *sc);
bScreen *ED_screen_add(struct wmWindow *win, struct Scene *scene, const char *name);
-void ED_screen_set(struct bContext *C, struct bScreen *sc);
-void ED_screen_delete(struct bContext *C, struct bScreen *sc);
+bool ED_screen_set(struct bContext *C, struct bScreen *sc);
+bool ED_screen_delete(struct bContext *C, struct bScreen *sc);
void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene);
-void ED_screen_delete_scene(struct bContext *C, struct Scene *scene);
+bool ED_screen_delete_scene(struct bContext *C, struct Scene *scene);
void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh);
+void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
-void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
+void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa, const bool was_prev_temp);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
-struct ScrArea *ED_screen_full_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa);
+struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
+bool ED_screen_stereo3d_required(struct bScreen *screen);
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);
@@ -119,6 +124,7 @@ void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute
void ED_refresh_viewport_fps(struct bContext *C);
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
+bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
void ED_operatortypes_screen(void);
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index 2b02606c6d9..effecf43839 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -93,10 +93,13 @@ typedef struct AZone {
short x1, y1, x2, y2;
/* for clip */
rcti rect;
+ /* for fade in/out */
+ float alpha;
} AZone;
/* actionzone type */
#define AZONE_AREA 1 /* corner widgets for splitting areas */
#define AZONE_REGION 2 /* when a region is collapsed, draw a handle to expose */
+#define AZONE_FULLSCREEN 3 /* when in editor fullscreen draw a corner to go to normal mode */
#endif /* __ED_SCREEN_TYPES_H__ */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 85ff9b5d246..6daaac5bb42 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -41,8 +41,6 @@ struct rcti;
void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar,
struct RegionView3D *rv3d, struct Object *ob);
-void ED_sculpt_stroke_get_average(struct Object *ob, float stroke[3]);
-bool ED_sculpt_minmax(struct bContext *C, float min[3], float max[3]);
int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend);
#endif /* __ED_SCULPT_H__ */
diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h
index 4e9d67df61e..94885c2abe0 100644
--- a/source/blender/editors/include/ED_sequencer.h
+++ b/source/blender/editors/include/ED_sequencer.h
@@ -27,6 +27,7 @@
#ifndef __ED_SEQUENCER_H__
#define __ED_SEQUENCER_H__
+struct bContext;
struct Scene;
struct Sequence;
struct SpaceSeq;
@@ -39,7 +40,12 @@ bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene
int ED_space_sequencer_maskedit_poll(struct bContext *C);
bool ED_space_sequencer_check_show_imbuf(struct SpaceSeq *sseq);
+bool ED_space_sequencer_check_show_strip(struct SpaceSeq *sseq);
void ED_operatormacros_sequencer(void);
+Sequence *ED_sequencer_special_preview_get(void);
+void ED_sequencer_special_preview_set(struct bContext *C, const int mval[2]);
+void ED_sequencer_special_preview_clear(void);
+
#endif /* __ED_SEQUENCER_H__ */
diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h
index 9a36cb3d6ab..5df7d9cfaef 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -31,8 +31,11 @@
#define __ED_TEXT_H__
struct bContext;
+struct SpaceText;
+struct ARegion;
void ED_text_undo_step(struct bContext *C, int step);
+bool ED_text_region_location_from_cursor(struct SpaceText *st, struct ARegion *ar, const int cursor_co[2], int r_pixel_co[2]);
#endif /* __ED_TEXT_H__ */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index daa6864b5aa..b14ba45a64d 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -35,17 +35,14 @@
/* ******************* Registration Function ********************** */
struct ARegion;
-struct EnumPropertyItem;
struct ListBase;
struct Object;
struct View3D;
struct bContext;
-struct uiLayout;
struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperatorType;
-struct wmWindowManager;
void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
void transform_operatortypes(void);
@@ -73,6 +70,7 @@ enum TfmMode {
TFM_BONE_ENVELOPE,
TFM_CURVE_SHRINKFATTEN,
TFM_MASK_SHRINKFATTEN,
+ TFM_GPENCIL_SHRINKFATTEN,
TFM_BONE_ROLL,
TFM_TIME_TRANSLATE,
TFM_TIME_SLIDE,
@@ -85,7 +83,8 @@ enum TfmMode {
TFM_ALIGN,
TFM_EDGE_SLIDE,
TFM_VERT_SLIDE,
- TFM_SEQ_SLIDE
+ TFM_SEQ_SLIDE,
+ TFM_BONE_ENVELOPE_DIST,
};
/* TRANSFORM CONTEXTS */
@@ -99,6 +98,7 @@ enum TfmMode {
#define CTX_MOVIECLIP (1 << 6)
#define CTX_MASK (1 << 7)
#define CTX_PAINT_CURVE (1 << 8)
+#define CTX_GPENCIL_STROKES (1 << 9)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
@@ -107,7 +107,6 @@ enum TfmMode {
bool calculateTransformCenter(struct bContext *C, int centerMode, float cent3d[3], float cent2d[2]);
struct TransInfo;
-struct ScrArea;
struct Base;
struct Scene;
struct Object;
@@ -128,7 +127,7 @@ void BIF_createTransformOrientation(struct bContext *C, struct ReportList *repor
void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *ts);
void BIF_selectTransformOrientationValue(struct bContext *C, int orientation);
-void ED_getTransformOrientationMatrix(const struct bContext *C, float orientation_mat[3][3], const bool activeOnly);
+void ED_getTransformOrientationMatrix(const struct bContext *C, float orientation_mat[3][3], const short around);
int BIF_countTransformOrientation(const struct bContext *C);
@@ -146,6 +145,7 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_CORRECT_UV (1 << 8)
#define P_NO_DEFAULTS (1 << 10)
#define P_NO_TEXSPACE (1 << 11)
+#define P_GPENCIL_EDIT (1 << 12)
void Transform_Properties(struct wmOperatorType *ot, int flags);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 6d9f1c4eda0..496ce7f2c60 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -31,22 +31,18 @@
#ifndef __ED_UTIL_H__
#define __ED_UTIL_H__
-struct Scene;
-struct Object;
struct bContext;
-struct ARegion;
-struct uiBlock;
struct wmOperator;
struct wmOperatorType;
-struct BMEditMesh;
-struct Mesh;
/* ed_util.c */
void ED_editors_init(struct bContext *C);
void ED_editors_exit(struct bContext *C);
-void ED_editors_flush_edits(const struct bContext *C, bool for_render);
+bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
+
+void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
/* ************** Undo ************************ */
@@ -66,7 +62,7 @@ int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
-int ED_undo_valid(const struct bContext *C, const char *undoname);
+bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
/* undo_editmode.c */
void undo_editmode_push(struct bContext *C, const char *name,
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 4b82fa40c6a..535683823bf 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -31,18 +31,17 @@
#define __ED_UVEDIT_H__
struct ARegionType;
+struct BMesh;
struct BMEditMesh;
struct BMFace;
struct BMLoop;
struct Image;
struct ImageUser;
-struct MTFace;
struct MTexPoly;
struct Main;
struct Object;
struct Scene;
struct SpaceImage;
-struct bContext;
struct bNode;
struct wmKeyConfig;
@@ -52,6 +51,7 @@ void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
+void ED_uvedit_select_all(struct BMesh *bm);
bool ED_object_get_active_image(struct Object *ob, int mat_nr,
struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
@@ -92,19 +92,24 @@ void uvedit_uv_select_disable(struct BMEditMesh *em, struct Scene *scene, struct
bool ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima,
const float co[2], float r_uv[2]);
+void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
+
/* uvedit_unwrap_ops.c */
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
+void ED_uvedit_pack_islands(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
+void ED_uvedit_unwrap_cube_project(struct Object *ob, struct BMesh *bm, float cube_size, bool use_select);
/* single call up unwrap using scene settings, used for edge tag unwrapping */
void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
+
/* uvedit_draw.c */
-void draw_image_cursor(struct ARegion *ar, const float cursor[2]);
-void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);
+void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]);
+void ED_uvedit_draw_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);
/* uvedit_buttons.c */
void ED_uvedit_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index bd4f37cfb1e..416e821b3f8 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -61,6 +61,11 @@ struct rcti;
struct wmOperator;
struct wmOperatorType;
struct wmWindow;
+struct wmWindowManager;
+struct GPUFX;
+struct GPUOffScreen;
+struct GPUFXSettings;
+enum eGPUFXFlags;
/* for derivedmesh drawing callbacks, for view3d_select, .... */
typedef struct ViewContext {
@@ -99,7 +104,7 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
void ED_view3d_depth_update(struct ARegion *ar);
-float ED_view3d_depth_read_cached(struct ViewContext *vc, int x, int y);
+float ED_view3d_depth_read_cached(const struct ViewContext *vc, int x, int y);
void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
/* Projection */
@@ -214,55 +219,67 @@ void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], floa
bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
+void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
/* end */
-void ED_view3d_dist_range_get(struct View3D *v3d,
- float r_dist_range[2]);
-bool ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d,
- float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
-bool ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi,
- struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
+void ED_view3d_dist_range_get(
+ const struct View3D *v3d,
+ float r_dist_range[2]);
+bool ED_view3d_clip_range_get(
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
+bool ED_view3d_viewplane_get(
+ const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi,
+ struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
-void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar,
- struct View3D *v3d, struct RegionView3D *rv3d,
- struct rctf *r_viewborder, const bool no_shift);
-void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar,
- struct View3D *v3d, struct RegionView3D *rv3d,
- float r_size[2]);
+void ED_view3d_calc_camera_border(
+ const struct Scene *scene, const struct ARegion *ar,
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ struct rctf *r_viewborder, const bool no_shift);
+void ED_view3d_calc_camera_border_size(
+ const struct Scene *scene, const struct ARegion *ar,
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ float r_size[2]);
bool ED_view3d_calc_render_border(struct Scene *scene, struct View3D *v3d,
struct ARegion *ar, struct rcti *rect);
+void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]);
-bool ED_view3d_clipping_test(struct RegionView3D *rv3d, const float co[3], const bool is_local);
+bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local);
void ED_view3d_clipping_set(struct RegionView3D *rv3d);
void ED_view3d_clipping_enable(void);
void ED_view3d_clipping_disable(void);
-float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3]);
+float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
-float ED_view3d_radius_to_persp_dist(const float angle, const float radius);
-float ED_view3d_radius_to_ortho_dist(const float lens, const float radius);
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+float ED_view3d_radius_to_dist(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius);
void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4]);
/* backbuffer select and draw support */
-void view3d_validate_backbuf(struct ViewContext *vc);
-struct ImBuf *view3d_read_backbuf(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
-unsigned int view3d_sample_backbuf_rect(struct ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *dist, short strict,
- void *handle, bool (*indextest)(void *handle, unsigned int index));
-unsigned int view3d_sample_backbuf(struct ViewContext *vc, int x, int y);
-
-/* draws and does a 4x4 sample */
-bool ED_view3d_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
- const int mval[2], float mouse_worldloc[3],
- const bool alphaoverride, const float fallback_depth_pt[3]);
+void ED_view3d_backbuf_validate(struct ViewContext *vc);
+struct ImBuf *ED_view3d_backbuf_read(struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax);
+unsigned int ED_view3d_backbuf_sample_rect(
+ struct ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist);
+int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist);
+unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
+
+bool ED_view3d_autodist(
+ struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
+ const int mval[2], float mouse_worldloc[3],
+ const bool alphaoverride, const float fallback_depth_pt[3]);
/* only draw so ED_view3d_autodist_simple can be called many times after */
void ED_view3d_autodist_init(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode);
@@ -271,7 +288,8 @@ bool ED_view3d_autodist_depth(struct ARegion *ar, const int mval[2], int margin,
bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
/* select */
-#define MAXPICKBUF 10000
+#define MAXPICKELEMS 2500
+#define MAXPICKBUF (4 * MAXPICKELEMS)
short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest);
/* view3d_select.c */
@@ -303,14 +321,17 @@ int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
bool ED_view3d_context_activate(struct bContext *C);
void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d);
-void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
- int winx, int winy, float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky);
+void ED_view3d_draw_offscreen(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
+ float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp,
+ struct GPUOffScreen *ofs,
+ struct GPUFX *fx, struct GPUFXSettings *fx_settings,
+ const char *viewname);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, char err_out[256]);
+ bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool draw_background, int alpha_mode, char err_out[256]);
-void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]);
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
@@ -318,17 +339,16 @@ void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct AR
bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
char ED_view3d_lock_view_from_index(int index);
+char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(struct RegionView3D *rv3d);
-uint64_t ED_view3d_datamask(struct Scene *scene, struct View3D *v3d);
-uint64_t ED_view3d_screen_datamask(struct bScreen *screen);
+uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
+uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
-bool ED_view3d_view_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
-
-bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* camera lock functions */
-bool ED_view3d_camera_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* copy the camera to the view before starting a view transformation */
void ED_view3d_camera_lock_init_ex(struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -368,6 +388,10 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx,
#endif
/* render */
+void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar);
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
+#define V3D_IS_ZBUF(v3d) \
+ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 1d79cf749f9..e6421b0de41 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -54,7 +54,7 @@ DEF_ICON(DOT)
DEF_ICON(COLLAPSEMENU)
DEF_ICON(X)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK005)
+ DEF_ICON(BLANK005) /* XXX 'DOWNARROW' icon! */
#endif
DEF_ICON(GO_LEFT)
DEF_ICON(PLUG)
@@ -251,9 +251,7 @@ DEF_ICON(EMPTY_DATA)
DEF_ICON(SETTINGS)
DEF_ICON(RENDER_ANIMATION)
DEF_ICON(RENDER_STILL)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK080F)
-#endif
+DEF_ICON(LIBRARY_DATA_BROKEN)
DEF_ICON(BOIDS)
DEF_ICON(STRANDS)
DEF_ICON(LIBRARY_DATA_INDIRECT)
@@ -426,13 +424,11 @@ DEF_ICON(CURVE_PATH)
DEF_ICON(COLOR_RED)
DEF_ICON(COLOR_GREEN)
DEF_ICON(COLOR_BLUE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK652)
- DEF_ICON(BLANK653)
- DEF_ICON(BLANK654)
- DEF_ICON(BLANK655)
-#endif
-
+DEF_ICON(TRIA_RIGHT_BAR)
+DEF_ICON(TRIA_DOWN_BAR)
+DEF_ICON(TRIA_LEFT_BAR)
+DEF_ICON(TRIA_UP_BAR)
+
/* EMPTY */
DEF_ICON(FORCE_FORCE)
DEF_ICON(FORCE_WIND)
@@ -463,11 +459,13 @@ DEF_ICON(FORCE_SMOKEFLOW)
DEF_ICON(BLANK685)
/* EMPTY */
- DEF_ICON(BLANK690)
- DEF_ICON(BLANK691)
- DEF_ICON(BLANK692)
- DEF_ICON(BLANK693)
- DEF_ICON(BLANK694)
+ DEF_ICON(BLANK690) /* XXX 'Temperature' icon! */
+ DEF_ICON(BLANK691) /* XXX 'Temperature' icon! */
+ DEF_ICON(BLANK692) /* XXX 'Gear' icon! */
+#endif
+DEF_ICON(NODE_INSERT_ON)
+DEF_ICON(NODE_INSERT_OFF)
+#ifndef DEF_ICON_BLANK_SKIP
DEF_ICON(BLANK695)
DEF_ICON(BLANK696)
DEF_ICON(BLANK697)
@@ -591,9 +589,9 @@ DEF_ICON(MOD_WARP)
DEF_ICON(MOD_SKIN)
DEF_ICON(MOD_TRIANGULATE)
DEF_ICON(MOD_WIREFRAME)
+DEF_ICON(MOD_DATA_TRANSFER)
+DEF_ICON(MOD_NORMALEDIT)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK167)
- DEF_ICON(BLANK168)
DEF_ICON(BLANK169)
DEF_ICON(BLANK170)
DEF_ICON(BLANK171)
@@ -691,7 +689,7 @@ DEF_ICON(RNDCURVE)
DEF_ICON(PROP_OFF)
DEF_ICON(PROP_ON)
DEF_ICON(PROP_CON)
-DEF_ICON(SCULPT_DYNTOPO)
+DEF_ICON(SCULPT_DYNTOPO) /* XXX Empty icon! */
DEF_ICON(PARTICLE_POINT)
DEF_ICON(PARTICLE_TIP)
DEF_ICON(PARTICLE_PATH)
@@ -704,14 +702,12 @@ DEF_ICON(MANIPUL)
DEF_ICON(SNAP_OFF)
DEF_ICON(SNAP_ON)
DEF_ICON(SNAP_NORMAL)
-DEF_ICON(SNAP_INCREMENT)
+DEF_ICON(SNAP_GRID)
DEF_ICON(SNAP_VERTEX)
DEF_ICON(SNAP_EDGE)
DEF_ICON(SNAP_FACE)
DEF_ICON(SNAP_VOLUME)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK220)
-#endif
+DEF_ICON(SNAP_INCREMENT)
DEF_ICON(STICKY_UVS_LOC)
DEF_ICON(STICKY_UVS_DISABLE)
DEF_ICON(STICKY_UVS_VERT)
@@ -878,8 +874,8 @@ DEF_ICON(FORWARD)
DEF_ICON(BLANK312)
DEF_ICON(BLANK313)
DEF_ICON(BLANK314)
- DEF_ICON(BLANK315)
#endif
+DEF_ICON(FILE_HIDDEN)
DEF_ICON(FILE_BACKUP)
DEF_ICON(DISK_DRIVE)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index bc794bf3350..ba3e3a61aee 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -35,19 +35,15 @@
#include "BLI_compiler_attrs.h"
#include "BLI_sys_types.h" /* size_t */
#include "RNA_types.h"
-#include "DNA_userdef_types.h"
/* Struct Declarations */
struct ID;
-struct Main;
struct ListBase;
struct ARegion;
-struct ARegionType;
struct ScrArea;
struct wmEvent;
struct wmWindow;
-struct wmWindowManager;
struct wmOperator;
struct AutoComplete;
struct bContext;
@@ -58,18 +54,14 @@ struct PointerRNA;
struct PropertyRNA;
struct ReportList;
struct rcti;
-struct rctf;
struct uiList;
struct uiStyle;
struct uiFontStyle;
struct uiWidgetColors;
-struct ColorBand;
-struct CurveMapping;
struct Image;
struct ImageUser;
struct wmOperatorType;
struct uiWidgetColors;
-struct Tex;
struct MTex;
struct ImBuf;
struct bNodeTree;
@@ -93,25 +85,29 @@ typedef struct uiLayout uiLayout;
/* names */
#define UI_MAX_DRAW_STR 400
#define UI_MAX_NAME_STR 128
+#define UI_MAX_SHORTCUT_STR 64
/* use for clamping popups within the screen */
#define UI_SCREEN_MARGIN 10
/* uiBlock->dt and uiBut->dt */
-#define UI_EMBOSS 0 /* use widget style for drawing */
-#define UI_EMBOSSN 1 /* Nothing, only icon and/or text */
-#define UI_EMBOSSP 2 /* Pulldown menu style */
-#define UI_EMBOSST 3 /* Table */
-#define UI_EMBOSSR 4 /* Pie Menu */
+enum {
+ UI_EMBOSS = 0, /* use widget style for drawing */
+ UI_EMBOSS_NONE = 1, /* Nothing, only icon and/or text */
+ UI_EMBOSS_PULLDOWN = 2, /* Pulldown menu style */
+ UI_EMBOSS_RADIAL = 3, /* Pie Menu */
+};
/* uiBlock->direction */
-#define UI_DIRECTION (UI_TOP | UI_DOWN | UI_LEFT | UI_RIGHT)
-#define UI_TOP (1 << 0)
-#define UI_DOWN (1 << 1)
-#define UI_LEFT (1 << 2)
-#define UI_RIGHT (1 << 3)
-#define UI_CENTER (1 << 4)
-#define UI_SHIFT_FLIPPED (1 << 5)
+enum {
+ UI_DIR_UP = (1 << 0),
+ UI_DIR_DOWN = (1 << 1),
+ UI_DIR_LEFT = (1 << 2),
+ UI_DIR_RIGHT = (1 << 3),
+ UI_DIR_CENTER_Y = (1 << 4),
+
+ UI_DIR_ALL = (UI_DIR_UP | UI_DIR_DOWN | UI_DIR_LEFT | UI_DIR_RIGHT),
+};
#if 0
/* uiBlock->autofill (not yet used) */
@@ -121,8 +117,8 @@ typedef struct uiLayout uiLayout;
/* uiBlock->flag (controls) */
#define UI_BLOCK_LOOP (1 << 0)
-#define UI_BLOCK_REDRAW (1 << 1)
-#define UI_BLOCK_SEARCH_MENU (1 << 2)
+#define UI_BLOCK_IS_FLIP (1 << 1)
+#define UI_BLOCK_NO_FLIP (1 << 2)
#define UI_BLOCK_NUMSELECT (1 << 3)
#define UI_BLOCK_NO_WIN_CLIP (1 << 4) /* don't apply window clipping */ /* was UI_BLOCK_ENTER_OK */
#define UI_BLOCK_CLIPBOTTOM (1 << 5)
@@ -131,7 +127,7 @@ typedef struct uiLayout uiLayout;
#define UI_BLOCK_KEEP_OPEN (1 << 8)
#define UI_BLOCK_POPUP (1 << 9)
#define UI_BLOCK_OUT_1 (1 << 10)
-#define UI_BLOCK_NO_FLIP (1 << 11)
+#define UI_BLOCK_SEARCH_MENU (1 << 11)
#define UI_BLOCK_POPUP_MEMORY (1 << 12)
#define UI_BLOCK_CLIP_EVENTS (1 << 13) /* stop handling mouse events */
@@ -156,31 +152,33 @@ typedef struct uiLayout uiLayout;
/* but->flag - general state flags. */
enum {
/* warning, the first 6 flags are internal */
- UI_ICON_SUBMENU = (1 << 6),
- UI_ICON_PREVIEW = (1 << 7),
-
- UI_BUT_NODE_LINK = (1 << 8),
- UI_BUT_NODE_ACTIVE = (1 << 9),
- UI_BUT_DRAG_LOCK = (1 << 10),
- UI_BUT_DISABLED = (1 << 11),
- UI_BUT_COLOR_LOCK = (1 << 12),
- UI_BUT_ANIMATED = (1 << 13),
- UI_BUT_ANIMATED_KEY = (1 << 14),
- UI_BUT_DRIVEN = (1 << 15),
- UI_BUT_REDALERT = (1 << 16),
- UI_BUT_INACTIVE = (1 << 17),
- UI_BUT_LAST_ACTIVE = (1 << 18),
- UI_BUT_UNDO = (1 << 19),
- UI_BUT_IMMEDIATE = (1 << 20),
- UI_BUT_NO_UTF8 = (1 << 21),
-
- UI_BUT_VEC_SIZE_LOCK = (1 << 22), /* used to flag if color hsv-circle should keep luminance */
- UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */
- UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */
- UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
- UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */
- UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
- UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */
+ UI_BUT_ICON_SUBMENU = (1 << 6),
+ UI_BUT_ICON_PREVIEW = (1 << 7),
+
+ UI_BUT_NODE_LINK = (1 << 8),
+ UI_BUT_NODE_ACTIVE = (1 << 9),
+ UI_BUT_DRAG_LOCK = (1 << 10),
+ UI_BUT_DISABLED = (1 << 11),
+ UI_BUT_COLOR_LOCK = (1 << 12),
+ UI_BUT_ANIMATED = (1 << 13),
+ UI_BUT_ANIMATED_KEY = (1 << 14),
+ UI_BUT_DRIVEN = (1 << 15),
+ UI_BUT_REDALERT = (1 << 16),
+ UI_BUT_INACTIVE = (1 << 17),
+ UI_BUT_LAST_ACTIVE = (1 << 18),
+ UI_BUT_UNDO = (1 << 19),
+ UI_BUT_IMMEDIATE = (1 << 20),
+ UI_BUT_NO_UTF8 = (1 << 21),
+
+ UI_BUT_VEC_SIZE_LOCK = (1 << 22), /* used to flag if color hsv-circle should keep luminance */
+ UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */
+ UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */
+ UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
+ UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be gray out */
+ UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
+ UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */
+ UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
+ UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */
};
#define UI_PANEL_WIDTH 340
@@ -234,56 +232,56 @@ typedef enum {
/* assigned to but->type, OR'd with the flags above when passing args */
typedef enum {
- BUT = (1 << 9),
- ROW = (2 << 9),
- TOG = (3 << 9),
- NUM = (5 << 9),
- TEX = (6 << 9),
- TOGN = (9 << 9),
- LABEL = (10 << 9),
- MENU = (11 << 9), /* Dropdown list, actually! */
- ICONTOG = (13 << 9),
- NUMSLI = (14 << 9),
- COLOR = (15 << 9),
- SCROLL = (18 << 9),
- BLOCK = (19 << 9),
- BUTM = (20 << 9),
- SEPR = (21 << 9),
- LINK = (22 << 9),
- INLINK = (23 << 9),
- KEYEVT = (24 << 9),
- HSVCUBE = (26 << 9),
- PULLDOWN = (27 << 9), /* Menu, actually! */
- ROUNDBOX = (28 << 9),
- BUT_COLORBAND = (30 << 9),
- BUT_NORMAL = (31 << 9),
- BUT_CURVE = (32 << 9),
- ICONTOGN = (34 << 9),
- LISTBOX = (35 << 9),
- LISTROW = (36 << 9),
- TOGBUT = (37 << 9),
- OPTION = (38 << 9),
- OPTIONN = (39 << 9),
- TRACKPREVIEW = (40 << 9),
- /* buttons with value >= SEARCH_MENU don't get undo pushes */
- SEARCH_MENU = (41 << 9),
- BUT_EXTRA = (42 << 9),
- HSVCIRCLE = (43 << 9),
- HOTKEYEVT = (46 << 9),
- BUT_IMAGE = (47 << 9),
- HISTOGRAM = (48 << 9),
- WAVEFORM = (49 << 9),
- VECTORSCOPE = (50 << 9),
- PROGRESSBAR = (51 << 9),
- SEARCH_MENU_UNLINK = (52 << 9),
- NODESOCKET = (53 << 9),
- SEPRLINE = (54 << 9),
- GRIP = (55 << 9),
+ UI_BTYPE_BUT = (1 << 9),
+ UI_BTYPE_ROW = (2 << 9),
+ UI_BTYPE_TEXT = (3 << 9),
+ UI_BTYPE_MENU = (4 << 9), /* dropdown list */
+ UI_BTYPE_BUT_MENU = (5 << 9),
+ UI_BTYPE_NUM = (6 << 9), /* number button */
+ UI_BTYPE_NUM_SLIDER = (7 << 9), /* number slider */
+ UI_BTYPE_TOGGLE = (8 << 9),
+ UI_BTYPE_TOGGLE_N = (9 << 9),
+ UI_BTYPE_ICON_TOGGLE = (10 << 9),
+ UI_BTYPE_ICON_TOGGLE_N = (11 << 9),
+ UI_BTYPE_BUT_TOGGLE = (12 << 9), /* same as regular toggle, but no on/off state displayed */
+ UI_BTYPE_CHECKBOX = (13 << 9), /* similar to toggle, display a 'tick' */
+ UI_BTYPE_CHECKBOX_N = (14 << 9),
+ UI_BTYPE_COLOR = (15 << 9),
+ UI_BTYPE_SCROLL = (18 << 9),
+ UI_BTYPE_BLOCK = (19 << 9),
+ UI_BTYPE_LABEL = (20 << 9),
+ UI_BTYPE_LINK = (22 << 9),
+ UI_BTYPE_INLINK = (23 << 9),
+ UI_BTYPE_KEY_EVENT = (24 << 9),
+ UI_BTYPE_HSVCUBE = (26 << 9),
+ UI_BTYPE_PULLDOWN = (27 << 9), /* menu (often used in headers), **_MENU /w different draw-type */
+ UI_BTYPE_ROUNDBOX = (28 << 9),
+ UI_BTYPE_COLORBAND = (30 << 9),
+ UI_BTYPE_UNITVEC = (31 << 9), /* sphere widget (used to input a unit-vector, aka normal) */
+ UI_BTYPE_CURVE = (32 << 9),
+ UI_BTYPE_LISTBOX = (36 << 9),
+ UI_BTYPE_LISTROW = (37 << 9),
+ UI_BTYPE_HSVCIRCLE = (38 << 9),
+ UI_BTYPE_TRACK_PREVIEW = (40 << 9),
+
+ /* buttons with value >= UI_BTYPE_SEARCH_MENU don't get undo pushes */
+ UI_BTYPE_SEARCH_MENU = (41 << 9),
+ UI_BTYPE_EXTRA = (42 << 9),
+ UI_BTYPE_HOTKEY_EVENT = (46 << 9),
+ UI_BTYPE_IMAGE = (47 << 9), /* non-interactive image, used for splash screen */
+ UI_BTYPE_HISTOGRAM = (48 << 9),
+ UI_BTYPE_WAVEFORM = (49 << 9),
+ UI_BTYPE_VECTORSCOPE = (50 << 9),
+ UI_BTYPE_PROGRESS_BAR = (51 << 9),
+ UI_BTYPE_NODE_SOCKET = (53 << 9),
+ UI_BTYPE_SEPR = (54 << 9),
+ UI_BTYPE_SEPR_LINE = (55 << 9),
+ UI_BTYPE_GRIP = (56 << 9), /* resize handle (resize uilist) */
} eButType;
#define BUTTYPE (63 << 9)
-/* gradient types, for color picker HSVCUBE etc */
+/* gradient types, for color picker UI_BTYPE_HSVCUBE etc */
#define UI_GRAD_SV 0
#define UI_GRAD_HV 1
#define UI_GRAD_HS 2
@@ -301,35 +299,45 @@ typedef enum {
* Functions to draw various shapes, taking theme settings into account.
* Used for code that draws its own UI style elements. */
-void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad);
-void uiSetRoundBox(int type);
-int uiGetRoundBox(void);
-void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad);
-void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
-void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float rad);
-void uiDrawBoxShade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
-void uiDrawBoxVerticalShade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight);
+void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad);
+void UI_draw_roundbox_corner_set(int type);
+int UI_draw_roundbox_corner_get(void);
+void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad);
+void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
+void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad);
+void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
+void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight);
+void UI_draw_text_underline(int pos_x, int pos_y, int len, int height);
+
+void UI_draw_safe_areas(
+ float x1, float x2, float y1, float y2,
+ const float title_aspect[2], const float action_aspect[2]);
/* state for scrolldrawing */
#define UI_SCROLL_PRESSED (1 << 0)
#define UI_SCROLL_ARROWS (1 << 1)
#define UI_SCROLL_NO_OUTLINE (1 << 2)
-void uiWidgetScrollDraw(struct uiWidgetColors *wcol, const struct rcti *rect, const struct rcti *slider, int state);
+void UI_draw_widget_scroll(struct uiWidgetColors *wcol, const struct rcti *rect, const struct rcti *slider, int state);
+
+/* Shortening string helper. */
+float UI_text_clip_middle_ex(
+ struct uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char rpart_sep);
/* Callbacks
*
- * uiBlockSetHandleFunc/ButmFunc are for handling events through a callback.
+ * UI_block_func_handle_set/ButmFunc are for handling events through a callback.
* HandleFunc gets the retval passed on, and ButmFunc gets a2. The latter is
* mostly for compatibility with older code.
*
- * uiButSetCompleteFunc is for tab completion.
+ * UI_but_func_complete_set is for tab completion.
*
* uiButSearchFunc is for name buttons, showing a popup with matches
*
- * uiBlockSetFunc and uiButSetFunc are callbacks run when a button is used,
+ * UI_block_func_set and UI_but_func_set are callbacks run when a button is used,
* in case events, operators or RNA are not sufficient to handle the button.
*
- * uiButSetNFunc will free the argument with MEM_freeN. */
+ * UI_but_funcN_set will free the argument with MEM_freeN. */
typedef struct uiSearchItems uiSearchItems;
@@ -338,6 +346,9 @@ typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char *origs
typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
typedef void (*uiButSearchFunc)(const struct bContext *C, void *arg, const char *str, uiSearchItems *items);
+/* Must return allocated string. */
+typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip);
+
typedef void (*uiBlockHandleFunc)(struct bContext *C, void *arg, int event);
/* Menu Callbacks */
@@ -348,30 +359,35 @@ typedef void (*uiMenuHandleFunc)(struct bContext *C, void *arg, int event);
/* Popup Menus
*
* Functions used to create popup menus. For more extended menus the
- * uiPupMenuBegin/End functions can be used to define own items with
+ * UI_popup_menu_begin/End functions can be used to define own items with
* the uiItem functions in between. If it is a simple confirmation menu
* or similar, popups can be created with a single function call. */
typedef struct uiPopupMenu uiPopupMenu;
-struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
-void uiPupMenuEnd(struct bContext *C, struct uiPopupMenu *head);
-struct uiLayout *uiPupMenuLayout(uiPopupMenu *head);
+struct uiPopupMenu *UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *head);
+struct uiLayout *UI_popup_menu_layout(uiPopupMenu *head);
-void uiPupMenuReports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
-bool uiPupMenuInvoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
+void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
+int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
/* Pie menus */
typedef struct uiPieMenu uiPieMenu;
-void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event);
-void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
- const char *propname, const struct wmEvent *event);
-void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path, const struct wmEvent *event);
-
-struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) ATTR_NONNULL();
-void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie);
-struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie);
+int UI_pie_menu_invoke(struct bContext *C, const char *idname, const struct wmEvent *event);
+int UI_pie_menu_invoke_from_operator_enum(
+ struct bContext *C, const char *title, const char *opname,
+ const char *propname, const struct wmEvent *event);
+int UI_pie_menu_invoke_from_rna_enum(
+ struct bContext *C, const char *title,
+ const char *path, const struct wmEvent *event);
+
+struct uiPieMenu *UI_pie_menu_begin(
+ struct bContext *C, const char *title, int icon,
+ const struct wmEvent *event) ATTR_NONNULL();
+void UI_pie_menu_end(struct bContext *C, uiPieMenu *pie);
+struct uiLayout *UI_pie_menu_layout(struct uiPieMenu *pie);
/* Popup Blocks
*
* Functions used to create popup blocks. These are like popup menus
@@ -380,12 +396,12 @@ struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie);
typedef uiBlock * (*uiBlockCreateFunc)(struct bContext *C, struct ARegion *ar, void *arg1);
typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1);
-void uiPupBlock(struct bContext *C, uiBlockCreateFunc func, void *arg);
-void uiPupBlockO(struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext);
-void uiPupBlockEx(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
+void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg);
+void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext);
+void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
/* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */
-void uiPupBlockClose(struct bContext *C, uiBlock *block);
+void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
/* Blocks
*
@@ -398,29 +414,29 @@ void uiPupBlockClose(struct bContext *C, uiBlock *block);
*
* */
-uiBlock *uiBeginBlock(const struct bContext *C, struct ARegion *region, const char *name, short dt);
-void uiEndBlock_ex(const struct bContext *C, uiBlock *block, const int xy[2]);
-void uiEndBlock(const struct bContext *C, uiBlock *block);
-void uiDrawBlock(const struct bContext *C, struct uiBlock *block);
-void uiBlockUpdateFromOld(const struct bContext *C, struct uiBlock *block);
+uiBlock *UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, short dt);
+void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2]);
+void UI_block_end(const struct bContext *C, uiBlock *block);
+void UI_block_draw(const struct bContext *C, struct uiBlock *block);
+void UI_block_update_from_old(const struct bContext *C, struct uiBlock *block);
-uiBlock *uiGetBlock(const char *name, struct ARegion *ar);
+uiBlock *UI_block_find_in_region(const char *name, struct ARegion *ar);
-void uiBlockSetEmboss(uiBlock *block, char dt);
+void UI_block_emboss_set(uiBlock *block, char dt);
-void uiFreeBlock(const struct bContext *C, uiBlock *block);
-void uiFreeBlocks(const struct bContext *C, struct ListBase *lb);
-void uiFreeInactiveBlocks(const struct bContext *C, struct ListBase *lb);
-void uiFreeActiveButtons(const struct bContext *C, struct bScreen *screen);
+void UI_block_free(const struct bContext *C, uiBlock *block);
+void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
+void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb);
+void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen);
-void uiBlockSetRegion(uiBlock *block, struct ARegion *region);
+void UI_block_region_set(uiBlock *block, struct ARegion *region);
-void uiBlockSetButLock(uiBlock *block, bool val, const char *lockstr);
-void uiBlockClearButLock(uiBlock *block);
+void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr);
+void UI_block_lock_clear(uiBlock *block);
/* automatic aligning, horiz or verical */
-void uiBlockBeginAlign(uiBlock *block);
-void uiBlockEndAlign(uiBlock *block);
+void UI_block_align_begin(uiBlock *block);
+void UI_block_align_end(uiBlock *block);
/* block bounds/position calculation */
typedef enum {
@@ -433,45 +449,54 @@ typedef enum {
UI_BLOCK_BOUNDS_PIE_CENTER,
} eBlockBoundsCalc;
-void uiBoundsBlock(struct uiBlock *block, int addval);
-void uiTextBoundsBlock(uiBlock *block, int addval);
-void uiPopupBoundsBlock(uiBlock *block, int addval, int mx, int my);
-void uiMenuPopupBoundsBlock(uiBlock *block, int addvall, int mx, int my);
-void uiCenteredBoundsBlock(uiBlock *block, int addval);
-void uiExplicitBoundsBlock(uiBlock *block, int minx, int miny, int maxx, int maxy);
+void UI_block_bounds_set_normal(struct uiBlock *block, int addval);
+void UI_block_bounds_set_text(uiBlock *block, int addval);
+void UI_block_bounds_set_popup(uiBlock *block, int addval, int mx, int my);
+void UI_block_bounds_set_menu(uiBlock *block, int addvall, int mx, int my);
+void UI_block_bounds_set_centered(uiBlock *block, int addval);
+void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy);
-int uiBlocksGetYMin(struct ListBase *lb);
+int UI_blocklist_min_y_get(struct ListBase *lb);
-void uiBlockSetDirection(uiBlock *block, char direction);
-void uiBlockFlipOrder(uiBlock *block);
-void uiBlockSetFlag(uiBlock *block, int flag);
-void uiBlockClearFlag(uiBlock *block, int flag);
+void UI_block_direction_set(uiBlock *block, char direction);
+void UI_block_order_flip(uiBlock *block);
+void UI_block_flag_enable(uiBlock *block, int flag);
+void UI_block_flag_disable(uiBlock *block, int flag);
-int uiButGetRetVal(uiBut *but);
+int UI_but_return_value_get(uiBut *but);
-void uiButSetDragID(uiBut *but, struct ID *id);
-void uiButSetDragRNA(uiBut *but, struct PointerRNA *ptr);
-void uiButSetDragPath(uiBut *but, const char *path);
-void uiButSetDragName(uiBut *but, const char *name);
-void uiButSetDragValue(uiBut *but);
-void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale);
+void UI_but_drag_set_id(uiBut *but, struct ID *id);
+void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
+void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free);
+void UI_but_drag_set_name(uiBut *but, const char *name);
+void UI_but_drag_set_value(uiBut *but);
+void UI_but_drag_set_image(
+ uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale, const bool use_free);
bool UI_but_active_drop_name(struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
-void uiButSetFlag(uiBut *but, int flag);
-void uiButClearFlag(uiBut *but, int flag);
+void UI_but_flag_enable(uiBut *but, int flag);
+void UI_but_flag_disable(uiBut *but, int flag);
-void uiButSetDrawFlag(uiBut *but, int flag);
-void uiButClearDrawFlag(uiBut *but, int flag);
+void UI_but_drawflag_enable(uiBut *but, int flag);
+void UI_but_drawflag_disable(uiBut *but, int flag);
-void uiButSetMenuFromPulldown(uiBut *but);
+void UI_but_type_set_menu_from_pulldown(uiBut *but);
/* special button case, only draw it when used actively, for outliner etc */
-bool uiButActiveOnly(const struct bContext *C, struct ARegion *ar, uiBlock *block, uiBut *but);
+bool UI_but_active_only(const struct bContext *C, struct ARegion *ar, uiBlock *block, uiBut *but);
-void uiButExecute(const struct bContext *C, uiBut *but);
+void UI_but_execute(const struct bContext *C, uiBut *but);
+bool UI_but_online_manual_id(
+ const uiBut *but,
+ char *r_str, size_t maxlength)
+ ATTR_WARN_UNUSED_RESULT;
+bool UI_but_online_manual_id_from_active(
+ const struct bContext *C,
+ char *r_str, size_t maxlength)
+ ATTR_WARN_UNUSED_RESULT;
/* Buttons
*
@@ -544,10 +569,10 @@ uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcon
uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, int opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip);
/* for passing inputs to ButO buttons */
-struct PointerRNA *uiButGetOperatorPtrRNA(uiBut *but);
+struct PointerRNA *UI_but_operator_ptr_get(uiBut *but);
-void uiButSetUnitType(uiBut *but, const int unit_type);
-int uiButGetUnitType(const uiBut *but);
+void UI_but_unit_type_set(uiBut *but, const int unit_type);
+int UI_but_unit_type_get(const uiBut *but);
enum {
BUT_GET_RNAPROP_IDENTIFIER = 1,
@@ -572,7 +597,7 @@ typedef struct uiStringInfo {
/* Note: Expects pointers to uiStringInfo structs as parameters.
* Will fill them with translated strings, when possible.
* Strings in uiStringInfo must be MEM_freeN'ed by caller. */
-void uiButGetStrInfo(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0);
+void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0);
/* Edit i18n stuff. */
/* Name of the main py op from i18n addon. */
@@ -602,8 +627,8 @@ void uiButGetStrInfo(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0);
#define UI_ID_PREVIEWS (1 << 11)
#define UI_ID_FULL (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL)
-int uiIconFromID(struct ID *id);
-int uiIconFromReportType(int type);
+int UI_icon_from_id(struct ID *id);
+int UI_icon_from_report_type(int type);
uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip);
uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip);
@@ -632,41 +657,45 @@ int uiDefAutoButsRNA(uiLayout *layout, struct PointerRNA *ptr, bool (*check_prop
* Game engine logic brick links. Non-functional currently in 2.5,
* code to handle and draw these is disabled internally. */
-void uiSetButLink(struct uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to);
+void UI_but_link_set(struct uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to);
-void uiComposeLinks(uiBlock *block);
-uiBut *uiFindInlink(uiBlock *block, void *poin);
+void UI_block_links_compose(uiBlock *block);
+uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin);
/* use inside searchfunc to add items */
-bool uiSearchItemAdd(uiSearchItems *items, const char *name, void *poin, int iconid);
+bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid);
/* bfunc gets search item *poin as arg2, or if NULL the old string */
-void uiButSetSearchFunc(uiBut *but, uiButSearchFunc sfunc, void *arg1, uiButHandleFunc bfunc, void *active);
+void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg1, uiButHandleFunc bfunc, void *active);
/* height in pixels, it's using hardcoded values still */
-int uiSearchBoxHeight(void);
-int uiSearchBoxWidth(void);
+int UI_searchbox_size_y(void);
+int UI_searchbox_size_x(void);
/* check if a string is in an existing search box */
-int uiSearchItemFindIndex(uiSearchItems *items, const char *name);
+int UI_search_items_find_index(uiSearchItems *items, const char *name);
+
+void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
+void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
+void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
+void UI_block_funcN_set(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2);
-void uiBlockSetHandleFunc(uiBlock *block, uiBlockHandleFunc func, void *arg);
-void uiBlockSetButmFunc(uiBlock *block, uiMenuHandleFunc func, void *arg);
-void uiBlockSetFunc(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
-void uiBlockSetNFunc(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2);
+void UI_but_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1);
+void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2);
+void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2);
-void uiButSetRenameFunc(uiBut *but, uiButHandleRenameFunc func, void *arg1);
-void uiButSetFunc(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2);
-void uiButSetNFunc(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2);
+void UI_but_func_complete_set(uiBut *but, uiButCompleteFunc func, void *arg);
-void uiButSetCompleteFunc(uiBut *but, uiButCompleteFunc func, void *arg);
+void UI_but_func_drawextra_set(
+ uiBlock *block,
+ void (*func)(const struct bContext *C, void *, void *, void *, struct rcti *rect),
+ void *arg1, void *arg2);
-void uiBlockSetDrawExtraFunc(uiBlock *block,
- void (*func)(const struct bContext *C, void *, void *, void *, struct rcti *rect),
- void *arg1, void *arg2);
+void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN);
+void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C, struct ARegion *ar,
const void *rna_poin_data, const char *rna_prop_id);
bool UI_textbutton_activate_but(const struct bContext *C, uiBut *but);
-void uiButSetFocusOnEnter(struct wmWindow *win, uiBut *but);
+void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
/* Autocomplete
*
@@ -680,9 +709,9 @@ typedef struct AutoComplete AutoComplete;
#define AUTOCOMPLETE_FULL_MATCH 1
#define AUTOCOMPLETE_PARTIAL_MATCH 2
-AutoComplete *autocomplete_begin(const char *startname, size_t maxlen);
-void autocomplete_do_name(AutoComplete *autocpl, const char *name);
-int autocomplete_end(AutoComplete *autocpl, char *autoname);
+AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen);
+void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name);
+int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
/* Panels
*
@@ -690,15 +719,15 @@ int autocomplete_end(AutoComplete *autocpl, char *autoname);
* could use a good cleanup, though how they will function in 2.5 is
* not clear yet so we postpone that. */
-void uiBeginPanels(const struct bContext *C, struct ARegion *ar);
-void uiEndPanels(const struct bContext *C, struct ARegion *ar, int *x, int *y);
-void uiDrawPanels(const struct bContext *C, struct ARegion *ar);
+void UI_panels_begin(const struct bContext *C, struct ARegion *ar);
+void UI_panels_end(const struct bContext *C, struct ARegion *ar, int *x, int *y);
+void UI_panels_draw(const struct bContext *C, struct ARegion *ar);
-struct Panel *uiPanelFindByType(struct ARegion *ar, struct PanelType *pt);
-struct Panel *uiBeginPanel(struct ScrArea *sa, struct ARegion *ar, uiBlock *block,
- struct PanelType *pt, struct Panel *pa, bool *r_open);
-void uiEndPanel(uiBlock *block, int width, int height);
-void uiScalePanels(struct ARegion *ar, float new_width);
+struct Panel *UI_panel_find_by_type(struct ARegion *ar, struct PanelType *pt);
+struct Panel *UI_panel_begin(struct ScrArea *sa, struct ARegion *ar, uiBlock *block,
+ struct PanelType *pt, struct Panel *pa, bool *r_open);
+void UI_panel_end(uiBlock *block, int width, int height);
+void UI_panels_scale(struct ARegion *ar, float new_width);
bool UI_panel_category_is_visible(struct ARegion *ar);
void UI_panel_category_add(struct ARegion *ar, const char *name);
@@ -717,10 +746,10 @@ void UI_panel_category_draw_all(struct ARegion *ar, const
* handling WM events. Mostly this is done automatic by modules such
* as screen/ if ED_KEYMAP_UI is set, or internally in popup functions. */
-void UI_add_region_handlers(struct ListBase *handlers);
-void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click);
-void UI_remove_popup_handlers(struct ListBase *handlers, uiPopupBlockHandle *popup);
-void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers);
+void UI_region_handlers_add(struct ListBase *handlers);
+void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const char flag);
+void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup);
+void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers);
/* Module
*
@@ -797,9 +826,9 @@ enum {
/* not apart of the corner flags but mixed in some functions */
#define UI_RB_ALPHA (UI_CNR_ALL + 1)
-uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, struct uiStyle *style);
-void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout);
-void uiBlockLayoutResolve(uiBlock *block, int *x, int *y);
+uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, struct uiStyle *style);
+void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
+void UI_block_layout_resolve(uiBlock *block, int *x, int *y);
uiBlock *uiLayoutGetBlock(uiLayout *layout);
@@ -810,7 +839,7 @@ const char *uiLayoutIntrospect(uiLayout *layout); // XXX - testing
void uiLayoutOperatorButs(const struct bContext *C, struct uiLayout *layout, struct wmOperator *op,
bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
const char label_align, const short flag);
-struct MenuType *uiButGetMenuType(uiBut *but);
+struct MenuType *UI_but_menutype_get(uiBut *but);
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext);
void uiLayoutSetActive(uiLayout *layout, bool active);
@@ -861,7 +890,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id);
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand);
-void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int show_labels, float icon_scale);
void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
@@ -873,11 +902,15 @@ void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *prop
PointerRNA *used_ptr, const char *used_propname, int active_layer);
void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
PointerRNA *used_ptr, const char *used_propname, int active_state);
-void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact);
+void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact, int multiview);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
+void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
+void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
+void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr);
void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser);
+void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser);
void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
-void uiOperatorSearch_But(uiBut *but);
+void UI_but_func_operator_search(uiBut *but);
void uiTemplateOperatorSearch(uiLayout *layout);
void uiTemplateHeader3D(uiLayout *layout, struct bContext *C);
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
@@ -890,7 +923,8 @@ void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr,
- const char *active_propname, int rows, int maxrows, int layout_type, int columns);
+ const char *active_propname, const char *item_dyntip_propname,
+ int rows, int maxrows, int layout_type, int columns);
void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
@@ -921,6 +955,7 @@ PointerRNA uiItemFullO(uiLayout *layout, const char *idname, const char *name, i
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon);
void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int flag, const char *name, int icon);
+void uiItemEnumR_prop(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, PropertyRNA *prop, int value);
void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value);
void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon);
void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
@@ -935,6 +970,7 @@ void uiItemS(uiLayout *layout); /* separator */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg);
void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, const char *propname, const char *name, int icon);
+void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon);
void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon);
/* UI Operators */
@@ -943,32 +979,42 @@ typedef struct uiDragColorHandle {
bool gamma_corrected;
} uiDragColorHandle;
-void UI_buttons_operatortypes(void);
+void ED_button_operatortypes(void);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
+bool UI_context_copy_to_selected_list(
+ struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
+ struct ListBase *r_lb, bool *r_use_path_from_id, char **r_path);
+
/* Helpers for Operators */
-uiBut *uiContextActiveButton(const struct bContext *C);
-void uiContextActiveProperty(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
-void uiContextActivePropertyHandle(struct bContext *C);
-struct wmOperator *uiContextActiveOperator(const struct bContext *C);
-void uiContextAnimUpdate(const struct bContext *C);
-void uiFileBrowseContextProperty(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
-void uiIDContextProperty(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+uiBut *UI_context_active_but_get(const struct bContext *C);
+void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
+void UI_context_active_but_prop_handle(struct bContext *C);
+struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
+void UI_context_update_anim_flag(const struct bContext *C);
+void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
+void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
/* Styled text draw */
-void uiStyleFontSet(struct uiFontStyle *fs);
-void uiStyleFontDrawExt(struct uiFontStyle *fs, const struct rcti *rect, const char *str,
- size_t len, float *r_xofs, float *r_yofs);
-void uiStyleFontDraw(struct uiFontStyle *fs, const struct rcti *rect, const char *str);
-void uiStyleFontDrawRotated(struct uiFontStyle *fs, const struct rcti *rect, const char *str);
+void UI_fontstyle_set(const struct uiFontStyle *fs);
+void UI_fontstyle_draw_ex(
+ const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
+ size_t len, float *r_xofs, float *r_yofs);
+void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
+void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
+void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str);
+void UI_fontstyle_draw_simple_backdrop(
+ const struct uiFontStyle *fs, float x, float y, const char *str,
+ const unsigned char fg[4], const unsigned char bg[4]);
+
+int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str);
+int UI_fontstyle_height_max(const struct uiFontStyle *fs);
-int UI_GetStringWidth(const char *str); // XXX temp
-void UI_DrawString(float x, float y, const char *str); // XXX temp
-void UI_DrawTriIcon(float x, float y, char dir);
+void UI_draw_icon_tri(float x, float y, char dir);
-uiStyle *UI_GetStyle(void); /* use for fonts etc */
-uiStyle *UI_GetStyleDraw(void); /* DPI scaled settings for drawing */
+struct uiStyle *UI_style_get(void); /* use for fonts etc */
+struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */
/* linker workaround ack! */
void UI_template_fix_linking(void);
@@ -988,12 +1034,18 @@ void UI_butstore_free(uiBlock *block, uiButStore *bs);
bool UI_butstore_is_valid(uiButStore *bs);
bool UI_butstore_is_registered(uiBlock *block, uiBut *but);
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
+bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* Float precision helpers */
#define UI_PRECISION_FLOAT_MAX 7
+/* For float buttons the 'step' (or a1), is scaled */
+#define UI_PRECISION_FLOAT_SCALE 0.01f
+
+/* Typical UI text */
+#define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget)
-int uiFloatPrecisionCalc(int prec, double value);
+int UI_calc_float_precision(int prec, double value);
#endif /* __UI_INTERFACE_H__ */
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 6104505ef58..945ac1b6db9 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -33,15 +33,13 @@
#define __UI_INTERFACE_ICONS_H__
struct bContext;
-struct Image;
-struct ImBuf;
-struct World;
-struct Tex;
-struct Lamp;
-struct Material;
+struct ID;
+struct Scene;
struct PreviewImage;
struct PointerRNA;
+enum eIconSizes;
+
typedef struct IconFile {
struct IconFile *next, *prev;
char filename[256]; /* FILE_MAXFILE size */
@@ -54,7 +52,7 @@ typedef struct IconFile {
#define ICON_DEFAULT_HEIGHT_SCALE ((int)(UI_UNIT_Y * 0.8f))
#define ICON_DEFAULT_WIDTH_SCALE ((int)(UI_UNIT_X * 0.8f))
-#define PREVIEW_DEFAULT_HEIGHT 96
+#define PREVIEW_DEFAULT_HEIGHT 128
/*
* Resizable Icons for Blender
@@ -63,10 +61,14 @@ void UI_icons_init(int first_dyn_id);
int UI_icon_get_width(int icon_id);
int UI_icon_get_height(int icon_id);
+void UI_id_icon_render(
+ const struct bContext *C, struct Scene *scene, struct ID *id, const bool big, const bool use_job);
+int UI_preview_render_size(enum eIconSizes size);
+
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_preview(float x, float y, int icon_id);
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect);
-void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size);
+void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size);
void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha);
void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3]);
@@ -80,5 +82,6 @@ int UI_iconfile_get_index(const char *filename);
struct PreviewImage *UI_icon_to_preview(int icon_id);
int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, const bool big);
+int UI_idcode_icon_get(const int idcode);
#endif /* __UI_INTERFACE_ICONS_H__ */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 872bd32b75b..2b19b6180e5 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -87,6 +87,7 @@ enum {
TH_GRID,
TH_WIRE,
+ TH_WIRE_INNER,
TH_WIRE_EDIT,
TH_SELECT,
TH_ACTIVE,
@@ -110,6 +111,8 @@ enum {
TH_FACE_DOT,
TH_FACEDOT_SIZE,
TH_CFRAME,
+ TH_TIME_KEYFRAME,
+ TH_TIME_GP_KEYFRAME,
TH_NURB_ULINE,
TH_NURB_VLINE,
TH_NURB_SEL_ULINE,
@@ -206,6 +209,10 @@ enum {
TH_HANDLE_VERTEX_SELECT,
TH_HANDLE_VERTEX_SIZE,
+ TH_GP_VERTEX,
+ TH_GP_VERTEX_SELECT,
+ TH_GP_VERTEX_SIZE,
+
TH_DOPESHEET_CHANNELOB,
TH_DOPESHEET_CHANNELSUBOB,
@@ -265,6 +272,8 @@ enum {
TH_NLA_SOUND,
TH_NLA_SOUND_SEL,
+ TH_WIDGET_EMBOSS,
+
TH_AXIS_X, /* X/Y/Z Axis */
TH_AXIS_Y,
TH_AXIS_Z,
@@ -284,13 +293,22 @@ enum {
TH_INFO_DEBUG,
TH_INFO_DEBUG_TEXT,
TH_VIEW_OVERLAY,
+
+ TH_V3D_CLIPPING_BORDER,
+
+ TH_METADATA_BG,
+ TH_METADATA_TEXT
};
/* XXX WARNING: previous is saved in file, so do not change order! */
/* specific defines per space should have higher define values */
struct bTheme;
-struct PointerRNA;
+
+struct bThemeState {
+ struct bTheme *theme;
+ int spacetype, regionid;
+};
// THE CODERS API FOR THEMES:
@@ -345,12 +363,18 @@ void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned
// clear the openGL ClearColor using the input colorid
void UI_ThemeClearColor(int colorid);
+// clear the openGL ClearColor using the input colorid using optional transparency
+void UI_ThemeClearColorAlpha(int colorid, float alpha);
+
// internal (blender) usage only, for init and set active
void UI_SetTheme(int spacetype, int regionid);
// get current theme
struct bTheme *UI_GetTheme(void);
+void UI_Theme_Store(struct bThemeState *theme_state);
+void UI_Theme_Restore(struct bThemeState *theme_state);
+
// return shadow width outside menus and popups */
int UI_ThemeMenuShadowWidth(void);
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index cb7cf3ee404..2c8f5f6590a 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -162,7 +162,7 @@ void UI_view2d_zoom_cache_reset(void);
/* view matrix operations */
void UI_view2d_view_ortho(struct View2D *v2d);
-void UI_view2d_view_orthoSpecial(struct ARegion *ar, struct View2D *v2d, short xaxis);
+void UI_view2d_view_orthoSpecial(struct ARegion *ar, struct View2D *v2d, const bool xaxis);
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
@@ -233,6 +233,6 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf);
void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar,
const struct rctf *cur, const int smooth_viewtx);
+#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#endif /* __UI_VIEW2D_H__ */
-
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index e13517adbb3..3efb4921bbe 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../gpu
../../imbuf
../../makesdna
@@ -30,6 +31,7 @@ set(INC
../../python
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -70,4 +72,12 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+if(WIN32)
+ if(WITH_INPUT_IME)
+ add_definitions(-DWITH_INPUT_IME)
+ endif()
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript
index 1936e17a7bb..ea6f35c54e6 100644
--- a/source/blender/editors/interface/SConscript
+++ b/source/blender/editors/interface/SConscript
@@ -31,11 +31,13 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../gpu',
'../../imbuf',
'../../makesdna',
@@ -46,6 +48,11 @@ incs = [
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
+ if env['WITH_BF_IME']:
+ defs.append('WITH_INPUT_IME')
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index b987f970b9e..78021612195 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -58,7 +59,7 @@
#include "BIF_gl.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "UI_interface.h"
@@ -76,20 +77,20 @@
#include "interface_intern.h"
-/* avoid unneeded calls to ui_get_but_val */
+/* avoid unneeded calls to ui_but_value_get */
#define UI_BUT_VALUE_UNSET DBL_MAX
-#define UI_GET_BUT_VALUE_INIT(_but, _value) if (_value == DBL_MAX) { (_value) = ui_get_but_val(_but); } (void)0
+#define UI_GET_BUT_VALUE_INIT(_but, _value) if (_value == DBL_MAX) { (_value) = ui_but_value_get(_but); } (void)0
#define B_NOP -1
-/*
- * a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt
+/**
+ * a full doc with API notes can be found in 'blender/doc/guides/interface_API.txt'
*
- * uiBlahBlah() external function
- * ui_blah_blah() internal function
+ * `uiBlahBlah()` external function.
+ * `ui_blah_blah()` internal function.
*/
-static void ui_free_but(const bContext *C, uiBut *but);
+static void ui_but_free(const bContext *C, uiBut *but);
bool ui_block_is_menu(const uiBlock *block)
{
@@ -103,17 +104,17 @@ bool ui_block_is_pie_menu(const uiBlock *block)
return ((block->flag & UI_BLOCK_RADIAL) != 0);
}
-static bool ui_is_but_unit_radians_ex(UnitSettings *unit, const int unit_type)
+static bool ui_but_is_unit_radians_ex(UnitSettings *unit, const int unit_type)
{
return (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION);
}
-static bool ui_is_but_unit_radians(const uiBut *but)
+static bool ui_but_is_unit_radians(const uiBut *but)
{
UnitSettings *unit = but->block->unit;
- const int unit_type = uiButGetUnitType(but);
+ const int unit_type = UI_but_unit_type_get(but);
- return ui_is_but_unit_radians_ex(unit, unit_type);
+ return ui_but_is_unit_radians_ex(unit, unit_type);
}
/* ************* window matrix ************** */
@@ -209,6 +210,28 @@ void ui_window_to_region(const ARegion *ar, int *x, int *y)
*y -= ar->winrct.ymin;
}
+void ui_region_to_window(const ARegion *ar, int *x, int *y)
+{
+ *x += ar->winrct.xmin;
+ *y += ar->winrct.ymin;
+}
+
+/**
+ * Popups will add a margin to #ARegion.winrct for shadow,
+ * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
+ */
+void ui_region_winrct_get_no_margin(const struct ARegion *ar, struct rcti *r_rect)
+{
+ uiBlock *block = ar->uiblocks.first;
+ if (block && (block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_RADIAL) == 0) {
+ BLI_rcti_rctf_copy_floor(r_rect, &block->rect);
+ BLI_rcti_translate(r_rect, ar->winrct.xmin, ar->winrct.ymin);
+ }
+ else {
+ *r_rect = ar->winrct;
+ }
+}
+
/* ******************* block calc ************************* */
void ui_block_translate(uiBlock *block, int x, int y)
@@ -222,16 +245,16 @@ void ui_block_translate(uiBlock *block, int x, int y)
BLI_rctf_translate(&block->rect, x, y);
}
-static void ui_text_bounds_block(uiBlock *block, float offset)
+static void ui_block_bounds_calc_text(uiBlock *block, float offset)
{
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
uiBut *bt, *init_col_bt, *col_bt;
int i = 0, j, x1addval = offset;
- uiStyleFontSet(&style->widget);
+ UI_fontstyle_set(&style->widget);
for (init_col_bt = bt = block->buttons.first; bt; bt = bt->next) {
- if (!ELEM(bt->type, SEPR, SEPRLINE)) {
+ if (!ELEM(bt->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
j = BLF_width(style->widget.uifont_id, bt->drawstr, sizeof(bt->drawstr));
if (j > i)
@@ -244,7 +267,7 @@ static void ui_text_bounds_block(uiBlock *block, float offset)
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = x1addval + i + block->bounds;
- ui_check_but(col_bt); /* clips text again */
+ ui_but_update(col_bt); /* clips text again */
}
/* And we prepare next column. */
@@ -259,11 +282,11 @@ static void ui_text_bounds_block(uiBlock *block, float offset)
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
- ui_check_but(col_bt); /* clips text again */
+ ui_but_update(col_bt); /* clips text again */
}
}
-void ui_bounds_block(uiBlock *block)
+void ui_block_bounds_calc(uiBlock *block)
{
uiBut *bt;
int xof;
@@ -292,7 +315,7 @@ void ui_bounds_block(uiBlock *block)
/* hardcoded exception... but that one is annoying with larger safety */
bt = block->buttons.first;
- if (bt && strncmp(bt->str, "ERROR", 5) == 0) xof = 10;
+ if (bt && STREQLEN(bt->str, "ERROR", 5)) xof = 10;
else xof = 40;
block->safety.xmin = block->rect.xmin - xof;
@@ -301,7 +324,7 @@ void ui_bounds_block(uiBlock *block)
block->safety.ymax = block->rect.ymax + xof;
}
-static void ui_centered_bounds_block(wmWindow *window, uiBlock *block)
+static void ui_block_bounds_calc_centered(wmWindow *window, uiBlock *block)
{
int xmax, ymax;
int startx, starty;
@@ -313,7 +336,7 @@ static void ui_centered_bounds_block(wmWindow *window, uiBlock *block)
xmax = WM_window_pixels_x(window);
ymax = WM_window_pixels_y(window);
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
width = BLI_rctf_size_x(&block->rect);
height = BLI_rctf_size_y(&block->rect);
@@ -324,11 +347,11 @@ static void ui_centered_bounds_block(wmWindow *window, uiBlock *block)
ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
/* now recompute bounds and safety */
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
}
-static void ui_centered_pie_bounds_block(uiBlock *block)
+static void ui_block_bounds_calc_centered_pie(uiBlock *block)
{
const int xy[2] = {
block->pie_data.pie_center_spawned[0],
@@ -338,11 +361,12 @@ static void ui_centered_pie_bounds_block(uiBlock *block)
ui_block_translate(block, xy[0], xy[1]);
/* now recompute bounds and safety */
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
}
-static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
- eBlockBoundsCalc bounds_calc, const int xy[2])
+static void ui_block_bounds_calc_popup(
+ wmWindow *window, uiBlock *block,
+ eBlockBoundsCalc bounds_calc, const int xy[2])
{
int startx, starty, endx, endy, width, height, oldwidth, oldheight;
int oldbounds, xmax, ymax;
@@ -351,7 +375,7 @@ static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
oldbounds = block->bounds;
/* compute mouse position with user defined offset */
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
xmax = WM_window_pixels_x(window);
ymax = WM_window_pixels_y(window);
@@ -363,13 +387,13 @@ static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
if (bounds_calc == UI_BLOCK_BOUNDS_POPUP_MENU) {
if (block->flag & UI_BLOCK_LOOP) {
block->bounds = 2.5f * UI_UNIT_X;
- ui_text_bounds_block(block, block->rect.xmin);
+ ui_block_bounds_calc_text(block, block->rect.xmin);
}
}
/* next we recompute bounds */
block->bounds = oldbounds;
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
/* and we adjust the position to fit within window */
width = BLI_rctf_size_x(&block->rect);
@@ -380,7 +404,7 @@ static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
oldheight = oldheight > 0 ? oldheight : MAX2(1, height);
/* offset block based on mouse position, user offset is scaled
- * along in case we resized the block in ui_text_bounds_block */
+ * along in case we resized the block in ui_block_bounds_calc_text */
startx = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth;
starty = xy[1] + block->rect.ymin + (block->my * height) / oldheight;
@@ -404,11 +428,11 @@ static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
/* now recompute bounds and safety */
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
}
/* used for various cases */
-void uiBoundsBlock(uiBlock *block, int addval)
+void UI_block_bounds_set_normal(uiBlock *block, int addval)
{
if (block == NULL)
return;
@@ -418,14 +442,14 @@ void uiBoundsBlock(uiBlock *block, int addval)
}
/* used for pulldowns */
-void uiTextBoundsBlock(uiBlock *block, int addval)
+void UI_block_bounds_set_text(uiBlock *block, int addval)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_TEXT;
}
/* used for block popups */
-void uiPopupBoundsBlock(uiBlock *block, int addval, int mx, int my)
+void UI_block_bounds_set_popup(uiBlock *block, int addval, int mx, int my)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_POPUP_MOUSE;
@@ -434,7 +458,7 @@ void uiPopupBoundsBlock(uiBlock *block, int addval, int mx, int my)
}
/* used for menu popups */
-void uiMenuPopupBoundsBlock(uiBlock *block, int addval, int mx, int my)
+void UI_block_bounds_set_menu(uiBlock *block, int addval, int mx, int my)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_POPUP_MENU;
@@ -443,13 +467,13 @@ void uiMenuPopupBoundsBlock(uiBlock *block, int addval, int mx, int my)
}
/* used for centered popups, i.e. splash */
-void uiCenteredBoundsBlock(uiBlock *block, int addval)
+void UI_block_bounds_set_centered(uiBlock *block, int addval)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_POPUP_CENTER;
}
-void uiExplicitBoundsBlock(uiBlock *block, int minx, int miny, int maxx, int maxy)
+void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy)
{
block->rect.xmin = minx;
block->rect.ymin = miny;
@@ -458,21 +482,21 @@ void uiExplicitBoundsBlock(uiBlock *block, int minx, int miny, int maxx, int max
block->bounds_type = UI_BLOCK_BOUNDS_NONE;
}
-static int ui_but_float_precision(uiBut *but, double value)
+static int ui_but_calc_float_precision(uiBut *but, double value)
{
int prec = (int)but->a2;
/* first check for various special cases:
* * If button is radians, we want additional precision (see T39861).
* * If prec is not set, we fallback to a simple default */
- if (ui_is_but_unit_radians(but) && prec < 5) {
+ if (ui_but_is_unit_radians(but) && prec < 5) {
prec = 5;
}
else if (prec == -1) {
prec = (but->hardmax < 10.001f) ? 3 : 2;
}
- return uiFloatPrecisionCalc(prec, value);
+ return UI_calc_float_precision(prec, value);
}
/* ************** LINK LINE DRAWING ************* */
@@ -507,14 +531,14 @@ static void ui_draw_links(uiBlock *block)
uiBut *but;
uiLinkLine *line;
- /* Draw the grey out lines. Do this first so they appear at the
+ /* Draw the gray out lines. Do this first so they appear at the
* bottom of inactive or active lines.
* As we go, remember if we see any active or selected lines. */
bool found_selectline = false;
bool found_activeline = false;
for (but = block->buttons.first; but; but = but->next) {
- if (but->type == LINK && but->link) {
+ if (but->type == UI_BTYPE_LINK && but->link) {
for (line = but->link->lines.first; line; line = line->next) {
if (!(line->from->flag & UI_ACTIVE) && !(line->to->flag & UI_ACTIVE)) {
if (line->deactive)
@@ -531,7 +555,7 @@ static void ui_draw_links(uiBlock *block)
/* Draw the inactive lines (lines with neither button being hovered over) */
for (but = block->buttons.first; but; but = but->next) {
- if (but->type == LINK && but->link) {
+ if (but->type == UI_BTYPE_LINK && but->link) {
for (line = but->link->lines.first; line; line = line->next) {
if (!(line->from->flag & UI_ACTIVE) && !(line->to->flag & UI_ACTIVE)) {
if (!line->deactive)
@@ -542,10 +566,10 @@ static void ui_draw_links(uiBlock *block)
}
/* Draw any active lines (lines with either button being hovered over).
- * Do this last so they appear on top of inactive and grey out lines. */
+ * Do this last so they appear on top of inactive and gray out lines. */
if (found_activeline) {
for (but = block->buttons.first; but; but = but->next) {
- if (but->type == LINK && but->link) {
+ if (but->type == UI_BTYPE_LINK && but->link) {
for (line = but->link->lines.first; line; line = line->next) {
if ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE))
ui_draw_linkline(line, !found_selectline, false);
@@ -603,8 +627,8 @@ static void ui_but_update_linklines(uiBlock *block, uiBut *oldbut, uiBut *newbut
uiLinkLine *line;
uiBut *but;
- /* if active button is LINK */
- if (newbut->type == LINK && newbut->link) {
+ /* if active button is UI_BTYPE_LINK */
+ if (newbut->type == UI_BTYPE_LINK && newbut->link) {
SWAP(uiLink *, oldbut->link, newbut->link);
@@ -618,7 +642,7 @@ static void ui_but_update_linklines(uiBlock *block, uiBut *oldbut, uiBut *newbut
/* check all other button links */
for (but = block->buttons.first; but; but = but->next) {
- if (but != newbut && but->type == LINK && but->link) {
+ if (but != newbut && but->type == UI_BTYPE_LINK && but->link) {
for (line = but->link->lines.first; line; line = line->next) {
if (line->to == newbut)
line->to = oldbut;
@@ -710,6 +734,7 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
if (oldbut->poin != (char *)oldbut) {
SWAP(char *, oldbut->poin, but->poin);
SWAP(void *, oldbut->func_argN, but->func_argN);
+ SWAP(void *, oldbut->tip_argN, but->tip_argN);
}
oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy);
@@ -717,11 +742,15 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
/* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
* when scrolling without moving mouse (see [#28432]) */
- if (ELEM(oldbut->type, ROW, LISTROW))
+ if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW))
oldbut->hardmax = but->hardmax;
ui_but_update_linklines(block, oldbut, but);
+ if (!BLI_listbase_is_empty(&block->butstore)) {
+ UI_butstore_register_update(block, oldbut, but);
+ }
+
/* move/copy string from the new button to the old */
/* needed for alt+mouse wheel over enums */
if (but->str != but->strdata) {
@@ -741,8 +770,12 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
BLI_strncpy(oldbut->strdata, but->strdata, sizeof(oldbut->strdata));
}
+ if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ SWAP(void *, but->dragpoin, oldbut->dragpoin);
+ }
+
BLI_remlink(&block->buttons, but);
- ui_free_but(C, but);
+ ui_but_free(C, but);
/* note: if layout hasn't been applied yet, it uses old button pointers... */
}
@@ -754,7 +787,7 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
/* ensures one button can get activated, and in case the buttons
* draw are the same this gives O(1) lookup for each button */
BLI_remlink(&oldblock->buttons, oldbut);
- ui_free_but(C, oldbut);
+ ui_but_free(C, oldbut);
}
return found_active;
@@ -763,7 +796,7 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
/* needed for temporarily rename buttons, such as in outliner or file-select,
* they should keep calling uiDefButs to keep them alive */
/* returns 0 when button removed */
-bool uiButActiveOnly(const bContext *C, ARegion *ar, uiBlock *block, uiBut *but)
+bool UI_but_active_only(const bContext *C, ARegion *ar, uiBlock *block, uiBut *but)
{
uiBlock *oldblock;
uiBut *oldbut;
@@ -784,11 +817,11 @@ bool uiButActiveOnly(const bContext *C, ARegion *ar, uiBlock *block, uiBut *but)
}
}
if ((activate == true) || (found == false)) {
- ui_button_activate_do((bContext *)C, ar, but);
+ ui_but_activate_event((bContext *)C, ar, but);
}
else if ((found == true) && (isactive == false)) {
BLI_remlink(&block->buttons, but);
- ui_free_but(C, but);
+ ui_but_free(C, but);
return false;
}
@@ -796,18 +829,18 @@ bool uiButActiveOnly(const bContext *C, ARegion *ar, uiBlock *block, uiBut *but)
}
/* simulate button click */
-void uiButExecute(const bContext *C, uiBut *but)
+void UI_but_execute(const bContext *C, uiBut *but)
{
ARegion *ar = CTX_wm_region(C);
void *active_back;
- ui_button_execute_begin((bContext *)C, ar, but, &active_back);
+ ui_but_execute_begin((bContext *)C, ar, but, &active_back);
/* Value is applied in begin. No further action required. */
- ui_button_execute_end((bContext *)C, ar, but, active_back);
+ ui_but_execute_end((bContext *)C, ar, but, active_back);
}
/* use to check if we need to disable undo, but don't make any changes
* returns false if undo needs to be disabled. */
-static bool ui_is_but_rna_undo(const uiBut *but)
+static bool ui_but_is_rna_undo(const uiBut *but)
{
if (but->rnapoin.id.data) {
/* avoid undo push for buttons who's ID are screen or wm level
@@ -850,7 +883,13 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
* fun first pass on all buttons so first word chars always get first priority */
for (but = block->buttons.first; but; but = but->next) {
- if (!ELEM(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
+ if (!ELEM(but->type,
+ UI_BTYPE_BUT,
+ UI_BTYPE_BUT_MENU,
+ UI_BTYPE_MENU, UI_BTYPE_BLOCK,
+ UI_BTYPE_PULLDOWN) ||
+ (but->flag & UI_HIDDEN))
+ {
/* pass */
}
else if (but->menu_key == '\0') {
@@ -930,7 +969,7 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str
MEM_freeN(butstr_orig);
but->str = but->strdata;
but->flag |= UI_BUT_HAS_SEP_CHAR;
- ui_check_but(but);
+ ui_but_update(but);
}
}
@@ -942,13 +981,11 @@ static bool ui_but_event_operator_string(const bContext *C, uiBut *but, char *bu
if (but->optype) {
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
- if (WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, true,
- buf, buf_len))
- {
+ if (WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, true, buf_len, buf)) {
found = true;
}
}
- else if ((mt = uiButGetMenuType(but))) {
+ else if ((mt = UI_but_menutype_get(but))) {
IDProperty *prop_menu;
IDProperty *prop_menu_name;
@@ -959,8 +996,8 @@ static bool ui_but_event_operator_string(const bContext *C, uiBut *but, char *bu
IDP_AssignString(prop_menu_name, mt->idname, sizeof(mt->idname));
- if (WM_key_event_operator_string(C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu, true,
- buf, buf_len))
+ if (WM_key_event_operator_string(C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu,
+ true, buf_len, buf))
{
found = true;
}
@@ -1065,7 +1102,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) {
//printf("\t%s\n", ctx_toggle_opnames[i]);
if (WM_key_event_operator_string(C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
- buf, buf_len))
+ buf_len, buf))
{
found = true;
break;
@@ -1082,13 +1119,16 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
return found;
}
-/* this goes in a seemingly weird pattern:
+/**
+ * This goes in a seemingly weird pattern:
*
+ * <pre>
* 4
* 5 6
* 1 2
* 7 8
* 3
+ * </pre>
*
* but it's actually quite logical. It's designed to be 'upwards compatible'
* for muscle memory so that the menu item locations are fixed and don't move
@@ -1147,7 +1187,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
}
}
-void uiBlockUpdateFromOld(const bContext *C, uiBlock *block)
+void UI_block_update_from_old(const bContext *C, uiBlock *block)
{
uiBut *but_old;
uiBut *but;
@@ -1163,20 +1203,19 @@ void uiBlockUpdateFromOld(const bContext *C, uiBlock *block)
for (but = block->buttons.first; but; but = but->next) {
if (ui_but_update_from_old_block(C, block, &but, &but_old)) {
- ui_check_but(but);
+ ui_but_update(but);
}
}
block->auto_open = block->oldblock->auto_open;
block->auto_open_last = block->oldblock->auto_open_last;
block->tooltipdisabled = block->oldblock->tooltipdisabled;
- copy_v3_v3(ui_block_hsv_get(block),
- ui_block_hsv_get(block->oldblock));
+ BLI_movelisttolist(&block->color_pickers.list, &block->oldblock->color_pickers.list);
block->oldblock = NULL;
}
-void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
+void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2])
{
wmWindow *window = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
@@ -1184,7 +1223,7 @@ void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
BLI_assert(block->active);
- uiBlockUpdateFromOld(C, block);
+ UI_block_update_from_old(C, block);
/* inherit flags from 'old' buttons that was drawn here previous, based
* on matching buttons, we need this to make button event handling non
@@ -1214,9 +1253,9 @@ void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
/* handle pending stuff */
if (block->layouts.first) {
- uiBlockLayoutResolve(block, NULL, NULL);
+ UI_block_layout_resolve(block, NULL, NULL);
}
- ui_block_do_align(block);
+ ui_block_align_calc(block);
if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) {
ui_menu_block_set_keyaccels(block); /* could use a different flag to check */
}
@@ -1230,40 +1269,40 @@ void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
case UI_BLOCK_BOUNDS_NONE:
break;
case UI_BLOCK_BOUNDS:
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
break;
case UI_BLOCK_BOUNDS_TEXT:
- ui_text_bounds_block(block, 0.0f);
+ ui_block_bounds_calc_text(block, 0.0f);
break;
case UI_BLOCK_BOUNDS_POPUP_CENTER:
- ui_centered_bounds_block(window, block);
+ ui_block_bounds_calc_centered(window, block);
break;
case UI_BLOCK_BOUNDS_PIE_CENTER:
- ui_centered_pie_bounds_block(block);
+ ui_block_bounds_calc_centered_pie(block);
break;
/* fallback */
case UI_BLOCK_BOUNDS_POPUP_MOUSE:
case UI_BLOCK_BOUNDS_POPUP_MENU:
- ui_popup_bounds_block(window, block, block->bounds_type, xy);
+ ui_block_bounds_calc_popup(window, block, block->bounds_type, xy);
break;
}
if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
- uiBoundsBlock(block, 0);
+ UI_block_bounds_set_normal(block, 0);
}
if (block->flag & UI_BUT_ALIGN) {
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
block->endblock = 1;
}
-void uiEndBlock(const bContext *C, uiBlock *block)
+void UI_block_end(const bContext *C, uiBlock *block)
{
wmWindow *window = CTX_wm_window(C);
- uiEndBlock_ex(C, block, &window->eventstate->x);
+ UI_block_end_ex(C, block, &window->eventstate->x);
}
/* ************** BLOCK DRAWING FUNCTION ************* */
@@ -1291,38 +1330,26 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u
rctf rectf;
ui_block_to_window_rctf(ar, block, &rectf, (but) ? &but->rect : &block->rect);
-
- rectf.xmin -= ar->winrct.xmin;
- rectf.ymin -= ar->winrct.ymin;
- rectf.xmax -= ar->winrct.xmin;
- rectf.ymax -= ar->winrct.ymin;
-
- rect->xmin = floorf(rectf.xmin);
- rect->ymin = floorf(rectf.ymin);
- rect->xmax = floorf(rectf.xmax);
- rect->ymax = floorf(rectf.ymax);
+ BLI_rcti_rctf_copy_floor(rect, &rectf);
+ BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin);
}
/* uses local copy of style, to scale things down, and allow widgets to change stuff */
-void uiDrawBlock(const bContext *C, uiBlock *block)
+void UI_block_draw(const bContext *C, uiBlock *block)
{
- uiStyle style = *UI_GetStyleDraw(); /* XXX pass on as arg */
+ uiStyle style = *UI_style_get_dpi(); /* XXX pass on as arg */
ARegion *ar;
uiBut *but;
rcti rect;
int multisample_enabled;
- /* early exit if cancelled */
- if ((block->flag & UI_BLOCK_RADIAL) && (block->pie_data.flags & UI_PIE_FINISHED))
- return;
-
/* get menu region or area region */
ar = CTX_wm_menu(C);
if (!ar)
ar = CTX_wm_region(C);
if (!block->endblock)
- uiEndBlock(C, block);
+ UI_block_end(C, block);
/* disable AA, makes widgets too blurry */
multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB);
@@ -1389,12 +1416,12 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
*
* \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
*/
-int ui_is_but_push_ex(uiBut *but, double *value)
+int ui_but_is_pushed_ex(uiBut *but, double *value)
{
int is_push = 0;
if (but->bit) {
- const bool state = ELEM(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
+ const bool state = ELEM(but->type, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE_N, UI_BTYPE_CHECKBOX_N) ? false : true;
int lvalue;
UI_GET_BUT_VALUE_INIT(but, *value);
lvalue = (int)*value;
@@ -1407,27 +1434,27 @@ int ui_is_but_push_ex(uiBut *but, double *value)
}
else {
switch (but->type) {
- case BUT:
- case HOTKEYEVT:
- case KEYEVT:
- case COLOR:
+ case UI_BTYPE_BUT:
+ case UI_BTYPE_HOTKEY_EVENT:
+ case UI_BTYPE_KEY_EVENT:
+ case UI_BTYPE_COLOR:
is_push = -1;
break;
- case TOGBUT:
- case TOG:
- case ICONTOG:
- case OPTION:
+ case UI_BTYPE_BUT_TOGGLE:
+ case UI_BTYPE_TOGGLE:
+ case UI_BTYPE_ICON_TOGGLE:
+ case UI_BTYPE_CHECKBOX:
UI_GET_BUT_VALUE_INIT(but, *value);
if (*value != (double)but->hardmin) is_push = true;
break;
- case ICONTOGN:
- case TOGN:
- case OPTIONN:
+ case UI_BTYPE_ICON_TOGGLE_N:
+ case UI_BTYPE_TOGGLE_N:
+ case UI_BTYPE_CHECKBOX_N:
UI_GET_BUT_VALUE_INIT(but, *value);
if (*value == 0.0) is_push = true;
break;
- case ROW:
- case LISTROW:
+ case UI_BTYPE_ROW:
+ case UI_BTYPE_LISTROW:
UI_GET_BUT_VALUE_INIT(but, *value);
/* support for rna enum buts */
if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
@@ -1445,15 +1472,15 @@ int ui_is_but_push_ex(uiBut *but, double *value)
return is_push;
}
-int ui_is_but_push(uiBut *but)
+int ui_but_is_pushed(uiBut *but)
{
double value = UI_BUT_VALUE_UNSET;
- return ui_is_but_push_ex(but, &value);
+ return ui_but_is_pushed_ex(but, &value);
}
-static void ui_check_but_select(uiBut *but, double *value)
+static void ui_but_update_select_flag(uiBut *but, double *value)
{
- switch (ui_is_but_push_ex(but, value)) {
+ switch (ui_but_is_pushed_ex(but, value)) {
case true:
but->flag |= UI_SELECT;
break;
@@ -1463,13 +1490,13 @@ static void ui_check_but_select(uiBut *but, double *value)
}
}
-static uiBut *ui_find_inlink(uiBlock *block, void *poin)
+static uiBut *ui_linkline_find_inlink(uiBlock *block, void *poin)
{
uiBut *but;
but = block->buttons.first;
while (but) {
- if (but->type == INLINK) {
+ if (but->type == UI_BTYPE_INLINK) {
if (but->poin == poin) return but;
}
but = but->next;
@@ -1477,7 +1504,7 @@ static uiBut *ui_find_inlink(uiBlock *block, void *poin)
return NULL;
}
-static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt, short deactive)
+static void ui_linkline_add(ListBase *listb, uiBut *but, uiBut *bt, short deactive)
{
uiLinkLine *line;
@@ -1488,12 +1515,12 @@ static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt, short deact
line->deactive = deactive;
}
-uiBut *uiFindInlink(uiBlock *block, void *poin)
+uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin)
{
- return ui_find_inlink(block, poin);
+ return ui_linkline_find_inlink(block, poin);
}
-void uiComposeLinks(uiBlock *block)
+void UI_block_links_compose(uiBlock *block)
{
uiBut *but, *bt;
uiLink *link;
@@ -1502,7 +1529,7 @@ void uiComposeLinks(uiBlock *block)
but = block->buttons.first;
while (but) {
- if (but->type == LINK) {
+ if (but->type == UI_BTYPE_LINK) {
link = but->link;
/* for all pointers in the array */
@@ -1510,26 +1537,26 @@ void uiComposeLinks(uiBlock *block)
if (link->ppoin) {
ppoin = link->ppoin;
for (a = 0; a < *(link->totlink); a++) {
- bt = ui_find_inlink(block, (*ppoin)[a]);
+ bt = ui_linkline_find_inlink(block, (*ppoin)[a]);
if (bt) {
if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) {
- ui_add_link_line(&link->lines, but, bt, true);
+ ui_linkline_add(&link->lines, but, bt, true);
}
else {
- ui_add_link_line(&link->lines, but, bt, false);
+ ui_linkline_add(&link->lines, but, bt, false);
}
}
}
}
else if (link->poin) {
- bt = ui_find_inlink(block, *link->poin);
+ bt = ui_linkline_find_inlink(block, *link->poin);
if (bt) {
if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) {
- ui_add_link_line(&link->lines, but, bt, true);
+ ui_linkline_add(&link->lines, but, bt, true);
}
else {
- ui_add_link_line(&link->lines, but, bt, false);
+ ui_linkline_add(&link->lines, but, bt, false);
}
}
}
@@ -1542,7 +1569,7 @@ void uiComposeLinks(uiBlock *block)
/* ************************************************ */
-void uiBlockSetButLock(uiBlock *block, bool val, const char *lockstr)
+void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr)
{
if (val) {
block->lock = val;
@@ -1550,7 +1577,7 @@ void uiBlockSetButLock(uiBlock *block, bool val, const char *lockstr)
}
}
-void uiBlockClearButLock(uiBlock *block)
+void UI_block_lock_clear(uiBlock *block)
{
block->lock = false;
block->lockstr = NULL;
@@ -1558,7 +1585,7 @@ void uiBlockClearButLock(uiBlock *block)
/* *************************************************************** */
-void ui_delete_linkline(uiLinkLine *line, uiBut *but)
+void ui_linkline_remove(uiLinkLine *line, uiBut *but)
{
uiLink *link;
int a, b;
@@ -1599,7 +1626,7 @@ void ui_delete_linkline(uiLinkLine *line, uiBut *but)
* an edit override pointer while dragging for example */
/* for buttons pointing to color for example */
-void ui_get_but_vectorf(uiBut *but, float vec[3])
+void ui_but_v3_get(uiBut *but, float vec[3])
{
PropertyRNA *prop;
int a;
@@ -1645,13 +1672,13 @@ void ui_get_but_vectorf(uiBut *but, float vec[3])
}
}
- if (but->type == BUT_NORMAL) {
+ if (but->type == UI_BTYPE_UNITVEC) {
normalize_v3(vec);
}
}
/* for buttons pointing to color for example */
-void ui_set_but_vectorf(uiBut *but, const float vec[3])
+void ui_but_v3_set(uiBut *but, const float vec[3])
{
PropertyRNA *prop;
@@ -1691,7 +1718,7 @@ void ui_set_but_vectorf(uiBut *but, const float vec[3])
}
}
-bool ui_is_but_float(const uiBut *but)
+bool ui_but_is_float(const uiBut *but)
{
if (but->pointype == UI_BUT_POIN_FLOAT && but->poin)
return true;
@@ -1702,28 +1729,31 @@ bool ui_is_but_float(const uiBut *but)
return false;
}
-bool ui_is_but_bool(const uiBut *but)
+bool ui_but_is_bool(const uiBut *but)
{
- if (ELEM(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
+ if (ELEM(but->type, UI_BTYPE_TOGGLE, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE, UI_BTYPE_ICON_TOGGLE_N))
return true;
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
return true;
+ if ((but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) && (but->type == UI_BTYPE_ROW))
+ return true;
+
return false;
}
-bool ui_is_but_unit(const uiBut *but)
+bool ui_but_is_unit(const uiBut *but)
{
UnitSettings *unit = but->block->unit;
- const int unit_type = uiButGetUnitType(but);
+ const int unit_type = UI_but_unit_type_get(but);
if (unit_type == PROP_UNIT_NONE)
return false;
#if 1 /* removed so angle buttons get correct snapping */
- if (ui_is_but_unit_radians_ex(unit, unit_type))
+ if (ui_but_is_unit_radians_ex(unit, unit_type))
return false;
#endif
@@ -1743,7 +1773,7 @@ bool ui_is_but_unit(const uiBut *but)
/**
* Check if this button is similar enough to be grouped with another.
*/
-bool ui_is_but_compatible(const uiBut *but_a, const uiBut *but_b)
+bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b)
{
if (but_a->type != but_b->type)
return false;
@@ -1751,12 +1781,10 @@ bool ui_is_but_compatible(const uiBut *but_a, const uiBut *but_b)
return false;
if (but_a->rnaprop) {
+ /* skip 'rnapoin.data', 'rnapoin.id.data'
+ * allow different data to have the same props edited at once */
if (but_a->rnapoin.type != but_b->rnapoin.type)
return false;
- if (but_a->rnapoin.data != but_b->rnapoin.data)
- return false;
- if (but_a->rnapoin.id.data != but_b->rnapoin.id.data)
- return false;
if (RNA_property_type(but_a->rnaprop) != RNA_property_type(but_b->rnaprop))
return false;
if (RNA_property_subtype(but_a->rnaprop) != RNA_property_subtype(but_b->rnaprop))
@@ -1766,7 +1794,7 @@ bool ui_is_but_compatible(const uiBut *but_a, const uiBut *but_b)
return true;
}
-bool ui_is_but_rna_valid(uiBut *but)
+bool ui_but_is_rna_valid(uiBut *but)
{
if (but->rnaprop == NULL || RNA_struct_contains_property(&but->rnapoin, but->rnaprop)) {
return true;
@@ -1777,7 +1805,17 @@ bool ui_is_but_rna_valid(uiBut *but)
}
}
-double ui_get_but_val(uiBut *but)
+/**
+ * Checks if the button supports ctrl+mousewheel cycling
+ */
+bool ui_but_supports_cycling(const uiBut *but)
+{
+ return ((ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX)) ||
+ (but->type == UI_BTYPE_MENU && ui_but_menu_step_poll(but)) ||
+ (but->type == UI_BTYPE_COLOR && but->a1 != -1));
+}
+
+double ui_but_value_get(uiBut *but)
{
PropertyRNA *prop;
double value = 0.0;
@@ -1833,7 +1871,7 @@ double ui_get_but_val(uiBut *but)
return value;
}
-void ui_set_but_val(uiBut *but, double value)
+void ui_but_value_set(uiBut *but, double value)
{
PropertyRNA *prop;
@@ -1912,18 +1950,18 @@ void ui_set_but_val(uiBut *but, double value)
value = *((float *)but->poin) = (float)value;
}
- ui_check_but_select(but, &value);
+ ui_but_update_select_flag(but, &value);
}
-int ui_get_but_string_max_length(uiBut *but)
+int ui_but_string_get_max_length(uiBut *but)
{
- if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU))
return but->hardmax;
else
return UI_MAX_DRAW_STR;
}
-uiBut *ui_get_but_drag_multi_edit(uiBut *but)
+uiBut *ui_but_drag_multi_edit_get(uiBut *but)
{
uiBut *but_iter;
@@ -1938,10 +1976,60 @@ uiBut *ui_get_but_drag_multi_edit(uiBut *but)
return but_iter;
}
+/** \name Check to show extra icons
+ *
+ * Extra icons are shown on the right hand side of buttons.
+ * \{ */
+
+static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
+{
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
+ return ((but->editstr == NULL) &&
+ (but->drawstr[0] != '\0') &&
+ (but->flag & UI_BUT_SEARCH_UNLINK));
+}
+
+static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
+{
+ StructRNA *type;
+ short idcode;
+
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK));
+
+ if (but->rnaprop == NULL) {
+ return false;
+ }
+
+ type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
+ idcode = RNA_type_to_ID_code(type);
+
+
+ return ((but->editstr == NULL) &&
+ (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
+}
+
+uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
+{
+ if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) {
+ /* pass */
+ }
+ else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+ return UI_BUT_ICONEXTRA_UNLINK;
+ }
+ else if (ui_but_icon_extra_is_visible_eyedropper(but)) {
+ return UI_BUT_ICONEXTRA_EYEDROPPER;
+ }
+
+ return UI_BUT_ICONEXTRA_NONE;
+}
+
+/** \} */
+
+
static double ui_get_but_scale_unit(uiBut *but, double value)
{
UnitSettings *unit = but->block->unit;
- int unit_type = uiButGetUnitType(but);
+ int unit_type = UI_but_unit_type_get(but);
/* Time unit is a bit special, not handled by BKE_scene_unit_scale() for now. */
if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */
@@ -1954,11 +2042,11 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
}
/* str will be overwritten */
-void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
+void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
{
- if (ui_is_but_unit(but)) {
+ if (ui_but_is_unit(but)) {
UnitSettings *unit = but->block->unit;
- int unit_type = uiButGetUnitType(but);
+ int unit_type = UI_but_unit_type_get(but);
char *orig_str;
orig_str = BLI_strdup(str);
@@ -1976,7 +2064,7 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va
{
UnitSettings *unit = but->block->unit;
const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
- int unit_type = uiButGetUnitType(but);
+ int unit_type = UI_but_unit_type_get(but);
int precision;
if (unit->scale_length < 0.0001f) unit->scale_length = 1.0f; // XXX do_versions
@@ -1998,15 +2086,33 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va
static float ui_get_but_step_unit(uiBut *but, float step_default)
{
- int unit_type = RNA_SUBTYPE_UNIT_VALUE(uiButGetUnitType(but));
- double step;
-
- step = bUnit_ClosestScalar(ui_get_but_scale_unit(but, step_default), but->block->unit->system, unit_type);
+ int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
+ const double step_orig = step_default * UI_PRECISION_FLOAT_SCALE;
+ /* Scaling up 'step_origg ' here is a bit arbitrary, its just giving better scales from user POV */
+ const double scale_step = ui_get_but_scale_unit(but, step_orig * 10);
+ const double step = bUnit_ClosestScalar(scale_step, but->block->unit->system, unit_type);
/* -1 is an error value */
if (step != -1.0) {
+ const double scale_unit = ui_get_but_scale_unit(but, 1.0);
+ const double step_unit = bUnit_ClosestScalar(scale_unit, but->block->unit->system, unit_type);
+ double step_final;
+
BLI_assert(step > 0.0);
- return (float)(step / ui_get_but_scale_unit(but, 1.0)) * 100.0f;
+
+ step_final = (step / scale_unit) / UI_PRECISION_FLOAT_SCALE;
+
+ if (step == step_unit) {
+ /* Logic here is to scale by the original 'step_orig'
+ * only when the unit step matches the scaled step.
+ *
+ * This is needed for units that don't have a wide range of scales (degrees for eg.).
+ * Without this we can't select between a single degree, or a 10th of a degree.
+ */
+ step_final *= step_orig;
+ }
+
+ return (float)step_final;
}
else {
return step_default;
@@ -2016,9 +2122,9 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
/**
* \param float_precision For number buttons the precision to use or -1 to fallback to the button default.
*/
-void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
+void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
- if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
@@ -2050,17 +2156,23 @@ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int
str[0] = '\0';
}
else if (buf && buf != str) {
+ BLI_assert(maxlen <= buf_len + 1);
/* string was too long, we have to truncate */
- memcpy(str, buf, MIN2(maxlen, (size_t)(buf_len + 1)));
+ if (ui_but_is_utf8(but)) {
+ BLI_strncpy_utf8(str, buf, maxlen);
+ }
+ else {
+ BLI_strncpy(str, buf, maxlen);
+ }
MEM_freeN((void *)buf);
}
}
- else if (but->type == TEX) {
+ else if (but->type == UI_BTYPE_TEXT) {
/* string */
BLI_strncpy(str, but->poin, maxlen);
return;
}
- else if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* string */
BLI_strncpy(str, but->poin, maxlen);
return;
@@ -2072,14 +2184,14 @@ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int
/* number editing */
double value;
- value = ui_get_but_val(but);
+ value = ui_but_value_get(but);
- if (ui_is_but_float(but)) {
- if (ui_is_but_unit(but)) {
+ if (ui_but_is_float(but)) {
+ if (ui_but_is_unit(but)) {
ui_get_but_string_unit(but, str, maxlen, value, false, float_precision);
}
else {
- const int prec = (float_precision == -1) ? ui_but_float_precision(but, value) : float_precision;
+ const int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : float_precision;
BLI_snprintf(str, maxlen, "%.*f", prec, value);
}
}
@@ -2087,9 +2199,9 @@ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int
BLI_snprintf(str, maxlen, "%d", (int)value);
}
}
-void ui_get_but_string(uiBut *but, char *str, const size_t maxlen)
+void ui_but_string_get(uiBut *but, char *str, const size_t maxlen)
{
- ui_get_but_string_ex(but, str, maxlen, -1);
+ ui_but_string_get_ex(but, str, maxlen, -1);
}
#ifdef WITH_PYTHON
@@ -2097,7 +2209,7 @@ void ui_get_but_string(uiBut *but, char *str, const size_t maxlen)
static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value)
{
char str_unit_convert[256];
- const int unit_type = uiButGetUnitType(but);
+ const int unit_type = UI_but_unit_type_get(but);
BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
@@ -2112,14 +2224,14 @@ static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char
#endif /* WITH_PYTHON */
-bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double *value)
+bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *value)
{
bool ok = false;
#ifdef WITH_PYTHON
if (str[0] != '\0') {
- bool is_unit_but = (ui_is_but_float(but) && ui_is_but_unit(but));
+ bool is_unit_but = (ui_but_is_float(but) && ui_but_is_unit(but));
/* only enable verbose if we won't run again with units */
if (BPY_button_exec(C, str, value, is_unit_but == false) != -1) {
/* if the value parsed ok without unit conversion this button may still need a unit multiplier */
@@ -2152,10 +2264,36 @@ bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double
return ok;
}
+/* just the assignment/free part */
+static void ui_but_string_set_internal(uiBut *but, const char *str, size_t str_len)
+{
+ BLI_assert(str_len == strlen(str));
+ BLI_assert(but->str == NULL);
+ str_len += 1;
+
+ if (str_len > UI_MAX_NAME_STR) {
+ but->str = MEM_mallocN(str_len, "ui_def_but str");
+ }
+ else {
+ but->str = but->strdata;
+ }
+ memcpy(but->str, str, str_len);
+}
+
+static void ui_but_string_free_internal(uiBut *but)
+{
+ if (but->str) {
+ if (but->str != but->strdata) {
+ MEM_freeN(but->str);
+ }
+ /* must call 'ui_but_string_set_internal' after */
+ but->str = NULL;
+ }
+}
-bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
+bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2200,14 +2338,14 @@ bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
}
}
}
- else if (but->type == TEX) {
+ else if (but->type == UI_BTYPE_TEXT) {
/* string */
- if (ui_is_but_utf8(but)) BLI_strncpy_utf8(but->poin, str, but->hardmax);
+ if (ui_but_is_utf8(but)) BLI_strncpy_utf8(but->poin, str, but->hardmax);
else BLI_strncpy(but->poin, str, but->hardmax);
return true;
}
- else if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* string */
BLI_strncpy(but->poin, str, but->hardmax);
return true;
@@ -2224,38 +2362,38 @@ bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
/* number editing */
double value;
- if (ui_set_but_string_eval_num(C, but, str, &value) == false) {
+ if (ui_but_string_set_eval_num(C, but, str, &value) == false) {
+ WM_report_banner_show(C);
return false;
}
- if (!ui_is_but_float(but)) value = (int)floor(value + 0.5);
+ if (!ui_but_is_float(but)) value = (int)floor(value + 0.5);
/* not that we use hard limits here */
if (value < (double)but->hardmin) value = but->hardmin;
if (value > (double)but->hardmax) value = but->hardmax;
- ui_set_but_val(but, value);
+ ui_but_value_set(but, value);
return true;
}
return false;
}
-void ui_set_but_default(bContext *C, const bool all, const bool use_afterfunc)
+void ui_but_default_set(bContext *C, const bool all, const bool use_afterfunc)
{
- const char *opstring = "UI_OT_reset_default_button";
+ wmOperatorType *ot = WM_operatortype_find("UI_OT_reset_default_button", true);
if (use_afterfunc) {
PointerRNA *ptr;
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
ptr = ui_handle_afterfunc_add_operator(ot, WM_OP_EXEC_DEFAULT, true);
RNA_boolean_set(ptr, "all", all);
}
else {
PointerRNA ptr;
- WM_operator_properties_create(&ptr, opstring);
+ WM_operator_properties_create_ptr(&ptr, ot);
RNA_boolean_set(&ptr, "all", all);
- WM_operator_name_call(C, opstring, WM_OP_EXEC_DEFAULT, &ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
}
}
@@ -2371,7 +2509,7 @@ static void ui_set_but_soft_range(uiBut *but)
but->softmax = softmax;
}
else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) {
- float value = ui_get_but_val(but);
+ float value = ui_but_value_get(but);
CLAMP(value, but->hardmin, but->hardmax);
but->softmin = min_ff(but->softmin, value);
but->softmax = max_ff(but->softmax, value);
@@ -2392,7 +2530,7 @@ static void ui_free_link(uiLink *link)
}
/* can be called with C==NULL */
-static void ui_free_but(const bContext *C, uiBut *but)
+static void ui_but_free(const bContext *C, uiBut *but)
{
if (but->opptr) {
WM_operator_properties_free(but->opptr);
@@ -2403,12 +2541,16 @@ static void ui_free_but(const bContext *C, uiBut *but)
MEM_freeN(but->func_argN);
}
+ if (but->tip_argN) {
+ MEM_freeN(but->tip_argN);
+ }
+
if (but->active) {
/* XXX solve later, buttons should be free-able without context ideally,
* however they may have open tooltips or popup windows, which need to
* be closed using a context pointer */
if (C) {
- ui_button_active_free(C, but);
+ ui_but_active_free(C, but);
}
else {
if (but->active) {
@@ -2421,24 +2563,28 @@ static void ui_free_but(const bContext *C, uiBut *but)
}
ui_free_link(but->link);
- if ((but->type == BUT_IMAGE) && but->poin) {
+ if ((but->type == UI_BTYPE_IMAGE) && but->poin) {
IMB_freeImBuf((struct ImBuf *)but->poin);
}
+ if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ MEM_freeN(but->dragpoin);
+ }
+
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
MEM_freeN(but);
}
/* can be called with C==NULL */
-void uiFreeBlock(const bContext *C, uiBlock *block)
+void UI_block_free(const bContext *C, uiBlock *block)
{
uiBut *but;
UI_butstore_clear(block);
while ((but = BLI_pophead(&block->buttons))) {
- ui_free_but(C, but);
+ ui_but_free(C, but);
}
if (block->unit) {
@@ -2452,21 +2598,22 @@ void uiFreeBlock(const bContext *C, uiBlock *block)
CTX_store_free_list(&block->contexts);
BLI_freelistN(&block->saferct);
+ BLI_freelistN(&block->color_pickers.list);
MEM_freeN(block);
}
/* can be called with C==NULL */
-void uiFreeBlocks(const bContext *C, ListBase *lb)
+void UI_blocklist_free(const bContext *C, ListBase *lb)
{
uiBlock *block;
while ((block = BLI_pophead(lb))) {
- uiFreeBlock(C, block);
+ UI_block_free(C, block);
}
}
-void uiFreeInactiveBlocks(const bContext *C, ListBase *lb)
+void UI_blocklist_free_inactive(const bContext *C, ListBase *lb)
{
uiBlock *block, *nextblock;
@@ -2476,7 +2623,7 @@ void uiFreeInactiveBlocks(const bContext *C, ListBase *lb)
if (!block->handle) {
if (!block->active) {
BLI_remlink(lb, block);
- uiFreeBlock(C, block);
+ UI_block_free(C, block);
}
else
block->active = 0;
@@ -2484,7 +2631,7 @@ void uiFreeInactiveBlocks(const bContext *C, ListBase *lb)
}
}
-void uiBlockSetRegion(uiBlock *block, ARegion *region)
+void UI_block_region_set(uiBlock *block, ARegion *region)
{
ListBase *lb = &region->uiblocks;
uiBlock *oldblock = NULL;
@@ -2507,7 +2654,7 @@ void uiBlockSetRegion(uiBlock *block, ARegion *region)
block->oldblock = oldblock;
}
-uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, short dt)
+uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, short dt)
{
uiBlock *block;
wmWindow *window;
@@ -2540,7 +2687,7 @@ uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, shor
BLI_strncpy(block->name, name, sizeof(block->name));
if (region)
- uiBlockSetRegion(block, region);
+ UI_block_region_set(block, region);
/* window matrix and aspect */
if (region && region->swinid) {
@@ -2564,23 +2711,23 @@ uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, shor
return block;
}
-uiBlock *uiGetBlock(const char *name, ARegion *ar)
+uiBlock *UI_block_find_in_region(const char *name, ARegion *ar)
{
return BLI_findstring(&ar->uiblocks, name, offsetof(uiBlock, name));
}
-void uiBlockSetEmboss(uiBlock *block, char dt)
+void UI_block_emboss_set(uiBlock *block, char dt)
{
block->dt = dt;
}
-void ui_check_but(uiBut *but)
+void ui_but_update(uiBut *but)
{
/* if something changed in the button */
double value = UI_BUT_VALUE_UNSET;
// float okwidth; // UNUSED
- ui_check_but_select(but, &value);
+ ui_but_update_select_flag(but, &value);
/* only update soft range while not editing */
if (!(but->editval || but->editstr || but->editvec)) {
@@ -2593,16 +2740,20 @@ void ui_check_but(uiBut *but)
/* test for min and max, icon sliders, etc */
switch (but->type) {
- case NUM:
- case SCROLL:
- case NUMSLI:
+ case UI_BTYPE_NUM:
+ case UI_BTYPE_SCROLL:
+ case UI_BTYPE_NUM_SLIDER:
UI_GET_BUT_VALUE_INIT(but, value);
- if (value < (double)but->hardmin) ui_set_but_val(but, but->hardmin);
- else if (value > (double)but->hardmax) ui_set_but_val(but, but->hardmax);
+ if (value < (double)but->hardmin) ui_but_value_set(but, but->hardmin);
+ else if (value > (double)but->hardmax) ui_but_value_set(but, but->hardmax);
+
+ /* max must never be smaller than min! Both being equal is allowed though */
+ BLI_assert(but->softmin <= but->softmax &&
+ but->hardmin <= but->hardmax);
break;
- case ICONTOG:
- case ICONTOGN:
+ case UI_BTYPE_ICON_TOGGLE:
+ case UI_BTYPE_ICON_TOGGLE_N:
if (!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) {
if (but->flag & UI_SELECT) but->iconadd = 1;
else but->iconadd = 0;
@@ -2621,7 +2772,7 @@ void ui_check_but(uiBut *but)
/* name: */
switch (but->type) {
- case MENU:
+ case UI_BTYPE_MENU:
if (BLI_rctf_size_x(&but->rect) > 24.0f) {
/* only needed for menus in popup blocks that don't recreate buttons on redraw */
if (but->block->flag & UI_BLOCK_LOOP) {
@@ -2631,7 +2782,9 @@ void ui_check_but(uiBut *but)
if (RNA_property_enum_name_gettexted(but->block->evil_C,
&but->rnapoin, but->rnaprop, value, &buf))
{
- BLI_strncpy(but->str, buf, sizeof(but->strdata));
+ size_t slen = strlen(buf);
+ ui_but_string_free_internal(but);
+ ui_but_string_set_internal(but, buf, slen);
}
}
}
@@ -2639,8 +2792,8 @@ void ui_check_but(uiBut *but)
}
break;
- case NUM:
- case NUMSLI:
+ case UI_BTYPE_NUM:
+ case UI_BTYPE_NUM_SLIDER:
if (!but->editstr) {
const char *drawstr_suffix = NULL;
@@ -2650,7 +2803,7 @@ void ui_check_but(uiBut *but)
slen = BLI_strncpy_rlen(but->drawstr, but->str, sizeof(but->drawstr));
- if (ui_is_but_float(but)) {
+ if (ui_but_is_float(but)) {
if (value == (double) FLT_MAX) {
slen += BLI_strncpy_rlen(but->drawstr + slen, "inf", sizeof(but->drawstr) - slen);
}
@@ -2658,18 +2811,18 @@ void ui_check_but(uiBut *but)
slen += BLI_strncpy_rlen(but->drawstr + slen, "-inf", sizeof(but->drawstr) - slen);
}
/* support length type buttons */
- else if (ui_is_but_unit(but)) {
+ else if (ui_but_is_unit(but)) {
char new_str[sizeof(but->drawstr)];
ui_get_but_string_unit(but, new_str, sizeof(new_str), value, true, -1);
slen += BLI_strncpy_rlen(but->drawstr + slen, new_str, sizeof(but->drawstr) - slen);
}
else {
- const int prec = ui_but_float_precision(but, value);
- slen += BLI_snprintf(but->drawstr + slen, sizeof(but->drawstr) - slen, "%.*f", prec, value);
+ const int prec = ui_but_calc_float_precision(but, value);
+ slen += BLI_snprintf_rlen(but->drawstr + slen, sizeof(but->drawstr) - slen, "%.*f", prec, value);
}
}
else {
- slen += BLI_snprintf(but->drawstr + slen, sizeof(but->drawstr) - slen, "%d", (int)value);
+ slen += BLI_snprintf_rlen(but->drawstr + slen, sizeof(but->drawstr) - slen, "%d", (int)value);
}
if (but->rnaprop) {
@@ -2690,11 +2843,11 @@ void ui_check_but(uiBut *but)
}
break;
- case LABEL:
- if (ui_is_but_float(but)) {
+ case UI_BTYPE_LABEL:
+ if (ui_but_is_float(but)) {
int prec;
UI_GET_BUT_VALUE_INIT(but, value);
- prec = ui_but_float_precision(but, value);
+ prec = ui_but_calc_float_precision(but, value);
BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%.*f", but->str, prec, value);
}
else {
@@ -2703,18 +2856,17 @@ void ui_check_but(uiBut *but)
break;
- case TEX:
- case SEARCH_MENU:
- case SEARCH_MENU_UNLINK:
+ case UI_BTYPE_TEXT:
+ case UI_BTYPE_SEARCH_MENU:
if (!but->editstr) {
char str[UI_MAX_DRAW_STR];
- ui_get_but_string(but, str, UI_MAX_DRAW_STR);
+ ui_but_string_get(but, str, UI_MAX_DRAW_STR);
BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, str);
}
break;
- case KEYEVT:
+ case UI_BTYPE_KEY_EVENT:
{
const char *str;
if (but->flag & UI_SELECT) {
@@ -2722,12 +2874,12 @@ void ui_check_but(uiBut *but)
}
else {
UI_GET_BUT_VALUE_INIT(but, value);
- str = WM_key_event_string((short)value);
+ str = WM_key_event_string((short)value, false);
}
BLI_snprintf(but->drawstr, UI_MAX_DRAW_STR, "%s%s", but->str, str);
break;
}
- case HOTKEYEVT:
+ case UI_BTYPE_HOTKEY_EVENT:
if (but->flag & UI_SELECT) {
if (but->modifier_key) {
@@ -2754,8 +2906,8 @@ void ui_check_but(uiBut *but)
break;
- case HSVCUBE:
- case HSVCIRCLE:
+ case UI_BTYPE_HSVCUBE:
+ case UI_BTYPE_HSVCIRCLE:
break;
default:
BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR);
@@ -2771,10 +2923,10 @@ void ui_check_but(uiBut *but)
}
-void uiBlockBeginAlign(uiBlock *block)
+void UI_block_align_begin(uiBlock *block)
{
/* if other align was active, end it */
- if (block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
+ if (block->flag & UI_BUT_ALIGN) UI_block_align_end(block);
block->flag |= UI_BUT_ALIGN_DOWN;
block->alignnr++;
@@ -2800,17 +2952,17 @@ static bool buts_are_horiz(uiBut *but1, uiBut *but2)
return (dx <= dy);
}
-void uiBlockEndAlign(uiBlock *block)
+void UI_block_align_end(uiBlock *block)
{
block->flag &= ~UI_BUT_ALIGN; /* all 4 flags */
}
bool ui_but_can_align(uiBut *but)
{
- return !ELEM(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
+ return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE);
}
-static void ui_block_do_align_but(uiBut *first, short nr)
+static void ui_block_align_calc_but(uiBut *first, short nr)
{
uiBut *prev, *but = NULL, *next;
int flag = 0, cols = 0, rows = 0;
@@ -2950,7 +3102,7 @@ static void ui_block_do_align_but(uiBut *first, short nr)
}
}
-void ui_block_do_align(uiBlock *block)
+void ui_block_align_calc(uiBlock *block)
{
uiBut *but;
short nr;
@@ -2959,7 +3111,7 @@ void ui_block_do_align(uiBlock *block)
for (but = block->buttons.first; but; ) {
if (but->alignnr) {
nr = but->alignnr;
- ui_block_do_align_but(but, nr);
+ ui_block_align_calc_but(but, nr);
/* skip with same number */
for (; but && but->alignnr == nr; but = but->next) {
@@ -2976,39 +3128,54 @@ void ui_block_do_align(uiBlock *block)
}
}
-struct ColorManagedDisplay *ui_block_display_get(uiBlock *block)
+struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block)
{
return IMB_colormanagement_display_get_named(block->display_device);
}
-void ui_block_to_display_space_v3(uiBlock *block, float pixel[3])
+void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
{
- struct ColorManagedDisplay *display = ui_block_display_get(block);
+ struct ColorManagedDisplay *display = ui_block_cm_display_get(block);
IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
}
-void ui_block_to_scene_linear_v3(uiBlock *block, float pixel[3])
+void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3])
{
- struct ColorManagedDisplay *display = ui_block_display_get(block);
+ struct ColorManagedDisplay *display = ui_block_cm_display_get(block);
IMB_colormanagement_display_to_scene_linear_v3(pixel, display);
}
+void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max)
+{
+ struct ColorManagedDisplay *display = ui_block_cm_display_get(block);
+ float pixel[3];
+
+ copy_v3_fl(pixel, *min);
+ IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
+ *min = min_fff(UNPACK3(pixel));
+
+ copy_v3_fl(pixel, *max);
+ IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
+ *max = max_fff(UNPACK3(pixel));
+}
+
/**
* \brief ui_def_but is the function that draws many button types
*
- * \param x,y The lower left hand corner of the button (X axis)
- * \param width,height The size of the button.
+ * \param x, y: The lower left hand corner of the button (X axis)
+ * \param width, height: The size of the button.
*
* for float buttons:
- * - \a a1 Click Step (how much to change the value each click)
- * - \a a2 Number of decimal point values to display. 0 defaults to 3 (0.000)
- * 1,2,3, and a maximum of 4, all greater values will be clamped to 4.
+ * \param a1: Click Step (how much to change the value each click)
+ * \param a2: Number of decimal point values to display. 0 defaults to 3 (0.000)
+ * 1,2,3, and a maximum of 4, all greater values will be clamped to 4.
*/
-static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
- int x, int y, short width, short height,
- void *poin, float min, float max, float a1, float a2, const char *tip)
+static uiBut *ui_def_but(
+ uiBlock *block, int type, int retval, const char *str,
+ int x, int y, short width, short height,
+ void *poin, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but;
int slen;
@@ -3016,7 +3183,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
BLI_assert(width >= 0 && height >= 0);
/* we could do some more error checks here */
- if ((type & BUTTYPE) == LABEL) {
+ if ((type & BUTTYPE) == UI_BTYPE_LABEL) {
BLI_assert((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)) == false);
}
@@ -3039,13 +3206,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->retval = retval;
slen = strlen(str);
- if (slen >= UI_MAX_NAME_STR) {
- but->str = MEM_mallocN(slen + 1, "ui_def_but str");
- }
- else {
- but->str = but->strdata;
- }
- memcpy(but->str, str, slen + 1);
+ ui_but_string_set_internal(but, str, slen);
but->rect.xmin = x;
but->rect.ymin = y;
@@ -3079,7 +3240,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->pos = -1; /* cursor invisible */
- if (ELEM(but->type, NUM, NUMSLI)) { /* add a space to name */
+ if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* add a space to name */
/* slen remains unchanged from previous assignment, ensure this stays true */
if (slen > 0 && slen < UI_MAX_NAME_STR - 2) {
if (but->str[slen - 1] != ' ') {
@@ -3093,12 +3254,15 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
else if ((block->flag & UI_BLOCK_LOOP) ||
- ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
+ ELEM(but->type,
+ UI_BTYPE_MENU, UI_BTYPE_TEXT, UI_BTYPE_LABEL,
+ UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU,
+ UI_BTYPE_PROGRESS_BAR))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
#ifdef USE_NUMBUTS_LR_ALIGN
- else if (ELEM(but->type, NUM, NUMSLI)) {
+ else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
but->drawflag |= UI_BUT_TEXT_LEFT;
}
#endif
@@ -3112,9 +3276,18 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
/* keep track of UI_interface.h */
- if (ELEM(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
- else if (but->type >= SEARCH_MENU) {}
- else but->flag |= UI_BUT_UNDO;
+ if (ELEM(but->type,
+ UI_BTYPE_BLOCK, UI_BTYPE_BUT, UI_BTYPE_LABEL,
+ UI_BTYPE_PULLDOWN, UI_BTYPE_ROUNDBOX, UI_BTYPE_LISTBOX,
+ UI_BTYPE_BUT_MENU, UI_BTYPE_SCROLL, UI_BTYPE_GRIP,
+ UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE) ||
+ (but->type >= UI_BTYPE_SEARCH_MENU))
+ {
+ /* pass */
+ }
+ else {
+ but->flag |= UI_BUT_UNDO;
+ }
BLI_addtail(&block->buttons, but);
@@ -3131,6 +3304,19 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
return but;
}
+void ui_def_but_icon(uiBut *but, const int icon, const int flag)
+{
+ if (icon) {
+ ui_icon_ensure_deferred(but->block->evil_C, icon, (flag & UI_BUT_ICON_PREVIEW) != 0);
+ }
+ but->icon = (BIFIconID)icon;
+ but->flag |= flag;
+
+ if (but->str && but->str[0]) {
+ but->drawflag |= UI_BUT_ICON_LEFT;
+ }
+}
+
static void ui_def_but_rna__disable(uiBut *but)
{
but->flag |= UI_BUT_DISABLED;
@@ -3155,13 +3341,13 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
int column_start = 0, column_end = 0;
int nbr_entries_nosepr = 0;
- uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
+ UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
RNA_property_enum_items_gettexted(block->evil_C, &but->rnapoin, but->rnaprop, &item_array, NULL, &free);
/* we dont want nested rows, cols in menus */
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
for (item = item_array; item->identifier; item++, totitems++) {
if (!item->identifier[0]) {
@@ -3190,7 +3376,7 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
rows++;
/* Title */
- uiDefBut(block, LABEL, 0, RNA_property_ui_name(but->rnaprop),
+ uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_property_ui_name(but->rnaprop),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
@@ -3233,7 +3419,7 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
}
else {
/* Do not use uiItemL here, as our root layout is a menu one, it will add a fake blank icon! */
- uiDefBut(block, LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
}
else {
@@ -3242,21 +3428,24 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
}
else {
if (item->icon) {
- uiDefIconTextButI(block, BUTM, B_NOP, item->icon, item->name, 0, 0,
+ uiDefIconTextButI(block, UI_BTYPE_BUT_MENU, B_NOP, item->icon, item->name, 0, 0,
UI_UNIT_X * 5, UI_UNIT_Y, &handle->retvalue, item->value, 0.0, 0, -1, item->description);
}
else {
- uiDefButI(block, BUTM, B_NOP, item->name, 0, 0,
+ uiDefButI(block, UI_BTYPE_BUT_MENU, B_NOP, item->name, 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &handle->retvalue, item->value, 0.0, 0, -1, item->description);
}
}
}
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (free) {
MEM_freeN(item_array);
}
+
+ BLI_assert((block->flag & UI_BLOCK_IS_FLIP) == 0);
+ block->flag |= UI_BLOCK_IS_FLIP;
}
/**
@@ -3267,23 +3456,24 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
* When this kind of change won't disrupt branches, best look into making more
* of our UI functions take prop rather then propname.
*/
-static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *str,
- int x, int y, short width, short height,
- PointerRNA *ptr, PropertyRNA *prop, int index,
- float min, float max, float a1, float a2, const char *tip)
+static uiBut *ui_def_but_rna(
+ uiBlock *block, int type, int retval, const char *str,
+ int x, int y, short width, short height,
+ PointerRNA *ptr, PropertyRNA *prop, int index,
+ float min, float max, float a1, float a2, const char *tip)
{
const PropertyType proptype = RNA_property_type(prop);
uiBut *but;
int icon = 0;
uiMenuCreateFunc func = NULL;
- if (ELEM(type, COLOR, HSVCIRCLE, HSVCUBE)) {
+ if (ELEM(type, UI_BTYPE_COLOR, UI_BTYPE_HSVCIRCLE, UI_BTYPE_HSVCUBE)) {
BLI_assert(index == -1);
}
/* use rna values if parameters are not specified */
- if ((proptype == PROP_ENUM) && ELEM(type, MENU, ROW, LISTROW)) {
- /* MENU is handled a little differently here */
+ if ((proptype == PROP_ENUM) && ELEM(type, UI_BTYPE_MENU, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
+ /* UI_BTYPE_MENU is handled a little differently here */
EnumPropertyItem *item;
int value;
bool free;
@@ -3291,7 +3481,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
RNA_property_enum_items(block->evil_C, ptr, prop, &item, NULL, &free);
- if (type == MENU) {
+ if (type == UI_BTYPE_MENU) {
value = RNA_property_enum_get(ptr, prop);
}
else {
@@ -3312,7 +3502,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
}
else {
if (!str) {
- if (type == MENU) {
+ if (type == UI_BTYPE_MENU) {
str = "";
}
else {
@@ -3321,7 +3511,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
}
}
- if (type == MENU) {
+ if (type == UI_BTYPE_MENU) {
func = ui_def_but_rna__menu;
}
@@ -3346,7 +3536,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
RNA_property_int_range(ptr, prop, &hardmin, &hardmax);
RNA_property_int_ui_range(ptr, prop, &softmin, &softmax, &step);
- if (!ELEM(type, ROW, LISTROW) && min == max) {
+ if (!ELEM(type, UI_BTYPE_ROW, UI_BTYPE_LISTROW) && min == max) {
min = hardmin;
max = hardmax;
}
@@ -3361,7 +3551,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
- if (!ELEM(type, ROW, LISTROW) && min == max) {
+ if (!ELEM(type, UI_BTYPE_ROW, UI_BTYPE_LISTROW) && min == max) {
min = hardmin;
max = hardmax;
}
@@ -3390,27 +3580,23 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
but->rnaindex = 0;
if (icon) {
- but->icon = (BIFIconID)icon;
- but->flag |= UI_HAS_ICON;
- if (str[0]) {
- but->drawflag |= UI_BUT_ICON_LEFT;
- }
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
}
- if ((type == MENU) && (but->dt == UI_EMBOSSP)) {
- but->flag |= UI_ICON_SUBMENU;
+ if ((type == UI_BTYPE_MENU) && (but->dt == UI_EMBOSS_PULLDOWN)) {
+ but->flag |= UI_BUT_ICON_SUBMENU;
}
if (!RNA_property_editable(&but->rnapoin, prop)) {
ui_def_but_rna__disable(but);
}
- if (but->flag & UI_BUT_UNDO && (ui_is_but_rna_undo(but) == false)) {
+ if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
but->flag &= ~UI_BUT_UNDO;
}
/* If this button uses units, calculate the step from this */
- if ((proptype == PROP_FLOAT) && ui_is_but_unit(but)) {
+ if ((proptype == PROP_FLOAT) && ui_but_is_unit(but)) {
but->a1 = ui_get_but_step_unit(but, but->a1);
}
@@ -3457,7 +3643,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *
but = ui_def_but(block, type, -1, str, x, y, width, height, NULL, 0, 0, 0, 0, tip);
but->optype = ot;
but->opcontext = opcontext;
- but->flag &= ~UI_BUT_UNDO; /* no need for ui_is_but_rna_undo(), we never need undo here */
+ but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_rna_undo(), we never need undo here */
if (!ot) {
but->flag |= UI_BUT_DISABLED;
@@ -3472,7 +3658,7 @@ uiBut *uiDefBut(uiBlock *block, int type, int retval, const char *str, int x, in
{
uiBut *but = ui_def_but(block, type, retval, str, x, y, width, height, poin, min, max, a1, a2, tip);
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
@@ -3512,7 +3698,7 @@ struct AutoComplete {
const char *startname;
};
-AutoComplete *autocomplete_begin(const char *startname, size_t maxlen)
+AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen)
{
AutoComplete *autocpl;
@@ -3525,7 +3711,7 @@ AutoComplete *autocomplete_begin(const char *startname, size_t maxlen)
return autocpl;
}
-void autocomplete_do_name(AutoComplete *autocpl, const char *name)
+void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name)
{
char *truncate = autocpl->truncate;
const char *startname = autocpl->startname;
@@ -3555,7 +3741,7 @@ void autocomplete_do_name(AutoComplete *autocpl, const char *name)
}
}
-int autocomplete_end(AutoComplete *autocpl, char *autoname)
+int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
{
int match = AUTOCOMPLETE_NO_MATCH;
if (autocpl->truncate[0]) {
@@ -3578,14 +3764,13 @@ int autocomplete_end(AutoComplete *autocpl, char *autoname)
return match;
}
-static void ui_check_but_and_iconize(uiBut *but, int icon)
+static void ui_but_update_and_icon_set(uiBut *but, int icon)
{
if (icon) {
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
}
- ui_check_but(but);
+ ui_but_update(but);
}
static uiBut *uiDefButBit(uiBlock *block, int type, int bit, int retval, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
@@ -3634,14 +3819,14 @@ uiBut *uiDefButR(uiBlock *block, int type, int retval, const char *str, int x, i
{
uiBut *but;
but = ui_def_but_rna_propname(block, type, retval, str, x, y, width, height, ptr, propname, index, min, max, a1, a2, tip);
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefButR_prop(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but;
but = ui_def_but_rna(block, type, retval, str, x, y, width, height, ptr, prop, index, min, max, a1, a2, tip);
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
@@ -3649,7 +3834,7 @@ uiBut *uiDefButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int opcontext
{
uiBut *but;
but = ui_def_but_operator_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefButO(uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, const char *tip)
@@ -3663,7 +3848,7 @@ uiBut *uiDefButO(uiBlock *block, int type, const char *opname, int opcontext, co
uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but = ui_def_but(block, type, retval, "", x, y, width, height, poin, min, max, a1, a2, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
return but;
}
static uiBut *uiDefIconButBit(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
@@ -3713,14 +3898,14 @@ uiBut *uiDefIconButR(uiBlock *block, int type, int retval, int icon, int x, int
{
uiBut *but;
but = ui_def_but_rna_propname(block, type, retval, "", x, y, width, height, ptr, propname, index, min, max, a1, a2, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
return but;
}
uiBut *uiDefIconButR_prop(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but;
but = ui_def_but_rna(block, type, retval, "", x, y, width, height, ptr, prop, index, min, max, a1, a2, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
return but;
}
@@ -3728,7 +3913,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int opcon
{
uiBut *but;
but = ui_def_but_operator_ptr(block, type, ot, opcontext, "", x, y, width, height, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
return but;
}
uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, int x, int y, short width, short height, const char *tip)
@@ -3741,7 +3926,7 @@ uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, int opcontext
uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but = ui_def_but(block, type, retval, str, x, y, width, height, poin, min, max, a1, a2, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
@@ -3792,7 +3977,7 @@ uiBut *uiDefIconTextButR(uiBlock *block, int type, int retval, int icon, const c
{
uiBut *but;
but = ui_def_but_rna_propname(block, type, retval, str, x, y, width, height, ptr, propname, index, min, max, a1, a2, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
@@ -3800,7 +3985,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block, int type, int retval, int icon, co
{
uiBut *but;
but = ui_def_but_rna(block, type, retval, str, x, y, width, height, ptr, prop, index, min, max, a1, a2, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
@@ -3808,7 +3993,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int o
{
uiBut *but;
but = ui_def_but_operator_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
- ui_check_but_and_iconize(but, icon);
+ ui_but_update_and_icon_set(but, icon);
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
@@ -3820,7 +4005,7 @@ uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcon
/* END Button containing both string label and icon */
-void uiSetButLink(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to)
+void UI_but_link_set(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to)
{
uiLink *link;
@@ -3835,7 +4020,7 @@ void uiSetButLink(uiBut *but, void **poin, void ***ppoin, short *tot, int from,
/* cruft to make uiBlock and uiBut private */
-int uiBlocksGetYMin(ListBase *lb)
+int UI_blocklist_min_y_get(ListBase *lb)
{
uiBlock *block;
int min = 0;
@@ -3847,13 +4032,13 @@ int uiBlocksGetYMin(ListBase *lb)
return min;
}
-void uiBlockSetDirection(uiBlock *block, char direction)
+void UI_block_direction_set(uiBlock *block, char direction)
{
block->direction = direction;
}
/* this call escapes if there's alignment flags */
-void uiBlockFlipOrder(uiBlock *block)
+void UI_block_order_flip(uiBlock *block)
{
uiBut *but;
float centy, miny = 10000, maxy = -10000;
@@ -3875,92 +4060,120 @@ void uiBlockFlipOrder(uiBlock *block)
but->rect.ymax = centy - (but->rect.ymax - centy);
SWAP(float, but->rect.ymin, but->rect.ymax);
}
+
+ block->flag ^= UI_BLOCK_IS_FLIP;
}
-void uiBlockSetFlag(uiBlock *block, int flag)
+void UI_block_flag_enable(uiBlock *block, int flag)
{
block->flag |= flag;
}
-void uiBlockClearFlag(uiBlock *block, int flag)
+void UI_block_flag_disable(uiBlock *block, int flag)
{
block->flag &= ~flag;
}
-void uiButSetFlag(uiBut *but, int flag)
+void UI_but_flag_enable(uiBut *but, int flag)
{
but->flag |= flag;
}
-void uiButClearFlag(uiBut *but, int flag)
+void UI_but_flag_disable(uiBut *but, int flag)
{
but->flag &= ~flag;
}
-void uiButSetDrawFlag(uiBut *but, int flag)
+void UI_but_drawflag_enable(uiBut *but, int flag)
{
but->drawflag |= flag;
}
-void uiButClearDrawFlag(uiBut *but, int flag)
+void UI_but_drawflag_disable(uiBut *but, int flag)
{
but->drawflag &= ~flag;
}
-void uiButSetMenuFromPulldown(uiBut *but)
+void UI_but_type_set_menu_from_pulldown(uiBut *but)
{
- BLI_assert(but->type == PULLDOWN);
- but->type = MENU;
- uiButClearDrawFlag(but, UI_BUT_TEXT_RIGHT);
- uiButSetDrawFlag(but, UI_BUT_TEXT_LEFT);
+ BLI_assert(but->type == UI_BTYPE_PULLDOWN);
+ but->type = UI_BTYPE_MENU;
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_RIGHT);
+ UI_but_drawflag_enable(but, UI_BUT_TEXT_LEFT);
}
-int uiButGetRetVal(uiBut *but)
+int UI_but_return_value_get(uiBut *but)
{
return but->retval;
}
-void uiButSetDragID(uiBut *but, ID *id)
+void UI_but_drag_set_id(uiBut *but, ID *id)
{
but->dragtype = WM_DRAG_ID;
+ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ MEM_SAFE_FREE(but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
but->dragpoin = (void *)id;
}
-void uiButSetDragRNA(uiBut *but, PointerRNA *ptr)
+void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
{
but->dragtype = WM_DRAG_RNA;
+ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ MEM_SAFE_FREE(but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
but->dragpoin = (void *)ptr;
}
-void uiButSetDragPath(uiBut *but, const char *path)
+void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
{
but->dragtype = WM_DRAG_PATH;
+ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ MEM_SAFE_FREE(but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
}
-void uiButSetDragName(uiBut *but, const char *name)
+void UI_but_drag_set_name(uiBut *but, const char *name)
{
but->dragtype = WM_DRAG_NAME;
+ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ MEM_SAFE_FREE(but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
but->dragpoin = (void *)name;
}
/* value from button itself */
-void uiButSetDragValue(uiBut *but)
+void UI_but_drag_set_value(uiBut *but)
{
but->dragtype = WM_DRAG_VALUE;
}
-void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale)
+void UI_but_drag_set_image(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
{
but->dragtype = WM_DRAG_PATH;
- but->icon = icon; /* no flag UI_HAS_ICON, so icon doesnt draw in button */
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesnt draw in button */
+ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ MEM_SAFE_FREE(but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
but->imb = imb;
but->imb_scale = scale;
}
-PointerRNA *uiButGetOperatorPtrRNA(uiBut *but)
+PointerRNA *UI_but_operator_ptr_get(uiBut *but)
{
if (but->optype && !but->opptr) {
but->opptr = MEM_callocN(sizeof(PointerRNA), "uiButOpPtr");
@@ -3970,12 +4183,12 @@ PointerRNA *uiButGetOperatorPtrRNA(uiBut *but)
return but->opptr;
}
-void uiButSetUnitType(uiBut *but, const int unit_type)
+void UI_but_unit_type_set(uiBut *but, const int unit_type)
{
but->unit_type = (unsigned char)(RNA_SUBTYPE_UNIT_VALUE(unit_type));
}
-int uiButGetUnitType(const uiBut *but)
+int UI_but_unit_type_get(const uiBut *but)
{
int ownUnit = (int)but->unit_type;
@@ -3991,26 +4204,26 @@ int uiButGetUnitType(const uiBut *but)
}
}
-void uiBlockSetHandleFunc(uiBlock *block, uiBlockHandleFunc func, void *arg)
+void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
{
block->handle_func = func;
block->handle_func_arg = arg;
}
-void uiBlockSetButmFunc(uiBlock *block, uiMenuHandleFunc func, void *arg)
+void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg)
{
block->butm_func = func;
block->butm_func_arg = arg;
}
-void uiBlockSetFunc(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2)
+void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2)
{
block->func = func;
block->func_arg1 = arg1;
block->func_arg2 = arg2;
}
-void uiBlockSetNFunc(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2)
+void UI_block_funcN_set(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2)
{
if (block->func_argN) {
MEM_freeN(block->func_argN);
@@ -4021,27 +4234,27 @@ void uiBlockSetNFunc(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *a
block->func_arg2 = arg2;
}
-void uiButSetRenameFunc(uiBut *but, uiButHandleRenameFunc func, void *arg1)
+void UI_but_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1)
{
but->rename_func = func;
but->rename_arg1 = arg1;
}
-void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)(const bContext *C, void *idv, void *arg1, void *arg2, rcti *rect), void *arg1, void *arg2)
+void UI_but_func_drawextra_set(uiBlock *block, void (*func)(const bContext *C, void *idv, void *arg1, void *arg2, rcti *rect), void *arg1, void *arg2)
{
block->drawextra = func;
block->drawextra_arg1 = arg1;
block->drawextra_arg2 = arg2;
}
-void uiButSetFunc(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
+void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
{
but->func = func;
but->func_arg1 = arg1;
but->func_arg2 = arg2;
}
-void uiButSetNFunc(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2)
+void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2)
{
if (but->func_argN) {
MEM_freeN(but->func_argN);
@@ -4052,75 +4265,82 @@ void uiButSetNFunc(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2)
but->func_arg2 = arg2;
}
-void uiButSetCompleteFunc(uiBut *but, uiButCompleteFunc func, void *arg)
+void UI_but_func_complete_set(uiBut *but, uiButCompleteFunc func, void *arg)
{
but->autocomplete_func = func;
but->autofunc_arg = arg;
}
+void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN)
+{
+ but->tip_func = func;
+ if (but->tip_argN) {
+ MEM_freeN(but->tip_argN);
+ }
+ but->tip_argN = argN;
+}
+
uiBut *uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, BLOCK, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
but->block_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, const char *str, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, BLOCK, 0, str, x, y, width, height, NULL, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, 0, str, x, y, width, height, NULL, 0.0, 0.0, 0.0, 0.0, tip);
but->block_create_func = func;
if (but->func_argN) {
MEM_freeN(but->func_argN);
}
but->func_argN = argN;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
but->block_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
but->menu_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag |= UI_BUT_ICON_LEFT;
- but->flag |= UI_ICON_SUBMENU;
+ but->flag |= UI_BUT_ICON_SUBMENU;
but->menu_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, PULLDOWN, 0, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag &= ~UI_BUT_ICON_LEFT;
but->menu_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
@@ -4128,18 +4348,18 @@ uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int ic
/* Block button containing both string label and icon */
uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, BLOCK, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- /* XXX temp, old menu calls pass on icon arrow, which is now UI_ICON_SUBMENU flag */
+ /* XXX temp, old menu calls pass on icon arrow, which is now UI_BUT_ICON_SUBMENU flag */
if (icon != ICON_RIGHTARROW_THIN) {
- but->icon = (BIFIconID) icon;
+ ui_def_but_icon(but, icon, 0);
but->drawflag |= UI_BUT_ICON_LEFT;
}
but->flag |= UI_HAS_ICON;
- but->flag |= UI_ICON_SUBMENU;
+ but->flag |= UI_BUT_ICON_SUBMENU;
but->block_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
@@ -4147,23 +4367,22 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
/* Block button containing icon */
uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, int x, int y, short width, short height, const char *tip)
{
- uiBut *but = ui_def_but(block, BLOCK, retval, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
-
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, retval, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
+
but->drawflag |= UI_BUT_ICON_LEFT;
but->block_create_func = func;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
uiBut *uiDefKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y, short width, short height, short *spoin, const char *tip)
{
- uiBut *but = ui_def_but(block, KEYEVT | UI_BUT_POIN_SHORT, retval, str, x, y, width, height, spoin, 0.0, 0.0, 0.0, 0.0, tip);
- ui_check_but(but);
+ uiBut *but = ui_def_but(block, UI_BTYPE_KEY_EVENT | UI_BUT_POIN_SHORT, retval, str, x, y, width, height, spoin, 0.0, 0.0, 0.0, 0.0, tip);
+ ui_but_update(but);
return but;
}
@@ -4171,44 +4390,46 @@ uiBut *uiDefKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y
/* modkeypoin will be set to KM_SHIFT, KM_ALT, KM_CTRL, KM_OSKEY bits */
uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y, short width, short height, short *keypoin, short *modkeypoin, const char *tip)
{
- uiBut *but = ui_def_but(block, HOTKEYEVT | UI_BUT_POIN_SHORT, retval, str, x, y, width, height, keypoin, 0.0, 0.0, 0.0, 0.0, tip);
+ uiBut *but = ui_def_but(block, UI_BTYPE_HOTKEY_EVENT | UI_BUT_POIN_SHORT, retval, str, x, y, width, height, keypoin, 0.0, 0.0, 0.0, 0.0, tip);
but->modifier_key = *modkeypoin;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
-/* arg is pointer to string/name, use uiButSetSearchFunc() below to make this work */
+/* arg is pointer to string/name, use UI_but_func_search_set() below to make this work */
/* here a1 and a2, if set, control thumbnail preview rows/cols */
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, int x, int y, short width, short height, float a1, float a2, const char *tip)
{
- uiBut *but = ui_def_but(block, SEARCH_MENU, retval, "", x, y, width, height, arg, 0.0, maxlen, a1, a2, tip);
-
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ uiBut *but = ui_def_but(block, UI_BTYPE_SEARCH_MENU, retval, "", x, y, width, height, arg, 0.0, maxlen, a1, a2, tip);
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
+
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
- ui_check_but(but);
+ ui_but_update(but);
return but;
}
-/* arg is user value, searchfunc and handlefunc both get it as arg */
-/* if active set, button opens with this item visible and selected */
-void uiButSetSearchFunc(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active)
+/**
+ * \param sfunc, bfunc: both get it as \a arg.
+ * \param arg: user value,
+ * \param active: when set, button opens with this item visible and selected.
+ */
+void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active)
{
but->search_func = sfunc;
but->search_arg = arg;
- uiButSetFunc(but, bfunc, arg, active);
+ UI_but_func_set(but, bfunc, arg, active);
/* search buttons show red-alert if item doesn't exist, not for menus */
if (0 == (but->block->flag & UI_BLOCK_LOOP)) {
/* skip empty buttons, not all buttons need input, we only show invalid */
if (but->drawstr[0])
- ui_but_search_test(but);
+ ui_but_search_refresh(but);
}
}
@@ -4227,7 +4448,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c
__func__, ot->idname, RNA_property_identifier(prop));
}
else {
- PointerRNA *ptr = uiButGetOperatorPtrRNA(but); /* Will create it if needed! */
+ PointerRNA *ptr = UI_but_operator_ptr_get(but); /* Will create it if needed! */
EnumPropertyItem *item, *item_array;
bool do_free;
@@ -4236,7 +4457,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c
for (item = item_array; item->identifier; item++) {
/* note: need to give the index rather than the identifier because the enum can be freed */
if (BLI_strcasestr(item->name, str)) {
- if (false == uiSearchItemAdd(items, item->name, SET_INT_IN_POINTER(item->value), 0))
+ if (false == UI_search_item_add(items, item->name, SET_INT_IN_POINTER(item->value), 0))
break;
}
}
@@ -4249,7 +4470,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c
static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *arg2)
{
wmOperatorType *ot = ((uiBut *)but)->optype;
- PointerRNA *opptr = uiButGetOperatorPtrRNA(but); /* Will create it if needed! */
+ PointerRNA *opptr = UI_but_operator_ptr_get(but); /* Will create it if needed! */
if (ot) {
if (ot->prop) {
@@ -4265,22 +4486,25 @@ static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *a
}
}
-/* Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback
- * to call again the right op with the right options (properties values). */
-uiBut *uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *properties,
- void *arg, int retval, int icon, int maxlen, int x, int y,
- short width, short height, float a1, float a2, const char *tip)
+/**
+ * Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback
+ * to call again the right op with the right options (properties values).
+ */
+uiBut *uiDefSearchButO_ptr(
+ uiBlock *block, wmOperatorType *ot, IDProperty *properties,
+ void *arg, int retval, int icon, int maxlen, int x, int y,
+ short width, short height, float a1, float a2, const char *tip)
{
uiBut *but;
but = uiDefSearchBut(block, arg, retval, icon, maxlen, x, y, width, height, a1, a2, tip);
- uiButSetSearchFunc(but, operator_enum_search_cb, but, operator_enum_call_cb, NULL);
+ UI_but_func_search_set(but, operator_enum_search_cb, but, operator_enum_call_cb, NULL);
but->optype = ot;
but->opcontext = WM_OP_EXEC_DEFAULT;
if (properties) {
- PointerRNA *ptr = uiButGetOperatorPtrRNA(but);
+ PointerRNA *ptr = UI_but_operator_ptr_get(but);
/* Copy idproperties. */
ptr->data = IDP_CopyProperty(properties);
}
@@ -4288,10 +4512,11 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *prope
return but;
}
-/* push a new event onto event queue to activate the given button
+/**
+ * push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup
*/
-void uiButSetFocusOnEnter(wmWindow *win, uiBut *but)
+void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
{
wmEvent event;
@@ -4305,7 +4530,7 @@ void uiButSetFocusOnEnter(wmWindow *win, uiBut *but)
wm_event_add(win, &event);
}
-void uiButGetStrInfo(bContext *C, uiBut *but, ...)
+void UI_but_string_info_get(bContext *C, uiBut *but, ...)
{
va_list args;
uiStringInfo *si;
@@ -4321,14 +4546,29 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
if (type == BUT_GET_LABEL) {
if (but->str) {
- tmp = BLI_strdup(but->str);
+ const char *str_sep;
+ size_t str_len;
+
+ if ((but->flag & UI_BUT_HAS_SEP_CHAR) &&
+ (str_sep = strrchr(but->str, UI_SEP_CHAR)))
+ {
+ str_len = (str_sep - but->str);
+ }
+ else {
+ str_len = strlen(but->str);
+ }
+
+ tmp = BLI_strdupn(but->str, str_len);
}
else {
type = BUT_GET_RNA_LABEL; /* Fail-safe solution... */
}
}
else if (type == BUT_GET_TIP) {
- if (but->tip && but->tip[0])
+ if (but->tip_func) {
+ tmp = but->tip_func(C, but->tip_argN, but->tip);
+ }
+ else if (but->tip && but->tip[0])
tmp = BLI_strdup(but->tip);
else
type = BUT_GET_RNA_TIP; /* Fail-safe solution... */
@@ -4343,8 +4583,8 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
tmp = BLI_strdup(RNA_struct_identifier(but->rnapoin.type));
else if (but->optype)
tmp = BLI_strdup(but->optype->idname);
- else if (ELEM(but->type, MENU, PULLDOWN)) {
- MenuType *mt = uiButGetMenuType(but);
+ else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
+ MenuType *mt = UI_but_menutype_get(but);
if (mt)
tmp = BLI_strdup(mt->idname);
}
@@ -4368,8 +4608,8 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
tmp = BLI_strdup(t);
}
}
- else if (ELEM(but->type, MENU, PULLDOWN)) {
- MenuType *mt = uiButGetMenuType(but);
+ else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
+ MenuType *mt = UI_but_menutype_get(but);
if (mt) {
/* not all menus are from python */
if (mt->ext.srna) {
@@ -4385,18 +4625,18 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
}
}
else if (type == BUT_GET_RNA_LABEL_CONTEXT) {
- const char *_tmp = BLF_I18NCONTEXT_DEFAULT;
+ const char *_tmp = BLT_I18NCONTEXT_DEFAULT;
if (but->rnaprop)
_tmp = RNA_property_translation_context(but->rnaprop);
else if (but->optype)
_tmp = RNA_struct_translation_context(but->optype->srna);
- else if (ELEM(but->type, MENU, PULLDOWN)) {
- MenuType *mt = uiButGetMenuType(but);
+ else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
+ MenuType *mt = UI_but_menutype_get(but);
if (mt)
_tmp = RNA_struct_translation_context(mt->ext.srna);
}
- if (BLF_is_default_context(_tmp)) {
- _tmp = BLF_I18NCONTEXT_DEFAULT_BPYRNA;
+ if (BLT_is_default_context(_tmp)) {
+ _tmp = BLT_I18NCONTEXT_DEFAULT_BPYRNA;
}
tmp = BLI_strdup(_tmp);
}
@@ -4410,10 +4650,10 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
/* enum property */
ptr = &but->rnapoin;
prop = but->rnaprop;
- value = (but->type == ROW) ? (int)but->hardmax : (int)ui_get_but_val(but);
+ value = (but->type == UI_BTYPE_ROW) ? (int)but->hardmax : (int)ui_but_value_get(but);
}
else if (but->optype) {
- PointerRNA *opptr = uiButGetOperatorPtrRNA(but);
+ PointerRNA *opptr = UI_but_operator_ptr_get(but);
wmOperatorType *ot = but->optype;
/* if the default property of the operator is enum and it is set,
@@ -4498,6 +4738,6 @@ void UI_reinit_font(void)
void UI_exit(void)
{
ui_resources_free();
- ui_button_clipboard_free();
+ ui_but_clipboard_free();
}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index fa0832b6273..37895a711fd 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -34,15 +34,14 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_animsys.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_nla.h"
#include "ED_keyframing.h"
@@ -55,28 +54,42 @@
#include "interface_intern.h"
-static FCurve *ui_but_get_fcurve(uiBut *but, bAction **action, bool *r_driven)
+static FCurve *ui_but_get_fcurve(uiBut *but, AnimData **adt, bAction **action, bool *r_driven, bool *r_special)
{
/* for entire array buttons we check the first component, it's not perfect
* but works well enough in typical cases */
int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return rna_get_fcurve(&but->rnapoin, but->rnaprop, rnaindex, action, r_driven);
+ return rna_get_fcurve_context_ui(but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
}
void ui_but_anim_flag(uiBut *but, float cfra)
{
+ AnimData *adt;
+ bAction *act;
FCurve *fcu;
bool driven;
-
+ bool special;
+
but->flag &= ~(UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN);
-
- fcu = ui_but_get_fcurve(but, NULL, &driven);
-
+
+ /* NOTE: "special" is reserved for special F-Curves stored on the animation data
+ * itself (which are used to animate properties of the animation data).
+ * We count those as "animated" too for now
+ */
+ fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
+
if (fcu) {
if (!driven) {
but->flag |= UI_BUT_ANIMATED;
+ /* T41525 - When the active action is a NLA strip being edited,
+ * we need to correct the frame number to "look inside" the
+ * remapped action
+ */
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
+
if (fcurve_frame_has_keyframe(fcu, cfra, 0))
but->flag |= UI_BUT_ANIMATED_KEY;
}
@@ -90,10 +103,10 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
ChannelDriver *driver;
- bool driven;
-
- fcu = ui_but_get_fcurve(but, NULL, &driven);
-
+ bool driven, special;
+
+ fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
+
if (fcu && driven) {
driver = fcu->driver;
@@ -110,9 +123,9 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
{
FCurve *fcu;
ChannelDriver *driver;
- bool driven;
+ bool driven, special;
- fcu = ui_but_get_fcurve(but, NULL, &driven);
+ fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
if (fcu && driven) {
driver = fcu->driver;
@@ -207,10 +220,28 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
bAction *action;
FCurve *fcu;
bool driven;
+ bool special;
- fcu = ui_but_get_fcurve(but, &action, &driven);
-
- if (fcu && !driven) {
+ fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special);
+
+ if (fcu == NULL)
+ return;
+
+ if (special) {
+ /* NLA Strip property */
+ if (IS_AUTOKEY_ON(scene)) {
+ ReportList *reports = CTX_wm_reports(C);
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, 0);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ }
+ else if (!driven) {
id = but->rnapoin.id.data;
/* TODO: this should probably respect the keyingset only option for anim */
@@ -219,7 +250,14 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
short flag = ANIM_get_keyframing_flags(scene, 1);
fcu->flag &= ~FCURVE_SELECTED;
- insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
+
+ /* Note: We use but->rnaindex instead of fcu->array_index,
+ * because a button may control all items of an array at once.
+ * E.g., color wheels (see T42567). */
+ BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1));
+ insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, but->rnaindex, cfra, flag);
+
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
@@ -227,54 +265,54 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
void ui_but_anim_insert_keyframe(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_keyframe_insert_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_delete_keyframe(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_keyframe_delete_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_clear_keyframe(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_keyframe_clear_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_add_driver(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_driver_button_add", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_remove_driver(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_driver_button_remove", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_copy_driver(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_paste_driver(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_add_keyingset(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_keyingset_button_add", WM_OP_INVOKE_DEFAULT, NULL);
}
void ui_but_anim_remove_keyingset(bContext *C)
{
- /* this operator calls uiContextActiveProperty */
+ /* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_keyingset_button_remove", WM_OP_INVOKE_DEFAULT, NULL);
}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 235d7652539..84767eae350 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -62,21 +62,21 @@
static int roundboxtype = UI_CNR_ALL;
-void uiSetRoundBox(int type)
+void UI_draw_roundbox_corner_set(int type)
{
/* Not sure the roundbox function is the best place to change this
- * if this is undone, its not that big a deal, only makes curves edges
+ * if this is undone, it's not that big a deal, only makes curves edges
* square for the */
roundboxtype = type;
}
-int uiGetRoundBox(void)
+int UI_draw_roundbox_corner_get(void)
{
return roundboxtype;
}
-void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float rad)
+void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad)
{
float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
{0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
@@ -152,7 +152,9 @@ static void round_box_shade_col(const float col1[3], float const col2[3], const
/* linear horizontal shade within button or in outline */
/* view2d scrollers use it */
-void uiDrawBoxShade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown)
+void UI_draw_roundbox_shade_x(
+ int mode, float minx, float miny, float maxx, float maxy,
+ float rad, float shadetop, float shadedown)
{
float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
{0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
@@ -260,8 +262,9 @@ void uiDrawBoxShade(int mode, float minx, float miny, float maxx, float maxy, fl
/* linear vertical shade within button or in outline */
/* view2d scrollers use it */
-void uiDrawBoxVerticalShade(int mode, float minx, float miny, float maxx, float maxy,
- float rad, float shadeLeft, float shadeRight)
+void UI_draw_roundbox_shade_y(
+ int mode, float minx, float miny, float maxx, float maxy,
+ float rad, float shadeLeft, float shadeRight)
{
float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
{0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
@@ -365,7 +368,7 @@ void uiDrawBoxVerticalShade(int mode, float minx, float miny, float maxx, float
}
/* plain antialiased unfilled rectangle */
-void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad)
+void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad)
{
float color[4];
@@ -380,18 +383,24 @@ void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad)
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
- uiDrawBox(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
/* (old, used in outliner) plain antialiased filled box */
-void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad)
+void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad)
{
ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA);
}
+void UI_draw_text_underline(int pos_x, int pos_y, int len, int height)
+{
+ int ofs_y = 4 * U.pixelsize;
+ glRecti(pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
+}
+
/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
@@ -441,6 +450,51 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
#endif
}
+/**
+ * Draw title and text safe areas.
+ *
+ * The first 4 parameters are the offsets for the view, not the zones.
+ */
+void UI_draw_safe_areas(
+ float x1, float x2, float y1, float y2,
+ const float title_aspect[2], const float action_aspect[2])
+{
+ const float size_x_half = (x2 - x1) * 0.5f;
+ const float size_y_half = (y2 - y1) * 0.5f;
+
+ const float *safe_areas[] = {title_aspect, action_aspect};
+ int i, safe_len = ARRAY_SIZE(safe_areas);
+ bool is_first = true;
+
+ for (i = 0; i < safe_len; i++) {
+ if (safe_areas[i][0] || safe_areas[i][1]) {
+ float margin_x, margin_y;
+ float minx, miny, maxx, maxy;
+
+ if (is_first) {
+ UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0);
+ is_first = false;
+ }
+
+ margin_x = safe_areas[i][0] * size_x_half;
+ margin_y = safe_areas[i][1] * size_y_half;
+
+ minx = x1 + margin_x;
+ miny = y1 + margin_y;
+ maxx = x2 - margin_x;
+ maxy = y2 - margin_y;
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(maxx, miny);
+ glVertex2f(maxx, maxy);
+ glVertex2f(minx, maxy);
+ glVertex2f(minx, miny);
+ glEnd();
+ }
+ }
+}
+
+
static void draw_scope_end(const rctf *rect, GLint *scissor)
{
/* restore scissortest */
@@ -450,12 +504,13 @@ static void draw_scope_end(const rctf *rect, GLint *scissor)
/* outline */
glColor4f(0.f, 0.f, 0.f, 0.5f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f);
}
-static void histogram_draw_one(float r, float g, float b, float alpha,
- float x, float y, float w, float h, const float *data, int res, const bool is_line)
+static void histogram_draw_one(
+ float r, float g, float b, float alpha,
+ float x, float y, float w, float h, const float *data, int res, const bool is_line)
{
int i;
@@ -485,7 +540,7 @@ static void histogram_draw_one(float r, float g, float b, float alpha,
glColor4f(r, g, b, alpha);
glShadeModel(GL_FLAT);
- glBegin(GL_QUAD_STRIP);
+ glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x, y);
glVertex2f(x, y + (data[0] * h));
for (i = 1; i < res; i++) {
@@ -533,10 +588,10 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glColor4f(0.f, 0.f, 0.f, 0.3f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
+
+ UI_ThemeColor4(TH_PREVIEW_BACK);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
/* need scissor test, histogram can draw outside of boundary */
glGetIntegerv(GL_VIEWPORT, scissor);
@@ -620,10 +675,10 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glColor4f(0.f, 0.f, 0.f, 0.3f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
+
+ UI_ThemeColor4(TH_PREVIEW_BACK);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
/* need scissor test, waveform can draw outside of boundary */
glGetIntegerv(GL_VIEWPORT, scissor);
@@ -768,8 +823,8 @@ static void vectorscope_draw_target(float centerx, float centery, float diam, co
if (u > 0 && v >= 0) tangle = atanf(v / u);
else if (u > 0 && v < 0) tangle = atanf(v / u) + 2.0f * (float)M_PI;
else if (u < 0) tangle = atanf(v / u) + (float)M_PI;
- else if (u == 0 && v > 0.0f) tangle = (float)M_PI / 2.0f;
- else if (u == 0 && v < 0.0f) tangle = -(float)M_PI / 2.0f;
+ else if (u == 0 && v > 0.0f) tangle = M_PI_2;
+ else if (u == 0 && v < 0.0f) tangle = -M_PI_2;
tampli = sqrtf(u * u + v * v);
/* small target vary by 2.5 degree and 2.5 IRE unit */
@@ -839,10 +894,10 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glColor4f(0.f, 0.f, 0.f, 0.3f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
+
+ UI_ThemeColor4(TH_PREVIEW_BACK);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
/* need scissor test, hvectorscope can draw outside of boundary */
glGetIntegerv(GL_VIEWPORT, scissor);
@@ -1067,7 +1122,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
if (coba == NULL) return;
if (but->block->color_profile)
- display = ui_block_display_get(but->block);
+ display = ui_block_cm_display_get(but->block);
x1 = rect->xmin;
sizex = rect->xmax - x1;
@@ -1093,7 +1148,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[1] = y1 + sizey_solid;
v2[1] = rect->ymax;
- glBegin(GL_QUAD_STRIP);
+ glBegin(GL_TRIANGLE_STRIP);
for (a = 0; a <= sizex; a++) {
pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
@@ -1112,7 +1167,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[1] = y1;
v2[1] = y1 + sizey_solid;
- glBegin(GL_QUAD_STRIP);
+ glBegin(GL_TRIANGLE_STRIP);
for (a = 0; a <= sizex; a++) {
pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
@@ -1158,7 +1213,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
}
}
-void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
+void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
{
static GLuint displist = 0;
int a, old[8];
@@ -1171,8 +1226,8 @@ void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
/* backdrop */
glColor3ubv((unsigned char *)wcol->inner);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f);
/* sphere color */
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffn);
@@ -1189,7 +1244,7 @@ void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
glEnable(GL_LIGHT7);
glEnable(GL_LIGHTING);
- ui_get_but_vectorf(but, dir);
+ ui_but_v3_get(but, dir);
dir[3] = 0.0f; /* glLightfv needs 4 args, 0.0 is sun */
glLightfv(GL_LIGHT7, GL_POSITION, dir);
@@ -1206,8 +1261,8 @@ void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
size = BLI_rcti_size_x(rect) / 200.f;
else
size = BLI_rcti_size_y(rect) / 200.f;
-
- glScalef(size, size, size);
+
+ glScalef(size, size, MIN2(size, 1.0f));
if (displist == 0) {
GLUquadricObj *qobj;
@@ -1399,7 +1454,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
glEnd();
}
else if (cumap->cur == 3) {
- float lum = rgb_to_bw(cumap->sample);
+ float lum = IMB_colormanagement_get_luminance(cumap->sample);
glColor3ub(240, 240, 240);
glBegin(GL_LINES);
@@ -1511,8 +1566,8 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
if (scopes->track_disabled) {
glColor4f(0.7f, 0.3f, 0.3f, 0.3f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
ok = 1;
}
@@ -1559,8 +1614,8 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
if (scopes->use_track_mask) {
glColor4f(0.0f, 0.0f, 0.0f, 0.3f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
}
glaDrawPixelsSafe(rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y,
@@ -1600,8 +1655,8 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
if (!ok) {
glColor4f(0.f, 0.f, 0.f, 0.3f);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
}
/* outline */
@@ -1717,7 +1772,7 @@ static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float s
glShadeModel(GL_FLAT);
}
-void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
+void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
/* accumulated outline boxes to make shade not linear, is more pleasant */
ui_shadowbox(minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8);
@@ -1727,7 +1782,7 @@ void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, fl
}
-void ui_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int UNUSED(select))
+void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int UNUSED(select))
{
int i;
float rad;
@@ -1758,13 +1813,13 @@ void ui_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int
glColor4f(0.0f, 0.0f, 0.0f, calpha);
calpha += dalpha;
- uiDrawBox(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a);
}
/* outline emphasis */
glEnable(GL_LINE_SMOOTH);
glColor4ub(0, 0, 0, 100);
- uiDrawBox(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 5b7915e20c5..ceea4ff42d9 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -36,10 +36,13 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
#include "BKE_idcode.h"
+#include "BKE_unit.h"
#include "RNA_access.h"
@@ -64,6 +67,38 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+/* -------------------------------------------------------------------- */
+/* Utility Functions
+ */
+/** \name Generic Shared Functions
+ * \{ */
+
+static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name)
+{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ wmWindow *win = CTX_wm_window(C);
+ int x = win->eventstate->x;
+ int y = win->eventstate->y;
+ const unsigned char fg[4] = {255, 255, 255, 255};
+ const unsigned char bg[4] = {0, 0, 0, 50};
+
+
+ if ((name[0] == '\0') ||
+ (BLI_rcti_isect_pt(&ar->winrct, x, y) == false))
+ {
+ return;
+ }
+
+ x = x - ar->winrct.xmin;
+ y = y - ar->winrct.ymin;
+
+ y += U.widget_unit;
+
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/* Eyedropper
@@ -91,7 +126,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
- uiContextActiveProperty(C, &eye->ptr, &eye->prop, &eye->index);
+ UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
if ((eye->ptr.data == NULL) ||
(eye->prop == NULL) ||
@@ -139,43 +174,42 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) {
- if (sa->spacetype == SPACE_IMAGE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- SpaceImage *sima = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) {
- return;
- }
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+
+ if (sa) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceImage *sima = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) {
+ return;
}
}
- else if (sa->spacetype == SPACE_NODE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- SpaceNode *snode = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) {
- return;
- }
+ }
+ else if (sa->spacetype == SPACE_NODE) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceNode *snode = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) {
+ return;
}
}
- else if (sa->spacetype == SPACE_CLIP) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- SpaceClip *sc = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) {
- return;
- }
+ }
+ else if (sa->spacetype == SPACE_CLIP) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceClip *sc = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) {
+ return;
}
}
}
@@ -328,7 +362,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a data-block from the 3D view";
/* api callbacks */
ot->invoke = eyedropper_invoke;
@@ -338,20 +372,20 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
ot->poll = eyedropper_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
/* properties */
}
+
/** \} */
/* -------------------------------------------------------------------- */
-/* Data Dropper
- *
- * note: datadropper is only internal name to avoid confusion in this file
- */
+/* Data Dropper */
/** \name Eyedropper (ID data-blocks)
+ *
+ * \note: datadropper is only internal name to avoid confusion in this file.
* \{ */
typedef struct DataDropper {
@@ -369,31 +403,7 @@ typedef struct DataDropper {
static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
{
DataDropper *ddr = arg;
- int width;
- const char *name = ddr->name;
- wmWindow *win = CTX_wm_window(C);
- int x = win->eventstate->x;
- int y = win->eventstate->y;
-
- if ((name[0] == '\0') ||
- (BLI_rcti_isect_pt(&ar->winrct, x, y) == false))
- {
- return;
- }
-
- width = UI_GetStringWidth(name);
- x = x - ar->winrct.xmin;
- y = y - ar->winrct.ymin;
-
- y += 20;
-
- glColor4ub(0, 0, 0, 50);
-
- uiSetRoundBox(UI_CNR_ALL | UI_RB_ALPHA);
- uiRoundBox(x, y, x + width + 8, y + 15, 4);
-
- glColor4ub(255, 255, 255, 255);
- UI_DrawString(x + 4, y + 4, name);
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
}
@@ -411,7 +421,7 @@ static int datadropper_init(bContext *C, wmOperator *op)
op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
- uiContextActiveProperty(C, &ddr->ptr, &ddr->prop, &index_dummy);
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
if ((ddr->ptr.data == NULL) ||
(ddr->prop == NULL) ||
@@ -427,7 +437,8 @@ static int datadropper_init(bContext *C, wmOperator *op)
type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
ddr->idcode = RNA_type_to_ID_code(type);
BLI_assert(ddr->idcode != 0);
- ddr->idcode_name = BKE_idcode_to_name(ddr->idcode);
+ /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
+ ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
return true;
}
@@ -447,6 +458,8 @@ static void datadropper_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
+
+ WM_event_add_mousemove(C);
}
static void datadropper_cancel(bContext *C, wmOperator *op)
@@ -464,53 +477,49 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa;
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my);
ScrArea *area_prev = CTX_wm_area(C);
ARegion *ar_prev = CTX_wm_region(C);
ddr->name[0] = '\0';
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- const int mval[2] = {
- mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
- Base *base;
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* grr, always draw else we leave stale text */
- ED_region_tag_redraw(ar);
-
- base = ED_view3d_give_base_under_cursor(C, mval);
- if (base) {
- Object *ob = base->object;
- ID *id = NULL;
- if (ddr->idcode == ID_OB) {
- id = (ID *)ob;
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ Base *base;
+
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* grr, always draw else we leave stale text */
+ ED_region_tag_redraw(ar);
+
+ base = ED_view3d_give_base_under_cursor(C, mval);
+ if (base) {
+ Object *ob = base->object;
+ ID *id = NULL;
+ if (ddr->idcode == ID_OB) {
+ id = (ID *)ob;
+ }
+ else if (ob->data) {
+ if (GS(((ID *)ob->data)->name) == ddr->idcode) {
+ id = (ID *)ob->data;
}
- else if (ob->data) {
- if (GS(((ID *)ob->data)->name) == ddr->idcode) {
- id = (ID *)ob->data;
- }
- else {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
- ddr->idcode_name);
- }
- }
-
- if (id) {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
- ddr->idcode_name, id->name + 2);
- *r_id = id;
+ else {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
+ ddr->idcode_name);
}
+ }
- break;
+ if (id) {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
+ ddr->idcode_name, id->name + 2);
+ *r_id = id;
}
}
}
@@ -627,7 +636,7 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper Datablock";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a datablock from the Blender Window to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -637,7 +646,312 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
ot->poll = datadropper_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Depth Dropper */
+
+/** \name Eyedropper (Depth)
+ *
+ * \note: depthdropper is only internal name to avoid confusion in this file.
+ * \{ */
+
+typedef struct DepthDropper {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ bool accum_start; /* has mouse been presed */
+ float accum_depth;
+ int accum_tot;
+
+ ARegionType *art;
+ void *draw_handle_pixel;
+ char name[200];
+} DepthDropper;
+
+
+static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
+{
+ DepthDropper *ddr = arg;
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
+}
+
+
+static int depthdropper_init(bContext *C, wmOperator *op)
+{
+ DepthDropper *ddr;
+ int index_dummy;
+
+ SpaceType *st;
+ ARegionType *art;
+
+ st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
+
+ op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
+
+ /* fallback to the active camera's dof */
+ if (ddr->prop == NULL) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && (((ID *)v3d->camera->data)->lib == NULL)) {
+ RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
+ ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
+ }
+ }
+ }
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_type(ddr->prop) != PROP_FLOAT))
+ {
+ return false;
+ }
+
+ ddr->art = art;
+ ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+
+ return true;
+}
+
+static void depthdropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ DepthDropper *ddr = (DepthDropper *)op->customdata;
+
+ if (ddr->art) {
+ ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
+ }
+
+ MEM_freeN(op->customdata);
+
+ op->customdata = NULL;
+ }
+}
+
+static void depthdropper_cancel(bContext *C, wmOperator *op)
+{
+ depthdropper_exit(C, op);
+}
+
+/* *** depthdropper id helper functions *** */
+/**
+ * \brief get the ID from the screen.
+ *
+ */
+static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
+{
+
+ /* we could use some clever */
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+ Scene *scene = win->screen->scene;
+ UnitSettings *unit = &scene->unit;
+ const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+
+ ddr->name[0] = '\0';
+
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ /* weak, we could pass in some reference point */
+ const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ float co[3];
+
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* grr, always draw else we leave stale text */
+ ED_region_tag_redraw(ar);
+
+ view3d_operator_needs_opengl(C);
+
+ if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) {
+ const float mval_center_fl[2] = {
+ (float)ar->winx / 2,
+ (float)ar->winy / 2};
+ float co_align[3];
+
+ /* quick way to get view-center aligned point */
+ ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align);
+
+ *r_depth = len_v3v3(view_co, co_align);
+
+ bUnit_AsString(ddr->name, sizeof(ddr->name),
+ (double)*r_depth,
+ 4, unit->system, B_UNIT_LENGTH, do_split, false);
+ }
+ else {
+ BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
+ }
+ }
+ }
+ }
+
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+}
+
+/* sets the sample depth RGB, maintaining A */
+static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
+{
+ RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
+ RNA_property_update(C, &ddr->ptr, ddr->prop);
+}
+
+/* set sample from accumulated values */
+static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
+{
+ float depth = ddr->accum_depth;
+ if (ddr->accum_tot) {
+ depth /= (float)ddr->accum_tot;
+ }
+ depthdropper_depth_set(C, ddr, depth);
+}
+
+/* single point sample & set */
+static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
+{
+ float depth = -1.0f;
+ if (depth != -1.0f) {
+ depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
+ depthdropper_depth_set(C, ddr, depth);
+ }
+}
+
+static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
+{
+ float depth = -1.0f;
+ depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
+ if (depth != -1.0f) {
+ ddr->accum_depth += depth;
+ ddr->accum_tot++;
+ }
+}
+
+/* main modal status check */
+static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ DepthDropper *ddr = (DepthDropper *)op->customdata;
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ depthdropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ if (ddr->accum_tot == 0) {
+ depthdropper_depth_sample(C, ddr, event->x, event->y);
+ }
+ else {
+ depthdropper_depth_set_accum(C, ddr);
+ }
+ depthdropper_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ else if (event->val == KM_PRESS) {
+ /* enable accum and make first sample */
+ ddr->accum_start = true;
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ }
+ break;
+ case MOUSEMOVE:
+ if (ddr->accum_start) {
+ /* button is pressed so keep sampling */
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_set_accum(C, ddr);
+ }
+ break;
+ case SPACEKEY:
+ if (event->val == KM_RELEASE) {
+ ddr->accum_tot = 0;
+ ddr->accum_depth = 0.0f;
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_set_accum(C, ddr);
+ }
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (depthdropper_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ depthdropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int depthdropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (depthdropper_init(C, op)) {
+ /* cleanup */
+ depthdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int depthdropper_poll(bContext *C)
+{
+ if (!CTX_wm_window(C)) return 0;
+ else return 1;
+}
+
+void UI_OT_eyedropper_depth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Depth";
+ ot->idname = "UI_OT_eyedropper_depth";
+ ot->description = "Sample depth from the 3D view";
+
+ /* api callbacks */
+ ot->invoke = depthdropper_invoke;
+ ot->modal = depthdropper_modal;
+ ot->cancel = depthdropper_cancel;
+ ot->exec = depthdropper_exec;
+ ot->poll = depthdropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
/* properties */
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index d3c9ec1fafb..fe5a5031725 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -52,11 +52,11 @@
#include "BLI_linklist.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
+#include "BLI_string_cursor_utf8.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
-#include "BLI_string_cursor_utf8.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "PIL_time.h"
@@ -87,6 +87,11 @@
#include "WM_api.h"
#include "WM_types.h"
+#ifdef WITH_INPUT_IME
+# include "wm_window.h"
+# include "BLT_lang.h"
+#endif
+
/* place the mouse at the scaled down location when un-grabbing */
#define USE_CONT_MOUSE_CORRECT
/* support dragging toggle buttons */
@@ -95,6 +100,9 @@
/* support dragging multiple number buttons at once */
#define USE_DRAG_MULTINUM
+/* allow dragging/editing all other selected items at once */
+#define USE_ALLSELECT
+
/* so we can avoid very small mouse-moves from jumping away from keyboard navigation [#34936] */
#define USE_KEYNAV_LIMIT
@@ -103,10 +111,14 @@
#define UI_MAX_PASSWORD_STR 128
+/* This hack is needed because we don't have a good way to re-reference keymap items once added: T42944 */
+#define USE_KEYMAP_ADD_HACK
+
/* proto */
-static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
-static void ui_add_link(bContext *C, uiBut *from, uiBut *to);
+static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to);
+static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to);
static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event);
+static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b);
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -150,17 +162,63 @@ typedef enum uiHandleButtonState {
} uiHandleButtonState;
+#ifdef USE_ALLSELECT
+
+/* Unfortunately theres no good way handle more generally:
+ * (propagate single clicks on layer buttons to other objects) */
+#define USE_ALLSELECT_LAYER_HACK
+
+typedef struct uiSelectContextElem {
+ PointerRNA ptr;
+ union {
+ bool val_b;
+ int val_i;
+ float val_f;
+ };
+} uiSelectContextElem;
+
+typedef struct uiSelectContextStore {
+ uiSelectContextElem *elems;
+ int elems_len;
+ bool do_free;
+ bool is_enabled;
+ /* When set, simply copy values (don't apply difference).
+ * Rules are:
+ * - dragging numbers uses delta.
+ * - typing in values will assign to all. */
+ bool is_copy;
+} uiSelectContextStore;
+
+static bool ui_selectcontext_begin(
+ bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data);
+static void ui_selectcontext_end(
+ uiBut *but, uiSelectContextStore *selctx_data);
+static void ui_selectcontext_apply(
+ bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data,
+ const double value, const double value_orig);
+
+#define IS_ALLSELECT_EVENT(event) ((event)->alt != 0)
+
+/** just show a tinted color so users know its activated */
+#define UI_BUT_IS_SELECT_CONTEXT UI_BUT_NODE_ACTIVE
+
+#endif /* USE_ALLSELECT */
+
+
#ifdef USE_DRAG_MULTINUM
-/* how far to drag before we check for gesture direction (in pixels),
+/**
+ * how far to drag before we check for gesture direction (in pixels),
* note: half the height of a button is about right... */
#define DRAG_MULTINUM_THRESHOLD_DRAG_X (UI_UNIT_Y / 4)
-/* how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
+/**
+ * how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
* locking down the buttons so we can drag freely without worrying about vertical movement. */
#define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4)
-/* how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product)
+/**
+ * how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product)
* note: we should be quite strict here, since doing a vertical gesture by accident should be avoided,
* however with some care a user should be able to do a vertical movement without *missing*. */
#define DRAG_MULTINUM_THRESHOLD_VERTICAL (0.75f)
@@ -170,6 +228,10 @@ typedef enum uiHandleButtonState {
typedef struct uiButMultiState {
double origvalue;
uiBut *but;
+
+#ifdef USE_ALLSELECT
+ uiSelectContextStore select_others;
+#endif
} uiButMultiState;
typedef struct uiHandleButtonMulti {
@@ -202,8 +264,6 @@ typedef struct uiHandleButtonMulti {
#endif /* USE_DRAG_MULTINUM */
-
-
typedef struct uiHandleButtonData {
wmWindowManager *wm;
wmWindow *window;
@@ -252,16 +312,16 @@ typedef struct uiHandleButtonData {
CBData *dragcbd;
#ifdef USE_CONT_MOUSE_CORRECT
- /* when ungrabbing buttons which are #ui_is_a_warp_but(), we may want to position them
+ /* when ungrabbing buttons which are #ui_but_is_cursor_warp(), we may want to position them
* FLT_MAX signifies do-nothing, use #ui_block_to_window_fl() to get this into a usable space */
float ungrab_mval[2];
#endif
- /* menu open (watch uiFreeActiveButtons) */
+ /* menu open (watch UI_screen_free_active_but) */
uiPopupBlockHandle *menu;
int menuretval;
- /* search box (watch uiFreeActiveButtons) */
+ /* search box (watch UI_screen_free_active_but) */
ARegion *searchbox;
#ifdef USE_KEYNAV_LIMIT
struct uiKeyNavLock searchbox_keynav_state;
@@ -272,6 +332,10 @@ typedef struct uiHandleButtonData {
uiHandleButtonMulti multi_data;
#endif
+#ifdef USE_ALLSELECT
+ uiSelectContextStore select_others;
+#endif
+
/* post activate */
uiButtonActivateType posttype;
uiBut *postbut;
@@ -313,21 +377,21 @@ typedef struct uiAfterFunc {
-static bool ui_is_but_interactive(const uiBut *but, const bool labeledit);
+static bool ui_but_is_interactive(const uiBut *but, const bool labeledit);
static bool ui_but_contains_pt(uiBut *but, float mx, float my);
-static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y);
+static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y);
static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit);
static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event);
static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
-static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data,
- const bool mousemove, const bool onfree);
+static void button_activate_exit(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ const bool mousemove, const bool onfree);
static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *userdata);
static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
-static void button_timers_tooltip_remove(bContext *C, uiBut *but);
#ifdef USE_DRAG_MULTINUM
-static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block);
+static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block);
static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut *but);
#endif
@@ -348,11 +412,17 @@ static enum eSnapType ui_event_to_snap(const wmEvent *event)
return (event->ctrl) ? (event->shift) ? SNAP_ON_SMALL : SNAP_ON : SNAP_OFF;
}
+static bool ui_event_is_snap(const wmEvent *event)
+{
+ return (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY) ||
+ ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY));
+}
+
static void ui_color_snap_hue(const enum eSnapType snap, float *r_hue)
{
const float snap_increment = (snap == SNAP_ON_SMALL) ? 24 : 12;
BLI_assert(snap != SNAP_OFF);
- *r_hue = floorf(0.5f + ((*r_hue) * snap_increment)) / snap_increment;
+ *r_hue = roundf((*r_hue) * snap_increment) / snap_increment;
}
/* assumes event type is MOUSEPAN */
@@ -390,7 +460,17 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
bool ui_but_is_editable(const uiBut *but)
{
- return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
+ return !ELEM(but->type,
+ UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE,
+ UI_BTYPE_ROUNDBOX, UI_BTYPE_LISTBOX, UI_BTYPE_PROGRESS_BAR);
+}
+
+bool ui_but_is_editable_as_text(const uiBut *but)
+{
+ return ELEM(but->type,
+ UI_BTYPE_TEXT, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER,
+ UI_BTYPE_SEARCH_MENU);
+
}
static uiBut *ui_but_prev(uiBut *but)
@@ -435,10 +515,13 @@ static uiBut *ui_but_last(uiBlock *block)
return NULL;
}
-static bool ui_is_a_warp_but(uiBut *but)
+static bool ui_but_is_cursor_warp(uiBut *but)
{
if (U.uiflag & USER_CONTINUOUS_MOUSE) {
- if (ELEM(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
+ if (ELEM(but->type,
+ UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_HSVCIRCLE,
+ UI_BTYPE_TRACK_PREVIEW, UI_BTYPE_HSVCUBE, UI_BTYPE_CURVE))
+ {
return true;
}
}
@@ -451,10 +534,9 @@ static float ui_mouse_scale_warp_factor(const bool shift)
return shift ? 0.05f : 1.0f;
}
-static void ui_mouse_scale_warp(uiHandleButtonData *data,
- const float mx, const float my,
- float *r_mx, float *r_my,
- const bool shift)
+static void ui_mouse_scale_warp(
+ uiHandleButtonData *data, const float mx, const float my,
+ float *r_mx, float *r_my, const bool shift)
{
const float fac = ui_mouse_scale_warp_factor(shift);
@@ -464,7 +546,7 @@ static void ui_mouse_scale_warp(uiHandleButtonData *data,
}
/* file selectors are exempt from utf-8 checks */
-bool ui_is_but_utf8(const uiBut *but)
+bool ui_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
const int subtype = RNA_property_subtype(but->rnaprop);
@@ -523,7 +605,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
* with these functions removing the buttons we are working with */
if (but->func || but->funcN || block->handle_func || but->rename_func ||
- (but->type == BUTM && block->butm_func) || but->optype || but->rnaprop)
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func) || but->optype || but->rnaprop)
{
after = ui_afterfunc_new();
@@ -548,7 +630,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->handle_func_arg = block->handle_func_arg;
after->retval = but->retval;
- if (but->type == BUTM) {
+ if (but->type == UI_BTYPE_BUT_MENU) {
after->butm_func = block->butm_func;
after->butm_func_arg = block->butm_func_arg;
after->a2 = but->a2;
@@ -570,8 +652,8 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
}
}
-/* typically call ui_apply_undo(), ui_apply_autokey() */
-static void ui_apply_undo(uiBut *but)
+/* typically call ui_apply_but_undo(), ui_apply_but_autokey() */
+static void ui_apply_but_undo(uiBut *but)
{
uiAfterFunc *after;
@@ -579,8 +661,8 @@ static void ui_apply_undo(uiBut *but)
const char *str = NULL;
/* define which string to use for undo */
- if (ELEM(but->type, LINK, INLINK)) str = "Add button link";
- else if (but->type == MENU) str = but->drawstr;
+ if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) str = "Add button link";
+ else if (but->type == UI_BTYPE_MENU) str = but->drawstr;
else if (but->drawstr[0]) str = but->drawstr;
else str = but->tip;
@@ -595,7 +677,7 @@ static void ui_apply_undo(uiBut *but)
}
}
-static void ui_apply_autokey(bContext *C, uiBut *but)
+static void ui_apply_but_autokey(bContext *C, uiBut *but)
{
Scene *scene = CTX_data_scene(C);
@@ -689,7 +771,7 @@ static void ui_apply_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_BUTM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
- ui_set_but_val(but, but->hardmin);
+ ui_but_value_set(but, but->hardmin);
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -698,10 +780,10 @@ static void ui_apply_but_BUTM(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data)
{
- if (but->type == MENU)
- ui_set_but_val(but, data->value);
+ if (but->type == UI_BTYPE_MENU)
+ ui_but_value_set(but, data->value);
- ui_check_but(but);
+ ui_but_update(but);
ui_apply_but_func(C, but);
data->retval = but->retval;
data->applied = true;
@@ -712,7 +794,7 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
double value;
int w, lvalue, push;
- value = ui_get_but_val(but);
+ value = ui_but_value_get(but);
lvalue = (int)value;
if (but->bit) {
@@ -720,17 +802,17 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
if (w) lvalue = UI_BITBUT_CLR(lvalue, but->bitnr);
else lvalue = UI_BITBUT_SET(lvalue, but->bitnr);
- ui_set_but_val(but, (double)lvalue);
- if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but);
+ ui_but_value_set(but, (double)lvalue);
+ if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) ui_but_update(but);
}
else {
if (value == 0.0) push = 1;
else push = 0;
- if (ELEM(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
- ui_set_but_val(but, (double)push);
- if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but);
+ if (ELEM(but->type, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE_N, UI_BTYPE_CHECKBOX_N)) push = !push;
+ ui_but_value_set(but, (double)push);
+ if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) ui_but_update(but);
}
ui_apply_but_func(C, but);
@@ -743,14 +825,14 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
{
uiBut *bt;
- ui_set_but_val(but, but->hardmax);
+ ui_but_value_set(but, but->hardmax);
ui_apply_but_func(C, but);
/* states of other row buttons */
for (bt = block->buttons.first; bt; bt = bt->next)
- if (bt != but && bt->poin == but->poin && ELEM(bt->type, ROW, LISTROW))
- ui_check_but(bt);
+ if (bt != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW))
+ ui_but_update(bt);
data->retval = but->retval;
data->applied = true;
@@ -761,14 +843,21 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
if (!data->str)
return;
- ui_set_but_string(C, but, data->str);
- ui_check_but(but);
+ ui_but_string_set(C, but, data->str);
+ ui_but_update(but);
- /* give butfunc the original text too */
- /* feature used for bone renaming, channels, etc */
- /* afterfunc frees origstr */
- but->rename_orig = data->origstr;
- data->origstr = NULL;
+ /* give butfunc a copy of the original text too.
+ * feature used for bone renaming, channels, etc.
+ * afterfunc frees rename_orig */
+ if (data->origstr && (but->flag & UI_BUT_TEXTEDIT_UPDATE)) {
+ /* In this case, we need to keep origstr available, to restore real org string in case we cancel after
+ * having typed something already. */
+ but->rename_orig = BLI_strdup(data->origstr);
+ }
+ else {
+ but->rename_orig = data->origstr;
+ data->origstr = NULL;
+ }
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -778,8 +867,8 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (data->str) {
- if (ui_set_but_string(C, but, data->str)) {
- data->value = ui_get_but_val(but);
+ if (ui_but_string_set(C, but, data->str)) {
+ data->value = ui_but_value_get(but);
}
else {
data->cancel = true;
@@ -787,9 +876,9 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
}
}
else
- ui_set_but_val(but, data->value);
+ ui_but_value_set(but, data->value);
- ui_check_but(but);
+ ui_but_update(but);
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -798,8 +887,8 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_VEC(bContext *C, uiBut *but, uiHandleButtonData *data)
{
- ui_set_but_vectorf(but, data->vec);
- ui_check_but(but);
+ ui_but_v3_set(but, data->vec);
+ ui_but_update(but);
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -836,7 +925,7 @@ static void ui_multibut_add(uiHandleButtonData *data, uiBut *but)
mbut_state = MEM_callocN(sizeof(*mbut_state), __func__);
mbut_state->but = but;
- mbut_state->origvalue = ui_get_but_val(but);
+ mbut_state->origvalue = ui_but_value_get(but);
BLI_linklist_prepend(&data->multi_data.mbuts, mbut_state);
@@ -860,7 +949,7 @@ static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut
return NULL;
}
-static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
+static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block)
{
uiBut *but;
@@ -868,7 +957,17 @@ static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
if (but->flag & UI_BUT_DRAG_MULTI) {
uiButMultiState *mbut_state = ui_multibut_lookup(data, but);
if (mbut_state) {
- ui_set_but_val(but, mbut_state->origvalue);
+ ui_but_value_set(but, mbut_state->origvalue);
+
+#ifdef USE_ALLSELECT
+ if (mbut_state->select_others.elems_len > 0) {
+ ui_selectcontext_apply(
+ C, but, &mbut_state->select_others,
+ mbut_state->origvalue, mbut_state->origvalue);
+ }
+#else
+ UNUSED_VARS(C);
+#endif
}
}
}
@@ -876,7 +975,26 @@ static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block)
{
+#ifdef USE_ALLSELECT
+ if (data->multi_data.mbuts) {
+ LinkNode *list = data->multi_data.mbuts;
+ while (list) {
+ LinkNode *next = list->next;
+ uiButMultiState *mbut_state = list->link;
+
+ if (mbut_state->select_others.elems) {
+ MEM_freeN(mbut_state->select_others.elems);
+ }
+
+ MEM_freeN(list->link);
+ MEM_freeN(list);
+ list = next;
+ }
+ }
+#else
BLI_linklist_freeN(data->multi_data.mbuts);
+#endif
+
data->multi_data.mbuts = NULL;
if (data->multi_data.bs_mbuts) {
@@ -915,11 +1033,11 @@ static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData *data,
drag_prev = true;
}
- if (ui_is_but_interactive(but, false)) {
+ if (ui_but_is_interactive(but, false)) {
/* drag checks */
if (but_active != but) {
- if (ui_is_but_compatible(but_active, but)) {
+ if (ui_but_is_compatible(but_active, but)) {
BLI_assert(but->active == NULL);
@@ -945,6 +1063,7 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
uiBut *but;
BLI_assert(data->multi_data.init == BUTTON_MULTI_INIT_SETUP);
+ BLI_assert(data->multi_data.has_mbuts);
data->multi_data.bs_mbuts = UI_butstore_create(but_active->block);
@@ -981,13 +1100,31 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
if (mbut_state) {
void *active_back;
- ui_button_execute_begin(C, ar, but, &active_back);
+ ui_but_execute_begin(C, ar, but, &active_back);
+
+#ifdef USE_ALLSELECT
+ if (data->select_others.is_enabled) {
+ /* init once! */
+ if (mbut_state->select_others.elems_len == 0) {
+ ui_selectcontext_begin(C, but, &mbut_state->select_others);
+ }
+ if (mbut_state->select_others.elems_len == 0) {
+ mbut_state->select_others.elems_len = -1;
+ }
+ }
+
+ /* needed so we apply the right deltas */
+ but->active->origvalue = mbut_state->origvalue;
+ but->active->select_others = mbut_state->select_others;
+ but->active->select_others.do_free = false;
+#endif
+
BLI_assert(active_back == NULL);
/* no need to check 'data->state' here */
if (data->str) {
/* entering text (set all) */
but->active->value = data->value;
- ui_set_but_string(C, but, data->str);
+ ui_but_string_set(C, but, data->str);
}
else {
/* dragging (use delta) */
@@ -1001,7 +1138,7 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
/* clamp based on soft limits, see: T40154 */
CLAMP(but->active->value, (double)but->softmin, (double)but->softmax);
}
- ui_button_execute_end(C, ar, but, active_back);
+ ui_but_execute_end(C, ar, but, active_back);
}
else {
/* highly unlikely */
@@ -1030,8 +1167,9 @@ typedef struct uiDragToggleHandle {
int xy_last[2];
} uiDragToggleHandle;
-static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy_src[2], const int xy_dst[2])
+static bool ui_drag_toggle_set_xy_xy(
+ bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+ const int xy_src[2], const int xy_dst[2])
{
/* popups such as layers won't re-evaluate on redraw */
const bool do_check = (ar->regiontype == RGN_TYPE_TEMPORARY);
@@ -1050,18 +1188,18 @@ static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set
for (but = block->buttons.first; but; but = but->next) {
/* Note: ctrl is always true here because (at least for now) we always want to consider text control
* in this case, even when not embossed. */
- if (ui_is_but_interactive(but, true)) {
+ if (ui_but_is_interactive(but, true)) {
if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
/* execute the button */
- if (ui_is_but_bool(but) && but->type == but_type_start) {
+ if (ui_but_is_bool(but) && but->type == but_type_start) {
/* is it pressed? */
- bool is_set_but = ui_is_but_push(but);
- BLI_assert(ui_is_but_bool(but) == true);
+ bool is_set_but = ui_but_is_pushed(but);
+ BLI_assert(ui_but_is_bool(but) == true);
if (is_set_but != is_set) {
- uiButExecute(C, but);
+ UI_but_execute(C, but);
if (do_check) {
- ui_check_but(but);
+ ui_but_update(but);
}
changed = true;
}
@@ -1164,7 +1302,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
uiBut *but = ui_but_find_mouse_over_ex(ar, drag_info->xy_init[0], drag_info->xy_init[1], true);
if (but) {
- ui_apply_undo(but);
+ ui_apply_but_undo(but);
}
WM_event_remove_ui_handler(&win->modalhandlers,
@@ -1181,9 +1319,9 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
}
}
-static bool ui_is_but_drag_toggle(const uiBut *but)
+static bool ui_but_is_drag_toggle(const uiBut *but)
{
- return ((ui_is_but_bool(but) == true) &&
+ return ((ui_but_is_bool(but) == true) &&
/* menu check is importnt so the button dragged over isn't removed instantly */
(ui_block_is_menu(but->block) == false));
}
@@ -1191,7 +1329,268 @@ static bool ui_is_but_drag_toggle(const uiBut *but)
#endif /* USE_DRAG_TOGGLE */
-static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *event)
+#ifdef USE_ALLSELECT
+
+static bool ui_selectcontext_begin(
+ bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
+{
+ PointerRNA ptr, lptr, idptr;
+ PropertyRNA *prop, *lprop;
+ bool success = false;
+ int index;
+
+ char *path = NULL;
+ ListBase lb = {NULL};
+
+ ptr = but->rnapoin;
+ prop = but->rnaprop;
+ index = but->rnaindex;
+
+ /* for now don't support whole colors */
+ if (index == -1)
+ return false;
+
+ /* if there is a valid property that is editable... */
+ if (ptr.data && prop) {
+ CollectionPointerLink *link;
+ bool use_path_from_id;
+ int i;
+
+ /* some facts we want to know */
+ const bool is_array = RNA_property_array_check(prop);
+ const int rna_type = RNA_property_type(prop);
+
+ if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
+ goto finally;
+ }
+
+ selctx_data->elems_len = BLI_listbase_count(&lb);
+ if (selctx_data->elems_len == 0) {
+ goto finally;
+ }
+
+ selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__);
+
+ for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ /* TODO,. de-duplicate copy_to_selected_button */
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
+
+ /* lptr might not be the same as link->ptr! */
+ if ((lptr.data != ptr.data) &&
+ (lprop == prop) &&
+ RNA_property_editable(&lptr, lprop))
+ {
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
+ }
+ /* ignored for now */
+#if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
+ }
+#endif
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
+ }
+ /* ignored for now */
+#if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
+#endif
+ }
+
+ continue;
+ }
+ }
+
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ }
+ }
+
+ success = (selctx_data->elems_len != 0);
+
+finally:
+ if (selctx_data->elems_len == 0) {
+ MEM_SAFE_FREE(selctx_data->elems);
+ }
+
+ MEM_SAFE_FREE(path);
+ BLI_freelistN(&lb);
+
+ /* caller can clear */
+ selctx_data->do_free = true;
+
+ if (success) {
+ but->flag |= UI_BUT_IS_SELECT_CONTEXT;
+ }
+
+ return success;
+}
+
+static void ui_selectcontext_end(
+ uiBut *but, uiSelectContextStore *selctx_data)
+{
+ if (selctx_data->do_free) {
+ if (selctx_data->elems) {
+ MEM_freeN(selctx_data->elems);
+ }
+ }
+
+ but->flag &= ~UI_BUT_IS_SELECT_CONTEXT;
+}
+
+static void ui_selectcontext_apply(
+ bContext *C, uiBut *but, uiSelectContextStore *selctx_data,
+ const double value, const double value_orig)
+{
+ if (selctx_data->elems) {
+ PropertyRNA *prop = but->rnaprop;
+ PropertyRNA *lprop = but->rnaprop;
+ int index = but->rnaindex;
+ int i;
+ const bool use_delta = (selctx_data->is_copy == false);
+
+ union {
+ bool b;
+ int i;
+ float f;
+ } delta, min, max;
+
+ const bool is_array = RNA_property_array_check(prop);
+ const int rna_type = RNA_property_type(prop);
+
+ if (rna_type == PROP_FLOAT) {
+ delta.f = use_delta ? (value - value_orig) : value;
+ RNA_property_float_range(&but->rnapoin, prop, &min.f, &max.f);
+ }
+ else if (rna_type == PROP_INT) {
+ delta.i = use_delta ? ((int)value - (int)value_orig) : (int)value;
+ RNA_property_int_range(&but->rnapoin, prop, &min.i, &max.i);
+ }
+ else if (rna_type == PROP_ENUM) {
+ delta.i = RNA_property_enum_get(&but->rnapoin, prop); /* not a delta infact */
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ if (is_array) {
+ delta.b = RNA_property_boolean_get_index(&but->rnapoin, prop, index); /* not a delta infact */
+ }
+ else {
+ delta.b = RNA_property_boolean_get(&but->rnapoin, prop); /* not a delta infact */
+ }
+ }
+
+#ifdef USE_ALLSELECT_LAYER_HACK
+ /* make up for not having 'handle_layer_buttons' */
+ {
+ PropertySubType subtype = RNA_property_subtype(prop);
+
+ if ((rna_type == PROP_BOOLEAN) &&
+ ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER) &&
+ is_array &&
+ /* could check for 'handle_layer_buttons' */
+ but->func)
+ {
+ wmWindow *win = CTX_wm_window(C);
+ if (!win->eventstate->shift) {
+ const int len = RNA_property_array_length(&but->rnapoin, prop);
+ int *tmparray = MEM_callocN(sizeof(int) * len, __func__);
+
+ tmparray[index] = true;
+
+ for (i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ PointerRNA lptr = other->ptr;
+ RNA_property_boolean_set_array(&lptr, lprop, tmparray);
+ RNA_property_update(C, &lptr, lprop);
+ }
+
+ MEM_freeN(tmparray);
+
+ return;
+ }
+ }
+ }
+#endif
+
+ for (i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ PointerRNA lptr = other->ptr;
+
+ if (rna_type == PROP_FLOAT) {
+ float other_value = use_delta ? (other->val_f + delta.f) : delta.f;
+ CLAMP(other_value, min.f, max.f);
+ if (is_array) {
+ RNA_property_float_set_index(&lptr, lprop, index, other_value);
+ }
+ else {
+ RNA_property_float_set(&lptr, lprop, other_value);
+ }
+ }
+ else if (rna_type == PROP_INT) {
+ int other_value = use_delta ? (other->val_i + delta.i) : delta.i;
+ CLAMP(other_value, min.i, max.i);
+ if (is_array) {
+ RNA_property_int_set_index(&lptr, lprop, index, other_value);
+ }
+ else {
+ RNA_property_int_set(&lptr, lprop, other_value);
+ }
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ const bool other_value = delta.b;
+ if (is_array) {
+ RNA_property_boolean_set_index(&lptr, lprop, index, other_value);
+ }
+ else {
+ RNA_property_boolean_set(&lptr, lprop, delta.b);
+ }
+ }
+ else if (rna_type == PROP_ENUM) {
+ const int other_value = delta.i;
+ BLI_assert(!is_array);
+ RNA_property_enum_set(&lptr, lprop, other_value);
+ }
+
+ RNA_property_update(C, &lptr, prop);
+ }
+ }
+}
+
+#endif /* USE_ALLSELECT */
+
+
+static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent *event)
{
rcti rect;
int x = event->x, y = event->y;
@@ -1200,7 +1599,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve
BLI_rcti_rctf_copy(&rect, &but->rect);
- if (but->imb || but->type == COLOR) {
+ if (but->imb || but->type == UI_BTYPE_COLOR) {
/* use button size itself */
}
else if (but->drawflag & UI_BUT_ICON_LEFT) {
@@ -1215,7 +1614,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve
return BLI_rcti_isect_pt(&rect, x, y);
}
-static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
/* prevent other WM gestures to start while we try to drag */
WM_gestures_remove(C);
@@ -1225,15 +1624,15 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = true;
#ifdef USE_DRAG_TOGGLE
- if (ui_is_but_bool(but)) {
+ if (ui_but_is_bool(but)) {
uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
ARegion *ar_prev;
/* call here because regular mouse-up event wont run,
* typically 'button_activate_exit()' handles this */
- ui_apply_autokey(C, but);
+ ui_apply_but_autokey(C, but);
- drag_info->is_set = ui_is_but_push(but);
+ drag_info->is_set = ui_but_is_pushed(but);
drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
drag_info->but_type_start = but->type;
@@ -1244,16 +1643,17 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
ar_prev = CTX_wm_region(C);
CTX_wm_region_set(C, data->region);
- WM_event_add_ui_handler(C, &data->window->modalhandlers,
- ui_handler_region_drag_toggle,
- ui_handler_region_drag_toggle_remove,
- drag_info, false);
+ WM_event_add_ui_handler(
+ C, &data->window->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info, WM_HANDLER_BLOCKING);
CTX_wm_region_set(C, ar_prev);
}
else
#endif
- if (but->type == COLOR) {
+ if (but->type == UI_BTYPE_COLOR) {
bool valid = false;
uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
@@ -1288,7 +1688,7 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
else {
wmDrag *drag;
- drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP);
+ drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP);
if (but->imb)
WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
}
@@ -1300,7 +1700,7 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
/* ********************** linklines *********************** */
-static void ui_delete_active_linkline(uiBlock *block)
+static void ui_linkline_remove_active(uiBlock *block)
{
uiBut *but;
uiLink *link;
@@ -1308,7 +1708,7 @@ static void ui_delete_active_linkline(uiBlock *block)
int a, b;
for (but = block->buttons.first; but; but = but->next) {
- if (but->type == LINK && but->link) {
+ if (but->type == UI_BTYPE_LINK && but->link) {
for (line = but->link->lines.first; line; line = nline) {
nline = line->next;
@@ -1349,7 +1749,7 @@ static void ui_delete_active_linkline(uiBlock *block)
}
-static uiLinkLine *ui_is_a_link(uiBut *from, uiBut *to)
+static uiLinkLine *ui_but_find_link(uiBut *from, uiBut *to)
{
uiLinkLine *line;
uiLink *link;
@@ -1367,7 +1767,7 @@ static uiLinkLine *ui_is_a_link(uiBut *from, uiBut *to)
/* XXX BAD BAD HACK, fixme later **************** */
/* Try to add an AND Controller between the sensor and the actuator logic bricks and to connect them all */
-static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to)
+static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to)
{
Object *ob = NULL;
bSensor *sens_iter;
@@ -1422,15 +1822,15 @@ static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to)
/* (4) link the sensor->controller->actuator */
tmp_but = MEM_callocN(sizeof(uiBut), "uiBut");
- uiSetButLink(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin);
+ UI_but_link_set(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin);
tmp_but->hardmin = from->link->tocode;
tmp_but->poin = (char *)cont;
- tmp_but->type = INLINK;
- ui_add_link(C, from, tmp_but);
+ tmp_but->type = UI_BTYPE_INLINK;
+ ui_but_link_add(C, from, tmp_but);
- tmp_but->type = LINK;
- ui_add_link(C, tmp_but, to);
+ tmp_but->type = UI_BTYPE_LINK;
+ ui_but_link_add(C, tmp_but, to);
/* (5) garbage collection */
MEM_freeN(tmp_but->link);
@@ -1439,7 +1839,7 @@ static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to)
WM_operator_properties_free(&props_ptr);
}
-static void ui_add_link(bContext *C, uiBut *from, uiBut *to)
+static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to)
{
/* in 'from' we have to add a link to 'to' */
uiLink *link;
@@ -1447,22 +1847,22 @@ static void ui_add_link(bContext *C, uiBut *from, uiBut *to)
void **oldppoin;
int a;
- if ((line = ui_is_a_link(from, to))) {
+ if ((line = ui_but_find_link(from, to))) {
line->flag |= UI_SELECT;
- ui_delete_active_linkline(from->block);
+ ui_linkline_remove_active(from->block);
return;
}
- if (from->type == INLINK && to->type == INLINK) {
+ if (from->type == UI_BTYPE_INLINK && to->type == UI_BTYPE_INLINK) {
return;
}
- else if (from->type == LINK && to->type == INLINK) {
+ else if (from->type == UI_BTYPE_LINK && to->type == UI_BTYPE_INLINK) {
if (from->link->tocode != (int)to->hardmin) {
- ui_add_smart_controller(C, from, to);
+ ui_but_smart_controller_add(C, from, to);
return;
}
}
- else if (from->type == INLINK && to->type == LINK) {
+ else if (from->type == UI_BTYPE_INLINK && to->type == UI_BTYPE_LINK) {
if (to->link->tocode == (int)from->hardmin) {
return;
}
@@ -1497,15 +1897,15 @@ static void ui_apply_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data)
uiBut *bt;
for (bt = but->block->buttons.first; bt; bt = bt->next) {
- if (ui_mouse_inside_button(ar, bt, but->linkto[0] + ar->winrct.xmin, but->linkto[1] + ar->winrct.ymin) )
+ if (ui_but_contains_point_px(ar, bt, but->linkto[0] + ar->winrct.xmin, but->linkto[1] + ar->winrct.ymin) )
break;
}
if (bt && bt != but) {
- if (!ELEM(bt->type, LINK, INLINK) || !ELEM(but->type, LINK, INLINK))
+ if (!ELEM(bt->type, UI_BTYPE_LINK, UI_BTYPE_INLINK) || !ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK))
return;
- if (but->type == LINK) ui_add_link(C, but, bt);
- else ui_add_link(C, bt, but);
+ if (but->type == UI_BTYPE_LINK) ui_but_link_add(C, but, bt);
+ else ui_but_link_add(C, bt, but);
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -1542,7 +1942,7 @@ static void ui_apply_but_TRACKPREVIEW(bContext *C, uiBut *but, uiHandleButtonDat
}
-static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const bool interactive)
+static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const bool interactive)
{
char *editstr;
double *editval;
@@ -1562,9 +1962,8 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
data->str = data->origstr;
data->origstr = NULL;
data->value = data->origvalue;
- data->origvalue = 0.0;
copy_v3_v3(data->vec, data->origvec);
- data->origvec[0] = data->origvec[1] = data->origvec[2] = 0.0f;
+ /* postpone clearing origdata */
}
else {
/* we avoid applying interactive edits a second time
@@ -1575,6 +1974,27 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
else if (data->applied_interactive) {
return;
}
+
+#ifdef USE_ALLSELECT
+# ifdef USE_DRAG_MULTINUM
+ if (but->flag & UI_BUT_DRAG_MULTI) {
+ /* pass */
+ }
+ else
+# endif
+ if (data->select_others.elems_len == 0) {
+ wmWindow *win = CTX_wm_window(C);
+ /* may have been enabled before activating */
+ if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) {
+ ui_selectcontext_begin(C, but, &data->select_others);
+ data->select_others.is_enabled = true;
+ }
+ }
+ if (data->select_others.elems_len == 0) {
+ /* dont check again */
+ data->select_others.elems_len = -1;
+ }
+#endif
}
/* ensures we are writing actual values */
@@ -1591,76 +2011,75 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
/* handle different types */
switch (but->type) {
- case BUT:
+ case UI_BTYPE_BUT:
ui_apply_but_BUT(C, but, data);
break;
- case TEX:
- case SEARCH_MENU_UNLINK:
- case SEARCH_MENU:
+ case UI_BTYPE_TEXT:
+ case UI_BTYPE_SEARCH_MENU:
ui_apply_but_TEX(C, but, data);
break;
- case TOGBUT:
- case TOG:
- case ICONTOG:
- case ICONTOGN:
- case TOGN:
- case OPTION:
- case OPTIONN:
+ case UI_BTYPE_BUT_TOGGLE:
+ case UI_BTYPE_TOGGLE:
+ case UI_BTYPE_TOGGLE_N:
+ case UI_BTYPE_ICON_TOGGLE:
+ case UI_BTYPE_ICON_TOGGLE_N:
+ case UI_BTYPE_CHECKBOX:
+ case UI_BTYPE_CHECKBOX_N:
ui_apply_but_TOG(C, but, data);
break;
- case ROW:
- case LISTROW:
+ case UI_BTYPE_ROW:
+ case UI_BTYPE_LISTROW:
ui_apply_but_ROW(C, block, but, data);
break;
- case SCROLL:
- case GRIP:
- case NUM:
- case NUMSLI:
+ case UI_BTYPE_SCROLL:
+ case UI_BTYPE_GRIP:
+ case UI_BTYPE_NUM:
+ case UI_BTYPE_NUM_SLIDER:
ui_apply_but_NUM(C, but, data);
break;
- case MENU:
- case BLOCK:
- case PULLDOWN:
+ case UI_BTYPE_MENU:
+ case UI_BTYPE_BLOCK:
+ case UI_BTYPE_PULLDOWN:
ui_apply_but_BLOCK(C, but, data);
break;
- case COLOR:
+ case UI_BTYPE_COLOR:
if (data->cancel)
ui_apply_but_VEC(C, but, data);
else
ui_apply_but_BLOCK(C, but, data);
break;
- case BUTM:
+ case UI_BTYPE_BUT_MENU:
ui_apply_but_BUTM(C, but, data);
break;
- case BUT_NORMAL:
- case HSVCUBE:
- case HSVCIRCLE:
+ case UI_BTYPE_UNITVEC:
+ case UI_BTYPE_HSVCUBE:
+ case UI_BTYPE_HSVCIRCLE:
ui_apply_but_VEC(C, but, data);
break;
- case BUT_COLORBAND:
+ case UI_BTYPE_COLORBAND:
ui_apply_but_COLORBAND(C, but, data);
break;
- case BUT_CURVE:
+ case UI_BTYPE_CURVE:
ui_apply_but_CURVE(C, but, data);
break;
- case KEYEVT:
- case HOTKEYEVT:
+ case UI_BTYPE_KEY_EVENT:
+ case UI_BTYPE_HOTKEY_EVENT:
ui_apply_but_BUT(C, but, data);
break;
- case LINK:
- case INLINK:
+ case UI_BTYPE_LINK:
+ case UI_BTYPE_INLINK:
ui_apply_but_LINK(C, but, data);
break;
- case BUT_IMAGE:
+ case UI_BTYPE_IMAGE:
ui_apply_but_IMAGE(C, but, data);
break;
- case HISTOGRAM:
+ case UI_BTYPE_HISTOGRAM:
ui_apply_but_HISTOGRAM(C, but, data);
break;
- case WAVEFORM:
+ case UI_BTYPE_WAVEFORM:
ui_apply_but_WAVEFORM(C, but, data);
break;
- case TRACKPREVIEW:
+ case UI_BTYPE_TRACK_PREVIEW:
ui_apply_but_TRACKPREVIEW(C, but, data);
break;
default:
@@ -1671,7 +2090,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
if (data->multi_data.has_mbuts) {
if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) {
if (data->cancel) {
- ui_multibut_restore(data, block);
+ ui_multibut_restore(C, data, block);
}
else {
ui_multibut_states_apply(C, data, block);
@@ -1680,6 +2099,15 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
}
#endif
+#ifdef USE_ALLSELECT
+ ui_selectcontext_apply(C, but, &data->select_others, data->value, data->origvalue);
+#endif
+
+ if (data->cancel) {
+ data->origvalue = 0.0;
+ zero_v3(data->origvec);
+ }
+
but->editstr = editstr;
but->editval = editval;
but->editvec = editvec;
@@ -1698,13 +2126,13 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
for (wmd = drags->first; wmd; wmd = wmd->next) {
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
- if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
BLI_strncpy(data->str, id->name + 2, data->maxlen);
- if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
but->changed = true;
ui_searchbox_update(C, data->searchbox, but, true);
}
@@ -1751,7 +2179,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
/* numeric value */
- if (ELEM(but->type, NUM, NUMSLI)) {
+ if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
if (but->poin == NULL && but->rnapoin.data == NULL) {
/* pass */
@@ -1760,7 +2188,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
/* Get many decimal places, then strip trailing zeros.
* note: too high values start to give strange results (6 or so is ok) */
char buf_copy[UI_MAX_DRAW_STR];
- ui_get_but_string_ex(but, buf_copy, sizeof(buf_copy), 6);
+ ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), 6);
BLI_str_rstrip_float_zero(buf_copy, '\0');
WM_clipboard_text_set(buf_copy, 0);
@@ -1768,17 +2196,17 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
else {
double val;
- if (ui_set_but_string_eval_num(C, but, buf_paste, &val)) {
+ if (ui_but_string_set_eval_num(C, but, buf_paste, &val)) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
data->value = val;
- ui_set_but_string(C, but, buf_paste);
+ ui_but_string_set(C, but, buf_paste);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
}
/* NORMAL button */
- else if (but->type == BUT_NORMAL) {
+ else if (but->type == UI_BTYPE_UNITVEC) {
float xyz[3];
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1786,7 +2214,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
else if (mode == 'c') {
char buf_copy[UI_MAX_DRAW_STR];
- ui_get_but_vectorf(but, xyz);
+ ui_but_v3_get(but, xyz);
BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f]", xyz[0], xyz[1], xyz[2]);
WM_clipboard_text_set(buf_copy, 0);
}
@@ -1797,7 +2225,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
xyz[2] = 1.0;
}
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- ui_set_but_vectorf(but, xyz);
+ ui_but_v3_set(but, xyz);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
@@ -1805,7 +2233,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
/* RGB triple */
- else if (but->type == COLOR) {
+ else if (but->type == UI_BTYPE_COLOR) {
float rgba[4];
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1819,7 +2247,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
else
rgba[3] = 1.0f;
- ui_get_but_vectorf(but, rgba);
+ ui_but_v3_get(but, rgba);
/* convert to linear color to do compatible copy between gamma and non-gamma */
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
srgb_to_linearrgb_v3_v3(rgba, rgba);
@@ -1835,7 +2263,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
linearrgb_to_srgb_v3_v3(rgba, rgba);
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- ui_set_but_vectorf(but, rgba);
+ ui_but_v3_set(but, rgba);
if (but->rnaprop && RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4)
RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, rgba[3]);
@@ -1845,7 +2273,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
/* text/string and ID data */
- else if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
uiHandleButtonData *active_data = but->active;
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1860,12 +2288,12 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
else {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- if (ui_is_but_utf8(but))
+ if (ui_but_is_utf8(but))
BLI_strncpy_utf8(active_data->str, buf_paste, active_data->maxlen);
else
BLI_strncpy(active_data->str, buf_paste, active_data->maxlen);
- if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
/* else uiSearchboxData.active member is not updated [#26856] */
but->changed = true;
ui_searchbox_update(C, data->searchbox, but, true);
@@ -1874,7 +2302,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
/* colorband (not supported by system clipboard) */
- else if (but->type == BUT_COLORBAND) {
+ else if (but->type == UI_BTYPE_COLORBAND) {
if (mode == 'c') {
if (but->poin != NULL) {
memcpy(&but_copypaste_coba, but->poin, sizeof(ColorBand));
@@ -1891,7 +2319,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
}
- else if (but->type == BUT_CURVE) {
+ else if (but->type == UI_BTYPE_CURVE) {
if (mode == 'c') {
if (but->poin != NULL) {
but_copypaste_curve_alive = true;
@@ -1916,7 +2344,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
if (mode == 'c') {
PointerRNA *opptr;
char *str;
- opptr = uiButGetOperatorPtrRNA(but); /* allocated when needed, the button owns it */
+ opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr);
@@ -1926,8 +2354,8 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
/* menu (any type) */
- else if (ELEM(but->type, MENU, PULLDOWN)) {
- MenuType *mt = uiButGetMenuType(but);
+ else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
+ MenuType *mt = UI_but_menutype_get(but);
if (mt) {
char str[32 + sizeof(mt->idname)];
BLI_snprintf(str, sizeof(str), "bpy.ops.wm.call_menu(name=\"%s\")", mt->idname);
@@ -1940,15 +2368,17 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
-/* ************************ password text ******************************
+/**
+ * Password Text
+ * =============
*
* Functions to convert password strings that should not be displayed
- * to asterisk representation (e.g. mysecretpasswd -> *************)
+ * to asterisk representation (e.g. 'mysecretpasswd' -> '*************')
*
* It converts every UTF-8 character to an asterisk, and also remaps
* the cursor position and selection start/end.
*
- * Note: remaping is used, because password could contain UTF-8 characters.
+ * \note: remaping is used, because password could contain UTF-8 characters.
*
*/
@@ -1971,7 +2401,7 @@ static int ui_text_position_to_hidden(uiBut *but, int pos)
return BLI_strnlen_utf8(butstr, pos);
}
-void ui_button_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *but, const bool restore)
+void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *but, const bool restore)
{
char *butstr;
@@ -2034,7 +2464,7 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
*/
static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, const float x)
{
- uiStyle *style = UI_GetStyle(); // XXX pass on as arg
+ uiStyle *style = UI_style_get(); // XXX pass on as arg
uiFontStyle *fstyle = &style->widget;
const float aspect = but->block->aspect;
const short fstyle_points_prev = fstyle->points;
@@ -2047,18 +2477,18 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
ui_fontscale(&fstyle->points, aspect);
- uiStyleFontSet(fstyle);
+ UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
- ui_button_text_password_hide(password_str, but, false);
+ ui_but_text_password_hide(password_str, but, false);
origstr = MEM_mallocN(sizeof(char) * data->maxlen, "ui_textedit origstr");
BLI_strncpy(origstr, but->editstr, data->maxlen);
- if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
}
@@ -2128,7 +2558,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
if (fstyle->kerning == 1)
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
- ui_button_text_password_hide(password_str, but, true);
+ ui_but_text_password_hide(password_str, but, true);
MEM_freeN(origstr);
@@ -2145,14 +2575,16 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data,
if (data->selextend == EXTEND_RIGHT) but->selend = but->pos;
else if (data->selextend == EXTEND_LEFT) but->selsta = but->pos;
- ui_check_but(but);
+ ui_but_update(but);
}
-/* this is used for both utf8 and ascii, its meant to be used for single keys,
+/**
+ * This is used for both utf8 and ascii, its meant to be used for single keys,
* notice the buffer is either copied or not, so its not suitable for pasting in
* - campbell */
-static bool ui_textedit_type_buf(uiBut *but, uiHandleButtonData *data,
- const char *utf8_buf, int utf8_buf_len)
+static bool ui_textedit_type_buf(
+ uiBut *but, uiHandleButtonData *data,
+ const char *utf8_buf, int utf8_buf_len)
{
char *str;
int len;
@@ -2185,7 +2617,7 @@ static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char as
{
char buf[2] = {ascii, '\0'};
- if (ui_is_but_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
+ if (ui_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
printf("%s: entering invalid ascii char into an ascii key (%d)\n",
__func__, (int)(unsigned char)ascii);
@@ -2196,15 +2628,16 @@ static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char as
return ui_textedit_type_buf(but, data, buf, 1);
}
-static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, strCursorJumpDirection direction,
- const bool select, strCursorJumpType jump)
+static void ui_textedit_move(
+ uiBut *but, uiHandleButtonData *data, strCursorJumpDirection direction,
+ const bool select, strCursorJumpType jump)
{
const char *str = data->str;
const int len = strlen(str);
const int pos_prev = but->pos;
const bool has_sel = (but->selend - but->selsta) > 0;
- ui_check_but(but);
+ ui_but_update(but);
/* special case, quit selection and set cursor */
if (has_sel && !select) {
@@ -2356,7 +2789,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
/* paste */
if (mode == UI_TEXTEDIT_PASTE) {
- /* TODO, ensure UTF8 ui_is_but_utf8() - campbell */
+ /* TODO, ensure UTF8 ui_but_is_utf8() - campbell */
/* extract the first line from the clipboard */
pbuf = WM_clipboard_text_get_firstline(false, &buf_len);
@@ -2412,9 +2845,65 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
return changed;
}
+#ifdef WITH_INPUT_IME
+/* test if the translation context allows IME input - used to
+ * avoid weird character drawing if IME inputs non-ascii chars */
+static bool ui_ime_is_lang_supported(void)
+{
+ const char *uilng = BLT_lang_get();
+ const bool is_lang_supported = STREQ(uilng, "zh_CN") ||
+ STREQ(uilng, "zh_TW") ||
+ STREQ(uilng, "ja_JP");
+
+ return ((U.transopts & USER_DOTRANSLATE) && is_lang_supported);
+}
+
+/* enable ime, and set up uibut ime data */
+static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
+{
+ /* XXX Is this really needed? */
+ int x, y;
+
+ BLI_assert(win->ime_data == NULL);
+
+ /* enable IME and position to cursor, it's a trick */
+ x = win->eventstate->x;
+ /* flip y and move down a bit, prevent the IME panel cover the edit button */
+ y = win->eventstate->y - 12;
+
+ wm_window_IME_begin(win, x, y, 0, 0, true);
+}
+
+/* disable ime, and clear uibut ime data */
+static void ui_textedit_ime_end(wmWindow *win, uiBut *UNUSED(but))
+{
+ wm_window_IME_end(win);
+}
+
+void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete)
+{
+ BLI_assert(but->active);
+
+ ui_region_to_window(but->active->region, &x, &y);
+ wm_window_IME_begin(but->active->window, x, y - 4, 0, 0, complete);
+}
+
+wmIMEData *ui_but_ime_data_get(uiBut *but)
+{
+ if (but->active && but->active->window) {
+ return but->active->window->ime_data;
+ }
+ else {
+ return NULL;
+ }
+}
+#endif /* WITH_INPUT_IME */
+
static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
{
+ wmWindow *win = CTX_wm_window(C);
int len;
+ const bool is_num_but = ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER);
if (data->str) {
MEM_freeN(data->str);
@@ -2426,24 +2915,34 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
if (data->applied_interactive) {
/* remove any small changes so canceling edit doesn't restore invalid value: T40538 */
data->cancel = true;
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
data->cancel = false;
data->applied_interactive = false;
}
#endif
+#ifdef USE_ALLSELECT
+ if (is_num_but) {
+ if (IS_ALLSELECT_EVENT(win->eventstate)) {
+ data->select_others.is_enabled = true;
+ data->select_others.is_copy = true;
+
+ }
+ }
+#endif
+
/* retrieve string */
- data->maxlen = ui_get_but_string_max_length(but);
+ data->maxlen = ui_but_string_get_max_length(but);
data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str");
- ui_get_but_string(but, data->str, data->maxlen);
+ ui_but_string_get(but, data->str, data->maxlen);
- if (ui_is_but_float(but) && !ui_is_but_unit(but)) {
+ if (ui_but_is_float(but) && !ui_but_is_unit(but)) {
BLI_str_rstrip_float_zero(data->str, '\0');
}
- if (ELEM(but->type, NUM, NUMSLI)) {
- ui_convert_to_unit_alt_name(but, data->str, data->maxlen);
+ if (is_num_but) {
+ ui_but_convert_to_unit_alt_name(but, data->str, data->maxlen);
}
/* won't change from now on */
@@ -2460,7 +2959,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
but->selend = len;
/* optional searchbox */
- if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
data->searchbox = ui_searchbox_create(C, data->region, but);
ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
}
@@ -2468,15 +2967,23 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
/* reset alert flag (avoid confusion, will refresh on exit) */
but->flag &= ~UI_BUT_REDALERT;
- ui_check_but(but);
-
- WM_cursor_modal_set(CTX_wm_window(C), BC_TEXTEDITCURSOR);
+ ui_but_update(but);
+
+ WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+
+#ifdef WITH_INPUT_IME
+ if (is_num_but == false && ui_ime_is_lang_supported()) {
+ ui_textedit_ime_begin(win, but);
+ }
+#endif
}
static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
{
+ wmWindow *win = CTX_wm_window(C);
+
if (but) {
- if (ui_is_but_utf8(but)) {
+ if (ui_but_is_utf8(but)) {
int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
/* not a file?, strip non utf-8 chars */
if (strip) {
@@ -2505,7 +3012,13 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
but->pos = -1;
}
- WM_cursor_modal_restore(CTX_wm_window(C));
+ WM_cursor_modal_restore(win);
+
+#ifdef WITH_INPUT_IME
+ if (win->ime_data) {
+ ui_textedit_ime_end(win, but);
+ }
+#endif
}
static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data)
@@ -2513,11 +3026,11 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_ROUNDBOX, UI_BTYPE_LISTBOX))
return;
for (but = actbut->next; but; but = but->next) {
- if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ui_but_is_editable_as_text(but)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2526,7 +3039,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.first; but != actbut; but = but->next) {
- if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ui_but_is_editable_as_text(but)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2541,11 +3054,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_ROUNDBOX, UI_BTYPE_LISTBOX))
return;
for (but = actbut->prev; but; but = but->prev) {
- if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ui_but_is_editable_as_text(but)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2554,7 +3067,7 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.last; but != actbut; but = but->prev) {
- if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ui_but_is_editable_as_text(but)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2570,6 +3083,14 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
int retval = WM_UI_HANDLER_CONTINUE;
bool changed = false, inbox = false, update = false;
+#ifdef WITH_INPUT_IME
+ wmWindow *win = CTX_wm_window(C);
+ wmIMEData *ime_data = win->ime_data;
+ bool is_ime_composing = ime_data && ime_data->is_ime_composing;
+#else
+ bool is_ime_composing = false;
+#endif
+
switch (event->type) {
case MOUSEMOVE:
case MOUSEPAN:
@@ -2590,6 +3111,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
case RIGHTMOUSE:
case ESCKEY:
if (event->val == KM_PRESS) {
+#ifdef WITH_INPUT_IME
+ /* skips button handling since it is not wanted */
+ if (is_ime_composing) {
+ break;
+ }
+#endif
data->cancel = true;
data->escapecancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -2647,12 +3174,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
}
}
- if (event->val == KM_PRESS) {
+ if (event->val == KM_PRESS && !is_ime_composing) {
switch (event->type) {
case VKEY:
case XKEY:
case CKEY:
- if (event->ctrl || event->oskey) {
+ if (IS_EVENT_MOD(event, ctrl, oskey)) {
if (event->type == VKEY)
changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE);
else if (event->type == CKEY)
@@ -2682,6 +3209,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_searchbox_event(C, data->searchbox, but, event);
break;
}
+ if (event->type == WHEELDOWNMOUSE) {
+ break;
+ }
/* fall-through */
case ENDKEY:
ui_textedit_move(but, data, STRCUR_DIR_NEXT,
@@ -2697,6 +3227,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_searchbox_event(C, data->searchbox, but, event);
break;
}
+ if (event->type == WHEELUPMOUSE) {
+ break;
+ }
/* fall-through */
case HOMEKEY:
ui_textedit_move(but, data, STRCUR_DIR_PREV,
@@ -2725,10 +3258,10 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
/* Ctrl + A: Select all */
#if defined(__APPLE__)
/* OSX uses cmd-a systemwide, so add it */
- if ((event->oskey && !(event->alt || event->shift || event->ctrl)) ||
- (event->ctrl && !(event->alt || event->shift || event->oskey)))
+ if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) ||
+ (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)))
#else
- if (event->ctrl && !(event->alt || event->shift || event->oskey))
+ if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))
#endif
{
ui_textedit_move(but, data, STRCUR_DIR_PREV,
@@ -2747,11 +3280,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
if (autocomplete == AUTOCOMPLETE_FULL_MATCH)
button_activate_state(C, but, BUTTON_STATE_EXIT);
-
- update = true; /* do live update for tab key */
}
/* the hotkey here is not well defined, was G.qual so we check all */
- else if (event->shift || event->ctrl || event->alt || event->oskey) {
+ else if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
ui_textedit_prev_but(block, but, data);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -2763,13 +3294,21 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
break;
}
- if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)) {
+ if ((event->ascii || event->utf8_buf[0]) &&
+ (retval == WM_UI_HANDLER_CONTINUE)
+#ifdef WITH_INPUT_IME
+ &&
+ !is_ime_composing &&
+ !WM_event_is_ime_switch(event)
+#endif
+ )
+ {
char ascii = event->ascii;
const char *utf8_buf = event->utf8_buf;
/* exception that's useful for number buttons, some keyboard
* numpads have a comma instead of a period */
- if (ELEM(but->type, NUM, NUMSLI)) { /* could use data->min*/
+ if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* could use data->min*/
if (event->type == PADPERIOD && ascii == ',') {
ascii = '.';
utf8_buf = NULL; /* force ascii fallback */
@@ -2793,18 +3332,38 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
retval = WM_UI_HANDLER_BREAK;
}
- /* textbutton with magnifier icon: do live update for search button */
- if (but->icon == ICON_VIEWZOOM)
+ /* textbutton with this flag: do live update (e.g. for search buttons) */
+ if (but->flag & UI_BUT_TEXTEDIT_UPDATE) {
update = true;
+ }
+ }
+
+#ifdef WITH_INPUT_IME
+ if (event->type == WM_IME_COMPOSITE_START || event->type == WM_IME_COMPOSITE_EVENT) {
+ changed = true;
+
+ if (event->type == WM_IME_COMPOSITE_START && but->selend > but->selsta) {
+ ui_textedit_delete_selection(but, data);
+ }
+ if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) {
+ ui_textedit_type_buf(
+ but, data,
+ ime_data->str_result,
+ ime_data->result_len);
+ }
}
+ else if (event->type == WM_IME_COMPOSITE_END) {
+ changed = true;
+ }
+#endif
if (changed) {
- /* only update when typing for TAB key */
+ /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */
if (update && data->interactive) {
- ui_apply_button(C, block, but, data, true);
+ ui_apply_but(C, block, but, data, true);
}
else {
- ui_check_but(but);
+ ui_but_update(but);
}
but->changed = true;
@@ -2839,7 +3398,7 @@ static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, u
}
if (retval == WM_UI_HANDLER_BREAK) {
- ui_check_but(but);
+ ui_but_update(but);
ED_region_tag_redraw(data->region);
}
}
@@ -2848,22 +3407,22 @@ static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, u
static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
{
- if (but->type == BUT_CURVE) {
+ if (but->type == UI_BTYPE_CURVE) {
but->editcumap = (CurveMapping *)but->poin;
}
- else if (but->type == BUT_COLORBAND) {
+ else if (but->type == UI_BTYPE_COLORBAND) {
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
}
- else if (ELEM(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
- ui_get_but_vectorf(but, data->origvec);
+ else if (ELEM(but->type, UI_BTYPE_UNITVEC, UI_BTYPE_HSVCUBE, UI_BTYPE_HSVCIRCLE, UI_BTYPE_COLOR)) {
+ ui_but_v3_get(but, data->origvec);
copy_v3_v3(data->vec, data->origvec);
but->editvec = data->vec;
}
else {
float softrange, softmin, softmax;
- data->startvalue = ui_get_but_val(but);
+ data->startvalue = ui_but_value_get(but);
data->origvalue = data->startvalue;
data->value = data->origvalue;
but->editval = &data->value;
@@ -2897,10 +3456,10 @@ static void ui_numedit_end(uiBut *but, uiHandleButtonData *data)
static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
{
if (data->interactive) {
- ui_apply_button(C, block, but, data, true);
+ ui_apply_but(C, block, but, data, true);
}
else {
- ui_check_but(but);
+ ui_but_update(but);
}
ED_region_tag_redraw(data->region);
@@ -2908,7 +3467,7 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
/* ****************** menu opening for various types **************** */
-static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
+static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
{
uiBlockCreateFunc func = NULL;
uiBlockHandleCreateFunc handlefunc = NULL;
@@ -2916,8 +3475,8 @@ static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data
void *arg = NULL;
switch (but->type) {
- case BLOCK:
- case PULLDOWN:
+ case UI_BTYPE_BLOCK:
+ case UI_BTYPE_PULLDOWN:
if (but->menu_create_func) {
menufunc = but->menu_create_func;
arg = but->poin;
@@ -2927,13 +3486,13 @@ static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data
arg = but->poin ? but->poin : but->func_argN;
}
break;
- case MENU:
+ case UI_BTYPE_MENU:
BLI_assert(but->menu_create_func);
menufunc = but->menu_create_func;
arg = but->poin;
break;
- case COLOR:
- ui_get_but_vectorf(but, data->origvec);
+ case UI_BTYPE_COLOR:
+ ui_but_v3_get(but, data->origvec);
copy_v3_v3(data->vec, data->origvec);
but->editvec = data->vec;
@@ -2957,11 +3516,20 @@ static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data
data->menu->popup = but->block->handle->popup;
}
+#ifdef USE_ALLSELECT
+ {
+ wmWindow *win = CTX_wm_window(C);
+ if (IS_ALLSELECT_EVENT(win->eventstate)) {
+ data->select_others.is_enabled = true;
+ }
+ }
+#endif
+
/* this makes adjacent blocks auto open from now on */
//if (but->block->auto_open == 0) but->block->auto_open = 1;
}
-static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data)
+static void ui_block_open_end(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (but) {
but->editval = NULL;
@@ -2976,7 +3544,7 @@ static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data)
}
}
-int ui_button_open_menu_direction(uiBut *but)
+int ui_but_menu_direction(uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -2986,14 +3554,18 @@ int ui_button_open_menu_direction(uiBut *but)
return 0;
}
-/* Hack for uiList LISTROW buttons to "give" events to overlaying TEX buttons (cltr-clic rename feature & co). */
-static uiBut *ui_but_list_row_text_activate(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event,
- uiButtonActivateType activate_type)
+/**
+ * Hack for #uiList #UI_BTYPE_LISTROW buttons to "give" events to overlaying #UI_BTYPE_TEXT buttons
+ * (Ctrl-Click rename feature & co).
+ */
+static uiBut *ui_but_list_row_text_activate(
+ bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event,
+ uiButtonActivateType activate_type)
{
ARegion *ar = CTX_wm_region(C);
uiBut *labelbut = ui_but_find_mouse_over_ex(ar, event->x, event->y, true);
- if (labelbut && labelbut->type == TEX && !(labelbut->flag & UI_BUT_DISABLED)) {
+ if (labelbut && labelbut->type == UI_BTYPE_TEXT && !(labelbut->flag & UI_BUT_DISABLED)) {
/* exit listrow */
data->cancel = true;
button_activate_exit(C, but, data, false, false);
@@ -3050,16 +3622,16 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
}
}
else if (data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
-
- if (event->type == MOUSEMOVE)
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
return WM_UI_HANDLER_CONTINUE;
-
+ }
+
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
/* only cancel if click outside the button */
- if (ui_mouse_inside_button(but->active->region, but, event->x, event->y) == 0) {
+ if (ui_but_contains_point_px(but->active->region, but, event->x, event->y) == 0) {
/* data->cancel doesnt work, this button opens immediate */
if (but->flag & UI_BUT_IMMEDIATE)
- ui_set_but_val(but, 0);
+ ui_but_value_set(but, 0);
else
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -3074,14 +3646,14 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
if (event->ctrl) but->modifier_key |= KM_CTRL;
if (event->oskey) but->modifier_key |= KM_OSKEY;
- ui_check_but(but);
+ ui_but_update(but);
ED_region_tag_redraw(data->region);
if (event->val == KM_PRESS) {
if (ISHOTKEY(event->type)) {
- if (WM_key_event_string(event->type)[0])
- ui_set_but_val(but, event->type);
+ if (WM_key_event_string(event->type, false)[0])
+ ui_but_value_set(but, event->type);
else
data->cancel = true;
@@ -3111,12 +3683,13 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c
}
}
else if (data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
- if (event->type == MOUSEMOVE)
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
return WM_UI_HANDLER_CONTINUE;
+ }
if (event->val == KM_PRESS) {
- if (WM_key_event_string(event->type)[0])
- ui_set_but_val(but, event->type);
+ if (WM_key_event_string(event->type, false)[0])
+ ui_but_value_set(but, event->type);
else
data->cancel = true;
@@ -3131,10 +3704,10 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
- if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) {
+ if (ELEM(event->type, PADENTER, RETKEY) && (!ui_but_is_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
- else if (but->dt == UI_EMBOSSN && !event->ctrl) {
+ else if (but->dt == UI_EMBOSS_NONE && !event->ctrl) {
/* pass */
}
else {
@@ -3157,9 +3730,11 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
+ uiButExtraIconType extra_icon_type;
+
/* unlink icon is on right */
- if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
- ui_is_but_search_unlink_visible(but))
+ if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) &&
+ ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
{
ARegion *ar = data->region;
rcti rect;
@@ -3170,14 +3745,29 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
BLI_rcti_rctf_copy(&rect, &but->rect);
rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect));
+ /* handle click on unlink/eyedropper icon */
if (BLI_rcti_isect_pt(&rect, x, y)) {
- /* most likely NULL, but let's check, and give it temp zero string */
- if (data->str == NULL)
- data->str = MEM_callocN(1, "temp str");
- data->str[0] = 0;
+ /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
+ if (event->val == KM_RELEASE) {
+ /* unlink */
+ if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
+ /* most likely NULL, but let's check, and give it temp zero string */
+ if (data->str == NULL) {
+ data->str = MEM_callocN(1, "temp str");
+ }
+ data->str[0] = 0;
- ui_apply_but_TEX(C, but, data);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ ui_apply_but_TEX(C, but, data);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ /* eyedropper */
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
return WM_UI_HANDLER_BREAK;
}
@@ -3189,12 +3779,12 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
{
#ifdef USE_DRAG_TOGGLE
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_is_but_drag_toggle(but)) {
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_but_is_drag_toggle(but)) {
#if 0 /* UNUSED */
data->togdual = event->ctrl;
data->togonly = !event->shift;
#endif
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -3216,6 +3806,38 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
+ else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
+ /* Support alt+wheel on expanded enum rows */
+ if (but->type == UI_BTYPE_ROW) {
+ const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
+ uiBut *but_select = ui_but_find_select_in_enum(but, direction);
+ if (but_select) {
+ uiBut *but_other = (direction == -1) ? but_select->next : but_select->prev;
+ if (but_other && ui_but_find_select_in_enum__cmp(but, but_other)) {
+ ARegion *ar = data->region;
+
+ data->cancel = true;
+ button_activate_exit(C, but, data, false, false);
+
+ /* Activate the text button. */
+ button_activate_init(C, ar, but_other, BUTTON_ACTIVATE_OVER);
+ data = but_other->active;
+ if (data) {
+ ui_apply_but(C, but->block, but_other, but_other->active, true);
+ button_activate_exit(C, but_other, data, false, false);
+
+ /* restore active button */
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+ }
+ else {
+ /* shouldn't happen */
+ BLI_assert(0);
+ }
+ }
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
}
return WM_UI_HANDLER_CONTINUE;
}
@@ -3227,7 +3849,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
/* first handle click on icondrag type button */
if (event->type == LEFTMOUSE && but->dragpoin) {
- if (ui_but_mouse_inside_icon(but, data->region, event)) {
+ if (ui_but_contains_point_px_icon(but, data->region, event)) {
/* tell the button to wait and keep checking further events to
* see if it should start dragging */
@@ -3238,7 +3860,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) {
+ if (event->type == LEFTMOUSE && ui_but_is_drag_toggle(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -3249,7 +3871,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX (a bit ugly) Special case handling for filebrowser drag button */
- if (but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) {
+ if (but->dragpoin && but->imb && ui_but_contains_point_px_icon(but, data->region, event)) {
ret = WM_UI_HANDLER_CONTINUE;
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -3259,7 +3881,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
else if (data->state == BUTTON_STATE_WAIT_DRAG) {
/* this function also ends state */
- if (ui_but_start_drag(C, but, data, event)) {
+ if (ui_but_drag_init(C, but, data, event)) {
return WM_UI_HANDLER_BREAK;
}
@@ -3280,8 +3902,9 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
/* var names match ui_numedit_but_NUM */
-static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, float softmax, float softrange,
- const enum eSnapType snap)
+static float ui_numedit_apply_snapf(
+ uiBut *but, float tempf, float softmin, float softmax, float softrange,
+ const enum eSnapType snap)
{
if (tempf == softmin || tempf == softmax || snap == SNAP_OFF) {
/* pass */
@@ -3289,9 +3912,9 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
else {
float fac = 1.0f;
- if (ui_is_but_unit(but)) {
+ if (ui_but_is_unit(but)) {
UnitSettings *unit = but->block->unit;
- int unit_type = RNA_SUBTYPE_UNIT_VALUE(uiButGetUnitType(but));
+ int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
if (bUnit_IsValid(unit->system, unit_type)) {
fac = (float)bUnit_BaseScalar(unit->system, unit_type);
@@ -3309,15 +3932,25 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
softrange /= fac;
}
+ /* workaround, too high snapping values */
+ /* snapping by 10's for float buttons is quite annoying (location, scale...),
+ * but allow for rotations */
+ if (softrange >= 21.0f) {
+ int unit_type = UI_but_unit_type_get(but);
+ if (!ELEM(unit_type, PROP_UNIT_ROTATION)) {
+ softrange = 20.0f;
+ }
+ }
+
if (snap == SNAP_ON) {
- if (softrange < 2.10f) tempf = 0.1f * floorf(10.0f * tempf);
- else if (softrange < 21.0f) tempf = floorf(tempf);
- else tempf = 10.0f * floorf(tempf / 10.0f);
+ if (softrange < 2.10f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else if (softrange < 21.0f) tempf = roundf(tempf);
+ else tempf = roundf(tempf * 0.1f) * 10.0f;
}
else if (snap == SNAP_ON_SMALL) {
- if (softrange < 2.10f) tempf = 0.01f * floorf(100.0f * tempf);
- else if (softrange < 21.0f) tempf = 0.1f * floorf(10.0f * tempf);
- else tempf = floor(tempf);
+ if (softrange < 2.10f) tempf = roundf(tempf * 100.0f) * 0.01f;
+ else if (softrange < 21.0f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else tempf = roundf(tempf);
}
else {
BLI_assert(0);
@@ -3330,8 +3963,9 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
return tempf;
}
-static float ui_numedit_apply_snap(int temp, float softmin, float softmax,
- const enum eSnapType snap)
+static float ui_numedit_apply_snap(
+ int temp, float softmin, float softmax,
+ const enum eSnapType snap)
{
if (temp == softmin || temp == softmax)
return temp;
@@ -3350,14 +3984,15 @@ static float ui_numedit_apply_snap(int temp, float softmin, float softmax,
return temp;
}
-static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
- int mx,
- const enum eSnapType snap, float fac)
+static bool ui_numedit_but_NUM(
+ uiBut *but, uiHandleButtonData *data,
+ int mx,
+ const enum eSnapType snap, float fac)
{
float deler, tempf, softmin, softmax, softrange;
int lvalue, temp;
bool changed = false;
- const bool is_float = ui_is_but_float(but);
+ const bool is_float = ui_but_is_float(but);
if (mx == data->draglastx)
return changed;
@@ -3381,7 +4016,7 @@ static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
softmax = but->softmax;
softrange = softmax - softmin;
- if (ui_is_a_warp_but(but)) {
+ if (ui_but_is_cursor_warp(but)) {
/* Mouse location isn't screen clamped to the screen so use a linear mapping
* 2px == 1-int, or 1px == 1-ClickStep */
if (is_float) {
@@ -3468,7 +4103,7 @@ static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
if (!is_float) {
- temp = floorf(tempf + 0.5f);
+ temp = iroundf(tempf);
temp = ui_numedit_apply_snap(temp, softmin, softmax, snap);
@@ -3521,11 +4156,11 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
/* XXX hardcoded keymap check.... */
if (type == MOUSEPAN && event->alt)
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
- else if (type == WHEELDOWNMOUSE && event->alt) {
+ else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
click = 1;
}
- else if (type == WHEELUPMOUSE && event->alt) {
+ else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
click = 1;
}
@@ -3535,7 +4170,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
retval = WM_UI_HANDLER_BREAK;
}
else if (event->type == LEFTMOUSE) {
- data->dragstartx = data->draglastx = ui_is_a_warp_but(but) ? screen_mx : mx;
+ data->dragstartx = data->draglastx = ui_but_is_cursor_warp(but) ? screen_mx : mx;
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -3580,7 +4215,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
}
- else if (event->type == MOUSEMOVE) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
const enum eSnapType snap = ui_event_to_snap(event);
float fac;
@@ -3591,9 +4226,8 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
fac = 1.0f;
if (event->shift) fac /= 10.0f;
- if (event->alt) fac /= 20.0f;
- if (ui_numedit_but_NUM(but, data, (ui_is_a_warp_but(but) ? screen_mx : mx), snap, fac))
+ if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac))
ui_numedit_apply(C, block, but, data);
#ifdef USE_DRAG_MULTINUM
else if (data->multi_data.has_mbuts) {
@@ -3626,7 +4260,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
handlewidth = min_ff(BLI_rctf_size_x(&but->rect) / 3, BLI_rctf_size_y(&but->rect));
- if (!ui_is_but_float(but)) {
+ if (!ui_but_is_float(but)) {
if (mx < (but->rect.xmin + handlewidth)) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
@@ -3657,7 +4291,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
if (mx < (but->rect.xmin + handlewidth)) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- tempf = (float)data->value - 0.01f * but->a1;
+ tempf = (float)data->value - (UI_PRECISION_FLOAT_SCALE * but->a1);
if (tempf < softmin) tempf = softmin;
data->value = tempf;
@@ -3666,7 +4300,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else if (mx > but->rect.xmax - handlewidth) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- tempf = (float)data->value + 0.01f * but->a1;
+ tempf = (float)data->value + (UI_PRECISION_FLOAT_SCALE * but->a1);
if (tempf > softmax) tempf = softmax;
data->value = tempf;
@@ -3686,9 +4320,10 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return retval;
}
-static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
- int mx, const bool is_horizontal,
- const bool snap, const bool shift)
+static bool ui_numedit_but_SLI(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, const bool is_horizontal,
+ const bool snap, const bool shift)
{
float deler, f, tempf, softmin, softmax, softrange;
int temp, lvalue;
@@ -3704,11 +4339,11 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
/* yes, 'mx' as both x/y is intentional */
ui_mouse_scale_warp(data, mx, mx, &mx_fl, &my_fl, shift);
- if (but->type == NUMSLI) {
+ if (but->type == UI_BTYPE_NUM_SLIDER) {
offs = (BLI_rctf_size_y(&but->rect) / 2.0f);
deler = BLI_rctf_size_x(&but->rect) - offs;
}
- else if (but->type == SCROLL) {
+ else if (but->type == UI_BTYPE_SCROLL) {
const float size = (is_horizontal) ? BLI_rctf_size_x(&but->rect) : -BLI_rctf_size_y(&but->rect);
deler = size * (but->softmax - but->softmin) / (but->softmax - but->softmin + but->a1);
offs = 0.0;
@@ -3724,7 +4359,7 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
/* deal with mouse correction */
#ifdef USE_CONT_MOUSE_CORRECT
- if (ui_is_a_warp_but(but)) {
+ if (ui_but_is_cursor_warp(but)) {
/* OK but can go outside bounds */
if (is_horizontal) {
data->ungrab_mval[0] = (but->rect.xmin + offs) + (f * deler);
@@ -3741,24 +4376,24 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
tempf = softmin + f * softrange;
- temp = floorf(tempf + 0.5f);
+ temp = iroundf(tempf);
if (snap) {
if (tempf == softmin || tempf == softmax) {
/* pass */
}
- else if (ui_is_but_float(but)) {
+ else if (ui_but_is_float(but)) {
if (shift) {
if (tempf == softmin || tempf == softmax) {}
- else if (softmax - softmin < 2.10f) tempf = 0.01f * floorf(100.0f * tempf);
- else if (softmax - softmin < 21.0f) tempf = 0.1f * floorf(10.0f * tempf);
- else tempf = floorf(tempf);
+ else if (softrange < 2.10f) tempf = roundf(tempf * 100.0f) * 0.01f;
+ else if (softrange < 21.0f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else tempf = roundf(tempf);
}
else {
- if (softmax - softmin < 2.10f) tempf = 0.1f * floorf(10.0f * tempf);
- else if (softmax - softmin < 21.0f) tempf = floorf(tempf);
- else tempf = 10.0f * floorf(tempf / 10.0f);
+ if (softrange < 2.10f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else if (softrange < 21.0f) tempf = roundf(tempf);
+ else tempf = roundf(tempf * 0.1f) * 10.0f;
}
}
else {
@@ -3767,8 +4402,8 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
}
}
- if (!ui_is_but_float(but)) {
- lvalue = floor(data->value + 0.5);
+ if (!ui_but_is_float(but)) {
+ lvalue = round(data->value);
CLAMP(temp, softmin, softmax);
@@ -3810,11 +4445,11 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
/* XXX hardcoded keymap check.... */
if (type == MOUSEPAN && event->alt)
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
- else if (type == WHEELDOWNMOUSE && event->alt) {
+ else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
click = 2;
}
- else if (type == WHEELUPMOUSE && event->alt) {
+ else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
click = 2;
}
@@ -3823,7 +4458,8 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
- /* alt-click on sides to get "arrows" like in NUM buttons, and match wheel usage above */
+#ifndef USE_ALLSELECT
+ /* alt-click on sides to get "arrows" like in UI_BTYPE_NUM buttons, and match wheel usage above */
else if (event->type == LEFTMOUSE && event->alt) {
int halfpos = BLI_rctf_cent_x(&but->rect);
click = 2;
@@ -3832,6 +4468,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else
mx = but->rect.xmax;
}
+#endif
else if (event->type == LEFTMOUSE) {
data->dragstartx = mx;
data->draglastx = mx;
@@ -3877,7 +4514,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
}
- else if (event->type == MOUSEMOVE) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
#ifdef USE_DRAG_MULTINUM
data->multi_data.drag_dir[0] += abs(data->draglastx - mx);
data->multi_data.drag_dir[1] += abs(data->draglasty - my);
@@ -3931,7 +4568,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
f = softmin + f * softrange;
- if (!ui_is_but_float(but)) {
+ if (!ui_but_is_float(but)) {
if (f < temp) temp--;
else temp++;
@@ -4097,7 +4734,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
/* first handle click on icondrag type button */
if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
- if (ui_but_mouse_inside_icon(but, data->region, event)) {
+ if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4105,7 +4742,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) {
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_but_is_drag_toggle(but))) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4117,14 +4754,14 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (but->type == MENU) {
- if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (but->type == UI_BTYPE_MENU) {
+ if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
- data->value = ui_step_name_menu(but, direction);
+ data->value = ui_but_menu_step(but, direction);
button_activate_state(C, but, BUTTON_STATE_EXIT);
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
/* button's state need to be changed to EXIT so moving mouse away from this mouse wouldn't lead
* to cancel changes made to this button, but changing state to EXIT also makes no button active for
@@ -4153,12 +4790,12 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
else if (data->state == BUTTON_STATE_WAIT_DRAG) {
/* this function also ends state */
- if (ui_but_start_drag(C, but, data, event)) {
+ if (ui_but_drag_init(C, but, data, event)) {
return WM_UI_HANDLER_BREAK;
}
/* outside icon quit, not needed if drag activated */
- if (0 == ui_but_mouse_inside_icon(but, data->region, event)) {
+ if (0 == ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = true;
return WM_UI_HANDLER_BREAK;
@@ -4174,9 +4811,10 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const enum eSnapType snap)
+static bool ui_numedit_but_UNITVEC(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const enum eSnapType snap)
{
float dx, dy, rad, radsq, mrad, *fp;
int mdx, mdy;
@@ -4242,7 +4880,7 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data,
* do this in "angle" space - this gives increments of same size */
for (i = 0; i < 3; i++) {
angle = asinf(fp[i]);
- angle_snap = floorf(0.5f + (angle / snap_steps_angle)) * snap_steps_angle;
+ angle_snap = roundf((angle / snap_steps_angle)) * snap_steps_angle;
fp[i] = sinf(angle_snap);
}
normalize_v3(fp);
@@ -4270,7 +4908,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
/* first handle click on icondrag type button */
if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
ui_palette_set_active(but);
- if (ui_but_mouse_inside_icon(but, data->region, event)) {
+ if (ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4292,11 +4930,13 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
- float *hsv = ui_block_hsv_get(but->block);
+ else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
+ ColorPicker *cpicker = but->custom_data;
+ float hsv_static[3] = {0.0f};
+ float *hsv = cpicker ? cpicker->color_data : hsv_static;
float col[3];
- ui_get_but_vectorf(but, col);
+ ui_but_v3_get(but, col);
rgb_to_hsv_compat_v(col, hsv);
if (event->type == WHEELDOWNMOUSE)
@@ -4309,10 +4949,10 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
hsv_to_rgb_v(hsv, data->vec);
- ui_set_but_vectorf(but, data->vec);
+ ui_but_v3_set(but, data->vec);
button_activate_state(C, but, BUTTON_STATE_EXIT);
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
return WM_UI_HANDLER_BREAK;
}
else if ((int)(but->a1) == UI_PALETTE_COLOR &&
@@ -4324,18 +4964,24 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
BKE_palette_color_remove(palette, color);
button_activate_state(C, but, BUTTON_STATE_EXIT);
+
+ /* this is risky. it works OK for now,
+ * but if it gives trouble we should delay execution */
+ but->rnapoin = PointerRNA_NULL;
+ but->rnaprop = NULL;
+
return WM_UI_HANDLER_BREAK;
}
}
else if (data->state == BUTTON_STATE_WAIT_DRAG) {
/* this function also ends state */
- if (ui_but_start_drag(C, but, data, event)) {
+ if (ui_but_drag_init(C, but, data, event)) {
return WM_UI_HANDLER_BREAK;
}
/* outside icon quit, not needed if drag activated */
- if (0 == ui_but_mouse_inside_icon(but, data->region, event)) {
+ if (0 == ui_but_contains_point_px_icon(but, data->region, event)) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = true;
return WM_UI_HANDLER_BREAK;
@@ -4354,7 +5000,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
- ui_block_to_scene_linear_v3(but->block, target);
+ ui_block_cm_to_scene_linear_v3(but->block, target);
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
@@ -4367,7 +5013,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
- ui_block_to_display_space_v3(but->block, color);
+ ui_block_cm_to_display_space_v3(but->block, color);
BKE_brush_color_set(scene, brush, color);
}
}
@@ -4389,7 +5035,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_NORMAL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -4407,17 +5053,17 @@ static int ui_do_but_NORMAL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
/* also do drag the first time */
- if (ui_numedit_but_NORMAL(but, data, mx, my, snap))
+ if (ui_numedit_but_UNITVEC(but, data, mx, my, snap))
ui_numedit_apply(C, block, but, data);
return WM_UI_HANDLER_BREAK;
}
}
else if (data->state == BUTTON_STATE_NUM_EDITING) {
- if (event->type == MOUSEMOVE) {
- if (mx != data->draglastx || my != data->draglasty) {
+ if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) {
const enum eSnapType snap = ui_event_to_snap(event);
- if (ui_numedit_but_NORMAL(but, data, mx, my, snap))
+ if (ui_numedit_but_UNITVEC(but, data, mx, my, snap))
ui_numedit_apply(C, block, but, data);
}
}
@@ -4468,21 +5114,23 @@ static void ui_color_picker_to_rgb_HSVCUBE_v(uiBut *but, const float hsv[3], flo
hsv_to_rgb_v(hsv, rgb);
}
-static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const enum eSnapType snap, const bool shift)
+static bool ui_numedit_but_HSVCUBE(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const enum eSnapType snap, const bool shift)
{
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
float rgb[3];
- float *hsv = ui_block_hsv_get(but->block);
float x, y;
float mx_fl, my_fl;
bool changed = true;
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
#ifdef USE_CONT_MOUSE_CORRECT
- if (ui_is_a_warp_but(but)) {
+ if (ui_but_is_cursor_warp(but)) {
/* OK but can go outside bounds */
data->ungrab_mval[0] = mx_fl;
data->ungrab_mval[1] = my_fl;
@@ -4490,10 +5138,10 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
#endif
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(but, rgb, hsv);
@@ -4507,9 +5155,9 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
/* calculate original hsv again */
copy_v3_v3(rgb, data->origvec);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
- copy_v3_v3(hsvo, ui_block_hsv_get(but->block));
+ copy_v3_v3(hsvo, hsv);
ui_rgb_to_color_picker_HSVCUBE_compat_v(but, rgb, hsvo);
@@ -4528,8 +5176,8 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
switch ((int)but->a1) {
case UI_GRAD_SV:
- hsv[2] = x;
- hsv[1] = y;
+ hsv[1] = x;
+ hsv[2] = y;
break;
case UI_GRAD_HV:
hsv[0] = x;
@@ -4552,11 +5200,16 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
hsv[2] = y;
break;
case UI_GRAD_V_ALT:
+ {
/* vertical 'value' strip */
-
+ float min = but->softmin, max = but->softmax;
+ if (use_display_colorspace) {
+ ui_block_cm_to_display_space_range(but->block, &min, &max);
+ }
/* exception only for value strip - use the range set in but->min/max */
- hsv[2] = y * (but->softmax - but->softmin) + but->softmin;
+ hsv[2] = y * (max - min) + min;
break;
+ }
default:
BLI_assert(0);
break;
@@ -4571,7 +5224,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
ui_color_picker_to_rgb_HSVCUBE_v(but, hsv, rgb);
if (use_display_colorspace)
- ui_block_to_scene_linear_v3(but->block, rgb);
+ ui_block_cm_to_scene_linear_v3(but->block, rgb);
/* clamp because with color conversion we can exceed range [#34295] */
if (but->a1 == UI_GRAD_V_ALT) {
@@ -4586,27 +5239,29 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
return changed;
}
-static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
- const wmNDOFMotionData *ndof,
- const enum eSnapType snap, const bool shift)
+static void ui_ndofedit_but_HSVCUBE(
+ uiBut *but, uiHandleButtonData *data,
+ const wmNDOFMotionData *ndof,
+ const enum eSnapType snap, const bool shift)
{
- float *hsv = ui_block_hsv_get(but->block);
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
const float hsv_v_max = max_ff(hsv[2], but->softmax);
float rgb[3];
float sensitivity = (shift ? 0.15f : 0.3f) * ndof->dt;
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(but, rgb, hsv);
switch ((int)but->a1) {
case UI_GRAD_SV:
- hsv[2] += ndof->rvec[2] * sensitivity;
- hsv[1] += ndof->rvec[0] * sensitivity;
+ hsv[1] += ndof->rvec[2] * sensitivity;
+ hsv[2] += ndof->rvec[0] * sensitivity;
break;
case UI_GRAD_HV:
hsv[0] += ndof->rvec[2] * sensitivity;
@@ -4651,10 +5306,10 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
ui_color_picker_to_rgb_HSVCUBE_v(but, hsv, rgb);
if (use_display_colorspace)
- ui_block_to_scene_linear_v3(but->block, rgb);
+ ui_block_cm_to_scene_linear_v3(but->block, rgb);
copy_v3_v3(data->vec, rgb);
- ui_set_but_vectorf(but, data->vec);
+ ui_but_v3_set(but, data->vec);
}
static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
@@ -4688,7 +5343,7 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
ui_ndofedit_but_HSVCUBE(but, data, ndof, snap, event->shift != 0);
button_activate_state(C, but, BUTTON_STATE_EXIT);
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
return WM_UI_HANDLER_BREAK;
}
@@ -4703,19 +5358,20 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
if (ELEM(len, 3, 4)) {
float rgb[3], def_hsv[3];
float def[4];
- float *hsv = ui_block_hsv_get(but->block);
-
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
+
RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def);
ui_rgb_to_color_picker_HSVCUBE_v(but, def, def_hsv);
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(but, rgb, hsv);
def_hsv[0] = hsv[0];
def_hsv[1] = hsv[1];
ui_color_picker_to_rgb_HSVCUBE_v(but, def_hsv, rgb);
- ui_set_but_vectorf(but, rgb);
+ ui_but_v3_set(but, rgb);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
return WM_UI_HANDLER_BREAK;
@@ -4731,8 +5387,8 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
- else if (event->type == MOUSEMOVE) {
- if (mx != data->draglastx || my != data->draglasty) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) {
const enum eSnapType snap = ui_event_to_snap(event);
if (ui_numedit_but_HSVCUBE(but, data, mx, my, snap, event->shift != 0))
@@ -4749,21 +5405,23 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
- float mx, float my,
- const enum eSnapType snap, const bool shift)
+static bool ui_numedit_but_HSVCIRCLE(
+ uiBut *but, uiHandleButtonData *data,
+ float mx, float my,
+ const enum eSnapType snap, const bool shift)
{
rcti rect;
bool changed = true;
float mx_fl, my_fl;
float rgb[3];
- float *hsv = ui_block_hsv_get(but->block);
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
#ifdef USE_CONT_MOUSE_CORRECT
- if (ui_is_a_warp_but(but)) {
+ if (ui_but_is_cursor_warp(but)) {
/* OK but can go outside bounds */
data->ungrab_mval[0] = mx_fl;
data->ungrab_mval[1] = my_fl;
@@ -4780,9 +5438,9 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
BLI_rcti_rctf_copy(&rect, &but->rect);
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
@@ -4793,8 +5451,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
if (hsv[2] == 0.f) hsv[2] = 0.0001f;
}
else {
- if (hsv[2] == 0.f) hsv[2] = 0.0001f;
- if (hsv[2] == 1.f) hsv[2] = 0.9999f;
+ if (hsv[2] == 0.0f) hsv[2] = 0.0001f;
+ if (hsv[2] >= 0.9999f) hsv[2] = 0.9999f;
}
}
@@ -4803,10 +5461,10 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
float xpos, ypos, hsvo[3], rgbo[3];
/* calculate original hsv again */
- copy_v3_v3(hsvo, ui_block_hsv_get(but->block));
+ copy_v3_v3(hsvo, hsv);
copy_v3_v3(rgbo, data->origvec);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgbo);
+ ui_block_cm_to_display_space_v3(but->block, rgbo);
ui_rgb_to_color_picker_compat_v(rgbo, hsvo);
@@ -4835,9 +5493,9 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
}
if (use_display_colorspace)
- ui_block_to_scene_linear_v3(but->block, rgb);
+ ui_block_cm_to_scene_linear_v3(but->block, rgb);
- ui_set_but_vectorf(but, rgb);
+ ui_but_v3_set(but, rgb);
data->draglastx = mx;
data->draglasty = my;
@@ -4845,19 +5503,21 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
return changed;
}
-static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
- const wmNDOFMotionData *ndof,
- const enum eSnapType snap, const bool shift)
+static void ui_ndofedit_but_HSVCIRCLE(
+ uiBut *but, uiHandleButtonData *data,
+ const wmNDOFMotionData *ndof,
+ const enum eSnapType snap, const bool shift)
{
- float *hsv = ui_block_hsv_get(but->block);
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
float rgb[3];
float phi, r /*, sqr */ /* UNUSED */, v[2];
float sensitivity = (shift ? 0.06f : 0.3f) * ndof->dt;
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
/* Convert current color on hue/sat disc to circular coordinates phi, r */
@@ -4910,14 +5570,16 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
}
if (use_display_colorspace)
- ui_block_to_scene_linear_v3(but->block, data->vec);
+ ui_block_cm_to_scene_linear_v3(but->block, data->vec);
- ui_set_but_vectorf(but, data->vec);
+ ui_but_v3_set(but, data->vec);
}
static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
int mx, my;
mx = event->x;
my = event->y;
@@ -4945,7 +5607,7 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_ndofedit_but_HSVCIRCLE(but, data, ndof, snap, event->shift != 0);
button_activate_state(C, but, BUTTON_STATE_EXIT);
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
return WM_UI_HANDLER_BREAK;
}
@@ -4959,20 +5621,19 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
if (len >= 3) {
float rgb[3], def_hsv[3];
float *def;
- float *hsv = ui_block_hsv_get(but->block);
def = MEM_callocN(sizeof(float) * len, "reset_defaults - float");
RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def);
ui_color_picker_to_rgb_v(def, def_hsv);
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
def_hsv[0] = hsv[0];
def_hsv[2] = hsv[2];
hsv_to_rgb_v(def_hsv, rgb);
- ui_set_but_vectorf(but, rgb);
+ ui_but_v3_set(but, rgb);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
@@ -4991,19 +5652,17 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
}
/* XXX hardcoded keymap check.... */
else if (event->type == WHEELDOWNMOUSE) {
- float *hsv = ui_block_hsv_get(but->block);
hsv[2] = CLAMPIS(hsv[2] - 0.05f, 0.0f, 1.0f);
- ui_set_but_hsv(but); /* converts to rgb */
+ ui_but_hsv_set(but); /* converts to rgb */
ui_numedit_apply(C, block, but, data);
}
else if (event->type == WHEELUPMOUSE) {
- float *hsv = ui_block_hsv_get(but->block);
hsv[2] = CLAMPIS(hsv[2] + 0.05f, 0.0f, 1.0f);
- ui_set_but_hsv(but); /* converts to rgb */
+ ui_but_hsv_set(but); /* converts to rgb */
ui_numedit_apply(C, block, but, data);
}
- else if (event->type == MOUSEMOVE) {
- if (mx != data->draglastx || my != data->draglasty) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) {
const enum eSnapType snap = ui_event_to_snap(event);
if (ui_numedit_but_HSVCIRCLE(but, data, mx, my, snap, event->shift != 0)) {
@@ -5049,7 +5708,9 @@ static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandle
{
ColorBand *coba;
CBData *cbd;
- int mx, my, a, xco, mindist = 12;
+ /* ignore zoom-level for mindist */
+ int mindist = (50 * UI_DPI_FAC) * block->aspect;
+ int mx, my, a, xco;
mx = event->x;
my = event->y;
@@ -5106,7 +5767,8 @@ static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandle
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData *data,
+static bool ui_numedit_but_CURVE(
+ uiBlock *block, uiBut *but, uiHandleButtonData *data,
int evtx, int evty,
bool snap, const bool shift)
{
@@ -5156,8 +5818,8 @@ static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData
cmp[a].x += fx;
cmp[a].y += fy;
if (snap) {
- cmp[a].x = 0.125f * floorf(0.5f + 8.0f * cmp[a].x);
- cmp[a].y = 0.125f * floorf(0.5f + 8.0f * cmp[a].y);
+ cmp[a].x = 0.125f * roundf(8.0f * cmp[a].x);
+ cmp[a].y = 0.125f * roundf(8.0f * cmp[a].y);
}
if (cmp[a].x != origx || cmp[a].y != origy)
moved_point = true;
@@ -5176,7 +5838,7 @@ static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData
#ifdef USE_CONT_MOUSE_CORRECT
/* note: using 'cmp_last' is weak since there may be multiple points selected,
* but in practice this isnt really an issue */
- if (ui_is_a_warp_but(but)) {
+ if (ui_but_is_cursor_warp(but)) {
/* OK but can go outside bounds */
data->ungrab_mval[0] = but->rect.xmin + ((cmp_last->x - cumap->curr.xmin) * zoomx);
data->ungrab_mval[1] = but->rect.ymin + ((cmp_last->y - cumap->curr.ymin) * zoomy);
@@ -5374,7 +6036,7 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m
float dy = my - data->draglasty;
/* scale histogram values (dy / 10 for better control) */
- const float yfac = min_ff(powf(hist->ymax, 2.0f), 1.0f) * 0.5f;
+ const float yfac = min_ff(pow2f(hist->ymax), 1.0f) * 0.5f;
hist->ymax += (dy * 0.1f) * yfac;
/* 0.1 allows us to see HDR colors up to 10 */
@@ -5540,9 +6202,10 @@ static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, con
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_TRACKPREVIEW(bContext *C, uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const bool shift)
+static bool ui_numedit_but_TRACKPREVIEW(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const bool shift)
{
MovieClipScopes *scopes = (MovieClipScopes *)but->poin;
bool changed = true;
@@ -5632,7 +6295,7 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
/* complex code to change name of button */
if (WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, true,
- shortcut_str, sizeof(shortcut_str)))
+ sizeof(shortcut_str), shortcut_str))
{
ui_but_add_shortcut(but, shortcut_str, true);
}
@@ -5652,7 +6315,7 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
wmKeyMapItem *kmi;
PointerRNA ptr;
uiLayout *layout;
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
@@ -5660,20 +6323,24 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
- block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
- uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
- uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
- uiBlockSetDirection(block, UI_CENTER);
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ UI_block_func_handle_set(block, but_shortcut_name_func, but);
+ UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
+ UI_block_direction_set(block, UI_DIR_CENTER_Y);
- layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
+ layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
- uiPopupBoundsBlock(block, 6, -50, 26);
+ UI_block_bounds_set_popup(block, 6, -50, 26);
return block;
}
+#ifdef USE_KEYMAP_ADD_HACK
+static int g_kmi_id_hack;
+#endif
+
static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -5683,7 +6350,7 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
wmKeyMapItem *kmi;
PointerRNA ptr;
uiLayout *layout;
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
int kmi_id;
@@ -5705,16 +6372,19 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
- block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
- uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
- uiBlockSetDirection(block, UI_CENTER);
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ UI_block_func_handle_set(block, but_shortcut_name_func, but);
+ UI_block_direction_set(block, UI_DIR_CENTER_Y);
- layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
+ layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, 0, style);
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
- uiPopupBoundsBlock(block, 6, -50, 26);
-
+ UI_block_bounds_set_popup(block, 6, -50, 26);
+
+#ifdef USE_KEYMAP_ADD_HACK
+ g_kmi_id_hack = kmi_id;
+#endif
return block;
}
@@ -5723,9 +6393,20 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
uiBut *but = (uiBut *)arg1;
wmKeyMap *km;
wmKeyMapItem *kmi;
- IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
- int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
-
+#ifndef USE_KEYMAP_ADD_HACK
+ IDProperty *prop;
+#endif
+ int kmi_id;
+
+#ifdef USE_KEYMAP_ADD_HACK
+ km = WM_keymap_guess_opname(C, but->optype->idname);
+ kmi_id = g_kmi_id_hack;
+ UNUSED_VARS(but);
+#else
+ prop = (but->opptr) ? but->opptr->data : NULL;
+ kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
+#endif
+
kmi = WM_keymap_item_find_id(km, kmi_id);
WM_keymap_remove_item(km, kmi);
}
@@ -5733,8 +6414,8 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- button_timers_tooltip_remove(C, but);
- uiPupBlock(C, menu_change_shortcut, but);
+ UI_but_tooltip_timer_remove(C, but);
+ UI_popup_block_invoke(C, menu_change_shortcut, but);
}
static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
@@ -5754,8 +6435,8 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- button_timers_tooltip_remove(C, but);
- uiPupBlockEx(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
+ UI_but_tooltip_timer_remove(C, but);
+ UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
}
/**
@@ -5770,8 +6451,8 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr);
- pup = uiPupMenuBegin(C, IFACE_("Panel"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
if (UI_panel_category_is_visible(ar)) {
char tmpstr[80];
BLI_snprintf(tmpstr, sizeof(tmpstr), "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift+Left Mouse"));
@@ -5785,7 +6466,7 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
}
}
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
static bool ui_but_menu(bContext *C, uiBut *but)
@@ -5799,17 +6480,17 @@ static bool ui_but_menu(bContext *C, uiBut *but)
/* return 0;*/
/* having this menu for some buttons makes no sense */
- if (but->type == BUT_IMAGE) {
+ if (but->type == UI_BTYPE_IMAGE) {
return false;
}
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
/* highly unlikely getting the label ever fails */
- uiButGetStrInfo(C, but, &label, NULL);
+ UI_but_string_info_get(C, but, &label, NULL);
- pup = uiPupMenuBegin(C, label.strinfo ? label.strinfo : "", ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, label.strinfo ? label.strinfo : "", ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
if (label.strinfo)
MEM_freeN(label.strinfo);
@@ -5835,19 +6516,19 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (but->flag & UI_BUT_ANIMATED_KEY) {
/* replace/delete keyfraemes */
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Single Keyframe"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Single Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframes"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Keyframe"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 0);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframe"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframe"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 1);
}
@@ -5861,26 +6542,26 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
else if (is_anim) {
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframes"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Single Keyframe"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Single Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframe"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
}
}
- if (but->flag & UI_BUT_ANIMATED) {
+ if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) {
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 0);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1);
}
}
@@ -5890,20 +6571,20 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemS(layout);
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Drivers"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Drivers"),
ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Driver"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Driver"),
ICON_NONE, "ANIM_OT_driver_button_remove", "all", 0);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Driver"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Driver"),
ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1);
}
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver"),
ICON_NONE, "ANIM_OT_copy_driver_button");
if (ANIM_driver_can_paste()) {
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
ICON_NONE, "ANIM_OT_paste_driver_button");
}
}
@@ -5914,18 +6595,18 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemS(layout);
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
ICON_NONE, "ANIM_OT_driver_button_add", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single Driver"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single Driver"),
ICON_NONE, "ANIM_OT_driver_button_add", "all", 0);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
ICON_NONE, "ANIM_OT_driver_button_add", "all", 1);
}
if (ANIM_driver_can_paste()) {
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
ICON_NONE, "ANIM_OT_paste_driver_button");
}
}
@@ -5936,17 +6617,17 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemS(layout);
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single to Keying Set"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single to Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 0);
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_remove");
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Keying Set"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1);
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_remove");
}
}
@@ -5959,23 +6640,23 @@ static bool ui_but_menu(bContext *C, uiBut *but)
* Paste Property Value */
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"),
ICON_NONE, "UI_OT_reset_default_button", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Single to Default Value"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Single to Default Value"),
ICON_NONE, "UI_OT_reset_default_button", "all", 0);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"),
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"),
ICON_NONE, "UI_OT_reset_default_button", "all", 1);
}
if (is_editable /*&& is_idprop*/ && is_set) {
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"),
ICON_NONE, "UI_OT_unset_property_button");
}
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
ICON_NONE, "UI_OT_copy_data_path_button");
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
ICON_NONE, "UI_OT_copy_to_selected_button");
uiItemS(layout);
@@ -6000,26 +6681,26 @@ static bool ui_but_menu(bContext *C, uiBut *but)
/* would rather use a block but, but gets weirdly positioned... */
//uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, "");
- but2 = uiDefIconTextBut(block, BUT, 0, 0, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"),
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but2, popup_change_shortcut_func, but, NULL);
+ UI_but_func_set(but2, popup_change_shortcut_func, but, NULL);
- but2 = uiDefIconTextBut(block, BUT, 0, 0, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but2, remove_shortcut_func, but, NULL);
+ UI_but_func_set(but2, remove_shortcut_func, but, NULL);
}
/* only show 'add' if there's a suitable key map for it to go in */
else if (WM_keymap_guess_opname(C, but->optype->idname)) {
- but2 = uiDefIconTextBut(block, BUT, 0, 0, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"),
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but2, popup_add_shortcut_func, but, NULL);
+ UI_but_func_set(but2, popup_add_shortcut_func, but, NULL);
}
uiItemS(layout);
}
/* Show header tools for header buttons. */
- {
+ if (ui_block_is_menu(but->block) == false) {
ARegion *ar = CTX_wm_region(C);
if (ar && (ar->regiontype == RGN_TYPE_HEADER)) {
uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL);
@@ -6031,18 +6712,13 @@ static bool ui_but_menu(bContext *C, uiBut *but)
char buf[512];
PointerRNA ptr_props;
- if (but->rnapoin.data && but->rnaprop) {
- BLI_snprintf(buf, sizeof(buf), "%s.%s",
- RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view_manual", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
+ if (UI_but_online_manual_id(but, buf, sizeof(buf))) {
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
+ ICON_NONE, "WM_OT_doc_view_manual_ui_context");
WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
/* XXX inactive option, not for public! */
@@ -6054,30 +6730,6 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
- else if (but->optype) {
- WM_operator_py_idname(buf, but->optype->idname);
-
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view_manual", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
-
- /* XXX inactive option, not for public! */
-#if 0
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
- RNA_string_set(&ptr_props, "doc_id", buf);
- RNA_string_set(&ptr_props, "doc_new", but->optype->description);
-
- uiItemFullO(layout, "WM_OT_doc_edit", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Submit Description"),
- ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
-#endif
- }
}
/* perhaps we should move this into (G.debug & G_DEBUG) - campbell */
@@ -6086,7 +6738,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
uiItemFullO(layout, "UI_OT_edittranslation_init", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
return true;
}
@@ -6104,9 +6756,11 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
/* handle copy-paste */
- if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS && (event->ctrl || event->oskey)) {
+ if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
+ IS_EVENT_MOD(event, ctrl, oskey))
+ {
/* Specific handling for listrows, we try to find their overlapping tex button. */
- if (but->type == LISTROW) {
+ if (but->type == UI_BTYPE_LISTROW) {
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
if (labelbut) {
but = labelbut;
@@ -6123,15 +6777,17 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle eyedropper */
else if ((event->type == EKEY) && (event->val == KM_PRESS)) {
- if (event->alt || event->shift || event->ctrl || event->oskey) {
+ if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
}
else {
- if (but->type == COLOR) {
+ if (but->type == UI_BTYPE_COLOR) {
WM_operator_name_call(C, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, NULL);
return WM_UI_HANDLER_BREAK;
}
- else if (but->type == SEARCH_MENU_UNLINK) {
+ else if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_POINTER) {
StructRNA *type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
const short idcode = RNA_type_to_ID_code(type);
@@ -6141,11 +6797,21 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
}
}
+ else if (but->type == UI_BTYPE_NUM) {
+ if (but->rnaprop &&
+ (RNA_property_type(but->rnaprop) == PROP_FLOAT) &&
+ (RNA_property_subtype(but->rnaprop) & PROP_UNIT_LENGTH) &&
+ (RNA_property_array_check(but->rnaprop) == false))
+ {
+ WM_operator_name_call(C, "UI_OT_eyedropper_depth", WM_OP_INVOKE_DEFAULT, NULL);
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
}
}
/* handle keyframing */
else if ((event->type == IKEY) &&
- !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey) &&
+ !IS_EVENT_MOD(event, ctrl, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt) {
@@ -6166,7 +6832,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle drivers */
else if ((event->type == DKEY) &&
- !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6180,7 +6846,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle keyingsets */
else if ((event->type == KKEY) &&
- !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6193,7 +6859,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
return WM_UI_HANDLER_BREAK;
}
/* handle menu */
- else if (event->type == RIGHTMOUSE && event->val == KM_PRESS) {
+ else if ((event->type == RIGHTMOUSE) &&
+ !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
+ (event->val == KM_PRESS))
+ {
/* RMB has two options now */
if (ui_but_menu(C, but)) {
return WM_UI_HANDLER_BREAK;
@@ -6220,107 +6889,112 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
switch (but->type) {
- case BUT:
+ case UI_BTYPE_BUT:
retval = ui_do_but_BUT(C, but, data, event);
break;
- case KEYEVT:
+ case UI_BTYPE_KEY_EVENT:
retval = ui_do_but_KEYEVT(C, but, data, event);
break;
- case HOTKEYEVT:
+ case UI_BTYPE_HOTKEY_EVENT:
retval = ui_do_but_HOTKEYEVT(C, but, data, event);
break;
- case TOGBUT:
- case TOG:
- case ICONTOG:
- case ICONTOGN:
- case TOGN:
- case OPTION:
- case OPTIONN:
+ case UI_BTYPE_BUT_TOGGLE:
+ case UI_BTYPE_TOGGLE:
+ case UI_BTYPE_ICON_TOGGLE:
+ case UI_BTYPE_ICON_TOGGLE_N:
+ case UI_BTYPE_TOGGLE_N:
+ case UI_BTYPE_CHECKBOX:
+ case UI_BTYPE_CHECKBOX_N:
+ case UI_BTYPE_ROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
- case SCROLL:
+ case UI_BTYPE_SCROLL:
retval = ui_do_but_SCROLL(C, block, but, data, event);
break;
- case GRIP:
+ case UI_BTYPE_GRIP:
retval = ui_do_but_GRIP(C, block, but, data, event);
break;
- case NUM:
+ case UI_BTYPE_NUM:
retval = ui_do_but_NUM(C, block, but, data, event);
break;
- case NUMSLI:
+ case UI_BTYPE_NUM_SLIDER:
retval = ui_do_but_SLI(C, block, but, data, event);
break;
- case LISTBOX:
+ case UI_BTYPE_LISTBOX:
/* Nothing to do! */
break;
- case LISTROW:
+ case UI_BTYPE_LISTROW:
retval = ui_do_but_LISTROW(C, but, data, event);
break;
- case ROUNDBOX:
- case LABEL:
- case ROW:
- case BUT_IMAGE:
- case PROGRESSBAR:
- case NODESOCKET:
+ case UI_BTYPE_ROUNDBOX:
+ case UI_BTYPE_LABEL:
+ case UI_BTYPE_IMAGE:
+ case UI_BTYPE_PROGRESS_BAR:
+ case UI_BTYPE_NODE_SOCKET:
retval = ui_do_but_EXIT(C, but, data, event);
break;
- case HISTOGRAM:
+ case UI_BTYPE_HISTOGRAM:
retval = ui_do_but_HISTOGRAM(C, block, but, data, event);
break;
- case WAVEFORM:
+ case UI_BTYPE_WAVEFORM:
retval = ui_do_but_WAVEFORM(C, block, but, data, event);
break;
- case VECTORSCOPE:
+ case UI_BTYPE_VECTORSCOPE:
/* Nothing to do! */
break;
- case TEX:
- case SEARCH_MENU:
+ case UI_BTYPE_TEXT:
+ case UI_BTYPE_SEARCH_MENU:
+ if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
+ retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
+ if (retval & WM_UI_HANDLER_BREAK) {
+ break;
+ }
+ }
retval = ui_do_but_TEX(C, block, but, data, event);
break;
- case SEARCH_MENU_UNLINK:
- retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
- break;
- case MENU:
- case BLOCK:
- case PULLDOWN:
+ case UI_BTYPE_MENU:
+ case UI_BTYPE_BLOCK:
+ case UI_BTYPE_PULLDOWN:
retval = ui_do_but_BLOCK(C, but, data, event);
break;
- case BUTM:
+ case UI_BTYPE_BUT_MENU:
retval = ui_do_but_BUT(C, but, data, event);
break;
- case COLOR:
+ case UI_BTYPE_COLOR:
if (but->a1 == -1) /* signal to prevent calling up color picker */
retval = ui_do_but_EXIT(C, but, data, event);
else
retval = ui_do_but_COLOR(C, but, data, event);
break;
- case BUT_NORMAL:
- retval = ui_do_but_NORMAL(C, block, but, data, event);
+ case UI_BTYPE_UNITVEC:
+ retval = ui_do_but_UNITVEC(C, block, but, data, event);
break;
- case BUT_COLORBAND:
+ case UI_BTYPE_COLORBAND:
retval = ui_do_but_COLORBAND(C, block, but, data, event);
break;
- case BUT_CURVE:
+ case UI_BTYPE_CURVE:
retval = ui_do_but_CURVE(C, block, but, data, event);
break;
- case HSVCUBE:
+ case UI_BTYPE_HSVCUBE:
retval = ui_do_but_HSVCUBE(C, block, but, data, event);
break;
- case HSVCIRCLE:
+ case UI_BTYPE_HSVCIRCLE:
retval = ui_do_but_HSVCIRCLE(C, block, but, data, event);
break;
- case LINK:
- case INLINK:
+ case UI_BTYPE_LINK:
+ case UI_BTYPE_INLINK:
retval = ui_do_but_LINK(C, but, data, event);
break;
- case TRACKPREVIEW:
+ case UI_BTYPE_TRACK_PREVIEW:
retval = ui_do_but_TRACKPREVIEW(C, block, but, data, event);
break;
/* quiet warnings for unhandled types */
- case SEPR:
- case SEPRLINE:
- case BUT_EXTRA:
+ case UI_BTYPE_SEPR:
+ case UI_BTYPE_SEPR_LINE:
+ case UI_BTYPE_EXTRA:
break;
}
@@ -6333,7 +7007,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
(event->type == BACKSPACEKEY && event->val == KM_PRESS))
{
/* ctrl+backspace = reset active button; backspace = reset a whole array*/
- ui_set_but_default(C, !event->ctrl, true);
+ ui_but_default_set(C, !event->ctrl, true);
ED_region_tag_redraw(data->region);
retval = WM_UI_HANDLER_BREAK;
}
@@ -6345,7 +7019,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* if we started dragging, progress on any event */
(data->multi_data.init == BUTTON_MULTI_INIT_SETUP))
{
- if (ELEM(but->type, NUM, NUMSLI) &&
+ if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) &&
ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING))
{
/* initialize! */
@@ -6379,8 +7053,13 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* just to be sure, check we're dragging more hoz then virt */
abs(event->prevx - event->x) > abs(event->prevy - event->y)))
{
- ui_multibut_states_create(but, data);
- data->multi_data.init = BUTTON_MULTI_INIT_ENABLE;
+ if (data->multi_data.has_mbuts) {
+ ui_multibut_states_create(but, data);
+ data->multi_data.init = BUTTON_MULTI_INIT_ENABLE;
+ }
+ else {
+ data->multi_data.init = BUTTON_MULTI_INIT_DISABLE;
+ }
}
}
@@ -6431,7 +7110,46 @@ static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but)
return false;
}
-uiBut *ui_but_find_activated(ARegion *ar)
+static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b)
+{
+ return ((but_a->type == but_b->type) &&
+ (but_a->alignnr == but_b->alignnr) &&
+ (but_a->poin == but_b->poin) &&
+ (but_a->rnapoin.type == but_b->rnapoin.type) &&
+ (but_a->rnaprop == but_b->rnaprop));
+}
+
+/**
+ * Finds the pressed button in an aligned row (typically an expanded enum).
+ *
+ * \param direction Use when there may be multiple buttons pressed.
+ */
+uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
+{
+ uiBut *but_iter = but;
+ uiBut *but_found = NULL;
+ BLI_assert(ELEM(direction, -1, 1));
+
+ while ((but_iter->prev) &&
+ ui_but_find_select_in_enum__cmp(but_iter->prev, but))
+ {
+ but_iter = but_iter->prev;
+ }
+
+ while (but_iter && ui_but_find_select_in_enum__cmp(but_iter, but)) {
+ if (but_iter->flag & UI_SELECT) {
+ but_found = but_iter;
+ if (direction == 1) {
+ break;
+ }
+ }
+ but_iter = but_iter->next;
+ }
+
+ return but_found;
+}
+
+uiBut *ui_but_find_active_in_region(ARegion *ar)
{
uiBlock *block;
uiBut *but;
@@ -6444,26 +7162,26 @@ uiBut *ui_but_find_activated(ARegion *ar)
return NULL;
}
-bool ui_button_is_active(ARegion *ar)
+bool ui_but_is_active(ARegion *ar)
{
- return (ui_but_find_activated(ar) != NULL);
+ return (ui_but_find_active_in_region(ar) != NULL);
}
/* is called by notifier */
-void uiFreeActiveButtons(const bContext *C, bScreen *screen)
+void UI_screen_free_active_but(const bContext *C, bScreen *screen)
{
ScrArea *sa = screen->areabase.first;
for (; sa; sa = sa->next) {
ARegion *ar = sa->regionbase.first;
for (; ar; ar = ar->next) {
- uiBut *but = ui_but_find_activated(ar);
+ uiBut *but = ui_but_find_active_in_region(ar);
if (but) {
uiHandleButtonData *data = but->active;
if (data->menu == NULL && data->searchbox == NULL)
if (data->state == BUTTON_STATE_HIGHLIGHT)
- ui_button_active_free(C, but);
+ ui_but_active_free(C, but);
}
}
}
@@ -6476,10 +7194,10 @@ void uiFreeActiveButtons(const bContext *C, bScreen *screen)
bool UI_but_active_drop_name(bContext *C)
{
ARegion *ar = CTX_wm_region(C);
- uiBut *but = ui_but_find_activated(ar);
+ uiBut *but = ui_but_find_active_in_region(ar);
if (but) {
- if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU))
return 1;
}
@@ -6491,9 +7209,9 @@ bool UI_but_active_drop_color(bContext *C)
ARegion *ar = CTX_wm_region(C);
if (ar) {
- uiBut *but = ui_but_find_activated(ar);
+ uiBut *but = ui_but_find_active_in_region(ar);
- if (but && but->type == COLOR)
+ if (but && but->type == UI_BTYPE_COLOR)
return true;
}
@@ -6513,12 +7231,16 @@ static void ui_blocks_set_tooltips(ARegion *ar, const bool enable)
block->tooltipdisabled = !enable;
}
-static bool ui_mouse_inside_region(ARegion *ar, int x, int y)
+static bool ui_region_contains_point_px(ARegion *ar, int x, int y)
{
- uiBlock *block;
-
+ uiBlock *block = ar->uiblocks.first;
+ rcti winrct;
+
+ /* scale down area rect to exclude shadow */
+ ui_region_winrct_get_no_margin(ar, &winrct);
+
/* check if the mouse is in the region */
- if (!BLI_rcti_isect_pt(&ar->winrct, x, y)) {
+ if (!BLI_rcti_isect_pt(&winrct, x, y)) {
for (block = ar->uiblocks.first; block; block = block->next)
block->auto_open = false;
@@ -6547,11 +7269,11 @@ static bool ui_mouse_inside_region(ARegion *ar, int x, int y)
return true;
}
-static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
+static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y)
{
uiBlock *block = but->block;
float mx, my;
- if (!ui_mouse_inside_region(ar, x, y))
+ if (!ui_region_contains_point_px(ar, x, y))
return false;
mx = x;
@@ -6559,7 +7281,7 @@ static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
ui_window_to_block_fl(ar, block, &mx, &my);
- if (but->dt == UI_EMBOSSR) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
if (!ui_but_isect_pie_seg(block, but)) {
return false;
}
@@ -6573,34 +7295,27 @@ static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
/**
* Can we mouse over the button or is it hidden/disabled/layout.
- * Note: ctrl is kind of a hack currently, so that non-embossed TEX button behaves as a label when ctrl is not pressed.
+ * Note: ctrl is kind of a hack currently, so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
*/
-static bool ui_is_but_interactive(const uiBut *but, const bool labeledit)
+static bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
- /* note, LABEL is included for highlights, this allows drags */
- if ((but->type == LABEL) && but->dragpoin == NULL)
+ /* note, UI_BTYPE_LABEL is included for highlights, this allows drags */
+ if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == NULL)
return false;
- if (ELEM(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
+ if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX))
return false;
if (but->flag & UI_HIDDEN)
return false;
if (but->flag & UI_SCROLLED)
return false;
- if ((but->type == TEX) && (but->dt == UI_EMBOSSN) && !labeledit)
+ if ((but->type == UI_BTYPE_TEXT) && (but->dt == UI_EMBOSS_NONE) && !labeledit)
return false;
- if ((but->type == LISTROW) && labeledit)
+ if ((but->type == UI_BTYPE_LISTROW) && labeledit)
return false;
return true;
}
-bool ui_is_but_search_unlink_visible(const uiBut *but)
-{
- BLI_assert(but->type == SEARCH_MENU_UNLINK);
- return ((but->editstr == NULL) &&
- (but->drawstr[0] != '\0'));
-}
-
/* x and y are only used in case event is NULL... */
static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit)
{
@@ -6610,7 +7325,7 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
// if (!win->active)
// return NULL;
- if (!ui_mouse_inside_region(ar, x, y))
+ if (!ui_region_contains_point_px(ar, x, y))
return NULL;
for (block = ar->uiblocks.first; block; block = block->next) {
@@ -6619,7 +7334,7 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
ui_window_to_block_fl(ar, block, &mx, &my);
for (but = block->buttons.last; but; but = but->prev) {
- if (ui_is_but_interactive(but, labeledit)) {
+ if (ui_but_is_interactive(but, labeledit)) {
if (but->pie_dir != UI_RADIAL_NONE) {
if (ui_but_isect_pie_seg(block, but)) {
butover = but;
@@ -6651,13 +7366,13 @@ static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event)
}
-static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
+static uiBut *ui_list_find_mouse_over_ex(ARegion *ar, int x, int y)
{
uiBlock *block;
uiBut *but;
float mx, my;
- if (!ui_mouse_inside_region(ar, x, y))
+ if (!ui_region_contains_point_px(ar, x, y))
return NULL;
for (block = ar->uiblocks.first; block; block = block->next) {
@@ -6666,7 +7381,7 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
ui_window_to_block_fl(ar, block, &mx, &my);
for (but = block->buttons.last; but; but = but->prev) {
- if (but->type == LISTBOX && ui_but_contains_pt(but, mx, my)) {
+ if (but->type == UI_BTYPE_LISTBOX && ui_but_contains_pt(but, mx, my)) {
return but;
}
}
@@ -6675,6 +7390,11 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
return NULL;
}
+static uiBut *ui_list_find_mouse_over(ARegion *ar, const wmEvent *event)
+{
+ return ui_list_find_mouse_over_ex(ar, event->x, event->y);
+}
+
/* ****************** button state handling **************************/
static bool button_modal_state(uiHandleButtonState state)
@@ -6688,7 +7408,8 @@ static bool button_modal_state(uiHandleButtonState state)
BUTTON_STATE_MENU_OPEN);
}
-static void button_timers_tooltip_remove(bContext *C, uiBut *but)
+/* removes tooltip timer from active but (meaning tooltip is disabled until it's reenabled again) */
+void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
uiHandleButtonData *data;
@@ -6747,14 +7468,14 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
button_tooltip_timer_reset(C, but);
/* automatic open pulldown block timer */
- if (ELEM(but->type, BLOCK, PULLDOWN)) {
+ if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN)) {
if (data->used_mouse && !data->autoopentimer) {
int time;
if (but->block->auto_open == true) { /* test for toolbox */
time = 1;
}
- else if ((but->block->flag & UI_BLOCK_LOOP && but->type != BLOCK) || but->block->auto_open == true) {
+ else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || but->block->auto_open == true) {
time = 5 * U.menuthreshold2;
}
else if (U.uiflag & USER_MENUOPENAUTO) {
@@ -6772,7 +7493,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
}
else {
but->flag |= UI_SELECT;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
}
/* text editing */
@@ -6785,7 +7506,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
/* number editing */
if (state == BUTTON_STATE_NUM_EDITING) {
- if (ui_is_a_warp_but(but))
+ if (ui_but_is_cursor_warp(but))
WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
ui_numedit_begin(but, data);
}
@@ -6795,7 +7516,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (but->flag & UI_BUT_DRIVEN)
WM_report(C, RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup.");
- if (ui_is_a_warp_but(but)) {
+ if (ui_but_is_cursor_warp(but)) {
#ifdef USE_CONT_MOUSE_CORRECT
if (data->ungrab_mval[0] != FLT_MAX) {
@@ -6816,9 +7537,9 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
}
/* menu open */
if (state == BUTTON_STATE_MENU_OPEN)
- ui_blockopen_begin(C, but, data);
+ ui_block_open_begin(C, but, data);
else if (data->state == BUTTON_STATE_MENU_OPEN)
- ui_blockopen_end(C, but, data);
+ ui_block_open_end(C, but, data);
/* add a short delay before exiting, to ensure there is some feedback */
if (state == BUTTON_STATE_WAIT_FLASH) {
@@ -6834,7 +7555,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (!(but->block->handle && but->block->handle->popup)) {
if (button_modal_state(state)) {
if (!button_modal_state(data->state))
- WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false);
+ WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, 0);
}
else {
if (button_modal_state(data->state)) {
@@ -6852,13 +7573,13 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
data->state = state;
if (state != BUTTON_STATE_EXIT) {
- /* When objects for eg. are removed, running ui_check_but() can access
+ /* When objects for eg. are removed, running ui_but_update() can access
* the removed data - so disable update on exit. Also in case of
* highlight when not in a popup menu, we remove because data used in
* button below popup might have been removed by action of popup. Needs
* a more reliable solution... */
if (state != BUTTON_STATE_HIGHLIGHT || (but->block->flag & UI_BLOCK_LOOP))
- ui_check_but(but);
+ ui_but_update(but);
}
/* redraw */
@@ -6879,7 +7600,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU)) {
/* XXX curve is temp */
}
else {
@@ -6906,7 +7627,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
/* activate right away */
if (but->flag & UI_BUT_IMMEDIATE) {
- if (but->type == HOTKEYEVT)
+ if (but->type == UI_BTYPE_HOTKEY_EVENT)
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
/* .. more to be added here */
}
@@ -6933,19 +7654,20 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
else if (type == BUTTON_ACTIVATE_APPLY)
button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH);
- if (but->type == GRIP) {
+ if (but->type == UI_BTYPE_GRIP) {
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
}
}
-static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data,
- const bool mousemove, const bool onfree)
+static void button_activate_exit(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ const bool mousemove, const bool onfree)
{
uiBlock *block = but->block;
uiBut *bt;
- if (but->type == GRIP) {
+ if (but->type == UI_BTYPE_GRIP) {
WM_cursor_modal_restore(data->window);
}
@@ -6955,7 +7677,7 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
/* apply the button action or value */
if (!onfree)
- ui_apply_button(C, block, but, data, false);
+ ui_apply_but(C, block, but, data, false);
#ifdef USE_DRAG_MULTINUM
if (data->multi_data.has_mbuts) {
@@ -6964,7 +7686,7 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
bt->flag &= ~UI_BUT_DRAG_MULTI;
if (!data->cancel) {
- ui_apply_autokey(C, bt);
+ ui_apply_but_autokey(C, bt);
}
}
}
@@ -6988,8 +7710,8 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
if (!onfree && !data->cancel) {
/* autokey & undo push */
- ui_apply_undo(but);
- ui_apply_autokey(C, but);
+ ui_apply_but_undo(but);
+ ui_apply_but_autokey(C, but);
/* popup menu memory */
if (block->flag & UI_BLOCK_POPUP_MEMORY)
@@ -7012,6 +7734,10 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
if (data->origstr)
MEM_freeN(data->origstr);
+#ifdef USE_ALLSELECT
+ ui_selectcontext_end(but, &data->select_others);
+#endif
+
/* redraw (data is but->active!) */
ED_region_tag_redraw(data->region);
@@ -7024,7 +7750,7 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
but->flag &= ~(UI_ACTIVE | UI_SELECT);
but->flag |= UI_BUT_LAST_ACTIVE;
if (!onfree)
- ui_check_but(but);
+ ui_but_update(but);
/* adds empty mousemove in queue for re-init handler, in case mouse is
* still over a button. we cannot just check for this ourselfs because
@@ -7033,7 +7759,7 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
WM_event_add_mousemove(C);
}
-void ui_button_active_free(const bContext *C, uiBut *but)
+void ui_but_active_free(const bContext *C, uiBut *but)
{
uiHandleButtonData *data;
@@ -7099,13 +7825,13 @@ static uiBut *ui_context_rna_button_active(const bContext *C)
return ui_context_button_active(C, ui_context_rna_button_active_test);
}
-uiBut *uiContextActiveButton(const struct bContext *C)
+uiBut *UI_context_active_but_get(const struct bContext *C)
{
return ui_context_button_active(C, NULL);
}
/* helper function for insert keyframe, reset to default, etc operators */
-void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
{
uiBut *activebut = ui_context_rna_button_active(C);
@@ -7122,7 +7848,7 @@ void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct P
}
}
-void uiContextActivePropertyHandle(bContext *C)
+void UI_context_active_but_prop_handle(bContext *C)
{
uiBut *activebut = ui_context_rna_button_active(C);
if (activebut) {
@@ -7136,7 +7862,7 @@ void uiContextActivePropertyHandle(bContext *C)
}
}
-wmOperator *uiContextActiveOperator(const struct bContext *C)
+wmOperator *UI_context_active_operator_get(const struct bContext *C)
{
ARegion *ar_ctx = CTX_wm_region(C);
uiBlock *block;
@@ -7174,7 +7900,7 @@ wmOperator *uiContextActiveOperator(const struct bContext *C)
}
/* helper function for insert keyframe, reset to default, etc operators */
-void uiContextAnimUpdate(const bContext *C)
+void UI_context_update_anim_flag(const bContext *C)
{
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
@@ -7218,7 +7944,7 @@ void uiContextAnimUpdate(const bContext *C)
/************** handle activating a button *************/
-static uiBut *uit_but_find_open_event(ARegion *ar, const wmEvent *event)
+static uiBut *ui_but_find_open_event(ARegion *ar, const wmEvent *event)
{
uiBlock *block;
uiBut *but;
@@ -7249,7 +7975,7 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
}
}
else if (event->type == EVT_BUT_OPEN) {
- but = uit_but_find_open_event(ar, event);
+ but = ui_but_find_open_event(ar, event);
if (but) {
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
ui_do_button(C, but->block, but, event);
@@ -7259,8 +7985,8 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
return WM_UI_HANDLER_CONTINUE;
}
-/* exported to interface.c: uiButActiveOnly() */
-void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but)
+/* exported to interface.c: UI_but_active_only() */
+void ui_but_activate_event(bContext *C, ARegion *ar, uiBut *but)
{
wmWindow *win = CTX_wm_window(C);
wmEvent event;
@@ -7282,12 +8008,12 @@ void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but)
* exported so menus can start with a highlighted button,
* even if the mouse isnt over it
*/
-void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but)
+void ui_but_activate_over(bContext *C, ARegion *ar, uiBut *but)
{
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
}
-void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back)
+void ui_but_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back)
{
/* note: ideally we would not have to change 'but->active' however
* some functions we call don't use data (as they should be doing) */
@@ -7298,12 +8024,12 @@ void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiB
data->region = ar;
}
-void ui_button_execute_end(struct bContext *C, struct ARegion *UNUSED(ar), uiBut *but, void *active_back)
+void ui_but_execute_end(struct bContext *C, struct ARegion *UNUSED(ar), uiBut *but, void *active_back)
{
- ui_apply_button(C, but->block, but, but->active, true);
+ ui_apply_but(C, but->block, but, but->active, true);
if ((but->flag & UI_BUT_DRAG_MULTI) == 0) {
- ui_apply_autokey(C, but);
+ ui_apply_but_autokey(C, but);
}
/* use onfree event so undo is handled by caller and apply is already done above */
button_activate_exit((bContext *)C, but, but->active, false, true);
@@ -7315,7 +8041,7 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu
uiBut *oldbut;
uiHandleButtonData *data;
- oldbut = ui_but_find_activated(ar);
+ oldbut = ui_but_find_active_in_region(ar);
if (oldbut) {
data = oldbut->active;
data->cancel = true;
@@ -7353,8 +8079,9 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
uiBut *but_other = ui_but_find_mouse_over(ar, event);
bool exit = false;
- if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(but->block)) &&
- !ui_mouse_inside_button(ar, but, event->x, event->y))
+ /* always deactivate button for pie menus, else moving to blank space will leave activated */
+ if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(block)) &&
+ !ui_but_contains_point_px(ar, but, event->x, event->y))
{
exit = true;
}
@@ -7389,19 +8116,19 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
data->autoopentimer = NULL;
- if (ui_mouse_inside_button(ar, but, event->x, event->y))
+ if (ui_but_contains_point_px(ar, but, event->x, event->y))
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
}
retval = WM_UI_HANDLER_CONTINUE;
break;
}
- /* XXX hardcoded keymap check... but anyway, while view changes, tooltips should be removed */
+ /* XXX hardcoded keymap check... but anyway, while view changes, tooltips should be removed */
case WHEELUPMOUSE:
case WHEELDOWNMOUSE:
case MIDDLEMOUSE:
case MOUSEPAN:
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
/* fall-through */
default:
/* handle button type specific events */
@@ -7417,7 +8144,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
break;
case MOUSEMOVE:
- if (ELEM(but->type, LINK, INLINK)) {
+ if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) {
ARegion *ar = data->region;
but->flag |= UI_SELECT;
ui_do_button(C, block, but, event);
@@ -7426,7 +8153,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
else {
/* deselect the button when moving the mouse away */
/* also de-activate for buttons that only show higlights */
- if (ui_mouse_inside_button(ar, but, event->x, event->y)) {
+ if (ui_but_contains_point_px(ar, but, event->x, event->y)) {
if (!(but->flag & UI_SELECT)) {
but->flag |= (UI_SELECT | UI_ACTIVE);
data->cancel = false;
@@ -7471,7 +8198,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
uiBut *bt;
if (data->menu && data->menu->region) {
- if (ui_mouse_inside_region(data->menu->region, event->x, event->y)) {
+ if (ui_region_contains_point_px(data->menu->region, event->x, event->y)) {
break;
}
}
@@ -7479,7 +8206,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
bt = ui_but_find_mouse_over(ar, event);
if (bt && bt->active != data) {
- if (but->type != COLOR) { /* exception */
+ if (but->type != UI_BTYPE_COLOR) { /* exception */
data->cancel = true;
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -7526,21 +8253,15 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
return retval;
}
-static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
+static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, uiBut *listbox)
{
- uiBut *but;
uiList *ui_list;
uiListDyn *dyn_data;
int retval = WM_UI_HANDLER_CONTINUE;
int type = event->type, val = event->val;
int mx, my;
- but = ui_list_find_mouse_over(ar, event->x, event->y);
- if (!but) {
- return retval;
- }
-
- ui_list = but->custom_data;
+ ui_list = listbox->custom_data;
if (!ui_list || !ui_list->dyn_data) {
return retval;
}
@@ -7548,7 +8269,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
mx = event->x;
my = event->y;
- ui_window_to_block(ar, but->block, &mx, &my);
+ ui_window_to_block(ar, listbox->block, &mx, &my);
/* convert pan to scrollwheel */
if (type == MOUSEPAN) {
@@ -7562,9 +8283,9 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
if (val == KM_PRESS) {
if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
- ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
+ ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl)))
{
- const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop);
+ const int value_orig = RNA_property_int_get(&listbox->rnapoin, listbox->rnaprop);
int value, min, max, inc;
/* activate up/down the list */
@@ -7617,14 +8338,14 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
CLAMP(value, 0, dyn_data->items_len - 1);
- RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
+ RNA_property_int_range(&listbox->rnapoin, listbox->rnaprop, &min, &max);
CLAMP(value, min, max);
if (value != value_orig) {
- RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
- RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, value);
+ RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop);
- ui_apply_undo(but);
+ ui_apply_but_undo(listbox);
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
ED_region_tag_redraw(ar);
@@ -7668,18 +8389,18 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
/* copy over return values from the closing menu */
if ((menu->menuretval & UI_RETURN_OK) || (menu->menuretval & UI_RETURN_UPDATE)) {
- if (but->type == COLOR)
+ if (but->type == UI_BTYPE_COLOR)
copy_v3_v3(data->vec, menu->retvec);
- else if (but->type == MENU)
+ else if (but->type == UI_BTYPE_MENU)
data->value = menu->retvalue;
}
if (menu->menuretval & UI_RETURN_UPDATE) {
if (data->interactive) {
- ui_apply_button(C, but->block, but, data, true);
+ ui_apply_but(C, but->block, but, data, true);
}
else {
- ui_check_but(but);
+ ui_but_update(but);
}
menu->menuretval = 0;
@@ -7693,7 +8414,7 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
button_activate_exit(C, but, data, true, false);
}
else if (menu->menuretval & UI_RETURN_OUT) {
- if (event->type == MOUSEMOVE && ui_mouse_inside_button(data->region, but, event->x, event->y)) {
+ if (event->type == MOUSEMOVE && ui_but_contains_point_px(data->region, but, event->x, event->y)) {
button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
}
else {
@@ -7712,13 +8433,14 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
/* ************************* menu handling *******************************/
-/* function used to prevent loosing the open menu when using nested pulldowns,
+/**
+ * Function used to prevent loosing the open menu when using nested pulldowns,
* when moving mouse towards the pulldown menu over other buttons that could
* steal the highlight from the current button, only checks:
*
* - while mouse moves in triangular area defined old mouse position and
- * left/right side of new menu
- * - only for 1 second
+ * left/right side of new menu.
+ * - only for 1 second.
*/
static void ui_mouse_motion_towards_init_ex(uiPopupBlockHandle *menu, const int xy[2], const bool force)
@@ -7747,8 +8469,9 @@ static void ui_mouse_motion_towards_reinit(uiPopupBlockHandle *menu, const int x
ui_mouse_motion_towards_init_ex(menu, xy, true);
}
-static bool ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *menu, const int xy[2],
- const bool use_wiggle_room)
+static bool ui_mouse_motion_towards_check(
+ uiBlock *block, uiPopupBlockHandle *menu, const int xy[2],
+ const bool use_wiggle_room)
{
float p1[2], p2[2], p3[2], p4[2];
float oldp[2] = {menu->towards_xy[0], menu->towards_xy[1]};
@@ -7936,8 +8659,9 @@ static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my, uiBut *to_bt)
*
* Without this keyboard navigation from menu's wont work.
*/
-static bool ui_menu_pass_event_to_parent_if_nonactive(uiPopupBlockHandle *menu, const uiBut *but,
- const int level, const int retval)
+static bool ui_menu_pass_event_to_parent_if_nonactive(
+ uiPopupBlockHandle *menu, const uiBut *but,
+ const int level, const int retval)
{
if ((level != 0) && (but == NULL)) {
menu->menuretval = UI_RETURN_OUT | UI_RETURN_OUT_PARENT;
@@ -7953,7 +8677,7 @@ static bool ui_menu_pass_event_to_parent_if_nonactive(uiPopupBlockHandle *menu,
static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu)
{
ARegion *ar = menu->region;
- uiBut *but = ui_but_find_activated(ar);
+ uiBut *but = ui_but_find_active_in_region(ar);
int retval;
if (but) {
@@ -7965,11 +8689,11 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
/* pass, skip for dialogs */
}
- else if (!ui_mouse_inside_region(but->active->region, event->x, event->y)) {
+ else if (!ui_region_contains_point_px(but->active->region, event->x, event->y)) {
/* pass, needed to click-exit outside of non-flaoting menus */
}
else if ((!ELEM(event->type, MOUSEMOVE, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN)) && ISMOUSE(event->type)) {
- if (!ui_mouse_inside_button(but->active->region, but, event->x, event->y)) {
+ if (!ui_but_contains_point_px(but->active->region, but, event->x, event->y)) {
but = NULL;
}
}
@@ -7994,7 +8718,7 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
return retval;
}
-void ui_block_calculate_pie_segment(uiBlock *block, const float event_xy[2])
+float ui_block_calc_pie_segment(uiBlock *block, const float event_xy[2])
{
float seg1[2];
float seg2[2];
@@ -8011,11 +8735,12 @@ void ui_block_calculate_pie_segment(uiBlock *block, const float event_xy[2])
len = normalize_v2_v2(block->pie_data.pie_dir, seg2);
- /* ten pixels for now, a bit arbitrary */
if (len < U.pie_menu_threshold * U.pixelsize)
block->pie_data.flags |= UI_PIE_INVALID_DIR;
else
block->pie_data.flags &= ~UI_PIE_INVALID_DIR;
+
+ return len;
}
static int ui_handle_menu_event(
@@ -8024,7 +8749,7 @@ static int ui_handle_menu_event(
{
ARegion *ar;
uiBlock *block;
- uiBut *but, *bt;
+ uiBut *but;
int mx, my, retval;
bool inside;
bool inside_title; /* check for title dragging */
@@ -8043,7 +8768,7 @@ static int ui_handle_menu_event(
inside_title = inside && ((my + (UI_UNIT_Y * 1.5f)) > block->rect.ymax);
/* if there's an active modal button, don't check events or outside, except for search menu */
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
#ifdef USE_DRAG_POPUP
if (menu->is_grab) {
@@ -8119,15 +8844,15 @@ static int ui_handle_menu_event(
if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval))
break;
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
if (!but) {
/* no item active, we make first active */
- if (block->direction & UI_TOP) but = ui_but_last(block);
+ if (block->direction & UI_DIR_UP) but = ui_but_last(block);
else but = ui_but_first(block);
}
- if (but && ELEM(but->type, BLOCK, PULLDOWN))
+ if (but && ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN))
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_OPEN);
}
@@ -8140,7 +8865,7 @@ static int ui_handle_menu_event(
case WHEELDOWNMOUSE:
case MOUSEPAN:
/* arrowkeys: only handle for block_loop blocks */
- if (event->alt || event->shift || event->ctrl || event->oskey) {
+ if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
}
else if (inside || (block->flag & UI_BLOCK_LOOP)) {
@@ -8152,7 +8877,9 @@ static int ui_handle_menu_event(
ui_pan_to_scroll(event, &type, &val);
if (val == KM_PRESS) {
- const eButType type_flip = BUT | ROW;
+ const bool is_next =
+ (ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE) ==
+ ((block->flag & UI_BLOCK_IS_FLIP) != 0));
if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval))
break;
@@ -8161,58 +8888,24 @@ static int ui_handle_menu_event(
ui_mouse_motion_keynav_init(&menu->keynav_state, event);
#endif
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
if (but) {
- /* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */
- if (((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) ||
- ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) ||
- ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP)))
- {
- /* the following is just a hack - uiBut->type set to BUT and BUTM have there menus built
- * opposite ways - this should be changed so that all popup-menus use the same uiBlock->direction */
- if (but->type & type_flip)
- but = ui_but_next(but);
- else
- but = ui_but_prev(but);
- }
- else {
- if (but->type & type_flip)
- but = ui_but_prev(but);
- else
- but = ui_but_next(but);
- }
-
- if (but) {
- ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
- ui_menu_scroll(ar, block, my, but);
- }
+ /* next button */
+ but = is_next ? ui_but_next(but) : ui_but_prev(but);
}
if (!but) {
- if (((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) ||
- ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) ||
- ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP)))
- {
- if ((bt = ui_but_first(block)) && (bt->type & type_flip)) {
- bt = ui_but_last(block);
- }
- else {
- /* keep ui_but_first() */
- }
- }
- else {
- if ((bt = ui_but_first(block)) && (bt->type & type_flip)) {
- /* keep ui_but_first() */
- }
- else {
- bt = ui_but_last(block);
- }
+ /* wrap button */
+ uiBut *but_wrap;
+ but_wrap = is_next ? ui_but_first(block) : ui_but_last(block);
+ if (but_wrap) {
+ but = but_wrap;
}
+ }
- if (bt) {
- ui_handle_button_activate(C, ar, bt, BUTTON_ACTIVATE);
- ui_menu_scroll(ar, block, my, bt);
- }
+ if (but) {
+ ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
+ ui_menu_scroll(ar, block, my, but);
}
}
@@ -8254,7 +8947,7 @@ static int ui_handle_menu_event(
for (but = block->buttons.first; but; but = but->next) {
bool doit = false;
- if (!ELEM(but->type, LABEL, SEPR, SEPRLINE))
+ if (!ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE))
count++;
/* exception for rna layer buts */
@@ -8272,7 +8965,7 @@ static int ui_handle_menu_event(
if (doit) {
/* activate buttons but open menu's */
uiButtonActivateType activate;
- if (but->type == PULLDOWN) {
+ if (but->type == UI_BTYPE_PULLDOWN) {
activate = BUTTON_ACTIVATE_OPEN;
}
else {
@@ -8317,9 +9010,7 @@ static int ui_handle_menu_event(
case ZKEY:
{
if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
- (event->shift == 0) &&
- (event->ctrl == 0) &&
- (event->oskey == 0))
+ !IS_EVENT_MOD(event, shift, ctrl, oskey))
{
if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval))
break;
@@ -8327,20 +9018,20 @@ static int ui_handle_menu_event(
for (but = block->buttons.first; but; but = but->next) {
if (but->menu_key == event->type) {
- if (ELEM(but->type, BUT, BUTM)) {
+ if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_BUT_MENU)) {
/* mainly for operator buttons */
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_APPLY);
}
- else if (ELEM(but->type, BLOCK, PULLDOWN)) {
+ else if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN)) {
/* open submenus (like right arrow key) */
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_OPEN);
}
- else if (but->type == MENU) {
+ else if (but->type == UI_BTYPE_MENU) {
/* activate menu items */
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
}
else {
- printf("%s: error, but->menu_key type: %d\n", __func__, but->type);
+ printf("%s: error, but->menu_key type: %u\n", __func__, but->type);
}
break;
@@ -8400,16 +9091,16 @@ static int ui_handle_menu_event(
else if (ELEM(event->type, RETKEY, PADENTER) && event->val == KM_PRESS) {
/* enter will always close this block, we let the event
* get handled by the button if it is activated, otherwise we cancel */
- if (!ui_but_find_activated(ar))
+ if (!ui_but_find_active_in_region(ar))
menu->menuretval = UI_RETURN_CANCEL | UI_RETURN_POPUP_OK;
}
#ifdef USE_DRAG_POPUP
else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) &&
(inside && is_floating && inside_title))
{
- if (!but || !ui_mouse_inside_button(ar, but, event->x, event->y)) {
+ if (!but || !ui_but_contains_point_px(ar, but, event->x, event->y)) {
if (but) {
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
}
menu->is_grab = true;
@@ -8487,7 +9178,10 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
ar = menu->region;
block = ar->uiblocks.first;
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
+
+ BLI_assert(but);
+
data = but->active;
submenu = data->menu;
@@ -8520,14 +9214,6 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
}
if (menu->menuretval) {
- /* pie menus should not close but wait for release instead */
- if ((block->flag & UI_BLOCK_RADIAL) &&
- !(block->pie_data.flags & UI_PIE_CLICK_STYLE))
- {
- menu->menuretval = 0;
- block->pie_data.flags |= UI_PIE_FINISHED;
- }
-
return WM_UI_HANDLER_CONTINUE;
}
else {
@@ -8537,18 +9223,18 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
static bool ui_but_pie_menu_supported_apply(uiBut *but)
{
- return (but->type != NUMSLI);
+ return (!ELEM(but->type, UI_BTYPE_NUM_SLIDER, UI_BTYPE_NUM));
}
-static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *but, bool force_close, bool click_style)
+static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *but, bool force_close)
{
int retval = WM_UI_HANDLER_BREAK;
if (but && ui_but_pie_menu_supported_apply(but)) {
- if (but->type == MENU) {
+ if (but->type == UI_BTYPE_MENU) {
/* forcing the pie menu to close will not handle menus */
if (!force_close) {
- uiBut *active_but = ui_but_find_activated(menu->region);
+ uiBut *active_but = ui_but_find_active_in_region(menu->region);
if (active_but) {
button_activate_exit(C, active_but, active_but->active, false, false);
@@ -8562,27 +9248,14 @@ static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *b
}
}
else {
- ui_apply_button(C, but->block, but, but->active, false);
+ ui_apply_but(C, but->block, but, but->active, false);
button_activate_exit((bContext *)C, but, but->active, false, true);
- if (!(click_style || force_close)) {
- but->block->pie_data.flags |= UI_PIE_FINISHED;
- menu->menuretval = 0;
- }
- else {
- menu->menuretval = UI_RETURN_OK;
- }
+ menu->menuretval = UI_RETURN_OK;
}
}
else {
- uiBlock *block = menu->region->uiblocks.first;
-
- if (!(click_style || force_close)) {
- block->pie_data.flags |= UI_PIE_FINISHED;
- }
- else {
- menu->menuretval = UI_RETURN_CANCEL;
- }
+ menu->menuretval = UI_RETURN_CANCEL;
ED_region_tag_redraw(menu->region);
}
@@ -8596,7 +9269,7 @@ static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, Ra
if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) {
for (but = block->buttons.first; but; but = but->next) {
- if (but->pie_dir == dir && !ELEM(but->type, SEPR, SEPRLINE)) {
+ if (but->pie_dir == dir && !ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
return but;
}
}
@@ -8605,23 +9278,23 @@ static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, Ra
return NULL;
}
-static int ui_but_pie_button_activate(bContext *C, uiBut *but, uiPopupBlockHandle *menu, bool is_click_style)
+static int ui_but_pie_button_activate(bContext *C, uiBut *but, uiPopupBlockHandle *menu)
{
uiBut *active_but;
if (but == NULL)
return WM_UI_HANDLER_BREAK;
- active_but = ui_but_find_activated(menu->region);
+ active_but = ui_but_find_active_in_region(menu->region);
if (active_but)
button_activate_exit(C, active_but, active_but->active, false, false);
button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OVER);
- return ui_but_pie_menu_apply(C, menu, but, false, is_click_style);
+ return ui_but_pie_menu_apply(C, menu, but, false);
}
-static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu)
+static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu)
{
ARegion *ar;
uiBlock *block;
@@ -8629,6 +9302,7 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
float event_xy[2];
double duration;
bool is_click_style;
+ float dist;
/* we block all events, this is modal interaction, except for drop events which is described below */
int retval = WM_UI_HANDLER_BREAK;
@@ -8652,6 +9326,13 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
duration = menu->scrolltimer->duration;
+ event_xy[0] = event->x;
+ event_xy[1] = event->y;
+
+ ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]);
+
+ dist = ui_block_calc_pie_segment(block, event_xy);
+
if (event->type == TIMER) {
if (event->customdata == menu->scrolltimer) {
/* deactivate initial direction after a while */
@@ -8686,7 +9367,7 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
mul_v2_fl(vec, pie_radius);
add_v2_v2(vec, center);
- mul_v2_fl(vec, fac);
+ mul_v2_fl(vec, fac);
add_v2_v2(vec, block->pie_data.pie_center_spawned);
BLI_rctf_recenter(&but->rect, vec[0], vec[1]);
@@ -8697,27 +9378,29 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
ED_region_tag_redraw(ar);
}
}
- }
- event_xy[0] = event->x;
- event_xy[1] = event->y;
+ /* check pie velociy here if gesture has ended */
+ if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) {
+ float len_sq = 10;
- ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]);
+ /* use a time threshold to ensure we leave time to the mouse to move */
+ if (duration - block->pie_data.duration_gesture > 0.02) {
+ len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos);
+ copy_v2_v2(block->pie_data.last_pos, event_xy);
+ block->pie_data.duration_gesture = duration;
+ }
- ui_block_calculate_pie_segment(block, event_xy);
+ if (len_sq < 1.0f) {
+ uiBut *but = ui_but_find_active_in_region(menu->region);
- if (block->pie_data.flags & UI_PIE_FINISHED) {
- if ((event->type == block->pie_data.event && event->val == KM_RELEASE) ||
- ((event->type == RIGHTMOUSE || event->type == ESCKEY) && (event->val == KM_PRESS)))
- {
- menu->menuretval = UI_RETURN_OK;
+ if (but) {
+ return ui_but_pie_menu_apply(C, menu, but, true);
+ }
+ }
}
-
- ED_region_tag_redraw(ar);
- return WM_UI_HANDLER_BREAK;
}
- if (event->type == block->pie_data.event) {
+ if (event->type == block->pie_data.event && !is_click_style) {
if (event->val != KM_RELEASE) {
ui_handle_menu_button(C, event, menu);
@@ -8733,10 +9416,18 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) {
block->pie_data.flags |= UI_PIE_CLICK_STYLE;
}
- else if (!is_click_style) {
- uiBut *but = ui_but_find_activated(menu->region);
+ else {
+ uiBut *but = ui_but_find_active_in_region(menu->region);
+
+ if (but && (U.pie_menu_confirm > 0) &&
+ (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ {
+ if (but)
+ return ui_but_pie_menu_apply(C, menu, but, true);
+ }
+
+ retval = ui_but_pie_menu_apply(C, menu, but, true);
- retval = ui_but_pie_menu_apply(C, menu, but, true, is_click_style);
}
}
}
@@ -8746,9 +9437,24 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
switch (event->type) {
case MOUSEMOVE:
- if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) {
- block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ if (!is_click_style) {
+ float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init);
+
+ /* here we use the initial position explicitly */
+ if (len_sq > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
+
+ /* here instead, we use the offset location to account for the initial direction timeout */
+ if ((U.pie_menu_confirm > 0) &&
+ (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ {
+ block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT;
+ copy_v2_v2(block->pie_data.last_pos, event_xy);
+ block->pie_data.duration_gesture = duration;
+ }
}
+
ui_handle_menu_button(C, event, menu);
/* mouse move should always refresh the area for pie menus */
@@ -8756,21 +9462,19 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
break;
case LEFTMOUSE:
- if (event->val == KM_PRESS) {
- uiBut *but = ui_but_find_activated(menu->region);
- retval = ui_but_pie_menu_apply(C, menu, but, false, is_click_style);
+ if (is_click_style) {
+ if (block->pie_data.flags & UI_PIE_INVALID_DIR) {
+ menu->menuretval = UI_RETURN_CANCEL;
+ }
+ else {
+ retval = ui_handle_menu_button(C, event, menu);
+ }
}
break;
case ESCKEY:
case RIGHTMOUSE:
- if (!is_click_style) {
- block->pie_data.flags |= UI_PIE_FINISHED;
- menu->menuretval = 0;
- ED_region_tag_redraw(ar);
- }
- else
- menu->menuretval = UI_RETURN_CANCEL;
+ menu->menuretval = UI_RETURN_CANCEL;
break;
case AKEY:
@@ -8801,13 +9505,11 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
case ZKEY:
{
if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
- (event->shift == 0) &&
- (event->ctrl == 0) &&
- (event->oskey == 0))
+ !IS_EVENT_MOD(event, shift, ctrl, oskey))
{
for (but = block->buttons.first; but; but = but->next) {
if (but->menu_key == event->type) {
- ui_but_pie_button_activate(C, but, menu, is_click_style);
+ ui_but_pie_button_activate(C, but, menu);
}
}
}
@@ -8828,7 +9530,7 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle
CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
{
but = ui_block_pie_dir_activate(block, event, num_dir);
- retval = ui_but_pie_button_activate(C, but, menu, is_click_style);
+ retval = ui_but_pie_button_activate(C, but, menu);
break;
}
#undef CASE_NUM_TO_DIR
@@ -8852,7 +9554,7 @@ static int ui_handle_menus_recursive(
bool do_towards_reinit = false;
/* check if we have a submenu, and handle events for it first */
- but = ui_but_find_activated(menu->region);
+ but = ui_but_find_active_in_region(menu->region);
data = (but) ? but->active : NULL;
submenu = (data) ? data->menu : NULL;
@@ -8879,7 +9581,7 @@ static int ui_handle_menus_recursive(
/* now handle events for our own menu */
if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
- const bool do_but_search = (but && ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK));
+ const bool do_but_search = (but && (but->type == UI_BTYPE_SEARCH_MENU));
if (submenu && submenu->menuretval) {
const bool do_ret_out_parent = (submenu->menuretval & UI_RETURN_OUT_PARENT) != 0;
retval = ui_handle_menu_return_submenu(C, event, menu);
@@ -8901,7 +9603,7 @@ static int ui_handle_menus_recursive(
if (block->flag & UI_BLOCK_MOVEMOUSE_QUIT) {
/* when there is a active search button and we close it,
* we need to reinit the mouse coords [#35346] */
- if (ui_but_find_activated(menu->region) != but) {
+ if (ui_but_find_active_in_region(menu->region) != but) {
do_towards_reinit = true;
}
}
@@ -8910,7 +9612,7 @@ static int ui_handle_menus_recursive(
uiBlock *block = menu->region->uiblocks.first;
if (block->flag & UI_BLOCK_RADIAL)
- retval = ui_handler_pie(C, event, menu);
+ retval = ui_pie_handler(C, event, menu);
else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
}
@@ -8925,10 +9627,10 @@ static int ui_handle_menus_recursive(
/* *************** UI event handlers **************** */
-static int ui_handler_region(bContext *C, const wmEvent *event, void *UNUSED(userdata))
+static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata))
{
ARegion *ar;
- uiBut *but;
+ uiBut *but, *listbox;
int retval;
/* here we handle buttons at the region level, non-modal */
@@ -8940,12 +9642,13 @@ static int ui_handler_region(bContext *C, const wmEvent *event, void *UNUSED(use
}
/* either handle events for already activated button or try to activate */
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
+ listbox = ui_list_find_mouse_over(ar, event);
- retval = ui_handler_panel_region(C, event, ar);
+ retval = ui_handler_panel_region(C, event, ar, listbox ? listbox : but);
- if (retval == WM_UI_HANDLER_CONTINUE)
- retval = ui_handle_list_event(C, event, ar);
+ if (retval == WM_UI_HANDLER_CONTINUE && listbox)
+ retval = ui_handle_list_event(C, event, ar, listbox);
if (retval == WM_UI_HANDLER_CONTINUE) {
if (but)
@@ -8964,7 +9667,7 @@ static int ui_handler_region(bContext *C, const wmEvent *event, void *UNUSED(use
return retval;
}
-static void ui_handler_remove_region(bContext *C, void *UNUSED(userdata))
+static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
{
bScreen *sc;
ARegion *ar;
@@ -8972,40 +9675,58 @@ static void ui_handler_remove_region(bContext *C, void *UNUSED(userdata))
ar = CTX_wm_region(C);
if (ar == NULL) return;
- uiFreeBlocks(C, &ar->uiblocks);
+ UI_blocklist_free(C, &ar->uiblocks);
sc = CTX_wm_screen(C);
if (sc == NULL) return;
/* delayed apply callbacks, but not for screen level regions, those
* we rather do at the very end after closing them all, which will
- * be done in ui_handler_region/window */
+ * be done in ui_region_handler/window */
if (BLI_findindex(&sc->regionbase, ar) == -1)
ui_apply_but_funcs_after(C);
}
+/* handle buttons at the window level, modal, for example while
+ * 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;
uiBut *but;
- /* here we handle buttons at the window level, modal, for example
- * while number sliding, text editing, or when a menu block is open */
ar = CTX_wm_menu(C);
if (!ar)
ar = CTX_wm_region(C);
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
if (but) {
+ bScreen *screen = CTX_wm_screen(C);
+ ARegion *ar_temp;
uiBut *but_other;
uiHandleButtonData *data;
+ bool is_inside_menu = false;
+
+ /* look for a popup menu containing the mouse */
+ for (ar_temp = screen->regionbase.first; ar_temp; ar_temp = ar_temp->next) {
+ rcti winrct;
+
+ ui_region_winrct_get_no_margin(ar_temp, &winrct);
+
+ if (BLI_rcti_isect_pt_v(&winrct, &event->x)) {
+ BLI_assert(ar_temp->type->regionid == RGN_TYPE_TEMPORARY);
+
+ is_inside_menu = true;
+ break;
+ }
+ }
/* handle activated button events */
data = but->active;
if ((data->state == BUTTON_STATE_MENU_OPEN) &&
- (but->type == PULLDOWN) &&
+ (is_inside_menu == false) && /* make sure mouse isn't inside another menu (see T43247) */
+ (but->type == UI_BTYPE_PULLDOWN) &&
(but_other = ui_but_find_mouse_over(ar, event)) &&
(but != but_other) &&
(but->type == but_other->type))
@@ -9051,12 +9772,13 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
}
/* two types of popups, one with operator + enum, other with regular callbacks */
-static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
+static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
struct ARegion *menu_region;
/* we block all events, this is modal interaction, except for drop events which is described below */
int retval = WM_UI_HANDLER_BREAK;
+ bool reset_pie = false;
menu_region = CTX_wm_menu(C);
CTX_wm_menu_set(C, menu->region);
@@ -9077,9 +9799,17 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
wmWindow *win = CTX_wm_window(C);
/* copy values, we have to free first (closes region) */
uiPopupBlockHandle temp = *menu;
+ uiBlock *block = menu->region->uiblocks.first;
+
+ /* set last pie event to allow chained pie spawning */
+ if (block->flag & UI_BLOCK_RADIAL) {
+ win->last_pie_event = block->pie_data.event;
+ reset_pie = true;
+ }
ui_popup_block_free(C, menu);
- UI_remove_popup_handlers(&win->modalhandlers, menu);
+ UI_popup_handlers_remove(&win->modalhandlers, menu);
+ CTX_wm_menu_set(C, NULL);
#ifdef USE_DRAG_TOGGLE
{
@@ -9108,12 +9838,20 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
/* delayed apply callbacks */
ui_apply_but_funcs_after(C);
+ if (reset_pie) {
+ /* reaqcuire window in case pie invalidates it somehow */
+ wmWindow *win = CTX_wm_window(C);
+
+ if (win)
+ win->last_pie_event = EVENT_NONE;
+ }
+
CTX_wm_region_set(C, menu_region);
return retval;
}
-static void ui_handler_remove_popup(bContext *C, void *userdata)
+static void ui_popup_handler_remove(bContext *C, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
@@ -9124,36 +9862,37 @@ static void ui_handler_remove_popup(bContext *C, void *userdata)
ui_apply_but_funcs_after(C);
}
-void UI_add_region_handlers(ListBase *handlers)
+void UI_region_handlers_add(ListBase *handlers)
{
- WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
- WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
+ WM_event_remove_ui_handler(handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
+ WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, 0);
}
-void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click)
+void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const char flag)
{
- WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup, accept_dbl_click);
+ WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, flag);
}
-void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup)
+void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup)
{
- WM_event_remove_ui_handler(handlers, ui_handler_popup, ui_handler_remove_popup, popup, false);
+ WM_event_remove_ui_handler(handlers, ui_popup_handler, ui_popup_handler_remove, popup, false);
}
-void UI_remove_popup_handlers_all(bContext *C, ListBase *handlers)
+void UI_popup_handlers_remove_all(bContext *C, ListBase *handlers)
{
- WM_event_free_ui_handler_all(C, handlers, ui_handler_popup, ui_handler_remove_popup);
+ WM_event_free_ui_handler_all(C, handlers, ui_popup_handler, ui_popup_handler_remove);
}
-bool UI_textbutton_activate_rna(const bContext *C, ARegion *ar,
- const void *rna_poin_data, const char *rna_prop_id)
+bool UI_textbutton_activate_rna(
+ const bContext *C, ARegion *ar,
+ const void *rna_poin_data, const char *rna_prop_id)
{
uiBlock *block;
uiBut *but = NULL;
for (block = ar->uiblocks.first; block; block = block->next) {
for (but = block->buttons.first; but; but = but->next) {
- if (but->type == TEX) {
+ if (but->type == UI_BTYPE_TEXT) {
if (but->rnaprop && but->rnapoin.data == rna_poin_data) {
if (STREQ(RNA_property_identifier(but->rnaprop), rna_prop_id)) {
break;
@@ -9166,7 +9905,7 @@ bool UI_textbutton_activate_rna(const bContext *C, ARegion *ar,
}
if (but) {
- uiButActiveOnly(C, ar, block, but);
+ UI_but_active_only(C, ar, block, but);
return true;
}
else {
@@ -9182,7 +9921,7 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
for (block = ar->uiblocks.first; block; block = block->next) {
for (but = block->buttons.first; but; but = but->next)
- if (but == actbut && but->type == TEX)
+ if (but == actbut && but->type == UI_BTYPE_TEXT)
break;
if (but)
@@ -9190,7 +9929,7 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
}
if (but) {
- uiButActiveOnly(C, ar, block, but);
+ UI_but_active_only(C, ar, block, but);
return true;
}
else {
@@ -9199,7 +9938,7 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
}
-void ui_button_clipboard_free(void)
+void ui_but_clipboard_free(void)
{
curvemapping_free_data(&but_copypaste_curve);
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 51dd9166e46..796a7646b87 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -51,9 +51,11 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
+#include "BKE_appdir.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -587,7 +589,7 @@ static void init_internal_icons(void)
#if 0 // temp disabled
if ((btheme != NULL) && btheme->tui.iconfile[0]) {
- char *icondir = BLI_get_folder(BLENDER_DATAFILES, "icons");
+ char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons");
char iconfilestr[FILE_MAX];
if (icondir) {
@@ -702,12 +704,12 @@ static void init_iconfile_list(struct ListBase *list)
const char *icondir;
BLI_listbase_clear(list);
- icondir = BLI_get_folder(BLENDER_DATAFILES, "icons");
+ icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons");
if (icondir == NULL)
return;
- totfile = BLI_dir_contents(icondir, &dir);
+ totfile = BLI_filelist_dir_contents(icondir, &dir);
for (i = 0; i < totfile; i++) {
if ((dir[i].type & S_IFREG)) {
@@ -755,7 +757,7 @@ static void init_iconfile_list(struct ListBase *list)
}
}
- BLI_free_filelist(dir, totfile);
+ BLI_filelist_free(dir, totfile);
dir = NULL;
}
@@ -887,11 +889,9 @@ int UI_icon_get_height(int icon_id)
void UI_icons_init(int first_dyn_id)
{
-#ifdef WITH_HEADLESS
- (void)first_dyn_id;
-#else
- init_iconfile_list(&iconfilelist);
BKE_icons_init(first_dyn_id);
+#ifndef WITH_HEADLESS
+ init_iconfile_list(&iconfilelist);
init_internal_icons();
init_brush_icons();
init_matcap_icons();
@@ -900,20 +900,23 @@ void UI_icons_init(int first_dyn_id)
/* Render size for preview images and icons
*/
-static int preview_render_size(enum eIconSizes size)
+int UI_preview_render_size(enum eIconSizes size)
{
switch (size) {
- case ICON_SIZE_ICON: return 32;
- case ICON_SIZE_PREVIEW: return PREVIEW_DEFAULT_HEIGHT;
+ case ICON_SIZE_ICON:
+ return ICON_RENDER_DEFAULT_HEIGHT;
+ case ICON_SIZE_PREVIEW:
+ return PREVIEW_RENDER_DEFAULT_HEIGHT;
+ default:
+ return 0;
}
- return 0;
}
/* Create rect for the icon
*/
static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
{
- unsigned int render_size = preview_render_size(size);
+ unsigned int render_size = UI_preview_render_size(size);
if (!prv_img) {
if (G.debug & G_DEBUG)
@@ -922,15 +925,53 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
else if (!prv_img->rect[size]) {
prv_img->w[size] = render_size;
prv_img->h[size] = render_size;
- prv_img->changed[size] = 1;
+ prv_img->flag[size] |= PRV_CHANGED;
prv_img->changed_timestamp[size] = 0;
prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(unsigned int), "prv_rect");
}
}
+void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
+{
+ Icon *icon = BKE_icon_get(icon_id);
+
+ if (icon) {
+ DrawInfo *di = (DrawInfo *)icon->drawinfo;
+
+ if (!di) {
+ di = icon_create_drawinfo();
+
+ icon->drawinfo = di;
+ icon->drawinfo_free = UI_icons_free_drawinfo;
+ }
+
+ if (di) {
+ if (di->type == ICON_TYPE_PREVIEW) {
+ PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
+
+ if (prv) {
+ const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
+
+ if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) {
+ return;
+ }
+
+ icon_create_rect(prv, size);
+
+ /* Always using job (background) version. */
+ ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]);
+
+ prv->flag[size] &= ~PRV_CHANGED;
+ }
+ }
+ }
+ }
+}
+
/* only called when icon has changed */
/* only call with valid pointer from UI_icon_draw */
-static void icon_set_image(bContext *C, ID *id, PreviewImage *prv_img, enum eIconSizes size)
+static void icon_set_image(
+ const bContext *C, Scene *scene, ID *id, PreviewImage *prv_img, enum eIconSizes size, const bool use_job)
{
if (!prv_img) {
if (G.debug & G_DEBUG)
@@ -938,10 +979,24 @@ static void icon_set_image(bContext *C, ID *id, PreviewImage *prv_img, enum eIco
return;
}
+ if (prv_img->flag[size] & PRV_USER_EDITED) {
+ /* user-edited preview, do not auto-update! */
+ return;
+ }
+
icon_create_rect(prv_img, size);
- ED_preview_icon_job(C, prv_img, id, prv_img->rect[size],
- prv_img->w[size], prv_img->h[size]);
+ if (use_job) {
+ /* Job (background) version */
+ ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
+ }
+ else {
+ if (!scene) {
+ scene = CTX_data_scene(C);
+ }
+ /* Immediate version */
+ ED_preview_icon_render(CTX_data_main(C), scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
+ }
}
PreviewImage *UI_icon_to_preview(int icon_id)
@@ -950,22 +1005,32 @@ PreviewImage *UI_icon_to_preview(int icon_id)
if (icon) {
DrawInfo *di = (DrawInfo *)icon->drawinfo;
- if (di && di->data.buffer.image) {
- ImBuf *bbuf;
-
- bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect, di->data.buffer.image->datatoc_size, IB_rect, NULL, "<matcap buffer>");
- if (bbuf) {
- PreviewImage *prv = BKE_previewimg_create();
-
- prv->rect[0] = bbuf->rect;
+ if (di) {
+ if (di->type == ICON_TYPE_PREVIEW) {
+ PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
- prv->w[0] = bbuf->x;
- prv->h[0] = bbuf->y;
-
- bbuf->rect = NULL;
- IMB_freeImBuf(bbuf);
-
- return prv;
+ if (prv) {
+ return BKE_previewimg_copy(prv);
+ }
+ }
+ else if (di->data.buffer.image) {
+ ImBuf *bbuf;
+
+ bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect, di->data.buffer.image->datatoc_size,
+ IB_rect, NULL, __func__);
+ if (bbuf) {
+ PreviewImage *prv = BKE_previewimg_create();
+
+ prv->rect[0] = bbuf->rect;
+
+ prv->w[0] = bbuf->x;
+ prv->h[0] = bbuf->y;
+
+ bbuf->rect = NULL;
+ IMB_freeImBuf(bbuf);
+
+ return prv;
+ }
}
}
}
@@ -976,6 +1041,10 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
unsigned int *rect, float alpha, const float rgb[3], const bool is_preview)
{
ImBuf *ima = NULL;
+ int draw_w = w;
+ int draw_h = h;
+ int draw_x = x;
+ int draw_y = y;
/* sanity check */
if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
@@ -995,21 +1064,34 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
/* rect contains image in 'rendersize', we only scale if needed */
- if (rw != w && rh != h) {
+ if (rw != w || rh != h) {
+ /* preserve aspect ratio and center */
+ if (rw > rh) {
+ draw_w = w;
+ draw_h = (int)(((float)rh / (float)rw) * (float)w);
+ draw_y += (h - draw_h) / 2;
+ }
+ else if (rw < rh) {
+ draw_w = (int)(((float)rw / (float)rh) * (float)h);
+ draw_h = h;
+ draw_x += (w - draw_w) / 2;
+ }
+ /* if the image is squared, the draw_ initialization values are good */
+
/* first allocate imbuf for scaling and copy preview into it */
ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
memcpy(ima->rect, rect, rw * rh * sizeof(unsigned int));
- IMB_scaleImBuf(ima, w, h); /* scale it */
+ IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
rect = ima->rect;
}
/* draw */
if (is_preview) {
- glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
- glRasterPos2f(x, y);
- glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glRasterPos2f(draw_x, draw_y);
+ glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
if (ima)
@@ -1026,8 +1108,9 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
}
-static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy,
- int UNUSED(iw), int ih, float alpha, const float rgb[3])
+static void icon_draw_texture(
+ float x, float y, float w, float h, int ix, int iy,
+ int UNUSED(iw), int ih, float alpha, const float rgb[3])
{
float x1, x2, y1, y2;
@@ -1069,16 +1152,20 @@ static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy
static int get_draw_size(enum eIconSizes size)
{
switch (size) {
- case ICON_SIZE_ICON: return ICON_DEFAULT_HEIGHT;
- case ICON_SIZE_PREVIEW: return PREVIEW_DEFAULT_HEIGHT;
+ case ICON_SIZE_ICON:
+ return ICON_DEFAULT_HEIGHT;
+ case ICON_SIZE_PREVIEW:
+ return PREVIEW_DEFAULT_HEIGHT;
+ default:
+ return 0;
}
- return 0;
}
-static void icon_draw_size(float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
- enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
+static void icon_draw_size(
+ float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
+ enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
{
bTheme *btheme = UI_GetTheme();
Icon *icon = NULL;
@@ -1134,45 +1221,52 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else if (di->type == ICON_TYPE_PREVIEW) {
- PreviewImage *pi = BKE_previewimg_get((ID *)icon->obj);
+ PreviewImage *pi = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
if (pi) {
/* no create icon on this level in code */
if (!pi->rect[size]) return; /* something has gone wrong! */
/* preview images use premul alpha ... */
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], 1.0f, NULL, is_preview);
+ if (GLEW_VERSION_1_4) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, is_preview);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
}
-static void ui_id_preview_image_render_size(bContext *C, ID *id, PreviewImage *pi, int size)
+static void ui_id_preview_image_render_size(
+ const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job)
{
- if ((pi->changed[size] || !pi->rect[size])) { /* changed only ever set by dynamic icons */
+ if (((pi->flag[size] & PRV_CHANGED) || !pi->rect[size])) { /* changed only ever set by dynamic icons */
/* create the rect if necessary */
- icon_set_image(C, id, pi, size);
+ icon_set_image(C, scene, id, pi, size, use_job);
- pi->changed[size] = 0;
+ pi->flag[size] &= ~PRV_CHANGED;
}
}
-static void ui_id_icon_render(bContext *C, ID *id, const bool big)
+void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job)
{
- PreviewImage *pi = BKE_previewimg_get(id);
+ PreviewImage *pi = BKE_previewimg_id_ensure(id);
if (pi) {
if (big)
- ui_id_preview_image_render_size(C, id, pi, ICON_SIZE_PREVIEW); /* bigger preview size */
+ ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_PREVIEW, use_job); /* bigger preview size */
else
- ui_id_preview_image_render_size(C, id, pi, ICON_SIZE_ICON); /* icon size */
+ ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_ICON, use_job); /* icon size */
}
}
-static void ui_id_brush_render(bContext *C, ID *id)
+static void ui_id_brush_render(const bContext *C, ID *id)
{
- PreviewImage *pi = BKE_previewimg_get(id);
+ PreviewImage *pi = BKE_previewimg_id_ensure(id);
enum eIconSizes i;
if (!pi)
@@ -1181,20 +1275,20 @@ static void ui_id_brush_render(bContext *C, ID *id)
for (i = 0; i < NUM_ICON_SIZES; i++) {
/* check if rect needs to be created; changed
* only set by dynamic icons */
- if ((pi->changed[i] || !pi->rect[i])) {
- icon_set_image(C, id, pi, i);
- pi->changed[i] = 0;
+ if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) {
+ icon_set_image(C, NULL, id, pi, i, true);
+ pi->flag[i] &= ~PRV_CHANGED;
}
}
}
-static int ui_id_brush_get_icon(bContext *C, ID *id)
+static int ui_id_brush_get_icon(const bContext *C, ID *id)
{
Brush *br = (Brush *)id;
if (br->flag & BRUSH_CUSTOM_ICON) {
- BKE_icon_getid(id);
+ BKE_icon_id_ensure(id);
ui_id_brush_render(C, id);
}
else {
@@ -1242,7 +1336,7 @@ static int ui_id_brush_get_icon(bContext *C, ID *id)
return id->icon_id;
}
-int ui_id_icon_get(bContext *C, ID *id, const bool big)
+int ui_id_icon_get(const bContext *C, ID *id, const bool big)
{
int iconid = 0;
@@ -1256,9 +1350,9 @@ int ui_id_icon_get(bContext *C, ID *id, const bool big)
case ID_IM: /* fall through */
case ID_WO: /* fall through */
case ID_LA: /* fall through */
- iconid = BKE_icon_getid(id);
+ iconid = BKE_icon_id_ensure(id);
/* checks if not exists, or changed */
- ui_id_icon_render(C, id, big);
+ UI_id_icon_render(C, NULL, id, big, true);
break;
default:
break;
@@ -1305,8 +1399,73 @@ int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big
return rnaicon;
}
-static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha,
- enum eIconSizes size, const bool nocreate)
+int UI_idcode_icon_get(const int idcode)
+{
+ switch (idcode) {
+ case ID_AC:
+ return ICON_ANIM_DATA;
+ case ID_AR:
+ return ICON_ARMATURE_DATA;
+ case ID_BR:
+ return ICON_BRUSH_DATA;
+ case ID_CA:
+ return ICON_CAMERA_DATA;
+ case ID_CU:
+ return ICON_CURVE_DATA;
+ case ID_GD:
+ return ICON_GREASEPENCIL;
+ case ID_GR:
+ return ICON_GROUP;
+ case ID_IM:
+ return ICON_IMAGE_DATA;
+ case ID_LA:
+ return ICON_LAMP_DATA;
+ case ID_LS:
+ return ICON_LINE_DATA;
+ case ID_LT:
+ return ICON_LATTICE_DATA;
+ case ID_MA:
+ return ICON_MATERIAL_DATA;
+ case ID_MB:
+ return ICON_META_DATA;
+ case ID_MC:
+ return ICON_CLIP;
+ case ID_ME:
+ return ICON_MESH_DATA;
+ case ID_MSK:
+ return ICON_MOD_MASK; /* TODO! this would need its own icon! */
+ case ID_NT:
+ return ICON_NODETREE;
+ case ID_OB:
+ return ICON_OBJECT_DATA;
+ case ID_PA:
+ return ICON_PARTICLE_DATA;
+ case ID_PAL:
+ return ICON_COLOR; /* TODO! this would need its own icon! */
+ case ID_PC:
+ return ICON_CURVE_BEZCURVE; /* TODO! this would need its own icon! */
+ case ID_SCE:
+ return ICON_SCENE_DATA;
+ case ID_SPK:
+ return ICON_SPEAKER;
+ case ID_SO:
+ return ICON_SOUND;
+ case ID_TE:
+ return ICON_TEXTURE_DATA;
+ case ID_TXT:
+ return ICON_TEXT;
+ case ID_VF:
+ return ICON_FONT_DATA;
+ case ID_WO:
+ return ICON_WORLD_DATA;
+ default:
+ return ICON_NONE;
+ }
+}
+
+static void icon_draw_at_size(
+ float x, float y, int icon_id, float aspect, float alpha,
+ enum eIconSizes size, const bool nocreate)
{
int draw_size = get_draw_size(size);
icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, nocreate, false);
@@ -1344,8 +1503,8 @@ void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, 0);
}
-void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
+void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, ICON_SIZE_PREVIEW, size, false, true);
+ icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, true);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 2f66c4a9900..032efad885e 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -36,14 +36,13 @@
#include "BLI_compiler_attrs.h"
#include "UI_resources.h"
#include "RNA_types.h"
+#include "DNA_listBase.h"
struct ARegion;
struct bContext;
-struct IDProperty;
struct uiHandleButtonData;
struct wmEvent;
struct wmOperatorType;
-struct wmWindow;
struct wmTimer;
struct uiStyle;
struct uiWidgetColors;
@@ -67,7 +66,7 @@ typedef enum {
/* standard set */
UI_WTYPE_LABEL,
UI_WTYPE_TOGGLE,
- UI_WTYPE_OPTION,
+ UI_WTYPE_CHECKBOX,
UI_WTYPE_RADIO,
UI_WTYPE_NUMBER,
UI_WTYPE_SLIDER,
@@ -95,7 +94,7 @@ typedef enum {
UI_WTYPE_ICON,
UI_WTYPE_SWATCH,
UI_WTYPE_RGB_PICKER,
- UI_WTYPE_NORMAL,
+ UI_WTYPE_UNITVEC,
UI_WTYPE_BOX,
UI_WTYPE_SCROLL,
UI_WTYPE_LISTITEM,
@@ -122,6 +121,19 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
+/* some buttons display icons only under special conditions
+ * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
+typedef enum uiButExtraIconType {
+ UI_BUT_ICONEXTRA_NONE = 1,
+ UI_BUT_ICONEXTRA_UNLINK,
+ UI_BUT_ICONEXTRA_EYEDROPPER,
+} uiButExtraIconType;
+
+/* uiBut->dragflag */
+enum {
+ UI_BUT_DRAGPOIN_FREE = (1 << 0),
+};
+
/* but->pie_dir */
typedef enum RadialDirection {
UI_RADIAL_NONE = -1,
@@ -157,7 +169,7 @@ extern const short ui_radial_dir_to_angle[8];
#define UI_BITBUT_SET(a, b) ( (a) | 1 << (b) )
#define UI_BITBUT_CLR(a, b) ( (a) & ~(1 << (b)) )
/* bit-row */
-#define UI_BITBUT_ROW(min, max) (((max) >= 31 ? 0xFFFFFFFF : (1 << (max + 1)) - 1) - ((min) ? ((1 << (min)) - 1) : 0) )
+#define UI_BITBUT_ROW(min, max) (((max) >= 31 ? 0xFFFFFFFF : (1 << ((max) + 1)) - 1) - ((min) ? ((1 << (min)) - 1) : 0) )
/* split numbuts by ':' and align l/r */
#define USE_NUMBUTS_LR_ALIGN
@@ -168,9 +180,9 @@ enum {
UI_PIE_INITIAL_DIRECTION = (1 << 1), /* use initial center of pie menu to calculate direction */
UI_PIE_DRAG_STYLE = (1 << 2), /* pie menu is drag style */
UI_PIE_INVALID_DIR = (1 << 3), /* mouse not far enough from center position */
- UI_PIE_FINISHED = (1 << 4), /* pie menu finished but we still wait for a release event */
- UI_PIE_CLICK_STYLE = (1 << 5), /* pie menu changed to click style, click to confirm */
- UI_PIE_ANIMATION_FINISHED = (1 << 6), /* pie animation finished, do not calculate any more motio */
+ UI_PIE_CLICK_STYLE = (1 << 4), /* pie menu changed to click style, click to confirm */
+ UI_PIE_ANIMATION_FINISHED = (1 << 5), /* pie animation finished, do not calculate any more motion */
+ UI_PIE_GESTURE_END_WAIT = (1 << 6), /* pie gesture selection has been done, now wait for mouse motion to end */
};
#define PIE_CLICK_THRESHOLD_SQ 50.0f
@@ -212,20 +224,20 @@ struct uiBut {
/* both these values use depends on the button type
* (polymorphic struct or union would be nicer for this stuff) */
- /* (type == HSVCUBE), Use UI_GRAD_* values.
- * (type == NUM), Use to store RNA 'step' value, for dragging and click-step.
- * (type == LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!).
- * (type == SCROLL) Use as scroll size.
- * (type == SEARCH_MENU) Use as number or rows.
- * (type == COLOR) Use as indication of color palette
+ /* (type == UI_BTYPE_HSVCUBE), Use UI_GRAD_* values.
+ * (type == UI_BTYPE_NUM), Use to store RNA 'step' value, for dragging and click-step.
+ * (type == UI_BTYPE_LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!).
+ * (type == UI_BTYPE_SCROLL) Use as scroll size.
+ * (type == UI_BTYPE_SEARCH_MENU) Use as number or rows.
+ * (type == UI_BTYPE_COLOR) Use as indication of color palette
*/
float a1;
- /* (type == HSVCIRCLE ), Use to store the luminosity.
- * (type == NUM), Use to store RNA 'precision' value, for dragging and click-step.
- * (type == LABEL), If (a1 == 1.0f) use a2 as a blending factor.
- * (type == SEARCH_MENU) Use as number or columns.
- * (type == COLOR) Use as index in palette (not so good, needs refactor)
+ /* (type == UI_BTYPE_HSVCIRCLE ), Use to store the luminosity.
+ * (type == UI_BTYPE_NUM), Use to store RNA 'precision' value, for dragging and click-step.
+ * (type == UI_BTYPE_LABEL), If (a1 == 1.0f) use a2 as a blending factor.
+ * (type == UI_BTYPE_SEARCH_MENU) Use as number or columns.
+ * (type == UI_BTYPE_COLOR) Use as index in palette (not so good, needs refactor)
*/
float a2;
@@ -253,21 +265,25 @@ struct uiBut {
uiLink *link;
short linkto[2]; /* region relative coords */
- const char *tip, *lockstr;
+ const char *tip;
+ uiButToolTipFunc tip_func;
+ void *tip_argN;
+
+ const char *lockstr;
BIFIconID icon;
bool lock;
- char dt; /* drawtype: UI_EMBOSS, UI_EMBOSSN ... etc, copied from the block */
+ char dt; /* drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the block */
signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
char changed; /* could be made into a single flag */
unsigned char unit_type; /* so buttons can support unit systems which are not RNA */
short modifier_key;
short iconadd;
- /* BLOCK data */
+ /* UI_BTYPE_BLOCK data */
uiBlockCreateFunc block_create_func;
- /* PULLDOWN/MENU data */
+ /* UI_BTYPE_PULLDOWN/UI_BTYPE_MENU data */
uiMenuCreateFunc menu_create_func;
/* RNA data */
@@ -286,6 +302,7 @@ struct uiBut {
/* Draggable data, type is WM_DRAG_... */
char dragtype;
+ short dragflag;
void *dragpoin;
struct ImBuf *imb;
float imb_scale;
@@ -306,10 +323,22 @@ struct uiBut {
uiBlock *block;
};
+typedef struct ColorPicker {
+ struct ColorPicker *next, *prev;
+ float color_data[3]; /* colr data may be HSV or HSL for now */
+ int representation; /* store hsv/hsl value */
+} ColorPicker;
+
+typedef struct ColorPickerData {
+ ListBase list;
+} ColorPickerData;
+
struct PieMenuData {
float pie_dir[2];
float pie_center_init[2];
float pie_center_spawned[2];
+ float last_pos[2];
+ double duration_gesture;
int flags;
int event; /* initial event used to fire the pie menu, store here so we can query for release */
float alphafac;
@@ -363,7 +392,7 @@ struct uiBlock {
short alignnr;
char direction;
- char dt; /* drawtype: UI_EMBOSS, UI_EMBOSSN ... etc, copied to buttons */
+ char dt; /* drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied to buttons */
bool auto_open;
char _pad[7];
double auto_open_last;
@@ -373,7 +402,7 @@ struct uiBlock {
char lock;
char active; /* to keep blocks while drawing and free them afterwards */
char tooltipdisabled; /* to avoid tooltip after click */
- char endblock; /* uiEndBlock done? */
+ char endblock; /* UI_block_end done? */
eBlockBoundsCalc bounds_type; /* for doing delayed */
int mx, my;
@@ -390,7 +419,7 @@ struct uiBlock {
void *evil_C; /* XXX hack for dynamic operator enums */
struct UnitSettings *unit; /* unit system, used a lot for numeric buttons so include here rather then fetching through the scene every time. */
- float _hsv[3]; /* XXX, only access via ui_block_hsv_get() */
+ ColorPickerData color_pickers; /* XXX, only accessed by color picker templates */
bool color_profile; /* color profile for correcting linear colors for display */
@@ -408,7 +437,7 @@ typedef struct uiSafetyRct {
/* interface.c */
-extern void ui_delete_linkline(uiLinkLine *line, uiBut *but);
+extern void ui_linkline_remove(uiLinkLine *line, uiBut *but);
void ui_fontscale(short *points, float aspect);
@@ -420,49 +449,56 @@ extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rc
extern void ui_window_to_block_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y);
extern void ui_window_to_block(const struct ARegion *ar, uiBlock *block, int *x, int *y);
extern void ui_window_to_region(const ARegion *ar, int *x, int *y);
-
-extern double ui_get_but_val(uiBut *but);
-extern void ui_set_but_val(uiBut *but, double value);
-extern void ui_set_but_hsv(uiBut *but);
-extern void ui_get_but_vectorf(uiBut *but, float vec[3]);
-extern void ui_set_but_vectorf(uiBut *but, const float vec[3]);
-
-extern void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
- const float mx, const float my);
+extern void ui_region_to_window(const struct ARegion *ar, int *x, int *y);
+extern void ui_region_winrct_get_no_margin(const struct ARegion *ar, struct rcti *r_rect);
+
+extern double ui_but_value_get(uiBut *but);
+extern void ui_but_value_set(uiBut *but, double value);
+extern void ui_but_hsv_set(uiBut *but);
+extern void ui_but_v3_get(uiBut *but, float vec[3]);
+extern void ui_but_v3_set(uiBut *but, const float vec[3]);
+
+extern void ui_hsvcircle_vals_from_pos(
+ float *val_rad, float *val_dist, const rcti *rect,
+ const float mx, const float my);
extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xpos, float *ypos);
extern void ui_hsvcube_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp);
-bool ui_color_picker_use_display_colorspace(struct uiBut *but);
+bool ui_but_is_colorpicker_display_space(struct uiBut *but);
+
+extern void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) ATTR_NONNULL();
+extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
+extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
+extern bool ui_but_string_set(struct bContext *C, uiBut *but, const char *str) ATTR_NONNULL();
+extern bool ui_but_string_set_eval_num(struct bContext *C, uiBut *but, const char *str, double *value) ATTR_NONNULL();
+extern int ui_but_string_get_max_length(uiBut *but);
+extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
-extern void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) ATTR_NONNULL();
-extern void ui_get_but_string(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
-extern void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
-extern bool ui_set_but_string(struct bContext *C, uiBut *but, const char *str) ATTR_NONNULL();
-extern bool ui_set_but_string_eval_num(struct bContext *C, uiBut *but, const char *str, double *value) ATTR_NONNULL();
-extern int ui_get_but_string_max_length(uiBut *but);
-extern uiBut *ui_get_but_drag_multi_edit(uiBut *but);
+void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but);
-extern void ui_set_but_default(struct bContext *C, const bool all, const bool use_afterfunc);
+extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc);
-extern void ui_check_but(uiBut *but);
-extern bool ui_is_but_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_is_but_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_is_but_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_is_but_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_is_but_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_is_but_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_is_but_search_unlink_visible(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern void ui_but_update(uiBut *but);
+extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern int ui_is_but_push_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
-extern int ui_is_but_push(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
+extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern void ui_bounds_block(uiBlock *block);
+extern void ui_block_bounds_calc(uiBlock *block);
extern void ui_block_translate(uiBlock *block, int x, int y);
-extern void ui_block_do_align(uiBlock *block);
+extern void ui_block_align_calc(uiBlock *block);
-extern struct ColorManagedDisplay *ui_block_display_get(uiBlock *block);
-void ui_block_to_display_space_v3(uiBlock *block, float pixel[3]);
-void ui_block_to_scene_linear_v3(uiBlock *block, float pixel[3]);
+extern struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block);
+void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]);
+void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3]);
+void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max);
/* interface_regions.c */
@@ -538,7 +574,7 @@ void ui_popup_menu_memory_set(uiBlock *block, struct uiBut *but);
void ui_popup_translate(struct bContext *C, struct ARegion *ar, const int mdiff[2]);
-float *ui_block_hsv_get(struct uiBlock *block);
+ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);
void ui_popup_block_scrolltest(struct uiBlock *block);
void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]);
@@ -555,29 +591,34 @@ int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *ar, uiBut *but
void ui_searchbox_event(struct bContext *C, struct ARegion *ar, uiBut *but, const struct wmEvent *event);
bool ui_searchbox_apply(uiBut *but, struct ARegion *ar);
void ui_searchbox_free(struct bContext *C, struct ARegion *ar);
-void ui_but_search_test(uiBut *but);
+void ui_but_search_refresh(uiBut *but);
-uiBlock *ui_popup_block_refresh(struct bContext *C, uiPopupBlockHandle *handle,
- ARegion *butregion, uiBut *but);
+uiBlock *ui_popup_block_refresh(
+ struct bContext *C, uiPopupBlockHandle *handle,
+ ARegion *butregion, uiBut *but);
-uiPopupBlockHandle *ui_popup_block_create(struct bContext *C, struct ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg);
-uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C, struct ARegion *butregion, uiBut *but,
- uiMenuCreateFunc create_func, void *arg);
+uiPopupBlockHandle *ui_popup_block_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg);
+uiPopupBlockHandle *ui_popup_menu_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc create_func, void *arg);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
-int ui_step_name_menu(uiBut *but, int step);
+int ui_but_menu_step(uiBut *but, int step);
+bool ui_but_menu_step_poll(const uiBut *but);
-struct AutoComplete;
/* interface_panel.c */
-extern int ui_handler_panel_region(struct bContext *C, const struct wmEvent *event, struct ARegion *ar);
+extern int ui_handler_panel_region(
+ struct bContext *C, const struct wmEvent *event,
+ struct ARegion *ar, const uiBut *active_but);
extern void ui_draw_aligned_panel(struct uiStyle *style, uiBlock *block, const rcti *rect, const bool show_pin);
/* interface_draw.c */
-extern void ui_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
+extern void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha);
@@ -585,7 +626,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol,
void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
-void ui_draw_but_NORMAL(uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
+void ui_draw_but_UNITVEC(uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_CURVE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
@@ -594,25 +635,32 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol
/* interface_handlers.c */
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props);
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
-extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but);
-extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but);
-extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back);
-extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back);
-extern void ui_button_active_free(const struct bContext *C, uiBut *but);
-extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
-extern int ui_button_open_menu_direction(uiBut *but);
-extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
-extern uiBut *ui_but_find_activated(struct ARegion *ar);
+extern void ui_but_activate_event(struct bContext *C, struct ARegion *ar, uiBut *but);
+extern void ui_but_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but);
+extern void ui_but_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back);
+extern void ui_but_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back);
+extern void ui_but_active_free(const struct bContext *C, uiBut *but);
+extern bool ui_but_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
+extern int ui_but_menu_direction(uiBut *but);
+extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
+extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
+extern uiBut *ui_but_find_active_in_region(struct ARegion *ar);
bool ui_but_is_editable(const uiBut *but);
+bool ui_but_is_editable_as_text(const uiBut *but);
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
-void ui_block_calculate_pie_segment(struct uiBlock *block, const float event_xy[2]);
+float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
-void ui_button_clipboard_free(void);
+void ui_but_clipboard_free(void);
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
+#ifdef WITH_INPUT_IME
+void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete);
+struct wmIMEData *ui_but_ime_data_get(uiBut *but);
+#endif
+
/* interface_widgets.c */
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
@@ -633,12 +681,14 @@ void ui_draw_menu_item(struct uiFontStyle *fstyle, rcti *rect, const char *name,
void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
#define UI_TEXT_MARGIN_X 0.4f
+#define UI_POPUP_MARGIN (UI_DPI_FAC * 12)
/* interface_style.c */
void uiStyleInit(void);
/* interface_icons.c */
-int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big);
+void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
+int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
/* resources.c */
void init_userdef_do_versions(void);
@@ -673,5 +723,6 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl
/* interface_eyedropper.c */
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
+void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c2bd6d307d1..67b4f183c82 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -43,7 +43,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -184,7 +184,7 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_
return name;
}
-static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
+static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, int *offset)
{
if (offset)
*offset = 0;
@@ -195,7 +195,7 @@ static int ui_item_fit(int item, int pos, int all, int available, int last, int
if (all > available) {
/* contents is bigger than available space */
- if (last)
+ if (is_last)
return available - pos;
else
return (item * available) / all;
@@ -203,7 +203,7 @@ static int ui_item_fit(int item, int pos, int all, int available, int last, int
else {
/* contents is smaller or equal to available space */
if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
- if (last)
+ if (is_last)
return available - pos;
else
return (item * available) / all;
@@ -235,9 +235,10 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X);
if (variable) {
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
/* it may seem odd that the icon only adds (UI_UNIT_X / 4)
* but taking margins into account its fine */
- return (UI_GetStringWidth(name) +
+ return (UI_fontstyle_string_width(fstyle, name) +
(UI_UNIT_X * ((compact ? 1.25f : 1.50f) +
(icon ? 0.25f : 0.0f))));
}
@@ -286,7 +287,7 @@ static void ui_item_position(uiItem *item, int x, int y, int w, int h)
bitem->but->rect.xmax = x + w;
bitem->but->rect.ymax = y + h;
- ui_check_but(bitem->but); /* for strlen */
+ ui_but_update(bitem->but); /* for strlen */
}
else {
uiLayout *litem = (uiLayout *)item;
@@ -350,14 +351,15 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
RNA_property_update(C, ptr, prop);
for (cbut = but->block->buttons.first; cbut; cbut = cbut->next)
- ui_check_but(cbut);
+ ui_but_update(cbut);
}
}
/* create buttons for an item with an RNA array */
-static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon,
- PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
- int expand, int slider, int toggle, int icon_only)
+static void ui_item_array(
+ uiLayout *layout, uiBlock *block, const char *name, int icon,
+ PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
+ bool expand, bool slider, bool toggle, bool icon_only)
{
uiStyle *style = layout->root->style;
uiBut *but;
@@ -371,11 +373,11 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
subtype = RNA_property_subtype(prop);
sub = ui_item_local_sublayout(layout, layout, 1);
- uiBlockSetCurLayout(block, sub);
+ UI_block_layout_set_current(block, sub);
/* create label */
if (name[0])
- uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* create buttons */
if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
@@ -386,7 +388,7 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
unsigned int layer_used = 0;
unsigned int layer_active = 0;
- uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, false));
+ UI_block_layout_set_current(block, uiLayoutAbsolute(layout, false));
unit = UI_UNIT_X * 0.75;
butw = unit;
@@ -410,7 +412,7 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
}
for (b = 0; b < cols; b++) {
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
for (a = 0; a < colbuts; a++) {
const int layer_num = a + b * colbuts;
@@ -428,7 +430,7 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
but = uiDefAutoButR(block, ptr, prop, layer_num, "", icon, x + butw * a, y + buth, butw, buth);
if (subtype == PROP_LAYER_MEMBER)
- uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(layer_num));
+ UI_but_func_set(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(layer_num));
}
for (a = 0; a < colbuts; a++) {
const int layer_num = a + len / 2 + b * colbuts;
@@ -446,9 +448,9 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
but = uiDefAutoButR(block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth);
if (subtype == PROP_LAYER_MEMBER)
- uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(layer_num));
+ UI_but_func_set(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(layer_num));
}
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
x += colbuts * butw + style->buttonspacex;
}
@@ -457,7 +459,7 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
int totdim, dim_size[3]; /* 3 == RNA_MAX_ARRAY_DIMENSION */
int row, col;
- uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, true));
+ UI_block_layout_set_current(block, uiLayoutAbsolute(layout, true));
totdim = RNA_property_array_dimension(ptr, prop, dim_size);
if (totdim != 2) return; /* only 2D matrices supported in UI so far */
@@ -470,12 +472,12 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
row = a / dim_size[0];
but = uiDefAutoButR(block, ptr, prop, a, "", ICON_NONE, x + w * col, y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y), w, UI_UNIT_Y);
- if (slider && but->type == NUM)
- but->type = NUMSLI;
+ if (slider && but->type == UI_BTYPE_NUM)
+ but->type = UI_BTYPE_NUM_SLIDER;
}
}
else if (subtype == PROP_DIRECTION && !expand) {
- uiDefButR_prop(block, BUT_NORMAL, 0, name, x, y, UI_UNIT_X * 3, UI_UNIT_Y * 3, ptr, prop, 0, 0, 0, -1, -1, NULL);
+ uiDefButR_prop(block, UI_BTYPE_UNITVEC, 0, name, x, y, UI_UNIT_X * 3, UI_UNIT_Y * 3, ptr, prop, -1, 0, 0, -1, -1, NULL);
}
else {
/* note, this block of code is a bit arbitrary and has just been made
@@ -500,8 +502,8 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
}
/* show checkboxes for rna on a non-emboss block (menu for eg) */
- if (type == PROP_BOOLEAN && ELEM(layout->root->block->dt, UI_EMBOSSN, UI_EMBOSSP)) {
- boolarr = MEM_callocN(sizeof(int) * len, "ui_item_array");
+ if (type == PROP_BOOLEAN && ELEM(layout->root->block->dt, UI_EMBOSS_NONE, UI_EMBOSS_PULLDOWN)) {
+ boolarr = MEM_callocN(sizeof(int) * len, __func__);
RNA_property_boolean_get_array(ptr, prop, boolarr);
}
@@ -509,12 +511,12 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
if (!icon_only) str[0] = RNA_property_array_item_char(prop, a);
if (boolarr) icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
but = uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
- if (slider && but->type == NUM)
- but->type = NUMSLI;
- if (toggle && but->type == OPTION)
- but->type = TOG;
+ if (slider && but->type == UI_BTYPE_NUM)
+ but->type = UI_BTYPE_NUM_SLIDER;
+ if (toggle && but->type == UI_BTYPE_CHECKBOX)
+ but->type = UI_BTYPE_TOGGLE;
if ((a == 0) && (subtype == PROP_AXISANGLE))
- uiButSetUnitType(but, PROP_UNIT_ROTATION);
+ UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
}
if (boolarr) {
@@ -523,7 +525,7 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in
}
}
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
}
static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
@@ -544,8 +546,9 @@ static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
}
}
-static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
- const char *uiname, int h, int icon_only)
+static void ui_item_enum_expand(
+ uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
+ const char *uiname, int h, bool icon_only)
{
/* XXX The way this function currently handles uiname parameter is insane and inconsistent with general UI API:
* * uiname is the *enum property* label.
@@ -571,13 +574,13 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
/* we dont want nested rows, cols in menus */
if (radial) {
layout_radial = uiLayoutRadial(layout);
- uiBlockSetCurLayout(block, layout_radial);
+ UI_block_layout_set_current(block, layout_radial);
}
else if (layout->root->type != UI_LAYOUT_MENU) {
- uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
+ UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1));
}
else {
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
}
for (item = item_array; item->identifier; item++) {
@@ -593,20 +596,20 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0);
if (icon && name[0] && !icon_only)
- but = uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ but = uiDefIconTextButR_prop(block, UI_BTYPE_ROW, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
else if (icon)
- but = uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ but = uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
else
- but = uiDefButR_prop(block, ROW, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_ROW, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
- uiButSetFunc(but, ui_item_enum_expand_handle, but, SET_INT_IN_POINTER(value));
+ UI_but_func_set(but, ui_item_enum_expand_handle, but, SET_INT_IN_POINTER(value));
}
if (ui_layout_local_dir(layout) != UI_LAYOUT_HORIZONTAL)
but->drawflag |= UI_BUT_TEXT_LEFT;
}
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (free) {
MEM_freeN(item_array);
@@ -634,16 +637,16 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
int labelw;
sub = uiLayoutRow(layout, layout->align);
- uiBlockSetCurLayout(block, sub);
+ UI_block_layout_set_current(block, sub);
if (name[0]) {
- /* XXX UI_GetStringWidth is not accurate */
+ /* XXX UI_fontstyle_string_width is not accurate */
#if 0
- labelw = UI_GetStringWidth(name);
+ labelw = UI_fontstyle_string_width(fstyle, name);
CLAMP(labelw, w / 4, 3 * w / 4);
#endif
labelw = w / 3;
- uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
w = w - labelw;
}
@@ -651,43 +654,46 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
subtype = RNA_property_subtype(prop);
if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
- uiBlockSetCurLayout(block, uiLayoutRow(sub, true));
+ UI_block_layout_set_current(block, uiLayoutRow(sub, true));
but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w - UI_UNIT_X, h);
- /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
- uiDefIconButO(block, BUT, subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" : "BUTTONS_OT_file_browse",
+ /* BUTTONS_OT_file_browse calls UI_context_active_but_prop_get_filebrowser */
+ uiDefIconButO(block, UI_BTYPE_BUT, subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" : "BUTTONS_OT_file_browse",
WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
}
else if (flag & UI_ITEM_R_EVENT) {
- uiDefButR_prop(block, KEYEVT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
+ uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
}
else if (flag & UI_ITEM_R_FULL_EVENT) {
if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
char buf[128];
- WM_keymap_item_to_string(ptr->data, buf, sizeof(buf));
+ WM_keymap_item_to_string(ptr->data, false, sizeof(buf), buf);
- but = uiDefButR_prop(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, ui_keymap_but_cb, but, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_HOTKEY_EVENT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
+ UI_but_func_set(but, ui_keymap_but_cb, but, NULL);
if (flag & UI_ITEM_R_IMMEDIATE)
- uiButSetFlag(but, UI_BUT_IMMEDIATE);
+ UI_but_flag_enable(but, UI_BUT_IMMEDIATE);
}
}
else
but = uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "", icon, x, y, w, h);
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
return but;
}
-void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_filebrowser(
+ const bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop, bool *r_is_undo)
{
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but, *prevbut;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_is_undo = false;
if (!ar)
return;
@@ -699,8 +705,9 @@ void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA
/* find the button before the active one */
if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
if (RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
- *ptr = prevbut->rnapoin;
- *prop = prevbut->rnaprop;
+ *r_ptr = prevbut->rnapoin;
+ *r_prop = prevbut->rnaprop;
+ *r_is_undo = (prevbut->flag & UI_BUT_UNDO) != 0;
return;
}
}
@@ -729,14 +736,14 @@ static void ui_item_disabled(uiLayout *layout, const char *name)
uiBut *but;
int w;
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (!name)
name = "";
w = ui_text_icon_width(layout, name, 0, 0);
- but = uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->flag |= UI_BUT_DISABLED;
but->lock = true;
but->lockstr = "";
@@ -760,24 +767,24 @@ PointerRNA uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *nam
icon = ICON_BLANK1;
/* create button */
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
w = ui_text_icon_width(layout, name, icon, 0);
if (flag & UI_ITEM_R_NO_BG)
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* create the button */
if (icon) {
if (name[0]) {
- but = uiDefIconTextButO_ptr(block, BUT, ot, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
+ but = uiDefIconTextButO_ptr(block, UI_BTYPE_BUT, ot, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
}
else {
- but = uiDefIconButO_ptr(block, BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
+ but = uiDefIconButO_ptr(block, UI_BTYPE_BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
}
}
else {
- but = uiDefButO_ptr(block, BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL);
+ but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL);
}
assert(but->optype != NULL);
@@ -787,14 +794,14 @@ PointerRNA uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *nam
but->drawflag |= UI_BUT_TEXT_LEFT;
if (flag & UI_ITEM_R_NO_BG)
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
if (layout->redalert)
- uiButSetFlag(but, UI_BUT_REDALERT);
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
/* assign properties */
if (properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
- PointerRNA *opptr = uiButGetOperatorPtrRNA(but);
+ PointerRNA *opptr = UI_but_operator_ptr_get(but);
if (properties) {
opptr->data = properties;
@@ -876,8 +883,9 @@ void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int ico
}
-void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
- int context, int flag)
+void uiItemsFullEnumO(
+ uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
+ int context, int flag)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
@@ -904,7 +912,7 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
if (prop && RNA_property_type(prop) == PROP_ENUM) {
EnumPropertyItem *item, *item_array = NULL;
bool free;
- uiLayout *split;
+ uiLayout *split = NULL;
uiLayout *target;
if (radial) {
@@ -958,7 +966,7 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
else {
/* Do not use uiItemL here, as our root layout is a menu one, it will add a fake blank icon! */
- but = uiDefBut(block, LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL,
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL,
0.0, 0.0, 0, 0, "");
}
ui_but_tip_from_enum_item(but, item);
@@ -977,6 +985,9 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
if (free) {
MEM_freeN(item_array);
}
+
+ /* intentionally don't touch UI_BLOCK_IS_FLIP here,
+ * we don't know the context this is called in */
}
else if (prop && RNA_property_type(prop) != PROP_ENUM) {
RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
@@ -1000,7 +1011,7 @@ void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char
PointerRNA ptr;
PropertyRNA *prop;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
@@ -1032,7 +1043,7 @@ void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char
int value;
bool free;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
@@ -1071,7 +1082,7 @@ void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *op
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_boolean_set(&ptr, propname, value);
@@ -1084,7 +1095,7 @@ void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_int_set(&ptr, propname, value);
@@ -1097,7 +1108,7 @@ void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opna
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_float_set(&ptr, propname, value);
@@ -1110,7 +1121,7 @@ void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opn
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, propname, value);
@@ -1125,8 +1136,9 @@ void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
/* RNA property items */
-static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
- int index, int icon_only, int *r_w, int *r_h)
+static void ui_item_rna_size(
+ uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
+ int index, bool icon_only, int *r_w, int *r_h)
{
PropertyType type;
PropertySubType subtype;
@@ -1196,10 +1208,11 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
uiBut *but = NULL;
PropertyType type;
char namestr[UI_MAX_NAME_STR];
- int len, w, h, slider, toggle, expand, icon_only, no_bg;
+ int len, w, h;
+ bool slider, toggle, expand, icon_only, no_bg;
bool is_array;
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
/* retrieve info */
type = RNA_property_type(prop);
@@ -1232,7 +1245,11 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
name = ui_item_name_add_colon(name, namestr);
}
- if (layout->root->type == UI_LAYOUT_MENU) {
+ /* menus and pie-menus don't show checkbox without this */
+ if ((layout->root->type == UI_LAYOUT_MENU) ||
+ /* use checkboxes only as a fallback in pie-menu's, when no icon is defined */
+ ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE)))
+ {
if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) {
if (is_array) icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
else icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
@@ -1248,17 +1265,17 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
}
}
- slider = (flag & UI_ITEM_R_SLIDER);
- toggle = (flag & UI_ITEM_R_TOGGLE);
- expand = (flag & UI_ITEM_R_EXPAND);
- icon_only = (flag & UI_ITEM_R_ICON_ONLY);
- no_bg = (flag & UI_ITEM_R_NO_BG);
+ slider = (flag & UI_ITEM_R_SLIDER) != 0;
+ toggle = (flag & UI_ITEM_R_TOGGLE) != 0;
+ expand = (flag & UI_ITEM_R_EXPAND) != 0;
+ icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0;
+ no_bg = (flag & UI_ITEM_R_NO_BG) != 0;
/* get size */
ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
if (no_bg)
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* array property */
if (index == RNA_NO_INDEX && is_array)
@@ -1266,11 +1283,11 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
/* enum item */
else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
if (icon && name[0] && !icon_only)
- uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ uiDefIconTextButR_prop(block, UI_BTYPE_ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
else if (icon)
- uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
else
- uiDefButR_prop(block, ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ uiDefButR_prop(block, UI_BTYPE_ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
}
/* expanded enum */
else if (type == PROP_ENUM && (expand || RNA_property_flag(prop) & PROP_ENUM_FLAG))
@@ -1281,29 +1298,29 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
ui_but_add_search(but, ptr, prop, NULL, NULL);
if (layout->redalert)
- uiButSetFlag(but, UI_BUT_REDALERT);
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
}
/* single button */
else {
but = uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
- if (slider && but->type == NUM)
- but->type = NUMSLI;
+ if (slider && but->type == UI_BTYPE_NUM)
+ but->type = UI_BTYPE_NUM_SLIDER;
- if (toggle && but->type == OPTION)
- but->type = TOG;
+ if (toggle && but->type == UI_BTYPE_CHECKBOX)
+ but->type = UI_BTYPE_TOGGLE;
if (layout->redalert)
- uiButSetFlag(but, UI_BUT_REDALERT);
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
}
/* Mark non-embossed textfields inside a listbox. */
- if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == TEX) && (but->dt & UI_EMBOSSN)) {
- uiButSetFlag(but, UI_BUT_LIST_ITEM);
+ if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) && (but->dt & UI_EMBOSS_NONE)) {
+ UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
}
if (no_bg)
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
/* ensure text isn't added to icon_only buttons */
if (but && icon_only) {
@@ -1325,11 +1342,23 @@ void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, int flag,
uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
}
+void uiItemEnumR_prop(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, PropertyRNA *prop, int value)
+{
+ if (RNA_property_type(prop) != PROP_ENUM) {
+ const char *propname = RNA_property_identifier(prop);
+ ui_item_disabled(layout, propname);
+ RNA_warning("property not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
+}
+
void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
- if (!prop || RNA_property_type(prop) != PROP_ENUM) {
+ if (prop == NULL) {
ui_item_disabled(layout, propname);
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
@@ -1405,7 +1434,7 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname
for (i = 0; i < totitem; i++) {
if (item[i].identifier[0]) {
- uiItemEnumR(column, item[i].name, ICON_NONE, ptr, propname, item[i].value);
+ uiItemEnumR_prop(column, item[i].name, item[i].icon, ptr, prop, item[i].value);
ui_but_tip_from_enum_item(block->buttons.last, &item[i]);
}
else {
@@ -1431,6 +1460,9 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname
MEM_freeN(item);
}
}
+
+ /* intentionally don't touch UI_BLOCK_IS_FLIP here,
+ * we don't know the context this is called in */
}
/* Pointer RNA button with search */
@@ -1444,8 +1476,8 @@ typedef struct CollItemSearch {
static int sort_search_items_list(const void *a, const void *b)
{
- CollItemSearch *cis1 = (CollItemSearch *)a;
- CollItemSearch *cis2 = (CollItemSearch *)b;
+ const CollItemSearch *cis1 = a;
+ const CollItemSearch *cis2 = b;
if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
return 1;
@@ -1460,7 +1492,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, const char *s
int i = 0, iconid = 0, flag = RNA_property_flag(but->rnaprop);
ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
CollItemSearch *cis;
- const int skip_filter = !but->changed;
+ const bool skip_filter = !but->changed;
/* build a temporary list of relevant items first */
RNA_PROP_BEGIN (&but->rnasearchpoin, itemptr, but->rnasearchprop)
@@ -1486,7 +1518,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, const char *s
BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
#endif
name = BLI_strdup(name_ui);
- iconid = ui_id_icon_get((bContext *)C, id, false);
+ iconid = ui_id_icon_get(C, id, false);
}
else {
name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
@@ -1508,11 +1540,11 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, const char *s
}
RNA_PROP_END;
- BLI_sortlist(items_list, sort_search_items_list);
+ BLI_listbase_sort(items_list, sort_search_items_list);
/* add search items from temporary list */
for (cis = items_list->first; cis; cis = cis->next) {
- if (false == uiSearchItemAdd(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
+ if (false == UI_search_item_add(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
break;
}
}
@@ -1564,11 +1596,14 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
/* turn button into search button */
if (searchprop) {
- but->type = RNA_property_is_unlink(prop) ? SEARCH_MENU_UNLINK : SEARCH_MENU;
+ but->type = UI_BTYPE_SEARCH_MENU;
but->hardmax = MAX2(but->hardmax, 256.0f);
but->rnasearchpoin = *searchptr;
but->rnasearchprop = searchprop;
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
+ if (RNA_property_is_unlink(prop)) {
+ but->flag |= UI_BUT_SEARCH_UNLINK;
+ }
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
@@ -1576,7 +1611,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
but->str[0] = 0;
}
- uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
+ UI_but_func_search_set(but, rna_search_cb, but, NULL, NULL);
}
}
@@ -1663,19 +1698,23 @@ static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
if (layout->context)
CTX_store_set(C, NULL);
+
+ /* menus are created flipped (from event handling pov) */
+ layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
}
-static uiBut *ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
- const char *tip, bool force_menu)
+static uiBut *ui_item_menu(
+ uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
+ const char *tip, bool force_menu)
{
uiBlock *block = layout->root->block;
uiBut *but;
int w, h;
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (layout->root->type == UI_LAYOUT_HEADER)
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
if (!name)
name = "";
@@ -1709,12 +1748,12 @@ static uiBut *ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuC
}
if (layout->root->type == UI_LAYOUT_HEADER) {
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
(force_menu && layout->root->type != UI_LAYOUT_MENU)) /* We never want a dropdown in menu! */
{
- uiButSetMenuFromPulldown(but);
+ UI_but_type_set_menu_from_pulldown(but);
}
return but;
@@ -1748,7 +1787,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
uiBut *but;
int w;
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (!name)
name = "";
@@ -1758,11 +1797,11 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
w = ui_text_icon_width(layout, name, icon, 0);
if (icon && name[0])
- but = uiDefIconTextBut(block, LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but = uiDefIconTextBut(block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
else if (icon)
- but = uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
else
- but = uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
/* to compensate for string size padding in ui_text_icon_width,
* make text aligned right if the layout is aligned right.
@@ -1791,7 +1830,7 @@ void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
if (ptr && ptr->type)
if (RNA_struct_is_ID(ptr->type))
- uiButSetDragID(but, ptr->id.data);
+ UI_but_drag_set_id(but, ptr->id.data);
}
@@ -1803,7 +1842,7 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
int *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
int w;
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (!name)
name = "";
@@ -1813,11 +1852,11 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
w = ui_text_icon_width(layout, name, icon, 0);
if (icon && name[0])
- uiDefIconTextButI(block, BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
+ uiDefIconTextButI(block, UI_BTYPE_BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
else if (icon)
- uiDefIconButI(block, BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
+ uiDefIconButI(block, UI_BTYPE_BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
else
- uiDefButI(block, BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
+ uiDefButI(block, UI_BTYPE_BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
}
/* separator item */
@@ -1827,8 +1866,8 @@ void uiItemS(uiLayout *layout)
bool is_menu = ui_block_is_menu(block);
int space = (is_menu) ? 0.45f * UI_UNIT_X : 0.3f * UI_UNIT_X;
- uiBlockSetCurLayout(block, layout);
- uiDefBut(block, (is_menu) ? SEPRLINE : SEPR, 0, "", 0, 0, space, space, NULL, 0.0, 0.0, 0, 0, "");
+ UI_block_layout_set_current(block, layout);
+ uiDefBut(block, (is_menu) ? UI_BTYPE_SEPR_LINE : UI_BTYPE_SEPR, 0, "", 0, 0, space, space, NULL, 0.0, 0.0, 0, 0, "");
}
/* level items */
@@ -1856,8 +1895,10 @@ static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, vo
uiLayoutSetOperatorContext(layout, lvl->opcontext);
uiItemsEnumO(layout, lvl->opname, lvl->propname);
+ layout->root->block->flag |= UI_BLOCK_IS_FLIP;
+
/* override default, needed since this was assumed pre 2.70 */
- uiBlockSetDirection(layout->root->block, UI_DOWN);
+ UI_block_direction_set(layout->root->block, UI_DIR_DOWN);
}
void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const char *propname, const char *name, int icon)
@@ -1866,7 +1907,7 @@ void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const ch
MenuItemLevel *lvl;
uiBut *but;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
if (!ot->srna) {
ui_item_disabled(layout, opname);
@@ -1895,7 +1936,7 @@ void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const ch
{
char keybuf[128];
if (WM_key_event_operator_string(C, ot->idname, layout->root->opcontext, NULL, false,
- keybuf, sizeof(keybuf)))
+ sizeof(keybuf), keybuf))
{
ui_but_add_shortcut(but, keybuf, false);
}
@@ -1908,19 +1949,12 @@ static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void
uiLayoutSetOperatorContext(layout, lvl->opcontext);
uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
+ layout->root->block->flag |= UI_BLOCK_IS_FLIP;
}
-void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
+void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon)
{
MenuItemLevel *lvl;
- PropertyRNA *prop;
-
- prop = RNA_struct_find_property(ptr, propname);
- if (!prop) {
- ui_item_disabled(layout, propname);
- RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
- return;
- }
if (!name)
name = RNA_property_ui_name(prop);
@@ -1929,12 +1963,26 @@ void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propn
lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
lvl->rnapoin = *ptr;
- BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
+ BLI_strncpy(lvl->propname, RNA_property_identifier(prop), sizeof(lvl->propname));
lvl->opcontext = layout->root->opcontext;
ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl, RNA_property_description(prop), false);
}
+void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(ptr, propname);
+ if (!prop) {
+ ui_item_disabled(layout, propname);
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
+}
+
/**************************** Layout Items ***************************/
/* single-row layout */
@@ -2118,7 +2166,11 @@ static void ui_litem_layout_column(uiLayout *litem)
static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
{
RadialDirection dir;
- BLI_assert(itemnum < 8);
+
+ if (itemnum >= 8) {
+ itemnum %= 8;
+ printf("Warning: Pie menus with more than 8 items are currently unsupported\n");
+ }
dir = ui_radial_dir_order[itemnum];
ui_but_pie_dir(dir, vec);
@@ -2129,7 +2181,7 @@ static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
static bool ui_item_is_radial_displayable(uiItem *item)
{
- if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == LABEL))
+ if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == UI_BTYPE_LABEL))
return false;
return true;
@@ -2138,7 +2190,7 @@ static bool ui_item_is_radial_displayable(uiItem *item)
static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
{
- if (ELEM(bitem->but->type, SEPR, SEPRLINE))
+ if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE))
return false;
return true;
@@ -2194,7 +2246,7 @@ static void ui_litem_layout_radial(uiLayout *litem)
bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
/* enable drawing as pie item if supported by widget */
if (ui_item_is_radial_drawable(bitem))
- bitem->but->dt = UI_EMBOSSR;
+ bitem->but->dt = UI_EMBOSS_RADIAL;
}
ui_item_size(item, &itemw, &itemh);
@@ -2499,7 +2551,7 @@ static void ui_litem_layout_split(uiLayout *litem)
uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem;
uiItem *item;
float percentage;
- const int tot = BLI_countlist(&litem->items);
+ const int tot = BLI_listbase_count(&litem->items);
int itemh, x, y, w, colw = 0;
if (tot == 0)
@@ -2587,7 +2639,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align)
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
- uiBlockSetCurLayout(layout->root->block, litem);
+ UI_block_layout_set_current(layout->root->block, litem);
return litem;
}
@@ -2608,7 +2660,7 @@ uiLayout *uiLayoutColumn(uiLayout *layout, int align)
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
- uiBlockSetCurLayout(layout->root->block, litem);
+ UI_block_layout_set_current(layout->root->block, litem);
return litem;
}
@@ -2630,7 +2682,7 @@ uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
flow->number = number;
BLI_addtail(&layout->items, flow);
- uiBlockSetCurLayout(layout->root->block, &flow->litem);
+ UI_block_layout_set_current(layout->root->block, &flow->litem);
return &flow->litem;
}
@@ -2650,7 +2702,7 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
box->litem.w = layout->w;
BLI_addtail(&layout->items, box);
- uiBlockSetCurLayout(layout->root->block, &box->litem);
+ UI_block_layout_set_current(layout->root->block, &box->litem);
box->roundbox = uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
@@ -2670,7 +2722,7 @@ uiLayout *uiLayoutRadial(uiLayout *layout)
for (item = layout->root->layout->items.first; item; item = item->next) {
litem = (uiLayout *)item;
if (litem->item.type == ITEM_LAYOUT_RADIAL) {
- uiBlockSetCurLayout(layout->root->block, litem);
+ UI_block_layout_set_current(layout->root->block, litem);
return litem;
}
}
@@ -2685,7 +2737,7 @@ uiLayout *uiLayoutRadial(uiLayout *layout)
litem->w = layout->w;
BLI_addtail(&layout->root->layout->items, litem);
- uiBlockSetCurLayout(layout->root->block, litem);
+ UI_block_layout_set_current(layout->root->block, litem);
return litem;
}
@@ -2693,10 +2745,11 @@ uiLayout *uiLayoutRadial(uiLayout *layout)
uiLayout *uiLayoutBox(uiLayout *layout)
{
- return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
+ return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
}
-/* Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
+/**
+ * Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
* Needed to handle correctly text colors of active (selected) list item.
*/
void ui_layout_list_set_labels_active(uiLayout *layout)
@@ -2707,15 +2760,16 @@ void ui_layout_list_set_labels_active(uiLayout *layout)
ui_layout_list_set_labels_active((uiLayout *)(&bitem->item));
}
else if (bitem->but->flag & UI_BUT_LIST_ITEM) {
- uiButSetFlag(bitem->but, UI_SELECT);
+ UI_but_flag_enable(bitem->but, UI_SELECT);
}
}
}
-uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
- PropertyRNA *actprop)
+uiLayout *uiLayoutListBox(
+ uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
+ PropertyRNA *actprop)
{
- uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX);
+ uiLayoutItemBx *box = ui_layout_box(layout, UI_BTYPE_LISTBOX);
uiBut *but = box->roundbox;
but->custom_data = ui_list;
@@ -2747,7 +2801,7 @@ uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
litem->redalert = layout->redalert;
BLI_addtail(&layout->items, litem);
- uiBlockSetCurLayout(layout->root->block, litem);
+ UI_block_layout_set_current(layout->root->block, litem);
return litem;
}
@@ -2775,7 +2829,7 @@ uiLayout *uiLayoutOverlap(uiLayout *layout)
litem->redalert = layout->redalert;
BLI_addtail(&layout->items, litem);
- uiBlockSetCurLayout(layout->root->block, litem);
+ UI_block_layout_set_current(layout->root->block, litem);
return litem;
}
@@ -2797,7 +2851,7 @@ uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align)
split->percentage = percentage;
BLI_addtail(&layout->items, split);
- uiBlockSetCurLayout(layout->root->block, &split->litem);
+ UI_block_layout_set_current(layout->root->block, &split->litem);
return &split->litem;
}
@@ -3052,7 +3106,7 @@ static void ui_item_layout(uiItem *item)
static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y)
{
if (layout->root->handlefunc)
- uiBlockSetHandleFunc(block, layout->root->handlefunc, layout->root->argv);
+ UI_block_func_handle_set(block, layout->root->handlefunc, layout->root->argv);
ui_item_estimate(&layout->item);
ui_item_layout(&layout->item);
@@ -3085,12 +3139,12 @@ static void ui_layout_add_padding_button(uiLayoutRoot *root)
uiLayout *prev_layout = block->curlayout;
block->curlayout = root->layout;
- uiDefBut(block, SEPR, 0, "", 0, 0, root->padding, root->padding, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_SEPR, 0, "", 0, 0, root->padding, root->padding, NULL, 0.0, 0.0, 0, 0, "");
block->curlayout = prev_layout;
}
}
-uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, uiStyle *style)
+uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, uiStyle *style)
{
uiLayout *layout;
uiLayoutRoot *root;
@@ -3145,7 +3199,7 @@ int uiLayoutGetOperatorContext(uiLayout *layout)
}
-void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
+void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
{
block->curlayout = layout;
}
@@ -3176,7 +3230,7 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
layout->root->argv = argv;
}
-void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
+void UI_block_layout_resolve(uiBlock *block, int *x, int *y)
{
uiLayoutRoot *root;
@@ -3252,7 +3306,7 @@ static void ui_intro_items(DynStr *ds, ListBase *lb)
/* could also use the INT but this is nicer*/
switch (item->type) {
case ITEM_BUTTON: BLI_dynstr_append(ds, "'type':'BUTTON', "); break;
- case ITEM_LAYOUT_ROW: BLI_dynstr_append(ds, "'type':'ROW', "); break;
+ case ITEM_LAYOUT_ROW: BLI_dynstr_append(ds, "'type':'UI_BTYPE_ROW', "); break;
case ITEM_LAYOUT_COLUMN: BLI_dynstr_append(ds, "'type':'COLUMN', "); break;
case ITEM_LAYOUT_COLUMN_FLOW: BLI_dynstr_append(ds, "'type':'COLUMN_FLOW', "); break;
case ITEM_LAYOUT_ROW_FLOW: BLI_dynstr_append(ds, "'type':'ROW_FLOW', "); break;
@@ -3312,9 +3366,10 @@ static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt,
#endif
/* this function does not initialize the layout, functions can be called on the layout before and after */
-void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
- bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
- const char label_align, const short flag)
+void uiLayoutOperatorButs(
+ const bContext *C, uiLayout *layout, wmOperator *op,
+ bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
+ const char label_align, const short flag)
{
if (!op->properties) {
IDPropertyTemplate val = {0};
@@ -3328,11 +3383,15 @@ void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
/* poll() on this operator may still fail, at the moment there is no nice feedback when this happens
* just fails silently */
if (!WM_operator_repeat_check(C, op)) {
- uiBlockSetButLock(uiLayoutGetBlock(layout), true, "Operator can't' redo");
+ UI_block_lock_set(uiLayoutGetBlock(layout), true, "Operator can't' redo");
/* XXX, could give some nicer feedback or not show redo panel at all? */
uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE);
}
+ else {
+ /* useful for macros where only one of the steps can't be re-done */
+ UI_block_lock_clear(uiLayoutGetBlock(layout));
+ }
/* menu */
if (op->type->flag & OPTYPE_PRESET) {
@@ -3388,9 +3447,9 @@ void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
col = uiLayoutColumn(layout, false);
block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block, BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults"));
- uiButSetFunc(but, ui_layout_operator_buts__reset_cb, op, NULL);
+ UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
}
#endif
@@ -3403,7 +3462,7 @@ void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
for (but = block->buttons.first; but; but = but->next) {
/* no undo for buttons for operator redo panels */
- uiButClearFlag(but, UI_BUT_UNDO);
+ UI_but_flag_disable(but, UI_BUT_UNDO);
/* only for popups, see [#36109] */
@@ -3411,8 +3470,8 @@ void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
* - this is used for allowing operators with popups to rename stuff with fewer clicks
*/
if (is_popup) {
- if ((but->rnaprop == op->type->prop) && (but->type == TEX)) {
- uiButSetFocusOnEnter(CTX_wm_window(C), but);
+ if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
+ UI_but_focus_on_enter_event(CTX_wm_window(C), but);
}
}
}
@@ -3420,7 +3479,7 @@ void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
}
/* this is a bit of a hack but best keep it in one place at least */
-MenuType *uiButGetMenuType(uiBut *but)
+MenuType *UI_but_menutype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_menutype_func) {
return (MenuType *)but->poin;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 817445cc14e..6ac657fa7a3 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -33,19 +33,20 @@
#include "DNA_screen_types.h"
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_lang.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "BKE_node.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
-#include "BKE_paint.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -98,7 +99,7 @@ static int copy_data_path_button_poll(bContext *C)
char *path;
int index;
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -120,7 +121,7 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
int index;
/* try to create driver using property retrieved from UI */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -160,7 +161,7 @@ static int operator_button_property_finish(bContext *C, PointerRNA *ptr, Propert
RNA_property_update(C, ptr, prop);
/* as if we pressed the button */
- uiContextActivePropertyHandle(C);
+ UI_context_active_but_prop_handle(C);
/* Since we don't want to undo _all_ edits to settings, eg window
* edits on the screen or on operator settings.
@@ -180,7 +181,7 @@ static int reset_default_button_poll(bContext *C)
PropertyRNA *prop;
int index;
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
return (ptr.data && prop && RNA_property_editable(&ptr, prop));
}
@@ -193,7 +194,7 @@ static int reset_default_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to reset the nominated setting to its default value */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* if there is a valid property that is editable... */
if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
@@ -231,7 +232,7 @@ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
int index;
/* try to unset the nominated property */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* if there is a valid property that is editable... */
if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
@@ -262,7 +263,7 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
/* Copy To Selected Operator ------------------------ */
-static bool copy_to_selected_list(
+bool UI_context_copy_to_selected_list(
bContext *C, PointerRNA *ptr, PropertyRNA *prop,
ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
{
@@ -275,9 +276,66 @@ static bool copy_to_selected_list(
else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
*r_lb = CTX_data_collection_get(C, "selected_pose_bones");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
+ ListBase lb;
+ lb = CTX_data_collection_get(C, "selected_pose_bones");
+
+ if (!BLI_listbase_is_empty(&lb)) {
+ CollectionPointerLink *link;
+ for (link = lb.first; link; link = link->next) {
+ bPoseChannel *pchan = link->ptr.data;
+ RNA_pointer_create(link->ptr.id.data, &RNA_Bone, pchan->bone, &link->ptr);
+ }
+ }
+
+ *r_lb = lb;
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_Node) ||
+ RNA_struct_is_a(ptr->type, &RNA_NodeSocket))
+ {
+ ListBase lb = {NULL, NULL};
+ char *path = NULL;
+ bNode *node = NULL;
+
+ /* Get the node we're editing */
+ if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
+ bNodeTree *ntree = ptr->id.data;
+ bNodeSocket *sock = ptr->data;
+ if (nodeFindNode(ntree, sock, &node, NULL)) {
+ if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) {
+ /* we're good! */
+ }
+ else {
+ node = NULL;
+ }
+ }
+ }
+ else {
+ node = ptr->data;
+ }
+
+ /* Now filter by type */
+ if (node) {
+ CollectionPointerLink *link, *link_next;
+ lb = CTX_data_collection_get(C, "selected_nodes");
+
+ for (link = lb.first; link; link = link_next) {
+ bNode *node_data = link->ptr.data;
+ link_next = link->next;
+
+ if (node_data->type != node->type) {
+ BLI_remlink(&lb, link);
+ MEM_freeN(link);
+ }
+ }
+ }
+
+ *r_lb = lb;
+ *r_path = path;
+ }
else if (ptr->id.data) {
ID *id = ptr->id.data;
@@ -286,6 +344,51 @@ static bool copy_to_selected_list(
*r_use_path_from_id = true;
*r_path = RNA_path_from_ID_to_property(ptr, prop);
}
+ else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
+ /* check we're using the active object */
+ const short id_code = GS(id->name);
+ ListBase lb = CTX_data_collection_get(C, "selected_editable_objects");
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
+
+ /* de-duplicate obdata */
+ if (!BLI_listbase_is_empty(&lb)) {
+ CollectionPointerLink *link, *link_next;
+
+ for (link = lb.first; link; link = link->next) {
+ Object *ob = link->ptr.id.data;
+ if (ob->data) {
+ ID *id_data = ob->data;
+ id_data->flag |= LIB_DOIT;
+ }
+ }
+
+ for (link = lb.first; link; link = link_next) {
+ Object *ob = link->ptr.id.data;
+ ID *id_data = ob->data;
+ link_next = link->next;
+
+ if ((id_data == NULL) ||
+ (id_data->flag & LIB_DOIT) == 0 ||
+ (id_data->lib) ||
+ (GS(id_data->name) != id_code))
+ {
+ BLI_remlink(&lb, link);
+ MEM_freeN(link);
+ }
+ else {
+ /* avoid prepending 'data' to the path */
+ RNA_id_pointer_create(id_data, &link->ptr);
+ }
+
+ if (id_data) {
+ id_data->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+
+ *r_lb = lb;
+ *r_path = path;
+ }
else if (GS(id->name) == ID_SCE) {
/* Sequencer's ID is scene :/ */
/* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
@@ -317,7 +420,7 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
int index;
/* try to reset the nominated setting to its default value */
- uiContextActiveProperty(C, &ptr, &prop, &index);
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* if there is a valid property that is editable... */
if (ptr.data && prop) {
@@ -326,7 +429,7 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
CollectionPointerLink *link;
ListBase lb;
- if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
+ if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
return success;
for (link = lb.first; link; link = link->next) {
@@ -516,7 +619,7 @@ static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
(but_a->rnaprop == but_b->rnaprop) &&
(but_a->optype == but_b->optype) &&
(but_a->unit_type == but_b->unit_type) &&
- (strncmp(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR) == 0))
+ STREQLEN(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR))
{
return true;
}
@@ -554,8 +657,9 @@ void UI_editsource_active_but_test(uiBut *but)
BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
}
-static int editsource_text_edit(bContext *C, wmOperator *op,
- char filepath[FILE_MAX], int line)
+static int editsource_text_edit(
+ bContext *C, wmOperator *op,
+ char filepath[FILE_MAX], int line)
{
struct Main *bmain = CTX_data_main(C);
Text *text;
@@ -595,7 +699,7 @@ static int editsource_text_edit(bContext *C, wmOperator *op,
static int editsource_exec(bContext *C, wmOperator *op)
{
- uiBut *but = uiContextActiveButton(C);
+ uiBut *but = UI_context_active_but_get(C);
if (but) {
GHashIterator ghi;
@@ -605,7 +709,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
int ret;
/* needed else the active button does not get tested */
- uiFreeActiveButtons(C, CTX_wm_screen(C));
+ UI_screen_free_active_but(C, CTX_wm_screen(C));
// printf("%s: begin\n", __func__);
@@ -614,6 +718,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
/* redraw and get active button python info */
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
BLI_ghashIterator_done(&ghi) == false;
@@ -668,10 +773,12 @@ static void UI_OT_editsource(wmOperatorType *ot)
}
/* ------------------------------------------------------------------------- */
-/* EditTranslation utility funcs and operator,
- * Note: this includes utility functions and button matching checks.
- * this only works in conjunction with a py operator! */
+/**
+ * EditTranslation utility funcs and operator,
+ * \note: this includes utility functions and button matching checks.
+ * this only works in conjunction with a py operator!
+ */
static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen)
{
char tstr[32]; /* Should be more than enough! */
@@ -715,7 +822,7 @@ static void edittranslation_find_po_file(const char *root, const char *uilng, ch
static int edittranslation_exec(bContext *C, wmOperator *op)
{
- uiBut *but = uiContextActiveButton(C);
+ uiBut *but = UI_context_active_but_get(C);
int ret = OPERATOR_CANCELLED;
if (but) {
@@ -723,7 +830,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
PointerRNA ptr;
char popath[FILE_MAX];
const char *root = U.i18ndir;
- const char *uilng = BLF_lang_get();
+ const char *uilng = BLT_lang_get();
uiStringInfo but_label = {BUT_GET_LABEL, NULL};
uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL};
@@ -755,7 +862,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- uiButGetStrInfo(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
+ UI_but_string_info_get(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
&rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL);
WM_operator_properties_create_ptr(&ptr, ot);
@@ -818,9 +925,9 @@ static void UI_OT_edittranslation_init(wmOperatorType *ot)
static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
- BLF_lang_init();
+ BLT_lang_init();
BLF_cache_clear();
- BLF_lang_set(NULL);
+ BLT_lang_set(NULL);
UI_reinit_font();
return OPERATOR_FINISHED;
}
@@ -859,7 +966,7 @@ int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(e
void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
{
- uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin;
+ uiDragColorHandle *drag_info = drag->poin;
RNA_float_set_array(drop->ptr, "color", drag_info->color);
RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
@@ -877,9 +984,9 @@ static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
/* find button under mouse, check if it has RNA color property and
* if it does copy the data */
- but = ui_but_find_activated(ar);
+ but = ui_but_find_active_in_region(ar);
- if (but && but->type == COLOR && but->rnaprop) {
+ if (but && but->type == UI_BTYPE_COLOR && but->rnaprop) {
const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
BLI_assert(color_len <= 4);
@@ -890,13 +997,13 @@ static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
if (!gamma)
- ui_block_to_display_space_v3(but->block, color);
+ ui_block_cm_to_display_space_v3(but->block, color);
RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
}
else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
if (gamma)
- ui_block_to_scene_linear_v3(but->block, color);
+ ui_block_cm_to_scene_linear_v3(but->block, color);
RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
RNA_property_update(C, &but->rnapoin, but->rnaprop);
}
@@ -922,6 +1029,7 @@ static void UI_OT_drop_color(wmOperatorType *ot)
ot->description = "Drop colors to buttons";
ot->invoke = drop_color_invoke;
+ ot->flag = OPTYPE_INTERNAL;
RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
@@ -932,7 +1040,7 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/* ********************************************************* */
/* Registration */
-void UI_buttons_operatortypes(void)
+void ED_button_operatortypes(void)
{
WM_operatortype_append(UI_OT_reset_default_theme);
WM_operatortype_append(UI_OT_copy_data_path_button);
@@ -950,4 +1058,5 @@ void UI_buttons_operatortypes(void)
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
WM_operatortype_append(UI_OT_eyedropper_id);
+ WM_operatortype_append(UI_OT_eyedropper_depth);
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 9265ca0d4b9..5ee7556a042 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -43,7 +43,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_userdef_types.h"
@@ -82,6 +82,14 @@
/* only show pin header button for pinned panels */
#define USE_PIN_HIDDEN
+/* the state of the mouse position relative to the panel */
+typedef enum uiPanelMouseState {
+ PANEL_MOUSE_OUTSIDE, /* mouse is not in the panel */
+ PANEL_MOUSE_INSIDE_CONTENT, /* mouse is in the actual panel content */
+ PANEL_MOUSE_INSIDE_HEADER, /* mouse is in the panel header */
+ PANEL_MOUSE_INSIDE_SCALE, /* mouse is inside panel scale widget */
+} uiPanelMouseState;
+
typedef enum uiHandlePanelState {
PANEL_STATE_DRAG,
PANEL_STATE_DRAG_SCALE,
@@ -202,12 +210,13 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
}
-/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
- * See also T41704.
+/**
+ * XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
+ * See also T41704.
*/
/* #define UI_USE_PANELTAB */
-Panel *uiPanelFindByType(ARegion *ar, PanelType *pt)
+Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
{
Panel *pa;
const char *idname = pt->idname;
@@ -233,9 +242,9 @@ Panel *uiPanelFindByType(ARegion *ar, PanelType *pt)
}
/**
- * \note \a pa should be return value from #uiPanelFindByType and can be NULL.
+ * \note \a pa should be return value from #UI_panel_find_by_type and can be NULL.
*/
-Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
+Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
{
Panel *palast, *panext;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
@@ -336,7 +345,7 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
return pa;
}
-void uiEndPanel(uiBlock *block, int width, int height)
+void UI_panel_end(uiBlock *block, int width, int height)
{
Panel *pa = block->panel;
@@ -363,12 +372,12 @@ void uiEndPanel(uiBlock *block, int width, int height)
static void ui_offset_panel_block(uiBlock *block)
{
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
uiBut *but;
int ofsy;
/* compute bounds and offset */
- ui_bounds_block(block);
+ ui_block_bounds_calc(block);
ofsy = block->panel->sizey - style->panelspace;
@@ -401,7 +410,7 @@ static void uiPanelPop(uiBlock *UNUSED(block))
#endif
/* triangle 'icon' for panel header */
-void UI_DrawTriIcon(float x, float y, char dir)
+void UI_draw_icon_tri(float x, float y, char dir)
{
float f3 = 0.15 * U.widget_unit;
float f5 = 0.25 * U.widget_unit;
@@ -542,14 +551,14 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r
if (dir == 'h') {
hrect.xmin = rect->xmin + pnl_icons;
hrect.ymin += 2.0f / block->aspect;
- uiStyleFontDraw(&style->paneltitle, &hrect, activename);
+ UI_fontstyle_draw(&style->paneltitle, &hrect, activename);
}
else {
/* ignore 'pnl_icons', otherwise the text gets offset horizontally
* + 0.001f to avoid flirting with float inaccuracy
*/
hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f;
- uiStyleFontDrawRotated(&style->paneltitle, &hrect, activename);
+ UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename);
}
}
@@ -560,6 +569,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
rcti headrect;
rctf itemrect;
int ofsx;
+ const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
+ const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false;
if (panel->paneltab) return;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
@@ -572,7 +583,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
{
float minx = rect->xmin;
- float maxx = rect->xmax;
+ float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
glEnable(GL_BLEND);
@@ -587,8 +598,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
else if (!(panel->runtime_flag & PNL_FIRST)) {
/* draw embossed separator */
- minx += 5.0f / block->aspect;
- maxx -= 5.0f / block->aspect;
+
+ if (is_closed_x == false) {
+ minx += 5.0f / block->aspect;
+ maxx -= 5.0f / block->aspect;
+ }
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
fdrawline(minx, y, maxx, y);
@@ -615,7 +629,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
/* horizontal title */
- if (!(panel->flag & PNL_CLOSEDX)) {
+ if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &headrect, 'h');
/* itemrect smaller */
@@ -631,9 +645,10 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
/* if the panel is minimized vertically:
* (------)
*/
- if (panel->flag & PNL_CLOSEDY) {
+ if (is_closed_y) {
+ /* skip */
}
- else if (panel->flag & PNL_CLOSEDX) {
+ else if (is_closed_x) {
/* draw vertical title */
ui_draw_aligned_panel_header(style, block, &headrect, 'v');
}
@@ -641,11 +656,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
else {
/* in some occasions, draw a border */
if (panel->flag & PNL_SELECT) {
- if (panel->control & UI_PNL_SOLID) uiSetRoundBox(UI_CNR_ALL);
- else uiSetRoundBox(UI_CNR_NONE);
+ if (panel->control & UI_PNL_SOLID) UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ else UI_draw_roundbox_corner_set(UI_CNR_NONE);
UI_ThemeColorShade(TH_BACK, -120);
- uiRoundRect(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8);
+ UI_draw_roundbox_unfilled(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8);
}
/* panel backdrop */
@@ -680,9 +695,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
BLI_rctf_scale(&itemrect, 0.35f);
- if (panel->flag & PNL_CLOSEDY)
+ if (is_closed_y)
ui_draw_tria_rect(&itemrect, 'h');
- else if (panel->flag & PNL_CLOSEDX)
+ else if (is_closed_x)
ui_draw_tria_rect(&itemrect, 'h');
else
ui_draw_tria_rect(&itemrect, 'v');
@@ -729,11 +744,13 @@ typedef struct PanelSort {
Panel *pa, *orig;
} PanelSort;
-/* note about sorting;
+/**
+ * \note about sorting;
* the sortorder has a lower value for new panels being added.
* however, that only works to insert a single panel, when more new panels get
* added the coordinates of existing panels and the previously stored to-be-inserted
- * panels do not match for sorting */
+ * panels do not match for sorting
+ */
static int find_leftmost_panel(const void *a1, const void *a2)
{
@@ -753,9 +770,13 @@ static int find_highest_panel(const void *a1, const void *a2)
const PanelSort *ps1 = a1, *ps2 = a2;
/* stick uppermost header-less panels to the top of the region -
- * prevent them from being sorted */
- if (ps1->pa->sortorder < ps2->pa->sortorder && ps1->pa->type->flag & PNL_NO_HEADER) return -1;
-
+ * prevent them from being sorted (multiple header-less panels have to be sorted though) */
+ if (ps1->pa->type->flag & PNL_NO_HEADER && ps2->pa->type->flag & PNL_NO_HEADER) {
+ /* skip and check for ofs and sortorder below */
+ }
+ else if (ps1->pa->type->flag & PNL_NO_HEADER) return -1;
+ else if (ps2->pa->type->flag & PNL_NO_HEADER) return 1;
+
if (ps1->pa->ofsy + ps1->pa->sizey < ps2->pa->ofsy + ps2->pa->sizey) return 1;
else if (ps1->pa->ofsy + ps1->pa->sizey > ps2->pa->ofsy + ps2->pa->sizey) return -1;
else if (ps1->pa->sortorder > ps2->pa->sortorder) return 1;
@@ -938,7 +959,7 @@ static void ui_do_animate(const bContext *C, Panel *panel)
}
}
-void uiBeginPanels(const bContext *UNUSED(C), ARegion *ar)
+void UI_panels_begin(const bContext *UNUSED(C), ARegion *ar)
{
Panel *pa;
@@ -953,7 +974,7 @@ void uiBeginPanels(const bContext *UNUSED(C), ARegion *ar)
}
/* only draws blocks with panels */
-void uiEndPanels(const bContext *C, ARegion *ar, int *x, int *y)
+void UI_panels_end(const bContext *C, ARegion *ar, int *x, int *y)
{
ScrArea *sa = CTX_wm_area(C);
uiBlock *block;
@@ -1012,7 +1033,7 @@ void uiEndPanels(const bContext *C, ARegion *ar, int *x, int *y)
ui_panels_size(sa, ar, x, y);
}
-void uiDrawPanels(const bContext *C, ARegion *ar)
+void UI_panels_draw(const bContext *C, ARegion *ar)
{
uiBlock *block;
@@ -1021,18 +1042,18 @@ void uiDrawPanels(const bContext *C, ARegion *ar)
/* draw panels, selected on top */
for (block = ar->uiblocks.first; block; block = block->next) {
if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) {
- uiDrawBlock(C, block);
+ UI_block_draw(C, block);
}
}
for (block = ar->uiblocks.first; block; block = block->next) {
if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
- uiDrawBlock(C, block);
+ UI_block_draw(C, block);
}
}
}
-void uiScalePanels(ARegion *ar, float new_width)
+void UI_panels_scale(ARegion *ar, float new_width)
{
uiBlock *block;
uiBut *but;
@@ -1040,7 +1061,6 @@ void uiScalePanels(ARegion *ar, float new_width)
for (block = ar->uiblocks.first; block; block = block->next) {
if (block->panel) {
float fac = new_width / (float)block->panel->sizex;
- printf("scaled %f\n", fac);
block->panel->sizex = new_width;
for (but = block->buttons.first; but; but = but->next) {
@@ -1124,6 +1144,157 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/******************* region level panel interaction *****************/
+static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, const Panel *pa, const int mx, const int my)
+{
+ /* open panel */
+ if (pa->flag & PNL_CLOSEDX) {
+ if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ }
+ /* outside left/right side */
+ else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) {
+ /* pass */
+ }
+ else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ /* open panel */
+ else if (!(pa->flag & PNL_CLOSEDY)) {
+ if (pa->control & UI_PNL_SCALE) {
+ if (block->rect.xmax - PNL_HEADER <= mx) {
+ if (block->rect.ymin + PNL_HEADER >= my) {
+ return PANEL_MOUSE_INSIDE_SCALE;
+ }
+ }
+ }
+ if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) {
+ if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_CONTENT;
+ }
+ }
+ }
+ return PANEL_MOUSE_OUTSIDE;
+}
+
+typedef struct uiPanelDragCollapseHandle {
+ bool was_first_open;
+ int xy_init[2];
+} uiPanelDragCollapseHandle;
+
+static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata)
+{
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ MEM_freeN(dragcol_data);
+}
+
+static void ui_panel_drag_collapse(bContext *C, uiPanelDragCollapseHandle *dragcol_data, const int xy_dst[2])
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ uiBlock *block;
+ Panel *pa;
+
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
+ float xy_b_block[2] = {UNPACK2(xy_dst)};
+ rctf rect = block->rect;
+ int oldflag;
+ const bool is_horizontal = (panel_aligned(sa, ar) == BUT_HORIZONTAL);
+
+ if ((pa = block->panel) == 0 || (pa->type && (pa->type->flag & PNL_NO_HEADER))) {
+ continue;
+ }
+ oldflag = pa->flag;
+
+ /* lock one axis */
+ if (is_horizontal) {
+ xy_b_block[1] = dragcol_data->xy_init[1];
+ }
+ else {
+ xy_b_block[0] = dragcol_data->xy_init[0];
+ }
+
+ /* use cursor coords in block space */
+ ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]);
+ ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]);
+
+ /* set up rect to match header size */
+ rect.ymin = rect.ymax;
+ rect.ymax = rect.ymin + PNL_HEADER;
+ if (pa->flag & PNL_CLOSEDX) {
+ rect.xmax = rect.xmin + PNL_HEADER;
+ }
+
+ /* touch all panels between last mouse coord and the current one */
+ if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
+ /* force panel to close */
+ if (dragcol_data->was_first_open == true) {
+ pa->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
+ }
+ /* force panel to open */
+ else {
+ pa->flag &= ~PNL_CLOSED;
+ }
+
+ /* if pa->flag has changed this means a panel was opened/closed here */
+ if (pa->flag != oldflag) {
+ panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ }
+ }
+ }
+}
+
+/**
+ * Panel drag-collapse (modal handler)
+ * Clicking and dragging over panels toggles their collapse state based on the panel that was first
+ * dragged over. If it was open all affected panels incl the initial one are closed and vise versa.
+ */
+static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata)
+{
+ wmWindow *win = CTX_wm_window(C);
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ short retval = WM_UI_HANDLER_CONTINUE;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ ui_panel_drag_collapse(C, dragcol_data, &event->x);
+
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* done! */
+ WM_event_remove_ui_handler(
+ &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, true);
+ ui_panel_drag_collapse_handler_remove(C, dragcol_data);
+ }
+ /* don't let any left-mouse event fall through! */
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ }
+
+ return retval;
+}
+
+static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was_open)
+{
+ wmWindow *win = CTX_wm_window(C);
+ wmEvent *event = win->eventstate;
+ uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
+
+ dragcol_data->was_first_open = was_open;
+ copy_v2_v2_int(dragcol_data->xy_init, &event->x);
+
+ WM_event_add_ui_handler(
+ C, &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, 0);
+}
/* this function is supposed to call general window drawing too */
/* also it supposes a block has panel, and isn't a menu */
@@ -1183,23 +1354,39 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
ED_region_tag_redraw(ar);
}
else { /* collapse */
- if (ctrl)
+ if (ctrl) {
panels_collapse_all(sa, ar, block->panel);
+ /* reset the view - we don't want to display a view without content */
+ UI_view2d_offset(&ar->v2d, 0.0f, 1.0f);
+ }
+
if (block->panel->flag & PNL_CLOSED) {
block->panel->flag &= ~PNL_CLOSED;
/* snap back up so full panel aligns with screen edge */
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = 0;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, false);
+ }
}
else if (align == BUT_HORIZONTAL) {
block->panel->flag |= PNL_CLOSEDX;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
else {
- /* snap down to bottom screen edge*/
+ /* snap down to bottom screen edge */
block->panel->flag |= PNL_CLOSEDY;
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = -block->panel->sizey;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -1226,7 +1413,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
bool UI_panel_category_is_visible(ARegion *ar)
{
- /* more then one */
+ /* more than one */
return ar->panels_category.first && ar->panels_category.first != ar->panels_category.last;
}
@@ -1327,11 +1514,12 @@ void UI_panel_category_clear_all(ARegion *ar)
BLI_freelistN(&ar->panels_category);
}
-/* based on uiDrawBox, check on making a version which allows us to skip some sides */
-static void ui_panel_category_draw_tab(int mode, float minx, float miny, float maxx, float maxy, float rad,
- int roundboxtype,
- const bool use_highlight, const bool use_shadow,
- const unsigned char highlight_fade[3])
+/* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
+static void ui_panel_category_draw_tab(
+ int mode, float minx, float miny, float maxx, float maxy, float rad,
+ int roundboxtype,
+ const bool use_highlight, const bool use_shadow,
+ const unsigned char highlight_fade[3])
{
float vec[4][2] = {
{0.195, 0.02},
@@ -1420,7 +1608,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* no tab outlines for */
// #define USE_FLAT_INACTIVE
View2D *v2d = &ar->v2d;
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
short fstyle_points = fstyle->points;
@@ -1486,8 +1674,8 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
}
BLF_enable(fontid, BLF_ROTATION);
- BLF_rotation(fontid, M_PI / 2);
- //uiStyleFontSet(&style->widget);
+ BLF_rotation(fontid, M_PI_2);
+ //UI_fontstyle_set(&style->widget);
ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f));
BLF_size(fontid, fstyle_points, U.dpi);
@@ -1662,7 +1850,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* XXX should become modal keymap */
/* AKey is opening/closing panels, independent of button state now */
-int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
+int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, const uiBut *active_but)
{
uiBlock *block;
Panel *pa;
@@ -1690,20 +1878,26 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* first check if the mouse is in the tab region */
if (event->ctrl || (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax)) {
- const char *category = UI_panel_category_active_get(ar, false);
- if (LIKELY(category)) {
- PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
- if (LIKELY(pc_dyn)) {
- pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
- if (pc_dyn) {
- /* intentionally don't reset scroll in this case,
- * this allows for quick browsing between tabs */
- UI_panel_category_active_set(ar, pc_dyn->idname);
- ED_region_tag_redraw(ar);
+ if (active_but && ui_but_supports_cycling(active_but)) {
+ /* skip - exception to make cycling buttons
+ * using ctrl+mousewheel work in tabbed regions */
+ }
+ else {
+ const char *category = UI_panel_category_active_get(ar, false);
+ if (LIKELY(category)) {
+ PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
+ if (LIKELY(pc_dyn)) {
+ pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
+ if (pc_dyn) {
+ /* intentionally don't reset scroll in this case,
+ * this allows for quick browsing between tabs */
+ UI_panel_category_active_set(ar, pc_dyn->idname);
+ ED_region_tag_redraw(ar);
+ }
}
}
+ retval = WM_UI_HANDLER_BREAK;
}
- retval = WM_UI_HANDLER_BREAK;
}
}
}
@@ -1714,8 +1908,8 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
for (block = ar->uiblocks.last; block; block = block->prev) {
- bool inside = false, inside_header = false, inside_scale = false;
-
+ uiPanelMouseState mouse_state;
+
mx = event->x;
my = event->y;
ui_window_to_block(ar, block, &mx, &my);
@@ -1727,33 +1921,12 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
continue;
if (pa->type && pa->type->flag & PNL_NO_HEADER) /* XXX - accessed freed panels when scripts reload, need to fix. */
continue;
-
- /* clicked at panel header? */
- if (pa->flag & PNL_CLOSEDX) {
- if (block->rect.xmin <= mx && block->rect.xmin + PNL_HEADER >= mx)
- inside_header = true;
- }
- else if (block->rect.xmin > mx || block->rect.xmax < mx) {
- /* outside left/right side */
- }
- else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
- inside_header = true;
- }
- else if (!(pa->flag & PNL_CLOSEDY)) {
- /* open panel */
- if (pa->control & UI_PNL_SCALE) {
- if (block->rect.xmax - PNL_HEADER <= mx)
- if (block->rect.ymin + PNL_HEADER >= my)
- inside_scale = true;
- }
- if (block->rect.xmin <= mx && block->rect.xmax >= mx)
- if (block->rect.ymin <= my && block->rect.ymax + PNL_HEADER >= my)
- inside = true;
- }
-
+
+ mouse_state = ui_panel_mouse_state_get(block, pa, mx, my);
+
/* XXX hardcoded key warning */
- if ((inside || inside_header) && event->val == KM_PRESS) {
- if (event->type == AKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && event->val == KM_PRESS) {
+ if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
if (pa->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my))
@@ -1768,16 +1941,16 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
/* on active button, do not handle panels */
- if (ui_button_is_active(ar))
+ if (ui_but_is_active(ar))
continue;
- if (inside || inside_header) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
if (event->val == KM_PRESS) {
/* open close on header */
if (ELEM(event->type, RETKEY, PADENTER)) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_handle_panel_header(C, block, mx, my, RETKEY, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1787,12 +1960,12 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* all inside clicks should return in break - overlapping/float panels */
retval = WM_UI_HANDLER_BREAK;
- if (inside_header) {
- ui_handle_panel_header(C, block, mx, my, 0, event->ctrl, event->shift);
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
+ ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
}
- else if (inside_scale && !(pa->flag & PNL_CLOSED)) {
+ else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) {
panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1800,7 +1973,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
else if (event->type == RIGHTMOUSE) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_panel_menu(C, ar, block->panel);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1939,7 +2112,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
pa->activedata = data;
- WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
+ WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 9b450b8fdf4..0b586dd9fca 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -27,8 +27,6 @@
* \ingroup edinterface
*/
-
-
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -54,7 +52,6 @@
#include "WM_types.h"
#include "wm_draw.h"
#include "wm_subwindow.h"
-#include "wm_window.h"
#include "RNA_access.h"
@@ -65,7 +62,7 @@
#include "UI_view2d.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "ED_screen.h"
@@ -73,8 +70,9 @@
#include "interface_intern.h"
-#define MENU_TOP 8
+#define MENU_TOP (int)(8 * UI_DPI_FAC)
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
+#define MENU_BORDER (int)(0.3f * U.widget_unit)
static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction)
{
@@ -109,20 +107,27 @@ static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRN
return value;
}
-int ui_step_name_menu(uiBut *but, int direction)
+bool ui_but_menu_step_poll(const uiBut *but)
{
+ BLI_assert(but->type == UI_BTYPE_MENU);
+
/* currenly only RNA buttons */
- if ((but->rnaprop == NULL) || (RNA_property_type(but->rnaprop) != PROP_ENUM)) {
- printf("%s: cannot cycle button '%s'", __func__, but->str);
- return 0;
+ return (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM);
+}
+
+int ui_but_menu_step(uiBut *but, int direction)
+{
+ if (ui_but_menu_step_poll(but)) {
+ return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
}
- return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
+ printf("%s: cannot cycle button '%s'\n", __func__, but->str);
+ return 0;
}
/******************** Creating Temporary regions ******************/
-static ARegion *ui_add_temporary_region(bScreen *sc)
+static ARegion *ui_region_temp_add(bScreen *sc)
{
ARegion *ar;
@@ -135,7 +140,7 @@ static ARegion *ui_add_temporary_region(bScreen *sc)
return ar;
}
-static void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar)
+static void ui_region_temp_remove(bContext *C, bScreen *sc, ARegion *ar)
{
wmWindow *win = CTX_wm_window(C);
if (win)
@@ -150,13 +155,14 @@ static void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar)
#define UI_TIP_PAD_FAC 1.3f
#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y)
+#define UI_TIP_MAXWIDTH 600
#define MAX_TOOLTIP_LINES 8
typedef struct uiTooltipData {
rcti bbox;
uiFontStyle fstyle;
- char lines[MAX_TOOLTIP_LINES][512];
- char header[512], active_info[512];
+ char lines[MAX_TOOLTIP_LINES][2048];
+ char header[2048], active_info[2048];
struct {
enum {
UI_TIP_STYLE_NORMAL = 0,
@@ -173,6 +179,14 @@ typedef struct uiTooltipData {
} color_id : 4;
int is_pad : 1;
} format[MAX_TOOLTIP_LINES];
+
+ struct {
+ unsigned int x_pos; /* x cursor position at the end of the last line */
+ unsigned int lines; /* number of lines, 1 or more with word-wrap */
+ } line_geom[MAX_TOOLTIP_LINES];
+
+ int wrap_width;
+
int totline;
int toth, lineh;
} uiTooltipData;
@@ -182,9 +196,10 @@ typedef struct uiTooltipData {
BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max");
BLI_STATIC_ASSERT(sizeof(((uiTooltipData *)NULL)->format[0]) <= sizeof(int), "oversize");
-static void rgb_tint(float col[3],
- float h, float h_strength,
- float v, float v_strength)
+static void rgb_tint(
+ float col[3],
+ float h, float h_strength,
+ float v, float v_strength)
{
float col_hsv_from[3];
float col_hsv_to[3];
@@ -225,7 +240,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
wmOrtho2_region_ui(ar);
/* draw background */
- ui_draw_tooltip_background(UI_GetStyle(), NULL, &bbox);
+ ui_draw_tooltip_background(UI_style_get(), NULL, &bbox);
/* set background_color */
rgb_uchar_to_float(background_color, (const unsigned char *)theme->inner);
@@ -244,69 +259,83 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* tone_fg = rgb_to_grayscale(main_color); */
/* mix the colors */
- rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light grey */
+ rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light gray */
rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* light blue */
- rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* grey */
- rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark grey */
+ rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* gray */
+ rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark gray */
rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */
/* draw text */
+ BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width);
+ BLF_wordwrap(blf_mono_font, data->wrap_width);
bbox.xmin += 0.5f * pad_px; /* add padding to the text */
- bbox.ymax -= 0.5f * (BLI_rcti_size_y(&bbox) - data->toth);
- bbox.ymin = bbox.ymax - data->lineh;
+ bbox.ymax -= 0.25f * pad_px;
for (i = 0; i < data->totline; i++) {
+ bbox.ymin = bbox.ymax - (data->lineh * data->line_geom[i].lines);
if (data->format[i].style == UI_TIP_STYLE_HEADER) {
/* draw header and active data (is done here to be able to change color) */
uiFontStyle fstyle_header = data->fstyle;
- float xofs;
+ float xofs, yofs;
/* override text-style */
fstyle_header.shadow = 1;
- fstyle_header.shadowcolor = rgb_to_luma(tip_colors[UI_TIP_LC_MAIN]);
+ fstyle_header.shadowcolor = rgb_to_grayscale(tip_colors[UI_TIP_LC_MAIN]);
fstyle_header.shadx = fstyle_header.shady = 0;
fstyle_header.shadowalpha = 1.0f;
+ fstyle_header.word_wrap = true;
- uiStyleFontSet(&fstyle_header);
+ UI_fontstyle_set(&fstyle_header);
glColor3fv(tip_colors[UI_TIP_LC_MAIN]);
- uiStyleFontDraw(&fstyle_header, &bbox, data->header);
+ UI_fontstyle_draw(&fstyle_header, &bbox, data->header);
- xofs = BLF_width(fstyle_header.uifont_id, data->header, sizeof(data->header));
+ /* offset to the end of the last line */
+ xofs = data->line_geom[i].x_pos;
+ yofs = data->lineh * (data->line_geom[i].lines - 1);
bbox.xmin += xofs;
+ bbox.ymax -= yofs;
glColor3fv(tip_colors[UI_TIP_LC_ACTIVE]);
- uiStyleFontDraw(&data->fstyle, &bbox, data->active_info);
+ fstyle_header.shadow = 0;
+ UI_fontstyle_draw(&fstyle_header, &bbox, data->active_info);
+ /* undo offset */
bbox.xmin -= xofs;
+ bbox.ymax += yofs;
}
else if (data->format[i].style == UI_TIP_STYLE_MONO) {
uiFontStyle fstyle_mono = data->fstyle;
fstyle_mono.uifont_id = blf_mono_font;
+ fstyle_mono.word_wrap = true;
- uiStyleFontSet(&fstyle_mono);
+ UI_fontstyle_set(&fstyle_mono);
/* XXX, needed because we dont have mono in 'U.uifonts' */
BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
glColor3fv(tip_colors[data->format[i].color_id]);
- uiStyleFontDraw(&fstyle_mono, &bbox, data->lines[i]);
+ UI_fontstyle_draw(&fstyle_mono, &bbox, data->lines[i]);
}
else {
+ uiFontStyle fstyle_normal = data->fstyle;
BLI_assert(data->format[i].style == UI_TIP_STYLE_NORMAL);
+ fstyle_normal.word_wrap = true;
+
/* draw remaining data */
- uiStyleFontSet(&data->fstyle);
+ UI_fontstyle_set(&fstyle_normal);
glColor3fv(tip_colors[data->format[i].color_id]);
- uiStyleFontDraw(&data->fstyle, &bbox, data->lines[i]);
+ UI_fontstyle_draw(&fstyle_normal, &bbox, data->lines[i]);
}
+
+ bbox.ymax -= data->lineh * data->line_geom[i].lines;
+
if ((i + 1 != data->totline) && data->format[i + 1].is_pad) {
- bbox.ymax -= data->lineh * UI_TIP_PAD_FAC;
- bbox.ymin -= data->lineh * UI_TIP_PAD_FAC;
- }
- else {
- bbox.ymax -= data->lineh;
- bbox.ymin -= data->lineh;
+ bbox.ymax -= data->lineh * (UI_TIP_PAD_FAC - 1);
}
}
+ BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP);
+ BLF_disable(blf_mono_font, BLF_WORD_WRAP);
+
if (multisample_enabled)
glEnable(GL_MULTISAMPLE_ARB);
}
@@ -324,7 +353,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
{
const float pad_px = UI_TIP_PADDING;
wmWindow *win = CTX_wm_window(C);
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
static ARegionType type;
ARegion *ar;
uiTooltipData *data;
@@ -332,10 +361,11 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
char buf[512];
/* aspect values that shrink text are likely unreadable */
const float aspect = min_ff(1.0f, but->block->aspect);
- float fonth, fontw;
- int winx, ofsx, ofsy, w = 0, h, i;
+ int fonth, fontw;
+ int winx, ofsx, ofsy, h, i;
rctf rect_fl;
rcti rect_i;
+ int font_flag = 0;
uiStringInfo but_tip = {BUT_GET_TIP, NULL};
uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
@@ -351,7 +381,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* create tooltip data */
data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
- uiButGetStrInfo(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &prop_keymap, &rna_struct, &rna_prop, NULL);
+ UI_but_string_info_get(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &prop_keymap, &rna_struct, &rna_prop, NULL);
/* Tip */
if (but_tip.strinfo) {
@@ -364,8 +394,9 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->totline++;
/* special case enum rna buttons */
- if ((but->type & ROW) && but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) {
- BLI_strncpy(data->lines[data->totline], IFACE_("(Shift-click to select multiple)"), sizeof(data->lines[0]));
+ if ((but->type & UI_BTYPE_ROW) && but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) {
+ BLI_strncpy(data->lines[data->totline], IFACE_("(Shift-Click/Drag to select multiple)"),
+ sizeof(data->lines[0]));
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
@@ -396,11 +427,11 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->totline++;
}
- if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
/* better not show the value of a password */
if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
- ui_get_but_string(but, buf, sizeof(buf));
+ ui_but_string_get(but, buf, sizeof(buf));
if (buf[0]) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Value: %s"), buf);
data->format[data->totline].is_pad = true;
@@ -411,7 +442,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
}
if (but->rnaprop) {
- int unit_type = uiButGetUnitType(but);
+ int unit_type = UI_but_unit_type_get(but);
if (unit_type == PROP_UNIT_ROTATION) {
if (RNA_property_type(but->rnaprop) == PROP_FLOAT) {
@@ -445,7 +476,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
else if (but->optype) {
PointerRNA *opptr;
char *str;
- opptr = uiButGetOperatorPtrRNA(but); /* allocated when needed, the button owns it */
+ opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
/* so the context is passed to itemf functions (some py itemf functions use it) */
WM_operator_properties_sanitize(opptr, false);
@@ -513,9 +544,10 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
}
if (data_path) {
+ const char *data_delim = (data_path[0] == '[') ? "" : ".";
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]),
- "%s.%s", /* no need to translate */
- id_path, data_path);
+ "%s%s%s", /* no need to translate */
+ id_path, data_delim, data_path);
MEM_freeN(data_path);
}
else if (prop) {
@@ -556,7 +588,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
}
/* create area region */
- ar = ui_add_temporary_region(CTX_wm_screen(C));
+ ar = ui_region_temp_add(CTX_wm_screen(C));
memset(&type, 0, sizeof(ARegionType));
type.draw = ui_tooltip_region_draw_cb;
@@ -568,7 +600,18 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->fstyle = style->widget; /* copy struct */
ui_fontscale(&data->fstyle.points, aspect);
- uiStyleFontSet(&data->fstyle);
+ UI_fontstyle_set(&data->fstyle);
+
+ data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, WM_window_pixels_x(win) - (UI_TIP_PADDING * 2));
+
+ font_flag |= BLF_WORD_WRAP;
+ if (data->fstyle.kerning == 1) {
+ font_flag |= BLF_KERNING_DEFAULT;
+ }
+ BLF_enable(data->fstyle.uifont_id, font_flag);
+ BLF_enable(blf_mono_font, font_flag);
+ BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width);
+ BLF_wordwrap(blf_mono_font, data->wrap_width);
/* these defines tweaked depending on font */
#define TIP_BORDER_X (16.0f / aspect)
@@ -577,33 +620,43 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
h = BLF_height_max(data->fstyle.uifont_id);
for (i = 0, fontw = 0, fonth = 0; i < data->totline; i++) {
+ struct ResultBLF info;
+ int w, x_pos = 0;
+
if (data->format[i].style == UI_TIP_STYLE_HEADER) {
- w = BLF_width(data->fstyle.uifont_id, data->header, sizeof(data->header));
- if (enum_label.strinfo)
- w += BLF_width(data->fstyle.uifont_id, data->active_info, sizeof(data->active_info));
+ w = BLF_width_ex(data->fstyle.uifont_id, data->header, sizeof(data->header), &info);
+ if (enum_label.strinfo) {
+ x_pos = info.width + (U.widget_unit / 2);
+ w = max_ii(w, x_pos + BLF_width(data->fstyle.uifont_id, data->active_info, sizeof(data->active_info)));
+ }
}
else if (data->format[i].style == UI_TIP_STYLE_MONO) {
BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi);
- w = BLF_width(blf_mono_font, data->lines[i], sizeof(data->lines[i]));
+ w = BLF_width_ex(blf_mono_font, data->lines[i], sizeof(data->lines[i]), &info);
}
else {
BLI_assert(data->format[i].style == UI_TIP_STYLE_NORMAL);
- w = BLF_width(data->fstyle.uifont_id, data->lines[i], sizeof(data->lines[i]));
+
+ w = BLF_width_ex(data->fstyle.uifont_id, data->lines[i], sizeof(data->lines[i]), &info);
}
- fontw = max_ff(fontw, (float)w);
+ fontw = max_ii(fontw, w);
+ fonth += h * info.lines;
if ((i + 1 != data->totline) && data->format[i + 1].is_pad) {
- fonth += h * UI_TIP_PAD_FAC;
- }
- else {
- fonth += h;
+ fonth += h * (UI_TIP_PAD_FAC - 1);
}
+
+ data->line_geom[i].lines = info.lines;
+ data->line_geom[i].x_pos = x_pos;
}
//fontw *= aspect;
+ BLF_disable(data->fstyle.uifont_id, font_flag);
+ BLF_disable(blf_mono_font, font_flag);
+
ar->regiondata = data;
data->toth = fonth;
@@ -668,18 +721,18 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* widget rect, in region coords */
{
- int width = UI_ThemeMenuShadowWidth();
+ const int margin = UI_POPUP_MARGIN;
- data->bbox.xmin = width;
- data->bbox.xmax = BLI_rcti_size_x(&rect_i) - width;
- data->bbox.ymin = width;
+ data->bbox.xmin = margin;
+ data->bbox.xmax = BLI_rcti_size_x(&rect_i) - margin;
+ data->bbox.ymin = margin;
data->bbox.ymax = BLI_rcti_size_y(&rect_i);
/* region bigger for shadow */
- ar->winrct.xmin = rect_i.xmin - width;
- ar->winrct.xmax = rect_i.xmax + width;
- ar->winrct.ymin = rect_i.ymin - width;
- ar->winrct.ymax = rect_i.ymax + width;
+ ar->winrct.xmin = rect_i.xmin - margin;
+ ar->winrct.xmax = rect_i.xmax + margin;
+ ar->winrct.ymin = rect_i.ymin - margin;
+ ar->winrct.ymax = rect_i.ymax + margin;
}
/* adds subwindow */
@@ -693,7 +746,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
void ui_tooltip_free(bContext *C, ARegion *ar)
{
- ui_remove_temporary_region(C, CTX_wm_screen(C), ar);
+ ui_region_temp_remove(C, CTX_wm_screen(C), ar);
}
@@ -728,11 +781,11 @@ typedef struct uiSearchboxData {
/* exported for use by search callbacks */
/* returns zero if nothing to add */
-bool uiSearchItemAdd(uiSearchItems *items, const char *name, void *poin, int iconid)
+bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid)
{
/* hijack for autocomplete */
if (items->autocpl) {
- autocomplete_do_name(items->autocpl, name);
+ UI_autocomplete_update_name(items->autocpl, name);
return true;
}
@@ -767,17 +820,17 @@ bool uiSearchItemAdd(uiSearchItems *items, const char *name, void *poin, int ico
return true;
}
-int uiSearchBoxHeight(void)
+int UI_searchbox_size_y(void)
{
return SEARCH_ITEMS * UI_UNIT_Y + 2 * MENU_TOP;
}
-int uiSearchBoxWidth(void)
+int UI_searchbox_size_x(void)
{
return 12 * UI_UNIT_X;
}
-int uiSearchItemFindIndex(uiSearchItems *items, const char *name)
+int UI_search_items_find_index(uiSearchItems *items, const char *name)
{
int i;
for (i = 0; i < items->totitem; i++) {
@@ -817,7 +870,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
}
else {
/* only let users step into an 'unset' state for unlink buttons */
- data->active = (but->type == SEARCH_MENU_UNLINK) ? -1 : 0;
+ data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0;
}
}
@@ -828,8 +881,8 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
{
/* thumbnail preview */
if (data->preview) {
- int butw = BLI_rcti_size_x(&data->bbox) / data->prv_cols;
- int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_TOP) / data->prv_rows;
+ int butw = (BLI_rcti_size_x(&data->bbox) - 2 * MENU_BORDER) / data->prv_cols;
+ int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_BORDER) / data->prv_rows;
int row, col;
*r_rect = data->bbox;
@@ -837,10 +890,10 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
col = itemnr % data->prv_cols;
row = itemnr / data->prv_cols;
- r_rect->xmin += col * butw;
+ r_rect->xmin += MENU_BORDER + (col * butw);
r_rect->xmax = r_rect->xmin + butw;
- r_rect->ymax = data->bbox.ymax - MENU_TOP - (row * buth);
+ r_rect->ymax -= MENU_BORDER + (row * buth);
r_rect->ymin = r_rect->ymax - buth;
}
/* list view */
@@ -860,7 +913,7 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
int ui_searchbox_find_index(ARegion *ar, const char *name)
{
uiSearchboxData *data = ar->regiondata;
- return uiSearchItemFindIndex(&data->items, name);
+ return UI_search_items_find_index(&data->items, name);
}
/* x and y in screencoords */
@@ -888,7 +941,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true;
}
- else if (but->type == SEARCH_MENU_UNLINK) {
+ else if (but->flag & UI_BUT_SEARCH_UNLINK) {
/* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */
but->editstr[0] = '\0';
@@ -1014,11 +1067,11 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str)
int match = AUTOCOMPLETE_NO_MATCH;
if (str[0]) {
- data->items.autocpl = autocomplete_begin(str, ui_get_but_string_max_length(but));
+ data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but));
but->search_func(C, but->search_arg, but->editstr, &data->items);
- match = autocomplete_end(data->items.autocpl, str);
+ match = UI_autocomplete_end(data->items.autocpl, str);
data->items.autocpl = NULL;
}
@@ -1046,14 +1099,8 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
- if (data->preview) {
- ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
- (a == data->active) ? UI_ACTIVE : 0);
- }
- else {
- ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
- (a == data->active) ? UI_ACTIVE : 0, data->use_sep);
- }
+ ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
+ (a == data->active) ? UI_ACTIVE : 0);
}
/* indicate more */
@@ -1118,18 +1165,19 @@ static void ui_searchbox_region_free_cb(ARegion *ar)
ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
{
wmWindow *win = CTX_wm_window(C);
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
static ARegionType type;
ARegion *ar;
uiSearchboxData *data;
float aspect = but->block->aspect;
rctf rect_fl;
rcti rect_i;
+ const int margin = UI_POPUP_MARGIN;
int winx /*, winy */, ofsx, ofsy;
int i;
/* create area region */
- ar = ui_add_temporary_region(CTX_wm_screen(C));
+ ar = ui_region_temp_add(CTX_wm_screen(C));
memset(&type, 0, sizeof(ARegionType));
type.draw = ui_searchbox_region_draw_cb;
@@ -1144,7 +1192,7 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
data->fstyle = style->widget; /* copy struct */
data->fstyle.align = UI_STYLE_TEXT_CENTER;
ui_fontscale(&data->fstyle.points, aspect);
- uiStyleFontSet(&data->fstyle);
+ UI_fontstyle_set(&data->fstyle);
ar->regiondata = data;
@@ -1166,35 +1214,33 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
/* compute position */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
- int width = UI_ThemeMenuShadowWidth();
+ const int search_but_h = BLI_rctf_size_y(&but->rect) + 10;
/* this case is search menu inside other menu */
/* we copy region size */
ar->winrct = butregion->winrct;
/* widget rect, in region coords */
- data->bbox.xmin = width;
- data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - width;
- /* Do not use shadow width for height, gives insane margin with big shadows, and issue T41548 with small ones */
- data->bbox.ymin = 8 * UI_DPI_FAC;
- data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - 8 * UI_DPI_FAC;
+ data->bbox.xmin = margin;
+ data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin;
+ data->bbox.ymin = margin;
+ data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - margin;
/* check if button is lower half */
if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) {
- data->bbox.ymin += BLI_rctf_size_y(&but->rect);
+ data->bbox.ymin += search_but_h;
}
else {
- data->bbox.ymax -= BLI_rctf_size_y(&but->rect);
+ data->bbox.ymax -= search_but_h;
}
}
else {
- const int searchbox_width = uiSearchBoxWidth();
- const int shadow_width = UI_ThemeMenuShadowWidth();
+ const int searchbox_width = UI_searchbox_size_x();
rect_fl.xmin = but->rect.xmin - 5; /* align text with button */
rect_fl.xmax = but->rect.xmax + 5; /* symmetrical */
rect_fl.ymax = but->rect.ymin;
- rect_fl.ymin = rect_fl.ymax - uiSearchBoxHeight();
+ rect_fl.ymin = rect_fl.ymax - UI_searchbox_size_y();
ofsx = (but->block->panel) ? but->block->panel->ofsx : 0;
ofsy = (but->block->panel) ? but->block->panel->ofsy : 0;
@@ -1244,15 +1290,15 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
}
/* widget rect, in region coords */
- data->bbox.xmin = shadow_width;
- data->bbox.xmax = BLI_rcti_size_x(&rect_i) + shadow_width;
- data->bbox.ymin = shadow_width;
- data->bbox.ymax = BLI_rcti_size_y(&rect_i) + shadow_width;
+ data->bbox.xmin = margin;
+ data->bbox.xmax = BLI_rcti_size_x(&rect_i) + margin;
+ data->bbox.ymin = margin;
+ data->bbox.ymax = BLI_rcti_size_y(&rect_i) + margin;
/* region bigger for shadow */
- ar->winrct.xmin = rect_i.xmin - shadow_width;
- ar->winrct.xmax = rect_i.xmax + shadow_width;
- ar->winrct.ymin = rect_i.ymin - shadow_width;
+ ar->winrct.xmin = rect_i.xmin - margin;
+ ar->winrct.xmax = rect_i.xmax + margin;
+ ar->winrct.ymin = rect_i.ymin - margin;
ar->winrct.ymax = rect_i.ymax;
}
@@ -1282,12 +1328,12 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
void ui_searchbox_free(bContext *C, ARegion *ar)
{
- ui_remove_temporary_region(C, CTX_wm_screen(C), ar);
+ ui_region_temp_remove(C, CTX_wm_screen(C), ar);
}
/* sets red alert if button holds a string it can't find */
/* XXX weak: search_func adds all partial matches... */
-void ui_but_search_test(uiBut *but)
+void ui_but_search_refresh(uiBut *but)
{
uiSearchItems *items;
int x1;
@@ -1311,11 +1357,11 @@ void ui_but_search_test(uiBut *but)
/* only redalert when we are sure of it, this can miss cases when >10 matches */
if (items->totitem == 0) {
- uiButSetFlag(but, UI_BUT_REDALERT);
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
}
else if (items->more == 0) {
- if (uiSearchItemFindIndex(items, but->drawstr) == -1) {
- uiButSetFlag(but, UI_BUT_REDALERT);
+ if (UI_search_items_find_index(items, but->drawstr) == -1) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
}
}
@@ -1343,7 +1389,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
/* widget_roundbox_set has this correction too, keep in sync */
- if (but->type != PULLDOWN) {
+ if (but->type != UI_BTYPE_PULLDOWN) {
if (but->drawflag & UI_BUT_ALIGN_TOP)
butrct.ymax += U.pixelsize;
if (but->drawflag & UI_BUT_ALIGN_LEFT)
@@ -1377,7 +1423,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
/* aspect /= (float)xsize;*/ /*UNUSED*/
{
- int left = 0, right = 0, top = 0, down = 0;
+ bool left = 0, right = 0, top = 0, down = 0;
int winx, winy;
// int offscreen;
@@ -1385,8 +1431,12 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
winy = WM_window_pixels_y(window);
// wm_window_get_size(window, &winx, &winy);
- if (block->direction & UI_CENTER) center = ysize / 2;
- else center = 0;
+ if (block->direction & UI_DIR_CENTER_Y) {
+ center = ysize / 2;
+ }
+ else {
+ center = 0;
+ }
/* check if there's space at all */
if (butrct.xmin - xsize > 0.0f) left = 1;
@@ -1401,69 +1451,66 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
down = 1;
}
- dir1 = block->direction & UI_DIRECTION;
+ dir1 = (block->direction & UI_DIR_ALL);
/* secundary directions */
- if (dir1 & (UI_TOP | UI_DOWN)) {
- if (dir1 & UI_LEFT) dir2 = UI_LEFT;
- else if (dir1 & UI_RIGHT) dir2 = UI_RIGHT;
- dir1 &= (UI_TOP | UI_DOWN);
+ if (dir1 & (UI_DIR_UP | UI_DIR_DOWN)) {
+ if (dir1 & UI_DIR_LEFT) dir2 = UI_DIR_LEFT;
+ else if (dir1 & UI_DIR_RIGHT) dir2 = UI_DIR_RIGHT;
+ dir1 &= (UI_DIR_UP | UI_DIR_DOWN);
}
- if ((dir2 == 0) && (dir1 == UI_LEFT || dir1 == UI_RIGHT)) dir2 = UI_DOWN;
- if ((dir2 == 0) && (dir1 == UI_TOP || dir1 == UI_DOWN)) dir2 = UI_LEFT;
+ if ((dir2 == 0) && (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT)) dir2 = UI_DIR_DOWN;
+ if ((dir2 == 0) && (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN)) dir2 = UI_DIR_LEFT;
/* no space at all? don't change */
if (left || right) {
- if (dir1 == UI_LEFT && left == 0) dir1 = UI_RIGHT;
- if (dir1 == UI_RIGHT && right == 0) dir1 = UI_LEFT;
+ if (dir1 == UI_DIR_LEFT && left == 0) dir1 = UI_DIR_RIGHT;
+ if (dir1 == UI_DIR_RIGHT && right == 0) dir1 = UI_DIR_LEFT;
/* this is aligning, not append! */
- if (dir2 == UI_LEFT && right == 0) dir2 = UI_RIGHT;
- if (dir2 == UI_RIGHT && left == 0) dir2 = UI_LEFT;
+ if (dir2 == UI_DIR_LEFT && right == 0) dir2 = UI_DIR_RIGHT;
+ if (dir2 == UI_DIR_RIGHT && left == 0) dir2 = UI_DIR_LEFT;
}
if (down || top) {
- if (dir1 == UI_TOP && top == 0) dir1 = UI_DOWN;
- if (dir1 == UI_DOWN && down == 0) dir1 = UI_TOP;
- if (dir2 == UI_TOP && top == 0) dir2 = UI_DOWN;
- if (dir2 == UI_DOWN && down == 0) dir2 = UI_TOP;
+ if (dir1 == UI_DIR_UP && top == 0) dir1 = UI_DIR_DOWN;
+ if (dir1 == UI_DIR_DOWN && down == 0) dir1 = UI_DIR_UP;
+ BLI_assert(dir2 != UI_DIR_UP);
+// if (dir2 == UI_DIR_UP && top == 0) dir2 = UI_DIR_DOWN;
+ if (dir2 == UI_DIR_DOWN && down == 0) dir2 = UI_DIR_UP;
}
- if (dir1 == UI_LEFT) {
+ if (dir1 == UI_DIR_LEFT) {
xof = butrct.xmin - block->rect.xmax;
- if (dir2 == UI_TOP) yof = butrct.ymin - block->rect.ymin - center - MENU_PADDING;
- else yof = butrct.ymax - block->rect.ymax + center + MENU_PADDING;
+ if (dir2 == UI_DIR_UP) yof = butrct.ymin - block->rect.ymin - center - MENU_PADDING;
+ else yof = butrct.ymax - block->rect.ymax + center + MENU_PADDING;
}
- else if (dir1 == UI_RIGHT) {
+ else if (dir1 == UI_DIR_RIGHT) {
xof = butrct.xmax - block->rect.xmin;
- if (dir2 == UI_TOP) yof = butrct.ymin - block->rect.ymin - center - MENU_PADDING;
- else yof = butrct.ymax - block->rect.ymax + center + MENU_PADDING;
+ if (dir2 == UI_DIR_UP) yof = butrct.ymin - block->rect.ymin - center - MENU_PADDING;
+ else yof = butrct.ymax - block->rect.ymax + center + MENU_PADDING;
}
- else if (dir1 == UI_TOP) {
+ else if (dir1 == UI_DIR_UP) {
yof = butrct.ymax - block->rect.ymin;
- if (dir2 == UI_RIGHT) xof = butrct.xmax - block->rect.xmax;
- else xof = butrct.xmin - block->rect.xmin;
+ if (dir2 == UI_DIR_RIGHT) xof = butrct.xmax - block->rect.xmax;
+ else xof = butrct.xmin - block->rect.xmin;
/* changed direction? */
if ((dir1 & block->direction) == 0) {
- if (block->direction & UI_SHIFT_FLIPPED)
- xof += dir2 == UI_LEFT ? 25 : -25;
- uiBlockFlipOrder(block);
+ UI_block_order_flip(block);
}
}
- else if (dir1 == UI_DOWN) {
+ else if (dir1 == UI_DIR_DOWN) {
yof = butrct.ymin - block->rect.ymax;
- if (dir2 == UI_RIGHT) xof = butrct.xmax - block->rect.xmax;
- else xof = butrct.xmin - block->rect.xmin;
+ if (dir2 == UI_DIR_RIGHT) xof = butrct.xmax - block->rect.xmax;
+ else xof = butrct.xmin - block->rect.xmin;
/* changed direction? */
if ((dir1 & block->direction) == 0) {
- if (block->direction & UI_SHIFT_FLIPPED)
- xof += dir2 == UI_LEFT ? 25 : -25;
- uiBlockFlipOrder(block);
+ UI_block_order_flip(block);
}
}
/* and now we handle the exception; no space below or to top */
if (top == 0 && down == 0) {
- if (dir1 == UI_LEFT || dir1 == UI_RIGHT) {
+ if (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT) {
/* align with bottom of screen */
// yof = ysize; (not with menu scrolls)
}
@@ -1471,7 +1518,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
/* or no space left or right */
if (left == 0 && right == 0) {
- if (dir1 == UI_TOP || dir1 == UI_DOWN) {
+ if (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN) {
/* align with left size of screen */
xof = -block->rect.xmin + 5;
}
@@ -1493,8 +1540,8 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
BLI_rctf_translate(&bt->rect, xof, yof);
- /* ui_check_but recalculates drawstring size in pixels */
- ui_check_but(bt);
+ /* ui_but_update recalculates drawstring size in pixels */
+ ui_but_update(bt);
}
BLI_rctf_translate(&block->rect, xof, yof);
@@ -1522,8 +1569,8 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
/* exception for switched pulldowns... */
if (dir1 && (dir1 & block->direction) == 0) {
- if (dir2 == UI_RIGHT) block->safety.xmax = block->rect.xmax + 3;
- if (dir2 == UI_LEFT) block->safety.xmin = block->rect.xmin - 3;
+ if (dir2 == UI_DIR_RIGHT) block->safety.xmax = block->rect.xmax + 3;
+ if (dir2 == UI_DIR_LEFT) block->safety.xmin = block->rect.xmin - 3;
}
block->direction = dir1;
}
@@ -1551,7 +1598,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
}
for (block = ar->uiblocks.first; block; block = block->next)
- uiDrawBlock(C, block);
+ UI_block_draw(C, block);
}
static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
@@ -1633,20 +1680,20 @@ void ui_popup_block_scrolltest(uiBlock *block)
static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
- ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region);
+ ui_region_temp_remove(C, CTX_wm_screen(C), handle->region);
if (handle->scrolltimer)
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), handle->scrolltimer);
}
/**
- * Called for creatign new popups and refreshing existing ones.
+ * Called for creating new popups and refreshing existing ones.
*/
uiBlock *ui_popup_block_refresh(
bContext *C, uiPopupBlockHandle *handle,
ARegion *butregion, uiBut *but)
{
- const int width = UI_ThemeMenuShadowWidth();
+ const int margin = UI_POPUP_MARGIN;
wmWindow *window = CTX_wm_window(C);
ARegion *ar = handle->region;
@@ -1667,7 +1714,7 @@ uiBlock *ui_popup_block_refresh(
else
block = handle_create_func(C, handle, arg);
- /* callbacks _must_ leave this for us, otherwise we can't call uiBlockUpdateFromOld */
+ /* callbacks _must_ leave this for us, otherwise we can't call UI_block_update_from_old */
BLI_assert(!block->endblock);
/* ensure we don't use mouse coords here! */
@@ -1685,14 +1732,9 @@ uiBlock *ui_popup_block_refresh(
ar->regiondata = handle;
- /* set UI_BLOCK_NUMSELECT before uiEndBlock() so we get alphanumeric keys assigned */
- if (but) {
- if (but->type == PULLDOWN) {
- block->flag |= UI_BLOCK_NUMSELECT;
- }
- }
- else {
- block->flag |= UI_BLOCK_POPUP | UI_BLOCK_NUMSELECT;
+ /* set UI_BLOCK_NUMSELECT before UI_block_end() so we get alphanumeric keys assigned */
+ if (but == NULL) {
+ block->flag |= UI_BLOCK_POPUP;
}
block->flag |= UI_BLOCK_LOOP;
@@ -1701,7 +1743,7 @@ uiBlock *ui_popup_block_refresh(
block->oldblock = NULL;
if (!block->endblock)
- uiEndBlock_ex(C, block, handle->popup_create_vars.event_xy);
+ UI_block_end_ex(C, block, handle->popup_create_vars.event_xy);
/* if this is being created from a button */
if (but) {
@@ -1756,7 +1798,7 @@ uiBlock *ui_popup_block_refresh(
ar->winrct.ymin = 0;
ar->winrct.ymax = winy;
- ui_block_calculate_pie_segment(block, block->pie_data.pie_center_init);
+ ui_block_calc_pie_segment(block, block->pie_data.pie_center_init);
/* lastly set the buttons at the center of the pie menu, ready for animation */
if (U.pie_animation_timeout > 0) {
@@ -1773,9 +1815,9 @@ uiBlock *ui_popup_block_refresh(
/* the block and buttons were positioned in window space as in 2.4x, now
* these menu blocks are regions so we bring it back to region space.
* additionally we add some padding for the menu shadow or rounded menus */
- ar->winrct.xmin = block->rect.xmin - width;
- ar->winrct.xmax = block->rect.xmax + width;
- ar->winrct.ymin = block->rect.ymin - width;
+ ar->winrct.xmin = block->rect.xmin - margin;
+ ar->winrct.xmax = block->rect.xmax + margin;
+ ar->winrct.ymin = block->rect.ymin - margin;
ar->winrct.ymax = block->rect.ymax + MENU_TOP;
ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
@@ -1783,8 +1825,8 @@ uiBlock *ui_popup_block_refresh(
if (block_old) {
block->oldblock = block_old;
- uiBlockUpdateFromOld(C, block);
- uiFreeInactiveBlocks(C, &ar->uiblocks);
+ UI_block_update_from_old(C, block);
+ UI_blocklist_free_inactive(C, &ar->uiblocks);
}
/* checks which buttons are visible, sets flags to prevent draw (do after region init) */
@@ -1810,9 +1852,10 @@ uiBlock *ui_popup_block_refresh(
return block;
}
-uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg)
+uiPopupBlockHandle *ui_popup_block_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg)
{
wmWindow *window = CTX_wm_window(C);
static ARegionType type;
@@ -1835,7 +1878,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut
copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x);
/* create area region */
- ar = ui_add_temporary_region(CTX_wm_screen(C));
+ ar = ui_region_temp_add(CTX_wm_screen(C));
handle->region = ar;
memset(&type, 0, sizeof(ARegionType));
@@ -1843,7 +1886,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut
type.regionid = RGN_TYPE_TEMPORARY;
ar->type = &type;
- UI_add_region_handlers(&ar->handlers);
+ UI_region_handlers_add(&ar->handlers);
block = ui_popup_block_refresh(C, handle, butregion, but);
handle = block->handle;
@@ -1875,21 +1918,23 @@ static void ui_warp_pointer(int x, int y)
/********************* Color Button ****************/
/* for picker, while editing hsv */
-void ui_set_but_hsv(uiBut *but)
+void ui_but_hsv_set(uiBut *but)
{
float col[3];
- const float *hsv = ui_block_hsv_get(but->block);
-
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
+
ui_color_picker_to_rgb_v(hsv, col);
- ui_set_but_vectorf(but, col);
+ ui_but_v3_set(but, col);
}
-/* also used by small picker, be careful with name checks below... */
-static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is_display_space)
+/* Updates all buttons who share the same color picker as the one passed
+ * also used by small picker, be careful with name checks below... */
+static void ui_update_color_picker_buts_rgb(uiBlock *block, ColorPicker *cpicker, const float rgb[3], bool is_display_space)
{
uiBut *bt;
- float *hsv = ui_block_hsv_get(block);
+ float *hsv = cpicker->color_data;
struct ColorManagedDisplay *display = NULL;
/* this is to keep the H and S value when V is equal to zero
* and we are working in HSV mode, of course!
@@ -1902,21 +1947,24 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is
float rgb_display[3];
copy_v3_v3(rgb_display, rgb);
- ui_block_to_display_space_v3(block, rgb_display);
+ ui_block_cm_to_display_space_v3(block, rgb_display);
ui_rgb_to_color_picker_compat_v(rgb_display, hsv);
}
if (block->color_profile)
- display = ui_block_display_get(block);
+ display = ui_block_cm_display_get(block);
/* this updates button strings, is hackish... but button pointers are on stack of caller function */
for (bt = block->buttons.first; bt; bt = bt->next) {
+ if (bt->custom_data != cpicker)
+ continue;
+
if (bt->rnaprop) {
- ui_set_but_vectorf(bt, rgb);
+ ui_but_v3_set(bt, rgb);
}
- else if (strcmp(bt->str, "Hex: ") == 0) {
+ else if (STREQ(bt->str, "Hex: ")) {
float rgb_gamma[3];
unsigned char rgb_gamma_uchar[3];
double intpart;
@@ -1942,33 +1990,33 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is
}
else if (bt->str[1] == ' ') {
if (bt->str[0] == 'R') {
- ui_set_but_val(bt, rgb[0]);
+ ui_but_value_set(bt, rgb[0]);
}
else if (bt->str[0] == 'G') {
- ui_set_but_val(bt, rgb[1]);
+ ui_but_value_set(bt, rgb[1]);
}
else if (bt->str[0] == 'B') {
- ui_set_but_val(bt, rgb[2]);
+ ui_but_value_set(bt, rgb[2]);
}
else if (bt->str[0] == 'H') {
- ui_set_but_val(bt, hsv[0]);
+ ui_but_value_set(bt, hsv[0]);
}
else if (bt->str[0] == 'S') {
- ui_set_but_val(bt, hsv[1]);
+ ui_but_value_set(bt, hsv[1]);
}
else if (bt->str[0] == 'V') {
- ui_set_but_val(bt, hsv[2]);
+ ui_but_value_set(bt, hsv[2]);
}
else if (bt->str[0] == 'L') {
- ui_set_but_val(bt, hsv[2]);
+ ui_but_value_set(bt, hsv[2]);
}
}
- ui_check_but(bt);
+ ui_but_update(bt);
}
}
-static void do_picker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
+static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
{
uiBut *but = (uiBut *)bt1;
uiPopupBlockHandle *popup = but->block->handle;
@@ -1978,38 +2026,40 @@ static void do_picker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
if (prop) {
RNA_property_float_get_array(&ptr, prop, rgb);
- ui_update_block_buts_rgb(but->block, rgb, (RNA_property_subtype(prop) == PROP_COLOR_GAMMA));
+ ui_update_color_picker_buts_rgb(but->block, but->custom_data, rgb, (RNA_property_subtype(prop) == PROP_COLOR_GAMMA));
}
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
}
-static void do_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
+static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
{
uiBut *but = (uiBut *)bt1;
uiPopupBlockHandle *popup = but->block->handle;
float rgb[3];
- const float *hsv = ui_block_hsv_get(but->block);
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
ui_color_picker_to_rgb_v(hsv, rgb);
/* hsv is saved in display space so convert back */
if (use_display_colorspace) {
- ui_block_to_scene_linear_v3(but->block, rgb);
+ ui_block_cm_to_scene_linear_v3(but->block, rgb);
}
- ui_update_block_buts_rgb(but->block, rgb, !use_display_colorspace);
+ ui_update_color_picker_buts_rgb(but->block, cpicker, rgb, !use_display_colorspace);
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
}
-static void do_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
+static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
{
uiBut *but = (uiBut *)bt1;
uiPopupBlockHandle *popup = but->block->handle;
+ ColorPicker *cpicker = but->custom_data;
char *hexcol = (char *)hexcl;
float rgb[3];
@@ -2018,16 +2068,16 @@ static void do_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
/* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
if (but->block->color_profile) {
/* so we need to linearise it for Blender */
- ui_block_to_scene_linear_v3(but->block, rgb);
+ ui_block_cm_to_scene_linear_v3(but->block, rgb);
}
- ui_update_block_buts_rgb(but->block, rgb, false);
+ ui_update_color_picker_buts_rgb(but->block, cpicker, rgb, false);
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
}
-static void close_popup_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
+static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
{
uiBut *but = (uiBut *)bt1;
uiPopupBlockHandle *popup = but->block->handle;
@@ -2036,23 +2086,23 @@ static void close_popup_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
popup->menuretval = UI_RETURN_OK;
}
-static void picker_new_hide_reveal(uiBlock *block, short colormode)
+static void ui_colorpicker_hide_reveal(uiBlock *block, short colormode)
{
uiBut *bt;
/* tag buttons */
for (bt = block->buttons.first; bt; bt = bt->next) {
- if ((bt->func == do_picker_rna_cb) && bt->type == NUMSLI && bt->rnaindex != 3) {
+ if ((bt->func == ui_colorpicker_rna_cb) && bt->type == UI_BTYPE_NUM_SLIDER && bt->rnaindex != 3) {
/* RGB sliders (color circle and alpha are always shown) */
if (colormode == 0) bt->flag &= ~UI_HIDDEN;
else bt->flag |= UI_HIDDEN;
}
- else if (bt->func == do_color_wheel_rna_cb) {
+ else if (bt->func == ui_color_wheel_rna_cb) {
/* HSV sliders */
if (colormode == 1) bt->flag &= ~UI_HIDDEN;
else bt->flag |= UI_HIDDEN;
}
- else if (bt->func == do_hex_rna_cb || bt->type == LABEL) {
+ else if (bt->func == ui_colorpicker_hex_rna_cb || bt->type == UI_BTYPE_LABEL) {
/* hex input or gamma correction status label */
if (colormode == 2) bt->flag &= ~UI_HIDDEN;
else bt->flag |= UI_HIDDEN;
@@ -2060,11 +2110,11 @@ static void picker_new_hide_reveal(uiBlock *block, short colormode)
}
}
-static void do_picker_new_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
+static void ui_colorpicker_create_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
{
uiBut *bt = bt1;
- short colormode = ui_get_but_val(bt);
- picker_new_hide_reveal(bt->block, colormode);
+ short colormode = ui_but_value_get(bt);
+ ui_colorpicker_hide_reveal(bt->block, colormode);
}
#define PICKER_H (7.5f * U.widget_unit)
@@ -2074,43 +2124,47 @@ static void do_picker_new_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(a
#define PICKER_TOTAL_W (PICKER_W + PICKER_SPACE + PICKER_BAR)
-static void circle_picker(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop)
+static void ui_colorpicker_circle(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, ColorPicker *cpicker)
{
uiBut *bt;
/* HS circle */
- bt = uiDefButR_prop(block, HSVCIRCLE, 0, "", 0, 0, PICKER_H, PICKER_W, ptr, prop, -1, 0.0, 0.0, 0.0, 0, TIP_("Color"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ bt = uiDefButR_prop(block, UI_BTYPE_HSVCIRCLE, 0, "", 0, 0, PICKER_H, PICKER_W, ptr, prop, -1, 0.0, 0.0, 0.0, 0, TIP_("Color"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
/* value */
if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
- bt = uiDefButR_prop(block, HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H, ptr, prop, -1, 0.0, 0.0, UI_GRAD_L_ALT, 0, "Lightness");
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ bt = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H, ptr, prop, -1, 0.0, 0.0, UI_GRAD_L_ALT, 0, "Lightness");
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
}
else {
- bt = uiDefButR_prop(block, HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H, ptr, prop, -1, 0.0, 0.0, UI_GRAD_V_ALT, 0, TIP_("Value"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ bt = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H, ptr, prop, -1, 0.0, 0.0, UI_GRAD_V_ALT, 0, TIP_("Value"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
}
+ bt->custom_data = cpicker;
}
-static void square_picker(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int type)
+static void ui_colorpicker_square(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int type, ColorPicker *cpicker)
{
uiBut *bt;
int bartype = type + 3;
/* HS square */
- bt = uiDefButR_prop(block, HSVCUBE, 0, "", 0, PICKER_BAR + PICKER_SPACE, PICKER_TOTAL_W, PICKER_H, ptr, prop, -1, 0.0, 0.0, type, 0, TIP_("Color"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ bt = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, PICKER_BAR + PICKER_SPACE, PICKER_TOTAL_W, PICKER_H, ptr, prop, -1, 0.0, 0.0, type, 0, TIP_("Color"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
/* value */
- bt = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, PICKER_TOTAL_W, PICKER_BAR, ptr, prop, -1, 0.0, 0.0, bartype, 0, TIP_("Value"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ bt = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 0, PICKER_TOTAL_W, PICKER_BAR, ptr, prop, -1, 0.0, 0.0, bartype, 0, TIP_("Value"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
}
/* a HS circle, V slider, rgb/hsv/hex sliders */
-static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, PropertyRNA *prop, bool show_picker)
+static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr, PropertyRNA *prop, bool show_picker)
{
static short colormode = 0; /* temp? 0=rgb, 1=hsv, 2=hex */
uiBut *bt;
@@ -2120,8 +2174,9 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
float rgb_gamma[3];
unsigned char rgb_gamma_uchar[3];
float softmin, softmax, hardmin, hardmax, step, precision;
- float *hsv = ui_block_hsv_get(block);
int yco;
+ ColorPicker *cpicker = ui_block_colorpicker_create(block);
+ float *hsv = cpicker->color_data;
width = PICKER_TOTAL_W;
butwidth = width - 1.5f * UI_UNIT_X;
@@ -2137,7 +2192,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
/* make a display version, for Hex code */
copy_v3_v3(rgb_gamma, rgba);
- ui_block_to_display_space_v3(block, rgb_gamma);
+ ui_block_cm_to_display_space_v3(block, rgb_gamma);
}
/* sneaky way to check for alpha */
@@ -2149,75 +2204,86 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
switch (U.color_picker_type) {
case USER_CP_SQUARE_SV:
- square_picker(block, ptr, prop, UI_GRAD_SV);
+ ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
break;
case USER_CP_SQUARE_HS:
- square_picker(block, ptr, prop, UI_GRAD_HS);
+ ui_colorpicker_square(block, ptr, prop, UI_GRAD_HS, cpicker);
break;
case USER_CP_SQUARE_HV:
- square_picker(block, ptr, prop, UI_GRAD_HV);
+ ui_colorpicker_square(block, ptr, prop, UI_GRAD_HV, cpicker);
break;
/* user default */
case USER_CP_CIRCLE_HSV:
case USER_CP_CIRCLE_HSL:
default:
- circle_picker(block, ptr, prop);
+ ui_colorpicker_circle(block, ptr, prop, cpicker);
break;
}
/* mode */
yco = -1.5f * UI_UNIT_Y;
- uiBlockBeginAlign(block);
- bt = uiDefButS(block, ROW, 0, IFACE_("RGB"), 0, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 0.0, 0, 0, "");
- uiButSetFunc(bt, do_picker_new_mode_cb, bt, NULL);
+ UI_block_align_begin(block);
+ bt = uiDefButS(block, UI_BTYPE_ROW, 0, IFACE_("RGB"), 0, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 0.0, 0, 0, "");
+ UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
+ bt->custom_data = cpicker;
if (U.color_picker_type == USER_CP_CIRCLE_HSL)
- bt = uiDefButS(block, ROW, 0, IFACE_("HSL"), width / 3, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 1.0, 0, 0, "");
+ bt = uiDefButS(block, UI_BTYPE_ROW, 0, IFACE_("HSL"), width / 3, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 1.0, 0, 0, "");
else
- bt = uiDefButS(block, ROW, 0, IFACE_("HSV"), width / 3, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 1.0, 0, 0, "");
- uiButSetFunc(bt, do_picker_new_mode_cb, bt, NULL);
- bt = uiDefButS(block, ROW, 0, IFACE_("Hex"), 2 * width / 3, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 2.0, 0, 0, "");
- uiButSetFunc(bt, do_picker_new_mode_cb, bt, NULL);
- uiBlockEndAlign(block);
+ bt = uiDefButS(block, UI_BTYPE_ROW, 0, IFACE_("HSV"), width / 3, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 1.0, 0, 0, "");
+ UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
+ bt->custom_data = cpicker;
+ bt = uiDefButS(block, UI_BTYPE_ROW, 0, IFACE_("Hex"), 2 * width / 3, yco, width / 3, UI_UNIT_Y, &colormode, 0.0, 2.0, 0, 0, "");
+ UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
+ bt->custom_data = cpicker;
+ UI_block_align_end(block);
yco = -3.0f * UI_UNIT_Y;
if (show_picker) {
- bt = uiDefIconButO(block, BUT, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, butwidth + 10, yco, UI_UNIT_X, UI_UNIT_Y, NULL);
- uiButSetFunc(bt, close_popup_cb, bt, NULL);
+ bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, butwidth + 10, yco, UI_UNIT_X, UI_UNIT_Y, NULL);
+ UI_but_func_set(bt, ui_popup_close_cb, bt, NULL);
+ bt->custom_data = cpicker;
}
/* RGB values */
- uiBlockBeginAlign(block);
- bt = uiDefButR_prop(block, NUMSLI, 0, IFACE_("R:"), 0, yco, butwidth, UI_UNIT_Y, ptr, prop, 0, 0.0, 0.0, 0, 3, TIP_("Red"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
- bt = uiDefButR_prop(block, NUMSLI, 0, IFACE_("G:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, ptr, prop, 1, 0.0, 0.0, 0, 3, TIP_("Green"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
- bt = uiDefButR_prop(block, NUMSLI, 0, IFACE_("B:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, ptr, prop, 2, 0.0, 0.0, 0, 3, TIP_("Blue"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ UI_block_align_begin(block);
+ bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("R:"), 0, yco, butwidth, UI_UNIT_Y, ptr, prop, 0, 0.0, 0.0, 0, 3, TIP_("Red"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
+ bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("G:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, ptr, prop, 1, 0.0, 0.0, 0, 3, TIP_("Green"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
+ bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("B:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, ptr, prop, 2, 0.0, 0.0, 0, 3, TIP_("Blue"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
/* could use uiItemFullR(col, ptr, prop, -1, 0, UI_ITEM_R_EXPAND|UI_ITEM_R_SLIDER, "", ICON_NONE);
- * but need to use uiButSetFunc for updating other fake buttons */
+ * but need to use UI_but_func_set for updating other fake buttons */
/* HSV values */
yco = -3.0f * UI_UNIT_Y;
- uiBlockBeginAlign(block);
- bt = uiDefButF(block, NUMSLI, 0, IFACE_("H:"), 0, yco, butwidth, UI_UNIT_Y, hsv, 0.0, 1.0, 10, 3, TIP_("Hue"));
- uiButSetFunc(bt, do_color_wheel_rna_cb, bt, hsv);
- bt = uiDefButF(block, NUMSLI, 0, IFACE_("S:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 1, 0.0, 1.0, 10, 3, TIP_("Saturation"));
- uiButSetFunc(bt, do_color_wheel_rna_cb, bt, hsv);
+ UI_block_align_begin(block);
+ bt = uiDefButF(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("H:"), 0, yco, butwidth, UI_UNIT_Y, hsv, 0.0, 1.0, 10, 3, TIP_("Hue"));
+ UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
+ bt->custom_data = cpicker;
+ bt = uiDefButF(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("S:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 1, 0.0, 1.0, 10, 3, TIP_("Saturation"));
+ UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
+ bt->custom_data = cpicker;
if (U.color_picker_type == USER_CP_CIRCLE_HSL)
- bt = uiDefButF(block, NUMSLI, 0, IFACE_("L:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 2, 0.0, 1.0, 10, 3, TIP_("Lightness"));
+ bt = uiDefButF(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("L:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 2, 0.0, 1.0, 10, 3, TIP_("Lightness"));
else
- bt = uiDefButF(block, NUMSLI, 0, IFACE_("V:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 2, 0.0, softmax, 10, 3, TIP_("Value"));
+ bt = uiDefButF(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("V:"), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 2, 0.0, softmax, 10, 3, TIP_("Value"));
bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */
- uiButSetFunc(bt, do_color_wheel_rna_cb, bt, hsv);
+ UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
+ bt->custom_data = cpicker;
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
if (rgba[3] != FLT_MAX) {
- bt = uiDefButR_prop(block, NUMSLI, 0, IFACE_("A: "), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, ptr, prop, 3, 0.0, 0.0, 0, 3, TIP_("Alpha"));
- uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
+ bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("A: "), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, ptr, prop, 3, 0.0, 0.0, 0, 3, TIP_("Alpha"));
+ UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
+ bt->custom_data = cpicker;
}
else {
rgba[3] = 1.0f;
@@ -2227,17 +2293,18 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
- bt = uiDefBut(block, TEX, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
- uiButSetFunc(bt, do_hex_rna_cb, bt, hexcol);
- uiDefBut(block, LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
+ UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
+ bt->custom_data = cpicker;
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
ui_rgb_to_color_picker_v(rgb_gamma, hsv);
- picker_new_hide_reveal(block, colormode);
+ ui_colorpicker_hide_reveal(block, colormode);
}
-static int ui_picker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, const wmEvent *event)
+static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, const wmEvent *event)
{
float add = 0.0f;
@@ -2250,16 +2317,17 @@ static int ui_picker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, c
uiBut *but;
for (but = block->buttons.first; but; but = but->next) {
- if (but->type == HSVCUBE && but->active == NULL) {
+ if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) {
uiPopupBlockHandle *popup = block->handle;
float rgb[3];
- float *hsv = ui_block_hsv_get(block);
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (use_display_colorspace)
- ui_block_to_display_space_v3(block, rgb);
+ ui_block_cm_to_display_space_v3(block, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
@@ -2267,11 +2335,11 @@ static int ui_picker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, c
ui_color_picker_to_rgb_v(hsv, rgb);
if (use_display_colorspace)
- ui_block_to_scene_linear_v3(block, rgb);
+ ui_block_cm_to_scene_linear_v3(block, rgb);
- ui_set_but_vectorf(but, rgb);
+ ui_but_v3_set(but, rgb);
- ui_update_block_buts_rgb(block, rgb, !use_display_colorspace);
+ ui_update_color_picker_buts_rgb(block, cpicker, rgb, !use_display_colorspace);
if (popup)
popup->menuretval = UI_RETURN_UPDATE;
@@ -2288,7 +2356,7 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_
uiBlock *block;
bool show_picker = true;
- block = uiBeginBlock(C, handle->region, __func__, UI_EMBOSS);
+ block = UI_block_begin(C, handle->region, __func__, UI_EMBOSS);
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
block->color_profile = false;
@@ -2304,15 +2372,15 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_
copy_v3_v3(handle->retvec, but->editvec);
- uiBlockPicker(block, handle->retvec, &but->rnapoin, but->rnaprop, show_picker);
+ ui_block_colorpicker(block, handle->retvec, &but->rnapoin, but->rnaprop, show_picker);
- block->flag = UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT;
- uiBoundsBlock(block, 0.5 * UI_UNIT_X);
+ block->flag = UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT;
+ UI_block_bounds_set_normal(block, 0.5 * UI_UNIT_X);
- block->block_event_func = ui_picker_small_wheel_cb;
+ block->block_event_func = ui_colorpicker_small_wheel_cb;
/* and lets go */
- block->direction = UI_TOP;
+ block->direction = UI_DIR_UP;
return block;
}
@@ -2448,39 +2516,39 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
/* allow overriding the direction from menu_func */
direction = pup->block->direction;
}
- else if ((pup->but->type == PULLDOWN) ||
- (uiButGetMenuType(pup->but) != NULL))
+ else if ((pup->but->type == UI_BTYPE_PULLDOWN) ||
+ (UI_but_menutype_get(pup->but) != NULL))
{
- direction = UI_DOWN;
+ direction = UI_DIR_DOWN;
}
else {
- direction = UI_TOP;
+ direction = UI_DIR_UP;
}
}
else {
minwidth = 50;
- direction = UI_DOWN;
+ direction = UI_DIR_DOWN;
}
- flip = (direction == UI_DOWN);
+ flip = (direction == UI_DIR_DOWN);
block = pup->block;
/* in some cases we create the block before the region,
* so we set it delayed here if necessary */
if (BLI_findindex(&handle->region->uiblocks, block) == -1)
- uiBlockSetRegion(block, handle->region);
+ UI_block_region_set(block, handle->region);
block->direction = direction;
- uiBlockLayoutResolve(block, &width, &height);
+ UI_block_layout_resolve(block, &width, &height);
- uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
+ UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
if (pup->popup) {
uiBut *but_activate = NULL;
- uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
- uiBlockSetDirection(block, direction);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NUMSELECT);
+ UI_block_direction_set(block, direction);
/* offset the mouse position, possibly based on earlier selection */
if ((block->flag & UI_BLOCK_POPUP_MEMORY) &&
@@ -2518,11 +2586,11 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
* to be within the window bounds may move it away from the mouse,
* This ensures we set an item to be active. */
if (but_activate) {
- ui_button_activate_over(C, handle->region, but_activate);
+ ui_but_activate_over(C, handle->region, but_activate);
}
block->minbounds = minwidth;
- uiMenuPopupBoundsBlock(block, 1, offset[0], offset[1]);
+ UI_block_bounds_set_menu(block, 1, offset[0], offset[1]);
}
else {
/* for a header menu we set the direction automatic */
@@ -2531,35 +2599,36 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
if (sa && sa->headertype == HEADERDOWN) {
ARegion *ar = CTX_wm_region(C);
if (ar && ar->regiontype == RGN_TYPE_HEADER) {
- uiBlockSetDirection(block, UI_TOP);
- uiBlockFlipOrder(block);
+ UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_order_flip(block);
}
}
}
block->minbounds = minwidth;
- uiTextBoundsBlock(block, 3.0f * UI_UNIT_X);
+ UI_block_bounds_set_text(block, 3.0f * UI_UNIT_X);
}
/* if menu slides out of other menu, override direction */
if (pup->slideout)
- uiBlockSetDirection(block, UI_RIGHT);
+ UI_block_direction_set(block, UI_DIR_RIGHT);
return pup->block;
}
-uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut *but,
- uiMenuCreateFunc menu_func, void *arg)
+uiPopupBlockHandle *ui_popup_menu_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc menu_func, void *arg)
{
wmWindow *window = CTX_wm_window(C);
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
uiPopupBlockHandle *handle;
uiPopupMenu *pup;
pup = MEM_callocN(sizeof(uiPopupMenu), __func__);
- pup->block = uiBeginBlock(C, NULL, __func__, UI_EMBOSSP);
+ pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS_PULLDOWN);
pup->block->flag |= UI_BLOCK_NUMSELECT; /* default menus to numselect */
- pup->layout = uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, MENU_PADDING, style);
+ pup->layout = UI_block_layout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, MENU_PADDING, style);
pup->slideout = but ? ui_block_is_menu(but->block) : false;
pup->but = but;
uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN);
@@ -2596,7 +2665,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
if (!but) {
handle->popup = true;
- UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -2608,16 +2677,16 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
/******************** Popup Menu API with begin and end ***********************/
/* only return handler, and set optional title */
-uiPopupMenu *uiPupMenuBegin(bContext *C, const char *title, int icon)
+uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
{
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
uiPopupMenu *pup = MEM_callocN(sizeof(uiPopupMenu), "popup menu");
uiBut *but;
- pup->block = uiBeginBlock(C, NULL, __func__, UI_EMBOSSP);
- pup->block->flag |= UI_BLOCK_POPUP_MEMORY;
+ pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS_PULLDOWN);
+ pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP;
pup->block->puphash = ui_popup_menu_hash(title);
- pup->layout = uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, MENU_PADDING, style);
+ pup->layout = UI_block_layout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, MENU_PADDING, style);
/* note, this intentionally differs from the menu & submenu default because many operators
* use popups like this to select one of their options - where having invoke doesn't make sense */
@@ -2632,10 +2701,10 @@ uiPopupMenu *uiPupMenuBegin(bContext *C, const char *title, int icon)
if (icon) {
BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
- uiDefIconTextBut(pup->block, LABEL, 0, icon, titlestr, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(pup->block, UI_BTYPE_LABEL, 0, icon, titlestr, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
else {
- but = uiDefBut(pup->block, LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but = uiDefBut(pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->drawflag = UI_BUT_TEXT_LEFT;
}
@@ -2646,7 +2715,7 @@ uiPopupMenu *uiPupMenuBegin(bContext *C, const char *title, int icon)
}
/* set the whole structure to work */
-void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
+void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *menu;
@@ -2658,13 +2727,13 @@ void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
menu->popup = true;
- UI_add_popup_handlers(C, &window->modalhandlers, menu, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(C);
MEM_freeN(pup);
}
-uiLayout *uiPupMenuLayout(uiPopupMenu *pup)
+uiLayout *UI_popup_menu_layout(uiPopupMenu *pup)
{
return pup->layout;
}
@@ -2683,11 +2752,11 @@ static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handl
/* in some cases we create the block before the region,
* so we set it delayed here if necessary */
if (BLI_findindex(&handle->region->uiblocks, block) == -1)
- uiBlockSetRegion(block, handle->region);
+ UI_block_region_set(block, handle->region);
- uiBlockLayoutResolve(block, &width, &height);
+ UI_block_layout_resolve(block, &width, &height);
- uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NUMSELECT);
block->minbounds = minwidth;
block->bounds = 1;
@@ -2701,26 +2770,56 @@ static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handl
return pie->block_radial;
}
-static float uiPieTitleWidth(const char *name, int icon)
+static float ui_pie_menu_title_width(const char *name, int icon)
{
- return (UI_GetStringWidth(name) +
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ return (UI_fontstyle_string_width(fstyle, name) +
(UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
}
-uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const wmEvent *event)
+uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, const wmEvent *event)
{
- uiStyle *style = UI_GetStyleDraw();
- uiPieMenu *pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu");
+ uiStyle *style;
+ uiPieMenu *pie;
+ short event_type;
- pie->block_radial = uiBeginBlock(C, NULL, __func__, UI_EMBOSS);
+ wmWindow *win = CTX_wm_window(C);
+
+ style = UI_style_get_dpi();
+ pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu");
+
+ pie->block_radial = UI_block_begin(C, NULL, __func__, UI_EMBOSS);
/* may be useful later to allow spawning pies
* from old positions */
/* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */
pie->block_radial->puphash = ui_popup_menu_hash(title);
pie->block_radial->flag |= UI_BLOCK_RADIAL;
- pie->block_radial->pie_data.event = event->type;
- pie->layout = uiBlockLayout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
+ /* if pie is spawned by a left click, it is always assumed to be click style */
+ if (event->type == LEFTMOUSE) {
+ pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ pie->block_radial->pie_data.event = EVENT_NONE;
+ win->lock_pie_event = EVENT_NONE;
+ }
+ else {
+ if (win->last_pie_event != EVENT_NONE) {
+ /* original pie key has been released, so don't propagate the event */
+ if (win->lock_pie_event == EVENT_NONE) {
+ event_type = EVENT_NONE;
+ pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ }
+ else
+ event_type = win->last_pie_event;
+ }
+ else {
+ event_type = event->type;
+ }
+
+ pie->block_radial->pie_data.event = event_type;
+ win->lock_pie_event = event_type;
+ }
+
+ pie->layout = UI_block_layout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
pie->mx = event->x;
pie->my = event->y;
@@ -2731,12 +2830,12 @@ uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const
int w;
if (icon) {
BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
- w = uiPieTitleWidth(titlestr, icon);
- but = uiDefIconTextBut(pie->block_radial, LABEL, 0, icon, titlestr, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ w = ui_pie_menu_title_width(titlestr, icon);
+ but = uiDefIconTextBut(pie->block_radial, UI_BTYPE_LABEL, 0, icon, titlestr, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
else {
- w = uiPieTitleWidth(title, 0);
- but = uiDefBut(pie->block_radial, LABEL, 0, title, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ w = ui_pie_menu_title_width(title, 0);
+ but = uiDefBut(pie->block_radial, UI_BTYPE_LABEL, 0, title, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
/* do not align left */
but->drawflag &= ~UI_BUT_TEXT_LEFT;
@@ -2745,7 +2844,7 @@ uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const
return pie;
}
-void uiPieMenuEnd(bContext *C, uiPieMenu *pie)
+void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *menu;
@@ -2754,18 +2853,20 @@ void uiPieMenuEnd(bContext *C, uiPieMenu *pie)
menu->popup = true;
menu->towardstime = PIL_check_seconds_timer();
- UI_add_popup_handlers(C, &window->modalhandlers, menu, true);
+ UI_popup_handlers_add(
+ C, &window->modalhandlers,
+ menu, WM_HANDLER_ACCEPT_DBL_CLICK);
WM_event_add_mousemove(C);
MEM_freeN(pie);
}
-uiLayout *uiPieMenuLayout(uiPieMenu *pie)
+uiLayout *UI_pie_menu_layout(uiPieMenu *pie)
{
return pie->layout;
}
-void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *event)
+int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *event)
{
uiPieMenu *pie;
uiLayout *layout;
@@ -2774,14 +2875,14 @@ void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *even
if (mt == NULL) {
printf("%s: named menu \"%s\" not found\n", __func__, idname);
- return;
+ return OPERATOR_CANCELLED;
}
if (mt->poll && mt->poll(C, mt) == 0)
- return;
+ return OPERATOR_CANCELLED;
- pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event);
- layout = uiPieMenuLayout(pie);
+ pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event);
+ layout = UI_pie_menu_layout(pie);
menu.layout = layout;
menu.type = mt;
@@ -2792,26 +2893,32 @@ void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *even
mt->draw(C, &menu);
- uiPieMenuEnd(C, pie);
+ UI_pie_menu_end(C, pie);
+
+ return OPERATOR_INTERFACE;
}
-void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
- const char *propname, const wmEvent *event)
+int UI_pie_menu_invoke_from_operator_enum(
+ struct bContext *C, const char *title, const char *opname,
+ const char *propname, const wmEvent *event)
{
uiPieMenu *pie;
uiLayout *layout;
- pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
- layout = uiPieMenuLayout(pie);
+ pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
+ layout = UI_pie_menu_layout(pie);
layout = uiLayoutRadial(layout);
uiItemsEnumO(layout, opname, propname);
- uiPieMenuEnd(C, pie);
+ UI_pie_menu_end(C, pie);
+
+ return OPERATOR_INTERFACE;
}
-void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path,
- const wmEvent *event)
+int UI_pie_menu_invoke_from_rna_enum(
+ struct bContext *C, const char *title, const char *path,
+ const wmEvent *event)
{
PointerRNA ctx_ptr;
PointerRNA r_ptr;
@@ -2822,28 +2929,31 @@ void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path,
RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
- return;
+ return OPERATOR_CANCELLED;
}
/* invalid property, only accept enums */
if (RNA_property_type(r_prop) != PROP_ENUM) {
BLI_assert(0);
- return;
+ return OPERATOR_CANCELLED;
}
- pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
- layout = uiPieMenuLayout(pie);
+ pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event);
+
+ layout = UI_pie_menu_layout(pie);
layout = uiLayoutRadial(layout);
uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0);
- uiPieMenuEnd(C, pie);
+ UI_pie_menu_end(C, pie);
+
+ return OPERATOR_INTERFACE;
}
/*************************** Standard Popup Menus ****************************/
-void uiPupMenuReports(bContext *C, ReportList *reports)
+void UI_popup_menu_reports(bContext *C, ReportList *reports)
{
Report *report;
@@ -2864,8 +2974,8 @@ void uiPupMenuReports(bContext *C, ReportList *reports)
if (pup == NULL) {
char title[UI_MAX_DRAW_STR];
BLI_snprintf(title, sizeof(title), "%s: %s", IFACE_("Report"), report->typestr);
- pup = uiPupMenuBegin(C, title, ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, title, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
}
else {
uiItemS(layout);
@@ -2873,7 +2983,7 @@ void uiPupMenuReports(bContext *C, ReportList *reports)
/* split each newline into a label */
msg = report->message;
- icon = uiIconFromReportType(report->type);
+ icon = UI_icon_from_report_type(report->type);
do {
char buf[UI_MAX_DRAW_STR];
msg_next = strchr(msg, '\n');
@@ -2888,11 +2998,11 @@ void uiPupMenuReports(bContext *C, ReportList *reports)
}
if (pup) {
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
}
-bool uiPupMenuInvoke(bContext *C, const char *idname, ReportList *reports)
+int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -2901,14 +3011,14 @@ bool uiPupMenuInvoke(bContext *C, const char *idname, ReportList *reports)
if (mt == NULL) {
BKE_reportf(reports, RPT_ERROR, "Menu \"%s\" not found", idname);
- return false;
+ return OPERATOR_CANCELLED;
}
if (mt->poll && mt->poll(C, mt) == 0)
- return false;
+ return OPERATOR_CANCELLED;
- pup = uiPupMenuBegin(C, IFACE_(mt->label), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
menu.layout = layout;
menu.type = mt;
@@ -2919,15 +3029,15 @@ bool uiPupMenuInvoke(bContext *C, const char *idname, ReportList *reports)
mt->draw(C, &menu);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return true;
+ return OPERATOR_INTERFACE;
}
/*************************** Popup Block API **************************/
-void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext)
+void UI_popup_block_invoke_ex(bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
@@ -2937,16 +3047,16 @@ void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opn
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
-void uiPupBlock(bContext *C, uiBlockCreateFunc func, void *arg)
+void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg)
{
- uiPupBlockO(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT);
+ UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT);
}
-void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg)
+void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
@@ -2960,7 +3070,7 @@ void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_f
handle->cancel_func = cancel_func;
// handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -2979,27 +3089,28 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int
handle->cancel_func = confirm_cancel_operator;
handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
#endif
-void uiPupBlockClose(bContext *C, uiBlock *block)
+void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
{
+ /* if loading new .blend while popup is open, window will be NULL */
if (block->handle) {
- wmWindow *win = CTX_wm_window(C);
-
- /* if loading new .blend while popup is open, window will be NULL */
if (win) {
- UI_remove_popup_handlers(&win->modalhandlers, block->handle);
+ UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
}
}
}
-float *ui_block_hsv_get(uiBlock *block)
+ColorPicker *ui_block_colorpicker_create(struct uiBlock *block)
{
- return block->_hsv;
+ ColorPicker *cpicker = MEM_callocN(sizeof(ColorPicker), "color_picker");
+ BLI_addhead(&block->color_pickers.list, cpicker);
+
+ return cpicker;
}
void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3])
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index c27789c0fc9..25a187c43ad 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -45,9 +45,12 @@
#include "BKE_global.h"
+#include "BIF_gl.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#ifdef WITH_INTERNATIONAL
+# include "BLT_translation.h"
+#endif
#include "UI_interface.h"
@@ -61,7 +64,7 @@
/* style + theme + layout-engine = UI */
-/*
+/**
* This is a complete set of layout rules, the 'state' of the Layout
* Engine. Multiple styles are possible, defined via C or Python. Styles
* get a name, and will typically get activated per region type, like
@@ -145,16 +148,38 @@ static uiFont *uifont_to_blfont(int id)
/* *************** draw ************************ */
-void uiStyleFontDrawExt(uiFontStyle *fs, const rcti *rect, const char *str,
- size_t len, float *r_xofs, float *r_yofs)
+void UI_fontstyle_draw_ex(
+ const uiFontStyle *fs, const rcti *rect, const char *str,
+ size_t len, float *r_xofs, float *r_yofs)
{
- float height;
int xofs = 0, yofs;
+ int font_flag = BLF_CLIPPING;
- uiStyleFontSet(fs);
+ UI_fontstyle_set(fs);
- height = BLF_ascender(fs->uifont_id);
- yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height));
+ /* set the flag */
+ if (fs->shadow) {
+ font_flag |= BLF_SHADOW;
+ BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
+ BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
+ }
+ if (fs->kerning == 1) {
+ font_flag |= BLF_KERNING_DEFAULT;
+ }
+ if (fs->word_wrap == 1) {
+ font_flag |= BLF_WORD_WRAP;
+ }
+
+ BLF_enable(fs->uifont_id, font_flag);
+
+ if (fs->word_wrap == 1) {
+ /* draw from boundbox top */
+ yofs = BLI_rcti_size_y(rect) - BLF_height_max(fs->uifont_id);
+ }
+ else {
+ /* draw from boundbox center */
+ yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - BLF_ascender(fs->uifont_id)));
+ }
if (fs->align == UI_STYLE_TEXT_CENTER) {
xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len)));
@@ -169,45 +194,34 @@ void uiStyleFontDrawExt(uiFontStyle *fs, const rcti *rect, const char *str,
/* clip is very strict, so we give it some space */
BLF_clipping(fs->uifont_id, rect->xmin - 2, rect->ymin - 4, rect->xmax + 1, rect->ymax + 4);
- BLF_enable(fs->uifont_id, BLF_CLIPPING);
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
- if (fs->shadow) {
- BLF_enable(fs->uifont_id, BLF_SHADOW);
- BLF_shadow(fs->uifont_id, fs->shadow, fs->shadowcolor, fs->shadowcolor, fs->shadowcolor, fs->shadowalpha);
- BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady);
- }
-
- if (fs->kerning == 1)
- BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
-
BLF_draw(fs->uifont_id, str, len);
- BLF_disable(fs->uifont_id, BLF_CLIPPING);
- if (fs->shadow)
- BLF_disable(fs->uifont_id, BLF_SHADOW);
- if (fs->kerning == 1)
- BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
+
+ BLF_disable(fs->uifont_id, font_flag);
*r_xofs = xofs;
*r_yofs = yofs;
}
-void uiStyleFontDraw(uiFontStyle *fs, const rcti *rect, const char *str)
+void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str)
{
float xofs, yofs;
- uiStyleFontDrawExt(fs, rect, str,
- BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
+
+ UI_fontstyle_draw_ex(
+ fs, rect, str,
+ BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
}
/* drawn same as above, but at 90 degree angle */
-void uiStyleFontDrawRotated(uiFontStyle *fs, const rcti *rect, const char *str)
+void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str)
{
float height;
int xofs, yofs;
float angle;
rcti txtrect;
- uiStyleFontSet(fs);
+ UI_fontstyle_set(fs);
height = BLF_ascender(fs->uifont_id);
/* becomes x-offset when rotated */
@@ -218,7 +232,7 @@ void uiStyleFontDrawRotated(uiFontStyle *fs, const rcti *rect, const char *str)
/* rotate counter-clockwise for now (assumes left-to-right language)*/
xofs += height;
yofs = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX) + 5;
- angle = (float)M_PI / 2.0f;
+ angle = M_PI_2;
/* translate rect to vertical */
txtrect.xmin = rect->xmin - BLI_rcti_size_y(rect);
@@ -253,20 +267,84 @@ void uiStyleFontDrawRotated(uiFontStyle *fs, const rcti *rect, const char *str)
BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
}
+/**
+ * Similar to #UI_fontstyle_draw
+ * but ignore alignment, shadow & no clipping rect.
+ *
+ * For drawing on-screen labels.
+ */
+void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str)
+{
+ if (fs->kerning == 1)
+ BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
+
+ UI_fontstyle_set(fs);
+ BLF_position(fs->uifont_id, x, y, 0.0f);
+ BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (fs->kerning == 1)
+ BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
+}
+
+/**
+ * Same as #UI_fontstyle_draw but draw a colored backdrop.
+ */
+void UI_fontstyle_draw_simple_backdrop(
+ const uiFontStyle *fs, float x, float y, const char *str,
+ const unsigned char fg[4], const unsigned char bg[4])
+{
+ if (fs->kerning == 1)
+ BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
+
+ UI_fontstyle_set(fs);
+
+ {
+ const float width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ const float height = BLF_height_max(fs->uifont_id);
+ const float decent = BLF_descender(fs->uifont_id);
+ const float margin = height / 4.0f;
+
+ /* backdrop */
+ glColor4ubv(bg);
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
+ UI_draw_roundbox(
+ x - margin,
+ (y + decent) - margin,
+ x + width + margin,
+ (y + decent) + height + margin,
+ margin);
+
+ glColor4ubv(fg);
+ }
+
+
+ BLF_position(fs->uifont_id, x, y, 0.0f);
+ BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (fs->kerning == 1)
+ BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
+}
+
+
/* ************** helpers ************************ */
/* XXX: read a style configure */
-uiStyle *UI_GetStyle(void)
+uiStyle *UI_style_get(void)
{
+#if 0
uiStyle *style = NULL;
/* offset is two struct uiStyle pointers */
- /* style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2) */;
+ style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2);
return (style != NULL) ? style : U.uistyles.first;
+#else
+ return U.uistyles.first;
+#endif
}
/* for drawing, scaled with DPI setting */
-uiStyle *UI_GetStyleDraw(void)
+uiStyle *UI_style_get_dpi(void)
{
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
static uiStyle _style;
_style = *style;
@@ -289,41 +367,29 @@ uiStyle *UI_GetStyleDraw(void)
return &_style;
}
-/* temporarily, does widget font */
-int UI_GetStringWidth(const char *str)
+int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
{
- uiStyle *style = UI_GetStyle();
- uiFontStyle *fstyle = &style->widget;
int width;
- if (fstyle->kerning == 1) /* for BLF_width */
- BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ if (fs->kerning == 1) /* for BLF_width */
+ BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
- uiStyleFontSet(fstyle);
- width = BLF_width(fstyle->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ UI_fontstyle_set(fs);
+ width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
- if (fstyle->kerning == 1)
- BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ if (fs->kerning == 1)
+ BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
return width;
}
-/* temporarily, does widget font */
-void UI_DrawString(float x, float y, const char *str)
+int UI_fontstyle_height_max(const uiFontStyle *fs)
{
- uiStyle *style = UI_GetStyle();
-
- if (style->widget.kerning == 1)
- BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
-
- uiStyleFontSet(&style->widget);
- BLF_position(style->widget.uifont_id, x, y, 0.0f);
- BLF_draw(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
-
- if (style->widget.kerning == 1)
- BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
+ UI_fontstyle_set(fs);
+ return BLF_height_max(fs->uifont_id);
}
+
/* ************** init exit ************************ */
/* called on each startup.blend read */
@@ -396,11 +462,10 @@ void uiStyleInit(void)
if (font->blf_id == -1) {
font->blf_id = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
}
- else {
- BLF_default_set(font->blf_id);
- }
}
+ BLF_default_set(font->blf_id);
+
if (font->blf_id == -1) {
if (G.debug & G_DEBUG)
printf("%s: error, no fonts available\n", __func__);
@@ -451,7 +516,7 @@ void uiStyleInit(void)
BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72);
}
-void uiStyleFontSet(uiFontStyle *fs)
+void UI_fontstyle_set(const uiFontStyle *fs)
{
uiFont *font = uifont_to_blfont(fs->uifont_id);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b0bea42e3bc..1238b883e9a 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -31,7 +31,6 @@
#include "MEM_guardedalloc.h"
-#include "DNA_dynamicpaint_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -48,7 +47,7 @@
#include "BLI_fnmatch.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -74,7 +73,6 @@
#include "ED_util.h"
#include "RNA_access.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -156,9 +154,9 @@ static void id_search_cb(const bContext *C, void *arg_template, const char *str,
char name_ui[MAX_ID_NAME + 1];
name_uiprefix_id(name_ui, id);
- iconid = ui_id_icon_get((bContext *)C, id, template->preview);
+ iconid = ui_id_icon_get(C, id, template->preview);
- if (false == uiSearchItemAdd(items, name_ui, id, iconid))
+ if (false == UI_search_item_add(items, name_ui, id, iconid))
break;
}
}
@@ -183,38 +181,38 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* get active id for showing first item */
idptr = RNA_property_pointer_get(&template.ptr, template.prop);
- block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
- uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_SEARCH_MENU);
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
/* preview thumbnails */
if (template.prv_rows > 0 && template.prv_cols > 0) {
int w = 4 * U.widget_unit * template.prv_cols;
- int h = 4 * U.widget_unit * template.prv_rows + U.widget_unit;
+ int h = 5 * U.widget_unit * template.prv_rows;
/* fake button, it holds space for search items */
- uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
template.prv_rows, template.prv_cols, "");
- uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
+ UI_but_func_search_set(but, id_search_cb, &template, id_search_call_cb, idptr.data);
}
/* list view */
else {
- const int searchbox_width = uiSearchBoxWidth();
- const int searchbox_height = uiSearchBoxHeight();
+ const int searchbox_width = UI_searchbox_size_x();
+ const int searchbox_height = UI_searchbox_size_y();
/* fake button, it holds space for search items */
- uiDefBut(block, LABEL, 0, "", 10, 15, searchbox_width, searchbox_height, NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, searchbox_width, searchbox_height, NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, searchbox_width, UI_UNIT_Y - 1, 0, 0, "");
- uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
+ UI_but_func_search_set(but, id_search_cb, &template, id_search_call_cb, idptr.data);
}
- uiBoundsBlock(block, 0.3f * U.widget_unit);
- uiBlockSetDirection(block, UI_DOWN);
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
+ UI_block_direction_set(block, UI_DIR_DOWN);
/* give search-field focus */
- uiButSetFocusOnEnter(win, but);
+ UI_but_focus_on_enter_event(win, but);
/* this type of search menu requires undo */
but->flag |= UI_BUT_UNDO;
@@ -225,7 +223,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
-void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
{
TemplateID *template;
ARegion *ar = CTX_wm_region(C);
@@ -268,15 +266,18 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_OPEN:
case UI_ID_ADD_NEW:
- /* these call uiIDContextProperty */
+ /* these call UI_context_active_but_prop_get_templateID */
break;
case UI_ID_DELETE:
memset(&idptr, 0, sizeof(idptr));
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
RNA_property_update(C, &template->ptr, template->prop);
- if (id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
+ if (id && CTX_wm_window(C)->eventstate->shift) {
+ /* only way to force-remove data (on save) */
+ id->flag &= ~LIB_FAKEUSER;
id->us = 0;
+ }
break;
case UI_ID_FAKE_USER:
@@ -352,6 +353,8 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_BR: return N_("Browse Brush to be linked");
case ID_PA: return N_("Browse Particle Settings to be linked");
case ID_GD: return N_("Browse Grease Pencil Data to be linked");
+ case ID_MC: return N_("Browse Movie Clip to be linked");
+ case ID_MSK: return N_("Browse Mask to be linked");
case ID_PAL: return N_("Browse Palette Data to be linked");
case ID_PC: return N_("Browse Paint Curve Data to be linked");
}
@@ -359,45 +362,23 @@ static const char *template_id_browse_tip(StructRNA *type)
return N_("Browse ID data to be linked");
}
-/* Return a type-based i18n context, needed e.g. by "New" button.
+/**
+ * \return a type-based i18n context, needed e.g. by "New" button.
* In most languages, this adjective takes different form based on gender of type name...
*/
#ifdef WITH_INTERNATIONAL
static const char *template_id_context(StructRNA *type)
{
if (type) {
- switch (RNA_type_to_ID_code(type)) {
- case ID_SCE: return BLF_I18NCONTEXT_ID_SCENE;
- case ID_OB: return BLF_I18NCONTEXT_ID_OBJECT;
- case ID_ME: return BLF_I18NCONTEXT_ID_MESH;
- case ID_CU: return BLF_I18NCONTEXT_ID_CURVE;
- case ID_MB: return BLF_I18NCONTEXT_ID_METABALL;
- case ID_MA: return BLF_I18NCONTEXT_ID_MATERIAL;
- case ID_TE: return BLF_I18NCONTEXT_ID_TEXTURE;
- case ID_IM: return BLF_I18NCONTEXT_ID_IMAGE;
- case ID_LS: return BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE;
- case ID_LT: return BLF_I18NCONTEXT_ID_LATTICE;
- case ID_LA: return BLF_I18NCONTEXT_ID_LAMP;
- case ID_CA: return BLF_I18NCONTEXT_ID_CAMERA;
- case ID_WO: return BLF_I18NCONTEXT_ID_WORLD;
- case ID_SCR: return BLF_I18NCONTEXT_ID_SCREEN;
- case ID_TXT: return BLF_I18NCONTEXT_ID_TEXT;
- case ID_SPK: return BLF_I18NCONTEXT_ID_SPEAKER;
- case ID_SO: return BLF_I18NCONTEXT_ID_SOUND;
- case ID_AR: return BLF_I18NCONTEXT_ID_ARMATURE;
- case ID_AC: return BLF_I18NCONTEXT_ID_ACTION;
- case ID_NT: return BLF_I18NCONTEXT_ID_NODETREE;
- case ID_BR: return BLF_I18NCONTEXT_ID_BRUSH;
- case ID_PA: return BLF_I18NCONTEXT_ID_PARTICLESETTINGS;
- case ID_GD: return BLF_I18NCONTEXT_ID_GPENCIL;
- }
- }
- return BLF_I18NCONTEXT_DEFAULT;
+ return BKE_idcode_to_translation_context(RNA_type_to_ID_code(type));
+ }
+ return BLT_I18NCONTEXT_DEFAULT;
}
#endif
-static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
- const char *newop, const char *openop, const char *unlinkop)
+static void template_ID(
+ bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
+ const char *newop, const char *openop, const char *unlinkop)
{
uiBut *but;
uiBlock *block;
@@ -412,7 +393,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
// lb = template->idlb;
block = uiLayoutGetBlock(layout);
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
if (idptr.type)
type = idptr.type;
@@ -422,25 +403,24 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6,
TIP_(template_id_browse_tip(type)));
- but->icon = id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type);
- uiButSetFlag(but, UI_HAS_ICON | UI_ICON_PREVIEW);
+ ui_def_but_icon(but, id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type),
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if ((idfrom && idfrom->lib) || !editable)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
uiLayoutRow(layout, true);
}
else if (flag & UI_ID_BROWSE) {
but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y,
TIP_(template_id_browse_tip(type)));
- but->icon = RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
/* default dragging of icon for id browse buttons */
- uiButSetDragID(but, id);
- uiButSetFlag(but, UI_HAS_ICON);
- uiButSetDrawFlag(but, UI_BUT_ICON_LEFT);
+ UI_but_drag_set_id(but, id);
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
if ((idfrom && idfrom->lib) || !editable)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
/* text button with name */
@@ -450,37 +430,39 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
//text_idbutton(id, name);
name[0] = '\0';
- but = uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_TEXT, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y,
&idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
- if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
+ if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib) {
if (id->flag & LIB_INDIRECT) {
- but = uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Indirect library datablock, cannot change"));
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
- but = uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local"));
if (!id_make_local(id, true /* test */) || (idfrom && idfrom->lib))
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
}
if (id->us > 1) {
char numstr[32];
+ short numstr_len;
- BLI_snprintf(numstr, sizeof(numstr), "%d", id->us);
+ numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", id->us);
- but = uiDefBut(block, BUT, 0, numstr, 0, 0, UI_UNIT_X + ((id->us < 10) ? 0 : 10), UI_UNIT_Y,
- NULL, 0, 0, 0, 0,
+ but = uiDefBut(block, UI_BTYPE_BUT, 0, numstr, 0, 0,
+ numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
TIP_("Display number of users of this data (click to make a single-user copy)"));
+ but->flag |= UI_BUT_UNDO;
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
if (/* test only */
(id_copy(id, NULL, true) == false) ||
(idfrom && idfrom->lib) ||
@@ -488,14 +470,14 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
/* object in editmode - don't change data */
(idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT)))
{
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
- if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
+ if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
- uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
+ uiDefButR(block, UI_BTYPE_TOGGLE, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
}
}
@@ -503,54 +485,54 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
int w = id ? UI_UNIT_X : (flag & UI_ID_OPEN) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
/* i18n markup, does nothing! */
- BLF_I18N_MSGID_MULTI_CTXT("New", BLF_I18NCONTEXT_DEFAULT,
- BLF_I18NCONTEXT_ID_SCENE,
- BLF_I18NCONTEXT_ID_OBJECT,
- BLF_I18NCONTEXT_ID_MESH,
- BLF_I18NCONTEXT_ID_CURVE,
- BLF_I18NCONTEXT_ID_METABALL,
- BLF_I18NCONTEXT_ID_MATERIAL,
- BLF_I18NCONTEXT_ID_TEXTURE,
- BLF_I18NCONTEXT_ID_IMAGE,
- BLF_I18NCONTEXT_ID_LATTICE,
- BLF_I18NCONTEXT_ID_LAMP,
- BLF_I18NCONTEXT_ID_CAMERA,
- BLF_I18NCONTEXT_ID_WORLD,
- BLF_I18NCONTEXT_ID_SCREEN,
- BLF_I18NCONTEXT_ID_TEXT,
+ BLT_I18N_MSGID_MULTI_CTXT("New", BLT_I18NCONTEXT_DEFAULT,
+ BLT_I18NCONTEXT_ID_SCENE,
+ BLT_I18NCONTEXT_ID_OBJECT,
+ BLT_I18NCONTEXT_ID_MESH,
+ BLT_I18NCONTEXT_ID_CURVE,
+ BLT_I18NCONTEXT_ID_METABALL,
+ BLT_I18NCONTEXT_ID_MATERIAL,
+ BLT_I18NCONTEXT_ID_TEXTURE,
+ BLT_I18NCONTEXT_ID_IMAGE,
+ BLT_I18NCONTEXT_ID_LATTICE,
+ BLT_I18NCONTEXT_ID_LAMP,
+ BLT_I18NCONTEXT_ID_CAMERA,
+ BLT_I18NCONTEXT_ID_WORLD,
+ BLT_I18NCONTEXT_ID_SCREEN,
+ BLT_I18NCONTEXT_ID_TEXT,
);
- BLF_I18N_MSGID_MULTI_CTXT("New", BLF_I18NCONTEXT_ID_SPEAKER,
- BLF_I18NCONTEXT_ID_SOUND,
- BLF_I18NCONTEXT_ID_ARMATURE,
- BLF_I18NCONTEXT_ID_ACTION,
- BLF_I18NCONTEXT_ID_NODETREE,
- BLF_I18NCONTEXT_ID_BRUSH,
- BLF_I18NCONTEXT_ID_PARTICLESETTINGS,
- BLF_I18NCONTEXT_ID_GPENCIL,
- BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE,
+ BLT_I18N_MSGID_MULTI_CTXT("New", BLT_I18NCONTEXT_ID_SPEAKER,
+ BLT_I18NCONTEXT_ID_SOUND,
+ BLT_I18NCONTEXT_ID_ARMATURE,
+ BLT_I18NCONTEXT_ID_ACTION,
+ BLT_I18NCONTEXT_ID_NODETREE,
+ BLT_I18NCONTEXT_ID_BRUSH,
+ BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
+ BLT_I18NCONTEXT_ID_GPENCIL,
+ BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
);
if (newop) {
- but = uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN,
+ but = uiDefIconTextButO(block, UI_BTYPE_BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN,
(id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL);
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
}
else {
- but = uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"),
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
}
if ((idfrom && idfrom->lib) || !editable)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
/* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
* Only for images, sound and fonts */
if (id && BKE_pack_check(id)) {
- but = uiDefIconButO(block, BUT, "FILE_OT_unpack_item", WM_OP_INVOKE_REGION_WIN, ICON_PACKAGE, 0, 0,
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_unpack_item", WM_OP_INVOKE_REGION_WIN, ICON_PACKAGE, 0, 0,
UI_UNIT_X, UI_UNIT_Y, TIP_("Packed File, click to unpack"));
- uiButGetOperatorPtrRNA(but);
+ UI_but_operator_ptr_get(but);
RNA_string_set(but->opptr, "id_name", id->name + 2);
RNA_int_set(but->opptr, "id_type", GS(id->name));
@@ -560,18 +542,18 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
if (openop) {
- but = uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"),
+ but = uiDefIconTextButO(block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"),
0, 0, w, UI_UNIT_Y, NULL);
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
}
else {
- but = uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y,
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y,
NULL, 0, 0, 0, 0, NULL);
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
}
if ((idfrom && idfrom->lib) || !editable)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
/* delete button */
@@ -581,26 +563,26 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
but = NULL;
if (unlinkop) {
- but = uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ but = uiDefIconButO(block, UI_BTYPE_BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
/* so we can access the template from operators, font unlinking needs this */
- uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
+ UI_but_funcN_set(but, NULL, MEM_dupallocN(template), NULL);
}
else {
if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
- but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
TIP_("Unlink datablock "
"(Shift + Click to set users to zero, data will then not be saved)"));
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) {
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
}
if (but) {
if ((idfrom && idfrom->lib) || !editable) {
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
}
@@ -608,11 +590,12 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
if (idcode == ID_TE)
uiTemplateTextureShow(layout, C, &template->ptr, template->prop);
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
-static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
+static void ui_template_id(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
{
TemplateID *template;
PropertyRNA *prop;
@@ -652,21 +635,24 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const
MEM_freeN(template);
}
-void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+void uiTemplateID(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, 0);
}
-void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+void uiTemplateIDBrowse(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, 0, 0);
}
-void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int rows, int cols)
+void uiTemplateIDPreview(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop, int rows, int cols)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols);
@@ -674,13 +660,15 @@ void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
/************************ ID Chooser Template ***************************/
-/* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
+/**
+ * This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
*
* - propname: property identifier for property that ID-pointer gets stored to
* - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
*/
-void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
- const char *text)
+void uiTemplateAnyID(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
+ const char *text)
{
PropertyRNA *propID, *propType;
uiLayout *split, *row, *sub;
@@ -733,7 +721,8 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co
/* ---------- */
-/* This is creating/editing RNA-Paths
+/**
+ * This is creating/editing RNA-Paths
*
* - ptr: struct which holds the path property
* - propname: property identifier for property that path gets stored to
@@ -814,10 +803,11 @@ static int modifier_is_simulation(ModifierData *md)
}
}
-static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
- ModifierData *md, int index, int cageIndex, int lastCageIndex)
+static uiLayout *draw_modifier(
+ uiLayout *layout, Scene *scene, Object *ob,
+ ModifierData *md, int index, int cageIndex, int lastCageIndex)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
PointerRNA ptr;
uiBut *but;
uiBlock *block;
@@ -842,26 +832,27 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
/* VIRTUAL MODIFIER */
/* XXX this is not used now, since these cannot be accessed via RNA */
BLI_snprintf(str, sizeof(str), IFACE_("%s parent deform"), md->name);
- uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Modifier name"));
+ uiDefBut(block, UI_BTYPE_LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Modifier name"));
- but = uiDefBut(block, BUT, 0, IFACE_("Make Real"), 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0,
+ but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Make Real"), 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0,
TIP_("Convert virtual modifier to a real modifier"));
- uiButSetFunc(but, modifiers_convertToReal, ob, md);
+ UI_but_func_set(but, modifiers_convertToReal, ob, md);
}
else {
/* REAL MODIFIER */
row = uiLayoutRow(box, false);
block = uiLayoutGetBlock(row);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* Open/Close ................................. */
uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
/* modifier-type icon */
uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
/* modifier name */
+ md->scene = scene;
if (mti->isDisabled && mti->isDisabled(md, 0)) {
uiLayoutSetRedAlert(row, true);
}
@@ -869,7 +860,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiLayoutSetRedAlert(row, false);
/* mode enabling buttons */
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
/* Softbody not allowed in this situation, enforce! */
if (((md->type != eModifierType_Softbody && md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
(md->type != eModifierType_Surface) )
@@ -900,10 +891,10 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
/* add disabled pre-tessellated button, so users could have
* message for this modifiers */
- but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0,
+ but = uiDefIconButBitI(block, UI_BTYPE_TOGGLE, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0,
UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
TIP_("This modifier can only be applied on splines' points"));
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else if (mti->type != eModifierTypeType_Constructive) {
/* constructive modifiers tessellates curve before applying */
@@ -911,23 +902,29 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
}
}
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
/* Up/Down + Delete ........................... */
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* When Modifier is a simulation, show button to switch to context rather than the delete button. */
- if (modifier_can_delete(md) && (!modifier_is_simulation(md) || STREQ(scene->r.engine, "BLENDER_GAME")))
+ if (modifier_can_delete(md) &&
+ (!modifier_is_simulation(md) ||
+ STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)))
+ {
uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
- else if (modifier_is_simulation(md) == 1)
+ }
+ else if (modifier_is_simulation(md) == 1) {
uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
- else if (modifier_is_simulation(md) == 2)
+ }
+ else if (modifier_is_simulation(md) == 2) {
uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
- uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+ UI_block_emboss_set(block, UI_EMBOSS);
}
@@ -939,39 +936,39 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
/* only here obdata, the rest of modifiers is ob level */
- uiBlockSetButLock(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
if (md->type == eModifierType_ParticleSystem) {
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
- uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), ICON_NONE,
+ uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), ICON_NONE,
"OBJECT_OT_duplicates_make_real");
else if (psys->part->ren_as == PART_DRAW_PATH && psys->pathcache)
- uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), ICON_NONE,
+ uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert"), ICON_NONE,
"OBJECT_OT_modifier_convert");
}
}
else {
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
- uiItemEnumO(row, "OBJECT_OT_modifier_apply", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
+ uiItemEnumO(row, "OBJECT_OT_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
0, "apply_as", MODIFIER_APPLY_DATA);
if (modifier_isSameTopology(md) && !modifier_isNonGeometrical(md)) {
uiItemEnumO(row, "OBJECT_OT_modifier_apply",
- CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"),
0, "apply_as", MODIFIER_APPLY_SHAPE);
}
}
- uiBlockClearButLock(block);
- uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_clear(block);
+ UI_block_lock_set(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
eModifierType_Cloth, eModifierType_Smoke))
{
- uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
+ uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
"OBJECT_OT_modifier_copy");
}
}
@@ -1013,7 +1010,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
- uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
/* find modifier and draw it */
cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
@@ -1052,7 +1049,8 @@ static void do_constraint_panels(bContext *C, void *ob_pt, int event)
case B_CONSTRAINT_CHANGETARGET:
{
Main *bmain = CTX_data_main(C);
- if (ob->pose) ob->pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ if (ob->pose)
+ BKE_pose_tag_recalc(bmain, ob->pose); /* checks & sorts pose channels */
DAG_relations_tag_update(bmain);
break;
}
@@ -1082,7 +1080,7 @@ static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
{
bPoseChannel *pchan = BKE_pose_channel_active(ob);
- bConstraintTypeInfo *cti;
+ const bConstraintTypeInfo *cti;
uiBlock *block;
uiLayout *result = NULL, *col, *box, *row;
PointerRNA ptr;
@@ -1107,8 +1105,8 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
/* unless button has own callback, it adds this callback to button */
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_constraint_panels, ob);
- uiBlockSetFunc(block, constraint_active_func, ob, con);
+ UI_block_func_handle_set(block, do_constraint_panels, ob);
+ UI_block_func_set(block, constraint_active_func, ob, con);
RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
@@ -1122,12 +1120,12 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
/* Draw constraint header */
/* open/close */
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
/* name */
- uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr,
+ uiDefBut(block, UI_BTYPE_LABEL, B_CONSTRAINT_TEST, typestr,
xco + 0.5f * UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f * UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "");
if (con->flag & CONSTRAINT_DISABLE)
@@ -1143,15 +1141,15 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
/* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
if (proxy_protected) {
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
- uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco + 12.2f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
+ uiDefIconBut(block, UI_BTYPE_BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco + 12.2f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Proxy Protected"));
- uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco + 13.1f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
+ uiDefIconBut(block, UI_BTYPE_BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco + 13.1f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Proxy Protected"));
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else {
short prev_proxylock, show_upbut, show_downbut;
@@ -1177,33 +1175,33 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
show_downbut = (con->next) ? 1 : 0;
/* enabled */
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
uiItemR(row, &ptr, "mute", 0, "",
(con->flag & CONSTRAINT_OFF) ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
/* up/down */
if (show_upbut || show_downbut) {
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
if (show_upbut)
uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
if (show_downbut)
uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
/* Close 'button' - emboss calls here disable drawing of 'button' behind X */
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
/* Set but-locks for protected settings (magic numbers are used here!) */
if (proxy_protected)
- uiBlockSetButLock(block, true, IFACE_("Cannot edit Proxy-Protected Constraint"));
+ UI_block_lock_set(block, true, IFACE_("Cannot edit Proxy-Protected Constraint"));
/* Draw constraint data */
if ((con->flag & CONSTRAINT_EXPAND) == 0) {
@@ -1216,7 +1214,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
}
/* clear any locks set up for proxies/lib-linking */
- uiBlockClearButLock(block);
+ UI_block_lock_clear(block);
return result;
}
@@ -1240,7 +1238,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
return NULL;
}
- uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
/* hrms, the temporal constraint should not draw! */
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
@@ -1270,8 +1268,9 @@ static void do_preview_buttons(bContext *C, void *arg, int event)
}
}
-void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot,
- const char *preview_id)
+void uiTemplatePreview(
+ uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot,
+ const char *preview_id)
{
uiLayout *row, *col;
uiBlock *block;
@@ -1345,11 +1344,11 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons,
uiLayoutSetKeepAspect(col, true);
/* add preview */
- uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X * 10, ui_preview->height, pid, 0.0, 0.0, 0, 0, "");
- uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
- uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
+ uiDefBut(block, UI_BTYPE_EXTRA, 0, "", 0, 0, UI_UNIT_X * 10, ui_preview->height, pid, 0.0, 0.0, 0, 0, "");
+ UI_but_func_drawextra_set(block, ED_preview_draw, pparent, slot);
+ UI_block_func_handle_set(block, do_preview_buttons, NULL);
- uiDefIconButS(block, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &ui_preview->height,
+ uiDefIconButS(block, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &ui_preview->height,
UI_UNIT_Y, UI_UNIT_Y * 50.0f, 0.0f, 0.0f, "");
/* add buttons */
@@ -1371,25 +1370,25 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons,
RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
uiLayoutRow(layout, true);
- uiDefButS(block, ROW, B_MATPRV, IFACE_("Texture"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Texture"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
if (GS(parent->name) == ID_MA) {
- uiDefButS(block, ROW, B_MATPRV, IFACE_("Material"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Material"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
}
else if (GS(parent->name) == ID_LA) {
- uiDefButS(block, ROW, B_MATPRV, IFACE_("Lamp"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Lamp"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
}
else if (GS(parent->name) == ID_WO) {
- uiDefButS(block, ROW, B_MATPRV, IFACE_("World"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("World"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
}
else if (GS(parent->name) == ID_LS) {
- uiDefButS(block, ROW, B_MATPRV, IFACE_("Line Style"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Line Style"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
}
- uiDefButS(block, ROW, B_MATPRV, IFACE_("Both"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Both"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
/* Alpha button for texture preview */
@@ -1479,8 +1478,9 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
bt->rnapoin.data = coba->data + coba->cur;
}
-static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr,
- RNAUpdateCb *cb, int expand)
+static void colorband_buttons_layout(
+ uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr,
+ RNAUpdateCb *cb, int expand)
{
uiLayout *row, *split, *subsplit;
uiBut *bt;
@@ -1493,28 +1493,28 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
split = uiLayoutSplit(layout, 0.4f, false);
- uiBlockSetEmboss(block, UI_EMBOSSN);
- uiBlockBeginAlign(block);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ UI_block_align_begin(block);
row = uiLayoutRow(split, false);
- bt = uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, "", 0, 0, 2.0f * unit, UI_UNIT_Y, NULL,
+ bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMIN, "", 0, 0, 2.0f * unit, UI_UNIT_Y, NULL,
0, 0, 0, 0, TIP_("Add a new color stop to the colorband"));
- uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
+ UI_but_funcN_set(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
- bt = uiDefIconTextBut(block, BUT, 0, ICON_ZOOMOUT, "", xs + 2.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
+ bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMOUT, "", xs + 2.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Delete the active position"));
- uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
+ UI_but_funcN_set(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
- bt = uiDefIconTextBut(block, BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
+ bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Flip the color ramp"));
- uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
- uiBlockEndAlign(block);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
+ UI_block_align_end(block);
+ UI_block_emboss_set(block, UI_EMBOSS);
row = uiLayoutRow(split, false);
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
uiItemR(row, &ptr, "color_mode", 0, "", ICON_NONE);
if (ELEM(coba->color_mode, COLBAND_BLEND_HSV, COLBAND_BLEND_HSL)) {
uiItemR(row, &ptr, "hue_interpolation", 0, "", ICON_NONE);
@@ -1522,12 +1522,12 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
else { /* COLBAND_BLEND_RGB */
uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE);
}
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
row = uiLayoutRow(layout, false);
- bt = uiDefBut(block, BUT_COLORBAND, 0, "", xs, ys, BLI_rctf_size_x(butr), UI_UNIT_Y, coba, 0, 0, 0, 0, "");
- uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+ bt = uiDefBut(block, UI_BTYPE_COLORBAND, 0, "", xs, ys, BLI_rctf_size_x(butr), UI_UNIT_Y, coba, 0, 0, 0, 0, "");
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
row = uiLayoutRow(layout, false);
@@ -1540,34 +1540,36 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
split = uiLayoutSplit(layout, 0.3f, false);
row = uiLayoutRow(split, false);
- uiDefButS(block, NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)),
+ uiDefButS(block, UI_BTYPE_NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)),
0, 0, TIP_("Choose active color stop"));
row = uiLayoutRow(split, false);
uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
- uiButSetFunc(bt, colorband_update_cb, bt, coba);
+ bt->a1 = 1.0f; /* gives a bit more precision for modifying position */
+ UI_but_func_set(bt, colorband_update_cb, bt, coba);
row = uiLayoutRow(layout, false);
uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
bt = block->buttons.last;
- uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
}
else {
split = uiLayoutSplit(layout, 0.5f, false);
subsplit = uiLayoutSplit(split, 0.35f, false);
row = uiLayoutRow(subsplit, false);
- uiDefButS(block, NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)),
+ uiDefButS(block, UI_BTYPE_NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)),
0, 0, TIP_("Choose active color stop"));
row = uiLayoutRow(subsplit, false);
uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
- uiButSetFunc(bt, colorband_update_cb, bt, coba);
+ bt->a1 = 1.0f; /* gives a bit more precision for modifying position */
+ UI_but_func_set(bt, colorband_update_cb, bt, coba);
row = uiLayoutRow(split, false);
uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
bt = block->buttons.last;
- uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
}
}
}
@@ -1598,55 +1600,69 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
block = uiLayoutAbsoluteBlock(layout);
id = cptr.id.data;
- uiBlockSetButLock(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
colorband_buttons_layout(layout, block, cptr.data, &rect, cb, expand);
- uiBlockClearButLock(block);
+ UI_block_lock_clear(block);
MEM_freeN(cb);
}
/********************* Icon viewer Template ************************/
+typedef struct IconViewMenuArgs {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ bool show_labels;
+ float icon_scale;
+} IconViewMenuArgs;
/* ID Search browse menu, open */
-static uiBlock *icon_view_menu(bContext *C, ARegion *ar, void *arg_litem)
+static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
{
- static RNAUpdateCb cb;
+ static IconViewMenuArgs args;
uiBlock *block;
uiBut *but;
- int icon;
+ int icon, value;
EnumPropertyItem *item;
int a;
bool free;
+ int w, h;
/* arg_litem is malloced, can be freed by parent button */
- cb = *((RNAUpdateCb *)arg_litem);
-
- /* unused */
- // icon = RNA_property_enum_get(&cb.ptr, cb.prop);
-
- block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
- uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW);
-
-
- RNA_property_enum_items(C, &cb.ptr, cb.prop, &item, NULL, &free);
-
+ args = *((IconViewMenuArgs *) arg_litem);
+ w = UI_UNIT_X * (args.icon_scale);
+ h = UI_UNIT_X * (args.icon_scale + args.show_labels);
+
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS_PULLDOWN);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP);
+
+ RNA_property_enum_items(C, &args.ptr, args.prop, &item, NULL, &free);
+
for (a = 0; item[a].identifier; a++) {
int x, y;
-
- /* XXX hardcoded size to 5 x unit */
- x = (a % 8) * UI_UNIT_X * 5;
- y = (a / 8) * UI_UNIT_X * 5;
-
+
+ x = (a % 8) * w;
+ y = (a / 8) * h;
+
icon = item[a].icon;
- but = uiDefIconButR_prop(block, ROW, 0, icon, x, y, UI_UNIT_X * 5, UI_UNIT_Y * 5, &cb.ptr, cb.prop, -1, 0, icon, -1, -1, NULL);
- uiButSetFlag(but, UI_HAS_ICON | UI_ICON_PREVIEW);
+ value = item[a].value;
+ if (args.show_labels) {
+ but = uiDefIconTextButR_prop(
+ block, UI_BTYPE_ROW, 0, icon, item[a].name, x, y, w, h,
+ &args.ptr, args.prop, -1, 0, value, -1, -1, NULL);
+ }
+ else {
+ but = uiDefIconButR_prop(
+ block, UI_BTYPE_ROW, 0, icon, x, y, w, h,
+ &args.ptr, args.prop, -1, 0, value, -1, -1, NULL);
+ }
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
- uiBoundsBlock(block, 0.3f * U.widget_unit);
- uiBlockSetDirection(block, UI_TOP);
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
+ UI_block_direction_set(block, UI_DIR_DOWN);
if (free) {
MEM_freeN(item);
@@ -1655,40 +1671,43 @@ static uiBlock *icon_view_menu(bContext *C, ARegion *ar, void *arg_litem)
return block;
}
-void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname)
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
+void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname, int show_labels, float icon_scale)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
- RNAUpdateCb *cb;
+ IconViewMenuArgs *cb_args;
+ EnumPropertyItem *items;
uiBlock *block;
uiBut *but;
-// rctf rect; /* UNUSED */
- int icon;
-
- if (!prop || RNA_property_type(prop) != PROP_ENUM)
+ int value, icon = ICON_NONE, tot_items;
+ bool free_items;
+
+ if (!prop || RNA_property_type(prop) != PROP_ENUM) {
+ RNA_warning("property of type Enum not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
-
- icon = RNA_property_enum_get(ptr, prop);
-
- cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
- cb->ptr = *ptr;
- cb->prop = prop;
-
-// rect.xmin = 0; rect.xmax = 10.0f * UI_UNIT_X;
-// rect.ymin = 0; rect.ymax = 10.0f * UI_UNIT_X;
-
+ }
+
block = uiLayoutAbsoluteBlock(layout);
- but = uiDefBlockButN(block, icon_view_menu, MEM_dupallocN(cb), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+ RNA_property_enum_items(block->evil_C, ptr, prop, &items, &tot_items, &free_items);
+ value = RNA_property_enum_get(ptr, prop);
+ RNA_enum_icon_from_value(items, value, &icon);
-
-// but = uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, BLI_rctf_size_x(&rect), BLI_rctf_size_y(&rect), ptr, prop, -1, 0, icon, -1, -1, NULL);
-
- but->icon = icon;
- uiButSetFlag(but, UI_HAS_ICON | UI_ICON_PREVIEW);
-
- uiButSetNFunc(but, rna_update_cb, MEM_dupallocN(cb), NULL);
-
- MEM_freeN(cb);
+ cb_args = MEM_callocN(sizeof(IconViewMenuArgs), __func__);
+ cb_args->ptr = *ptr;
+ cb_args->prop = prop;
+ cb_args->show_labels = show_labels;
+ cb_args->icon_scale = icon_scale;
+
+ but = uiDefBlockButN(block, ui_icon_view_menu_cb, cb_args, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+
+ if (free_items) {
+ MEM_freeN(items);
+ }
}
/********************* Histogram Template ************************/
@@ -1719,10 +1738,10 @@ void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname
col = uiLayoutColumn(layout, true);
block = uiLayoutGetBlock(col);
- uiDefBut(block, HISTOGRAM, 0, "", 0, 0, UI_UNIT_X * 10, hist->height, hist, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_HISTOGRAM, 0, "", 0, 0, UI_UNIT_X * 10, hist->height, hist, 0, 0, 0, 0, "");
/* Resize grip. */
- uiDefIconButI(block, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &hist->height,
+ uiDefIconButI(block, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &hist->height,
UI_UNIT_Y, UI_UNIT_Y * 20.0f, 0.0f, 0.0f, "");
}
@@ -1754,10 +1773,10 @@ void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
scopes->wavefrm_height = UI_UNIT_Y * 20;
}
- uiDefBut(block, WAVEFORM, 0, "", 0, 0, UI_UNIT_X * 10, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_WAVEFORM, 0, "", 0, 0, UI_UNIT_X * 10, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
/* Resize grip. */
- uiDefIconButI(block, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &scopes->wavefrm_height,
+ uiDefIconButI(block, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &scopes->wavefrm_height,
UI_UNIT_Y, UI_UNIT_Y * 20.0f, 0.0f, 0.0f, "");
}
@@ -1789,10 +1808,10 @@ void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propna
col = uiLayoutColumn(layout, true);
block = uiLayoutGetBlock(col);
- uiDefBut(block, VECTORSCOPE, 0, "", 0, 0, UI_UNIT_X * 10, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_VECTORSCOPE, 0, "", 0, 0, UI_UNIT_X * 10, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
/* Resize grip. */
- uiDefIconButI(block, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &scopes->vecscope_height,
+ uiDefIconButI(block, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &scopes->vecscope_height,
UI_UNIT_Y, UI_UNIT_Y * 20.0f, 0.0f, 0.0f, "");
}
@@ -1879,28 +1898,27 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
uiBut *bt;
float width = 8 * UI_UNIT_X;
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
/* use this for a fake extra empy space around the buttons */
- uiDefBut(block, LABEL, 0, "", -4, 16, width + 8, 6 * UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", -4, 16, width + 8, 6 * UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- bt = uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, IFACE_("Use Clipping"),
+ bt = uiDefButBitI(block, UI_BTYPE_TOGGLE, CUMA_DO_CLIP, 1, IFACE_("Use Clipping"),
0, 5 * UI_UNIT_Y, width, UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
- uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
+ UI_but_func_set(bt, curvemap_buttons_setclip, cumap, NULL);
- uiBlockBeginAlign(block);
- uiDefButF(block, NUM, 0, IFACE_("Min X "), 0, 4 * UI_UNIT_Y, width, UI_UNIT_Y,
+ UI_block_align_begin(block);
+ uiDefButF(block, UI_BTYPE_NUM, 0, IFACE_("Min X "), 0, 4 * UI_UNIT_Y, width, UI_UNIT_Y,
&cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 2, "");
- uiDefButF(block, NUM, 0, IFACE_("Min Y "), 0, 3 * UI_UNIT_Y, width, UI_UNIT_Y,
+ uiDefButF(block, UI_BTYPE_NUM, 0, IFACE_("Min Y "), 0, 3 * UI_UNIT_Y, width, UI_UNIT_Y,
&cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 2, "");
- uiDefButF(block, NUM, 0, IFACE_("Max X "), 0, 2 * UI_UNIT_Y, width, UI_UNIT_Y,
+ uiDefButF(block, UI_BTYPE_NUM, 0, IFACE_("Max X "), 0, 2 * UI_UNIT_Y, width, UI_UNIT_Y,
&cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 2, "");
- uiDefButF(block, NUM, 0, IFACE_("Max Y "), 0, UI_UNIT_Y, width, UI_UNIT_Y,
+ uiDefButF(block, UI_BTYPE_NUM, 0, IFACE_("Max Y "), 0, UI_UNIT_Y, width, UI_UNIT_Y,
&cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 2, "");
- uiBlockSetDirection(block, UI_RIGHT);
+ UI_block_direction_set(block, UI_DIR_RIGHT);
- uiEndBlock(C, block);
return block;
}
@@ -1956,26 +1974,25 @@ static uiBlock *curvemap_tools_posslope_func(bContext *C, ARegion *ar, void *cum
uiBlock *block;
short yco = 0, menuwidth = 10 * UI_UNIT_X;
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
- uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap_v);
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_HOZ, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_EXP, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_POS, "");
- uiBlockSetDirection(block, UI_RIGHT);
- uiTextBoundsBlock(block, 50);
+ UI_block_direction_set(block, UI_DIR_RIGHT);
+ UI_block_bounds_set_text(block, 50);
- uiEndBlock(C, block);
return block;
}
@@ -1984,26 +2001,25 @@ static uiBlock *curvemap_tools_negslope_func(bContext *C, ARegion *ar, void *cum
uiBlock *block;
short yco = 0, menuwidth = 10 * UI_UNIT_X;
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
- uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap_v);
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_HOZ, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_EXP, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_NEG, "");
- uiBlockSetDirection(block, UI_RIGHT);
- uiTextBoundsBlock(block, 50);
+ UI_block_direction_set(block, UI_DIR_RIGHT);
+ UI_block_bounds_set_text(block, 50);
- uiEndBlock(C, block);
return block;
}
@@ -2012,22 +2028,21 @@ static uiBlock *curvemap_brush_tools_func(bContext *C, ARegion *ar, void *cumap_
uiBlock *block;
short yco = 0, menuwidth = 10 * UI_UNIT_X;
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
- uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap_v);
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_NEG, "");
- uiBlockSetDirection(block, UI_RIGHT);
- uiTextBoundsBlock(block, 50);
+ UI_block_direction_set(block, UI_DIR_RIGHT);
+ UI_block_bounds_set_text(block, 50);
- uiEndBlock(C, block);
return block;
}
@@ -2062,8 +2077,9 @@ static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
}
/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
-static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels,
- int brush, int neg_slope, RNAUpdateCb *cb)
+static void curvemap_buttons_layout(
+ uiLayout *layout, PointerRNA *ptr, char labeltype, int levels,
+ int brush, int neg_slope, RNAUpdateCb *cb)
{
CurveMapping *cumap = ptr->data;
CurveMap *cm = &cumap->cm[cumap->cur];
@@ -2086,16 +2102,16 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
if (cumap->cm[0].curve) {
- bt = uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[1].curve) {
- bt = uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[2].curve) {
- bt = uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
}
else if (labeltype == 'c') {
@@ -2104,20 +2120,20 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
if (cumap->cm[3].curve) {
- bt = uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[0].curve) {
- bt = uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[1].curve) {
- bt = uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[2].curve) {
- bt = uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
}
else if (labeltype == 'h') {
@@ -2126,16 +2142,16 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
if (cumap->cm[0].curve) {
- bt = uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[1].curve) {
- bt = uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
if (cumap->cm[2].curve) {
- bt = uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
- uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
+ bt = uiDefButI(block, UI_BTYPE_ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
+ UI_but_func_set(bt, curvemap_buttons_redraw, NULL, NULL);
}
}
else
@@ -2147,13 +2163,13 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
/* operation buttons */
sub = uiLayoutRow(row, true);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
- uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
+ bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
+ UI_but_func_set(bt, curvemap_buttons_zoom_in, cumap, NULL);
- bt = uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
- uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
+ bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
+ UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL);
if (brush)
bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
@@ -2164,23 +2180,23 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
bt = uiDefIconBlockBut(block, curvemap_tools_posslope_func, cumap, 0, ICON_MODIFIER,
0, 0, dx, dx, TIP_("Tools"));
- uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
bt = uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
- uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
- bt = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete points"));
- uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
+ bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete points"));
+ UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
- uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
+ UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
/* curve itself */
size = uiLayoutGetWidth(layout);
row = uiLayoutRow(layout, false);
- uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, bg, 0, "");
+ uiDefBut(block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, bg, 0, "");
/* sliders for selected point */
for (i = 0; i < cm->totpoint; i++) {
@@ -2202,10 +2218,10 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
}
uiLayoutRow(layout, true);
- uiBlockSetNFunc(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
- uiDefButF(block, NUM, 0, "X", 0, 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
+ UI_block_funcN_set(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
+ uiDefButF(block, UI_BTYPE_NUM, 0, "X", 0, 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
&cmp->x, bounds.xmin, bounds.xmax, 1, 5, "");
- uiDefButF(block, NUM, 0, "Y", 0, 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButF(block, UI_BTYPE_NUM, 0, "Y", 0, 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y,
&cmp->y, bounds.ymin, bounds.ymax, 1, 5, "");
}
@@ -2216,16 +2232,17 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
uiItemR(uiLayoutColumn(split, false), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiLayoutRow(layout, false);
- bt = uiDefBut(block, BUT, 0, IFACE_("Reset"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
+ bt = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Reset"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
TIP_("Reset Black/White point and curves"));
- uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
+ UI_but_funcN_set(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
}
- uiBlockSetNFunc(block, NULL, NULL, NULL);
+ UI_block_funcN_set(block, NULL, NULL, NULL);
}
-void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
- int levels, int brush, int neg_slope)
+void uiTemplateCurveMapping(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
+ int levels, int brush, int neg_slope)
{
RNAUpdateCb *cb;
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -2254,11 +2271,11 @@ void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propn
cb->prop = prop;
id = cptr.id.data;
- uiBlockSetButLock(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
+ UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, cb);
- uiBlockClearButLock(block);
+ UI_block_lock_clear(block);
MEM_freeN(cb);
}
@@ -2268,13 +2285,15 @@ void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propn
#define WHEEL_SIZE (5 * U.widget_unit)
/* This template now follows User Preference for type - name is not correct anymore... */
-void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider,
- int lock, int lock_luminosity, int cubic)
+void uiTemplateColorPicker(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider,
+ int lock, int lock_luminosity, int cubic)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *col, *row;
uiBut *but = NULL;
+ ColorPicker *cpicker = ui_block_colorpicker_create(block);
float softmin, softmax, step, precision;
if (!prop) {
@@ -2289,15 +2308,15 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
switch (U.color_picker_type) {
case USER_CP_SQUARE_SV:
- but = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
-1, 0.0, 0.0, UI_GRAD_SV, 0, "");
break;
case USER_CP_SQUARE_HS:
- but = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
-1, 0.0, 0.0, UI_GRAD_HS, 0, "");
break;
case USER_CP_SQUARE_HV:
- but = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
-1, 0.0, 0.0, UI_GRAD_HV, 0, "");
break;
@@ -2305,12 +2324,14 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
case USER_CP_CIRCLE_HSV:
case USER_CP_CIRCLE_HSL:
default:
- but = uiDefButR_prop(block, HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop,
-1, 0.0, 0.0, 0, 0, "");
break;
}
+ but->custom_data = cpicker;
+
if (lock) {
but->flag |= UI_BUT_COLOR_LOCK;
}
@@ -2330,33 +2351,35 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
switch (U.color_picker_type) {
case USER_CP_CIRCLE_HSL:
uiItemS(row);
- uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop,
- -1, softmin, softmax, UI_GRAD_L_ALT, 0, "");
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop,
+ -1, softmin, softmax, UI_GRAD_L_ALT, 0, "");
break;
case USER_CP_SQUARE_SV:
uiItemS(col);
- uiDefButR_prop(block, HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop,
- -1, softmin, softmax, UI_GRAD_SV + 3, 0, "");
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop,
+ -1, softmin, softmax, UI_GRAD_SV + 3, 0, "");
break;
case USER_CP_SQUARE_HS:
uiItemS(col);
- uiDefButR_prop(block, HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop,
- -1, softmin, softmax, UI_GRAD_HS + 3, 0, "");
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop,
+ -1, softmin, softmax, UI_GRAD_HS + 3, 0, "");
break;
case USER_CP_SQUARE_HV:
uiItemS(col);
- uiDefButR_prop(block, HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop,
- -1, softmin, softmax, UI_GRAD_HV + 3, 0, "");
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop,
+ -1, softmin, softmax, UI_GRAD_HV + 3, 0, "");
break;
/* user default */
case USER_CP_CIRCLE_HSV:
default:
uiItemS(row);
- uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop,
- -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
+ but = uiDefButR_prop(block, UI_BTYPE_HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop,
+ -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
break;
}
+
+ but->custom_data = cpicker;
}
}
@@ -2384,15 +2407,12 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
palette = cptr.data;
- /* first delete any pending colors */
- BKE_palette_cleanup(palette);
-
color = palette->colors.first;
col = uiLayoutColumn(layout, true);
uiLayoutRow(col, true);
- uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
- uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, UI_BTYPE_BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, UI_BTYPE_BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
col = uiLayoutColumn(layout, true);
uiLayoutRow(col, true);
@@ -2406,7 +2426,7 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
}
RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr);
- uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
+ uiDefButR(block, UI_BTYPE_COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
UI_PALETTE_COLOR, col_id, "");
row_cols++;
col_id++;
@@ -2438,12 +2458,13 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* see view3d_header.c */
}
-/* TODO:
- * - for now, grouping of layers is determined by dividing up the length of
- * the array of layer bitflags */
-
-void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_layer)
+/**
+ * \todo for now, grouping of layers is determined by dividing up the length of
+ * the array of layer bitflags
+ */
+void uiTemplateLayers(
+ uiLayout *layout, PointerRNA *ptr, const char *propname,
+ PointerRNA *used_ptr, const char *used_propname, int active_layer)
{
uiLayout *uRow, *uCol;
PropertyRNA *prop, *used_prop = NULL;
@@ -2502,15 +2523,16 @@ void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
icon = ICON_LAYER_USED;
but = uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2);
- uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
- but->type = TOG;
+ UI_but_func_set(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
+ but->type = UI_BTYPE_TOGGLE;
}
}
}
}
-void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_state)
+void uiTemplateGameStates(
+ uiLayout *layout, PointerRNA *ptr, const char *propname,
+ PointerRNA *used_ptr, const char *used_propname, int active_state)
{
uiLayout *uRow, *uCol;
PropertyRNA *prop, *used_prop = NULL;
@@ -2569,10 +2591,10 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam
else if (used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, state))
icon = ICON_LAYER_USED;
- but = uiDefIconButR_prop(block, ICONTOG, 0, icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2, ptr, prop,
+ but = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2, ptr, prop,
state, 0, 0, -1, -1, sca_state_name_get(ob, state));
- uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(state));
- but->type = TOG;
+ UI_but_func_set(but, handle_layer_buttons, but, SET_INT_IN_POINTER(state));
+ but->type = UI_BTYPE_TOGGLE;
}
}
}
@@ -2580,10 +2602,11 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam
/************************* List Template **************************/
-static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
- struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
- struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
- int UNUSED(index), int UNUSED(flt_flag))
+static void uilist_draw_item_default(
+ struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
+ struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
+ struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
+ int UNUSED(index), int UNUSED(flt_flag))
{
PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type);
@@ -2658,7 +2681,7 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext
names = MEM_callocN(sizeof(StringCmp) * len, "StringCmp");
}
if (filter_raw[0]) {
- size_t idx = 0, slen = strlen(filter_raw);
+ size_t slen = strlen(filter_raw);
dyn_data->items_filter_flags = MEM_callocN(sizeof(int) * len, "items_filter_flags");
dyn_data->items_shown = 0;
@@ -2670,15 +2693,7 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext
else {
filter = filter_dyn = MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn");
}
- if (filter_raw[idx] != '*') {
- filter[idx++] = '*';
- }
- memcpy(filter + idx, filter_raw, slen);
- idx += slen;
- if (filter[idx - 1] != '*') {
- filter[idx++] = '*';
- }
- filter[idx] = '\0';
+ BLI_strncpy_ensure_pad(filter, filter_raw, '*', slen + 3);
}
RNA_PROP_BEGIN (dataptr, itemptr, prop)
@@ -2758,8 +2773,9 @@ typedef struct {
int end_idx; /* Index of last item to display + 1. */
} uiListLayoutdata;
-static void prepare_list(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
- uiListLayoutdata *layoutdata)
+static void uilist_prepare(
+ uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
+ uiListLayoutdata *layoutdata)
{
uiListDyn *dyn_data = ui_list->dyn_data;
int activei_row, max_scroll;
@@ -2812,7 +2828,7 @@ static void prepare_list(uiList *ui_list, int len, int activei, int rows, int ma
layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len);
}
-static void ui_list_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2))
+static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2))
{
uiList *ui_list = arg1;
uiListDyn *dyn_data = ui_list->dyn_data;
@@ -2827,9 +2843,28 @@ static void ui_list_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUS
}
}
-void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
- PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
- int rows, int maxrows, int layout_type, int columns)
+static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname)
+{
+ if (propname && propname[0] && itemptr && itemptr->data) {
+ PropertyRNA *prop = RNA_struct_find_property(itemptr, propname);
+
+ if (prop && (RNA_property_type(prop) == PROP_STRING)) {
+ return RNA_property_string_get_alloc(itemptr, prop, NULL, 0, NULL);
+ }
+ }
+ return NULL;
+}
+
+static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const char *tip)
+{
+ char *dyn_tooltip = argN;
+ return BLI_sprintfN("%s - %s", tip, dyn_tooltip);
+}
+
+void uiTemplateList(
+ uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
+ PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
+ const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns)
{
uiListType *ui_list_type;
uiList *ui_list = NULL;
@@ -2856,7 +2891,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* validate arguments */
/* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */
- if (!strcmp(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) {
+ if (STREQ(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) {
RNA_warning("template_list using default '%s' UIList class must provide a custom list_id",
UI_UL_DEFAULT_CLASS_NAME);
return;
@@ -3037,25 +3072,30 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
col = uiLayoutColumn(row, true);
/* init numbers */
- prepare_list(ui_list, len, activei, rows, maxrows, 1, &layoutdata);
+ uilist_prepare(ui_list, len, activei, rows, maxrows, 1, &layoutdata);
if (dataptr->data && prop) {
/* create list items */
for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) {
PointerRNA *itemptr = &items_ptr[i].item;
+ void *dyntip_data;
int org_i = items_ptr[i].org_idx;
int flt_flag = items_ptr[i].flt_flag;
subblock = uiLayoutGetBlock(col);
overlap = uiLayoutOverlap(col);
- uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM);
+ UI_block_flag_enable(subblock, UI_BLOCK_LIST_ITEM);
/* list item behind label & other buttons */
sub = uiLayoutRow(overlap, false);
- but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
- active_dataptr, activeprop, 0, 0, org_i, 0, 0, TIP_("Double click to rename"));
+ but = uiDefButR_prop(subblock, UI_BTYPE_LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ active_dataptr, activeprop, 0, 0, org_i, 0, 0,
+ TIP_("Double click to rename"));
+ if ((dyntip_data = uilist_item_use_dynamic_tooltip(itemptr, item_dyntip_propname))) {
+ UI_but_func_tooltip_set(but, uilist_item_tooltip_func, dyntip_data);
+ }
sub = uiLayoutRow(overlap, false);
@@ -3070,7 +3110,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
ui_layout_list_set_labels_active(sub);
}
- uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM);
+ UI_block_flag_disable(subblock, UI_BLOCK_LIST_ITEM);
}
}
@@ -3082,7 +3122,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* add scrollbar */
if (len > layoutdata.visual_items) {
col = uiLayoutColumn(row, false);
- uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
+ uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
&ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height,
dyn_data->visual_height, 0, "");
}
@@ -3108,10 +3148,10 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* next/prev button */
BLI_snprintf(numstr, sizeof(numstr), "%d :", dyn_data->items_shown);
- but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y,
+ but = uiDefIconTextButR_prop(block, UI_BTYPE_NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y,
active_dataptr, activeprop, 0, 0, 0, 0, 0, "");
if (dyn_data->items_shown == 0)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
break;
case UILST_LAYOUT_GRID:
box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop);
@@ -3120,7 +3160,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
col = uiLayoutColumn(row, true);
subrow = NULL; /* Quite gcc warning! */
- prepare_list(ui_list, len, activei, rows, maxrows, columns, &layoutdata);
+ uilist_prepare(ui_list, len, activei, rows, maxrows, columns, &layoutdata);
if (dataptr->data && prop) {
/* create list items */
@@ -3136,14 +3176,14 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
subblock = uiLayoutGetBlock(subrow);
overlap = uiLayoutOverlap(subrow);
- uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM);
+ UI_block_flag_enable(subblock, UI_BLOCK_LIST_ITEM);
/* list item behind label & other buttons */
sub = uiLayoutRow(overlap, false);
- but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ but = uiDefButR_prop(subblock, UI_BTYPE_LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL);
- uiButSetDrawFlag(but, UI_BUT_NO_TOOLTIP);
+ UI_but_drawflag_enable(but, UI_BUT_NO_TOOLTIP);
sub = uiLayoutRow(overlap, false);
@@ -3156,7 +3196,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
ui_layout_list_set_labels_active(sub);
}
- uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM);
+ UI_block_flag_disable(subblock, UI_BLOCK_LIST_ITEM);
}
}
@@ -3170,8 +3210,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* add scrollbar */
if (len > layoutdata.visual_items) {
- col = uiLayoutColumn(row, false);
- uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
+ /* col = */ uiLayoutColumn(row, false);
+ uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
&ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height,
dyn_data->visual_height, 0, "");
}
@@ -3179,8 +3219,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
}
if (glob) {
- /* About GRIP drag-resize:
- * We can't directly use results from GRIP button, since we have a rather complex behavior here
+ /* About UI_BTYPE_GRIP drag-resize:
+ * We can't directly use results from a grip button, since we have a rather complex behavior here
* (sizing by discrete steps and, overall, autosize feature).
* Since we *never* know whether we are grip-resizing or not (because there is no callback for when a
* button enters/leaves its "edit mode"), we use the fact that grip-controlled value (dyn_data->resize)
@@ -3193,37 +3233,37 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
row = uiLayoutRow(glob, true);
subblock = uiLayoutGetBlock(row);
- uiBlockSetEmboss(subblock, UI_EMBOSSN);
+ UI_block_emboss_set(subblock, UI_EMBOSS_NONE);
if (ui_list->filter_flag & UILST_FLT_SHOW) {
- but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_DOWN, 0, 0,
+ but = uiDefIconButBitI(subblock, UI_BTYPE_TOGGLE, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_DOWN, 0, 0,
UI_UNIT_X, UI_UNIT_Y * 0.5f, &(ui_list->filter_flag), 0, 0, 0, 0,
TIP_("Hide filtering options"));
- uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
+ UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
- but = uiDefIconButI(subblock, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.5f,
+ but = uiDefIconButI(subblock, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.5f,
&dyn_data->resize, 0.0, 0.0, 0, 0, "");
- uiButSetFunc(but, ui_list_resize_update_cb, ui_list, NULL);
+ UI_but_func_set(but, uilist_resize_update_cb, ui_list, NULL);
- uiBlockSetEmboss(subblock, UI_EMBOSS);
+ UI_block_emboss_set(subblock, UI_EMBOSS);
col = uiLayoutColumn(glob, false);
subblock = uiLayoutGetBlock(col);
- uiDefBut(subblock, SEPR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.05f, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(subblock, UI_BTYPE_SEPR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.05f, NULL, 0.0, 0.0, 0, 0, "");
draw_filter(ui_list, C, col);
}
else {
- but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_RIGHT, 0, 0,
+ but = uiDefIconButBitI(subblock, UI_BTYPE_TOGGLE, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_RIGHT, 0, 0,
UI_UNIT_X, UI_UNIT_Y * 0.5f, &(ui_list->filter_flag), 0, 0, 0, 0,
TIP_("Show filtering options"));
- uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
+ UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
- but = uiDefIconButI(subblock, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.5f,
+ but = uiDefIconButI(subblock, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.5f,
&dyn_data->resize, 0.0, 0.0, 0, 0, "");
- uiButSetFunc(but, ui_list_resize_update_cb, ui_list, NULL);
+ UI_but_func_set(but, uilist_resize_update_cb, ui_list, NULL);
- uiBlockSetEmboss(subblock, UI_EMBOSS);
+ UI_block_emboss_set(subblock, UI_EMBOSS);
}
}
@@ -3244,42 +3284,42 @@ static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
{
- GHashIterator *iter = WM_operatortype_iter();
+ GHashIterator iter;
- for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0)
continue;
- if (BLI_strcasestr(ot->name, str)) {
+ if (BLI_strcasestr(ot_ui_name, str)) {
if (WM_operator_poll((bContext *)C, ot)) {
char name[256];
- int len = strlen(ot->name);
+ int len = strlen(ot_ui_name);
/* display name for menu, can hold hotkey */
- BLI_strncpy(name, ot->name, sizeof(name));
+ BLI_strncpy(name, ot_ui_name, sizeof(name));
/* check for hotkey */
if (len < sizeof(name) - 6) {
if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, true,
- &name[len + 1], sizeof(name) - len - 1))
+ sizeof(name) - len - 1, &name[len + 1]))
{
name[len] = UI_SEP_CHAR;
}
}
- if (false == uiSearchItemAdd(items, name, ot, 0))
+ if (false == UI_search_item_add(items, name, ot, 0))
break;
}
}
}
- BLI_ghashIterator_free(iter);
}
-void uiOperatorSearch_But(uiBut *but)
+void UI_but_func_operator_search(uiBut *but)
{
- uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
+ UI_but_func_search_set(but, operator_search_cb, NULL, operator_call_cb, NULL);
}
void uiTemplateOperatorSearch(uiLayout *layout)
@@ -3289,10 +3329,10 @@ void uiTemplateOperatorSearch(uiLayout *layout)
static char search[256] = "";
block = uiLayoutGetBlock(layout);
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
- uiOperatorSearch_But(but);
+ UI_but_func_operator_search(but);
}
/************************* Running Jobs Template **************************/
@@ -3303,7 +3343,8 @@ void uiTemplateOperatorSearch(uiLayout *layout)
#define B_STOPCOMPO 4
#define B_STOPSEQ 5
#define B_STOPCLIP 6
-#define B_STOPOTHER 7
+#define B_STOPFILE 7
+#define B_STOPOTHER 8
static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
{
@@ -3326,6 +3367,9 @@ static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
case B_STOPCLIP:
WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
break;
+ case B_STOPFILE:
+ WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
+ break;
case B_STOPOTHER:
G.is_break = true;
break;
@@ -3342,9 +3386,9 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
int handle_event;
block = uiLayoutGetBlock(layout);
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
- uiBlockSetHandleFunc(block, do_running_jobs, NULL);
+ UI_block_func_handle_set(block, do_running_jobs, NULL);
if (sa->spacetype == SPACE_SEQ) {
if (WM_jobs_test(wm, sa, WM_JOB_TYPE_ANY))
@@ -3356,6 +3400,12 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
owner = sa;
handle_event = B_STOPCLIP;
}
+ else if (sa->spacetype == SPACE_FILE) {
+ if (WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR)) {
+ owner = sa;
+ }
+ handle_event = B_STOPFILE;
+ }
else {
Scene *scene;
/* another scene can be rendering too, for example via compositor */
@@ -3394,18 +3444,18 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
ui_abs = uiLayoutAbsolute(layout, false);
(void)ui_abs; /* UNUSED */
- uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 0, UI_UNIT_Y * 0.1, UI_UNIT_X * 0.8, UI_UNIT_Y * 0.8,
+ uiDefIconBut(block, UI_BTYPE_BUT, handle_event, ICON_PANEL_CLOSE, 0, UI_UNIT_Y * 0.1, UI_UNIT_X * 0.8, UI_UNIT_Y * 0.8,
NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop this job"));
- uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner),
+ uiDefBut(block, UI_BTYPE_PROGRESS_BAR, 0, WM_jobs_name(wm, owner),
UI_UNIT_X, 0, UI_UNIT_X * 5.0f, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, TIP_("Progress"));
uiLayoutRow(layout, false);
}
if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST))
- uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0, 0, UI_UNIT_X * 4.25f, UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0, 0, UI_UNIT_X * 4.25f, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop screencast"));
if (screen->animtimer)
- uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, IFACE_("Anim Player"), 0, 0, UI_UNIT_X * 5.0f, UI_UNIT_Y,
+ uiDefIconTextBut(block, UI_BTYPE_BUT, B_STOPANIM, ICON_CANCEL, IFACE_("Anim Player"), 0, 0, UI_UNIT_X * 5.0f, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop animation playback"));
}
@@ -3420,7 +3470,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
uiLayout *ui_abs;
uiBlock *block;
uiBut *but;
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
int width;
int icon;
@@ -3434,42 +3484,43 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
ui_abs = uiLayoutAbsolute(layout, false);
block = uiLayoutGetBlock(ui_abs);
- width = BLF_width(style->widget.uifont_id, report->message, report->len);
+ UI_fontstyle_set(&style->widgetlabel);
+ width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len);
width = min_ii((int)(rti->widthfac * width), width);
width = max_ii(width, 10);
/* make a box around the report to make it stand out */
- uiBlockBeginAlign(block);
- but = uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X + 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
- /* set the report's bg color in but->col - ROUNDBOX feature */
+ UI_block_align_begin(block);
+ but = uiDefBut(block, UI_BTYPE_ROUNDBOX, 0, "", 0, 0, UI_UNIT_X + 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
+ /* set the report's bg color in but->col - UI_BTYPE_ROUNDBOX feature */
rgb_float_to_uchar(but->col, rti->col);
but->col[3] = 255;
- but = uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y,
+ but = uiDefBut(block, UI_BTYPE_ROUNDBOX, 0, "", UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, "");
but->col[0] = but->col[1] = but->col[2] = FTOCHAR(rti->grayscale);
but->col[3] = 255;
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
/* icon and report message on top */
- icon = uiIconFromReportType(report->type);
+ icon = UI_icon_from_report_type(report->type);
/* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report
* to be shown instead of icon when appropriate...
*/
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
if (reports->list.first != reports->list.last)
- uiDefIconButO(block, BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0, UI_UNIT_X,
+ uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0, UI_UNIT_X,
UI_UNIT_Y, TIP_("Click to see the remaining reports in text block: 'Recent Reports'"));
else
- uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
+ uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
- uiDefBut(block, LABEL, 0, report->message, UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y,
+ uiDefBut(block, UI_BTYPE_LABEL, 0, report->message, UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, "");
}
@@ -3518,11 +3569,11 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title,
if (is_set) {
/* unset operator */
uiBlock *block = uiLayoutGetBlock(row);
- uiBlockSetEmboss(block, UI_EMBOSSN);
- but = uiDefIconButO(block, BUT, "UI_OT_unset_property_button", WM_OP_EXEC_DEFAULT, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_unset_property_button", WM_OP_EXEC_DEFAULT, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
but->rnapoin = *ptr;
but->rnaprop = prop;
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
}
RNA_STRUCT_END;
@@ -3542,7 +3593,7 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
for (; but; but = but->next) {
/* operator buttons may store props for use (file selector, [#36492]) */
if (but->rnaprop) {
- uiButSetFunc(but, keymap_item_modified, ptr->data, NULL);
+ UI_but_func_set(but, keymap_item_modified, ptr->data, NULL);
}
}
}
@@ -3565,8 +3616,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char
colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop);
- uiItemL(layout, IFACE_("Input Color Space:"), ICON_NONE);
- uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(layout, &colorspace_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE);
}
void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr, const char *propname)
@@ -3617,15 +3667,15 @@ static uiBlock *component_menu(bContext *C, ARegion *ar, void *args_v)
uiBlock *block;
uiLayout *layout;
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
- uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN);
- layout = uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, UI_GetStyle()), 0);
+ layout = uiLayoutColumn(UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, UI_style_get()), 0);
uiItemR(layout, &args->ptr, args->propname, UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiBoundsBlock(block, 6);
- uiBlockSetDirection(block, UI_DOWN);
+ UI_block_bounds_set_normal(block, 6);
+ UI_block_direction_set(block, UI_DIR_DOWN);
return block;
}
@@ -3639,7 +3689,7 @@ void uiTemplateComponentMenu(uiLayout *layout, PointerRNA *ptr, const char *prop
BLI_strncpy(args->propname, propname, sizeof(args->propname));
block = uiLayoutGetBlock(layout);
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
but = uiDefBlockButN(block, component_menu, args, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, "");
/* set rna directly, uiDefBlockButN doesn't do this */
@@ -3647,7 +3697,7 @@ void uiTemplateComponentMenu(uiLayout *layout, PointerRNA *ptr, const char *prop
but->rnaprop = RNA_struct_find_property(ptr, propname);
but->rnaindex = 0;
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
/************************* Node Socket Icon **************************/
@@ -3658,14 +3708,14 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
uiBut *but;
block = uiLayoutGetBlock(layout);
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
/* XXX using explicit socket colors is not quite ideal.
* Eventually it should be possible to use theme colors for this purpose,
* but this requires a better design for extendable color palettes in user prefs.
*/
- but = uiDefBut(block, NODESOCKET, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ but = uiDefBut(block, UI_BTYPE_NODE_SOCKET, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
rgba_float_to_uchar(but->col, color);
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 008ea84b607..1d51c0588b6 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -41,7 +41,7 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_report.h"
@@ -52,6 +52,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "interface_intern.h"
@@ -70,11 +73,11 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
return NULL;
if (icon && name && name[0] == '\0')
- but = uiDefIconButR_prop(block, ICONTOG, 0, icon, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, icon, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else if (icon)
- but = uiDefIconTextButR_prop(block, ICONTOG, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconTextButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else
- but = uiDefButR_prop(block, OPTION, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_CHECKBOX, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
break;
}
case PROP_INT:
@@ -83,30 +86,42 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
int arraylen = RNA_property_array_length(ptr, prop);
if (arraylen && index == -1) {
- if (ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA))
- but = uiDefButR_prop(block, COLOR, 0, name, x1, y1, x2, y2, ptr, prop, -1, 0, 0, -1, -1, NULL);
+ if (ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA)) {
+ but = uiDefButR_prop(block, UI_BTYPE_COLOR, 0, name, x1, y1, x2, y2, ptr, prop, -1, 0, 0, -1, -1, NULL);
+ }
+ else {
+ return NULL;
+ }
}
else if (RNA_property_subtype(prop) == PROP_PERCENTAGE || RNA_property_subtype(prop) == PROP_FACTOR)
- but = uiDefButR_prop(block, NUMSLI, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else
- but = uiDefButR_prop(block, NUM, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_NUM, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+
+ if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) {
+ UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE);
+ }
break;
}
case PROP_ENUM:
if (icon && name && name[0] == '\0')
- but = uiDefIconButR_prop(block, MENU, 0, icon, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconButR_prop(block, UI_BTYPE_MENU, 0, icon, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else if (icon)
- but = uiDefIconTextButR_prop(block, MENU, 0, icon, NULL, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconTextButR_prop(block, UI_BTYPE_MENU, 0, icon, NULL, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else
- but = uiDefButR_prop(block, MENU, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_MENU, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
break;
case PROP_STRING:
if (icon && name && name[0] == '\0')
- but = uiDefIconButR_prop(block, TEX, 0, icon, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconButR_prop(block, UI_BTYPE_TEXT, 0, icon, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else if (icon)
- but = uiDefIconTextButR_prop(block, TEX, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconTextButR_prop(block, UI_BTYPE_TEXT, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else
- but = uiDefButR_prop(block, TEX, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+
+ if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) {
+ UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE);
+ }
break;
case PROP_POINTER:
{
@@ -119,15 +134,15 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
if (icon == ICON_DOT)
icon = 0;
- but = uiDefIconTextButR_prop(block, SEARCH_MENU, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefIconTextButR_prop(block, UI_BTYPE_SEARCH_MENU, 0, icon, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
break;
}
case PROP_COLLECTION:
{
char text[256];
BLI_snprintf(text, sizeof(text), IFACE_("%d items"), RNA_property_collection_length(ptr, prop));
- but = uiDefBut(block, LABEL, 0, text, x1, y1, x2, y2, NULL, 0, 0, 0, 0, NULL);
- uiButSetFlag(but, UI_BUT_DISABLED);
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, text, x1, y1, x2, y2, NULL, 0, 0, 0, 0, NULL);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
break;
}
default:
@@ -142,9 +157,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
* \a check_prop callback filters functions to avoid drawing certain properties,
* in cases where PROP_HIDDEN flag can't be used for a property.
*/
-int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
- bool (*check_prop)(PointerRNA *, PropertyRNA *),
- const char label_align)
+int uiDefAutoButsRNA(
+ uiLayout *layout, PointerRNA *ptr,
+ bool (*check_prop)(PointerRNA *, PropertyRNA *),
+ const char label_align)
{
uiLayout *split, *col;
int flag;
@@ -201,7 +217,7 @@ int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
/***************************** ID Utilities *******************************/
-int uiIconFromID(ID *id)
+int UI_icon_from_id(ID *id)
{
Object *ob;
PointerRNA ptr;
@@ -219,7 +235,7 @@ int uiIconFromID(ID *id)
if (ob->type == OB_EMPTY)
return ICON_EMPTY_DATA;
else
- return uiIconFromID(ob->data);
+ return UI_icon_from_id(ob->data);
}
/* otherwise get it through RNA, creating the pointer
@@ -230,7 +246,7 @@ int uiIconFromID(ID *id)
}
/* see: report_type_str */
-int uiIconFromReportType(int type)
+int UI_icon_from_report_type(int type)
{
if (type & RPT_ERROR_ALL)
return ICON_ERROR;
@@ -247,7 +263,7 @@ int uiIconFromReportType(int type)
/**
* Returns the best "UI" precision for given floating value, so that e.g. 10.000001 rather gets drawn as '10'...
*/
-int uiFloatPrecisionCalc(int prec, double value)
+int UI_calc_float_precision(int prec, double value)
{
static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7};
static const double max_pow = 10000000.0; /* pow(10, UI_PRECISION_FLOAT_MAX) */
@@ -297,6 +313,34 @@ int uiFloatPrecisionCalc(int prec, double value)
return prec;
}
+bool UI_but_online_manual_id(const uiBut *but, char *r_str, size_t maxlength)
+{
+ if (but->rnapoin.id.data && but->rnapoin.data && but->rnaprop) {
+ BLI_snprintf(r_str, maxlength, "%s.%s", RNA_struct_identifier(but->rnapoin.type),
+ RNA_property_identifier(but->rnaprop));
+ return true;
+ }
+ else if (but->optype) {
+ WM_operator_py_idname(r_str, but->optype->idname);
+ return true;
+ }
+
+ *r_str = '\0';
+ return false;
+}
+
+bool UI_but_online_manual_id_from_active(const struct bContext *C, char *r_str, size_t maxlength)
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but) {
+ return UI_but_online_manual_id(but, r_str, maxlength);
+ }
+
+ *r_str = '\0';
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/* Modal Button Store API */
@@ -390,6 +434,27 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p)
}
/**
+ * Update the pointer for a registered button.
+ */
+bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src)
+{
+ uiButStore *bs_handle;
+ bool found = false;
+
+ for (bs_handle = block->butstore.first; bs_handle; bs_handle = bs_handle->next) {
+ uiButStoreElem *bs_elem;
+ for (bs_elem = bs_handle->items.first; bs_elem; bs_elem = bs_elem->next) {
+ if (*bs_elem->but_p == but_src) {
+ *bs_elem->but_p = but_dst;
+ found = true;
+ }
+ }
+ }
+
+ return found;
+}
+
+/**
* NULL all pointers, don't free since the owner needs to be able to inspect.
*/
void UI_butstore_clear(uiBlock *block)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 11b9b9c83cc..5d37f5c0fcf 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -27,7 +27,6 @@
* \ingroup edinterface
*/
-
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -56,19 +55,22 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
-
#include "interface_intern.h"
+#ifdef WITH_INPUT_IME
+# include "WM_types.h"
+#endif
+
/* icons are 80% of height of button (16 pixels inside 20 height) */
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
/* ************** widget base functions ************** */
-/*
+/**
* - in: roundbox codes for corner types and radius
- * - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords
+ * - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords
*
* - draw black box with alpha 0 on exact button boundbox
- * - for ever AA step:
+ * - for every AA step:
* - draw the inner part for a round filled box, with color blend codes or texture coords
* - draw outline in outline color
* - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
@@ -98,14 +100,14 @@ typedef struct uiWidgetBase {
float inner_v[WIDGET_SIZE_MAX][2];
float inner_uv[WIDGET_SIZE_MAX][2];
- bool inner, outline, emboss, shadedir;
+ bool draw_inner, draw_outline, draw_emboss, draw_shadedir;
uiWidgetTrias tria1;
uiWidgetTrias tria2;
} uiWidgetBase;
-/* uiWidgetType: for time being only for visual appearance,
+/** uiWidgetType: for time being only for visual appearance,
* later, a handling callback can be added too
*/
typedef struct uiWidgetType {
@@ -198,7 +200,7 @@ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslatef(jit[j][0], jit[j][1], 0.0f);
+ glTranslate2fv(jit[j]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
}
@@ -221,8 +223,8 @@ void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float m
glColor4fv(color);
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslatef(jit[j][0], jit[j][1], 0.0f);
- uiDrawBox(mode, minx, miny, maxx, maxy, rad);
+ glTranslate2fv(jit[j]);
+ UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad);
glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
}
@@ -235,10 +237,10 @@ static void widget_init(uiWidgetBase *wtb)
wtb->tria1.tot = 0;
wtb->tria2.tot = 0;
- wtb->inner = 1;
- wtb->outline = 1;
- wtb->emboss = 1;
- wtb->shadedir = 1;
+ wtb->draw_inner = true;
+ wtb->draw_outline = true;
+ wtb->draw_emboss = true;
+ wtb->draw_shadedir = true;
}
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
@@ -490,12 +492,12 @@ static void widget_draw_tria_ex(
minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
/* center position and size */
- centx = (float)rect->xmin + 0.5f * minsize;
+ centx = (float)rect->xmin + 0.4f * minsize;
centy = (float)rect->ymin + 0.5f * minsize;
sizex = sizey = -0.5f * triasize * minsize;
if (where == 'r') {
- centx = (float)rect->xmax - 0.5f * minsize;
+ centx = (float)rect->xmax - 0.4f * minsize;
sizex = -sizex;
}
else if (where == 't') {
@@ -545,12 +547,12 @@ static void widget_menu_trias(uiWidgetTrias *tria, const rcti *rect)
{
float centx, centy, size;
int a;
-
+
/* center position and size */
centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
- size = 0.4f * (float)BLI_rcti_size_y(rect);
-
+ size = 0.4f * BLI_rcti_size_y(rect);
+
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * menu_tria_vert[a][0] + centx;
tria->vec[a][1] = size * menu_tria_vert[a][1] + centy;
@@ -583,7 +585,6 @@ static void widget_check_trias(uiWidgetTrias *tria, const rcti *rect)
/* prepares shade colors */
static void shadecolors4(char coltop[4], char coldown[4], const char *color, short shadetop, short shadedown)
{
-
coltop[0] = CLAMPIS(color[0] + shadetop, 0, 255);
coltop[1] = CLAMPIS(color[1] + shadetop, 0, 255);
coltop[2] = CLAMPIS(color[2] + shadetop, 0, 255);
@@ -600,42 +601,42 @@ static void round_box_shade_col4_r(unsigned char r_col[4], const char col1[4], c
const int faci = FTOCHAR(fac);
const int facm = 255 - faci;
- r_col[0] = (faci * col1[0] + facm * col2[0]) >> 8;
- r_col[1] = (faci * col1[1] + facm * col2[1]) >> 8;
- r_col[2] = (faci * col1[2] + facm * col2[2]) >> 8;
- r_col[3] = (faci * col1[3] + facm * col2[3]) >> 8;
+ r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
+ r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
+ r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
+ r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
}
-static void widget_verts_to_quad_strip(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2])
+static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
{
int a;
for (a = 0; a < totvert; a++) {
- copy_v2_v2(quad_strip[a * 2], wtb->outer_v[a]);
- copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[a]);
+ copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[a]);
+ copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[a]);
}
- copy_v2_v2(quad_strip[a * 2], wtb->outer_v[0]);
- copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[0]);
+ copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[0]);
+ copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
}
-static void widget_verts_to_quad_strip_open(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2][2])
+static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2])
{
int a;
for (a = 0; a < totvert; a++) {
- quad_strip[a * 2][0] = wtb->outer_v[a][0];
- quad_strip[a * 2][1] = wtb->outer_v[a][1];
- quad_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
- quad_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
+ triangle_strip[a * 2][0] = wtb->outer_v[a][0];
+ triangle_strip[a * 2][1] = wtb->outer_v[a][1];
+ triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
+ triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
}
}
static void widgetbase_outline(uiWidgetBase *wtb)
{
- float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
- widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
+ float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
+ widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
glDisableClientState(GL_VERTEX_ARRAY);
}
@@ -646,7 +647,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glEnable(GL_BLEND);
/* backdrop non AA */
- if (wtb->inner) {
+ if (wtb->draw_inner) {
if (wcol->shaded == 0) {
if (wcol->alpha_check) {
float inner_v_half[WIDGET_SIZE_MAX][2];
@@ -712,7 +713,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glShadeModel(GL_SMOOTH);
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
- round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->shadedir]);
+ round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
glEnableClientState(GL_VERTEX_ARRAY);
@@ -728,38 +729,43 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
}
/* for each AA step */
- if (wtb->outline) {
- float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
- float quad_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
+ if (wtb->draw_outline) {
+ float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
+ float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
const unsigned char tcol[4] = {wcol->outline[0],
wcol->outline[1],
wcol->outline[2],
wcol->outline[3] / WIDGET_AA_JITTER};
- widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
+ widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
- if (wtb->emboss) {
- widget_verts_to_quad_strip_open(wtb, wtb->halfwayvert, quad_strip_emboss);
+ if (wtb->draw_emboss) {
+ widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
}
glEnableClientState(GL_VERTEX_ARRAY);
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslatef(jit[j][0], jit[j][1], 0.0f);
+ unsigned char emboss[4];
+
+ glTranslate2fv(jit[j]);
/* outline */
glColor4ubv(tcol);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
-
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
+
/* emboss bottom shadow */
- if (wtb->emboss) {
- glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
+ if (wtb->draw_emboss) {
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss);
- glDrawArrays(GL_QUAD_STRIP, 0, wtb->halfwayvert * 2);
+ if (emboss[3]) {
+ glColor4ubv(emboss);
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->halfwayvert * 2);
+ }
}
glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
@@ -774,9 +780,10 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
wcol->item[1],
wcol->item[2],
(unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
+
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslatef(jit[j][0], jit[j][1], 0.0f);
+ glTranslate2fv(jit[j]);
if (wtb->tria1.tot) {
glColor4ubv(tcol);
@@ -792,7 +799,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
}
glDisable(GL_BLEND);
-
}
/* *********************** text/icon ************************************** */
@@ -801,7 +807,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
#define PREVIEW_PAD 4
-static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti *rect)
+static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
{
int w, h, size;
@@ -817,25 +823,26 @@ static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti
int x = rect->xmin + w / 2 - size / 2;
int y = rect->ymin + h / 2 - size / 2;
- UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, size);
+ UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, alpha, size);
}
}
static int ui_but_draw_menu_icon(const uiBut *but)
{
- return (but->flag & UI_ICON_SUBMENU) && (but->dt == UI_EMBOSSP);
+ return (but->flag & UI_BUT_ICON_SUBMENU) && (but->dt == UI_EMBOSS_PULLDOWN);
}
/* icons have been standardized... and this call draws in untransformed coordinates */
-static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
- const bool show_menu_icon)
+static void widget_draw_icon(
+ const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
+ const bool show_menu_icon)
{
float xs = 0.0f, ys = 0.0f;
float aspect, height;
- if (but->flag & UI_ICON_PREVIEW) {
+ if (but->flag & UI_BUT_ICON_PREVIEW) {
glEnable(GL_BLEND);
widget_draw_preview(icon, alpha, rect);
glDisable(GL_BLEND);
@@ -843,20 +850,20 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
}
/* this icon doesn't need draw... */
- if (icon == ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU) == 0) return;
+ if (icon == ICON_BLANK1 && (but->flag & UI_BUT_ICON_SUBMENU) == 0) return;
aspect = but->block->aspect / UI_DPI_FAC;
height = ICON_DEFAULT_HEIGHT / aspect;
/* calculate blend color */
- if (ELEM(but->type, TOG, ROW, TOGN, LISTROW)) {
+ if (ELEM(but->type, UI_BTYPE_TOGGLE, UI_BTYPE_ROW, UI_BTYPE_TOGGLE_N, UI_BTYPE_LISTROW)) {
if (but->flag & UI_SELECT) {}
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
}
/* extra feature allows more alpha blending */
- if ((but->type == LABEL) && but->a1 == 1.0f)
+ if ((but->type == UI_BTYPE_LABEL) && but->a1 == 1.0f)
alpha *= but->a2;
glEnable(GL_BLEND);
@@ -866,7 +873,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
if (but->drawflag & UI_BUT_ICON_LEFT) {
if (but->block->flag & UI_BLOCK_LOOP) {
- if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (but->type == UI_BTYPE_SEARCH_MENU)
xs = rect->xmin + 4.0f * ofs;
else
xs = rect->xmin + ofs;
@@ -922,12 +929,14 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str)
but->ofs += bytes;
}
-/* Helper.
+/**
+ * Helper.
* This func assumes things like kerning handling have already been handled!
* Return the length of modified (right-clipped + ellipsis) string.
*/
-static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
- const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
+static void ui_text_clip_right_ex(
+ uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
+ const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
{
float tmp;
int l_end;
@@ -959,15 +968,20 @@ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t m
* If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep is preserved at all cost (useful
* for strings with shortcuts, like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
- const size_t max_len, const char *rpart_sep)
+float UI_text_clip_middle_ex(
+ uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char rpart_sep)
{
float strwidth;
+ /* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits!
+ * Better to have a small piece of the last char cut out, than two remaining chars replaced by an allipsis... */
+ okwidth += 1.0f + UI_DPI_FAC;
+
BLI_assert(str[0]);
/* need to set this first */
- uiStyleFontSet(fstyle);
+ UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) { /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
@@ -989,7 +1003,7 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidt
size_t final_lpart_len;
if (rpart_sep) {
- rpart = strstr(str, rpart_sep);
+ rpart = strrchr(str, rpart_sep);
if (rpart) {
rpart_len = strlen(rpart);
@@ -1060,34 +1074,34 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidt
}
/**
- * Wrapper around ui_text_clip_middle_ex.
+ * Wrapper around UI_text_clip_middle_ex.
*/
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
/* No margin for labels! */
- const int border = ELEM(but->type, LABEL, MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
+ const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
const size_t max_len = sizeof(but->drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL);
+ but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, '\0');
}
/**
* Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep.
* Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char *rsep)
+static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep)
{
/* No margin for labels! */
- const int border = ELEM(but->type, LABEL, MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
+ const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
const size_t max_len = sizeof(but->drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
+ but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
}
/**
@@ -1101,7 +1115,7 @@ static void ui_text_clip_cursor(uiFontStyle *fstyle, uiBut *but, const rcti *rec
BLI_assert(but->editstr && but->pos >= 0);
/* need to set this first */
- uiStyleFontSet(fstyle);
+ UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
@@ -1164,7 +1178,7 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti
const char *cpend = but->drawstr + drawstr_len;
/* need to set this first */
- uiStyleFontSet(fstyle);
+ UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
@@ -1208,7 +1222,6 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs, sizeof(but->drawstr) - but->ofs);
if (but->strwidth < 10) break;
}
-
}
@@ -1226,6 +1239,50 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
+#ifdef WITH_INPUT_IME
+static void widget_draw_text_ime_underline(
+ uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, const rcti *rect,
+ const wmIMEData *ime_data, const char *drawstr)
+{
+ int ofs_x, width;
+ int rect_x = BLI_rcti_size_x(rect);
+ int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end;
+
+ if (drawstr[0] != 0) {
+ if (but->pos >= but->ofs) {
+ ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
+ }
+ else {
+ ofs_x = 0;
+ }
+
+ width = BLF_width(fstyle->uifont_id, drawstr + but->ofs,
+ ime_data->composite_len + but->pos - but->ofs);
+
+ glColor4ubv((unsigned char *)wcol->text);
+ UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1);
+
+ /* draw the thick line */
+ if (sel_start != -1 && sel_end != -1) {
+ sel_end -= sel_start;
+ sel_start += but->pos;
+
+ if (sel_start >= but->ofs) {
+ ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_start - but->ofs);
+ }
+ else {
+ ofs_x = 0;
+ }
+
+ width = BLF_width(fstyle->uifont_id, drawstr + but->ofs,
+ sel_end + sel_start - but->ofs);
+
+ UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2);
+ }
+ }
+}
+#endif /* WITH_INPUT_IME */
+
static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
{
int drawstr_left_len = UI_MAX_DRAW_STR;
@@ -1233,7 +1290,11 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
const char *drawstr_right = NULL;
bool use_right_only = false;
- uiStyleFontSet(fstyle);
+#ifdef WITH_INPUT_IME
+ const wmIMEData *ime_data;
+#endif
+
+ UI_fontstyle_set(fstyle);
if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT))
fstyle->align = UI_STYLE_TEXT_LEFT;
@@ -1249,7 +1310,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* Special case: when we're entering text for multiple buttons,
* don't draw the text for any of the multi-editing buttons */
if (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI)) {
- uiBut *but_edit = ui_get_but_drag_multi_edit(but);
+ uiBut *but_edit = ui_but_drag_multi_edit_get(but);
if (but_edit) {
drawstr = but_edit->editstr;
fstyle->align = UI_STYLE_TEXT_LEFT;
@@ -1260,13 +1321,30 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* max length isn't used in this case,
* we rely on string being NULL terminated. */
drawstr_left_len = INT_MAX;
- drawstr = but->editstr;
+
+#ifdef WITH_INPUT_IME
+ /* FIXME, IME is modifying 'const char *drawstr! */
+ ime_data = ui_but_ime_data_get(but);
+
+ if (ime_data && ime_data->composite_len) {
+ /* insert composite string into cursor pos */
+ BLI_snprintf((char *)drawstr, UI_MAX_DRAW_STR, "%s%s%s",
+ but->editstr, ime_data->str_composite,
+ but->editstr + but->pos);
+ }
+ else
+#endif
+ {
+ drawstr = but->editstr;
+ }
}
}
- /* text button selection and cursor */
+ /* text button selection, cursor, composite underline */
if (but->editstr && but->pos != -1) {
+ int but_pos_ofs;
+ int tx, ty;
/* text button selection */
if ((but->selend - but->selsta) > 0) {
@@ -1292,18 +1370,44 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
}
/* text cursor */
+ but_pos_ofs = but->pos;
+
+#ifdef WITH_INPUT_IME
+ /* if is ime compositing, move the cursor */
+ if (ime_data && ime_data->composite_len && ime_data->cursor_pos != -1) {
+ but_pos_ofs += ime_data->cursor_pos;
+ }
+#endif
+
if (but->pos >= but->ofs) {
int t;
if (drawstr[0] != 0) {
- t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
+ t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but_pos_ofs - but->ofs);
}
else {
t = 0;
}
- glColor3f(0.20, 0.6, 0.9);
- glRecti(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
+ glColor3f(0.2, 0.6, 0.9);
+
+ tx = rect->xmin + t + 2;
+ ty = rect->ymin + 2;
+
+ /* draw cursor */
+ glRecti(rect->xmin + t, ty, tx, rect->ymax - 2);
+ }
+
+#ifdef WITH_INPUT_IME
+ if (ime_data && ime_data->composite_len) {
+ /* ime cursor following */
+ if (but->pos >= but->ofs) {
+ ui_but_ime_reposition(but, tx + 5, ty + 3, false);
+ }
+
+ /* composite underline */
+ widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
}
+#endif
}
if (fstyle->kerning == 1)
@@ -1328,7 +1432,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
}
#ifdef USE_NUMBUTS_LR_ALIGN
- if (!drawstr_right && ELEM(but->type, NUM, NUMSLI) &&
+ if (!drawstr_right && ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) &&
/* if we're editing or multi-drag (fake editing), then use left alignment */
(but->editstr == NULL) && (drawstr == but->drawstr))
{
@@ -1355,7 +1459,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* for underline drawing */
float font_xofs, font_yofs;
- uiStyleFontDrawExt(fstyle, rect, drawstr + but->ofs,
+ UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs,
drawstr_left_len - but->ofs, &font_xofs, &font_yofs);
if (but->menu_key != '\0') {
@@ -1395,7 +1499,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
if (drawstr_right) {
fstyle->align = UI_STYLE_TEXT_RIGHT;
rect->xmax -= UI_TEXT_CLIP_MARGIN;
- uiStyleFontDraw(fstyle, rect, drawstr_right);
+ UI_fontstyle_draw(fstyle, rect, drawstr_right);
}
}
@@ -1405,11 +1509,12 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
+ uiButExtraIconType extra_icon_type;
- ui_button_text_password_hide(password_str, but, false);
+ ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
- if (but->type == MENU && (but->flag & UI_BUT_NODE_LINK)) {
+ if (but->type == UI_BTYPE_MENU && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, false);
@@ -1418,7 +1523,34 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
* and offset the text label to accommodate it */
- if (but->flag & UI_HAS_ICON || show_menu_icon) {
+ /* Big previews with optional text label below */
+ if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
+ const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
+ int icon_size = BLI_rcti_size_y(rect);
+ int text_size = 0;
+
+ /* This is a bit britle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */
+ if (icon_size > BLI_rcti_size_x(rect)) {
+ /* button is not square, it has extra height for label */
+ text_size = UI_UNIT_Y;
+ icon_size -= text_size;
+ }
+
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
+ glEnable(GL_BLEND);
+ widget_draw_preview(icon, alpha, rect);
+ glDisable(GL_BLEND);
+
+ /* offset rect to draw label in */
+ rect->ymin -= text_size;
+ rect->ymax -= icon_size;
+
+ /* vertically centering text */
+ rect->ymin += UI_UNIT_Y / 2;
+ }
+ /* Icons on the left with optional text label on the right */
+ else if (but->flag & UI_HAS_ICON || show_menu_icon) {
const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
@@ -1444,11 +1576,23 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
}
/* unlink icon for this button type */
- if ((but->type == SEARCH_MENU_UNLINK) && ui_is_but_search_unlink_visible(but)) {
+ if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
+ {
rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
- widget_draw_icon(but, ICON_X, alpha, &temp, false);
+
+ if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
+ widget_draw_icon(but, ICON_X, alpha, &temp, false);
+ }
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
+ }
+ else {
+ BLI_assert(0);
+ }
+
rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
}
@@ -1461,12 +1605,12 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
but->ofs = 0;
but->strwidth = 0;
}
- else if (ELEM(but->type, NUM, NUMSLI)) {
+ else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
ui_text_clip_right_label(fstyle, but, rect);
}
- else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
+ else if (but->flag & UI_BUT_HAS_SEP_CHAR) {
/* Clip middle, but protect in all case right part containing the shortcut, if any. */
- ui_text_clip_middle_protect_right(fstyle, but, rect, "|");
+ ui_text_clip_middle_protect_right(fstyle, but, rect, UI_SEP_CHAR);
}
else {
ui_text_clip_middle(fstyle, but, rect);
@@ -1475,7 +1619,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* always draw text for textbutton cursor */
widget_draw_text(fstyle, wcol, but, rect);
- ui_button_text_password_hide(password_str, but, true);
+ ui_but_text_password_hide(password_str, but, true);
}
#undef UI_TEXT_CLIP_MARGIN
@@ -1483,17 +1627,6 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* *********************** widget types ************************************* */
-
-/* uiWidgetStateColors
- * char inner_anim[4];
- * char inner_anim_sel[4];
- * char inner_key[4];
- * char inner_key_sel[4];
- * char inner_driven[4];
- * char inner_driven_sel[4];
- * float blend;
- */
-
static struct uiWidgetStateColors wcol_state_colors = {
{115, 190, 76, 255},
{90, 166, 51, 255},
@@ -1504,18 +1637,6 @@ static struct uiWidgetStateColors wcol_state_colors = {
0.5f, 0.0f
};
-/* uiWidgetColors
- * char outline[3];
- * char inner[4];
- * char inner_sel[4];
- * char item[3];
- * char text[3];
- * char text_sel[3];
- *
- * short shaded;
- * float shadetop, shadedown;
- */
-
static struct uiWidgetColors wcol_num = {
{25, 25, 25, 255},
{180, 180, 180, 255},
@@ -1646,7 +1767,7 @@ static struct uiWidgetColors wcol_tooltip = {
{45, 45, 45, 230},
{100, 100, 100, 255},
- {160, 160, 160, 255},
+ {255, 255, 255, 255},
{255, 255, 255, 255},
0,
@@ -1808,6 +1929,23 @@ static void widget_state_blend(char cp[3], const char cpstate[3], const float fa
}
}
+/* put all widget colors on half alpha, use local storage */
+static void ui_widget_color_disabled(uiWidgetType *wt)
+{
+ static uiWidgetColors wcol_theme_s;
+
+ wcol_theme_s = *wt->wcol_theme;
+
+ wcol_theme_s.outline[3] *= 0.5;
+ wcol_theme_s.inner[3] *= 0.5;
+ wcol_theme_s.inner_sel[3] *= 0.5;
+ wcol_theme_s.item[3] *= 0.5;
+ wcol_theme_s.text[3] *= 0.5;
+ wcol_theme_s.text_sel[3] *= 0.5;
+
+ wt->wcol_theme = &wcol_theme_s;
+}
+
/* copy colors from theme, and set changes in it based on state */
static void widget_state(uiWidgetType *wt, int state)
{
@@ -1817,6 +1955,10 @@ static void widget_state(uiWidgetType *wt, int state)
/* Override default widget's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
+
+ if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ ui_widget_color_disabled(wt);
+ }
}
wt->wcol = *(wt->wcol_theme);
@@ -1998,7 +2140,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
rcti rect1 = *rect;
float alphastep;
int step, totvert;
- float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2];
+ float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2];
const float radout = UI_ThemeMenuShadowWidth();
/* disabled shadow */
@@ -2026,10 +2168,10 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
- widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
+ widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
}
glDisableClientState(GL_VERTEX_ARRAY);
@@ -2047,11 +2189,11 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
//rect->ymin -= 4.0;
//rect->ymax += 4.0;
}
- else if (direction == UI_DOWN) {
+ else if (direction == UI_DIR_DOWN) {
roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
rect->ymin -= 0.1f * U.widget_unit;
}
- else if (direction == UI_TOP) {
+ else if (direction == UI_DIR_UP) {
roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
rect->ymax += 0.1f * U.widget_unit;
}
@@ -2060,7 +2202,7 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
- wtb.emboss = 0;
+ wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
glDisable(GL_BLEND);
@@ -2069,7 +2211,6 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
static void ui_hsv_cursor(float x, float y)
{
-
glPushMatrix();
glTranslatef(x, y, 0.0f);
@@ -2084,7 +2225,6 @@ static void ui_hsv_cursor(float x, float y)
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
-
}
void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
@@ -2110,10 +2250,10 @@ void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float
float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
float ang, radius_t;
- ang = 2.0f * (float)M_PI * hsv[0] + 0.5f * (float)M_PI;
+ ang = 2.0f * (float)M_PI * hsv[0] + (float)M_PI_2;
if ((but->flag & UI_BUT_COLOR_CUBIC) && (U.color_picker_type == USER_CP_CIRCLE_HSV))
- radius_t = (1.0f - powf(1.0f - hsv[1], 3.0f));
+ radius_t = (1.0f - pow3f(1.0f - hsv[1]));
else
radius_t = hsv[1];
@@ -2131,14 +2271,15 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
/* gouraud triangle fan */
- const float *hsv_ptr = ui_block_hsv_get(but->block);
+ ColorPicker *cpicker = but->custom_data;
+ const float *hsv_ptr = cpicker->color_data;
float xpos, ypos, ang = 0.0f;
float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
int a;
- bool color_profile = ui_color_picker_use_display_colorspace(but);
+ bool color_profile = ui_but_is_colorpicker_display_space(but);
/* color */
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
/* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
hsvo[0] = hsv[0] = hsv_ptr[0];
@@ -2146,7 +2287,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
hsvo[2] = hsv[2] = hsv_ptr[2];
if (color_profile)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
copy_v3_v3(hsvo, hsv);
@@ -2158,12 +2299,12 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
* Useful for color correction tools where you're only interested in hue. */
if (but->flag & UI_BUT_COLOR_LOCK) {
if (U.color_picker_type == USER_CP_CIRCLE_HSV)
- hsv[2] = 1.f;
+ hsv[2] = 1.0f;
else
hsv[2] = 0.5f;
}
- ui_color_picker_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
+ ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
glShadeModel(GL_SMOOTH);
@@ -2209,7 +2350,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
{
/* allows for 4 steps (red->yellow) */
- const float color_step = (1.0 / 48.0);
+ const float color_step = 1.0f / 48.0f;
int a;
float h = hsv[0], s = hsv[1], v = hsv[2];
float dx, dy, sx1, sx2, sy;
@@ -2222,9 +2363,9 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
switch (type) {
case UI_GRAD_SV:
hsv_to_rgb(h, 0.0, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
- hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
- hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
- hsv_to_rgb(h, 1.0, 0.0, &col1[3][0], &col1[3][1], &col1[3][2]);
+ hsv_to_rgb(h, 0.0, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, 0.0, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 0.0, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(0.0, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
@@ -2239,26 +2380,26 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
hsv_to_rgb(0.0, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
- hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
case UI_GRAD_S:
- hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
- hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
break;
default:
assert(!"invalid 'type' argument");
- hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
@@ -2279,10 +2420,10 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
/* new color */
switch (type) {
case UI_GRAD_SV:
- hsv_to_rgb(h, 0.0, dx, &col1[0][0], &col1[0][1], &col1[0][2]);
- hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
- hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
- hsv_to_rgb(h, 1.0, dx, &col1[3][0], &col1[3][1], &col1[3][2]);
+ hsv_to_rgb(h, dx, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(h, dx, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, dx, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, dx, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(dx_next, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
@@ -2297,23 +2438,21 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
hsv_to_rgb(dx_next, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
- {
/* annoying but without this the color shifts - could be solved some other way
* - campbell */
- hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
- }
case UI_GRAD_S:
- hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
- hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
@@ -2342,12 +2481,11 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
glEnd();
}
-
+
glShadeModel(GL_FLAT);
-
}
-bool ui_color_picker_use_display_colorspace(uiBut *but)
+bool ui_but_is_colorpicker_display_space(uiBut *but)
{
bool color_profile = but->block->color_profile;
@@ -2365,7 +2503,7 @@ void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *x
switch ((int)but->a1) {
case UI_GRAD_SV:
- x = hsv[2]; y = hsv[1]; break;
+ x = hsv[1]; y = hsv[2]; break;
case UI_GRAD_HV:
x = hsv[0]; y = hsv[2]; break;
case UI_GRAD_HS:
@@ -2387,27 +2525,27 @@ void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *x
y = (hsv[2] - but->softmin) / (but->softmax - but->softmin);
break;
}
-
+
/* cursor */
*xp = rect->xmin + x * BLI_rcti_size_x(rect);
*yp = rect->ymin + y * BLI_rcti_size_y(rect);
-
}
static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
{
float rgb[3];
float x = 0.0f, y = 0.0f;
- const float *hsv = ui_block_hsv_get(but->block);
+ ColorPicker *cpicker = but->custom_data;
+ float *hsv = cpicker->color_data;
float hsv_n[3];
- bool use_display_colorspace = ui_color_picker_use_display_colorspace(but);
+ bool use_display_colorspace = ui_but_is_colorpicker_display_space(but);
copy_v3_v3(hsv_n, hsv);
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (use_display_colorspace)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
rgb_to_hsv_compat_v(rgb, hsv_n);
@@ -2436,10 +2574,10 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
color_profile = false;
- ui_get_but_vectorf(but, rgb);
+ ui_but_v3_get(but, rgb);
if (color_profile)
- ui_block_to_display_space_v3(but->block, rgb);
+ ui_block_cm_to_display_space_v3(but->block, rgb);
if (but->a1 == UI_GRAD_L_ALT)
rgb_to_hsl_v(rgb, hsv);
@@ -2449,8 +2587,11 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
/* map v from property range to [0,1] */
if (but->a1 == UI_GRAD_V_ALT) {
- float range = but->softmax - but->softmin;
- v = (v - but->softmin) / range;
+ float min = but->softmin, max = but->softmax;
+ if (color_profile) {
+ ui_block_cm_to_display_space_range(but->block, &min, &max);
+ }
+ v = (v - min) / (max - min);
}
widget_init(&wtb);
@@ -2471,9 +2612,8 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
-
+
ui_hsv_cursor(x, y);
-
}
@@ -2558,7 +2698,8 @@ bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], &coord_array[0][0], resol, sizeof(float[2]));
BKE_curve_forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], &coord_array[0][1], resol, sizeof(float[2]));
- return 1;
+ /* TODO: why return anything if always true? */
+ return true;
}
#define LINK_RESOL 24
@@ -2567,9 +2708,10 @@ void ui_draw_link_bezier(const rcti *rect)
float coord_array[LINK_RESOL + 1][2];
if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
+#if 0 /* unused */
/* we can reuse the dist variable here to increment the GL curve eval amount*/
- // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
-
+ const float dist = 1.0f / (float)LINK_RESOL;
+#endif
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
@@ -2580,12 +2722,11 @@ void ui_draw_link_bezier(const rcti *rect)
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
}
}
/* function in use for buttons and for view2d sliders */
-void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
+void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
int horizontal;
@@ -2602,7 +2743,7 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slid
else
rad = 0.5f * BLI_rcti_size_x(rect);
- wtb.shadedir = (horizontal) ? 1 : 0;
+ wtb.draw_shadedir = (horizontal) ? true : false;
/* draw back part, colors swapped and shading inverted */
if (horizontal)
@@ -2631,11 +2772,11 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slid
}
/* draw */
- wtb.emboss = 0; /* only emboss once */
+ wtb.draw_emboss = false; /* only emboss once */
/* exception for progress bar */
if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.outline);
+ SWAP(bool, outline, wtb.draw_outline);
}
round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
@@ -2658,7 +2799,7 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slid
widgetbase_draw(&wtb, wcol);
if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.outline);
+ SWAP(bool, outline, wtb.draw_outline);
}
}
}
@@ -2671,7 +2812,7 @@ static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
int horizontal;
/* calculate slider part */
- value = ui_get_but_val(but);
+ value = ui_but_value_get(but);
size = (but->softmax + but->a1 - but->softmin);
size = max_ff(size, 2.0f);
@@ -2721,7 +2862,7 @@ static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
state = UI_SCROLL_PRESSED;
else
state = 0;
- uiWidgetScrollDraw(wcol, rect, &rect1, state);
+ UI_draw_widget_scroll(wcol, rect, &rect1, state);
}
static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
@@ -2743,7 +2884,7 @@ static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int
rect_bar.xmax = rect_bar.xmin + w;
- uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
+ UI_draw_widget_scroll(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
/* raise text a bit */
rect->ymin += 6 * UI_DPI_FAC;
@@ -2772,7 +2913,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
uiWidgetBase wtb, wtb1;
rcti rect1;
double value;
- float offs, toffs, fac;
+ float offs, toffs, fac = 0;
char outline[3];
widget_init(&wtb);
@@ -2785,7 +2926,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
toffs = offs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, offs);
- wtb.outline = 0;
+ wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
/* draw left/right parts only when not in text editing */
@@ -2802,13 +2943,15 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
rect1 = *rect;
- value = ui_get_but_val(but);
- fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
+ value = ui_but_value_get(but);
+ if ((but->softmax - but->softmin) > 0) {
+ fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
+ }
/* left part of slider, always rounded */
rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
- wtb1.outline = 0;
+ wtb1.draw_outline = false;
widgetbase_draw(&wtb1, wcol);
/* right part of slider, interpolate roundness */
@@ -2833,8 +2976,8 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
}
/* outline */
- wtb.outline = 1;
- wtb.inner = 0;
+ wtb.draw_outline = true;
+ wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
/* add space at either side of the button so text aligns with numbuttons (which have arrow icons) */
@@ -2842,7 +2985,6 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
rect->xmax -= toffs;
rect->xmin += toffs;
}
-
}
/* I think 3 is sufficient border to indicate keyed status */
@@ -2873,7 +3015,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
rad = 0.25f * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
- ui_get_but_vectorf(but, col);
+ ui_but_v3_get(but, col);
if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
/* draw based on state - color for keyed etc */
@@ -2889,7 +3031,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
}
if (color_profile)
- ui_block_to_display_space_v3(but->block, col);
+ ui_block_cm_to_display_space_v3(but->block, col);
rgba_float_to_uchar((unsigned char *)wcol->inner, col);
@@ -2902,12 +3044,9 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
float width = rect->xmax - rect->xmin;
float height = rect->ymax - rect->ymin;
/* find color luminance and change it slightly */
- float bw = rgb_to_bw(col);
-
- if (bw > 0.5)
- bw -= 0.5;
- else
- bw += 0.5;
+ float bw = rgb_to_grayscale(col);
+
+ bw += (bw < 0.5f) ? 0.5f : -0.5f;
glColor4f(bw, bw, bw, 1.0);
glBegin(GL_TRIANGLES);
@@ -2918,9 +3057,9 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
}
}
-static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_unitvec(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
- ui_draw_but_NORMAL(but, wcol, rect);
+ ui_draw_but_UNITVEC(but, wcol, rect);
}
static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
@@ -2930,14 +3069,14 @@ static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, i
float rad;
widget_init(&wtb);
- wtb.outline = 0;
+ wtb.draw_outline = false;
/* rounded */
rad = 0.5f * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
- else if (but->type == NUM) {
+ else if (but->type == UI_BTYPE_NUM) {
/* Draw number buttons still with left/right
* triangles when field is not embossed */
widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
@@ -2960,7 +3099,6 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
@@ -3046,7 +3184,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
/* not rounded, no outline */
- wtb.outline = 0;
+ wtb.draw_outline = false;
round_box_edges(&wtb, 0, rect, 0.0f);
widgetbase_draw(&wtb, wcol);
@@ -3060,7 +3198,7 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r
widget_init(&wtb);
- wtb.emboss = 0;
+ wtb.draw_emboss = false;
rad = 0.5f * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -3083,7 +3221,7 @@ static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
/* rounded, but no outline */
- wtb.outline = 0;
+ wtb.draw_outline = false;
rad = 0.2f * U.widget_unit;
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -3156,7 +3294,6 @@ static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3197,7 +3334,6 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3238,10 +3374,9 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *
/* outline */
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- wtb.outline = 1;
- wtb.inner = 0;
+ wtb.draw_outline = true;
+ wtb.draw_inner = false;
widgetbase_draw(&wtb, &wt->wcol);
-
}
static uiWidgetType *widget_type(uiWidgetTypeEnum type)
@@ -3270,7 +3405,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.wcol_theme = &btheme->tui.wcol_toggle;
break;
- case UI_WTYPE_OPTION:
+ case UI_WTYPE_CHECKBOX:
wt.wcol_theme = &btheme->tui.wcol_option;
wt.draw = widget_optionbut;
break;
@@ -3374,8 +3509,8 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_RGB_PICKER:
break;
- case UI_WTYPE_NORMAL:
- wt.custom = widget_normal;
+ case UI_WTYPE_UNITVEC:
+ wt.custom = widget_unitvec;
break;
case UI_WTYPE_SCROLL:
@@ -3410,7 +3545,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
int roundbox = UI_CNR_ALL;
/* alignment */
- if ((but->drawflag & UI_BUT_ALIGN) && but->type != PULLDOWN) {
+ if ((but->drawflag & UI_BUT_ALIGN) && but->type != UI_BTYPE_PULLDOWN) {
/* ui_block_position has this correction too, keep in sync */
if (but->drawflag & UI_BUT_ALIGN_TOP)
@@ -3451,34 +3586,17 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
/* align with open menu */
if (but->active) {
- int direction = ui_button_open_menu_direction(but);
+ int direction = ui_but_menu_direction(but);
- if (direction == UI_TOP) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
- else if (direction == UI_DOWN) roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
- else if (direction == UI_LEFT) roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
- else if (direction == UI_RIGHT) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ if (direction == UI_DIR_UP) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
+ else if (direction == UI_DIR_DOWN) roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ else if (direction == UI_DIR_LEFT) roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
+ else if (direction == UI_DIR_RIGHT) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
}
return roundbox;
}
-/* put all widget colors on half alpha, use local storage */
-static void ui_widget_color_disabled(uiWidgetType *wt)
-{
- static uiWidgetColors wcol_theme_s;
-
- wcol_theme_s = *wt->wcol_theme;
-
- wcol_theme_s.outline[3] *= 0.5;
- wcol_theme_s.inner[3] *= 0.5;
- wcol_theme_s.inner_sel[3] *= 0.5;
- wcol_theme_s.item[3] *= 0.5;
- wcol_theme_s.text[3] *= 0.5;
- wcol_theme_s.text_sel[3] *= 0.5;
-
- wt->wcol_theme = &wcol_theme_s;
-}
-
/* conversion from old to new buttons, so still messy */
void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
{
@@ -3488,12 +3606,12 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
uiWidgetType *wt = NULL;
/* handle menus separately */
- if (but->dt == UI_EMBOSSP) {
+ if (but->dt == UI_EMBOSS_PULLDOWN) {
switch (but->type) {
- case LABEL:
+ case UI_BTYPE_LABEL:
widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
break;
- case SEPRLINE:
+ case UI_BTYPE_SEPR_LINE:
ui_draw_separator(rect, &tui->wcol_menu_item);
break;
default:
@@ -3501,17 +3619,18 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
break;
}
}
- else if (but->dt == UI_EMBOSSN) {
+ else if (but->dt == UI_EMBOSS_NONE) {
/* "nothing" */
wt = widget_type(UI_WTYPE_ICON);
}
- else if (but->dt == UI_EMBOSSR) {
+ else if (but->dt == UI_EMBOSS_RADIAL) {
wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
}
else {
-
+ BLI_assert(but->dt == UI_EMBOSS);
+
switch (but->type) {
- case LABEL:
+ case UI_BTYPE_LABEL:
if (but->block->flag & UI_BLOCK_LOOP)
widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
else {
@@ -3520,51 +3639,50 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
}
break;
- case SEPR:
- case SEPRLINE:
+ case UI_BTYPE_SEPR:
+ case UI_BTYPE_SEPR_LINE:
break;
- case BUT:
+ case UI_BTYPE_BUT:
wt = widget_type(UI_WTYPE_EXEC);
break;
- case NUM:
+ case UI_BTYPE_NUM:
wt = widget_type(UI_WTYPE_NUMBER);
break;
- case NUMSLI:
+ case UI_BTYPE_NUM_SLIDER:
wt = widget_type(UI_WTYPE_SLIDER);
break;
- case ROW:
+ case UI_BTYPE_ROW:
wt = widget_type(UI_WTYPE_RADIO);
break;
- case LISTROW:
+ case UI_BTYPE_LISTROW:
wt = widget_type(UI_WTYPE_LISTITEM);
break;
- case TEX:
+ case UI_BTYPE_TEXT:
wt = widget_type(UI_WTYPE_NAME);
break;
-
- case SEARCH_MENU_UNLINK:
- case SEARCH_MENU:
+
+ case UI_BTYPE_SEARCH_MENU:
wt = widget_type(UI_WTYPE_NAME);
if (but->block->flag & UI_BLOCK_LOOP)
wt->wcol_theme = &btheme->tui.wcol_menu_back;
break;
- case TOGBUT:
- case TOG:
- case TOGN:
+ case UI_BTYPE_BUT_TOGGLE:
+ case UI_BTYPE_TOGGLE:
+ case UI_BTYPE_TOGGLE_N:
wt = widget_type(UI_WTYPE_TOGGLE);
break;
- case OPTION:
- case OPTIONN:
+ case UI_BTYPE_CHECKBOX:
+ case UI_BTYPE_CHECKBOX_N:
if (!(but->flag & UI_HAS_ICON)) {
- wt = widget_type(UI_WTYPE_OPTION);
+ wt = widget_type(UI_WTYPE_CHECKBOX);
but->drawflag |= UI_BUT_TEXT_LEFT;
}
else
@@ -3576,8 +3694,8 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
break;
- case MENU:
- case BLOCK:
+ case UI_BTYPE_MENU:
+ case UI_BTYPE_BLOCK:
if (but->flag & UI_BUT_NODE_LINK) {
/* new node-link button, not active yet XXX */
wt = widget_type(UI_WTYPE_MENU_NODE_LINK);
@@ -3589,7 +3707,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
* add updown arrows if there is room. */
if ((!but->str[0] && but->icon && (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect) + 2)) ||
/* disable for brushes also */
- (but->flag & UI_ICON_PREVIEW))
+ (but->flag & UI_BUT_ICON_PREVIEW))
{
/* no arrows */
wt = widget_type(UI_WTYPE_MENU_ICON_RADIO);
@@ -3600,35 +3718,35 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
}
break;
- case PULLDOWN:
+ case UI_BTYPE_PULLDOWN:
wt = widget_type(UI_WTYPE_PULLDOWN);
break;
- case BUTM:
+ case UI_BTYPE_BUT_MENU:
wt = widget_type(UI_WTYPE_MENU_ITEM);
break;
- case COLOR:
+ case UI_BTYPE_COLOR:
wt = widget_type(UI_WTYPE_SWATCH);
break;
- case ROUNDBOX:
- case LISTBOX:
+ case UI_BTYPE_ROUNDBOX:
+ case UI_BTYPE_LISTBOX:
wt = widget_type(UI_WTYPE_BOX);
break;
- case LINK:
- case INLINK:
+ case UI_BTYPE_LINK:
+ case UI_BTYPE_INLINK:
wt = widget_type(UI_WTYPE_ICON);
wt->custom = widget_link;
break;
- case BUT_EXTRA:
+ case UI_BTYPE_EXTRA:
widget_draw_extra_mask(C, but, widget_type(UI_WTYPE_BOX), rect);
break;
- case HSVCUBE:
+ case UI_BTYPE_HSVCUBE:
if (ELEM(but->a1, UI_GRAD_V_ALT, UI_GRAD_L_ALT)) { /* vertical V slider, uses new widget draw now */
ui_draw_but_HSV_v(but, rect);
}
@@ -3637,56 +3755,56 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
}
break;
- case HSVCIRCLE:
+ case UI_BTYPE_HSVCIRCLE:
ui_draw_but_HSVCIRCLE(but, &tui->wcol_regular, rect);
break;
- case BUT_COLORBAND:
+ case UI_BTYPE_COLORBAND:
ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
break;
- case BUT_NORMAL:
- wt = widget_type(UI_WTYPE_NORMAL);
+ case UI_BTYPE_UNITVEC:
+ wt = widget_type(UI_WTYPE_UNITVEC);
break;
- case BUT_IMAGE:
+ case UI_BTYPE_IMAGE:
ui_draw_but_IMAGE(ar, but, &tui->wcol_regular, rect);
break;
- case HISTOGRAM:
+ case UI_BTYPE_HISTOGRAM:
ui_draw_but_HISTOGRAM(ar, but, &tui->wcol_regular, rect);
break;
- case WAVEFORM:
+ case UI_BTYPE_WAVEFORM:
ui_draw_but_WAVEFORM(ar, but, &tui->wcol_regular, rect);
break;
- case VECTORSCOPE:
+ case UI_BTYPE_VECTORSCOPE:
ui_draw_but_VECTORSCOPE(ar, but, &tui->wcol_regular, rect);
break;
- case BUT_CURVE:
+ case UI_BTYPE_CURVE:
ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
break;
- case PROGRESSBAR:
+ case UI_BTYPE_PROGRESS_BAR:
wt = widget_type(UI_WTYPE_PROGRESSBAR);
fstyle = &style->widgetlabel;
break;
- case SCROLL:
+ case UI_BTYPE_SCROLL:
wt = widget_type(UI_WTYPE_SCROLL);
break;
- case GRIP:
+ case UI_BTYPE_GRIP:
wt = widget_type(UI_WTYPE_ICON);
break;
- case TRACKPREVIEW:
+ case UI_BTYPE_TRACK_PREVIEW:
ui_draw_but_TRACKPREVIEW(ar, but, &tui->wcol_regular, rect);
break;
- case NODESOCKET:
+ case UI_BTYPE_NODE_SOCKET:
ui_draw_but_NODESOCKET(ar, but, &tui->wcol_regular, rect);
break;
@@ -3706,24 +3824,24 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
state = but->flag;
if ((but->editstr) ||
- (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_get_but_drag_multi_edit(but)))
+ (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but)))
{
state |= UI_TEXTINPUT;
}
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE))
- if (but->dt != UI_EMBOSSP)
+ if (but->dt != UI_EMBOSS_PULLDOWN)
disabled = true;
if (disabled)
ui_widget_color_disabled(wt);
-
+
wt->state(wt, state);
if (wt->custom)
wt->custom(but, &wt->wcol, rect, state, roundboxalign);
else if (wt->draw)
wt->draw(&wt->wcol, rect, state, roundboxalign);
-
+
if (disabled)
glEnable(GL_BLEND);
wt->text(fstyle, &wt->wcol, but, rect);
@@ -3731,7 +3849,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
glDisable(GL_BLEND);
// if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE))
-// if (but->dt != UI_EMBOSSP)
+// if (but->dt != UI_EMBOSS_PULLDOWN)
// widget_disabled(&disablerect);
}
}
@@ -3750,12 +3868,12 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
if (block->flag & UI_BLOCK_CLIPTOP) {
/* XXX no scaling for UI here yet */
glColor3ubv((unsigned char *)wt->wcol.text);
- UI_DrawTriIcon(BLI_rcti_cent_x(rect), rect->ymax - 8, 't');
+ UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't');
}
if (block->flag & UI_BLOCK_CLIPBOTTOM) {
/* XXX no scaling for UI here yet */
glColor3ubv((unsigned char *)wt->wcol.text);
- UI_DrawTriIcon(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v');
+ UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v');
}
}
}
@@ -3825,7 +3943,6 @@ static void draw_disk_shaded(
glVertex2f(c * radius_ext, s * radius_ext);
}
glEnd();
-
}
void ui_draw_pie_center(uiBlock *block)
@@ -3842,7 +3959,7 @@ void ui_draw_pie_center(uiBlock *block)
int subd = 40;
float angle = atan2f(pie_dir[1], pie_dir[0]);
- float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? ((float)M_PI / 2.0f) : ((float)M_PI / 4.0f);
+ float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_2 : M_PI_4;
glPushMatrix();
glTranslatef(cx, cy, 0.0f);
@@ -3874,6 +3991,14 @@ void ui_draw_pie_center(uiBlock *block)
glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd);
glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd);
+ if (U.pie_menu_confirm > 0 && !(block->pie_data.flags & (UI_PIE_INVALID_DIR | UI_PIE_CLICK_STYLE))) {
+ float pie_confirm_radius = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm);
+ float pie_confirm_external = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm + 7.0f);
+
+ glColor4ub(btheme->tui.wcol_pie_menu.text_sel[0], btheme->tui.wcol_pie_menu.text_sel[1], btheme->tui.wcol_pie_menu.text_sel[2], 64);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, NULL, NULL, false);
+ }
+
glDisable(GL_BLEND);
glPopMatrix();
}
@@ -3906,7 +4031,6 @@ void ui_draw_search_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->draw(&wt->wcol, rect, block->flag, UI_CNR_ALL);
else
wt->draw(&wt->wcol, rect, 0, UI_CNR_ALL);
-
}
@@ -3921,7 +4045,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
wt->state(wt, state);
wt->draw(&wt->wcol, rect, 0, 0);
- uiStyleFontSet(fstyle);
+ UI_fontstyle_set(fstyle);
fstyle->align = UI_STYLE_TEXT_LEFT;
/* text location offset */
@@ -3935,7 +4059,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
*cpoin = 0;
/* need to set this first */
- uiStyleFontSet(fstyle);
+ UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) { /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
@@ -3956,10 +4080,10 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wt->wcol.text);
- uiStyleFontDraw(fstyle, rect, drawstr);
+ UI_fontstyle_draw(fstyle, rect, drawstr);
}
/* part text right aligned */
@@ -3967,7 +4091,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
if (cpoin) {
fstyle->align = UI_STYLE_TEXT_RIGHT;
rect->xmax = _rect.xmax - 5;
- uiStyleFontDraw(fstyle, rect, cpoin + 1);
+ UI_fontstyle_draw(fstyle, rect, cpoin + 1);
*cpoin = UI_SEP_CHAR;
}
}
@@ -3991,39 +4115,31 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state)
{
- rcti trect = *rect, bg_rect;
+ rcti trect = *rect;
+ const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
+ /* drawing button background */
wt->state(wt, state);
wt->draw(&wt->wcol, rect, 0, 0);
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
glEnable(GL_BLEND);
widget_draw_preview(iconid, 1.0f, rect);
+ glDisable(GL_BLEND);
BLF_width_and_height(fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
/* text rect */
trect.xmin += 0;
- trect.xmax = trect.xmin + font_dims[0] + 10;
- trect.ymin += 10;
+ trect.xmax = trect.xmin + font_dims[0] + U.widget_unit / 2;
+ trect.ymin += U.widget_unit / 2;
trect.ymax = trect.ymin + font_dims[1];
if (trect.xmax > rect->xmax - PREVIEW_PAD)
trect.xmax = rect->xmax - PREVIEW_PAD;
- bg_rect = trect;
- bg_rect.xmin = rect->xmin + PREVIEW_PAD;
- bg_rect.ymin = rect->ymin + PREVIEW_PAD;
- bg_rect.xmax = rect->xmax - PREVIEW_PAD;
- bg_rect.ymax += PREVIEW_PAD / 2;
-
- if (bg_rect.xmax > rect->xmax - PREVIEW_PAD)
- bg_rect.xmax = rect->xmax - PREVIEW_PAD;
-
- glColor4ubv((unsigned char *)wt->wcol_theme->inner_sel);
- glRecti(bg_rect.xmin, bg_rect.ymin, bg_rect.xmax, bg_rect.ymax);
- glDisable(GL_BLEND);
-
{
char drawstr[UI_MAX_DRAW_STR];
const float okwidth = (float)BLI_rcti_size_x(&trect);
@@ -4031,9 +4147,9 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wt->wcol.text);
- uiStyleFontDraw(fstyle, &trect, drawstr);
+ UI_fontstyle_draw(fstyle, &trect, drawstr);
}
}
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 0879f335c68..568f7569e0b 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BKE_appdir.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -60,9 +61,16 @@
/* global for themes */
typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
-static bTheme *theme_active = NULL;
-static int theme_spacetype = SPACE_VIEW3D;
-static int theme_regionid = RGN_TYPE_WINDOW;
+/* be sure to keep 'bThemeState' in sync */
+static struct bThemeState g_theme_state = {
+ NULL,
+ SPACE_VIEW3D,
+ RGN_TYPE_WINDOW,
+};
+
+#define theme_active g_theme_state.theme
+#define theme_spacetype g_theme_state.spacetype
+#define theme_regionid g_theme_state.regionid
void ui_resources_init(void)
{
@@ -271,6 +279,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->view_overlay; break;
case TH_WIRE:
cp = ts->wire; break;
+ case TH_WIRE_INNER:
+ cp = ts->syntaxr; break;
case TH_WIRE_EDIT:
cp = ts->wire_edit; break;
case TH_LAMP:
@@ -369,6 +379,10 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->keyborder_select; break;
case TH_CFRAME:
cp = ts->cframe; break;
+ case TH_TIME_KEYFRAME:
+ cp = ts->time_keyframe; break;
+ case TH_TIME_GP_KEYFRAME:
+ cp = ts->time_gp_keyframe; break;
case TH_NURB_ULINE:
cp = ts->nurb_uline; break;
case TH_NURB_VLINE:
@@ -503,6 +517,17 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_HANDLE_VERTEX_SIZE:
cp = &ts->handle_vertex_size;
break;
+
+ case TH_GP_VERTEX:
+ cp = ts->gp_vertex;
+ break;
+ case TH_GP_VERTEX_SELECT:
+ cp = ts->gp_vertex_select;
+ break;
+ case TH_GP_VERTEX_SIZE:
+ cp = &ts->gp_vertex_size;
+ break;
+
case TH_DOPESHEET_CHANNELOB:
cp = ts->ds_channel;
break;
@@ -544,6 +569,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->paint_curve_pivot;
break;
+ case TH_METADATA_BG:
+ cp = ts->metadatabg;
+ break;
+ case TH_METADATA_TEXT:
+ cp = ts->metadatatext;
+ break;
+
case TH_UV_OTHERS:
cp = ts->uv_others;
break;
@@ -617,6 +649,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->nla_sound_sel;
break;
+ case TH_WIDGET_EMBOSS:
+ cp = btheme->tui.widget_emboss; break;
+
case TH_AXIS_X:
cp = btheme->tui.xaxis; break;
case TH_AXIS_Y:
@@ -654,11 +689,14 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_INFO_DEBUG_TEXT:
cp = ts->info_debug_text;
break;
+ case TH_V3D_CLIPPING_BORDER:
+ cp = ts->clipping_border_3d;
+ break;
}
}
}
- return (unsigned char *)cp;
+ return (const unsigned char *)cp;
}
/* use this call to init new bone color sets in Theme */
@@ -786,8 +824,9 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
}
-/* initialize default theme
- * Note: when you add new colors, created & saved themes need initialized
+/**
+ * initialize default theme
+ * \note: when you add new colors, created & saved themes need initialized
* use function below, init_userdef_do_versions()
*/
void ui_theme_init_default(void)
@@ -813,6 +852,10 @@ void ui_theme_init_default(void)
btheme->tui.panel.show_header = false;
rgba_char_args_set(btheme->tui.panel.header, 0, 0, 0, 25);
+ rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
+
+ rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f);
+
rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255);
rgba_char_args_set(btheme->tui.yaxis, 0, 220, 0, 255);
rgba_char_args_set(btheme->tui.zaxis, 0, 0, 220, 255);
@@ -883,6 +926,9 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ rgba_char_args_set(btheme->tv3d.gp_vertex, 0, 0, 0, 255);
+ rgba_char_args_set(btheme->tv3d.gp_vertex_select, 255, 133, 0, 255);
+ btheme->tv3d.gp_vertex_size = 3;
btheme->tv3d.facedot_size = 4;
@@ -916,6 +962,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.gradients.high_gradient, 58, 58, 58, 255);
btheme->tv3d.gradients.show_grad = false;
+ rgba_char_args_set(btheme->tv3d.clipping_border_3d, 50, 50, 50, 255);
/* space buttons */
/* to have something initialized */
btheme->tbuts = btheme->tv3d;
@@ -1030,7 +1077,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tima.face, 255, 255, 255, 10);
rgba_char_args_set(btheme->tima.face_select, 255, 133, 0, 60);
rgba_char_args_set(btheme->tima.editmesh_active, 255, 255, 255, 128);
- rgba_char_args_set_fl(btheme->tima.preview_back, 0.45, 0.45, 0.45, 1.0);
+ rgba_char_args_set_fl(btheme->tima.preview_back, 0.0, 0.0, 0.0, 0.3);
rgba_char_args_set_fl(btheme->tima.preview_stitch_face, 0.5, 0.5, 0.0, 0.2);
rgba_char_args_set_fl(btheme->tima.preview_stitch_edge, 1.0, 0.0, 1.0, 0.2);
rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2);
@@ -1059,7 +1106,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange*/
rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin Red-purple */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */
+ rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
/* space oops */
btheme->toops = btheme->tv3d;
@@ -1102,8 +1149,12 @@ void ui_theme_init_default(void)
rgba_char_args_set_fl(btheme->ttime.grid, 0.36, 0.36, 0.36, 1.0);
rgba_char_args_set(btheme->ttime.shade1, 173, 173, 173, 255); /* sliders */
+ rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
+ rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+
/* space node, re-uses syntax and console color storage */
btheme->tnode = btheme->tv3d;
+ rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255); /* wire inner color */
rgba_char_args_set(btheme->tnode.edge_select, 255, 255, 255, 255); /* wire selected */
rgba_char_args_set(btheme->tnode.syntaxl, 155, 155, 155, 160); /* TH_NODE, backdrop */
rgba_char_args_set(btheme->tnode.syntaxn, 100, 100, 100, 255); /* in */
@@ -1183,6 +1234,18 @@ bTheme *UI_GetTheme(void)
return U.themes.first;
}
+/**
+ * for the rare case we need to temp swap in a different theme (offscreen render)
+ */
+void UI_Theme_Store(struct bThemeState *theme_state)
+{
+ *theme_state = g_theme_state;
+}
+void UI_Theme_Restore(struct bThemeState *theme_state)
+{
+ g_theme_state = *theme_state;
+}
+
/* for space windows only */
void UI_ThemeColor(int colorid)
{
@@ -1449,8 +1512,9 @@ void UI_GetColorPtrShade3ubv(const unsigned char cp[3], unsigned char col[3], in
}
/* get a 3 byte color, blended and shaded between two other char color pointers */
-void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3],
- float fac, int offset)
+void UI_GetColorPtrBlendShade3ubv(
+ const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3],
+ float fac, int offset)
{
int r, g, b;
@@ -1473,9 +1537,17 @@ void UI_ThemeClearColor(int colorid)
float col[3];
UI_GetThemeColor3fv(colorid, col);
- glClearColor(col[0], col[1], col[2], 0.0);
+ glClearColor(col[0], col[1], col[2], 0.0f);
}
+void UI_ThemeClearColorAlpha(int colorid, float alpha)
+{
+ float col[3];
+ UI_GetThemeColor3fv(colorid, col);
+ glClearColor(col[0], col[1], col[2], alpha);
+}
+
+
int UI_ThemeMenuShadowWidth(void)
{
bTheme *btheme = UI_GetTheme();
@@ -1512,6 +1584,8 @@ void init_userdef_do_versions(void)
{
Main *bmain = G.main;
+#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(bmain, ver, subver)
+
/* the UserDef struct is not corrected with do_versions() .... ugh! */
if (U.wheellinescroll == 0) U.wheellinescroll = 3;
if (U.menuthreshold1 == 0) {
@@ -1523,8 +1597,8 @@ void init_userdef_do_versions(void)
U.tb_rightmouse = 5;
}
if (U.mixbufsize == 0) U.mixbufsize = 2048;
- if (strcmp(U.tempdir, "/") == 0) {
- BLI_system_temporary_dir(U.tempdir);
+ if (STREQ(U.tempdir, "/")) {
+ BKE_tempdir_system_init(U.tempdir);
}
if (U.autokey_mode == 0) {
/* 'add/replace' but not on */
@@ -1540,8 +1614,8 @@ void init_userdef_do_versions(void)
U.tw_size = 25; /* percentage of window size */
U.tw_handlesize = 16; /* percentage of widget radius */
}
- if (U.pad_rot_angle == 0)
- U.pad_rot_angle = 15;
+ if (U.pad_rot_angle == 0.0f)
+ U.pad_rot_angle = 15.0f;
/* graph editor - unselected F-Curve visibility */
if (U.fcu_inactive_alpha == 0) {
@@ -1552,17 +1626,17 @@ void init_userdef_do_versions(void)
/* run in case this was on and is now off in the user prefs [#28096] */
vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL, UI_GetTheme()->tv3d.vertex_unreferenced);
- if (bmain->versionfile <= 191) {
+ if (!USER_VERSION_ATLEAST(192, 0)) {
strcpy(U.sounddir, "/");
}
/* patch to set Dupli Armature */
- if (bmain->versionfile < 220) {
+ if (!USER_VERSION_ATLEAST(220, 0)) {
U.dupflag |= USER_DUP_ARM;
}
/* added seam, normal color, undo */
- if (bmain->versionfile <= 234) {
+ if (!USER_VERSION_ATLEAST(235, 0)) {
bTheme *btheme;
U.uiflag |= USER_GLOBALUNDO;
@@ -1585,12 +1659,12 @@ void init_userdef_do_versions(void)
}
}
}
- if (bmain->versionfile <= 235) {
+ if (!USER_VERSION_ATLEAST(236, 0)) {
/* illegal combo... */
if (U.flag & USER_LMOUSESELECT)
U.flag &= ~USER_TWOBUTTONMOUSE;
}
- if (bmain->versionfile <= 236) {
+ if (!USER_VERSION_ATLEAST(237, 0)) {
bTheme *btheme;
/* new space type */
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1611,7 +1685,7 @@ void init_userdef_do_versions(void)
}
}
}
- if (bmain->versionfile <= 237) {
+ if (!USER_VERSION_ATLEAST(238, 0)) {
bTheme *btheme;
/* bone colors */
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1622,7 +1696,7 @@ void init_userdef_do_versions(void)
}
}
}
- if (bmain->versionfile <= 238) {
+ if (!USER_VERSION_ATLEAST(239, 0)) {
bTheme *btheme;
/* bone colors */
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1633,7 +1707,7 @@ void init_userdef_do_versions(void)
}
}
}
- if (bmain->versionfile <= 239) {
+ if (!USER_VERSION_ATLEAST(240, 0)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1647,7 +1721,7 @@ void init_userdef_do_versions(void)
}
if (U.obcenter_dia == 0) U.obcenter_dia = 6;
}
- if (bmain->versionfile <= 241) {
+ if (!USER_VERSION_ATLEAST(242, 0)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
/* Node editor theme, check for alpha==0 is safe, then color was never set */
@@ -1687,7 +1761,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile <= 242) {
+ if (!USER_VERSION_ATLEAST(243, 0)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1705,11 +1779,11 @@ void init_userdef_do_versions(void)
}
}
}
- if (bmain->versionfile <= 243) {
+ if (!USER_VERSION_ATLEAST(244, 0)) {
/* set default number of recently-used files (if not set) */
if (U.recent_files == 0) U.recent_files = 10;
}
- if (bmain->versionfile < 245 || (bmain->versionfile == 245 && bmain->subversionfile < 3)) {
+ if (!USER_VERSION_ATLEAST(245, 3)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
@@ -1717,7 +1791,7 @@ void init_userdef_do_versions(void)
if (U.coba_weight.tot == 0)
init_colorband(&U.coba_weight, true);
}
- if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 11)) {
+ if (!USER_VERSION_ATLEAST(245, 3)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
/* these should all use the same color */
@@ -1730,7 +1804,7 @@ void init_userdef_do_versions(void)
rgba_char_args_set(btheme->ttime.cframe, 0x60, 0xc0, 0x40, 255);
}
}
- if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 13)) {
+ if (!USER_VERSION_ATLEAST(245, 3)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
/* action channel groups (recolor anyway) */
@@ -1742,10 +1816,10 @@ void init_userdef_do_versions(void)
ui_theme_init_boneColorSets(btheme);
}
}
- if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 16)) {
+ if (!USER_VERSION_ATLEAST(245, 3)) {
U.flag |= USER_ADD_VIEWALIGNED | USER_ADD_EDITMODE;
}
- if ((bmain->versionfile < 247) || (bmain->versionfile == 247 && bmain->subversionfile <= 2)) {
+ if (!USER_VERSION_ATLEAST(245, 3)) {
bTheme *btheme;
/* adjust themes */
@@ -1767,7 +1841,7 @@ void init_userdef_do_versions(void)
rgba_char_args_set(btheme->tseq.vertex_select, col[0], col[1], col[2], 255);
}
}
- if (bmain->versionfile < 250) {
+ if (!USER_VERSION_ATLEAST(250, 0)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1808,7 +1882,7 @@ void init_userdef_do_versions(void)
U.ipo_new = BEZT_IPO_BEZ;
}
- if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 1)) {
+ if (!USER_VERSION_ATLEAST(250, 1)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1831,7 +1905,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 3)) {
+ if (!USER_VERSION_ATLEAST(250, 3)) {
/* new audio system */
if (U.audiochannels == 0)
U.audiochannels = 2;
@@ -1849,59 +1923,60 @@ void init_userdef_do_versions(void)
U.audiorate = 44100;
}
- if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 5))
+ if (!USER_VERSION_ATLEAST(250, 3)) {
U.gameflags |= USER_DISABLE_VBO;
+ }
- if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 8)) {
+ if (!USER_VERSION_ATLEAST(250, 8)) {
wmKeyMap *km;
for (km = U.user_keymaps.first; km; km = km->next) {
- if (strcmp(km->idname, "Armature_Sketch") == 0)
+ if (STREQ(km->idname, "Armature_Sketch"))
strcpy(km->idname, "Armature Sketch");
- else if (strcmp(km->idname, "View3D") == 0)
+ else if (STREQ(km->idname, "View3D"))
strcpy(km->idname, "3D View");
- else if (strcmp(km->idname, "View3D Generic") == 0)
+ else if (STREQ(km->idname, "View3D Generic"))
strcpy(km->idname, "3D View Generic");
- else if (strcmp(km->idname, "EditMesh") == 0)
+ else if (STREQ(km->idname, "EditMesh"))
strcpy(km->idname, "Mesh");
- else if (strcmp(km->idname, "TimeLine") == 0)
+ else if (STREQ(km->idname, "TimeLine"))
strcpy(km->idname, "Timeline");
- else if (strcmp(km->idname, "UVEdit") == 0)
+ else if (STREQ(km->idname, "UVEdit"))
strcpy(km->idname, "UV Editor");
- else if (strcmp(km->idname, "Animation_Channels") == 0)
+ else if (STREQ(km->idname, "Animation_Channels"))
strcpy(km->idname, "Animation Channels");
- else if (strcmp(km->idname, "GraphEdit Keys") == 0)
+ else if (STREQ(km->idname, "GraphEdit Keys"))
strcpy(km->idname, "Graph Editor");
- else if (strcmp(km->idname, "GraphEdit Generic") == 0)
+ else if (STREQ(km->idname, "GraphEdit Generic"))
strcpy(km->idname, "Graph Editor Generic");
- else if (strcmp(km->idname, "Action_Keys") == 0)
+ else if (STREQ(km->idname, "Action_Keys"))
strcpy(km->idname, "Dopesheet");
- else if (strcmp(km->idname, "NLA Data") == 0)
+ else if (STREQ(km->idname, "NLA Data"))
strcpy(km->idname, "NLA Editor");
- else if (strcmp(km->idname, "Node Generic") == 0)
+ else if (STREQ(km->idname, "Node Generic"))
strcpy(km->idname, "Node Editor");
- else if (strcmp(km->idname, "Logic Generic") == 0)
+ else if (STREQ(km->idname, "Logic Generic"))
strcpy(km->idname, "Logic Editor");
- else if (strcmp(km->idname, "File") == 0)
+ else if (STREQ(km->idname, "File"))
strcpy(km->idname, "File Browser");
- else if (strcmp(km->idname, "FileMain") == 0)
+ else if (STREQ(km->idname, "FileMain"))
strcpy(km->idname, "File Browser Main");
- else if (strcmp(km->idname, "FileButtons") == 0)
+ else if (STREQ(km->idname, "FileButtons"))
strcpy(km->idname, "File Browser Buttons");
- else if (strcmp(km->idname, "Buttons Generic") == 0)
+ else if (STREQ(km->idname, "Buttons Generic"))
strcpy(km->idname, "Property Editor");
}
}
- if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 16)) {
+ if (!USER_VERSION_ATLEAST(250, 16)) {
if (U.wmdrawmethod == USER_DRAW_TRIPLE)
U.wmdrawmethod = USER_DRAW_AUTOMATIC;
}
- if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 3)) {
+ if (!USER_VERSION_ATLEAST(252, 3)) {
if (U.flag & USER_LMOUSESELECT)
U.flag &= ~USER_TWOBUTTONMOUSE;
}
- if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 4)) {
+ if (!USER_VERSION_ATLEAST(252, 4)) {
bTheme *btheme;
/* default new handle type is auto handles */
@@ -1916,7 +1991,7 @@ void init_userdef_do_versions(void)
rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0);
}
}
- if (bmain->versionfile <= 252) {
+ if (!USER_VERSION_ATLEAST(253, 0)) {
bTheme *btheme;
/* init new curve colors */
@@ -1925,7 +2000,7 @@ void init_userdef_do_versions(void)
rgba_char_args_set(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255);
}
}
- if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 5)) {
+ if (!USER_VERSION_ATLEAST(252, 5)) {
bTheme *btheme;
/* interface_widgets.c */
@@ -1948,7 +2023,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(255, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->tv3d.extra_edge_len, 32, 0, 0, 255);
@@ -1957,27 +2032,27 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 4)) {
+ if (!USER_VERSION_ATLEAST(256, 4)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if ((btheme->tv3d.outline_width) == 0) btheme->tv3d.outline_width = 1;
}
}
- if (bmain->versionfile < 257) {
+ if (!USER_VERSION_ATLEAST(257, 0)) {
/* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs,
* so that it doesn't linger around from old configs like a ghost */
U.autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET;
}
- if (bmain->versionfile < 258 || (bmain->versionfile == 258 && bmain->subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(258, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
btheme->tnode.noodle_curving = 5;
}
}
- if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 1)) {
+ if (!USER_VERSION_ATLEAST(259, 1)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -1985,7 +2060,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 3)) {
+ if (!USER_VERSION_ATLEAST(260, 3)) {
bTheme *btheme;
/* if new keyframes handle default is stuff "auto", make it "auto-clamped" instead
@@ -2034,7 +2109,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 5)) {
+ if (!USER_VERSION_ATLEAST(260, 5)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2043,7 +2118,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 4)) {
+ if (!USER_VERSION_ATLEAST(261, 4)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set_fl(btheme->tima.preview_stitch_face, 0.071, 0.259, 0.694, 0.150);
@@ -2060,7 +2135,7 @@ void init_userdef_do_versions(void)
U.use_16bit_textures = true;
}
- if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(262, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if (btheme->tui.wcol_menu_item.item[3] == 255)
@@ -2068,7 +2143,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 3)) {
+ if (!USER_VERSION_ATLEAST(262, 3)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if (btheme->tui.wcol_tooltip.inner[3] == 0) {
@@ -2080,7 +2155,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 4)) {
+ if (!USER_VERSION_ATLEAST(262, 4)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if (btheme->tseq.movieclip[3] == 0) {
@@ -2089,7 +2164,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(263, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if (btheme->tclip.strip[0] == 0) {
@@ -2100,13 +2175,13 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 6)) {
+ if (!USER_VERSION_ATLEAST(263, 6)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next)
rgba_char_args_set(btheme->tv3d.skin_root, 180, 77, 77, 255);
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 7)) {
+ if (!USER_VERSION_ATLEAST(263, 7)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2129,7 +2204,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 11)) {
+ if (!USER_VERSION_ATLEAST(263, 11)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if (btheme->tseq.mask[3] == 0) {
@@ -2138,14 +2213,14 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 15)) {
+ if (!USER_VERSION_ATLEAST(263, 15)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->tv3d.bone_pose_active, 140, 255, 255, 80);
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 16)) {
+ if (!USER_VERSION_ATLEAST(263, 16)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2157,7 +2232,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 22)) {
+ if (!USER_VERSION_ATLEAST(263, 22)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2169,7 +2244,7 @@ void init_userdef_do_versions(void)
}
}
- if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 9)) {
+ if (!USER_VERSION_ATLEAST(264, 9)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2179,7 +2254,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 267) {
+ if (!USER_VERSION_ATLEAST(267, 0)) {
/* Freestyle color settings */
bTheme *btheme;
@@ -2238,7 +2313,7 @@ void init_userdef_do_versions(void)
U.tweak_threshold = 10;
}
- if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 1)) {
+ if (!USER_VERSION_ATLEAST(265, 1)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2254,7 +2329,7 @@ void init_userdef_do_versions(void)
}
/* panel header/backdrop supported locally per editor now */
- if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(265, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2271,7 +2346,10 @@ void init_userdef_do_versions(void)
}
/* NOTE!! from now on use U.versionfile and U.subversionfile */
- if (U.versionfile < 266) {
+#undef USER_VERSION_ATLEAST
+#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST((&(U)), ver, subver)
+
+ if (!USER_VERSION_ATLEAST(266, 0)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
@@ -2283,23 +2361,23 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 265 || (U.versionfile == 265 && U.subversionfile < 4)) {
+ if (!USER_VERSION_ATLEAST(265, 4)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */
+ rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
}
}
- if (U.versionfile < 265 || (U.versionfile == 265 && U.subversionfile < 6)) {
+ if (!USER_VERSION_ATLEAST(265, 6)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
copy_v4_v4_char(btheme->tv3d.gradients.high_gradient, btheme->tv3d.back);
}
}
- if (U.versionfile < 265 || (U.versionfile == 265 && U.subversionfile < 9)) {
+ if (!USER_VERSION_ATLEAST(265, 9)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_test_set(btheme->tnode.syntaxs, 151, 116, 116, 255); /* matte nodes */
@@ -2307,23 +2385,21 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 265 || (U.versionfile == 265 && U.subversionfile < 11)) {
+ if (!USER_VERSION_ATLEAST(265, 11)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_test_set(btheme->tconsole.console_select, 255, 255, 255, 48);
}
}
- if (U.versionfile < 266 || (U.versionfile == 266 && U.subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(266, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_test_set(btheme->tnode.console_output, 223, 202, 53, 255); /* interface nodes */
}
}
- /* NOTE!! from now on use U.versionfile and U.subversionfile */
-
- if (U.versionfile < 268 || (U.versionfile == 268 && U.subversionfile < 3)) {
+ if (!USER_VERSION_ATLEAST(268, 3)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255);
@@ -2331,7 +2407,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 269 || (U.versionfile == 269 && U.subversionfile < 5)) {
+ if (!USER_VERSION_ATLEAST(269, 5)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->tima.wire_edit, 192, 192, 192, 255);
@@ -2339,7 +2415,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 269 || (U.versionfile == 269 && U.subversionfile < 6)) {
+ if (!USER_VERSION_ATLEAST(269, 6)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
char r, g, b;
@@ -2360,7 +2436,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 269 || (U.versionfile == 269 && U.subversionfile < 8)) {
+ if (!USER_VERSION_ATLEAST(269, 8)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_test_set(btheme->tinfo.info_selected, 96, 128, 255, 255);
@@ -2376,7 +2452,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 269 || (U.versionfile == 269 && U.subversionfile < 9)) {
+ if (!USER_VERSION_ATLEAST(269, 9)) {
bTheme *btheme;
U.tw_size = U.tw_size * 5.0f;
@@ -2416,7 +2492,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 269 || (U.versionfile == 269 && U.subversionfile < 10)) {
+ if (!USER_VERSION_ATLEAST(269, 10)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
ThemeSpace *ts;
@@ -2430,24 +2506,25 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 271) {
+ if (!USER_VERSION_ATLEAST(271, 0)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
}
}
- if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) {
+ if (!USER_VERSION_ATLEAST(272, 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255);
}
}
- if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 5)) {
+ if (!USER_VERSION_ATLEAST(271, 5)) {
bTheme *btheme;
struct uiWidgetColors wcol_pie_menu = {
@@ -2477,7 +2554,7 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 6)) {
+ if (!USER_VERSION_ATLEAST(271, 6)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
/* check for (alpha == 0) is safe, then color was never set */
@@ -2487,12 +2564,100 @@ void init_userdef_do_versions(void)
}
}
+ if (!USER_VERSION_ATLEAST(272, 3)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(273, 1)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* Grease Pencil vertex settings */
+ rgba_char_args_set(btheme->tv3d.gp_vertex, 0, 0, 0, 255);
+ rgba_char_args_set(btheme->tv3d.gp_vertex_select, 255, 133, 0, 255);
+ btheme->tv3d.gp_vertex_size = 3;
+
+ rgba_char_args_set(btheme->tseq.gp_vertex, 0, 0, 0, 255);
+ rgba_char_args_set(btheme->tseq.gp_vertex_select, 255, 133, 0, 255);
+ btheme->tseq.gp_vertex_size = 3;
+
+ rgba_char_args_set(btheme->tima.gp_vertex, 0, 0, 0, 255);
+ rgba_char_args_set(btheme->tima.gp_vertex_select, 255, 133, 0, 255);
+ btheme->tima.gp_vertex_size = 3;
+
+ rgba_char_args_set(btheme->tnode.gp_vertex, 0, 0, 0, 255);
+ rgba_char_args_set(btheme->tnode.gp_vertex_select, 255, 133, 0, 255);
+ btheme->tnode.gp_vertex_size = 3;
+
+ /* Timeline Keyframe Indicators */
+ rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
+ rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(273, 5)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ unsigned char *cp = (unsigned char *)btheme->tv3d.clipping_border_3d;
+ int c;
+ copy_v4_v4_char((char *)cp, btheme->tv3d.back);
+ c = cp[0] - 8;
+ CLAMP(c, 0, 255);
+ cp[0] = c;
+ c = cp[1] - 8;
+ CLAMP(c, 0, 255);
+ cp[1] = c;
+ c = cp[2] - 8;
+ CLAMP(c, 0, 255);
+ cp[2] = c;
+ cp[3] = 255;
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(274, 5)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ copy_v4_v4_char(btheme->tima.metadatatext, btheme->tima.text_hi);
+ copy_v4_v4_char(btheme->tseq.metadatatext, btheme->tseq.text_hi);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(275, 1)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ copy_v4_v4_char(btheme->tclip.metadatatext, btheme->tseq.text_hi);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(275, 2)) {
+ U.ndof_deadzone = 0.1;
+ }
+
+ if (!USER_VERSION_ATLEAST(275, 4)) {
+ U.node_margin = 80;
+ }
+
+ if (!USER_VERSION_ATLEAST(276, 1)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set_fl(btheme->tima.preview_back, 0.0f, 0.0f, 0.0f, 0.3f);
+ }
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
if (U.image_draw_method == 0)
U.image_draw_method = IMAGE_DRAW_METHOD_2DTEXTURE;
+ // keep the following until the new audaspace is default to be built with
+#ifdef WITH_SYSTEM_AUDASPACE
+ // we default to the first audio device
+ U.audiodevice = 0;
+#endif
+
/* funny name, but it is GE stuff, moves userdef stuff to engine */
// XXX space_set_commmandline_options();
/* this timer uses U */
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index d48faa34618..5f0c3ff6993 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -99,11 +99,12 @@ BLI_INLINE void clamp_rctf_to_rcti(rcti *dst, const rctf *src)
/* XXX still unresolved: scrolls hide/unhide vs region mask handling */
/* XXX there's V2D_SCROLL_HORIZONTAL_HIDE and V2D_SCROLL_HORIZONTAL_FULLR ... */
-/* helper to allow scrollbars to dynamically hide
- * - returns a copy of the scrollbar settings with the flags to display
- * horizontal/vertical scrollbars removed
- * - input scroll value is the v2d->scroll var
- * - hide flags are set per region at drawtime
+/**
+ * helper to allow scrollbars to dynamically hide
+ * - returns a copy of the scrollbar settings with the flags to display
+ * horizontal/vertical scrollbars removed
+ * - input scroll value is the v2d->scroll var
+ * - hide flags are set per region at drawtime
*/
static int view2d_scroll_mapped(int scroll)
{
@@ -197,16 +198,17 @@ static void view2d_masks(View2D *v2d, int check_scrollers)
/* Refresh and Validation */
-/* Initialize all relevant View2D data (including view rects if first time) and/or refresh mask sizes after view resize
- * - for some of these presets, it is expected that the region will have defined some
- * additional settings necessary for the customization of the 2D viewport to its requirements
- * - this function should only be called from region init() callbacks, where it is expected that
- * this is called before UI_view2d_size_update(), as this one checks that the rects are properly initialized.
+/**
+ * Initialize all relevant View2D data (including view rects if first time) and/or refresh mask sizes after view resize
+ * - for some of these presets, it is expected that the region will have defined some
+ * additional settings necessary for the customization of the 2D viewport to its requirements
+ * - this function should only be called from region init() callbacks, where it is expected that
+ * this is called before UI_view2d_size_update(), as this one checks that the rects are properly initialized.
*/
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
{
bool tot_changed = false, do_init;
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
do_init = (v2d->flag & V2D_IS_INITIALISED) == 0;
@@ -320,7 +322,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
if (do_init) {
float panelzoom = (style) ? style->panelzoom : 1.0f;
- float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f;
+ float scrolw = (v2d->scroll & V2D_SCROLL_RIGHT) ? V2D_SCROLL_WIDTH : 0.0f;
v2d->tot.xmin = 0.0f;
v2d->tot.xmax = winx - scrolw;
@@ -361,8 +363,9 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
-/* Ensure View2D rects remain in a viable configuration
- * - cur is not allowed to be: larger than max, smaller than min, or outside of tot
+/**
+ * Ensure View2D rects remain in a viable configuration
+ * 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers)
@@ -371,7 +374,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
float winx, winy;
rctf *cur, *tot;
- /* use mask as size of region that View2D resides in, as it takes into account scrollbars already */
+ /* use mask as size of region that View2D resides in, as it takes into account
+ * scrollbars already - keep in sync with zoomx/zoomy in view_zoomstep_apply_ex! */
winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1);
winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1);
@@ -393,6 +397,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
*/
totwidth = BLI_rctf_size_x(tot);
totheight = BLI_rctf_size_y(tot);
+ /* keep in sync with zoomx/zoomy in view_zoomstep_apply_ex! */
curwidth = width = BLI_rctf_size_x(cur);
curheight = height = BLI_rctf_size_y(cur);
@@ -840,7 +845,8 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
-/* Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot)
+/**
+ * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot)
* This does not take into account if zooming the view on an axis will improve the view (if allowed)
*/
void UI_view2d_curRect_reset(View2D *v2d)
@@ -1096,10 +1102,12 @@ void UI_view2d_view_ortho(View2D *v2d)
glLoadIdentity();
}
-/* Set view matrices to only use one axis of 'cur' only
- * - xaxis = if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x)
+/**
+ * Set view matrices to only use one axis of 'cur' only
+ *
+ * \param xaxis: if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x)
*/
-void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, short xaxis)
+void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis)
{
rctf curmasked;
float xofs, yofs;
@@ -1190,20 +1198,23 @@ static void step_to_grid(float *step, int *power, int unit)
}
}
-/* Initialize settings necessary for drawing gridlines in a 2d-view
- * - Currently, will return pointer to View2DGrid struct that needs to
- * be freed with UI_view2d_grid_free()
- * - Is used for scrollbar drawing too (for units drawing)
- * - Units + clamping args will be checked, to make sure they are valid values that can be used
- * so it is very possible that we won't return grid at all!
- *
- * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames
- * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals
- * - winx = width of region we're drawing to, note: not used but keeping for completeness.
- * - winy = height of region we're drawing into
+/**
+ * Initialize settings necessary for drawing gridlines in a 2d-view
+ *
+ * - Currently, will return pointer to View2DGrid struct that needs to
+ * be freed with UI_view2d_grid_free()
+ * - Is used for scrollbar drawing too (for units drawing)
+ * - Units + clamping args will be checked, to make sure they are valid values that can be used
+ * so it is very possible that we won't return grid at all!
+ *
+ * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames
+ * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals
+ * - winx = width of region we're drawing to, note: not used but keeping for completeness.
+ * - winy = height of region we're drawing into
*/
-View2DGrid *UI_view2d_grid_calc(Scene *scene, View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp, int UNUSED(winx), int winy)
+View2DGrid *UI_view2d_grid_calc(
+ Scene *scene, View2D *v2d,
+ short xunits, short xclamp, short yunits, short yclamp, int UNUSED(winx), int winy)
{
View2DGrid *grid;
@@ -1481,9 +1492,11 @@ void UI_view2d_grid_free(View2DGrid *grid)
/* *********************************************************************** */
/* Scrollers */
-/* View2DScrollers is typedef'd in UI_view2d.h
- * WARNING: the start of this struct must not change, as view2d_ops.c uses this too.
- * For now, we don't need to have a separate (internal) header for structs like this...
+/**
+ * View2DScrollers is typedef'd in UI_view2d.h
+ *
+ * \warning The start of this struct must not change, as view2d_ops.c uses this too.
+ * For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
/* focus bubbles */
@@ -1500,8 +1513,9 @@ struct View2DScrollers {
};
/* Calculate relevant scroller properties */
-View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp)
+View2DScrollers *UI_view2d_scrollers_calc(
+ const bContext *C, View2D *v2d,
+ short xunits, short xclamp, short yunits, short yclamp)
{
View2DScrollers *scrollers;
rcti vert, hor;
@@ -1649,7 +1663,7 @@ static void scroll_printstr(Scene *scene, float x, float y, float val, int power
BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), power, val, FPS, U.timecode_style);
}
else {
- BLI_timecode_string_from_time_simple(timecode_str, sizeof(timecode_str), power, val);
+ BLI_timecode_string_from_time_seconds(timecode_str, sizeof(timecode_str), power, val);
}
/* get length of string, and adjust printing location to fit it into the horizontal scrollbar */
@@ -1719,7 +1733,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax);
}
- uiWidgetScrollDraw(&wcol, &hor, &slider, state);
+ UI_draw_widget_scroll(&wcol, &hor, &slider, state);
/* scale indicators */
if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) {
@@ -1820,7 +1834,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax);
}
- uiWidgetScrollDraw(&wcol, &vert, &slider, state);
+ UI_draw_widget_scroll(&wcol, &vert, &slider, state);
/* scale indiators */
@@ -1851,7 +1865,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
/* draw vertical steps */
if (dfac > 0.0f) {
- BLF_rotation_default(M_PI / 2);
+ BLF_rotation_default(M_PI_2);
BLF_enable_default(BLF_ROTATION);
for (; fac < vert.ymax - 10; fac += dfac, val += grid->dy) {
@@ -1883,18 +1897,22 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers)
/* *********************************************************************** */
/* List View Utilities */
-/* Get the view-coordinates of the nominated cell
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates (in 'tot' rect space) that the list starts from
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * - column, row = the 2d-coordinates (in 2D-view / 'tot' rect space) the cell exists at
- * - rect = coordinates of the cell (passed as single var instead of 4 separate, as it's more useful this way)
+/** Get the view-coordinates of the nominated cell
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param column, row: The 2d-coordinates
+ * (in 2D-view / 'tot' rect space) the cell exists at
+ * \param rect: coordinates of the cell
+ * (passed as single var instead of 4 separate, as it's more useful this way)
*/
-void UI_view2d_listview_cell_to_view(View2D *v2d, float columnwidth, float rowheight,
- float startx, float starty,
- int column, int row, rctf *rect)
+void UI_view2d_listview_cell_to_view(
+ View2D *v2d, float columnwidth, float rowheight,
+ float startx, float starty,
+ int column, int row, rctf *rect)
{
/* sanity checks */
if (ELEM(NULL, v2d, rect)) {
@@ -1928,17 +1946,20 @@ void UI_view2d_listview_cell_to_view(View2D *v2d, float columnwidth, float rowhe
}
}
-/* Get the 'cell' (row, column) that the given 2D-view coordinates (i.e. in 'tot' rect space) lie in.
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates (in 'tot' rect space) that the list starts from
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * - viewx, viewy = 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
- * - column, row = the 'coordinates' of the relevant 'cell'
+/**
+ * Get the 'cell' (row, column) that the given 2D-view coordinates (i.e. in 'tot' rect space) lie in.
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
+ * \param column, row: the 'coordinates' of the relevant 'cell'
*/
-void UI_view2d_listview_view_to_cell(View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
- float viewx, float viewy, int *column, int *row)
+void UI_view2d_listview_view_to_cell(
+ View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
+ float viewx, float viewy, int *column, int *row)
{
/* adjust view coordinates to be all positive ints, corrected for the start offset */
const int x = (int)(floorf(fabsf(viewx) + 0.5f) - startx);
@@ -1965,13 +1986,16 @@ void UI_view2d_listview_view_to_cell(View2D *v2d, float columnwidth, float rowhe
*row = 0;
}
-/* Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates that the list starts from, which should be (0,0) for most views
- * - column/row_min/max = the starting and ending column/row indices
+/**
+ * Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect
+ *
+ * \param columnwidth, rowheight: Size of each 'cell'
+ * \param startx, starty: Coordinates that the list starts from, which should be (0,0) for most views
+ * \param column_min, column_max, row_min, row_max: The starting and ending column/row indices
*/
-void UI_view2d_listview_visible_cells(View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
- int *column_min, int *column_max, int *row_min, int *row_max)
+void UI_view2d_listview_visible_cells(
+ View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
+ int *column_min, int *column_max, int *row_min, int *row_max)
{
/* using 'cur' rect coordinates, call the cell-getting function to get the cells for this */
if (v2d) {
@@ -1997,10 +2021,11 @@ float UI_view2d_region_to_view_y(struct View2D *v2d, float y)
return (v2d->cur.ymin + (BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
-/* Convert from screen/region space to 2d-View space
- *
- * - x,y = coordinates to convert
- * - viewx,viewy = resultant coordinates
+/**
+ * Convert from screen/region space to 2d-View space
+ *
+ * \param x, y: coordinates to convert
+ * \param r_view_x, r_view_y: resultant coordinates
*/
void UI_view2d_region_to_view(View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
@@ -2028,11 +2053,12 @@ float UI_view2d_view_to_region_y(View2D *v2d, float y)
return (v2d->mask.ymin + (((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
-/* Convert from 2d-View space to screen/region space
- * - Coordinates are clamped to lie within bounds of region
+/**
+ * Convert from 2d-View space to screen/region space
+ * \note Coordinates are clamped to lie within bounds of region
*
- * - x,y = coordinates to convert
- * - regionx,regiony = resultant coordinates
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
*/
bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -2055,11 +2081,13 @@ bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_
}
}
-/* Convert from 2d-view space to screen/region space
- * - Coordinates are NOT clamped to lie within bounds of region
+/**
+ * Convert from 2d-view space to screen/region space
+ *
+ * \note Coordinates are NOT clamped to lie within bounds of region.
*
- * - x,y = coordinates to convert
- * - regionx,regiony = resultant coordinates
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
*/
void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -2173,25 +2201,30 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
}
-/* Calculate the scale per-axis of the drawing-area
- * - Is used to inverse correct drawing of icons, etc. that need to follow view
- * but not be affected by scale
+/**
+ * Calculate the scale per-axis of the drawing-area
*
- * - x,y = scale on each axis
+ * Is used to inverse correct drawing of icons, etc. that need to follow view
+ * but not be affected by scale
+ *
+ * \param x, y: scale on each axis
*/
void UI_view2d_scale_get(View2D *v2d, float *x, float *y)
{
if (x) *x = BLI_rcti_size_x(&v2d->mask) / BLI_rctf_size_x(&v2d->cur);
if (y) *y = BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
-/* Same as UI_view2d_scale_get() - 1.0f / x, y */
+/**
+ * Same as ``UI_view2d_scale_get() - 1.0f / x, y``
+ */
void UI_view2d_scale_get_inverse(View2D *v2d, float *x, float *y)
{
if (x) *x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
if (y) *y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
}
-/* Simple functions for consistent center offset access.
+/**
+ * Simple functions for consistent center offset access.
* Used by node editor to shift view center for each individual node tree.
*/
void UI_view2d_center_get(struct View2D *v2d, float *x, float *y)
@@ -2237,13 +2270,15 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
UI_view2d_curRect_validate(v2d);
}
-/* Check if mouse is within scrollers
- * - Returns appropriate code for match
- * 'h' = in horizontal scroller
- * 'v' = in vertical scroller
- * 0 = not in scroller
- *
- * - x,y = mouse coordinates in screen (not region) space
+/**
+ * Check if mouse is within scrollers
+ *
+ * \param x, y: Mouse coordinates in screen (not region) space.
+ *
+ * \return appropriate code for match.
+ * - 'h' = in horizontal scroller.
+ * - 'v' = in vertical scroller.
+ * - 0 = not in scroller.
*/
short UI_view2d_mouse_in_scrollers(const bContext *C, View2D *v2d, int x, int y)
{
@@ -2286,8 +2321,9 @@ typedef struct View2DString {
static MemArena *g_v2d_strings_arena = NULL;
static View2DString *g_v2d_strings = NULL;
-void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
- const char *str, size_t str_len, const char col[4])
+void UI_view2d_text_cache_add(
+ View2D *v2d, float x, float y,
+ const char *str, size_t str_len, const char col[4])
{
int mval[2];
@@ -2305,7 +2341,7 @@ void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
BLI_LINKS_PREPEND(g_v2d_strings, v2s);
- v2s->col.pack = *((int *)col);
+ v2s->col.pack = *((const int *)col);
memset(&v2s->rect, 0, sizeof(v2s->rect));
@@ -2317,8 +2353,9 @@ void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
}
/* no clip (yet) */
-void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view,
- const char *str, size_t str_len, const char col[4])
+void UI_view2d_text_cache_add_rectf(
+ View2D *v2d, const rctf *rect_view,
+ const char *str, size_t str_len, const char col[4])
{
rcti rect;
@@ -2336,7 +2373,7 @@ void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view,
BLI_LINKS_PREPEND(g_v2d_strings, v2s);
- v2s->col.pack = *((int *)col);
+ v2s->col.pack = *((const int *)col);
v2s->rect = rect;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 2b84c0678ae..07275d6be2a 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -63,12 +63,13 @@ static int view2d_poll(bContext *C)
/* ********************************************************* */
/* VIEW PANNING OPERATOR */
-/* This group of operators come in several forms:
- * 1) Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
- * 2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
+/**
+ * This group of operators come in several forms:
+ * -# Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
+ * -# Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - define how much to move view by (relative to zoom-correction factor)
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
*/
/* ------------------ Shared 'core' stuff ---------------------- */
@@ -275,8 +276,8 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
view_pan_apply(C, op);
break;
}
- /* XXX - Mode switching isn't implemented. See comments in 36818.
- * switch to zoom */
+ /* XXX - Mode switching isn't implemented. See comments in 36818.
+ * switch to zoom */
#if 0
case LEFTMOUSE:
if (event->val == KM_PRESS) {
@@ -328,7 +329,7 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
ot->cancel = view_pan_cancel;
/* operator is modal */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna - must keep these in sync with the other operators */
RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
@@ -525,15 +526,18 @@ static void VIEW2D_OT_scroll_up(wmOperatorType *ot)
/* ********************************************************* */
/* SINGLE-STEP VIEW ZOOMING OPERATOR */
-/* This group of operators come in several forms:
- * 1) Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount
- * 2) Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y) // XXX this could be implemented...
- * 3) Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount
+/**
+ * This group of operators come in several forms:
+ * -# Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount.
+ * -# Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y).
+ * XXX this could be implemented...
+ * -# Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount.
*
* In order to make sure this works, each operator must define the following RNA-Operator Props:
- * zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling.
- * It is safe to scale by 0, as these factors are used to determine
- * amount to enlarge 'cur' by
+ *
+ * - zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling.
+ * It is safe to scale by 0, as these factors are used to determine.
+ * amount to enlarge 'cur' by.
*/
/* ------------------ 'Shared' stuff ------------------------ */
@@ -620,11 +624,13 @@ static int view_zoom_poll(bContext *C)
}
/* apply transform to view (i.e. adjust 'cur' rect) */
-static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool use_mousepos,
- const float facx, const float facy)
+static void view_zoomstep_apply_ex(
+ bContext *C, v2dViewZoomData *vzd, const bool use_mousepos,
+ const float facx, const float facy)
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
+ const rctf cur_old = v2d->cur;
float dx, dy;
/* calculate amount to move view by, ensuring symmetry so the
@@ -651,17 +657,25 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
v2d->cur.xmax -= 2 * dx;
}
else {
+
+ v2d->cur.xmin += dx;
+ v2d->cur.xmax -= dx;
+
if (use_mousepos && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
- float mval_fac = (vzd->mx_2d - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
- float mval_faci = 1.0f - mval_fac;
- float ofs = (mval_fac * dx) - (mval_faci * dx);
-
- v2d->cur.xmin += ofs + dx;
- v2d->cur.xmax += ofs - dx;
- }
- else {
- v2d->cur.xmin += dx;
- v2d->cur.xmax -= dx;
+ /* get zoom fac the same way as in ui_view2d_curRect_validate_resize - better keep in sync! */
+ const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
+
+ /* only move view to mouse if zoom fac is inside minzoom/maxzoom */
+ if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
+ IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom))
+ {
+ float mval_fac = (vzd->mx_2d - cur_old.xmin) / BLI_rctf_size_x(&cur_old);
+ float mval_faci = 1.0f - mval_fac;
+ float ofs = (mval_fac * dx) - (mval_faci * dx);
+
+ v2d->cur.xmin += ofs;
+ v2d->cur.xmax += ofs;
+ }
}
}
}
@@ -676,17 +690,25 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
v2d->cur.ymax -= 2 * dy;
}
else {
+
+ v2d->cur.ymin += dy;
+ v2d->cur.ymax -= dy;
+
if (use_mousepos && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
- float mval_fac = (vzd->my_2d - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur);
- float mval_faci = 1.0f - mval_fac;
- float ofs = (mval_fac * dy) - (mval_faci * dy);
-
- v2d->cur.ymin += ofs + dy;
- v2d->cur.ymax += ofs - dy;
- }
- else {
- v2d->cur.ymin += dy;
- v2d->cur.ymax -= dy;
+ /* get zoom fac the same way as in ui_view2d_curRect_validate_resize - better keep in sync! */
+ const float zoomy = (float)(BLI_rcti_size_y(&v2d->mask) + 1) / BLI_rctf_size_y(&v2d->cur);
+
+ /* only move view to mouse if zoom fac is inside minzoom/maxzoom */
+ if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
+ IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom))
+ {
+ float mval_fac = (vzd->my_2d - cur_old.ymin) / BLI_rctf_size_y(&cur_old);
+ float mval_faci = 1.0f - mval_fac;
+ float ofs = (mval_fac * dy) - (mval_faci * dy);
+
+ v2d->cur.ymin += ofs;
+ v2d->cur.ymax += ofs;
+ }
}
}
}
@@ -854,10 +876,11 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
/* ********************************************************* */
/* DRAG-ZOOM OPERATOR */
-/* MMB Drag - allows non-uniform scaling by dragging mouse
+/**
+ * MMB Drag - allows non-uniform scaling by dragging mouse
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - amounts to add to each side of the 'cur' rect
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - amounts to add to each side of the 'cur' rect
*/
/* apply transform to view (i.e. adjust 'cur' rect) */
@@ -1162,7 +1185,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* operator is repeatable */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna - must keep these in sync with the other operators */
prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
@@ -1174,10 +1197,12 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
/* ********************************************************* */
/* BORDER-ZOOM */
-/* The user defines a rect using standard borderselect tools, and we use this rect to
+/**
+ * The user defines a rect using standard borderselect tools, and we use this rect to
* define the new zoom-level of the view in the following ways:
- * 1) LEFTMOUSE - zoom in to view
- * 2) RIGHTMOUSE - zoom out of view
+ *
+ * -# LEFTMOUSE - zoom in to view
+ * -# RIGHTMOUSE - zoom out of view
*
* Currently, these key mappings are hardcoded, but it shouldn't be too important to
* have custom keymappings for this...
@@ -1389,8 +1414,9 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
/* will start timer if appropriate */
/* the arguments are the desired situation */
-void UI_view2d_smooth_view(bContext *C, ARegion *ar,
- const rctf *cur, const int smooth_viewtx)
+void UI_view2d_smooth_view(
+ bContext *C, ARegion *ar,
+ const rctf *cur, const int smooth_viewtx)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -1515,13 +1541,14 @@ static void VIEW2D_OT_smoothview(wmOperatorType *ot)
/* ********************************************************* */
/* SCROLLERS */
-/* Scrollers should behave in the following ways, when clicked on with LMB (and dragged):
- * 1) 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable,
- * enlarge 'cur' rect on the relevant side
- * 2) 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite)
+/**
+ * Scrollers should behave in the following ways, when clicked on with LMB (and dragged):
+ * -# 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable,
+ * enlarge 'cur' rect on the relevant side.
+ * -# 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite).
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - define how much to move view by (relative to zoom-correction factor)
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
*/
/* customdata for scroller-invoke data */
@@ -1543,10 +1570,12 @@ typedef struct v2dScrollerMove {
} v2dScrollerMove;
-/* View2DScrollers is typedef'd in UI_view2d.h
+/**
+ * #View2DScrollers is typedef'd in UI_view2d.h
* This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c, as we only need focus bubble info
- * WARNING: the start of this struct must not change, so that it stays in sync with the 'real' version
- * For now, we don't need to have a separate (internal) header for structs like this...
+ *
+ * \warning: The start of this struct must not change, so that it stays in sync with the 'real' version
+ * For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
/* focus bubbles */
@@ -1565,10 +1594,12 @@ enum {
/* ------------------------ */
-/* check if mouse is within scroller handle
- * - mouse = relevant mouse coordinate in region space
- * - sc_min, sc_max = extents of scroller 'groove' (potential available space for scroller)
- * - sh_min, sh_max = positions of scrollbar handles
+/**
+ * Check if mouse is within scroller handle.
+ *
+ * \param mouse: relevant mouse coordinate in region space.
+ * \param sc_min, sc_max: extents of scroller 'groove' (potential available space for scroller).
+ * \param sh_min, sh_max: positions of scrollbar handles.
*/
static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
{
@@ -1772,7 +1803,10 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
-/* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */
+/**
+ * Handle user input for scrollers - calculations of mouse-movement need to be done here,
+ * not in the apply callback!
+ */
static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dScrollerMove *vsm = op->customdata;
@@ -1951,7 +1985,7 @@ static void VIEW2D_OT_scroller_activate(wmOperatorType *ot)
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
{
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
int winx, winy;
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index f331dea5c5c..828cb494eab 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -20,9 +20,9 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../makesdna
../../makesrna
diff --git a/source/blender/editors/io/SConscript b/source/blender/editors/io/SConscript
index 0facb24e2c3..2b1a638b891 100644
--- a/source/blender/editors/io/SConscript
+++ b/source/blender/editors/io/SConscript
@@ -33,9 +33,9 @@ defs = []
incs = [
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../collada',
'../../makesrna',
'../../windowmanager',
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index a4130540b1b..021b040fdd5 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -30,7 +30,7 @@
#ifdef WITH_COLLADA
#include "DNA_scene_types.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -96,7 +96,9 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_object_instantiation;
int sort_by_name;
int export_transformation_type;
- int open_sim;
+ int open_sim;
+
+ int export_count;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -148,33 +150,36 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
ED_object_editmode_load(CTX_data_edit_object(C));
-
- if (collada_export(CTX_data_scene(C),
- filepath,
- apply_modifiers,
- export_mesh_type,
- selected,
- include_children,
- include_armatures,
- include_shapekeys,
- deform_bones_only,
-
- active_uv_only,
- include_uv_textures,
- include_material_textures,
- use_texture_copies,
-
- triangulate,
- use_object_instantiation,
- sort_by_name,
- export_transformation_type,
- open_sim))
- {
- return OPERATOR_FINISHED;
+ export_count = collada_export(CTX_data_scene(C),
+ filepath,
+ apply_modifiers,
+ export_mesh_type,
+ selected,
+ include_children,
+ include_armatures,
+ include_shapekeys,
+ deform_bones_only,
+
+ active_uv_only,
+ include_uv_textures,
+ include_material_textures,
+ use_texture_copies,
+
+ triangulate,
+ use_object_instantiation,
+ sort_by_name,
+ export_transformation_type,
+ open_sim);
+
+ if (export_count == 0) {
+ BKE_report(op->reports, RPT_WARNING, "Export file is empty");
+ return OPERATOR_CANCELLED;
}
else {
- BKE_report(op->reports, RPT_WARNING, "Export file not created");
- return OPERATOR_CANCELLED;
+ char buff[100];
+ sprintf(buff, "Exported %d Objects", export_count);
+ BKE_report(op->reports, RPT_INFO, buff);
+ return OPERATOR_FINISHED;
}
}
@@ -293,8 +298,8 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->ui = wm_collada_export_draw;
- WM_operator_properties_filesel(ot, FOLDERFILE | COLLADAFILE, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna,
"apply_modifiers", 0, "Apply Modifiers",
@@ -322,11 +327,11 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Only export deforming bones with armatures");
- RNA_def_boolean(ot->srna, "active_uv_only", 0, "Only Active UV layer",
- "Export textures assigned to the object UV maps");
+ RNA_def_boolean(ot->srna, "active_uv_only", 0, "Only Selected UV Map",
+ "Export only the selected UV Map");
RNA_def_boolean(ot->srna, "include_uv_textures", 0, "Include UV Textures",
- "Export textures assigned to the object UV maps");
+ "Export textures assigned to the object UV Maps");
RNA_def_boolean(ot->srna, "include_material_textures", 0, "Include Material Textures",
"Export textures assigned to the object Materials");
@@ -350,8 +355,8 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
"Transform", "Transformation type for translation, scale and rotation");
- RNA_def_boolean(ot->srna, "open_sim", 0, "Export for OpenSim",
- "Compatibility mode for OpenSim and compatible online worlds");
+ RNA_def_boolean(ot->srna, "open_sim", 0, "Export to SL/OpenSim",
+ "Compatibility mode for SL, OpenSim and other compatible online worlds");
}
@@ -360,6 +365,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
{
char filename[FILE_MAX];
int import_units;
+ int find_chains;
+ int fix_orientation;
+ int min_chain_length;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -367,10 +375,19 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
}
/* Options panel */
- import_units = RNA_boolean_get(op->ptr, "import_units");
+ import_units = RNA_boolean_get(op->ptr, "import_units");
+ find_chains = RNA_boolean_get(op->ptr, "find_chains");
+ fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
+ min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
RNA_string_get(op->ptr, "filepath", filename);
- if (collada_import(C, filename, import_units)) {
+ if (collada_import(
+ C, filename,
+ import_units,
+ find_chains,
+ fix_orientation,
+ min_chain_length))
+ {
return OPERATOR_FINISHED;
}
else {
@@ -390,6 +407,19 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "import_units", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Armature Options:"), ICON_MESH_DATA);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "fix_orientation", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "find_chains", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
}
static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op)
@@ -414,13 +444,31 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->ui = wm_collada_import_draw;
- WM_operator_properties_filesel(ot, FOLDERFILE | COLLADAFILE, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna,
+ "import_units", 0, "Import Units",
+ "If disabled match import to Blender's current Unit settings, "
+ "otherwise use the settings from the Imported scene");
+
+ RNA_def_boolean(ot->srna,
+ "fix_orientation", 0, "Fix Leaf Bones",
+ "Fix Orientation of Leaf Bones (Collada does only support Joints)");
RNA_def_boolean(ot->srna,
- "import_units", 0, "Import Units",
- "If disabled match import to Blender's current Unit settings, "
- "otherwise use the settings from the Imported scene");
+ "find_chains", 0, "Find Bone Chains",
+ "Find best matching Bone Chains and ensure bones in chain are connected");
+
+ RNA_def_int(ot->srna,
+ "min_chain_length",
+ 0,
+ 0,
+ INT_MAX,
+ "Minimum Chain Length",
+ "When searching Bone Chains disregard chains of length below this value",
+ 0,
+ INT_MAX);
}
#endif
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index a33340cc39a..a70a51a60be 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -28,16 +28,13 @@
* \ingroup collada
*/
-
-#include "io_collada.h"
-
-#include "BLI_utildefines.h"
-
-#include "WM_types.h"
-#include "WM_api.h"
-
#include "io_ops.h" /* own include */
+#ifdef WITH_COLLADA
+# include "io_collada.h"
+# include "WM_api.h"
+#endif
+
void ED_operatortypes_io(void)
{
#ifdef WITH_COLLADA
diff --git a/source/blender/editors/mask/CMakeLists.txt b/source/blender/editors/mask/CMakeLists.txt
index b1cf6db3144..033d034cf4e 100644
--- a/source/blender/editors/mask/CMakeLists.txt
+++ b/source/blender/editors/mask/CMakeLists.txt
@@ -25,10 +25,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -48,4 +50,6 @@ set(SRC
mask_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_mask "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/mask/SConscript b/source/blender/editors/mask/SConscript
index 9dd521e3a7c..c4e6daaf5df 100644
--- a/source/blender/editors/mask/SConscript
+++ b/source/blender/editors/mask/SConscript
@@ -30,13 +30,16 @@ Import ('env')
sources = env.Glob('*.c')
defs = []
+defs += env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index b816103de13..822bb429f9e 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -57,12 +57,14 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
struct Mask *mask,
const float normal_co[2],
int threshold, bool feather,
+ float tangent[2],
+ const bool use_deform,
+ const bool use_project,
MaskLayer **masklay_r,
MaskSpline **spline_r,
MaskSplinePoint **point_r,
- float *u_r, float tangent[2],
- const bool use_deform,
- const bool use_project)
+ float *u_r,
+ float *score_r)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -70,9 +72,9 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
MaskLayer *masklay, *point_masklay;
MaskSpline *point_spline;
MaskSplinePoint *point = NULL;
- float dist = FLT_MAX, co[2];
+ float dist_best_sq = FLT_MAX, co[2];
int width, height;
- float u;
+ float u = 0.0f;
float scalex, scaley;
ED_mask_get_size(sa, &width, &height);
@@ -121,7 +123,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
for (j = 0; j < tot_point - 1; j++) {
- float cur_dist, a[2], b[2];
+ float dist_sq, a[2], b[2];
a[0] = points[2 * j] * scalex;
a[1] = points[2 * j + 1] * scaley;
@@ -129,16 +131,16 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
b[0] = points[2 * j + 2] * scalex;
b[1] = points[2 * j + 3] * scaley;
- cur_dist = dist_to_line_segment_v2(co, a, b);
+ dist_sq = dist_squared_to_line_segment_v2(co, a, b);
- if (cur_dist < dist) {
+ if (dist_sq < dist_best_sq) {
if (tangent)
sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
point_masklay = masklay;
point_spline = spline;
point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
- dist = cur_dist;
+ dist_best_sq = dist_sq;
u = (float)j / tot_point;
}
}
@@ -152,7 +154,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
}
- if (point && dist < threshold) {
+ if (point && dist_best_sq < threshold) {
if (masklay_r)
*masklay_r = point_masklay;
@@ -171,6 +173,10 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
*u_r = u;
}
+ if (score_r) {
+ *score_r = dist_best_sq;
+ }
+
return true;
}
@@ -339,7 +345,9 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
float tangent[2];
float u;
- if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, &masklay, &spline, &point, &u, tangent, true, true)) {
+ if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, tangent, true, true,
+ &masklay, &spline, &point, &u, NULL))
+ {
MaskSplinePoint *new_point;
int point_index = point - spline->points;
@@ -624,7 +632,9 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
if (point)
return OPERATOR_FINISHED;
- if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, true, &masklay, &spline, &point, &u, NULL, true, true)) {
+ if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, true, NULL, true, true,
+ &masklay, &spline, &point, &u, NULL))
+ {
Scene *scene = CTX_data_scene(C);
float w = BKE_mask_point_weight(spline, point, u);
float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 7e767d8f6c8..2efa9e211c9 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -253,7 +253,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
return;
if (sc)
- undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
+ undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
/* TODO, add this to sequence editor */
handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
@@ -422,7 +422,7 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
float (*points)[2] = orig_points;
if (sc) {
- int undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+ const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
if (undistort) {
int i;
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index e2eb32e86d9..e1a58d529b6 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_mask.h"
+#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "WM_api.h"
@@ -397,6 +398,58 @@ void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
}
}
+bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
+{
+ Mask *mask = CTX_data_edit_mask(C);
+ MaskLayer *mask_layer;
+ bool ok = false;
+ INIT_MINMAX2(min, max);
+ for (mask_layer = mask->masklayers.first;
+ mask_layer != NULL;
+ mask_layer = mask_layer->next)
+ {
+ MaskSpline *spline;
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+ for (spline = mask_layer->splines.first;
+ spline != NULL;
+ spline = spline->next)
+ {
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+ int i;
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+ MaskSplinePoint *deform_point = &points_array[i];
+ BezTriple *bezt = &point->bezt;
+ float handle[2];
+ if (!MASKPOINT_ISSEL_ANY(point)) {
+ continue;
+ }
+ if (bezt->f2 & SELECT) {
+ minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]);
+ }
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle);
+ minmax_v2v2_v2(min, max, handle);
+ }
+ else {
+ if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) {
+ BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle);
+ minmax_v2v2_v2(min, max, handle);
+ }
+ if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) {
+ BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle);
+ minmax_v2v2_v2(min, max, handle);
+ }
+ }
+ ok = true;
+ }
+ }
+ }
+ return ok;
+}
+
/********************** registration *********************/
void ED_operatortypes_mask(void)
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 6899cf7e6f5..66a6c75272e 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -34,7 +34,6 @@
struct bContext;
struct Mask;
-struct wmEvent;
struct wmOperatorType;
/* internal exports only */
@@ -44,12 +43,14 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
int threshold, bool feather,
+ float tangent[2],
+ const bool use_deform,
+ const bool use_project,
struct MaskLayer **masklay_r,
struct MaskSpline **spline_r,
struct MaskSplinePoint **point_r,
- float *u_r, float tangent[2],
- const bool use_deform,
- const bool use_project);
+ float *u_r,
+ float *score_r);
void MASK_OT_add_vertex(struct wmOperatorType *ot);
void MASK_OT_add_feather_vertex(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 2497095aca6..bf8630ff843 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -510,12 +510,13 @@ static bool spline_under_mouse_get(const bContext *C,
MaskLayer **mask_layer_r,
MaskSpline **mask_spline_r)
{
+ const float threshold = 19.0f;
ScrArea *sa = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MaskLayer *mask_layer;
int width, height;
float pixel_co[2];
- float closest_dist_squared;
+ float closest_dist_squared = 0.0f;
MaskLayer *closest_layer = NULL;
MaskSpline *closest_spline = NULL;
bool undistort = false;
@@ -580,7 +581,18 @@ static bool spline_under_mouse_get(const bContext *C,
}
}
}
- if (closest_spline != NULL) {
+ if (closest_dist_squared < SQUARE(threshold) && closest_spline != NULL) {
+ float diff_score;
+ if (ED_mask_find_nearest_diff_point(C, mask, co, threshold,
+ false, NULL, true, false,
+ NULL, NULL, NULL, NULL,
+ &diff_score))
+ {
+ if (SQUARE(diff_score) < closest_dist_squared) {
+ return false;
+ }
+ }
+
*mask_layer_r = closest_layer;
*mask_spline_r = closest_spline;
return true;
@@ -772,7 +784,7 @@ static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SlidePointData *slidedata;
if (mask == NULL) {
- return OPERATOR_CANCELLED;
+ return OPERATOR_PASS_THROUGH;
}
slidedata = slide_point_customdata(C, op, event);
@@ -1164,7 +1176,7 @@ static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
{
Mask *mask = CTX_data_edit_mask(C);
float co[2];
- const float threshold = 19;
+ const float threshold = 19.0f;
ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
@@ -1182,7 +1194,7 @@ static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
static SlideSplineCurvatureData *slide_spline_curvature_customdata(
bContext *C, const wmEvent *event)
{
- const float threshold = 19;
+ const float threshold = 19.0f;
Mask *mask = CTX_data_edit_mask(C);
SlideSplineCurvatureData *slide_data;
@@ -1195,8 +1207,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(
ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
if (!ED_mask_find_nearest_diff_point(C, mask, co, threshold, false,
+ NULL, true, false,
&mask_layer, &spline, &point, &u,
- NULL, true, false))
+ NULL))
{
return NULL;
}
@@ -1273,7 +1286,7 @@ static int slide_spline_curvature_invoke(bContext *C, wmOperator *op, const wmEv
SlideSplineCurvatureData *slide_data;
if (mask == NULL) {
- return OPERATOR_CANCELLED;
+ return OPERATOR_PASS_THROUGH;
}
/* Be sure we don't conflict with point slide here. */
@@ -2196,7 +2209,7 @@ static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
}
if (end >= start) {
int tot_point;
- int tot_point_shape_start;
+ int tot_point_shape_start = 0;
MaskSpline *new_spline = BKE_mask_spline_add(mask_layer);
MaskSplinePoint *new_point;
int b;
@@ -2294,6 +2307,10 @@ static int copy_splines_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *mask_layer = BKE_mask_layer_active(mask);
+ if (mask_layer == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
BKE_mask_clipboard_copy_from_layer(mask_layer);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index e02561d839c..4e0aa8f84ae 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -39,7 +39,6 @@
#include "BKE_tracking.h"
#include "DNA_mask_types.h"
-#include "DNA_object_types.h" /* SELECT */
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 0cb2dd1eb68..0280f662a26 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -21,9 +21,9 @@
set(INC
../include
../uvedit
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../gpu
../../imbuf
@@ -32,6 +32,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -86,4 +87,6 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_mesh "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index 6fa48c12eca..df58b2a90b3 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -30,15 +30,17 @@ Import ('env')
sources = env.Glob('*.c')
defs = []
+defs += env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../uvedit',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../imbuf',
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 87b429f1165..0017cd3c2ae 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -31,8 +31,6 @@
#include "BLI_math.h"
#include "BLI_bitmap.h"
-#include "BLF_translation.h"
-
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -64,9 +62,8 @@ void paintface_flush_flags(Object *ob)
Mesh *me = BKE_mesh_from_object(ob);
DerivedMesh *dm = ob->derivedFinal;
MPoly *polys, *mp_orig;
- MFace *faces;
const int *index_array = NULL;
- int totface, totpoly;
+ int totpoly;
int i;
if (me == NULL)
@@ -81,26 +78,7 @@ void paintface_flush_flags(Object *ob)
if (dm == NULL)
return;
- /*
- * Try to push updated mesh poly flags to three other data sets:
- * - Mesh polys => Mesh tess faces
- * - Mesh polys => Final derived polys
- * - Final derived polys => Final derived tessfaces
- */
-
- if ((index_array = CustomData_get_layer(&me->fdata, CD_ORIGINDEX))) {
- faces = me->mface;
- totface = me->totface;
-
- /* loop over tessfaces */
- for (i = 0; i < totface; i++) {
- if (index_array[i] != ORIGINDEX_NONE) {
- /* Copy flags onto the original tessface from its original poly */
- mp_orig = me->mpoly + index_array[i];
- faces[i].flag = mp_orig->flag;
- }
- }
- }
+ /* Mesh polys => Final derived polys */
if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) {
polys = dm->getPolyArray(dm);
@@ -115,21 +93,6 @@ void paintface_flush_flags(Object *ob)
}
}
}
-
- if ((index_array = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))) {
- polys = dm->getPolyArray(dm);
- faces = dm->getTessFaceArray(dm);
- totface = dm->getNumTessFaces(dm);
-
- /* loop over tessfaces */
- for (i = 0; i < totface; i++) {
- if (index_array[i] != ORIGINDEX_NONE) {
- /* Copy flags onto the final tessface from its final poly */
- mp_orig = polys + index_array[i];
- faces[i].flag = mp_orig->flag;
- }
- }
- }
}
void paintface_hide(Object *ob, const bool unselected)
@@ -428,13 +391,15 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
unsigned int *rt;
char *selar;
int a, index;
- int sx = BLI_rcti_size_x(rect) + 1;
- int sy = BLI_rcti_size_y(rect) + 1;
+ const int size[2] = {
+ BLI_rcti_size_x(rect) + 1,
+ BLI_rcti_size_y(rect) + 1};
me = BKE_mesh_from_object(ob);
- if (me == NULL || me->totpoly == 0 || sx * sy <= 0)
+ if ((me == NULL) || (me->totpoly == 0) || (size[0] * size[1] <= 0)) {
return OPERATOR_CANCELLED;
+ }
selar = MEM_callocN(me->totpoly + 1, "selar");
@@ -448,18 +413,23 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
}
}
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
- ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
+ ibuf = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
rt = ibuf->rect;
- view3d_opengl_read_pixels(vc->ar, rect->xmin, rect->ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+ view3d_opengl_read_pixels(vc->ar, rect->xmin, rect->ymin, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ if (ENDIAN_ORDER == B_ENDIAN) {
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+ WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
- a = sx * sy;
+ a = size[0] * size[1];
while (a--) {
if (*rt) {
- index = WM_framebuffer_to_index(*rt);
- if (index <= me->totpoly) selar[index] = 1;
+ index = *rt;
+ if (index <= me->totpoly) {
+ selar[index] = 1;
+ }
}
rt++;
}
@@ -627,7 +597,7 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */
/* note, this is not the best place for the function to be but moved
- * here to for the purpose of syncing with bmesh */
+ * here for the purpose of syncing with bmesh */
typedef unsigned int MirrTopoHash_t;
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index b288a02a3d1..e073a255f73 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -32,8 +32,9 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_library.h"
@@ -51,6 +52,10 @@
#include "mesh_intern.h" /* own include */
+
+#define MESH_ADD_VERTS_MAXI 10000000
+
+
/* ********* add primitive operators ************* */
static Object *make_prim_init(bContext *C, const char *idname,
@@ -61,17 +66,14 @@ static Object *make_prim_init(bContext *C, const char *idname,
*was_editmode = false;
if (obedit == NULL || obedit->type != OB_MESH) {
- obedit = ED_object_add_type(C, OB_MESH, loc, rot, false, layer);
-
- rename_id((ID *)obedit, idname);
- rename_id((ID *)obedit->data, idname);
+ obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer);
/* create editmode */
ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
*was_editmode = true;
}
- *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false);
+ *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
return obedit;
}
@@ -106,7 +108,7 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -151,7 +153,7 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -207,7 +209,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -239,7 +241,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
+ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
ED_object_add_unit_props(ot);
RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
@@ -260,7 +262,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -297,9 +299,9 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
+ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
ED_object_add_unit_props(ot);
- prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
@@ -320,7 +322,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -354,12 +356,12 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
- prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00);
+ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
+ prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, FLT_MAX, "Radius 2", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
@@ -377,7 +379,7 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -410,8 +412,10 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "x_subdivisions", 10, 2, INT_MAX, "X Subdivisions", "", 2, 1000);
- RNA_def_int(ot->srna, "y_subdivisions", 10, 2, INT_MAX, "Y Subdivisions", "", 2, 1000);
+ /* Note that if you use MESH_ADD_VERTS_MAXI for both x and y at the same time you will still reach
+ * impossible values (10^12 vertices or so...). */
+ RNA_def_int(ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000);
+ RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, true);
@@ -421,7 +425,9 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
{
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float mat[4][4];
+ float loc[3], rot[3];
+ float dia;
bool enter_editmode;
unsigned int layer;
bool was_editmode;
@@ -429,11 +435,9 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer);
dia = RNA_float_get(op->ptr, "radius");
- mat[0][0] *= dia;
- mat[1][1] *= dia;
- mat[2][2] *= dia;
+ mul_mat3_m4_fl(mat, dia);
em = BKE_editmesh_from_object(obedit);
@@ -478,7 +482,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -512,9 +516,9 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "segments", 32, 3, INT_MAX, "Segments", "", 3, 500);
- RNA_def_int(ot->srna, "ring_count", 16, 3, INT_MAX, "Rings", "", 3, 500);
- prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
+ RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500);
+ RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500);
+ prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
ED_object_add_generic_props(ot, true);
@@ -531,7 +535,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
if (!EDBM_op_call_and_selectf(
@@ -565,8 +569,8 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "subdivisions", 2, 1, INT_MAX, "Subdivisions", "", 1, 8);
- prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
+ RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8);
+ prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
ED_object_add_generic_props(ot, true);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 48d5113a279..ce6856321d2 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -31,7 +31,7 @@
#include "BLI_string.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -75,7 +75,8 @@ typedef struct {
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
- const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Offset: %s, Segments: %d");
+ const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
+ "Vertex Only: %s (V), Offset: %s, Segments: %d");
char msg[HEADER_LENGTH];
ScrArea *sa = CTX_wm_area(C);
@@ -96,7 +97,10 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str);
- BLI_snprintf(msg, HEADER_LENGTH, str, type_str, offset_str, RNA_int_get(op->ptr, "segments"));
+ BLI_snprintf(msg, HEADER_LENGTH, str, type_str,
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
+ offset_str, RNA_int_get(op->ptr, "segments"));
ED_area_headerprint(sa, msg);
}
@@ -150,7 +154,9 @@ static bool edbm_bevel_calc(wmOperator *op)
const int segments = RNA_int_get(op->ptr, "segments");
const float profile = RNA_float_get(op->ptr, "profile");
const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
+ const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
int material = RNA_int_get(op->ptr, "material");
+ const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide");
/* revert to original mesh */
if (opdata->is_modal) {
@@ -161,8 +167,9 @@ static bool edbm_bevel_calc(wmOperator *op)
material = CLAMPIS(material, -1, em->ob->totcol - 1);
EDBM_op_init(em, &bmop, op,
- "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f material=%i",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, material);
+ "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
+ "material=%i loop_slide=%b",
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material, loop_slide);
BMO_op_exec(em->bm, &bmop);
@@ -408,6 +415,31 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case CKEY:
+ if (event->val == KM_RELEASE)
+ break;
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "clamp_overlap");
+ RNA_property_enum_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
+ }
+ edbm_bevel_calc(op);
+ edbm_bevel_update_header(C, op);
+ handled = true;
+ break;
+ case VKEY:
+ if (event->val == KM_RELEASE)
+ break;
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "vertex_only");
+ RNA_property_enum_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
+ }
+ edbm_bevel_calc(op);
+ edbm_bevel_update_header(C, op);
+ handled = true;
+ break;
+
}
/* Modal numinput inactive, try to handle numeric inputs last... */
@@ -460,13 +492,16 @@ void MESH_OT_bevel(wmOperatorType *ot)
ot->poll = ED_operator_editmesh;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
- prop = RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "", 0.0f, 1.0f);
+ prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
- RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices");
+ RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
+ RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
+ "Do not allow beveled edges/vertices to overlap each other");
+ RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
}
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 6a54f1979cf..08d0697e0f1 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -33,7 +33,7 @@
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_global.h"
#include "BKE_context.h"
@@ -264,7 +264,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
invert_m4_m4(imat, obedit->obmat);
mul_m4_v3(imat, plane_co);
- mul_mat3_m4_v3(imat, plane_no);
+ mul_transposed_mat3_m4_v3(obedit->obmat, plane_no);
EDBM_op_init(em, &bmop, op,
"bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
@@ -335,11 +335,11 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -FLT_MAX, FLT_MAX,
- "Plane Point", "A point on the plane", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -1e12f, 1e12f,
+ "Plane Point", "A point on the plane", -1e4f, 1e4f);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -FLT_MAX, FLT_MAX,
- "Plane Normal", "The direction the plane points", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -1.0f, 1.0f,
+ "Plane Normal", "The direction the plane points", -1.0f, 1.0f);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut");
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 3e403387a67..a020fed0835 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -54,18 +54,6 @@
#include "mesh_intern.h" /* own include */
-/* allow accumulated normals to form a new direction but don't
- * accept direct opposite directions else they will cancel each other out */
-static void add_normal_aligned(float nor[3], const float add[3])
-{
- if (dot_v3v3(nor, add) < -0.9999f) {
- sub_v3_v3(nor, add);
- }
- else {
- add_v3_v3(nor, add);
- }
-}
-
static void edbm_extrude_edge_exclude_mirror(
Object *obedit, BMEditMesh *em,
const char hflag,
@@ -137,7 +125,7 @@ static void edbm_extrude_edge_exclude_mirror(
/* individual face extrude */
/* will use vertex normals for extrusion directions, so *nor is unaffected */
-static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
+static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag)
{
BMOIter siter;
BMIter liter;
@@ -165,14 +153,14 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c
}
if (!EDBM_op_finish(em, &bmop, op, true)) {
- return 0;
+ return false;
}
- return 's'; /* s is shrink/fatten */
+ return true;
}
/* extrudes individual edges */
-static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
+static bool edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag)
{
BMesh *bm = em->bm;
BMOperator bmop;
@@ -191,14 +179,14 @@ static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
if (!EDBM_op_finish(em, &bmop, op, true)) {
- return 0;
+ return false;
}
- return 'n'; /* n is normal grab */
+ return true;
}
/* extrudes individual vertices */
-static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
+static bool edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag)
{
BMOperator bmop;
@@ -214,27 +202,55 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
if (!EDBM_op_finish(em, &bmop, op, true)) {
- return 0;
+ return false;
}
- return 'g'; /* g is grab */
+ return true;
}
-static short edbm_extrude_edge_ex(
+static char edbm_extrude_htype_from_em_select(BMEditMesh *em)
+{
+ char htype = BM_ALL_NOLOOP;
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ /* pass */
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ htype &= ~BM_VERT;
+ }
+ else {
+ htype &= ~(BM_VERT | BM_EDGE);
+ }
+
+ if (em->bm->totedgesel == 0) {
+ htype &= ~(BM_EDGE | BM_FACE);
+ }
+ else if (em->bm->totfacesel == 0) {
+ htype &= ~BM_FACE;
+ }
+
+ return htype;
+}
+
+static bool edbm_extrude_ex(
Object *obedit, BMEditMesh *em,
- const char hflag, float nor[3],
+ char htype, const char hflag,
const bool use_mirror,
const bool use_select_history)
{
BMesh *bm = em->bm;
BMOIter siter;
BMOperator extop;
- BMFace *f;
BMElem *ele;
+ /* needed to remove the faces left behind */
+ if (htype & BM_FACE) {
+ htype |= BM_EDGE;
+ }
+
BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history);
- BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE, hflag);
+ BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag);
if (use_mirror) {
BMOpSlot *slot_edges_exclude;
@@ -248,61 +264,14 @@ static short edbm_extrude_edge_ex(
BM_SELECT_HISTORY_RESTORE(bm);
BMO_op_exec(bm, &extop);
-
- zero_v3(nor);
- BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL) {
+ BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) {
BM_elem_select_set(bm, ele, true);
-
- if (ele->head.htype == BM_FACE) {
- f = (BMFace *)ele;
- add_normal_aligned(nor, f->no);
- }
}
- normalize_v3(nor);
-
BMO_op_finish(bm, &extop);
- /* grab / normal constraint */
- return is_zero_v3(nor) ? 'g' : 'n';
-}
-
-static short edbm_extrude_edge(
- Object *obedit, BMEditMesh *em,
- const char hflag, float nor[3])
-{
- return edbm_extrude_edge_ex(obedit, em, hflag, nor, true, true);
-}
-
-static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
-{
- BMIter iter;
- BMEdge *eed;
-
- /* ensure vert flags are consistent for edge selections */
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, hflag)) {
- if (hflag & BM_ELEM_SELECT) {
- BM_vert_select_set(em->bm, eed->v1, true);
- BM_vert_select_set(em->bm, eed->v2, true);
- }
-
- BM_elem_flag_enable(eed->v1, hflag & ~BM_ELEM_SELECT);
- BM_elem_flag_enable(eed->v2, hflag & ~BM_ELEM_SELECT);
- }
- else {
- if (BM_elem_flag_test(eed->v1, hflag) && BM_elem_flag_test(eed->v2, hflag)) {
- if (hflag & BM_ELEM_SELECT) {
- BM_edge_select_set(em->bm, eed, true);
- }
-
- BM_elem_flag_enable(eed, hflag & ~BM_ELEM_SELECT);
- }
- }
- }
-
- return edbm_extrude_edge(obedit, em, hflag, nor);
+ return true;
}
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
@@ -314,7 +283,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
const int steps = RNA_int_get(op->ptr, "steps");
const float offs = RNA_float_get(op->ptr, "offset");
- float dvec[3], tmat[3][3], bmat[3][3], nor[3] = {0.0, 0.0, 0.0};
+ float dvec[3], tmat[3][3], bmat[3][3];
short a;
/* dvec */
@@ -327,7 +296,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
mul_m3_v3(tmat, dvec);
for (a = 0; a < steps; a++) {
- edbm_extrude_edge_ex(obedit, em, BM_ELEM_SELECT, nor, false, false);
+ edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false);
BMO_op_callf(
em->bm, BMO_FLAG_DEFAULTS,
@@ -357,92 +326,63 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, FLT_MAX, "Offset", "", 0.0f, 100.0f);
- RNA_def_int(ot->srna, "steps", 10, 0, INT_MAX, "Steps", "", 0, 180);
+ RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
+ RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
}
/* generic extern called extruder */
-static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
+static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
{
- short nr, transmode = 0;
- float stacknor[3] = {0.0f, 0.0f, 0.0f};
- float *nor = norin ? norin : stacknor;
-
- zero_v3(nor);
+ bool changed = false;
+ const char htype = edbm_extrude_htype_from_em_select(em);
+ enum {NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY} nr;
if (em->selectmode & SCE_SELECT_VERTEX) {
- if (em->bm->totvertsel == 0) nr = 0;
- else if (em->bm->totvertsel == 1) nr = 4;
- else if (em->bm->totedgesel == 0) nr = 4;
- else if (em->bm->totfacesel == 0)
- nr = 3;
- else if (em->bm->totfacesel == 1)
- nr = 1;
- else
- nr = 1;
+ if (em->bm->totvertsel == 0) nr = NONE;
+ else if (em->bm->totvertsel == 1) nr = VERT_ONLY;
+ else if (em->bm->totedgesel == 0) nr = VERT_ONLY;
+ else nr = ELEM_FLAG;
}
else if (em->selectmode & SCE_SELECT_EDGE) {
- if (em->bm->totedgesel == 0) nr = 0;
-
- nr = 1;
+ if (em->bm->totedgesel == 0) nr = NONE;
+ else if (em->bm->totfacesel == 0) nr = EDGE_ONLY;
+ else nr = ELEM_FLAG;
}
else {
- if (em->bm->totfacesel == 0) nr = 0;
- else if (em->bm->totfacesel == 1) nr = 1;
- else
- nr = 1;
+ if (em->bm->totfacesel == 0) nr = NONE;
+ else nr = ELEM_FLAG;
}
- if (nr < 1) return 'g';
-
- if (nr == 1 && (em->selectmode & SCE_SELECT_VERTEX))
- transmode = edbm_extrude_vert(obedit, em, BM_ELEM_SELECT, nor);
- else if (nr == 1) transmode = edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor);
- else if (nr == 4) transmode = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor);
- else if (nr == 3) transmode = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor);
- else transmode = edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT, nor);
+ switch (nr) {
+ case NONE:
+ return false;
+ case ELEM_FLAG:
+ changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, true, true);
+ break;
+ case VERT_ONLY:
+ changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
+ break;
+ case EDGE_ONLY:
+ changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
+ break;
+ }
- if (transmode == 0) {
- BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
+ if (changed) {
+ return true;
}
else {
-
- /* We need to force immediate calculation here because
- * transform may use derived objects (which are now stale).
- *
- * This shouldn't be necessary, derived queries should be
- * automatically building this data if invalid. Or something.
- */
-// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- BKE_object_handle_update(G.main->eval_ctx, scene, obedit);
-
- /* individual faces? */
- if (nr == 2) {
-// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
-// Transform();
- }
- else {
-// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
- if (transmode == 'n') {
- mul_m4_v3(obedit->obmat, nor);
- sub_v3_v3v3(nor, nor, obedit->obmat[3]);
-// BIF_setSingleAxisConstraint(nor, "along normal");
- }
-// Transform();
- }
+ BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
+ return false;
}
-
- return transmode;
}
/* extrude without transform */
static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- edbm_extrude_mesh(scene, obedit, em, op, NULL);
+ edbm_extrude_mesh(obedit, em, op);
/* This normally happens when pushing undo but modal operators
* like this one don't push undo data until after modal mode is
@@ -476,9 +416,8 @@ static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- float nor[3];
- edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor);
+ edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
EDBM_update_generic(em, true, true);
@@ -507,9 +446,8 @@ static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- float nor[3];
- edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor);
+ edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
EDBM_update_generic(em, true, true);
@@ -538,9 +476,8 @@ static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- float nor[3];
- edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT, nor);
+ edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
EDBM_update_generic(em, true, true);
@@ -573,12 +510,11 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
float min[3], max[3];
bool done = false;
bool use_proj;
-
+
em_setup_viewcontext(C, &vc);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
-
use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
@@ -593,6 +529,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
/* call extrude? */
if (done) {
+ const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em);
const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
BMEdge *eed;
float vec[3], cent[3], mat[3][3];
@@ -637,8 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
/* correct the normal to be aligned on the view plane */
- copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(vc.obedit->imat, view_vec);
+ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]);
cross_v3_v3v3(cross, nor, view_vec);
cross_v3_v3v3(nor, view_vec, cross);
normalize_v3(nor);
@@ -686,7 +622,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
EMBM_project_snap_verts(C, vc.ar, vc.em);
}
- edbm_extrude_edge(vc.obedit, vc.em, BM_ELEM_SELECT, nor);
+ edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, true, true);
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
BM_ELEM_SELECT, cent, mat);
EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v",
@@ -742,7 +678,7 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
+ RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape");
}
@@ -765,6 +701,11 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
angle = -angle;
dupli = RNA_boolean_get(op->ptr, "dupli");
+ if (is_zero_v3(axis)) {
+ BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
+ return OPERATOR_CANCELLED;
+ }
+
/* keep the values in worldspace since we're passing the obmat */
if (!EDBM_op_init(em, &spinop, op,
"spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 use_duplicate=%b",
@@ -809,19 +750,21 @@ void MESH_OT_spin(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_spin_invoke;
ot->exec = edbm_spin_exec;
- ot->poll = EDBM_view3d_poll;
+ ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, INT_MAX);
+ RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
- prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -FLT_MAX, FLT_MAX, "Angle", "Angle", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+ prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -1e12f, 1e12f, "Angle", "Rotation for each step",
+ DEG2RADF(-360.0f), DEG2RADF(360.0f));
RNA_def_property_subtype(prop, PROP_ANGLE);
- RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX, "Axis", "Axis in global view space", -1.0f, 1.0f);
+ RNA_def_float_vector(ot->srna, "center", 3, NULL, -1e12f, 1e12f,
+ "Center", "Center in global view space", -1e4f, 1e4f);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
@@ -844,6 +787,11 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "center", cent);
RNA_float_get_array(op->ptr, "axis", axis);
+ if (is_zero_v3(axis)) {
+ BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
+ return OPERATOR_CANCELLED;
+ }
+
/* find two vertices with valence count == 1, more or less is wrong */
v1 = NULL;
v2 = NULL;
@@ -927,17 +875,17 @@ void MESH_OT_screw(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_screw_invoke;
ot->exec = edbm_screw_exec;
- ot->poll = EDBM_view3d_poll;
+ ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "steps", 9, 1, INT_MAX, "Steps", "Steps", 3, 256);
- RNA_def_int(ot->srna, "turns", 1, 1, INT_MAX, "Turns", "Turns", 1, 256);
+ RNA_def_int(ot->srna, "steps", 9, 1, 100000, "Steps", "Steps", 3, 256);
+ RNA_def_int(ot->srna, "turns", 1, 1, 100000, "Turns", "Turns", 1, 256);
- RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX,
- "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX,
+ RNA_def_float_vector(ot->srna, "center", 3, NULL, -1e12f, 1e12f,
+ "Center", "Center in global view space", -1e4f, 1e4f);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f,
"Axis", "Axis in global view space", -1.0f, 1.0f);
}
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index a90a002f29a..c037b0c6b0f 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -31,7 +31,7 @@
#include "BLI_string.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -499,7 +499,7 @@ void MESH_OT_inset(wmOperatorType *ot)
ot->poll = ED_operator_editmesh;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
@@ -507,14 +507,14 @@ void MESH_OT_inset(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, FLT_MAX, "Thickness", "", 0.0f, 10.0f);
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- prop = RNA_def_float(ot->srna, "depth", 0.0f, -FLT_MAX, FLT_MAX, "Depth", "", -10.0f, 10.0f);
+ prop = RNA_def_float(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f);
RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4);
RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset");
- RNA_def_boolean(ot->srna, "use_select_inset", true, "Select Outer", "Select the new inset faces");
+ RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces");
RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual Face Inset");
RNA_def_boolean(ot->srna, "use_interpolate", true, "Interpolate", "Blend face data across the inset");
}
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index df6776950d7..e2e4638254b 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -38,7 +38,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "WM_api.h"
#include "WM_types.h"
#include "ED_mesh.h"
@@ -334,7 +333,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BMVert *v_other = BM_edge_other_vert(e, v);
float e_dir[3];
- /* we wan't closest to zero */
+ /* we want closest to zero */
float dot_best = FLT_MAX;
sub_v3_v3v3(e_dir, v_other->co, v->co);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 76c41adf444..dbbf49a527b 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -46,7 +46,7 @@
#include "BLI_smallhash.h"
#include "BLI_memarena.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
@@ -66,6 +66,8 @@
#include "WM_types.h"
#include "DNA_object_types.h"
+
+#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
@@ -75,10 +77,16 @@
#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */
+/* WARNING: knife float precision is fragile:
+ * be careful before making changes here see: (T43229, T42864, T42459, T41164).
+ */
#define KNIFE_FLT_EPS 0.00001f
#define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS)
#define KNIFE_FLT_EPSBIG 0.0005f
-#define KNIFE_FLT_EPS_PX 0.2f
+
+#define KNIFE_FLT_EPS_PX_VERT 0.5f
+#define KNIFE_FLT_EPS_PX_EDGE 0.05f
+#define KNIFE_FLT_EPS_PX_FACE 0.05f
typedef struct KnifeColors {
unsigned char line[3];
@@ -97,7 +105,7 @@ typedef struct KnifeVert {
float co[3], cageco[3], sco[2]; /* sco is screen coordinates for cageco */
bool is_face, in_space;
- bool draw;
+ bool is_cut; /* along a cut created by user input (will draw too) */
} KnifeVert;
typedef struct Ref {
@@ -111,7 +119,7 @@ typedef struct KnifeEdge {
ListBase faces;
BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */
- bool draw;
+ bool is_cut; /* along a cut created by user input (will draw too) */
} KnifeEdge;
typedef struct KnifeLineHit {
@@ -152,6 +160,7 @@ typedef struct KnifeTool_OpData {
float mval[2]; /* mouse value with snapping applied */
//bContext *C;
+ Scene *scene;
Object *ob;
BMEditMesh *em;
@@ -174,8 +183,10 @@ typedef struct KnifeTool_OpData {
KnifeLineHit *linehits;
int totlinehit;
- /* Data for mouse-position-derived data (cur) and previous click (prev) */
- KnifePosData curr, prev;
+ /* Data for mouse-position-derived data */
+ KnifePosData curr; /* current point under the cursor */
+ KnifePosData prev; /* last added cut (a line draws from the cursor to this) */
+ KnifePosData init; /* the first point in the cut-list, used for closing the loop */
int totkedge, totkvert;
@@ -198,6 +209,8 @@ typedef struct KnifeTool_OpData {
bool is_ortho;
float ortho_extent;
+ float ortho_extent_center[3];
+
float clipsta, clipend;
enum {
@@ -206,6 +219,7 @@ typedef struct KnifeTool_OpData {
MODE_CONNECT,
MODE_PANNING
} mode;
+ bool is_drag_hold;
int prevmode;
bool snap_midpoints;
@@ -226,6 +240,22 @@ typedef struct KnifeTool_OpData {
const float (*cagecos)[3];
} KnifeTool_OpData;
+enum {
+ KNF_MODAL_CANCEL = 1,
+ KNF_MODAL_CONFIRM,
+ KNF_MODAL_MIDPOINT_ON,
+ KNF_MODAL_MIDPOINT_OFF,
+ KNF_MODAL_NEW_CUT,
+ KNF_MODEL_IGNORE_SNAP_ON,
+ KNF_MODEL_IGNORE_SNAP_OFF,
+ KNF_MODAL_ADD_CUT,
+ KNF_MODAL_ANGLE_SNAP_TOGGLE,
+ KNF_MODAL_CUT_THROUGH_TOGGLE,
+ KNF_MODAL_PANNING,
+ KNF_MODAL_ADD_CUT_CLOSED,
+};
+
+
static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f);
static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs,
@@ -233,20 +263,35 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2],
static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f);
-static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
+static void knifetool_free_bmbvh(KnifeTool_OpData *kcd);
+
+static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *kcd)
{
-#define HEADER_LENGTH 256
- char header[HEADER_LENGTH];
+ char header[UI_MAX_DRAW_STR];
+ char buf[UI_MAX_DRAW_STR];
+
+ char *p = buf;
+ int available_len = sizeof(buf);
+
+#define WM_MODALKEY(_id) \
+ WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
+
+ BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, "
+ "%s: start/define cut, %s: close cut, %s: new cut, "
+ "%s: midpoint snap (%s), %s: ignore snap (%s), "
+ "%s: angle constraint (%s), %s: cut through (%s), "
+ "%s: panning"),
+ WM_MODALKEY(KNF_MODAL_CONFIRM), WM_MODALKEY(KNF_MODAL_CANCEL),
+ WM_MODALKEY(KNF_MODAL_ADD_CUT), WM_MODALKEY(KNF_MODAL_ADD_CUT_CLOSED), WM_MODALKEY(KNF_MODAL_NEW_CUT),
+ WM_MODALKEY(KNF_MODAL_MIDPOINT_ON), WM_bool_as_string(kcd->snap_midpoints),
+ WM_MODALKEY(KNF_MODEL_IGNORE_SNAP_ON), WM_bool_as_string(kcd->ignore_edge_snapping),
+ WM_MODALKEY(KNF_MODAL_ANGLE_SNAP_TOGGLE), WM_bool_as_string(kcd->angle_snapping),
+ WM_MODALKEY(KNF_MODAL_CUT_THROUGH_TOGGLE), WM_bool_as_string(kcd->cut_through),
+ WM_MODALKEY(KNF_MODAL_PANNING));
+
+#undef WM_MODALKEY
- BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB: define cut lines, Return/Spacebar: confirm, Esc or RMB: cancel, "
- "E: new cut, Ctrl: midpoint snap (%s), Shift: ignore snap (%s), "
- "C: angle constrain (%s), Z: cut through (%s)"),
- WM_bool_as_string(kcd->snap_midpoints),
- WM_bool_as_string(kcd->ignore_edge_snapping),
- WM_bool_as_string(kcd->angle_snapping),
- WM_bool_as_string(kcd->cut_through));
ED_area_headerprint(CTX_wm_area(C), header);
-#undef HEADER_LENGTH
}
static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2])
@@ -526,7 +571,7 @@ static KnifeVert *knife_split_edge(
newkfe->v1 = kfe->v1;
newkfe->v2 = new_knife_vert(kcd, co, cageco);
- newkfe->v2->draw = 1;
+ newkfe->v2->is_cut = true;
if (kfe->e) {
knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e);
}
@@ -551,7 +596,7 @@ static KnifeVert *knife_split_edge(
knife_add_to_vert_edges(kcd, newkfe);
- newkfe->draw = kfe->draw;
+ newkfe->is_cut = kfe->is_cut;
newkfe->e = kfe->e;
*r_kfe = newkfe;
@@ -559,6 +604,16 @@ static KnifeVert *knife_split_edge(
return newkfe->v2;
}
+static void linehit_to_knifepos(KnifePosData *kpos, KnifeLineHit *lh)
+{
+ kpos->bmface = lh->f;
+ kpos->vert = lh->v;
+ kpos->edge = lh->kfe;
+ copy_v3_v3(kpos->cage, lh->cagehit);
+ copy_v3_v3(kpos->co, lh->hit);
+ copy_v2_v2(kpos->mval, lh->schit);
+}
+
/* primary key: lambda along cut
* secondary key: lambda along depth
* tertiary key: pointer comparisons of verts if both snapped to verts
@@ -590,6 +645,7 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd)
{
KnifeLineHit *linehits, *lhi, *lhj;
int i, j, n;
+ bool is_double = false;
n = kcd->totlinehit;
linehits = kcd->linehits;
@@ -613,7 +669,11 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd)
{
break;
}
- lhj->l = -1.0f;
+
+ if (lhi->kfe == lhj->kfe) {
+ lhj->l = -1.0f;
+ is_double = true;
+ }
}
for (j = i + 1; j < n; j++) {
lhj = &linehits[j];
@@ -622,37 +682,42 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd)
{
break;
}
- if (lhj->kfe || lhi->v == lhj->v) {
+ if ((lhj->kfe && (lhi->kfe == lhj->kfe)) ||
+ (lhi->v == lhj->v))
+ {
lhj->l = -1.0f;
+ is_double = true;
}
}
}
}
- /* delete-in-place loop: copying from pos j to pos i+1 */
- i = 0;
- j = 1;
- while (j < n) {
- lhi = &linehits[i];
- lhj = &linehits[j];
- if (lhj->l == -1.0f) {
- j++; /* skip copying this one */
- }
- else {
- /* copy unless a no-op */
- if (lhi->l == -1.0f) {
- /* could happen if linehits[0] is being deleted */
- memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit));
+ if (is_double) {
+ /* delete-in-place loop: copying from pos j to pos i+1 */
+ i = 0;
+ j = 1;
+ while (j < n) {
+ lhi = &linehits[i];
+ lhj = &linehits[j];
+ if (lhj->l == -1.0f) {
+ j++; /* skip copying this one */
}
else {
- if (i + 1 != j)
- memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit));
- i++;
+ /* copy unless a no-op */
+ if (lhi->l == -1.0f) {
+ /* could happen if linehits[0] is being deleted */
+ memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit));
+ }
+ else {
+ if (i + 1 != j)
+ memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit));
+ i++;
+ }
+ j++;
}
- j++;
}
+ kcd->totlinehit = i + 1;
}
- kcd->totlinehit = i + 1;
}
/* Add hit to list of hits in facehits[f], where facehits is a map, if not already there */
@@ -667,9 +732,38 @@ static void add_hit_to_facehits(KnifeTool_OpData *kcd, GHash *facehits, BMFace *
knife_append_list_no_dup(kcd, lst, hit);
}
+/**
+ * special purpose function, if the linehit is connected to a real edge/vert
+ * return true if \a co is outside the face.
+ */
+static bool knife_add_single_cut__is_linehit_outside_face(BMFace *f, const KnifeLineHit *lh, const float co[3])
+{
+
+ if (lh->v && lh->v->v) {
+ BMLoop *l; /* side-of-loop */
+ if ((l = BM_face_vert_share_loop(f, lh->v->v)) &&
+ (BM_loop_point_side_of_loop_test(l, co) < 0.0f))
+ {
+ return true;
+ }
+ }
+ else if ((lh->kfe && lh->kfe->e)) {
+ BMLoop *l; /* side-of-edge */
+ if ((l = BM_face_edge_share_loop(f, lh->kfe->e)) &&
+ (BM_loop_point_side_of_edge_test(l, co) < 0.0f))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, KnifeLineHit *lh2, BMFace *f)
{
KnifeEdge *kfe, *kfe2;
+ BMEdge *e_base;
if ((lh1->v && lh1->v == lh2->v) ||
(lh1->kfe && lh1->kfe == lh2->kfe))
@@ -677,6 +771,25 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
return;
}
+ /* if the cut is on an edge, just tag that its a cut and return */
+ if ((lh1->v && lh2->v) &&
+ (lh1->v->v && lh2->v && lh2->v->v) &&
+ (e_base = BM_edge_exists(lh1->v->v, lh2->v->v)))
+ {
+ kfe = get_bm_knife_edge(kcd, e_base);
+ kfe->is_cut = true;
+ kfe->e = e_base;
+ return;
+ }
+ else {
+ if (knife_add_single_cut__is_linehit_outside_face(f, lh1, lh2->hit) ||
+ knife_add_single_cut__is_linehit_outside_face(f, lh2, lh1->hit))
+ {
+ return;
+ }
+ }
+
+
/* Check if edge actually lies within face (might not, if this face is concave) */
if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) {
if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) {
@@ -685,7 +798,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
}
kfe = new_knife_edge(kcd);
- kfe->draw = true;
+ kfe->is_cut = true;
kfe->basef = f;
if (lh1->v) {
@@ -698,7 +811,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
else {
BLI_assert(lh1->f);
kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit);
- kfe->v1->draw = true;
+ kfe->v1->is_cut = true;
kfe->v1->is_face = true;
knife_append_list(kcd, &kfe->v1->faces, lh1->f);
lh1->v = kfe->v1; /* record the KnifeVert for this hit */
@@ -714,7 +827,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
else {
BLI_assert(lh2->f);
kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit);
- kfe->v2->draw = true;
+ kfe->v2->is_cut = true;
kfe->v2->is_face = true;
knife_append_list(kcd, &kfe->v2->faces, lh2->f);
lh2->v = kfe->v2; /* record the KnifeVert for this hit */
@@ -735,23 +848,13 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits)
{
Ref *r;
- KnifeLineHit *lh, *prevlh;
- int n;
- (void) kcd;
-
- n = BLI_countlist(hits);
- if (n < 2)
+ if (BLI_listbase_count_ex(hits, 2) != 2)
return;
- prevlh = NULL;
- for (r = hits->first; r; r = r->next) {
- lh = (KnifeLineHit *)r->ref;
- if (prevlh)
- knife_add_single_cut(kcd, prevlh, lh, f);
- prevlh = lh;
+ for (r = hits->first; r->next; r = r->next) {
+ knife_add_single_cut(kcd, r->ref, r->next->ref, f);
}
-
}
/* User has just left-clicked after the first time.
@@ -771,7 +874,9 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
prepare_linehits_for_cut(kcd);
if (kcd->totlinehit == 0) {
- kcd->prev = kcd->curr;
+ if (kcd->is_drag_hold == false) {
+ kcd->prev = kcd->curr;
+ }
return;
}
@@ -806,10 +911,19 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
/* set up for next cut */
kcd->prev = kcd->curr;
+
+
if (kcd->prev.bmface) {
+ KnifeLineHit *lh;
/* was "in face" but now we have a KnifeVert it is snapped to */
+ lh = &kcd->linehits[kcd->totlinehit - 1];
+ kcd->prev.vert = lh->v;
kcd->prev.bmface = NULL;
- kcd->prev.vert = kcd->linehits[kcd->totlinehit - 1].v;
+ }
+
+ if (kcd->is_drag_hold) {
+ lh = &kcd->linehits[kcd->totlinehit - 1];
+ linehit_to_knifepos(&kcd->prev, lh);
}
BLI_ghash_free(facehits, NULL, NULL);
@@ -1055,7 +1169,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
BLI_mempool_iternew(kcd->kedges, &iter);
for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
- if (!kfe->draw)
+ if (!kfe->is_cut)
continue;
glColor3ubv(kcd->colors.line);
@@ -1077,7 +1191,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glBegin(GL_POINTS);
BLI_mempool_iternew(kcd->kverts, &iter);
for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
- if (!kfv->draw)
+ if (!kfv->is_cut)
continue;
glColor3ubv(kcd->colors.point);
@@ -1169,25 +1283,154 @@ static bool knife_ray_intersect_face(
return false;
}
-/* Calculate maximum excursion from (0,0,0) of mesh */
+/**
+ * Calculate the center and maximum excursion of mesh.
+ */
static void calc_ortho_extent(KnifeTool_OpData *kcd)
{
BMIter iter;
BMVert *v;
BMesh *bm = kcd->em->bm;
- float max_xyz = 0.0f;
- int i;
+ float min[3], max[3];
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- for (i = 0; i < 3; i++)
- max_xyz = max_ff(max_xyz, fabsf(v->co[i]));
+ INIT_MINMAX(min, max);
+
+ if (kcd->cagecos) {
+ minmax_v3v3_v3_array(min, max, kcd->cagecos, bm->totvert);
}
- kcd->ortho_extent = max_xyz;
+ else {
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ minmax_v3v3_v3(min, max, v->co);
+ }
+ }
+
+ kcd->ortho_extent = len_v3v3(min, max) / 2;
+ mid_v3_v3v3(kcd->ortho_extent_center, min, max);
}
-/* Check if p is visible (not clipped, not occluded by another face).
- * s in screen projection of p. */
-static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats)
+static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe)
+{
+ BMElem *ele_test;
+ KnifeEdge *kfe = NULL;
+
+ /* vert? */
+ ele_test = (BMElem *)kfv->v;
+
+ if (r_kfe || ele_test == NULL) {
+ if (kfv->v == NULL) {
+ Ref *ref;
+ for (ref = kfv->edges.first; ref; ref = ref->next) {
+ kfe = ref->ref;
+ if (kfe->e) {
+ if (r_kfe) {
+ *r_kfe = kfe;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /* edge? */
+ if (ele_test == NULL) {
+ if (kfe) {
+ ele_test = (BMElem *)kfe->e;
+ }
+ }
+
+ /* face? */
+ if (ele_test == NULL) {
+ if (BLI_listbase_is_single(&kfe->faces)) {
+ ele_test = ((Ref *)kfe->faces.first)->ref;
+ }
+ }
+
+ return ele_test;
+}
+
+static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe)
+{
+ BMElem *ele_test;
+
+ ele_test = (BMElem *)kfe->e;
+
+ if (ele_test == NULL) {
+ ele_test = (BMElem *)kfe->basef;
+ }
+
+ return ele_test;
+}
+
+/* Do edges e1 and e2 go between exactly the same coordinates? */
+static bool coinciding_edges(BMEdge *e1, BMEdge *e2)
+{
+ const float *co11, *co12, *co21, *co22;
+
+ co11 = e1->v1->co;
+ co12 = e1->v2->co;
+ co21 = e2->v1->co;
+ co22 = e2->v2->co;
+ if ((equals_v3v3(co11, co21) && equals_v3v3(co12, co22)) ||
+ (equals_v3v3(co11, co22) && equals_v3v3(co12, co21)))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/* Callback used in point_is_visible to exclude hits on the faces that are the same
+ * as or contain the hitting element (which is in user_data).
+ * Also (see T44492) want to exclude hits on faces that butt up to the hitting element
+ * (e.g., when you double an edge by an edge split).
+ */
+static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
+{
+ bool ans;
+ BMEdge *e, *e2;
+ BMIter iter;
+
+ switch (((BMElem *)user_data)->head.htype) {
+ case BM_FACE:
+ ans = (BMFace *)user_data != f;
+ break;
+ case BM_EDGE:
+ e = (BMEdge *)user_data;
+ ans = !BM_edge_in_face(e, f);
+ if (ans) {
+ /* Is it a boundary edge, coincident with a split edge? */
+ if (BM_edge_is_boundary(e)) {
+ BM_ITER_ELEM(e2, &iter, f, BM_EDGES_OF_FACE) {
+ if (coinciding_edges(e, e2)) {
+ ans = false;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case BM_VERT:
+ ans = !BM_vert_in_face((BMVert *)user_data, f);
+ break;
+ default:
+ ans = true;
+ break;
+ }
+ return ans;
+}
+
+
+/**
+ * Check if \a p is visible (not clipped, not occluded by another face).
+ * s in screen projection of p.
+ *
+ * \param ele_test Optional vert/edge/face to use when \a p is on the surface of the geometry,
+ * intersecting faces matching this face (or connected when an vert/edge) will be ignored.
+ */
+static bool point_is_visible(
+ KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats,
+ BMElem *ele_test)
{
BMFace *f_hit;
@@ -1211,7 +1454,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
/* make p_ofs a little towards view, so ray doesn't hit p's face. */
sub_v3_v3(view, p);
dist = normalize_v3(view);
- madd_v3_v3v3fl(p_ofs, p, view, KNIFE_FLT_EPSBIG * 3.0f);
+ copy_v3_v3(p_ofs, p);
/* avoid projecting behind the viewpoint */
if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
@@ -1230,9 +1473,19 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
}
/* see if there's a face hit between p1 and the view */
- f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL);
- if (f_hit)
+ if (ele_test) {
+ f_hit = BKE_bmbvh_ray_cast_filter(
+ kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL,
+ bm_ray_cast_cb_elem_not_in_face_check, ele_test);
+ }
+ else {
+ f_hit = BKE_bmbvh_ray_cast(
+ kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL);
+ }
+
+ if (f_hit) {
return false;
+ }
}
return true;
@@ -1240,14 +1493,20 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
/* Clip the line (v1, v2) to planes perpendicular to it and distances d from
* the closest point on the line to the origin */
-static void clip_to_ortho_planes(float v1[3], float v2[3], float d)
+static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3], const float d)
{
- float closest[3];
- const float origin[3] = {0.0f, 0.0f, 0.0f};
+ float closest[3], dir[3];
+
+ sub_v3_v3v3(dir, v1, v2);
+ normalize_v3(dir);
+
+ /* could be v1 or v2 */
+ sub_v3_v3(v1, center);
+ project_plane_v3_v3v3(closest, v1, dir);
+ add_v3_v3(closest, center);
- closest_to_line_v3(closest, origin, v1, v2);
- dist_ensure_v3_v3fl(v1, closest, d);
- dist_ensure_v3_v3fl(v2, closest, d);
+ madd_v3_v3v3fl(v1, closest, dir, d);
+ madd_v3_v3v3fl(v2, closest, dir, -d);
}
static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh)
@@ -1274,6 +1533,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
SmallHashIter hiter;
KnifeLineHit hit;
void *val;
+ void **val_p;
float plane_cos[12];
float s[2], se1[2], se2[2], sint[2];
float r1[3], r2[3];
@@ -1281,10 +1541,11 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
float vert_tol, vert_tol_sq;
float line_tol, line_tol_sq;
float face_tol, face_tol_sq;
- float eps_scale;
int isect_kind;
unsigned int tot;
int i;
+ const bool use_hit_prev = true;
+ const bool use_hit_curr = (kcd->is_drag_hold == false);
bgl_get_mats(&mats);
@@ -1329,8 +1590,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
if (kcd->ortho_extent == 0.0f)
calc_ortho_extent(kcd);
- clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f);
- clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f);
+ clip_to_ortho_planes(v1, v3, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
+ clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
}
/* First use bvh tree to find faces, knife edges, and knife verts that might
@@ -1346,7 +1607,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
BLI_bvhtree_insert(planetree, 0, plane_cos, 4);
BLI_bvhtree_balance(planetree);
- results = BLI_bvhtree_overlap(tree, planetree, &tot);
+ results = BLI_bvhtree_overlap(tree, planetree, &tot, NULL, NULL);
if (!results) {
BLI_bvhtree_free(planetree);
return;
@@ -1360,6 +1621,11 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
ls = (BMLoop **)kcd->em->looptris[result->indexA];
f = ls[0]->f;
set_lowest_face_tri(kcd, f, result->indexA);
+
+ /* occlude but never cut unselected faces (when only_select is used) */
+ if (kcd->only_select && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ continue;
+ }
/* for faces, store index of lowest hit looptri in hash */
if (BLI_smallhash_haskey(&faces, (uintptr_t)f)) {
continue;
@@ -1374,27 +1640,18 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
continue;
BLI_smallhash_insert(&kfes, (uintptr_t)kfe, kfe);
v = kfe->v1;
- if (!BLI_smallhash_haskey(&kfvs, (uintptr_t)v))
- BLI_smallhash_insert(&kfvs, (uintptr_t)v, v);
+ BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v);
v = kfe->v2;
- if (!BLI_smallhash_haskey(&kfvs, (uintptr_t)v))
- BLI_smallhash_insert(&kfvs, (uintptr_t)v, v);
+ BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v);
}
}
/* Now go through the candidates and find intersections */
/* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */
- {
- /* Scale the epsilon by the zoom level
- * to compensate for projection imprecision, see T41164 */
- float zoom_xy[2] = {kcd->vc.rv3d->winmat[0][0],
- kcd->vc.rv3d->winmat[1][1]};
- eps_scale = len_v2(zoom_xy);
- }
- vert_tol = KNIFE_FLT_EPS_PX * eps_scale;
- line_tol = KNIFE_FLT_EPS_PX * eps_scale;
- face_tol = max_ff(vert_tol, line_tol);
+ vert_tol = KNIFE_FLT_EPS_PX_VERT;
+ line_tol = KNIFE_FLT_EPS_PX_EDGE;
+ face_tol = KNIFE_FLT_EPS_PX_FACE;
vert_tol_sq = vert_tol * vert_tol;
line_tol_sq = line_tol * line_tol;
@@ -1403,30 +1660,55 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
/* Assume these tolerances swamp floating point rounding errors in calculations below */
/* first look for vertex hits */
- for (val = BLI_smallhash_iternew(&kfvs, &hiter, (uintptr_t *)&v); val;
- val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&v))
+ for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p;
+ val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v))
{
+ KnifeEdge *kfe_hit = NULL;
+
knife_project_v2(kcd, v->cageco, s);
d = dist_squared_to_line_segment_v2(s, s1, s2);
- if (d <= vert_tol_sq) {
- if (point_is_visible(kcd, v->cageco, s, &mats)) {
- memset(&hit, 0, sizeof(hit));
- hit.v = v;
- copy_v3_v3(hit.hit, v->co);
- copy_v3_v3(hit.cagehit, v->cageco);
- copy_v2_v2(hit.schit, s);
- set_linehit_depth(kcd, &hit);
- BLI_array_append(linehits, hit);
+ if ((d <= vert_tol_sq) &&
+ (point_is_visible(kcd, v->cageco, s, &mats, bm_elem_from_knife_vert(v, &kfe_hit))))
+ {
+ memset(&hit, 0, sizeof(hit));
+ hit.v = v;
+
+ /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally.
+ * knowing if the hit comes from an edge is important for edge-in-face checks later on
+ * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */
+ if (kfe_hit) {
+ hit.kfe = kfe_hit;
}
+
+ copy_v3_v3(hit.hit, v->co);
+ copy_v3_v3(hit.cagehit, v->cageco);
+ copy_v2_v2(hit.schit, s);
+ set_linehit_depth(kcd, &hit);
+ BLI_array_append(linehits, hit);
+ }
+ else {
+ /* note that these vertes aren't used */
+ *val_p = NULL;
}
}
+
/* now edge hits; don't add if a vertex at end of edge should have hit */
for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val;
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe))
{
+ int kfe_verts_in_cut;
+ /* if we intersect both verts, don't attempt to intersect the edge */
+
+ kfe_verts_in_cut = (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL) +
+ (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL);
+
+ if (kfe_verts_in_cut == 2) {
+ continue;
+ }
+
knife_project_v2(kcd, kfe->v1->cageco, se1);
knife_project_v2(kcd, kfe->v2->cageco, se2);
- isect_kind = isect_seg_seg_v2_point(s1, s2, se1, se2, sint);
+ isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint);
if (isect_kind == -1) {
/* isect_seg_seg_v2 doesn't do tolerance test around ends of s1-s2 */
closest_to_line_segment_v2(sint, s1, se1, se2);
@@ -1449,7 +1731,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
* Need to find 3d intersection of ray through sint */
knife_input_ray_segment(kcd, sint, 1.0f, r1, r2);
isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp);
- if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats)) {
+ if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats, bm_elem_from_knife_edge(kfe))) {
memset(&hit, 0, sizeof(hit));
if (kcd->snap_midpoints) {
/* choose intermediate point snap too */
@@ -1477,8 +1759,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
{
float p[3], p_cage[3];
- if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
- if (point_is_visible(kcd, p_cage, s1, &mats)) {
+ if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
+ if (point_is_visible(kcd, p_cage, s1, &mats, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
@@ -1488,8 +1770,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
BLI_array_append(linehits, hit);
}
}
- if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
- if (point_is_visible(kcd, p_cage, s2, &mats)) {
+
+ if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
+ if (point_is_visible(kcd, p_cage, s2, &mats, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
@@ -1543,13 +1826,18 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
float dist = KMAXDIST;
float origin[3];
float origin_ofs[3];
- float ray[3];
+ float ray[3], ray_normal[3];
/* unproject to find view ray */
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
sub_v3_v3v3(ray, origin_ofs, origin);
+ normalize_v3_v3(ray_normal, ray);
- f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, 0.0f, NULL, co, cageco);
+ f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray_normal, 0.0f, NULL, co, cageco);
+
+ if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) {
+ f = NULL;
+ }
if (is_space)
*is_space = !f;
@@ -1913,7 +2201,10 @@ static int knife_update_active(KnifeTool_OpData *kcd)
kcd->curr.vert = knife_find_closest_vert(kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
- if (!kcd->curr.vert) {
+ if (!kcd->curr.vert &&
+ /* no edge snapping while dragging (edges are too sticky when cuts are immediate) */
+ !kcd->is_drag_hold)
+ {
kcd->curr.edge = knife_find_closest_edge(kcd, kcd->curr.co, kcd->curr.cage,
&kcd->curr.bmface, &kcd->curr.is_space);
}
@@ -1942,34 +2233,17 @@ static int knife_update_active(KnifeTool_OpData *kcd)
return 1;
}
-/* sort list of kverts by fraction along edge e */
-static void sort_by_frac_along(ListBase *lst, BMEdge *e)
+static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p)
{
- /* note, since we know the point is along the edge, sort from distance to v1co */
- const float *v1co = e->v1->co;
- Ref *cur = NULL, *prev = NULL, *next = NULL;
-
- if (lst->first == lst->last)
- return;
+ const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref;
+ const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref;
+ const float *co = co_p;
+ const float a_sq = len_squared_v3v3(co, cur_a->co);
+ const float b_sq = len_squared_v3v3(co, cur_b->co);
- for (cur = ((Ref *)lst->first)->next; cur; cur = next) {
- KnifeVert *vcur = cur->ref;
- const float vcur_fac_sq = len_squared_v3v3(v1co, vcur->co);
-
- next = cur->next;
- prev = cur->prev;
-
- BLI_remlink(lst, cur);
-
- while (prev) {
- KnifeVert *vprev = prev->ref;
- if (len_squared_v3v3(v1co, vprev->co) <= vcur_fac_sq)
- break;
- prev = prev->prev;
- }
-
- BLI_insertlinkafter(lst, prev, cur);
- }
+ if (a_sq < b_sq) return -1;
+ else if (a_sq > b_sq) return 1;
+ else return 0;
}
/* The chain so far goes from an instantiated vertex to kfv (some may be reversed).
@@ -2063,7 +2337,7 @@ static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges)
break;
}
if (ans) {
- BLI_assert(BLI_countlist(ans) > 0);
+ BLI_assert(!BLI_listbase_is_empty(ans));
for (r = ans->first; r; r = r->next) {
ref = find_ref(fedges, r->ref);
BLI_assert(ref != NULL);
@@ -2157,7 +2431,7 @@ static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges)
static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, ListBase **mainchain,
ListBase **sidechain)
{
- float **fco, **hco;
+ float (*fco)[2], (*hco)[2];
BMVert **fv;
KnifeVert **hv;
KnifeEdge **he;
@@ -2171,7 +2445,7 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
int besti[2], bestj[2];
float dist_sq, dist_best_sq;
- nh = BLI_countlist(hole);
+ nh = BLI_listbase_count(hole);
nf = f->len;
if (nh < 2 || nf < 3)
return false;
@@ -2179,8 +2453,8 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
/* Gather 2d projections of hole and face vertex coordinates.
* Use best-axis projection - not completely accurate, maybe revisit */
axis_dominant_v3(&ax, &ay, f->no);
- hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float *));
- fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float *));
+ hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float[2]));
+ fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float[2]));
hv = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeVert *));
fv = BLI_memarena_alloc(kcd->arena, nf * sizeof(BMVert *));
he = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeEdge *));
@@ -2198,7 +2472,6 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
kfv = kfvother;
BLI_assert(kfv == kfe->v1 || kfv == kfe->v2);
}
- hco[i] = BLI_memarena_alloc(kcd->arena, 2 * sizeof(float));
hco[i][0] = kfv->co[ax];
hco[i][1] = kfv->co[ay];
hv[i] = kfv;
@@ -2208,7 +2481,6 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
j = 0;
BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
- fco[j] = BLI_memarena_alloc(kcd->arena, 2 * sizeof(float));
fco[j][0] = v->co[ax];
fco[j][1] = v->co[ay];
fv[j] = v;
@@ -2302,13 +2574,22 @@ static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
{
bool v1_inside, v2_inside;
bool v1_inface, v2_inface;
+ BMLoop *l1, *l2;
if (!f || !v1 || !v2)
return false;
+ l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL;
+ l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL;
+
+ if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) {
+ /* boundary-case, always false to avoid edge-in-face checks below */
+ return false;
+ }
+
/* find out if v1 and v2, if set, are part of the face */
- v1_inface = v1->v ? BM_vert_in_face(f, v1->v) : false;
- v2_inface = v2->v ? BM_vert_in_face(f, v2->v) : false;
+ v1_inface = (l1 != NULL);
+ v2_inface = (l2 != NULL);
/* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */
v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co);
@@ -2350,7 +2631,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha
KnifeVert *kfv, *kfvprev;
BMLoop *l_new, *l_iter;
int i;
- int nco = BLI_countlist(chain) - 1;
+ int nco = BLI_listbase_count(chain) - 1;
float (*cos)[3] = BLI_array_alloca(cos, nco);
KnifeVert **kverts = BLI_array_alloca(kverts, nco);
@@ -2423,7 +2704,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
Ref *ref, *refnext;
int count, oldcount;
- oldcount = BLI_countlist(kfedges);
+ oldcount = BLI_listbase_count(kfedges);
while ((chain = find_chain(kcd, kfedges)) != NULL) {
ListBase fnew_kfedges;
knife_make_chain_cut(kcd, f, chain, &fnew);
@@ -2452,7 +2733,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
/* find_chain should always remove edges if it returns true,
* but guard against infinite loop anyway */
- count = BLI_countlist(kfedges);
+ count = BLI_listbase_count(kfedges);
if (count >= oldcount) {
BLI_assert(!"knife find_chain infinite loop");
return;
@@ -2520,7 +2801,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
break;
/* find_hole should always remove edges if it returns true,
* but guard against infinite loop anyway */
- count = BLI_countlist(kfedges);
+ count = BLI_listbase_count(kfedges);
if (count >= oldcount) {
BLI_assert(!"knife find_hole infinite loop");
return;
@@ -2552,6 +2833,14 @@ static void knife_make_cuts(KnifeTool_OpData *kcd)
/* put list of cutting edges for a face into fhash, keyed by face */
BLI_mempool_iternew(kcd->kedges, &iter);
for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
+
+ /* select edges that lie directly on the cut */
+ if (kcd->select_result) {
+ if (kfe->e && kfe->is_cut) {
+ BM_edge_select_set(bm, kfe->e, true);
+ }
+ }
+
f = kfe->basef;
if (!f || kfe->e)
continue;
@@ -2588,7 +2877,8 @@ static void knife_make_cuts(KnifeTool_OpData *kcd)
for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst;
lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e))
{
- sort_by_frac_along(lst, e);
+ BLI_listbase_sort_r(lst, sort_verts_by_dist_cb, e->v1->co);
+
for (ref = lst->first; ref; ref = ref->next) {
kfv = ref->ref;
pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co);
@@ -2619,6 +2909,9 @@ static void knifetool_finish_ex(KnifeTool_OpData *kcd)
EDBM_selectmode_flush(kcd->em);
EDBM_mesh_normals_update(kcd->em);
EDBM_update_generic(kcd->em, true, true);
+
+ /* re-tessellating makes this invalid, dont use again by accident */
+ knifetool_free_bmbvh(kcd);
}
static void knifetool_finish(wmOperator *op)
{
@@ -2632,8 +2925,7 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
invert_m4_m4(kcd->projmat_inv, kcd->projmat);
- copy_v3_v3(kcd->proj_zaxis, kcd->vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(kcd->ob->imat, kcd->proj_zaxis);
+ mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]);
normalize_v3(kcd->proj_zaxis);
kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
@@ -2663,14 +2955,12 @@ static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
BLI_ghash_free(kcd->kedgefacemap, NULL, NULL);
BLI_ghash_free(kcd->facetrimap, NULL, NULL);
- BKE_bmbvh_free(kcd->bmbvh);
BLI_memarena_free(kcd->arena);
/* tag for redraw */
ED_region_tag_redraw(kcd->ar);
- if (kcd->cagecos)
- MEM_freeN((void *)kcd->cagecos);
+ knifetool_free_bmbvh(kcd);
if (kcd->linehits)
MEM_freeN(kcd->linehits);
@@ -2701,6 +2991,32 @@ static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
knifetool_update_mval(kcd, mval);
}
+static void knifetool_init_bmbvh(KnifeTool_OpData *kcd)
+{
+ BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
+
+ kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, kcd->scene, NULL);
+
+ kcd->bmbvh = BKE_bmbvh_new_from_editmesh(
+ kcd->em,
+ BMBVH_RETURN_ORIG |
+ ((kcd->only_select && kcd->cut_through) ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN),
+ kcd->cagecos, false);
+}
+
+static void knifetool_free_bmbvh(KnifeTool_OpData *kcd)
+{
+ if (kcd->bmbvh) {
+ BKE_bmbvh_free(kcd->bmbvh);
+ kcd->bmbvh = NULL;
+ }
+
+ if (kcd->cagecos) {
+ MEM_freeN((void *)kcd->cagecos);
+ kcd->cagecos = NULL;
+ }
+}
+
/* called when modal loop selection gets set up... */
static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
const bool only_select, const bool cut_through, const bool is_interactive)
@@ -2709,6 +3025,7 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
Object *obedit = CTX_data_edit_object(C);
/* assign the drawing handle for drawing preview line... */
+ kcd->scene = scene;
kcd->ob = obedit;
kcd->ar = CTX_wm_region(C);
@@ -2716,14 +3033,12 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
kcd->em = BKE_editmesh_from_object(kcd->ob);
- BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
-
- kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, scene, NULL);
+ /* cut all the way through the mesh if use_occlude_geometry button not pushed */
+ kcd->is_interactive = is_interactive;
+ kcd->cut_through = cut_through;
+ kcd->only_select = only_select;
- kcd->bmbvh = BKE_bmbvh_new_from_editmesh(kcd->em,
- BMBVH_RETURN_ORIG |
- (only_select ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN),
- kcd->cagecos, false);
+ knifetool_init_bmbvh(kcd);
kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife");
kcd->vthresh = KMAXDIST - 1;
@@ -2742,11 +3057,6 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
kcd->kedgefacemap = BLI_ghash_ptr_new("knife kedgefacemap");
kcd->facetrimap = BLI_ghash_ptr_new("knife facetrimap");
- /* cut all the way through the mesh if use_occlude_geometry button not pushed */
- kcd->is_interactive = is_interactive;
- kcd->cut_through = cut_through;
- kcd->only_select = only_select;
-
/* can't usefully select resulting edges in face mode */
kcd->select_result = (kcd->em->selectmode != SCE_SELECT_FACE);
@@ -2789,31 +3099,19 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
knifetool_init(C, kcd, only_select, cut_through, true);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
/* add a modal handler for this operator - handles loop selection */
WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
WM_event_add_modal_handler(C, op);
knifetool_update_mval_i(kcd, event->mval);
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
return OPERATOR_RUNNING_MODAL;
}
-enum {
- KNF_MODAL_CANCEL = 1,
- KNF_MODAL_CONFIRM,
- KNF_MODAL_MIDPOINT_ON,
- KNF_MODAL_MIDPOINT_OFF,
- KNF_MODAL_NEW_CUT,
- KNF_MODEL_IGNORE_SNAP_ON,
- KNF_MODEL_IGNORE_SNAP_OFF,
- KNF_MODAL_ADD_CUT,
- KNF_MODAL_ANGLE_SNAP_TOGGLE,
- KNF_MODAL_CUT_THROUGH_TOGGLE,
- KNF_MODAL_PANNING
-};
-
wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
{
static EnumPropertyItem modal_items[] = {
@@ -2842,7 +3140,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, KNF_MODAL_PANNING);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_ADD_CUT);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_DBL_CLICK, KM_ANY, 0, KNF_MODAL_ADD_CUT_CLOSED);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KNF_MODAL_ADD_CUT);
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
@@ -2879,6 +3178,9 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
+ em_setup_viewcontext(C, &kcd->vc);
+ kcd->ar = kcd->vc.ar;
+
view3d_operator_needs_opengl(C);
ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */
@@ -2910,7 +3212,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
knife_recalc_projmat(kcd);
knife_update_active(kcd);
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->ar);
do_refresh = true;
break;
@@ -2919,30 +3221,30 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
knife_recalc_projmat(kcd);
knife_update_active(kcd);
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
ED_region_tag_redraw(kcd->ar);
do_refresh = true;
break;
case KNF_MODEL_IGNORE_SNAP_ON:
ED_region_tag_redraw(kcd->ar);
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true;
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
do_refresh = true;
break;
case KNF_MODEL_IGNORE_SNAP_OFF:
ED_region_tag_redraw(kcd->ar);
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false;
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
do_refresh = true;
break;
case KNF_MODAL_ANGLE_SNAP_TOGGLE:
kcd->angle_snapping = !kcd->angle_snapping;
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
do_refresh = true;
break;
case KNF_MODAL_CUT_THROUGH_TOGGLE:
kcd->cut_through = !kcd->cut_through;
- knife_update_header(C, kcd);
+ knife_update_header(C, op, kcd);
do_refresh = true;
break;
case KNF_MODAL_NEW_CUT:
@@ -2953,16 +3255,53 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case KNF_MODAL_ADD_CUT:
knife_recalc_projmat(kcd);
- if (kcd->mode == MODE_DRAGGING) {
- knife_add_cut(kcd);
+ /* get the value of the event which triggered this one */
+ if (event->prevval != KM_RELEASE) {
+ if (kcd->mode == MODE_DRAGGING) {
+ knife_add_cut(kcd);
+ }
+ else if (kcd->mode != MODE_PANNING) {
+ knife_start_cut(kcd);
+ kcd->mode = MODE_DRAGGING;
+ kcd->init = kcd->curr;
+ }
+
+ /* freehand drawing is incompatible with cut-through */
+ if (kcd->cut_through == false) {
+ kcd->is_drag_hold = true;
+ }
}
- else if (kcd->mode != MODE_PANNING) {
- knife_start_cut(kcd);
- kcd->mode = MODE_DRAGGING;
+ else {
+ kcd->is_drag_hold = false;
+
+ /* needed because the last face 'hit' is ignored when dragging */
+ knifetool_update_mval(kcd, kcd->curr.mval);
}
ED_region_tag_redraw(kcd->ar);
break;
+ case KNF_MODAL_ADD_CUT_CLOSED:
+ if (kcd->mode == MODE_DRAGGING) {
+
+ /* shouldn't be possible with default key-layout, just incase... */
+ if (kcd->is_drag_hold) {
+ kcd->is_drag_hold = false;
+ knifetool_update_mval(kcd, kcd->curr.mval);
+ }
+
+ kcd->prev = kcd->curr;
+ kcd->curr = kcd->init;
+
+ knife_project_v2(kcd, kcd->curr.cage, kcd->curr.mval);
+ knifetool_update_mval(kcd, kcd->curr.mval);
+
+ knife_add_cut(kcd);
+
+ /* KNF_MODAL_NEW_CUT */
+ knife_finish_cut(kcd);
+ kcd->mode = MODE_IDLE;
+ }
+ break;
case KNF_MODAL_PANNING:
if (event->val != KM_RELEASE) {
if (kcd->mode != MODE_PANNING) {
@@ -2989,12 +3328,25 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
if (kcd->mode != MODE_PANNING) {
knifetool_update_mval_i(kcd, event->mval);
+
+ if (kcd->is_drag_hold) {
+ if (kcd->totlinehit >= 2) {
+ knife_add_cut(kcd);
+ }
+ }
}
break;
}
}
+ if (kcd->mode == MODE_DRAGGING) {
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
if (do_refresh) {
/* we don't really need to update mval,
* but this happens to be the best way to refresh at the moment */
@@ -3036,16 +3388,14 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
* tessellation here seems way overkill,
* but without this its very hard to know of a point is inside the face
*/
-static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
+static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3])
{
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
int j;
-
- const float *best_co[3] = {NULL};
- float best_area = -1.0f;
- bool ok = false;
+ int j_best = 0; /* use as fallback when unset */
+ float area_best = -1.0f;
BM_face_calc_tessellation(f, loops, index);
@@ -3055,52 +3405,35 @@ static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
const float *p3 = loops[index[j][2]]->v->co;
float area;
- float cross[3];
- cross_v3_v3v3(cross, p2, p3);
- area = fabsf(dot_v3v3(p1, cross));
- if (area > best_area) {
- best_co[0] = p1;
- best_co[1] = p2;
- best_co[2] = p3;
- best_area = area;
- ok = true;
+ area = area_squared_tri_v3(p1, p2, p3);
+ if (area > area_best) {
+ j_best = j;
+ area_best = area;
}
}
- if (ok) {
- mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]);
- }
- else {
- mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co);
- }
+ mid_v3_v3v3v3(
+ r_cent,
+ loops[index[j_best][0]]->v->co,
+ loops[index[j_best][1]]->v->co,
+ loops[index[j_best][2]]->v->co);
}
-static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4])
+static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
{
- float cent_ss[2];
- float cent[3];
-
- edvm_mesh_knife_face_point(f, cent);
-
- ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat);
-
- /* check */
- {
- LinkNode *p = polys;
- int isect = 0;
+ LinkNode *p = polys;
+ int isect = 0;
- while (p) {
- const float (*mval_fl)[2] = p->link;
- const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
- isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false);
- p = p->next;
- }
-
- if (isect % 2) {
- return true;
- }
+ while (p) {
+ const float (*mval_fl)[2] = p->link;
+ const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
+ isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false);
+ p = p->next;
}
+ if (isect % 2) {
+ return true;
+ }
return false;
}
@@ -3110,6 +3443,7 @@ static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f,
void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
+ bglMats mats;
view3d_operator_needs_opengl(C);
@@ -3128,6 +3462,10 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
if (use_tag) {
BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
+
+ if (kcd->cut_through == false) {
+ bgl_get_mats(&mats);
+ }
}
/* execute */
@@ -3171,6 +3509,11 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
bool keep_search;
+ /* freed on knifetool_finish_ex, but we need again to check if points are visible */
+ if (kcd->cut_through == false) {
+ knifetool_init_bmbvh(kcd);
+ }
+
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat);
/* use face-loop tag to store if we have intersected */
@@ -3192,7 +3535,10 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
BMFace *f;
BMIter fiter;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
+ float cent[3], cent_ss[2];
+ edbm_mesh_knife_face_point(f, cent);
+ knife_project_v2(kcd, cent, cent_ss);
+ if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
}
}
@@ -3225,7 +3571,12 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
} while ((l_iter = l_iter->next) != l_first && (found == false));
if (found) {
- if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
+ float cent[3], cent_ss[2];
+ edbm_mesh_knife_face_point(f, cent);
+ knife_project_v2(kcd, cent, cent_ss);
+ if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) &&
+ edbm_mesh_knife_point_isect(polys, cent_ss))
+ {
BM_elem_flag_enable(f, BM_ELEM_TAG);
keep_search = true;
}
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 553c1faa36a..0d3cc07589b 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -166,7 +166,7 @@ void MESH_OT_knife_project(wmOperatorType *ot)
/* callbacks */
ot->exec = knifeproject_exec;
- ot->poll = ED_operator_editmesh_view3d;
+ ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 12be32b764e..c612ebfcc24 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -32,11 +32,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_array.h"
+#include "BLI_stack.h"
#include "BLI_string.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_modifier.h"
@@ -224,7 +224,8 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
BMEdge *eed, *eed_last;
BMVert *v[2][2] = {{NULL}}, *v_last;
float (*edges)[2][3] = NULL;
- BLI_array_declare(edges);
+ BLI_Stack *edge_stack;
+
int i, tot = 0;
BMW_init(&walker, bm, BMW_EDGERING,
@@ -232,10 +233,27 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
+
+ edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
+
+ eed_last = NULL;
+ for (eed = eed_last = BMW_begin(&walker, lcd->eed); eed; eed = BMW_step(&walker)) {
+ BLI_stack_push(edge_stack, &eed);
+ }
+ BMW_end(&walker);
+
+
+ eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
+
+ edges = MEM_mallocN(
+ (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__);
+
v_last = NULL;
eed_last = NULL;
- for (eed = eed_start = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
+ while (!BLI_stack_is_empty(edge_stack)) {
+ BLI_stack_pop(edge_stack, &eed);
+
if (eed_last) {
if (v_last) {
v[1][0] = v[0][0];
@@ -250,8 +268,6 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
edgering_find_order(eed_last, eed, v_last, v);
v_last = v[0][0];
- BLI_array_grow_items(edges, previewlines);
-
for (i = 1; i <= previewlines; i++) {
const float fac = (i / ((float)previewlines + 1));
float v_cos[2][2][3];
@@ -279,8 +295,6 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
edgering_find_order(eed_last, eed_start, v_last, v);
- BLI_array_grow_items(edges, previewlines);
-
for (i = 1; i <= previewlines; i++) {
const float fac = (i / ((float)previewlines + 1));
float v_cos[2][2][3];
@@ -297,7 +311,8 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
}
}
- BMW_end(&walker);
+ BLI_stack_free(edge_stack);
+
lcd->edges = edges;
lcd->totedge = tot;
}
@@ -362,9 +377,9 @@ static void edgering_select(RingSelOpData *lcd)
}
BMW_init(&walker, em->bm, BMW_EDGERING,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
BM_edge_select_set(em->bm, eed, true);
@@ -412,11 +427,12 @@ static void ringsel_finish(bContext *C, wmOperator *op)
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
smoothness, smooth_falloff, true,
0.0f, 0.0f,
- cuts, seltype, SUBD_PATH, 0, true,
+ cuts, seltype, SUBD_CORNER_PATH, 0, true,
use_only_quads, 0);
- /* when used in a macro tessface is already re-recalculated */
- EDBM_update_generic(em, (is_macro == false), true);
+ /* when used in a macro the tessfaces will be recalculated anyway,
+ * this is needed here because modifiers depend on updated tessellation, see T45920 */
+ EDBM_update_generic(em, true, true);
if (is_single) {
/* de-select endpoints */
@@ -553,6 +569,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
/* add a modal handler for this operator - handles loop selection */
if (is_interactive) {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
WM_event_add_modal_handler(C, op);
}
@@ -639,6 +656,9 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool show_cuts = false;
const bool has_numinput = hasNumInput(&lcd->num);
+ em_setup_viewcontext(C, &lcd->vc);
+ lcd->ar = lcd->vc.ar;
+
view3d_operator_needs_opengl(C);
/* using the keyboard to input the number of cuts */
@@ -825,21 +845,21 @@ void MESH_OT_loopcut(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 100);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_float(ot->srna, "smoothness", 0.0f, -FLT_MAX, FLT_MAX,
+ prop = RNA_def_float(ot->srna, "smoothness", 0.0f, -1e3f, 1e3f,
"Smoothness", "Smoothness factor", -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
- RNA_def_property_enum_default(prop, PROP_ROOT);
+ RNA_def_property_enum_default(prop, PROP_INVSQUARE);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
- RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Number of Cuts", "", 0, INT_MAX);
+ prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
#ifdef USE_LOOPSLIDE_HACK
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 44d03da93a2..72dfb89e5f3 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -32,9 +32,12 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_windowmanager_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_meshdata_types.h"
+#endif
+
#include "BLI_math.h"
#include "BLI_linklist.h"
@@ -91,7 +94,7 @@ static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
float dist = ED_view3d_select_dist_px();
const bool use_length = true;
- v_dst = EDBM_vert_find_nearest(vc, &dist, false, false);
+ v_dst = EDBM_vert_find_nearest(vc, &dist);
if (v_dst) {
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
LinkNode *path = NULL;
@@ -99,7 +102,7 @@ static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
if (v_act && (v_act != v_dst)) {
if ((path = BM_mesh_calc_path_vert(bm, v_act, v_dst, use_length,
- &user_data, verttag_filter_cb)))
+ verttag_filter_cb, &user_data)))
{
BM_select_history_remove(bm, v_act);
}
@@ -267,7 +270,7 @@ static bool mouse_mesh_shortest_path_edge(ViewContext *vc)
if (e_act && (e_act != e_dst)) {
if ((path = BM_mesh_calc_path_edge(bm, e_act, e_dst, use_length,
- &user_data, edgetag_filter_cb)))
+ edgetag_filter_cb, &user_data)))
{
BM_select_history_remove(bm, e_act);
}
@@ -388,7 +391,7 @@ static bool mouse_mesh_shortest_path_face(ViewContext *vc)
if (f_act) {
if (f_act != f_dst) {
if ((path = BM_mesh_calc_path_face(bm, f_act, f_dst, use_length,
- &user_data, facetag_filter_cb)))
+ facetag_filter_cb, &user_data)))
{
BM_select_history_remove(bm, f_act);
}
@@ -513,11 +516,6 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/* Select path between existing selection */
-static bool ele_filter_visible_cb(BMElem *ele, void *UNUSED(user_data))
-{
- return !BM_elem_flag_test(ele, BM_ELEM_HIDDEN);
-}
-
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
@@ -577,17 +575,17 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
case BM_VERT:
path = BM_mesh_calc_path_vert(
bm, (BMVert *)ele_src, (BMVert *)ele_dst, use_length,
- NULL, (bool (*)(BMVert *, void *))ele_filter_visible_cb);
+ BM_elem_cb_check_hflag_disabled_simple(BMVert *, BM_ELEM_HIDDEN));
break;
case BM_EDGE:
path = BM_mesh_calc_path_edge(
bm, (BMEdge *)ele_src, (BMEdge *)ele_dst, use_length,
- NULL, (bool (*)(BMEdge *, void *))ele_filter_visible_cb);
+ BM_elem_cb_check_hflag_disabled_simple(BMEdge *, BM_ELEM_HIDDEN));
break;
case BM_FACE:
path = BM_mesh_calc_path_face(
bm, (BMFace *)ele_src, (BMFace *)ele_dst, use_length,
- NULL, (bool (*)(BMFace *, void *))ele_filter_visible_cb);
+ BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN));
break;
}
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 3b993332db0..c7a7828f3b2 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -63,9 +63,10 @@
* point and would result in the same distance.
*/
#define INSET_DEFAULT 0.00001f
-static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2],
- const float inset)
+static float edbm_rip_edgedist_squared(
+ ARegion *ar, float mat[4][4],
+ const float co1[3], const float co2[3], const float mvalf[2],
+ const float inset)
{
float vec1[2], vec2[2], dist_sq;
@@ -89,8 +90,9 @@ static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4],
}
#if 0
-static float edbm_rip_linedist(ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2])
+static float edbm_rip_linedist(
+ ARegion *ar, float mat[4][4],
+ const float co1[3], const float co2[3], const float mvalf[2])
{
float vec1[2], vec2[2];
@@ -114,9 +116,10 @@ static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
}
-static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l,
- ARegion *ar,
- float projectMat[4][4], const float fmval[2])
+static float edbm_rip_edge_side_measure(
+ BMEdge *e, BMLoop *e_l,
+ ARegion *ar,
+ float projectMat[4][4], const float fmval[2])
{
float cent[3] = {0, 0, 0}, mid[3];
@@ -309,8 +312,7 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
uid_start = uid;
uid = uid_end + bm->totedge;
- BLI_array_grow_one(eloop_pairs);
- lp = &eloop_pairs[BLI_array_count(eloop_pairs) - 1];
+ lp = BLI_array_append_ret(eloop_pairs);
BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b); /* no need to check, we know this will be true */
@@ -323,8 +325,7 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
}
/* null terminate */
- BLI_array_grow_one(eloop_pairs);
- lp = &eloop_pairs[BLI_array_count(eloop_pairs) - 1];
+ lp = BLI_array_append_ret(eloop_pairs);
lp->l_a = lp->l_b = NULL;
return eloop_pairs;
@@ -534,14 +535,14 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BMesh *bm = em->bm;
BMIter iter, liter;
BMLoop *l;
- BMEdge *e, *e2;
+ BMEdge *e_best;
BMVert *v;
const int totvert_orig = bm->totvert;
int i;
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
float dist_sq = FLT_MAX;
float d;
- bool is_wire;
+ bool is_wire, is_manifold_region;
BMEditSelection ese;
int totboundary_edge = 0;
@@ -561,65 +562,91 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- /* this should be impossible, but sanity checks are a good thing */
- if (!v)
+ /* (v == NULL) should be impossible */
+ if ((v == NULL) || (v->e == NULL)) {
return OPERATOR_CANCELLED;
+ }
is_wire = BM_vert_is_wire(v);
+ is_manifold_region = BM_vert_is_manifold_region(v);
- e2 = NULL;
+ e_best = NULL;
- if (v->e) {
+ {
+ BMEdge *e;
/* find closest edge to mouse cursor */
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- const bool is_boundary = BM_edge_is_boundary(e);
/* consider wire as boundary for this purpose,
* otherwise we can't a face away from a wire edge */
- totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e));
+ totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- if (is_boundary == false && BM_edge_is_manifold(e)) {
+ if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
- if ((e2 == NULL) || (d < dist_sq)) {
+ if ((e_best == NULL) || (d < dist_sq)) {
dist_sq = d;
- e2 = e;
+ e_best = e;
}
}
}
}
+ }
- /* if we are ripping a single vertex from 3 faces,
- * then measure the distance to the face corner as well as the edge */
- if (BM_vert_face_count(v) == 3 &&
- BM_vert_edge_count(v) == 3)
- {
- BMEdge *e_all[3];
- BMLoop *l_all[3];
- int i1, i2;
-
- BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
- BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
-
- /* not do a loop similar to the one above, but test against loops */
- for (i1 = 0; i1 < 3; i1++) {
- /* consider wire as boundary for this purpose,
- * otherwise we can't a face away from a wire edge */
- float l_mid_co[3];
- l = l_all[i1];
- edbm_calc_loop_co(l, l_mid_co);
- d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
- if ((e2 == NULL) || (d < dist_sq)) {
- dist_sq = d;
-
- /* find the edge that is not in this loop */
- e2 = NULL;
- for (i2 = 0; i2 < 3; i2++) {
- if (!BM_edge_in_loop(e_all[i2], l)) {
- e2 = e_all[i2];
- break;
- }
+ if (e_best && (is_manifold_region == false)) {
+ /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
+ BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
+ BMVert *v_new;
+
+ BLI_assert(l_sep->v == v);
+ v_new = bmesh_urmv_loop_region(bm, l_sep);
+ BLI_assert(BM_vert_find_first_loop(v));
+
+ BM_vert_select_set(bm, v, false);
+ BM_select_history_remove(bm, v);
+
+ BM_vert_select_set(bm, v_new, true);
+ if (ese.ele) {
+ BM_select_history_store(bm, v_new);
+ }
+
+ if (do_fill) {
+ BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+
+ /* if we are ripping a single vertex from 3 faces,
+ * then measure the distance to the face corner as well as the edge */
+ if (BM_vert_face_count_is_equal(v, 3) &&
+ BM_vert_edge_count_is_equal(v, 3))
+ {
+ BMEdge *e_all[3];
+ BMLoop *l_all[3];
+ int i1, i2;
+
+ BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
+ BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
+
+ /* not do a loop similar to the one above, but test against loops */
+ for (i1 = 0; i1 < 3; i1++) {
+ /* consider wire as boundary for this purpose,
+ * otherwise we can't a face away from a wire edge */
+ float l_mid_co[3];
+ l = l_all[i1];
+ edbm_calc_loop_co(l, l_mid_co);
+ d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
+ if ((e_best == NULL) || (d < dist_sq)) {
+ dist_sq = d;
+
+ /* find the edge that is not in this loop */
+ e_best = NULL;
+ for (i2 = 0; i2 < 3; i2++) {
+ if (!BM_edge_in_loop(e_all[i2], l)) {
+ e_best = e_all[i2];
+ break;
}
- BLI_assert(e2 != NULL);
}
+ BLI_assert(e_best != NULL);
}
}
}
@@ -628,7 +655,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
* split off vertex if...
* - we cant find an edge - this means we are ripping a faces vert that is connected to other
* geometry only at the vertex.
- * - the boundary edge total is greater then 2,
+ * - the boundary edge total is greater than 2,
* in this case edge split _can_ work but we get far nicer results if we use this special case.
* - there are only 2 edges but we are a wire vert. */
if ((is_wire == false && totboundary_edge > 2) ||
@@ -679,6 +706,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
else {
+ BMEdge *e;
/* a wire vert, find the best edge */
BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
@@ -696,6 +724,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
+ /* vout[0] == best
+ * vout[1] == glue
+ * vout[2+] == splice with glue (when vout_len > 2)
+ */
+ if (vi_best != 0) {
+ SWAP(BMVert *, vout[0], vout[vi_best]);
+ vi_best = 0;
+ }
+
/* select the vert from the best region */
v = vout[vi_best];
BM_vert_select_set(bm, v, true);
@@ -706,18 +743,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* splice all others back together */
if (vout_len > 2) {
-
- /* vout[0] == best
- * vout[1] == glue
- * vout[2+] == splice with glue
- */
- if (vi_best != 0) {
- SWAP(BMVert *, vout[0], vout[vi_best]);
- vi_best = 0;
+ for (i = 2; i < vout_len; i++) {
+ BM_vert_splice(bm, vout[1], vout[i]);
}
+ }
- for (i = 2; i < vout_len; i++) {
- BM_vert_splice(bm, vout[i], vout[1]);
+ if (do_fill) {
+ if (do_fill) {
+ /* match extrude vert-order */
+ BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
}
}
@@ -727,7 +761,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- if (!e2) {
+ if (!e_best) {
BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached");
return OPERATOR_CANCELLED;
}
@@ -736,20 +770,51 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* unlike edge split, for single vertex split we only use the operator in one of the cases
* but both allocate fill */
- /* rip two adjacent edges */
- if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) {
- /* Don't run the edge split operator in this case */
+ {
BMVert *v_rip;
+ BMLoop *larr[2];
+ int larr_len = 0;
- l = BM_edge_vert_share_loop(e2->l, v);
+ /* rip two adjacent edges */
+ if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) {
+ /* Don't run the edge split operator in this case */
- /* only tag for face-fill (we don't call the operator) */
- if (BM_edge_is_boundary(e2)) {
- BM_elem_flag_enable(e2, BM_ELEM_TAG);
+ l = BM_edge_vert_share_loop(e_best->l, v);
+ larr[larr_len] = l;
+ larr_len++;
+
+ /* only tag for face-fill (we don't call the operator) */
+ if (BM_edge_is_boundary(e_best)) {
+ BM_elem_flag_enable(e_best, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(l->e, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ }
}
else {
- BM_elem_flag_enable(l->e, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ if (BM_edge_is_manifold(e_best)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_best->l;
+ do {
+ larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
+
+ if (do_fill) {
+ /* Only needed when filling...
+ * Also, we never want to tag best edge, that one won't change during split. See T44618. */
+ if (larr[larr_len]->e == e_best) {
+ BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
+ }
+ }
+ larr_len++;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ else {
+ /* looks like there are no split edges, we could just return/report-error? - Campbell */
+ }
}
/* keep directly before edgesplit */
@@ -757,13 +822,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
}
-#if 0
- v_rip = BM_face_vert_separate(bm, l->f, v);
-#else
- v_rip = BM_face_loop_separate(bm, l);
-#endif
-
- BLI_assert(v_rip);
+ if (larr_len) {
+ v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
+ }
+ else {
+ v_rip = NULL;
+ }
if (v_rip) {
BM_vert_select_set(bm, v_rip, true);
@@ -773,27 +837,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
}
- else {
- if (BM_edge_is_manifold(e2)) {
- l = e2->l;
- e = BM_loop_other_edge_loop(l, v)->e;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
-
- l = e2->l->radial_next;
- e = BM_loop_other_edge_loop(l, v)->e;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
- else {
- /* looks like there are no split edges, we could just return/report-error? - Campbell */
- }
-
- /* keep directly before edgesplit */
- if (do_fill) {
- fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
- }
-
- BM_mesh_edgesplit(em->bm, true, true, true);
- }
{
/* --- select which vert --- */
@@ -856,7 +899,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
BMesh *bm = em->bm;
BMIter iter, eiter;
BMLoop *l;
- BMEdge *e, *e2;
+ BMEdge *e_best;
BMVert *v;
const int totedge_orig = bm->totedge;
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
@@ -870,11 +913,12 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* expand edge selection */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BMEdge *e;
bool all_manifold;
int totedge_manifold; /* manifold, visible edges */
int i;
- e2 = NULL;
+ e_best = NULL;
i = 0;
totedge_manifold = 0;
all_manifold = true;
@@ -886,7 +930,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* important to check selection rather then tag here
* else we get feedback loop */
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- e2 = e;
+ e_best = e;
i++;
}
totedge_manifold++;
@@ -899,18 +943,18 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
/* single edge, extend */
- if (i == 1 && e2->l) {
+ if (i == 1 && e_best->l) {
/* note: if the case of 3 edges has one change in loop stepping,
* if this becomes more involved we may be better off splitting
* the 3 edge case into its own else-if branch */
if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
- BMLoop *l_a = e2->l;
+ BMLoop *l_a = e_best->l;
BMLoop *l_b = l_a->radial_next;
/* find the best face to follow, this way the edge won't point away from
* the mouse when there are more than 4 (takes the shortest face fan around) */
- l = (edbm_rip_edge_side_measure(e2, l_a, ar, projectMat, fmval) <
- edbm_rip_edge_side_measure(e2, l_b, ar, projectMat, fmval)) ? l_a : l_b;
+ l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) <
+ edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? l_a : l_b;
l = BM_loop_other_edge_loop(l, v);
/* important edge is manifold else we can be attempting to split off a fan that don't budge,
@@ -928,7 +972,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
}
else {
- e = BM_vert_other_disk_edge(v, e2);
+ e = BM_vert_other_disk_edge(v, e_best);
if (e) {
BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG));
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index 5daf33fae3b..a501dfc8c2c 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -24,8 +24,6 @@
* based on mouse cursor position, split of vertices along the closest edge.
*/
-#include "MEM_guardedalloc.h"
-
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -34,9 +32,6 @@
#include "BKE_report.h"
#include "BKE_editmesh.h"
-#include "RNA_define.h"
-#include "RNA_access.h"
-
#include "WM_types.h"
#include "ED_mesh.h"
@@ -177,7 +172,7 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat);
- /* avoid comparing with view-axis aligned edges (less then a pixel) */
+ /* avoid comparing with view-axis aligned edges (less than a pixel) */
if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
float v_dir[2];
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 9cdfb43ae15..7f22ff7c241 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -36,9 +36,9 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_rand.h"
#include "BLI_array.h"
-#include "BLI_smallhash.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -53,6 +53,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -62,10 +63,10 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "GPU_extensions.h"
-
#include "UI_resources.h"
+#include "bmesh_tools.h"
+
#include "mesh_intern.h" /* own include */
/* use bmesh operator flags for a few operators */
@@ -197,13 +198,14 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma
unsigned int *dr;
int a;
- if (vc->obedit == NULL || vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
return false;
}
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if (buf == NULL) return false;
- if (bm_vertoffs == 0) return false;
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
+ if ((buf == NULL) || (bm_vertoffs == 0)) {
+ return false;
+ }
dr = buf->rect;
@@ -272,13 +274,14 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
return false;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ else if (!V3D_IS_ZBUF(vc->v3d)) {
return false;
}
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if (buf == NULL) return false;
- if (bm_vertoffs == 0) return false;
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
+ if ((buf == NULL) || (bm_vertoffs == 0)) {
+ return false;
+ }
dr = buf->rect;
@@ -321,15 +324,16 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
return false;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ else if (!V3D_IS_ZBUF(vc->v3d)) {
return false;
}
xmin = xs - rads; xmax = xs + rads;
ymin = ys - rads; ymax = ys + rads;
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if (bm_vertoffs == 0) return false;
- if (buf == NULL) return false;
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
+ if ((buf == NULL) || (bm_vertoffs == 0)) {
+ return false;
+ }
dr = buf->rect;
@@ -351,196 +355,369 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Find Nearest Vert/Edge/Face
+ *
+ * \note Screen-space manhatten distances are used here,
+ * since its faster and good enough for the purpose of selection.
+ *
+ * \note \a dist_bias is used so we can bias against selected items.
+ * when choosing between elements of a single type, but return the real distance
+ * to avoid the bias interfering with distance comparisons when mixing types.
+ * \{ */
+
+#define FIND_NEAR_SELECT_BIAS 5
+#define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
+
+struct NearestVertUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMVert *vert;
+};
+
+struct NearestVertUserData {
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestVertUserData_Hit hit;
+ struct NearestVertUserData_Hit hit_cycle;
+};
+
static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
{
- struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
+ struct NearestVertUserData *data = userData;
+ float dist_test, dist_test_bias;
- if (data->pass == 0) {
- if (index <= data->lastIndex)
- return;
- }
- else {
- if (index > data->lastIndex)
- return;
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
+
+ if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
- if (data->dist > 3) {
- float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->select) {
- if (data->strict == 1) {
- return;
- }
- else {
- dist_test += 5;
- }
- }
+ if (dist_test_bias < data->hit.dist_bias) {
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.vert = eve;
+ }
- if (dist_test < data->dist) {
- data->dist = dist_test;
- data->closest = eve;
- data->closestIndex = index;
+ if (data->use_cycle) {
+ if ((data->hit_cycle.vert == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.vert = eve;
}
}
}
-
-
-
-static bool findnearestvert__backbufIndextest(void *handle, unsigned int index)
-{
- BMEditMesh *em = (BMEditMesh *)handle;
- BMVert *eve = BM_vert_at_index_find(em->bm, index - 1);
- return !(eve && BM_elem_flag_test(eve, BM_ELEM_SELECT));
-}
/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them further than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ * Nearest vertex under the cursor.
+ *
+ * \param r_dist (in/out), minimal distance to the nearest and at the end, actual distance
+ * \param use_select_bias
+ * - When true, selected vertice are given a 5 pixel bias to make them further than unselect verts.
+ * - When false, unselected vertice are given the bias.
+ * \param use_cycle Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
*/
-BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist, const bool sel, const bool strict)
+BMVert *EDBM_vert_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ const bool use_select_bias, bool use_cycle)
{
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- float distance;
+ BMesh *bm = vc->em->bm;
+
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
+ float dist_test;
unsigned int index;
BMVert *eve;
- if (strict) {
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
- strict, vc->em, findnearestvert__backbufIndextest);
- }
- else {
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
- 0, NULL, NULL);
- }
-
- eve = index ? BM_vert_at_index_find(vc->em->bm, index - 1) : NULL;
+ index = ED_view3d_backbuf_sample_rect(
+ vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
+ eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
- if (eve && distance < *r_dist) {
- *r_dist = distance;
- return eve;
- }
- else {
- return NULL;
+ if (eve) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
+ return eve;
+ }
}
-
+ return NULL;
}
else {
- struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } data;
- static int lastSelectedIndex = 0;
- static BMVert *lastSelected = NULL;
-
- if (lastSelected && BM_vert_at_index_find(vc->em->bm, lastSelectedIndex) != lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
+ struct NearestVertUserData data = {{0}};
+ const struct NearestVertUserData_Hit *hit;
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
+
+ static int prev_select_index = 0;
+ static const BMVert *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
}
- data.lastIndex = lastSelectedIndex;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.select = sel ? BM_ELEM_SELECT : 0;
- data.dist = *r_dist;
- data.strict = strict;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag);
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
- if (data.dist > 3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
- }
+ prev_select_elem = hit->vert;
+ prev_select_index = hit->index;
- *r_dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
+ return hit->vert;
+ }
+}
- return data.closest;
+BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist)
+{
+ return EDBM_vert_find_nearest_ex(vc, r_dist, false, false);
+}
+
+/* find the distance to the edge we already have */
+struct NearestEdgeUserData_ZBuf {
+ float mval_fl[2];
+ float dist;
+ const BMEdge *edge_test;
+};
+
+static void find_nearest_edge_center__doZBuf(
+ void *userData, BMEdge *eed,
+ const float screen_co_a[2], const float screen_co_b[2],
+ int UNUSED(index))
+{
+ struct NearestEdgeUserData_ZBuf *data = userData;
+
+ if (eed == data->edge_test) {
+ float dist_test;
+ float screen_co_mid[2];
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
+
+ if (dist_test < data->dist) {
+ data->dist = dist_test;
+ }
}
}
+struct NearestEdgeUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMEdge *edge;
+
+ /* edges only, un-biased manhatten distance to which ever edge we pick
+ * (not used for choosing) */
+ float dist_center;
+};
+
+struct NearestEdgeUserData {
+ ViewContext vc;
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestEdgeUserData_Hit hit;
+ struct NearestEdgeUserData_Hit hit_cycle;
+};
+
/* note; uses v3d, so needs active 3d window */
-static void findnearestedge__doClosest(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
+static void find_nearest_edge__doClosest(
+ void *userData, BMEdge *eed,
+ const float screen_co_a[2], const float screen_co_b[2],
+ int index)
{
- struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } *data = userData;
- int distance;
+ struct NearestEdgeUserData *data = userData;
+ float dist_test, dist_test_bias;
- distance = dist_to_line_segment_v2(data->mval_fl, screen_co_a, screen_co_b);
-
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- distance += 5;
+ float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
+ float screen_co[2];
+
+ if (fac <= 0.0f) {
+ fac = 0.0f;
+ copy_v2_v2(screen_co, screen_co_a);
+ }
+ else if (fac >= 1.0f) {
+ fac = 1.0f;
+ copy_v2_v2(screen_co, screen_co_b);
+ }
+ else {
+ interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
}
- if (distance < data->dist) {
- if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
- float lambda = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
- float vec[3];
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
- vec[0] = eed->v1->co[0] + lambda * (eed->v2->co[0] - eed->v1->co[0]);
- vec[1] = eed->v1->co[1] + lambda * (eed->v2->co[1] - eed->v1->co[1]);
- vec[2] = eed->v1->co[2] + lambda * (eed->v2->co[2] - eed->v1->co[2]);
+ if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
+ }
- if (ED_view3d_clipping_test(data->vc.rv3d, vec, true) == 0) {
- data->dist = distance;
- data->closest = eed;
- }
+ if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
+ if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
+ return;
}
- else {
- data->dist = distance;
- data->closest = eed;
+ }
+
+ if (dist_test_bias < data->hit.dist_bias) {
+ float screen_co_mid[2];
+
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.edge = eed;
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
+ }
+
+ if (data->use_cycle) {
+ if ((data->hit_cycle.edge == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ float screen_co_mid[2];
+
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.edge = eed;
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
}
}
}
-BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist)
+
+BMEdge *EDBM_edge_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ BMEdge **r_eed_zbuf)
{
+ BMesh *bm = vc->em->bm;
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- float distance;
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
+ float dist_test = 0.0f;
unsigned int index;
BMEdge *eed;
- view3d_validate_backbuf(vc);
-
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance, 0, NULL, NULL);
- eed = index ? BM_edge_at_index_find(vc->em->bm, index - 1) : NULL;
-
- if (eed && distance < *r_dist) {
- *r_dist = distance;
- return eed;
+ ED_view3d_backbuf_validate(vc);
+
+ index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
+ eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
+
+ if (r_eed_zbuf) {
+ *r_eed_zbuf = eed;
}
- else {
- return NULL;
+
+ /* exception for faces (verts don't need this) */
+ if (r_dist_center && eed) {
+ struct NearestEdgeUserData_ZBuf data;
+
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
+ data.dist = FLT_MAX;
+ data.edge_test = eed;
+
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenEdge(vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ *r_dist_center = data.dist;
+ }
+ /* end exception */
+
+ if (eed) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
+ return eed;
+ }
}
+ return NULL;
}
else {
- struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } data;
+ struct NearestEdgeUserData data = {{0}};
+ const struct NearestEdgeUserData_Hit *hit;
+ /* interpolate along the edge before doing a clipping plane test */
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB;
+
+ static int prev_select_index = 0;
+ static const BMEdge *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
+ }
data.vc = *vc;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.dist = *r_dist;
- data.closest = NULL;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
+
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag);
- mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, V3D_PROJ_TEST_CLIP_WIN);
+ hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
+ if (r_dist_center) {
+ *r_dist_center = hit->dist_center;
+ }
+
+ prev_select_elem = hit->edge;
+ prev_select_index = hit->index;
- *r_dist = data.dist;
- return data.closest;
+ return hit->edge;
}
}
-static void findnearestface__getDistance(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
+BMEdge *EDBM_edge_find_nearest(
+ ViewContext *vc, float *r_dist)
+{
+ return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
+}
+
+/* find the distance to the face we already have */
+struct NearestFaceUserData_ZBuf {
+ float mval_fl[2];
+ float dist;
+ const BMFace *face_test;
+};
+
+static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
{
- struct { float mval_fl[2]; float dist; BMFace *toFace; } *data = userData;
+ struct NearestFaceUserData_ZBuf *data = userData;
- if (efa == data->toFace) {
+ if (efa == data->face_test) {
const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
if (dist_test < data->dist) {
@@ -548,96 +725,152 @@ static void findnearestface__getDistance(void *userData, BMFace *efa, const floa
}
}
}
+
+
+struct NearestFaceUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMFace *face;
+};
+
+struct NearestFaceUserData {
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestFaceUserData_Hit hit;
+ struct NearestFaceUserData_Hit hit_cycle;
+};
+
static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
{
- struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
+ struct NearestFaceUserData *data = userData;
+ float dist_test, dist_test_bias;
- if (data->pass == 0) {
- if (index <= data->lastIndex)
- return;
- }
- else {
- if (index > data->lastIndex)
- return;
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
+
+ if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
- if (data->dist > 3) {
- const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
+ if (dist_test_bias < data->hit.dist_bias) {
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.face = efa;
+ }
- if (dist_test < data->dist) {
- data->dist = dist_test;
- data->closest = efa;
- data->closestIndex = index;
+ if (data->use_cycle) {
+ if ((data->hit_cycle.face == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.face = efa;
}
}
}
-BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
+
+BMFace *EDBM_face_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ BMFace **r_efa_zbuf)
{
+ BMesh *bm = vc->em->bm;
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ float dist_test = 0.0f;
unsigned int index;
BMFace *efa;
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
- index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
- efa = index ? BM_face_at_index_find(vc->em->bm, index - 1) : NULL;
+ index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
+ efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
- if (efa) {
- struct { float mval_fl[2]; float dist; BMFace *toFace; } data;
+ if (r_efa_zbuf) {
+ *r_efa_zbuf = efa;
+ }
+
+ /* exception for faces (verts don't need this) */
+ if (r_dist_center && efa) {
+ struct NearestFaceUserData_ZBuf data;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
data.dist = FLT_MAX;
- data.toFace = efa;
+ data.face_test = efa;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__getDistance, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenFace(vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
- if ((vc->em->selectmode == SCE_SELECT_FACE) || (data.dist < *r_dist)) { /* only faces, no dist check */
- *r_dist = data.dist;
+ *r_dist_center = data.dist;
+ }
+ /* end exception */
+
+ if (efa) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
return efa;
}
}
-
return NULL;
}
else {
- struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } data;
- static int lastSelectedIndex = 0;
- static BMFace *lastSelected = NULL;
+ struct NearestFaceUserData data = {{0}};
+ const struct NearestFaceUserData_Hit *hit;
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
+
+ static int prev_select_index = 0;
+ static const BMFace *prev_select_elem = NULL;
- if (lastSelected && BM_face_at_index_find(vc->em->bm, lastSelectedIndex) != lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
}
- data.lastIndex = lastSelectedIndex;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.dist = *r_dist;
- data.closest = NULL;
- data.closestIndex = 0;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
- data.pass = 0;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag);
- if (data.dist > 3.0f) {
- data.pass = 1;
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
+ if (r_dist_center) {
+ *r_dist_center = hit->dist;
}
- *r_dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
+ prev_select_elem = hit->face;
+ prev_select_index = hit->index;
- return data.closest;
+ return hit->face;
}
}
+BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
+{
+ return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
+}
+
+#undef FIND_NEAR_SELECT_BIAS
+#undef FIND_NEAR_CYCLE_THRESHOLD_MIN
+
+
/* best distance based on screen coords.
* use em->selectmode to define how to use
* selected vertices and edges get disadvantage
@@ -646,35 +879,78 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
BMEditMesh *em = vc->em;
- float dist = ED_view3d_select_dist_px();
-
- *r_eve = NULL;
- *r_eed = NULL;
- *r_efa = NULL;
+ static short mval_prev[2] = {-1, -1};
+ /* only cycle while the mouse remains still */
+ const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
+ const float dist_init = ED_view3d_select_dist_px();
+ /* since edges select lines, we give dots advantage of ~20 pix */
+ const float dist_margin = (dist_init / 2);
+ float dist = dist_init;
+ BMFace *efa_zbuf = NULL;
+ BMEdge *eed_zbuf = NULL;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
+
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(vc);
-
- if (em->selectmode & SCE_SELECT_VERTEX)
- *r_eve = EDBM_vert_find_nearest(vc, &dist, BM_ELEM_SELECT, 0);
- if (em->selectmode & SCE_SELECT_FACE)
- *r_efa = EDBM_face_find_nearest(vc, &dist);
+ ED_view3d_backbuf_validate(vc);
+
+ if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
+ float dist_center = 0.0f;
+ float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
+ efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
+ if (efa && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ }
- dist -= 20; /* since edges select lines, we give dots advantage of 20 pix */
- if (em->selectmode & SCE_SELECT_EDGE)
- *r_eed = EDBM_edge_find_nearest(vc, &dist);
+ if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
+ float dist_center = 0.0f;
+ float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
+ eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
+ if (eed && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ }
+
+ if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
+ eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
+ }
/* return only one of 3 pointers, for frontbuffer redraws */
- if (*r_eed) {
- *r_efa = NULL; *r_eve = NULL;
+ if (eve) {
+ efa = NULL; eed = NULL;
}
- else if (*r_efa) {
- *r_eve = NULL;
+ else if (eed) {
+ efa = NULL;
}
-
- return (*r_eve || *r_eed || *r_efa);
+
+ /* there may be a face under the cursor, who's center if too far away
+ * use this if all else fails, it makes sense to select this */
+ if ((eve || eed || efa) == 0) {
+ if (eed_zbuf) {
+ eed = eed_zbuf;
+ }
+ else if (efa_zbuf) {
+ efa = efa_zbuf;
+ }
+ }
+
+ mval_prev[0] = vc->mval[0];
+ mval_prev[1] = vc->mval[1];
+
+ *r_eve = eve;
+ *r_eed = eed;
+ *r_efa = efa;
+
+ return (eve || eed || efa);
}
+/** \} */
+
+
/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
static EnumPropertyItem prop_similar_compare_types[] = {
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
@@ -709,6 +985,7 @@ static EnumPropertyItem prop_similar_types[] = {
{SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
{SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
{SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+ {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""},
#ifdef WITH_FREESTYLE
{SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
#endif
@@ -886,7 +1163,7 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUS
#ifdef WITH_FREESTYLE
const int a_end = SIMFACE_FREESTYLE;
#else
- const int a_end = SIMFACE_COPLANAR;
+ const int a_end = SIMFACE_SMOOTH;
#endif
for (a = SIMFACE_MATERIAL; a <= a_end; a++) {
RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
@@ -899,7 +1176,7 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUS
return item;
}
- return NULL;
+ return prop_similar_types;
}
void MESH_OT_select_similar(wmOperatorType *ot)
@@ -925,7 +1202,98 @@ void MESH_OT_select_similar(wmOperatorType *ot)
RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
- RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold", "", 0.0, 1.0);
+ RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Select Similar Regions */
+
+static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ bool changed = false;
+
+ /* group vars */
+ int *groups_array;
+ int (*group_index)[2];
+ int group_tot;
+ int i;
+
+ if (bm->totfacesel < 2) {
+ BKE_report(op->reports, RPT_ERROR, "No face regions selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
+ group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index,
+ NULL, NULL,
+ BM_ELEM_SELECT, BM_VERT);
+
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ for (i = 0; i < group_tot; i++) {
+ ListBase faces_regions;
+ int tot;
+
+ const int fg_sta = group_index[i][0];
+ const int fg_len = group_index[i][1];
+ int j;
+ BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__);
+
+
+ for (j = 0; j < fg_len; j++) {
+ fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
+ }
+
+ tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions);
+
+ MEM_freeN(fg);
+
+ if (tot) {
+ LinkData *link;
+ while ((link = BLI_pophead(&faces_regions))) {
+ BMFace *f, **faces = link->data;
+ unsigned int i = 0;
+ while ((f = faces[i++])) {
+ BM_face_select_set(bm, f, true);
+ }
+ MEM_freeN(faces);
+ MEM_freeN(link);
+
+ changed = true;
+ }
+ }
+ }
+
+ MEM_freeN(groups_array);
+ MEM_freeN(group_index);
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_similar_region(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar Regions";
+ ot->idname = "MESH_OT_select_similar_region";
+ ot->description = "Select similar face regions to the current selection";
+
+ /* api callbacks */
+ ot->exec = edbm_select_similar_region_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -1090,7 +1458,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
else {
for (edindex = 0; edindex < totedgesel; edindex += 1) {
eed = edarray[edindex];
- walker_select(em, BMW_LOOP, eed, true);
+ walker_select(em, BMW_EDGELOOP, eed, true);
}
EDBM_selectmode_flush(em);
}
@@ -1148,12 +1516,12 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
{
bool edge_boundary = false;
- /* cycle between BMW_LOOP / BMW_EDGEBOUNDARY */
+ /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY */
if (select_cycle && BM_edge_is_boundary(eed)) {
int tot[2];
/* if the loops selected toggle the boundaries */
- walker_select_count(em, BMW_LOOP, eed, select, false,
+ walker_select_count(em, BMW_EDGELOOP, eed, select, false,
&tot[0], &tot[1]);
if (tot[select] == 0) {
edge_boundary = true;
@@ -1175,7 +1543,7 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
walker_select(em, BMW_EDGEBOUNDARY, eed, select);
}
else {
- walker_select(em, BMW_LOOP, eed, select);
+ walker_select(em, BMW_EDGELOOP, eed, select);
}
}
@@ -1197,9 +1565,9 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
em = vc.em;
/* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
- view3d_validate_backbuf(&vc);
+ ED_view3d_backbuf_validate(&vc);
- eed = EDBM_edge_find_nearest(&vc, &dist);
+ eed = EDBM_edge_find_nearest_ex(&vc, &dist, NULL, true, true, NULL);
if (eed == NULL) {
return false;
}
@@ -1645,7 +2013,7 @@ void EDBM_selectmode_set(BMEditMesh *em)
/**
* Expand & Contract the Selection
- * (used when chaning modes and Ctrl key held)
+ * (used when changing modes and Ctrl key held)
*
* Flush the selection up:
* - vert -> edge
@@ -1953,7 +2321,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
ok = true;
BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
- if (BM_edge_face_count(eed) < 3) {
+ if (!BM_edge_face_count_is_over(eed, 2)) {
ok = false;
break;
}
@@ -1971,16 +2339,107 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
/************************ Select Linked Operator *************************/
-static void linked_limit_default(bContext *C, wmOperator *op)
+struct DelimitData {
+ int cd_loop_type;
+ int cd_loop_offset;
+};
+
+static bool select_linked_delimit_test(
+ BMEdge *e, int delimit,
+ const struct DelimitData *delimit_data)
{
- if (!RNA_struct_property_is_set(op->ptr, "limit")) {
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->selectmode == SCE_SELECT_FACE)
- RNA_boolean_set(op->ptr, "limit", true);
- else
- RNA_boolean_set(op->ptr, "limit", false);
+ BLI_assert(delimit);
+
+ if (delimit & BMO_DELIM_SEAM) {
+ if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_SHARP) {
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_NORMAL) {
+ if (!BM_edge_is_contiguous(e)) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_MATERIAL) {
+ if (e->l && e->l->radial_next != e->l) {
+ const short mat_nr = e->l->f->mat_nr;
+ BMLoop *l_iter = e->l->radial_next;
+ do {
+ if (l_iter->f->mat_nr != mat_nr) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+
+ if (delimit & BMO_DELIM_UV) {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
+ return true;
+ }
}
+
+ return false;
+}
+
+static void select_linked_delimit_validate(BMesh *bm, int *delimit)
+{
+ if ((*delimit) & BMO_DELIM_UV) {
+ if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) {
+ (*delimit) &= ~BMO_DELIM_UV;
+ }
+ }
+}
+
+static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit)
+{
+ struct DelimitData delimit_data = {0};
+
+ BMIter iter;
+ BMEdge *e;
+
+ if (delimit & BMO_DELIM_UV) {
+ delimit_data.cd_loop_type = CD_MLOOPUV;
+ delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
+ if (delimit_data.cd_loop_offset == -1) {
+ delimit &= ~BMO_DELIM_UV;
+ }
+ }
+
+ /* grr, shouldn't need to alloc BMO flags here */
+ BM_mesh_elem_toolflags_ensure(bm);
+ if (selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ const bool is_walk_ok = (
+ (select_linked_delimit_test(e, delimit, &delimit_data) == false));
+
+ BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ }
+ }
+ else {
+ /* don't delimit selected edges in vert/edge mode */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ const bool is_walk_ok = (
+ BM_elem_flag_test(e, BM_ELEM_SELECT) ||
+ (select_linked_delimit_test(e, delimit, &delimit_data) == false));
+
+ BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ }
+ }
+}
+
+static void select_linked_delimit_end(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ BM_mesh_elem_toolflags_clear(bm);
}
static int edbm_select_linked_exec(bContext *C, wmOperator *op)
@@ -1989,72 +2448,141 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMIter iter;
- BMEdge *e;
BMWalker walker;
- int limit;
+ int delimit = RNA_enum_get(op->ptr, "delimit");
- linked_limit_default(C, op);
+ select_linked_delimit_validate(bm, &delimit);
- limit = RNA_boolean_get(op->ptr, "limit");
+ if (delimit) {
+ select_linked_delimit_begin(em->bm, em->selectmode, delimit);
+ }
- if (em->selectmode == SCE_SELECT_FACE) {
- BMFace *efa;
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_set(efa, BM_ELEM_TAG, BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
}
- if (limit) {
- /* grr, shouldn't need to alloc BMO flags here */
- BM_mesh_elem_toolflags_ensure(bm);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, !BM_elem_flag_test(e, BM_ELEM_SEAM));
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, v) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(em->bm, v_step, true);
+ BM_elem_flag_disable(v_step, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, v) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
+ }
}
}
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, limit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
+
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
- BM_face_select_set(bm, efa, true);
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (delimit) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, e) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMLoop *l_step = (BMLoop *)ele_walk;
+ BM_edge_select_set(em->bm, l_step->e, true);
+ BM_edge_select_set(em->bm, l_step->prev->e, true);
+ BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, e) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
}
}
}
+
BMW_end(&walker);
- if (limit) {
- BM_mesh_elem_toolflags_clear(bm);
- }
+ EDBM_selectmode_flush(em);
}
else {
- BMVert *v;
+ BMFace *f;
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
}
- BMW_init(&walker, em->bm, BMW_VERT_SHELL,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- for (e = BMW_begin(&walker, v); e; e = BMW_step(&walker)) {
- BM_edge_select_set(em->bm, e, true);
- BM_elem_flag_disable(e, BM_ELEM_TAG);
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, f) {
+ BM_face_select_set(bm, f_walk, true);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
}
}
}
+
BMW_end(&walker);
+ }
- EDBM_selectmode_flush(em);
+ if (delimit) {
+ select_linked_delimit_end(em);
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2076,99 +2604,211 @@ void MESH_OT_select_linked(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+}
+
+static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
+
+static void edbm_select_linked_pick_ex(
+ BMEditMesh *em,
+ BMVert *eve, BMEdge *eed, BMFace *efa,
+ bool sel, int delimit)
+{
+ BMesh *bm = em->bm;
+ BMWalker walker;
+
+ select_linked_delimit_validate(bm, &delimit);
+
+ if (delimit) {
+ select_linked_delimit_begin(bm, em->selectmode, delimit);
+ }
+
+ /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
+
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+
+ BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, eve) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(bm, v_step, sel);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ }
+ }
+ else {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, eve) {
+ BM_edge_select_set(bm, e_walk, sel);
+ }
+ }
+
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+
+ BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, eed) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMEdge *e_step = ((BMLoop *)ele_walk)->e;
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ }
+ }
+ else {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, eed) {
+ BM_edge_select_set(bm, e_walk, sel);
+ }
+ }
+
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, efa) {
+ BM_face_select_set(bm, f_walk, sel);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
+ }
+ }
+
+ BMW_end(&walker);
+ }
+
+ if (delimit) {
+ select_linked_delimit_end(em);
+ }
}
static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
- BMesh *bm;
- BMWalker walker;
BMEditMesh *em;
+ BMesh *bm;
BMVert *eve;
- BMEdge *e, *eed;
+ BMEdge *eed;
BMFace *efa;
const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
+ int index;
- int limit;
-
- linked_limit_default(C, op);
-
- limit = RNA_boolean_get(op->ptr, "limit");
+ if (RNA_struct_property_is_set(op->ptr, "index")) {
+ return edbm_select_linked_pick_exec(C, op);
+ }
/* unified_finednearest needs ogl */
view3d_operator_needs_opengl(C);
-
+
/* setup view context for argument to callbacks */
em_setup_viewcontext(C, &vc);
em = vc.em;
+ bm = em->bm;
- if (em->bm->totedge == 0)
+ if (bm->totedge == 0) {
return OPERATOR_CANCELLED;
-
- bm = em->bm;
+ }
vc.mval[0] = event->mval[0];
vc.mval[1] = event->mval[1];
-
+
/* return warning! */
-
if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
-
+
return OPERATOR_CANCELLED;
}
-
- if (em->selectmode == SCE_SELECT_FACE) {
- BMIter iter;
- if (efa == NULL)
- return OPERATOR_CANCELLED;
+ edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
- if (limit) {
- /* grr, shouldn't need to alloc BMO flags here */
- BM_mesh_elem_toolflags_ensure(bm);
- /* hflag no-seam --> bmo-tag */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, !BM_elem_flag_test(e, BM_ELEM_SEAM));
- }
- }
-
- /* walk */
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, limit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
-
- for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
- BM_face_select_set(bm, efa, sel);
- }
- BMW_end(&walker);
+ /* to support redo */
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ index = BM_elem_index_get(eve);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+ BM_mesh_elem_index_ensure(bm, BM_EDGE);
+ index = BM_elem_index_get(eed) + bm->totvert;
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ index = BM_elem_index_get(efa) + bm->totvert + bm->totedge;
}
else {
- if (efa) {
- eed = BM_FACE_FIRST_LOOP(efa)->e;
- }
- else if (!eed) {
- if (!eve || !eve->e)
- return OPERATOR_CANCELLED;
+ index = -1;
+ }
- eed = eve->e;
- }
+ RNA_int_set(op->ptr, "index", index);
- BMW_init(&walker, bm, BMW_VERT_SHELL,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
- for (e = BMW_begin(&walker, eed->v1); e; e = BMW_step(&walker)) {
- BM_edge_select_set(bm, e, sel);
- }
- BMW_end(&walker);
+ return OPERATOR_FINISHED;
+}
- EDBM_selectmode_flush(em);
+
+static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int index;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+ const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
+
+ index = RNA_int_get(op->ptr, "index");
+ if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (index < bm->totvert) {
+ eve = BM_vert_at_index_find_or_table(bm, index);
+ }
+ else if (index < (bm->totvert + bm->totedge)) {
+ index -= bm->totvert;
+ eed = BM_edge_at_index_find_or_table(bm, index);
}
+ else if (index < (bm->totvert + bm->totedge + bm->totface)) {
+ index -= (bm->totvert + bm->totedge);
+ efa = BM_face_at_index_find_or_table(bm, index);
+ }
+
+ edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2177,6 +2817,8 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
void MESH_OT_select_linked_pick(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Select Linked";
ot->idname = "MESH_OT_select_linked_pick";
@@ -2184,13 +2826,19 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_select_linked_pick_invoke;
+ ot->exec = edbm_select_linked_pick_exec;
ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+
+ /* use for redo */
+ prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -2381,12 +3029,13 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
/* ******************** **************** */
-static int edbm_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+static int edbm_select_more_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
- EDBM_select_more(em);
+ EDBM_select_more(em, use_face_step);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
return OPERATOR_FINISHED;
@@ -2405,14 +3054,17 @@ void MESH_OT_select_more(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
}
-static int edbm_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+static int edbm_select_less_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
- EDBM_select_less(em);
+ EDBM_select_less(em, use_face_step);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
return OPERATOR_FINISHED;
@@ -2431,6 +3083,8 @@ void MESH_OT_select_less(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
}
/**
@@ -2457,7 +3111,7 @@ static bool bm_edge_is_select_isolated(BMEdge *e)
/* Walk all reachable elements of the same type as h_act in breadth-first
* order, starting from h_act. Deselects elements if the depth when they
* are reached is not a multiple of "nth". */
-static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
+static void walker_deselect_nth(BMEditMesh *em, int nth, int skip, int offset, BMHeader *h_act)
{
BMElem *ele;
BMesh *bm = em->bm;
@@ -2523,7 +3177,8 @@ static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h
for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
/* Deselect elements that aren't at "nth" depth from active */
- if ((offset + BMW_current_depth(&walker)) % nth) {
+ const int depth = BMW_current_depth(&walker) - 1;
+ if ((offset + depth) % (skip + nth) >= skip) {
BM_elem_select_set(bm, ele, false);
}
BM_elem_flag_enable(ele, BM_ELEM_TAG);
@@ -2590,7 +3245,7 @@ static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed,
}
}
-static bool edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
+static bool edbm_deselect_nth(BMEditMesh *em, int nth, int skip, int offset)
{
BMVert *v;
BMEdge *e;
@@ -2599,15 +3254,15 @@ static bool edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
deselect_nth_active(em, &v, &e, &f);
if (v) {
- walker_deselect_nth(em, nth, offset, &v->head);
+ walker_deselect_nth(em, nth, skip, offset, &v->head);
return true;
}
else if (e) {
- walker_deselect_nth(em, nth, offset, &e->head);
+ walker_deselect_nth(em, nth, skip, offset, &e->head);
return true;
}
else if (f) {
- walker_deselect_nth(em, nth, offset, &f->head);
+ walker_deselect_nth(em, nth, skip, offset, &f->head);
return true;
}
@@ -2618,15 +3273,14 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int nth = RNA_int_get(op->ptr, "nth");
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
int offset = RNA_int_get(op->ptr, "offset");
/* so input of offset zero ends up being (nth - 1) */
- offset = mod_i(offset, nth);
- /* depth starts at 1, this keeps active item selected */
- offset -= 1;
+ offset = mod_i(offset, nth + skip);
- if (edbm_deselect_nth(em, nth, offset) == false) {
+ if (edbm_deselect_nth(em, nth, skip, offset) == false) {
BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
return OPERATOR_CANCELLED;
}
@@ -2652,6 +3306,7 @@ void MESH_OT_select_nth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
}
@@ -2842,7 +3497,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
if ((use_wire && BM_edge_is_wire(e)) ||
(use_boundary && BM_edge_is_boundary(e)) ||
(use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
- (use_multi_face && (BM_edge_face_count(e) > 2)))
+ (use_multi_face && (BM_edge_face_count_is_over(e, 2))))
{
/* check we never select perfect edge (in test above) */
BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
@@ -2952,8 +3607,8 @@ void MESH_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
- "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
+ RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f,
+ "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
WM_operator_properties_select_action_simple(ot, SEL_SELECT);
}
@@ -3041,7 +3696,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op)
else {
BMVert *v;
BMIter iter;
- const float limit = CTX_data_tool_settings(C)->doublimit; // XXX
+ const float limit = RNA_float_get(op->ptr, "threshold");
float value = v_act->co[axis];
if (mode == 0)
@@ -3106,6 +3761,7 @@ void MESH_OT_select_axis(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
+ RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
}
@@ -3267,8 +3923,8 @@ static int loop_find_region(BMLoop *l, int flag,
static int verg_radial(const void *va, const void *vb)
{
- BMEdge *e_a = *((BMEdge **)va);
- BMEdge *e_b = *((BMEdge **)vb);
+ const BMEdge *e_a = *((const BMEdge **)va);
+ const BMEdge *e_b = *((const BMEdge **)vb);
int a, b;
a = BM_edge_face_count(e_a);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 3f1023b7fb4..d3937188358 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -55,7 +55,7 @@
#include "BKE_main.h"
#include "BKE_editmesh.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -90,13 +90,13 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
if (RNA_boolean_get(op->ptr, "quadtri") &&
- RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
+ RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT)
{
- RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
+ RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
}
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_ROOT, false,
+ smooth, SUBD_FALLOFF_INVSQUARE, false,
fractal, along_normal,
cuts,
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
@@ -110,10 +110,10 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
/* Note, these values must match delete_mesh() event values */
static EnumPropertyItem prop_mesh_cornervert_types[] = {
- {SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
- {SUBD_PATH, "PATH", 0, "Path", ""},
- {SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
- {SUBD_FAN, "FAN", 0, "Fan", ""},
+ {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
+ {SUBD_CORNER_PATH, "PATH", 0, "Path", ""},
+ {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
+ {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -134,19 +134,20 @@ void MESH_OT_subdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
- RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT,
+ RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT,
"Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
- RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f, "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
+ RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, 1e6f, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f,
+ "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255);
}
/* -------------------------------------------------------------------- */
@@ -176,24 +177,24 @@ static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_defa
PropertyRNA *prop;
- prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, INT_MAX, "Number of Cuts", "", 0, 64);
+ prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", 0, 64);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
"Interpolation", "Interpolation method");
- RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, FLT_MAX,
+ RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1e3f,
"Smoothness", "Smoothness factor", 0.0f, 2.0f);
/* profile-shape */
- RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -FLT_MAX, FLT_MAX,
- "Profile Factor", "", -2.0f, 2.0f);
+ RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -1e3f, 1e3f,
+ "Profile Factor", "How much intermediary new edges are shrunk/expanded", -2.0f, 2.0f);
prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
RNA_def_property_enum_default(prop, PROP_SMOOTH);
RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
- RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
}
static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props)
@@ -289,7 +290,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "iterations", 2, 1, INT_MAX, "Iterations", "Number of times to unsubdivide", 1, 100);
+ RNA_def_int(ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100);
}
void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
@@ -313,6 +314,16 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
}
}
+
+/* Note, these values must match delete_mesh() event values */
+enum {
+ MESH_DELETE_VERT = 0,
+ MESH_DELETE_EDGE = 1,
+ MESH_DELETE_FACE = 2,
+ MESH_DELETE_EDGE_FACE = 3,
+ MESH_DELETE_ONLY_FACE = 4,
+};
+
static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
{
BKE_reportf(reports, RPT_INFO,
@@ -320,45 +331,38 @@ static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int to
totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
}
-/* Note, these values must match delete_mesh() event values */
-static EnumPropertyItem prop_mesh_delete_types[] = {
- {0, "VERT", 0, "Vertices", ""},
- {1, "EDGE", 0, "Edges", ""},
- {2, "FACE", 0, "Faces", ""},
- {3, "EDGE_FACE", 0, "Only Edges & Faces", ""},
- {4, "ONLY_FACE", 0, "Only Faces", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
static int edbm_delete_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
- if (type == 0) {
- if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
- return OPERATOR_CANCELLED;
- }
- else if (type == 1) {
- if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
- return OPERATOR_CANCELLED;
- }
- else if (type == 2) {
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
- return OPERATOR_CANCELLED;
- }
- else if (type == 3) {
- if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) /* Edges and Faces */
- return OPERATOR_CANCELLED;
- }
- else if (type == 4) {
- //"Erase Only Faces";
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i",
- BM_ELEM_SELECT, DEL_ONLYFACES))
- {
- return OPERATOR_CANCELLED;
- }
+ switch (type) {
+ case MESH_DELETE_VERT:
+ if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_EDGE:
+ if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_FACE:
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_EDGE_FACE:
+ /* Edges and Faces */
+ if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_ONLY_FACE:
+ /* Only faces. */
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))
+ return OPERATOR_CANCELLED;
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -370,6 +374,15 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
void MESH_OT_delete(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_mesh_delete_types[] = {
+ {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""},
+ {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""},
+ {MESH_DELETE_FACE, "FACE", 0, "Faces", ""},
+ {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
+ {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Delete";
ot->description = "Delete selected vertices, edges or faces";
@@ -385,7 +398,8 @@ void MESH_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 0, "Type", "Method used for deleting mesh data");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, MESH_DELETE_VERT,
+ "Type", "Method used for deleting mesh data");
}
@@ -492,7 +506,7 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
+ if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true))
return OPERATOR_CANCELLED;
EDBM_update_generic(em, true, true);
@@ -877,23 +891,49 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMOperator bmop;
- const bool is_pair = (bm->totvertsel == 2);
- int len;
-
+ bool is_pair = (bm->totvertsel == 2);
+ int len = 0;
+ bool check_degenerate = true;
+ const int verts_len = bm->totvertsel;
+ BMVert **verts;
+
+ verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__);
+ {
+ BMIter iter;
+ BMVert *v;
+ int i = 0;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ verts[i++] = v;
+ }
+ }
+
+ if (is_pair) {
+ if (BM_vert_pair_share_face_check_cb(
+ verts[0], verts[1],
+ BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN)))
+ {
+ check_degenerate = false;
+ is_pair = false;
+ }
+ }
+ }
+
if (is_pair) {
if (!EDBM_op_init(em, &bmop, op,
- "connect_vert_pair verts=%hv verts_exclude=%hv faces_exclude=%hf",
- BM_ELEM_SELECT, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
+ "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
+ verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
{
- return OPERATOR_CANCELLED;
+ goto finally;
}
}
else {
if (!EDBM_op_init(em, &bmop, op,
- "connect_verts verts=%hv faces_exclude=%hf check_degenerate=%b",
- BM_ELEM_SELECT, BM_ELEM_HIDDEN, true))
+ "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
+ verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
{
- return OPERATOR_CANCELLED;
+ goto finally;
}
}
@@ -908,15 +948,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
}
if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ len = 0;
}
else {
EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */
EDBM_update_generic(em, true, true);
-
- return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+
+
+finally:
+ MEM_freeN(verts);
+ return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void MESH_OT_vert_connect(wmOperatorType *ot)
@@ -924,7 +967,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
/* identifiers */
ot->name = "Vertex Connect";
ot->idname = "MESH_OT_vert_connect";
- ot->description = "Connect 2 vertices of a face by an edge, splitting the face in two";
+ ot->description = "Connect selected vertices of faces, splitting the face";
/* api callbacks */
ot->exec = edbm_vert_connect_exec;
@@ -935,6 +978,308 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
}
+/**
+ * check that endpoints are verts and only have a single selected edge connected.
+ */
+static bool bm_vert_is_select_history_open(BMesh *bm)
+{
+ BMEditSelection *ele_a = bm->selected.first;
+ BMEditSelection *ele_b = bm->selected.last;
+ if ((ele_a->htype == BM_VERT) &&
+ (ele_b->htype == BM_VERT))
+ {
+ if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == 1) &&
+ (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == 1))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b)
+{
+ BMOperator bmop;
+ BMVert **verts;
+ const int totedge_orig = bm->totedge;
+
+ BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair");
+
+ verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2);
+ verts[0] = v_a;
+ verts[1] = v_b;
+
+ BM_vert_normal_update(verts[0]);
+ BM_vert_normal_update(verts[1]);
+
+ BMO_op_exec(bm, &bmop);
+ BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ BMO_op_finish(bm, &bmop);
+ return (bm->totedge != totedge_orig);
+}
+
+static bool bm_vert_connect_select_history(BMesh *bm)
+{
+ /* Logic is as follows:
+ *
+ * - If there are any isolated/wire verts - connect as edges.
+ * - Otherwise connect faces.
+ * - If all edges have been created already, closed the loop.
+ */
+ if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
+ BMEditSelection *ese;
+ int tot = 0;
+ bool changed = false;
+ bool has_wire = false;
+ // bool all_verts;
+
+ /* ensure all verts have history */
+ for (ese = bm->selected.first; ese; ese = ese->next, tot++) {
+ BMVert *v;
+ if (ese->htype != BM_VERT) {
+ break;
+ }
+ v = (BMVert *)ese->ele;
+ if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) {
+ has_wire = true;
+ }
+ }
+ // all_verts = (ese == NULL);
+
+ if (has_wire == false) {
+ /* all verts have faces , connect verts via faces! */
+ if (tot == bm->totvertsel) {
+ BMEditSelection *ese_last;
+ ese_last = bm->selected.first;
+ ese = ese_last->next;
+
+ do {
+
+ if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) {
+ /* pass, edge exists (and will be selected) */
+ }
+ else {
+ changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele);
+ }
+ } while ((ese_last = ese),
+ (ese = ese->next));
+
+ if (changed) {
+ return true;
+ }
+ }
+
+ if (changed == false) {
+ /* existing loops: close the selection */
+ if (bm_vert_is_select_history_open(bm)) {
+ changed |= bm_vert_connect_pair(
+ bm,
+ (BMVert *)((BMEditSelection *)bm->selected.first)->ele,
+ (BMVert *)((BMEditSelection *)bm->selected.last)->ele);
+
+ if (changed) {
+ return true;
+ }
+ }
+ }
+ }
+
+ else {
+ /* no faces, simply connect the verts by edges */
+ BMEditSelection *ese_prev;
+ ese_prev = bm->selected.first;
+ ese = ese_prev->next;
+
+
+ do {
+ if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) {
+ /* pass, edge exists (and will be selected) */
+ }
+ else {
+ BMEdge *e;
+ e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
+ BM_edge_select_set(bm, e, true);
+ changed = true;
+ }
+ } while ((ese_prev = ese),
+ (ese = ese->next));
+
+ if (changed == false) {
+ /* existing loops: close the selection */
+ if (bm_vert_is_select_history_open(bm)) {
+ BMEdge *e;
+ ese_prev = bm->selected.first;
+ ese = bm->selected.last;
+ e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
+ BM_edge_select_set(bm, e, true);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Convert an edge selection to a temp vertex selection
+ * (which must be cleared after use as a path to connect).
+ */
+static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected)
+{
+ ListBase selected_orig = {NULL, NULL};
+ BMEditSelection *ese;
+ int edges_len = 0;
+ bool side = false;
+
+ /* first check all edges are OK */
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->htype == BM_EDGE) {
+ edges_len += 1;
+ }
+ else {
+ return false;
+ }
+ }
+ /* if this is a mixed selection, bail out! */
+ if (bm->totedgesel != edges_len) {
+ return false;
+ }
+
+ SWAP(ListBase, bm->selected, selected_orig);
+
+ /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
+ for (ese = selected_orig.first; ese; ese = ese->next) {
+ BMEdge *e_curr = (BMEdge *)ese->ele;
+ BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
+ BMLoop *l_curr;
+ BMLoop *l_prev;
+ BMVert *v;
+
+ if (e_prev) {
+ BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
+ if (f) {
+ if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
+ side = !side;
+ }
+ }
+ else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
+ side = !side;
+ }
+ }
+
+ v = (&e_curr->v1)[side];
+ if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
+ BM_select_history_store_notest(bm, v);
+ }
+
+ v = (&e_curr->v1)[!side];
+ if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
+ BM_select_history_store_head_notest(bm, v);
+ }
+
+ e_prev = e_curr;
+ }
+
+ *r_selected = bm->selected;
+ bm->selected = selected_orig;
+
+ return true;
+}
+
+static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ bool is_pair = (em->bm->totvertsel == 2);
+ ListBase selected_orig = {NULL, NULL};
+ int retval;
+
+ /* when there is only 2 vertices, we can ignore selection order */
+ if (is_pair) {
+ return edbm_vert_connect_exec(C, op);
+ }
+
+ if (bm->selected.first) {
+ BMEditSelection *ese = bm->selected.first;
+ if (ese->htype == BM_EDGE) {
+ if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
+ SWAP(ListBase, bm->selected, selected_orig);
+ }
+ }
+ }
+
+ if (bm_vert_connect_select_history(bm)) {
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, true, true);
+ retval = OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
+ retval = OPERATOR_CANCELLED;
+ }
+
+ if (!BLI_listbase_is_empty(&selected_orig)) {
+ BM_select_history_clear(bm);
+ bm->selected = selected_orig;
+ }
+
+ return retval;
+}
+
+void MESH_OT_vert_connect_path(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Connect Path";
+ ot->idname = "MESH_OT_vert_connect_path";
+ ot->description = "Connect vertices by their selection order, creating edges, splitting faces";
+
+ /* api callbacks */
+ ot->exec = edbm_vert_connect_path_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "connect_verts_concave faces=%hf",
+ BM_ELEM_SELECT))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vert_connect_concave(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split Concave Faces";
+ ot->idname = "MESH_OT_vert_connect_concave";
+ ot->description = "Make all faces convex";
+
+ /* api callbacks */
+ ot->exec = edbm_vert_connect_concave_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -978,6 +1323,43 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
}
+static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int repeat = RNA_int_get(op->ptr, "repeat");
+ const float fac = RNA_float_get(op->ptr, "factor");
+
+ if (!EDBM_op_callf(
+ em, op, "planar_faces faces=%hf iterations=%i factor=%f",
+ BM_ELEM_SELECT, repeat, fac))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_face_make_planar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Planar Faces";
+ ot->idname = "MESH_OT_face_make_planar";
+ ot->description = "Flatten selected faces";
+
+ /* api callbacks */
+ ot->exec = edbm_face_make_planar_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
+}
+
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
@@ -1212,7 +1594,7 @@ void MESH_OT_hide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
}
static int edbm_reveal_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1274,7 +1656,7 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+ RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
}
@@ -1288,7 +1670,8 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
bool mirrx = false, mirry = false, mirrz = false;
int i, repeat;
float clip_dist = 0.0f;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
@@ -1322,12 +1705,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
repeat = RNA_int_get(op->ptr, "repeat");
if (!repeat)
repeat = 1;
-
+
for (i = 0; i < repeat; i++) {
if (!EDBM_op_callf(em, op,
- "smooth_vert verts=%hv mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b clip_dist=%f "
- "use_axis_x=%b use_axis_y=%b use_axis_z=%b",
- BM_ELEM_SELECT, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
{
return OPERATOR_CANCELLED;
}
@@ -1358,10 +1741,11 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Number of times to smooth the mesh", "", 1, 100);
- RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis");
- RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis");
- RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
+ RNA_def_float(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
+ RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
+ RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
+ RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
}
static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
@@ -1436,16 +1820,16 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "repeat", 1, 1, 200,
+ RNA_def_int(ot->srna, "repeat", 1, 1, 1000,
"Number of iterations to smooth the mesh", "", 1, 200);
- RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f,
- "Lambda factor", "", 0.0000001f, 1000.0f);
- RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f,
- "Lambda factor in border", "", 0.0000001f, 1000.0f);
- RNA_def_boolean(ot->srna, "use_x", 1, "Smooth X Axis", "Smooth object along X axis");
- RNA_def_boolean(ot->srna, "use_y", 1, "Smooth Y Axis", "Smooth object along Y axis");
- RNA_def_boolean(ot->srna, "use_z", 1, "Smooth Z Axis", "Smooth object along Z axis");
- RNA_def_boolean(ot->srna, "preserve_volume", 1, "Preserve Volume", "Apply volume preservation after smooth");
+ RNA_def_float(ot->srna, "lambda_factor", 5e-5f, 1e-7f, 1000.0f,
+ "Lambda factor", "", 1e-7f, 1000.0f);
+ RNA_def_float(ot->srna, "lambda_border", 5e-5f, 1e-7f, 1000.0f,
+ "Lambda factor in border", "", 1e-7f, 1000.0f);
+ RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
+ RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
+ RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
+ RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth");
}
/********************** Smooth/Solid Operators *************************/
@@ -1690,6 +2074,14 @@ void MESH_OT_colors_reverse(wmOperatorType *ot)
}
+enum {
+ MESH_MERGE_LAST = 1,
+ MESH_MERGE_CENTER = 3,
+ MESH_MERGE_CURSOR = 4,
+ MESH_MERGE_COLLAPSE = 5,
+ MESH_MERGE_FIRST = 6,
+};
+
static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop)
{
BMVert *mergevert;
@@ -1786,22 +2178,20 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
bool ok = false;
switch (type) {
- case 3:
+ case MESH_MERGE_CENTER:
ok = merge_target(em, scene, v3d, obedit, false, uvs, op);
break;
- case 4:
+ case MESH_MERGE_CURSOR:
ok = merge_target(em, scene, v3d, obedit, true, uvs, op);
break;
- case 1:
+ case MESH_MERGE_LAST:
ok = merge_firstlast(em, false, uvs, op);
break;
- case 6:
+ case MESH_MERGE_FIRST:
ok = merge_firstlast(em, true, uvs, op);
break;
- case 5:
- ok = true;
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
- ok = false;
+ case MESH_MERGE_COLLAPSE:
+ ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
break;
default:
BLI_assert(0);
@@ -1814,15 +2204,20 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
EDBM_update_generic(em, true, true);
+ /* once collapsed, we can't have edge/face selection */
+ if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
+
return OPERATOR_FINISHED;
}
static EnumPropertyItem merge_type_items[] = {
- {6, "FIRST", 0, "At First", ""},
- {1, "LAST", 0, "At Last", ""},
- {3, "CENTER", 0, "At Center", ""},
- {4, "CURSOR", 0, "At Cursor", ""},
- {5, "COLLAPSE", 0, "Collapse", ""},
+ {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""},
+ {MESH_MERGE_LAST, "LAST", 0, "At Last", ""},
+ {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""},
+ {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""},
+ {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1844,20 +2239,20 @@ static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),
((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT)
{
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
}
else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
}
else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
}
}
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CENTER);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CURSOR);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_COLLAPSE);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1884,9 +2279,9 @@ void MESH_OT_merge(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use");
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
RNA_def_enum_funcs(ot->prop, merge_type_itemf);
- RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge");
+ RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
}
@@ -1962,9 +2357,9 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 0.00001, 10.0);
- RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
}
@@ -2158,9 +2553,9 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
RNA_def_enum_funcs(prop, shape_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
- RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK);
+ RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f);
+ RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
}
static int edbm_solidify_exec(bContext *C, wmOperator *op)
@@ -2213,8 +2608,8 @@ void MESH_OT_solidify(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
- RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
}
/* ******************************************************************** */
@@ -2507,7 +2902,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
if (mode == KNIFE_MIDPOINT) numcuts = 1;
BMO_slot_int_set(bmop.slots_in, "cuts", numcuts);
- BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_STRAIGHT_CUT);
+ BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT);
BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false);
BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
@@ -2547,9 +2942,18 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
}
+
+/* *************** Operator: separate parts *************/
+
+enum {
+ MESH_SEPARATE_SELECTED = 0,
+ MESH_SEPARATE_MATERIAL = 1,
+ MESH_SEPARATE_LOOSE = 2,
+};
+
static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
{
Base *base_new;
@@ -2679,7 +3083,7 @@ static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
}
if (mat_nr < *totcolp) {
- ma_obdata = (*matarar)[mat_nr];
+ ma_obdata = (*matarar)[mat_nr];
}
else {
ma_obdata = NULL;
@@ -2833,17 +3237,27 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
/* editmode separate */
- if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm);
- else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm);
- else if (type == 2) retval = mesh_separate_loose(bmain, scene, base, em->bm);
- else BLI_assert(0);
+ switch (type) {
+ case MESH_SEPARATE_SELECTED:
+ retval = mesh_separate_selected(bmain, scene, base, em->bm);
+ break;
+ case MESH_SEPARATE_MATERIAL:
+ retval = mesh_separate_material(bmain, scene, base, em->bm);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval = mesh_separate_loose(bmain, scene, base, em->bm);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (retval) {
EDBM_update_generic(em, true, true);
}
}
else {
- if (type == 0) {
+ if (type == MESH_SEPARATE_SELECTED) {
BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode");
return OPERATOR_CANCELLED;
}
@@ -2862,9 +3276,17 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
BM_mesh_bm_from_me(bm_old, me, false, false, 0);
- if (type == 1) retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
- else if (type == 2) retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
- else BLI_assert(0);
+ switch (type) {
+ case MESH_SEPARATE_MATERIAL:
+ retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (retval_iter) {
BM_mesh_bm_to_me(bm_old, me, false);
@@ -2893,17 +3315,15 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-/* *************** Operator: separate parts *************/
-
-static EnumPropertyItem prop_separate_types[] = {
- {0, "SELECTED", 0, "Selection", ""},
- {1, "MATERIAL", 0, "By Material", ""},
- {2, "LOOSE", 0, "By loose parts", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
void MESH_OT_separate(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_separate_types[] = {
+ {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""},
+ {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""},
+ {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By loose parts", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Separate";
ot->description = "Separate selected geometry into a new mesh";
@@ -2917,7 +3337,7 @@ void MESH_OT_separate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
}
@@ -2927,7 +3347,14 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
BMOperator bmop;
-
+ const int totface_orig = em->bm->totface;
+ int ret;
+
+ if (em->bm->totedgesel == 0) {
+ BKE_report(op->reports, RPT_WARNING, "No edges selected");
+ return OPERATOR_CANCELLED;
+ }
+
if (!EDBM_op_init(em, &bmop, op,
"triangle_fill edges=%he use_beauty=%b",
BM_ELEM_SELECT, use_beauty))
@@ -2937,17 +3364,24 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
BMO_op_exec(em->bm, &bmop);
- /* select new geometry */
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
-
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ if (totface_orig != em->bm->totface) {
+ /* select new geometry */
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
+
+ EDBM_update_generic(em, true, true);
+
+ ret = OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No faces filled");
+ ret = OPERATOR_CANCELLED;
}
- EDBM_update_generic(em, true, true);
-
- return OPERATOR_FINISHED;
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ ret = OPERATOR_CANCELLED;
+ }
+ return ret;
}
void MESH_OT_fill(wmOperatorType *ot)
@@ -2997,6 +3431,9 @@ static float edbm_fill_grid_vert_tag_angle(BMVert *v)
*/
static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc)
{
+ /* angle differences below this value are considered 'even'
+ * in that they shouldn't be used to calculate corners used for the 'span' */
+ const float eps_even = 1e-3f;
BMEdge *e;
BMIter iter;
int count;
@@ -3042,13 +3479,15 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
v_act = v_act_link->data;
}
+ /* set this vertex first */
+ BLI_listbase_rotate_first(verts, v_act_link);
+
if (offset != 0) {
v_act_link = BLI_findlink(verts, offset);
v_act = v_act_link->data;
+ BLI_listbase_rotate_first(verts, v_act_link);
}
- /* set this vertex first */
- BLI_listbase_rotate_first(verts, v_act_link);
BM_edgeloop_edges_get(el_store, edges);
@@ -3073,18 +3512,23 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse);
- for (i = 0; i < 4; i++) {
- BMVert *v = ele_sort[i].data;
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
+ /* check that we have at least 3 corners,
+ * if the angle on the 3rd angle is roughly the same as the last,
+ * then we can't calculate 3+ corners - fallback to the even span. */
+ if ((ele_sort[2].sort_value - ele_sort[verts_len - 1].sort_value) > eps_even) {
+ for (i = 0; i < 4; i++) {
+ BMVert *v = ele_sort[i].data;
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
- /* now find the first... */
- for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
- BMVert *v = v_link->data;
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- if (v != v_act) {
- span = i;
- break;
+ /* now find the first... */
+ for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
+ BMVert *v = v_link->data;
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (v != v_act) {
+ span = i;
+ break;
+ }
}
}
}
@@ -3196,11 +3640,11 @@ void MESH_OT_fill_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100);
+ prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of sides (zero disables)", 1, 100);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100);
+ prop = RNA_def_int(ot->srna, "offset", 0, -1000, 1000, "Offset", "Number of sides (zero disables)", -100, 100);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_boolean(ot->srna, "use_interp_simple", 0, "Simple Blending", "");
+ RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", "");
}
static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
@@ -3238,7 +3682,8 @@ void MESH_OT_fill_holes(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "sides", 4, 0, INT_MAX, "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
+ RNA_def_int(ot->srna, "sides", 4, 0, 1000,
+ "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
}
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
@@ -3358,9 +3803,10 @@ void MESH_OT_poke(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
+ RNA_def_float(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED, "Poke Center", "Poke Face Center Calculation");
+ RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED,
+ "Poke Center", "Poke Face Center Calculation");
}
/********************** Quad/Tri Operators *************************/
@@ -3414,19 +3860,45 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int dosharp, douvs, dovcols, domaterials;
- const float limit = RNA_float_get(op->ptr, "limit");
+ bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
+ float angle_face_threshold, angle_shape_threshold;
+ PropertyRNA *prop;
- dosharp = RNA_boolean_get(op->ptr, "sharp");
- douvs = RNA_boolean_get(op->ptr, "uvs");
- dovcols = RNA_boolean_get(op->ptr, "vcols");
- domaterials = RNA_boolean_get(op->ptr, "materials");
+ /* When joining exactly 2 faces, no limit.
+ * this is useful for one off joins while editing. */
+ prop = RNA_struct_find_property(op->ptr, "face_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_face_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_face_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "shape_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_shape_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ do_seam = RNA_boolean_get(op->ptr, "seam");
+ do_sharp = RNA_boolean_get(op->ptr, "sharp");
+ do_uvs = RNA_boolean_get(op->ptr, "uvs");
+ do_vcols = RNA_boolean_get(op->ptr, "vcols");
+ do_materials = RNA_boolean_get(op->ptr, "materials");
if (!EDBM_op_call_and_selectf(
em, op,
"faces.out", true,
- "join_triangles faces=%hf limit=%f cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
- BM_ELEM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
+ "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
+ "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
+ BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
+ do_seam, do_sharp, do_uvs, do_vcols, do_materials))
{
return OPERATOR_CANCELLED;
}
@@ -3440,14 +3912,21 @@ static void join_triangle_props(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
- "Max Angle", "Angle Limit", 0.0f, DEG2RADF(180.0f));
+ prop = RNA_def_float_rotation(
+ ot->srna, "face_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Face Angle", "Face angle limit", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(40.0f));
+
+ prop = RNA_def_float_rotation(
+ ot->srna, "shape_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Shape Angle", "Shape angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(40.0f));
- RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
- RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
- RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
- RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
+ RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", "");
+ RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", "");
+ RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", "");
+ RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", "");
+ RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", "");
}
void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
@@ -3470,19 +3949,25 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/* Dissolve */
-static void edbm_dissolve_prop__use_verts(wmOperatorType *ot)
+static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
{
- RNA_def_boolean(ot->srna, "use_verts", 0, "Dissolve Verts",
- "Dissolve remaining vertices");
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(ot->srna, "use_verts", value, "Dissolve Verts",
+ "Dissolve remaining vertices");
+
+ if (flag) {
+ RNA_def_property_flag(prop, flag);
+ }
}
static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split",
+ RNA_def_boolean(ot->srna, "use_face_split", false, "Face Split",
"Split off face corners to maintain surrounding geometry");
}
static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary",
+ RNA_def_boolean(ot->srna, "use_boundary_tear", false, "Tear Boundary",
"Split off face corners instead of merging faces");
}
@@ -3558,7 +4043,7 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- edbm_dissolve_prop__use_verts(ot);
+ edbm_dissolve_prop__use_verts(ot, true, 0);
edbm_dissolve_prop__use_face_split(ot);
}
@@ -3597,7 +4082,7 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- edbm_dissolve_prop__use_verts(ot);
+ edbm_dissolve_prop__use_verts(ot, false, 0);
}
@@ -3605,6 +4090,15 @@ static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "use_verts");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ /* always enable in edge-mode */
+ if ((em->selectmode & SCE_SELECT_FACE) == 0) {
+ RNA_property_boolean_set(op->ptr, prop, true);
+ }
+ }
if (em->selectmode & SCE_SELECT_VERTEX) {
return edbm_dissolve_verts_exec(C, op);
@@ -3631,7 +4125,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- edbm_dissolve_prop__use_verts(ot);
+ edbm_dissolve_prop__use_verts(ot, false, PROP_SKIP_SAVE);
edbm_dissolve_prop__use_face_split(ot);
edbm_dissolve_prop__use_boundary_tear(ot);
}
@@ -3707,9 +4201,9 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
"Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
- RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundaries",
+ RNA_def_boolean(ot->srna, "use_dissolve_boundaries", false, "All Boundaries",
"Dissolve all vertices inbetween face boundaries");
- RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, 0, "Delimit",
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_NORMAL, "Delimit",
"Delimit dissolve operation");
}
@@ -3753,8 +4247,8 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 0.00001, 10.0);
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
}
@@ -3792,6 +4286,8 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+
EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
@@ -4431,8 +4927,9 @@ void MESH_OT_sort_elements(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Type of re-ordering operation to apply");
- RNA_def_enum_flag(ot->srna, "elements", elem_items, 0, "Elements",
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, SRT_VIEW_ZAXIS,
+ "Type", "Type of re-ordering operation to apply");
+ RNA_def_enum_flag(ot->srna, "elements", elem_items, BM_VERT, "Elements",
"Which elements to affect (vertices, edges and/or faces)");
RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect");
RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
@@ -4480,7 +4977,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL);
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false);
eve->co[2] += fac * tin;
}
}
@@ -4507,10 +5004,16 @@ void MESH_OT_noise(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f);
}
+enum {
+ MESH_BRIDGELOOP_SINGLE = 0,
+ MESH_BRIDGELOOP_CLOSED = 1,
+ MESH_BRIDGELOOP_PAIRS = 2,
+};
+
static int edbm_bridge_tag_boundary_edges(BMesh *bm)
{
/* tags boundary edges from a face selection */
@@ -4559,8 +5062,8 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
- const bool use_pairs = (type == 2);
- const bool use_cyclic = (type == 1);
+ const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
+ const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
@@ -4658,9 +5161,9 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
{
static EnumPropertyItem type_items[] = {
- {0, "SINGLE", 0, "Open Loop", ""},
- {1, "CLOSED", 0, "Closed Loop", ""},
- {2, "PAIRS", 0, "Loop Pairs", ""},
+ {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""},
+ {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""},
+ {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -4676,7 +5179,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0,
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, MESH_BRIDGELOOP_SINGLE,
"Connect Loops", "Method of bridging multiple loops");
RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces");
@@ -4737,19 +5240,73 @@ void MESH_OT_wireframe(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
- RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+ RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
+ RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, FLT_MAX, "Thickness", "", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, FLT_MAX, "Offset", "", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
- prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, FLT_MAX, "Crease weight", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
+ prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
}
+static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMOperator bmop;
+ const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
+
+ EDBM_op_init(
+ em, &bmop, op,
+ "offset_edgeloops edges=%he use_cap_endpoint=%b",
+ BM_ELEM_SELECT, use_cap_endpoint);
+
+ BMO_op_exec(em->bm, &bmop);
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state */
+ if (em->selectmode == SCE_SELECT_FACE) {
+ em->selectmode = SCE_SELECT_EDGE;
+ EDBM_selectmode_set(em);
+ EDBM_selectmode_to_scene(C);
+ }
+
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+ }
+}
+
+void MESH_OT_offset_edge_loops(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Offset Edge Loop";
+ ot->idname = "MESH_OT_offset_edge_loops";
+ ot->description = "Create offset edge loop from the current selection";
+
+ /* api callbacks */
+ ot->exec = edbm_offset_edgeloop_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* Keep internal, since this is only meant to be accessed via 'MESH_OT_offset_edge_loops_slide' */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
+}
+
#ifdef WITH_BULLET
static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
{
@@ -4793,11 +5350,16 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
/* Merge adjacent triangles */
if (RNA_boolean_get(op->ptr, "join_triangles")) {
- if (!EDBM_op_call_and_selectf(em, op,
- "faces.out", true,
- "join_triangles faces=%S limit=%f",
- &bmop, "geom.out",
- RNA_float_get(op->ptr, "limit")))
+ float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
+ float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "join_triangles faces=%S "
+ "angle_face_threshold=%f angle_shape_threshold=%f",
+ &bmop, "geom.out",
+ angle_face_threshold, angle_shape_threshold))
{
EDBM_op_finish(em, &bmop, op, true);
return OPERATOR_CANCELLED;
@@ -4893,7 +5455,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Threshold", "", 0.00001, 0.1);
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f);
}
static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
@@ -5017,8 +5579,8 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.05, 0.0, 10.0, "Threshold", "", 0.0001, 1.0);
- RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
+ RNA_def_float(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center");
}
@@ -5085,7 +5647,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+ prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -5149,7 +5711,7 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+ prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c7d1d883537..d521b2c01e5 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -33,9 +33,13 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
+#include "DNA_key_types.h"
#include "BLI_math.h"
#include "BLI_alloca.h"
+#include "BLI_buffer.h"
+#include "BLI_kdtree.h"
+#include "BLI_listbase.h"
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
@@ -230,7 +234,7 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool
else {
em->emcopyusers--;
if (em->emcopyusers < 0) {
- printf("warning: em->emcopyusers was less then zero.\n");
+ printf("warning: em->emcopyusers was less than zero.\n");
}
if (em->emcopyusers <= 0) {
@@ -381,6 +385,12 @@ void EDBM_mesh_load(Object *ob)
Mesh *me = ob->data;
BMesh *bm = me->edit_btmesh->bm;
+ /* Workaround for T42360, 'ob->shapenr' should be 1 in this case.
+ * however this isn't synchronized between objects at the moment. */
+ if (UNLIKELY((ob->shapenr == 0) && (me->key && !BLI_listbase_is_empty(&me->key->block)))) {
+ bm->shapenr = 1;
+ }
+
BM_mesh_bm_to_me(bm, me, false);
#ifdef USE_TESSFACE_DEFAULT
@@ -432,14 +442,14 @@ void EDBM_select_flush(BMEditMesh *em)
BM_mesh_select_flush(em->bm);
}
-void EDBM_select_more(BMEditMesh *em)
+void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
{
BMOperator bmop;
- int use_faces = em->selectmode == SCE_SELECT_FACE;
+ const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
- "region_extend geom=%hvef use_constrict=%b use_faces=%b",
- BM_ELEM_SELECT, false, use_faces);
+ "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
+ BM_ELEM_SELECT, false, use_faces, use_face_step);
BMO_op_exec(em->bm, &bmop);
/* don't flush selection in edge/vertex mode */
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
@@ -448,14 +458,14 @@ void EDBM_select_more(BMEditMesh *em)
EDBM_selectmode_flush(em);
}
-void EDBM_select_less(BMEditMesh *em)
+void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
{
BMOperator bmop;
- int use_faces = em->selectmode == SCE_SELECT_FACE;
+ const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
- "region_extend geom=%hvef use_constrict=%b use_faces=%b",
- BM_ELEM_SELECT, true, use_faces);
+ "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
+ BM_ELEM_SELECT, true, use_faces, use_face_step);
BMO_op_exec(em->bm, &bmop);
/* don't flush selection in edge/vertex mode */
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
@@ -524,30 +534,56 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
return um;
}
-static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *UNUSED(obdata))
+static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
{
BMEditMesh *em = em_v, *em_tmp;
Object *ob = em->ob;
UndoMesh *um = umv;
BMesh *bm;
+ Key *key = ((Mesh *) obdata)->key;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
- ob->shapenr = em->bm->shapenr = um->shapenr;
+ em->bm->shapenr = um->shapenr;
EDBM_mesh_free(em);
bm = BM_mesh_create(&allocsize);
- BM_mesh_bm_from_me(bm, &um->me, true, false, ob->shapenr);
+ BM_mesh_bm_from_me(bm, &um->me, true, false, um->shapenr);
em_tmp = BKE_editmesh_create(bm, true);
*em = *em_tmp;
-
+
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
em->ob = ob;
+ /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
+ * if the active is a basis for any other. */
+ if (key && (key->type == KEY_RELATIVE)) {
+ /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
+ * shapenr from restored bmesh and keyblock indices are in sync. */
+ const int kb_act_idx = ob->shapenr - 1;
+
+ /* If it is, let's patch the current mesh key block to its restored value.
+ * Else, the offsets won't be computed and it won't matter. */
+ if (BKE_keyblock_is_basis(key, kb_act_idx)) {
+ KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
+
+ if (kb_act->totelem != um->me.totvert) {
+ /* The current mesh has some extra/missing verts compared to the undo, adjust. */
+ MEM_SAFE_FREE(kb_act->data);
+ kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
+ kb_act->totelem = um->me.totvert;
+ }
+
+ BKE_keyblock_update_from_mesh(&um->me, kb_act);
+ }
+ }
+
+ ob->shapenr = um->shapenr;
+
MEM_freeN(em_tmp);
}
@@ -579,7 +615,9 @@ void undo_push_mesh(bContext *C, const char *name)
/**
* Return a new UVVertMap from the editmesh
*/
-UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2])
+UvVertMap *BM_uv_vert_map_create(
+ BMesh *bm,
+ const float limit[2], const bool use_select, const bool use_winding)
{
BMVert *ev;
BMFace *efa;
@@ -591,11 +629,14 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
/* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
unsigned int a;
- int totverts, i, totuv;
+ int totverts, i, totuv, totfaces;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ bool *winding = NULL;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
@@ -616,35 +657,46 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt");
buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert");
+ if (use_winding) {
+ winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
+ }
if (!vmap->vert || !vmap->buf) {
BKE_mesh_uv_vert_map_free(vmap);
return NULL;
}
- a = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- i = 0;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ float (*tf_uv)[2];
+
+ if (use_winding) {
+ tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ }
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->tfindex = i;
buf->f = a;
buf->separate = 0;
buf->next = vmap->vert[BM_elem_index_get(l->v)];
vmap->vert[BM_elem_index_get(l->v)] = buf;
-
buf++;
- i++;
+
+ if (use_winding) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
+ }
}
- }
- a++;
+ if (use_winding) {
+ winding[a] = cross_poly_v2((const float (*)[2])tf_uv, efa->len) > 0;
+ }
+ }
}
/* sort individual uvs for each vert */
- a = 0;
- BM_ITER_MESH (ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
UvMapVert *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
@@ -676,7 +728,9 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1]) {
+ if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] &&
+ (!use_winding || winding[iterv->f] == winding[v->f]))
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -693,9 +747,14 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
}
vmap->vert[a] = newvlist;
- a++;
}
+ if (use_winding) {
+ MEM_freeN(winding);
+ }
+
+ BLI_buffer_free(&tf_uv_buf);
+
return vmap;
}
@@ -709,7 +768,9 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
/* A specialized vert map used by stitch operator */
-UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const bool do_islands)
+UvElementMap *BM_uv_element_map_create(
+ BMesh *bm,
+ const bool selected, const bool use_winding, const bool do_islands)
{
BMVert *ev;
BMFace *efa;
@@ -718,29 +779,20 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
/* vars from original func */
UvElementMap *element_map;
UvElement *buf;
- UvElement *islandbuf;
- /* island number for faces */
- int *island_number;
+ bool *winding;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
MLoopUV *luv;
- int totverts, i, totuv, j, nislands = 0, islandbufsize = 0;
-
- unsigned int *map;
- BMFace **stack;
- int stacksize = 0;
+ int totverts, totfaces, i, totuv, j;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
- island_number = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_number_face");
- if (!island_number) {
- return NULL;
- }
-
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
@@ -749,28 +801,31 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
if (totuv == 0) {
- MEM_freeN(island_number);
return NULL;
}
+
element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
- if (!element_map) {
- MEM_freeN(island_number);
- return NULL;
- }
element_map->totalUVs = totuv;
element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts");
buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement");
- if (!element_map->vert || !element_map->buf) {
- BM_uv_element_map_free(element_map);
- MEM_freeN(island_number);
- return NULL;
+ if (use_winding) {
+ winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
}
- j = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- island_number[j++] = INVALID_ISLAND;
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
+
+ if (use_winding) {
+ winding[j] = false;
+ }
+
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ float (*tf_uv)[2];
+
+ if (use_winding) {
+ tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ }
+
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->l = l;
buf->separate = 0;
@@ -780,14 +835,22 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
buf->next = element_map->vert[BM_elem_index_get(l->v)];
element_map->vert[BM_elem_index_get(l->v)] = buf;
+ if (use_winding) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
+ }
+
buf++;
}
+
+ if (use_winding) {
+ winding[j] = cross_poly_v2((const float (*)[2])tf_uv, efa->len) > 0;
+ }
}
}
/* sort individual uvs for each vert */
- i = 0;
- BM_ITER_MESH (ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) {
UvElement *newvlist = NULL, *vlist = element_map->vert[i];
UvElement *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
@@ -814,7 +877,9 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT) {
+ if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT &&
+ (!use_winding || winding[BM_elem_index_get(iterv->l->f)] == winding[BM_elem_index_get(v->l->f)]))
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -831,14 +896,28 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
element_map->vert[i] = newvlist;
- i++;
+ }
+
+ if (use_winding) {
+ MEM_freeN(winding);
}
if (do_islands) {
+ unsigned int *map;
+ BMFace **stack;
+ int stacksize = 0;
+ UvElement *islandbuf;
+ /* island number for faces */
+ int *island_number = NULL;
+
+ int nislands = 0, islandbufsize = 0;
+
/* map holds the map from current vmap->buf to the new, sorted map */
map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
+ island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
+ copy_vn_i(island_number, totfaces, INVALID_ISLAND);
/* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
for (i = 0; i < totuv; i++) {
@@ -887,6 +966,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
}
+ MEM_freeN(island_number);
+
/* remap */
for (i = 0; i < bm->totvert; i++) {
/* important since we may do selection only. Some of these may be NULL */
@@ -895,14 +976,6 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, "UvElementMap_island_indices");
- if (!element_map->islandIndices) {
- MEM_freeN(islandbuf);
- MEM_freeN(stack);
- MEM_freeN(map);
- BM_uv_element_map_free(element_map);
- MEM_freeN(island_number);
- }
-
j = 0;
for (i = 0; i < totuv; i++) {
UvElement *element = element_map->buf[i].next;
@@ -924,7 +997,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
MEM_freeN(stack);
MEM_freeN(map);
}
- MEM_freeN(island_number);
+
+ BLI_buffer_free(&tf_uv_buf);
return element_map;
}
@@ -1002,26 +1076,19 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
}
/**
- * [note: I've decided to use ideasman's code for non-editmode stuff, but since
- * it has a big "not for editmode!" disclaimer, I'm going to keep what I have here
- * - joeedh]
+ * Mirror editing API, usage:
*
- * x-mirror editing api. usage:
+ * \code{.c}
+ * EDBM_verts_mirror_cache_begin(em, ...);
*
- * EDBM_verts_mirror_cache_begin(em);
- * ...
- * ...
- * BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- * mirrorv = EDBM_verts_mirror_get(em, v);
- * }
- * ...
- * ...
- * EDBM_verts_mirror_cache_end(em);
+ * BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ * v_mirror = EDBM_verts_mirror_get(em, v);
+ * e_mirror = EDBM_verts_mirror_get_edge(em, e);
+ * f_mirror = EDBM_verts_mirror_get_face(em, f);
+ * }
*
- * \param use_self Allow a vertex to reference its self.
- * \param use_select Only cache selected verts.
- *
- * \note why do we only allow x axis mirror editing?
+ * EDBM_verts_mirror_cache_end(em);
+ * \endcode
*/
/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
@@ -1046,9 +1113,10 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
BMVert *v;
int cd_vmirr_offset;
int i;
+ const float maxdist_sq = SQUARE(maxdist);
/* one or the other is used depending if topo is enabled */
- struct BMBVHTree *tree = NULL;
+ KDTree *tree = NULL;
MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1};
BM_mesh_elem_table_ensure(bm, BM_VERT);
@@ -1073,7 +1141,11 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, true);
}
else {
- tree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ tree = BLI_kdtree_new(bm->totvert);
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BLI_kdtree_insert(tree, i, v->co);
+ }
+ BLI_kdtree_balance(tree);
}
#define VERT_INTPTR(_v, _i) r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset);
@@ -1093,10 +1165,19 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i);
}
else {
+ int i_mirr;
float co[3];
copy_v3_v3(co, v->co);
co[axis] *= -1.0f;
- v_mirr = BKE_bmbvh_find_vert_closest(tree, co, maxdist);
+
+ v_mirr = NULL;
+ i_mirr = BLI_kdtree_find_nearest(tree, co, NULL);
+ if (i_mirr != -1) {
+ BMVert *v_test = BM_vert_at_index(bm, i_mirr);
+ if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
+ v_mirr = v_test;
+ }
+ }
}
if (v_mirr && (use_self || (v_mirr != v))) {
@@ -1118,7 +1199,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
ED_mesh_mirrtopo_free(&mesh_topo_store);
}
else {
- BKE_bmbvh_free(tree);
+ BLI_kdtree_free(tree);
}
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index bf8559add6f..a2054a5f43c 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -43,14 +43,13 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
-#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
@@ -58,6 +57,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -335,6 +335,26 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set)
return layernum_dst;
}
+void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
+{
+ BMEditMesh *em;
+ int layernum_dst;
+
+ if (me->edit_btmesh) {
+ em = me->edit_btmesh;
+
+ layernum_dst = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+ if (layernum_dst == 0)
+ ED_mesh_uv_texture_add(me, name, true);
+ }
+ else {
+ layernum_dst = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ if (layernum_dst == 0)
+ ED_mesh_uv_texture_add(me, name, true);
+ }
+}
+
+
bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
{
CustomData *pdata = GET_CD_DATA(me, pdata), *ldata = GET_CD_DATA(me, ldata);
@@ -409,7 +429,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set)
/* copy data from active vertex color layer */
if (layernum) {
const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL);
- BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum, layernum_dst);
+ BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
@@ -502,6 +522,12 @@ static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_mesh_uv_texture_add(me, NULL, true) == -1)
return OPERATOR_CANCELLED;
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -544,24 +570,13 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_CANCELLED;
}
- /* check input variables */
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- char path[FILE_MAX];
-
- RNA_string_get(op->ptr, "filepath", path);
- ima = BKE_image_load_exists(path);
- }
- else {
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- ima = (Image *)BKE_libblock_find_name(ID_IM, name);
- }
-
+ ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!ima) {
- BKE_report(op->reports, RPT_ERROR, "Not an image");
return OPERATOR_CANCELLED;
}
-
+ /* handled below */
+ id_us_min((ID *)ima);
+
/* put mesh in editmode */
obedit = base->object;
@@ -612,6 +627,7 @@ void MESH_OT_drop_named_image(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file");
+ RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
}
static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
@@ -622,6 +638,12 @@ static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
if (!ED_mesh_uv_texture_remove_active(me))
return OPERATOR_CANCELLED;
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -726,7 +748,7 @@ static int mesh_customdata_clear_exec__internal(bContext *C,
}
/* Clear Mask */
-static int mesh_customdata_clear_mask_poll(bContext *C)
+static int mesh_customdata_mask_clear_poll(bContext *C)
{
Object *ob = ED_object_context(C);
if (ob && ob->type == OB_MESH) {
@@ -750,7 +772,7 @@ static int mesh_customdata_clear_mask_poll(bContext *C)
}
return false;
}
-static int mesh_customdata_clear_mask_exec(bContext *C, wmOperator *UNUSED(op))
+static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
int ret_a = mesh_customdata_clear_exec__internal(C, BM_VERT, CD_PAINT_MASK);
int ret_b = mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_GRID_PAINT_MASK);
@@ -765,24 +787,27 @@ static int mesh_customdata_clear_mask_exec(bContext *C, wmOperator *UNUSED(op))
}
}
-void MESH_OT_customdata_clear_mask(wmOperatorType *ot)
+void MESH_OT_customdata_mask_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Sculpt-Mask Data";
- ot->idname = "MESH_OT_customdata_clear_mask";
+ ot->idname = "MESH_OT_customdata_mask_clear";
ot->description = "Clear vertex sculpt masking data from the mesh";
/* api callbacks */
- ot->exec = mesh_customdata_clear_mask_exec;
- ot->poll = mesh_customdata_clear_mask_poll;
+ ot->exec = mesh_customdata_mask_clear_exec;
+ ot->poll = mesh_customdata_mask_clear_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Clear Skin */
-static int mesh_customdata_clear_skin_poll(bContext *C)
+/**
+ * Clear Skin
+ * \return -1 invalid state, 0 no skin, 1 has skin.
+ */
+static int mesh_customdata_skin_state(bContext *C)
{
Object *ob = ED_object_context(C);
@@ -790,28 +815,130 @@ static int mesh_customdata_clear_skin_poll(bContext *C)
Mesh *me = ob->data;
if (me->id.lib == NULL) {
CustomData *data = GET_CD_DATA(me, vdata);
- if (CustomData_has_layer(data, CD_MVERT_SKIN)) {
- return true;
- }
+ return CustomData_has_layer(data, CD_MVERT_SKIN);
}
}
- return false;
+ return -1;
+}
+
+static int mesh_customdata_skin_add_poll(bContext *C)
+{
+ return (mesh_customdata_skin_state(C) == 0);
+}
+
+static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ BKE_mesh_ensure_skin_customdata(me);
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_customdata_skin_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Skin Data";
+ ot->idname = "MESH_OT_customdata_skin_add";
+ ot->description = "Add a vertex skin layer";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_skin_add_exec;
+ ot->poll = mesh_customdata_skin_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int mesh_customdata_clear_skin_exec(bContext *C, wmOperator *UNUSED(op))
+
+static int mesh_customdata_skin_clear_poll(bContext *C)
+{
+ return (mesh_customdata_skin_state(C) == 1);
+}
+
+static int mesh_customdata_skin_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_MVERT_SKIN);
}
-void MESH_OT_customdata_clear_skin(wmOperatorType *ot)
+void MESH_OT_customdata_skin_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Skin Data";
- ot->idname = "MESH_OT_customdata_clear_skin";
+ ot->idname = "MESH_OT_customdata_skin_clear";
ot->description = "Clear vertex skin layer";
/* api callbacks */
- ot->exec = mesh_customdata_clear_skin_exec;
- ot->poll = mesh_customdata_clear_skin_poll;
+ ot->exec = mesh_customdata_skin_clear_exec;
+ ot->poll = mesh_customdata_skin_clear_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* Clear custom loop normals */
+static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ if (!BKE_mesh_has_custom_loop_normals(me)) {
+ CustomData *data = GET_CD_DATA(me, ldata);
+
+ if (me->edit_btmesh) {
+ BM_data_layer_add(me->edit_btmesh->bm, data, CD_CUSTOMLOOPNORMAL);
+ }
+ else {
+ CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
+ }
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Custom Split Normals Data";
+ ot->idname = "MESH_OT_customdata_custom_splitnormals_add";
+ ot->description = "Add a custom split normals layer, if none exists yet";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_custom_splitnormals_add_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ if (BKE_mesh_has_custom_loop_normals(me)) {
+ return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Custom Split Normals Data";
+ ot->idname = "MESH_OT_customdata_custom_splitnormals_clear";
+ ot->description = "Remove the custom split normals layer, if it exists";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_custom_splitnormals_clear_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1148,7 +1275,7 @@ void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
mesh_add_polys(mesh, count);
}
-void ED_mesh_calc_tessface(Mesh *mesh)
+void ED_mesh_calc_tessface(Mesh *mesh, bool free_mpoly)
{
if (mesh->edit_btmesh) {
BKE_editmesh_tessface_calc(mesh->edit_btmesh);
@@ -1156,6 +1283,17 @@ void ED_mesh_calc_tessface(Mesh *mesh)
else {
BKE_mesh_tessface_calc(mesh);
}
+ if (free_mpoly) {
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+ mesh->totloop = 0;
+ mesh->totpoly = 0;
+ mesh->mloop = NULL;
+ mesh->mloopcol = NULL;
+ mesh->mloopuv = NULL;
+ mesh->mpoly = NULL;
+ mesh->mtpoly = NULL;
+ }
}
void ED_mesh_report_mirror_ex(wmOperator *op, int totmirr, int totfail,
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 76f6cb5ebb8..c56465f570a 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -34,14 +34,9 @@
#ifndef __MESH_INTERN_H__
#define __MESH_INTERN_H__
-struct BMEdge;
struct BMEditMesh;
-struct BMFace;
-struct BMHeader;
struct BMOperator;
-struct BMesh;
struct EnumPropertyItem;
-struct ViewContext;
struct bContext;
struct wmKeyConfig;
struct wmKeyMap;
@@ -137,6 +132,7 @@ void MESH_OT_rip_edge(struct wmOperatorType *ot);
/* *** editmesh_select.c *** */
void MESH_OT_select_similar(struct wmOperatorType *ot);
+void MESH_OT_select_similar_region(struct wmOperatorType *ot);
void MESH_OT_select_mode(struct wmOperatorType *ot);
void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
void MESH_OT_loop_select(struct wmOperatorType *ot);
@@ -174,9 +170,13 @@ void MESH_OT_normals_make_consistent(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth_laplacian(struct wmOperatorType *ot);
void MESH_OT_vert_connect(struct wmOperatorType *ot);
+void MESH_OT_vert_connect_path(struct wmOperatorType *ot);
+void MESH_OT_vert_connect_concave(struct wmOperatorType *ot);
void MESH_OT_vert_connect_nonplanar(struct wmOperatorType *ot);
+void MESH_OT_face_make_planar(struct wmOperatorType *ot);
void MESH_OT_edge_split(struct wmOperatorType *ot);
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
+void MESH_OT_offset_edge_loops(struct wmOperatorType *ot);
void MESH_OT_wireframe(struct wmOperatorType *ot);
void MESH_OT_convex_hull(struct wmOperatorType *ot);
void MESH_OT_symmetrize(struct wmOperatorType *ot);
@@ -234,8 +234,11 @@ void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
/* no create_mask yet */
-void MESH_OT_customdata_clear_mask(struct wmOperatorType *ot);
-void MESH_OT_customdata_clear_skin(struct wmOperatorType *ot);
+void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
+void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
+void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 440ab14dacd..1c36826b882 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -84,7 +84,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs,
for (oblink = obs; oblink; oblink = oblink->next) {
ob = (Object *) oblink->link;
dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
- BLI_linklist_append(&dms, (void *)dm);
+ BLI_linklist_prepend(&dms, dm);
nverts += dm->getNumVerts(dm);
nfaces = dm->getNumTessFaces(dm);
@@ -325,7 +325,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
if (createob) {
/* create new object */
- obedit = ED_object_add_type(C, OB_MESH, co, rot, false, lay);
+ obedit = ED_object_add_type(C, OB_MESH, "Navmesh", co, rot, false, lay);
}
else {
obedit = base->object;
@@ -429,7 +429,6 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
obedit->gameflag &= ~OB_COLLISION;
obedit->gameflag |= OB_NAVMESH;
obedit->body_type = OB_BODY_TYPE_NAVMESH;
- rename_id((ID *)obedit, "Navmesh");
}
BKE_mesh_ensure_navmesh(obedit->data);
@@ -452,7 +451,7 @@ static int navmesh_create_exec(bContext *C, wmOperator *op)
}
}
else {
- BLI_linklist_append(&obs, (void *)base->object);
+ BLI_linklist_prepend(&obs, base->object);
}
}
}
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 31653efa735..9718e63f012 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -130,6 +130,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_edge_face_add);
WM_operatortype_append(MESH_OT_shortest_path_pick);
WM_operatortype_append(MESH_OT_select_similar);
+ WM_operatortype_append(MESH_OT_select_similar_region);
WM_operatortype_append(MESH_OT_select_mode);
WM_operatortype_append(MESH_OT_loop_multi_select);
WM_operatortype_append(MESH_OT_mark_seam);
@@ -150,8 +151,11 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_uv_texture_remove);
WM_operatortype_append(MESH_OT_vertex_color_add);
WM_operatortype_append(MESH_OT_vertex_color_remove);
- WM_operatortype_append(MESH_OT_customdata_clear_mask);
- WM_operatortype_append(MESH_OT_customdata_clear_skin);
+ WM_operatortype_append(MESH_OT_customdata_mask_clear);
+ WM_operatortype_append(MESH_OT_customdata_skin_add);
+ WM_operatortype_append(MESH_OT_customdata_skin_clear);
+ WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add);
+ WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear);
WM_operatortype_append(MESH_OT_drop_named_image);
WM_operatortype_append(MESH_OT_edgering_select);
@@ -160,7 +164,10 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_solidify);
WM_operatortype_append(MESH_OT_select_nth);
WM_operatortype_append(MESH_OT_vert_connect);
+ WM_operatortype_append(MESH_OT_vert_connect_path);
+ WM_operatortype_append(MESH_OT_vert_connect_concave);
WM_operatortype_append(MESH_OT_vert_connect_nonplanar);
+ WM_operatortype_append(MESH_OT_face_make_planar);
WM_operatortype_append(MESH_OT_knife_tool);
WM_operatortype_append(MESH_OT_knife_project);
@@ -170,6 +177,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_bridge_edge_loops);
WM_operatortype_append(MESH_OT_inset);
+ WM_operatortype_append(MESH_OT_offset_edge_loops);
WM_operatortype_append(MESH_OT_intersect);
WM_operatortype_append(MESH_OT_face_split_by_edges);
WM_operatortype_append(MESH_OT_poke);
@@ -218,6 +226,13 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
RNA_boolean_set(otmacro->ptr, "release_confirm", false);
+ ot = WM_operatortype_append_macro("MESH_OT_offset_edge_loops_slide", "Offset Edge Slide", "Offset edge loop slide",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_offset_edge_loops");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
+ RNA_boolean_set(otmacro->ptr, "release_confirm", false);
+ RNA_boolean_set(otmacro->ptr, "single_side", true);
+
ot = WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", "Duplicate mesh and move",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
@@ -295,7 +310,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Mesh", 0, 0);
keymap->poll = ED_operator_editmesh;
- WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_offset_edge_loops_slide", RKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_add_item(keymap, "MESH_OT_inset", IKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "MESH_OT_poke", PKEY, KM_PRESS, KM_ALT, 0);
kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL, 0);
@@ -342,7 +358,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_faces_select_linked_flat", FKEY, KM_PRESS, (KM_CTRL | KM_SHIFT | KM_ALT), 0);
- WM_keymap_add_item(keymap, "MESH_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
/* selection mode */
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0);
@@ -397,7 +413,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_vert_connect", JKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0);
/* Vertex Slide */
WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 16f4f61f92b..2491685161c 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -329,7 +329,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (odg) {
/* Search for a match in the new object, and set new index */
for (dg = ob->defbase.first, index = 0; dg; dg = dg->next, index++) {
- if (!strcmp(dg->name, odg->name)) {
+ if (STREQ(dg->name, odg->name)) {
dvert[i].dw[j].def_nr = index;
break;
}
@@ -627,7 +627,7 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
/* first key added, so it was the basis. initialize it with the existing mesh */
kb = BKE_keyblock_add(key, NULL);
- BKE_key_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, kb);
}
/* now ready to add new keys from selected meshes */
@@ -895,7 +895,7 @@ int ED_mesh_mirror_get_vert(Object *ob, int index)
index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
}
else {
- index_mirr = mesh_get_x_mirror_vert(ob, index, use_topology);
+ index_mirr = mesh_get_x_mirror_vert(ob, index, use_topology);
}
return index_mirr;
@@ -1082,11 +1082,11 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int
* on an edge in the backbuf, we can still select a face */
float dummy_dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist, 0, NULL, NULL);
+ *index = ED_view3d_backbuf_sample_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist);
}
else {
/* sample only on the exact position */
- *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+ *index = ED_view3d_backbuf_sample(&vc, mval[0], mval[1]);
}
if ((*index) == 0 || (*index) > (unsigned int)me->totpoly)
@@ -1248,11 +1248,11 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
* on an face in the backbuf, we can still select a vert */
float dummy_dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+ *index = ED_view3d_backbuf_sample_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist);
}
else {
/* sample only on the exact position */
- *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+ *index = ED_view3d_backbuf_sample(&vc, mval[0], mval[1]);
}
if ((*index) == 0 || (*index) > (unsigned int)me->totvert)
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index f6a54beb8c8..42eda235276 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -47,7 +47,6 @@
#include "RNA_define.h"
#include "RNA_access.h"
-#include "RNA_enum_types.h"
#include "BKE_depsgraph.h"
#include "BKE_context.h"
@@ -405,7 +404,8 @@ void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
+ RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
+ "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
WM_operator_properties_select_action_simple(ot, SEL_SELECT);
}
@@ -533,7 +533,7 @@ void MBALL_OT_hide_metaelems(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
}
/***************************** Unhide operator *****************************/
@@ -584,7 +584,7 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo
MetaBall *mb = (MetaBall *)obedit->data;
MetaElem *ml, *ml_act = NULL;
int a, hits;
- unsigned int buffer[4 * MAXPICKBUF];
+ unsigned int buffer[MAXPICKBUF];
rcti rect;
view3d_set_viewcontext(C, &vc);
diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c
index b7822200d98..3af85c33bcc 100644
--- a/source/blender/editors/metaball/mball_ops.c
+++ b/source/blender/editors/metaball/mball_ops.c
@@ -30,8 +30,6 @@
#include "DNA_scene_types.h"
-#include "BLI_utildefines.h"
-
#include "RNA_access.h"
#include "WM_api.h"
@@ -62,7 +60,7 @@ void ED_operatormacros_metaball(void)
wmOperatorTypeMacro *otmacro;
ot = WM_operatortype_append_macro("MBALL_OT_duplicate_move", "Duplicate",
- "Make copies of the selected bones within the same armature and move them",
+ "Make copies of the selected metaelements and move them",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MBALL_OT_duplicate_metaelems");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 1bb35b65918..b3d02d45e13 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -20,9 +20,9 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../gpu
../../ikplugin
@@ -33,10 +33,11 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
-
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
@@ -55,6 +56,7 @@ set(SRC
object_relations.c
object_select.c
object_shapekey.c
+ object_data_transfer.c
object_transform.c
object_warp.c
object_vgroup.c
@@ -62,6 +64,8 @@ set(SRC
object_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript
index db30fae1f84..914ffa3061c 100644
--- a/source/blender/editors/object/SConscript
+++ b/source/blender/editors/object/SConscript
@@ -33,9 +33,9 @@ incs = [
'#/extern/recastnavigation',
'#/intern/guardedalloc',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../ikplugin',
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 8972dd7cf08..615fbb527b3 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -55,8 +55,9 @@
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
@@ -69,7 +70,6 @@
#include "BKE_effect.h"
#include "BKE_font.h"
#include "BKE_group.h"
-#include "BKE_image.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -97,7 +97,6 @@
#include "ED_armature.h"
#include "ED_curve.h"
-#include "ED_lattice.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_node.h"
@@ -108,7 +107,6 @@
#include "ED_transform.h"
#include "ED_view3d.h"
-#include "UI_interface.h"
#include "UI_resources.h"
#include "GPU_material.h"
@@ -165,14 +163,13 @@ void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_ax
BLI_assert(align_axis >= 'X' && align_axis <= 'Z');
if (rv3d) {
- const float pi_2 = (float)M_PI / 2.0f;
float quat[4];
switch (align_axis) {
case 'X':
{
float quat_y[4];
- axis_angle_to_quat(quat_y, rv3d->viewinv[1], -pi_2);
+ axis_angle_to_quat(quat_y, rv3d->viewinv[1], -M_PI_2);
mul_qt_qtqt(quat, rv3d->viewquat, quat_y);
quat[0] = -quat[0];
@@ -185,7 +182,7 @@ void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_ax
quat[0] = -quat[0];
quat_to_eul(rot, quat);
- rot[0] -= pi_2;
+ rot[0] -= (float)M_PI_2;
break;
}
case 'Z':
@@ -222,9 +219,9 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3],
/* Uses context to figure out transform for primitive.
* Returns standard diameter. */
-float ED_object_new_primitive_matrix(bContext *C, Object *obedit,
- const float loc[3], const float rot[3], float primmat[4][4],
- bool apply_diameter)
+float ED_object_new_primitive_matrix(
+ bContext *C, Object *obedit,
+ const float loc[3], const float rot[3], float primmat[4][4])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -249,13 +246,6 @@ float ED_object_new_primitive_matrix(bContext *C, Object *obedit,
{
const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL);
-
- if (apply_diameter) {
- primmat[0][0] *= dia;
- primmat[1][1] *= dia;
- primmat[2][2] *= dia;
- }
-
return dia;
}
@@ -273,7 +263,7 @@ void ED_object_add_unit_props(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
}
@@ -291,11 +281,12 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
- prop = RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
- "Location for the newly added object", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Location", "Location for the newly added object", -1000.0f, 1000.0f);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_float_rotation(ot->srna, "rotation", 3, NULL, -FLT_MAX, FLT_MAX, "Rotation",
- "Rotation for the newly added object", (float)-M_PI * 2.0f, (float)M_PI * 2.0f);
+ prop = RNA_def_float_rotation(ot->srna, "rotation", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Rotation", "Rotation for the newly added object",
+ DEG2RADF(-360.0f), DEG2RADF(360.0f));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
@@ -308,18 +299,19 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
{
View3D *v3d = CTX_wm_view3d(C);
unsigned int _layer;
+ PropertyRNA *prop;
- /* Switch to Edit mode? */
- if (RNA_struct_find_property(op->ptr, "enter_editmode")) { /* optional */
+ /* Switch to Edit mode? optional prop */
+ if ((prop = RNA_struct_find_property(op->ptr, "enter_editmode"))) {
bool _enter_editmode;
if (!enter_editmode)
enter_editmode = &_enter_editmode;
- if (RNA_struct_property_is_set(op->ptr, "enter_editmode") && enter_editmode)
- *enter_editmode = RNA_boolean_get(op->ptr, "enter_editmode");
+ if (RNA_property_is_set(op->ptr, prop) && enter_editmode)
+ *enter_editmode = RNA_property_boolean_get(op->ptr, prop);
else {
*enter_editmode = (U.flag & USER_ADD_EDITMODE) != 0;
- RNA_boolean_set(op->ptr, "enter_editmode", *enter_editmode);
+ RNA_property_boolean_set(op->ptr, prop, *enter_editmode);
}
}
@@ -329,8 +321,9 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
if (!layer)
layer = &_layer;
- if (RNA_struct_property_is_set(op->ptr, "layers")) {
- RNA_boolean_get_array(op->ptr, "layers", layer_values);
+ prop = RNA_struct_find_property(op->ptr, "layers");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_get_array(op->ptr, prop, layer_values);
*layer = 0;
for (a = 0; a < 20; a++) {
if (layer_values[a])
@@ -341,9 +334,9 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
Scene *scene = CTX_data_scene(C);
*layer = BKE_screen_view3d_layer_active_ex(v3d, scene, false);
for (a = 0; a < 20; a++) {
- layer_values[a] = *layer & (1 << a);
+ layer_values[a] = (*layer & (1 << a)) != 0;
}
- RNA_boolean_set_array(op->ptr, "layers", layer_values);
+ RNA_property_boolean_set_array(op->ptr, prop, layer_values);
}
/* in local view we additionally add local view layers,
@@ -403,8 +396,11 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
/* For object add primitive operators.
* Do not call undo push in this function (users of this function have to). */
-Object *ED_object_add_type(bContext *C, int type, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer)
+Object *ED_object_add_type(
+ bContext *C,
+ int type, const char *name,
+ const float loc[3], const float rot[3],
+ bool enter_editmode, unsigned int layer)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -415,7 +411,7 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
/* deselects all, sets scene->basact */
- ob = BKE_object_add(bmain, scene, type);
+ ob = BKE_object_add(bmain, scene, type, name);
BASACT->lay = ob->lay = layer;
/* editor level activate, notifiers */
ED_base_object_activate(C, BASACT);
@@ -449,14 +445,23 @@ static int object_add_exec(bContext *C, wmOperator *op)
Object *ob;
bool enter_editmode;
unsigned int layer;
- float loc[3], rot[3];
+ float loc[3], rot[3], radius;
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer);
- BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
+ radius = RNA_float_get(op->ptr, "radius");
+ ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode, layer);
+
+ if (ob->type == OB_LATTICE) {
+ /* lattice is a special case!
+ * we never want to scale the obdata since that is the rest-state */
+ copy_v3_fl(ob->size, radius);
+ }
+ else {
+ BKE_object_obdata_size_init(ob, radius);
+ }
return OPERATOR_FINISHED;
}
@@ -504,21 +509,21 @@ static int effector_add_exec(bContext *C, wmOperator *op)
if (type == PFIELD_GUIDE) {
Curve *cu;
- ob = ED_object_add_type(C, OB_CURVE, loc, rot, false, layer);
+ const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "CurveGuide");
+ ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false, layer);
- rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "CurveGuide"));
cu = ob->data;
cu->flag |= CU_PATH | CU_3D;
ED_object_editmode_enter(C, 0);
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat, false);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
BLI_addtail(&cu->editnurb->nurbs, add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia));
if (!enter_editmode)
ED_object_editmode_exit(C, EM_FREEDATA);
}
else {
- ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
+ const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field");
+ ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, layer);
BKE_object_obdata_size_init(ob, dia);
- rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "Field"));
if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX))
ob->empty_drawtype = OB_SINGLE_ARROW;
}
@@ -569,7 +574,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_CAMERA, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, layer);
if (v3d) {
if (v3d->camera == NULL)
@@ -626,14 +631,14 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if (obedit == NULL || obedit->type != OB_MBALL) {
- obedit = ED_object_add_type(C, OB_MBALL, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, layer);
newob = true;
}
else {
DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
dia = RNA_float_get(op->ptr, "radius");
add_metaball_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
@@ -685,7 +690,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
if (obedit && obedit->type == OB_FONT)
return OPERATOR_CANCELLED;
- obedit = ED_object_add_type(C, OB_FONT, loc, rot, enter_editmode, layer);
+ obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode, layer);
BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius"));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
@@ -729,7 +734,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
- obedit = ED_object_add_type(C, OB_ARMATURE, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, layer);
ED_object_editmode_enter(C, 0);
newob = true;
}
@@ -786,7 +791,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, layer);
BKE_object_empty_draw_type_set(ob, type);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
@@ -824,24 +829,12 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
Image *ima = NULL;
Object *ob = NULL;
- /* check image input variables */
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- char path[FILE_MAX];
-
- RNA_string_get(op->ptr, "filepath", path);
- ima = BKE_image_load_exists(path);
- }
- else if (RNA_struct_property_is_set(op->ptr, "name")) {
- char name[MAX_ID_NAME - 2];
-
- RNA_string_get(op->ptr, "name", name);
- ima = (Image *)BKE_libblock_find_name(ID_IM, name);
- }
-
- if (ima == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Not an image");
+ ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
+ if (!ima) {
return OPERATOR_CANCELLED;
}
+ /* handled below */
+ id_us_min((ID *)ima);
base = ED_view3d_give_base_under_cursor(C, event->mval);
@@ -858,7 +851,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, NULL, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, layer);
/* add under the mouse */
ED_object_location_from_view(C, ob->loc);
@@ -893,6 +886,8 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
/* properties */
prop = RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "Filepath", "Path to image file");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Image name to assign");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
ED_object_add_generic_props(ot, false);
@@ -903,13 +898,13 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
static const char *get_lamp_defname(int type)
{
switch (type) {
- case LA_LOCAL: return CTX_DATA_(BLF_I18NCONTEXT_ID_LAMP, "Point");
- case LA_SUN: return CTX_DATA_(BLF_I18NCONTEXT_ID_LAMP, "Sun");
- case LA_SPOT: return CTX_DATA_(BLF_I18NCONTEXT_ID_LAMP, "Spot");
- case LA_HEMI: return CTX_DATA_(BLF_I18NCONTEXT_ID_LAMP, "Hemi");
- case LA_AREA: return CTX_DATA_(BLF_I18NCONTEXT_ID_LAMP, "Area");
+ case LA_LOCAL: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Point");
+ case LA_SUN: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Sun");
+ case LA_SPOT: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Spot");
+ case LA_HEMI: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Hemi");
+ case LA_AREA: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Area");
default:
- return CTX_DATA_(BLF_I18NCONTEXT_ID_LAMP, "Lamp");
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Lamp");
}
}
@@ -926,13 +921,11 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_LAMP, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_LAMP, get_lamp_defname(type), loc, rot, false, layer);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
la = (Lamp *)ob->data;
la->type = type;
- rename_id(&ob->id, get_lamp_defname(type));
- rename_id(&la->id, get_lamp_defname(type));
if (BKE_scene_use_new_shading_nodes(scene)) {
ED_node_shader_default(C, &la->id);
@@ -959,7 +952,7 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", "");
- RNA_def_property_translation_context(ot->prop, BLF_I18NCONTEXT_ID_LAMP);
+ RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_LAMP);
ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, false);
@@ -981,8 +974,11 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
if (0 == RNA_struct_property_is_set(op->ptr, "location")) {
wmEvent *event = CTX_wm_window(C)->eventstate;
+ ARegion *ar = CTX_wm_region(C);
+ const int mval[2] = {event->x - ar->winrct.xmin,
+ event->y - ar->winrct.ymin};
ED_object_location_from_view(C, loc);
- ED_view3d_cursor3d_position(C, loc, event->mval);
+ ED_view3d_cursor3d_position(C, loc, mval);
RNA_float_set_array(op->ptr, "location", loc);
}
}
@@ -995,8 +991,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
if (group) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -1051,14 +1046,14 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_SPEAKER, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, layer);
/* to make it easier to start using this immediately in NLA, a default sound clip is created
* ready to be moved around to retime the sound and/or make new sound clips
*/
{
/* create new data for NLA hierarchy */
- AnimData *adt = BKE_id_add_animdata(&ob->id);
+ AnimData *adt = BKE_animdata_add_id(&ob->id);
NlaTrack *nlt = add_nlatrack(adt, NULL);
NlaStrip *strip = add_nla_soundstrip(scene, ob->data);
strip->start = CFRA;
@@ -1290,6 +1285,44 @@ static void copy_object_set_idnew(bContext *C, int dupflag)
/********************* Make Duplicates Real ************************/
+/**
+ * \note regarding hashing dupli-objects, skip the first member of #DupliObject.persistent_id
+ * since its a unique index and we only want to know if the group objects are from the same dupli-group instance.
+ */
+static unsigned int dupliobject_hash(const void *ptr)
+{
+ const DupliObject *dob = ptr;
+ unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
+ unsigned int i;
+ for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
+ hash ^= (dob->persistent_id[i] ^ i);
+ }
+ return hash;
+}
+
+static bool dupliobject_cmp(const void *a_, const void *b_)
+{
+ const DupliObject *a = a_;
+ const DupliObject *b = b_;
+ unsigned int i;
+
+ if (a->ob != b->ob) {
+ return true;
+ }
+
+ for (i = 1; (i < MAX_DUPLI_RECUR); i++) {
+ if (a->persistent_id[i] != b->persistent_id[i]) {
+ return true;
+ }
+ else if (a->persistent_id[i] == INT_MAX) {
+ break;
+ }
+ }
+
+ /* matching */
+ return false;
+}
+
static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
const bool use_base_parent,
const bool use_hierarchy)
@@ -1306,8 +1339,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
lb = object_duplilist(bmain->eval_ctx, scene, base->object);
if (use_hierarchy || use_base_parent) {
- dupli_gh = BLI_ghash_ptr_new("make_object_duplilist_real dupli_gh");
- parent_gh = BLI_ghash_pair_new("make_object_duplilist_real parent_gh");
+ dupli_gh = BLI_ghash_ptr_new(__func__);
+ parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
}
for (dob = lb->first; dob; dob = dob->next) {
@@ -1327,7 +1360,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
basen->object = ob;
/* make sure apply works */
- BKE_free_animdata(&ob->id);
+ BKE_animdata_free(&ob->id);
ob->adt = NULL;
/* Proxies are not to be copied. */
@@ -1347,7 +1380,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (dupli_gh)
BLI_ghash_insert(dupli_gh, dob, ob);
if (parent_gh)
- BLI_ghash_insert(parent_gh, BLI_ghashutil_pairalloc(dob->ob, SET_INT_IN_POINTER(dob->persistent_id[0])), ob);
+ BLI_ghash_insert(parent_gh, dob, ob);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
@@ -1363,9 +1396,14 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
/* find parent that was also made real */
if (ob_src_par) {
- GHashPair *pair = BLI_ghashutil_pairalloc(ob_src_par, SET_INT_IN_POINTER(dob->persistent_id[0]));
- ob_dst_par = BLI_ghash_lookup(parent_gh, pair);
- BLI_ghashutil_pairfree(pair);
+ /* OK to keep most of the members uninitialized,
+ * they won't be read, this is simply for a hash lookup. */
+ DupliObject dob_key;
+ dob_key.ob = ob_src_par;
+ memcpy(&dob_key.persistent_id[1],
+ &dob->persistent_id[1],
+ sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
+ ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key);
}
if (ob_dst_par) {
@@ -1428,7 +1466,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (dupli_gh)
BLI_ghash_free(dupli_gh, NULL, NULL);
if (parent_gh)
- BLI_ghash_free(parent_gh, BLI_ghashutil_pairfree, NULL);
+ BLI_ghash_free(parent_gh, NULL, NULL);
copy_object_set_idnew(C, 0);
@@ -1569,18 +1607,30 @@ static int convert_exec(bContext *C, wmOperator *op)
/* don't forget multiple users! */
- /* reset flags */
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
- ob = base->object;
- ob->flag &= ~OB_DONE;
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ ob = base->object;
+ ob->flag &= ~OB_DONE;
- /* flag data thats not been edited (only needed for !keep_original) */
- if (ob->data) {
- ((ID *)ob->data)->flag |= LIB_DOIT;
+ /* flag data thats not been edited (only needed for !keep_original) */
+ if (ob->data) {
+ ((ID *)ob->data)->flag |= LIB_DOIT;
+ }
+
+ /* possible metaball basis is not in this scene */
+ if (ob->type == OB_MBALL && target == OB_MESH) {
+ if (BKE_mball_is_basis(ob) == false) {
+ Object *ob_basis;
+ ob_basis = BKE_mball_basis_find(scene, ob);
+ if (ob_basis) {
+ ob_basis->flag &= ~OB_DONE;
+ }
+ }
+ }
}
}
- CTX_DATA_END;
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
@@ -1652,11 +1702,10 @@ static int convert_exec(bContext *C, wmOperator *op)
dm = mesh_get_derived_final(scene, newob, CD_MASK_MESH);
// dm = mesh_create_derived_no_deform(ob1, NULL); /* this was called original (instead of get_derived). man o man why! (ton) */
- DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH);
+ DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH, true);
/* re-tessellation is called by DM_to_mesh */
- dm->release(dm);
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
}
else if (ob->type == OB_FONT) {
@@ -1820,14 +1869,21 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!keep_original) {
if (mballConverted) {
- Base *base = scene->base.first, *tmpbase;
- while (base) {
- ob = base->object;
- tmpbase = base;
- base = base->next;
+ Base *base, *base_next;
+
+ for (base = scene->base.first; base; base = base_next) {
+ base_next = base->next;
+ ob = base->object;
if (ob->type == OB_MBALL) {
- ED_base_object_free_and_unlink(bmain, scene, tmpbase);
+ if (ob->flag & OB_DONE) {
+ Object *ob_basis = NULL;
+ if (BKE_mball_is_basis(ob) ||
+ ((ob_basis = BKE_mball_basis_find(scene, ob)) && (ob_basis->flag & OB_DONE)))
+ {
+ ED_base_object_free_and_unlink(bmain, scene, base);
+ }
+ }
}
}
}
@@ -1922,7 +1978,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
/* duplicates using userflags */
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&obn->id);
+ BKE_animdata_copy_id_action(&obn->id);
}
if (dupflag & USER_DUP_MAT) {
@@ -1935,7 +1991,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
id->us--;
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&obn->mat[a]->id);
+ BKE_animdata_copy_id_action(&obn->mat[a]->id);
}
}
}
@@ -1950,7 +2006,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
psys->part = BKE_particlesettings_copy(psys->part);
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&psys->part->id);
+ BKE_animdata_copy_id_action(&psys->part->id);
}
id->us--;
@@ -2028,7 +2084,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
case OB_ARMATURE:
DAG_id_tag_update(&obn->id, OB_RECALC_DATA);
if (obn->pose)
- obn->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, obn->pose);
if (dupflag & USER_DUP_ARM) {
ID_NEW_US2(obn->data)
else {
@@ -2078,9 +2134,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_ACT) {
bActuator *act;
- BKE_copy_animdata_id_action((ID *)obn->data);
+ BKE_animdata_copy_id_action((ID *)obn->data);
if (key) {
- BKE_copy_animdata_id_action((ID *)key);
+ BKE_animdata_copy_id_action((ID *)key);
}
/* Update the duplicated action in the action actuators */
@@ -2270,7 +2326,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
MEM_freeN(base);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index b8957514159..ecaa05ace99 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -45,8 +45,6 @@
#include "BLI_blenlib.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-#include "BLI_math_geom.h"
#include "BKE_blender.h"
#include "BKE_screen.h"
@@ -71,7 +69,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "IMB_colormanagement.h"
#include "GPU_draw.h" /* GPU_free_image */
@@ -218,7 +215,7 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
tmp_mmd.simple = true;
}
- DM_set_only_copy(cddm, CD_MASK_BAREMESH | CD_MASK_MTFACE);
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
tmp_mmd.lvl = *lvl;
tmp_mmd.sculptlvl = *lvl;
@@ -286,23 +283,6 @@ static void clear_single_image(Image *image, ClearFlag flag)
}
}
-static void clear_images(MTFace *mtface, int totface, ClearFlag flag)
-{
- int a;
-
- for (a = 0; a < totface; a++) {
- mtface[a].tpage->id.flag &= ~LIB_DOIT;
- }
-
- for (a = 0; a < totface; a++) {
- clear_single_image(mtface[a].tpage, flag);
- }
-
- for (a = 0; a < totface; a++) {
- mtface[a].tpage->id.flag &= ~LIB_DOIT;
- }
-}
-
static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag)
{
int a;
@@ -345,7 +325,6 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
clear_flag = CLEAR_DISPLACEMENT;
}
- clear_images(me->mtface, me->totface, clear_flag);
clear_images_poly(me->mtpoly, me->totpoly, clear_flag);
}
CTX_DATA_END;
@@ -438,12 +417,12 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
MultiresBakeJob *bkj = bkv;
int baked_objects = 0, tot_obj;
- tot_obj = BLI_countlist(&bkj->data);
+ tot_obj = BLI_listbase_count(&bkj->data);
if (bkj->bake_clear) { /* clear images */
for (data = bkj->data.first; data; data = data->next) {
DerivedMesh *dm = data->lores_dm;
- MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY);
ClearFlag clear_flag = 0;
if (bkj->mode == RE_BAKE_NORMALS) {
@@ -453,7 +432,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
clear_flag = CLEAR_DISPLACEMENT;
}
- clear_images(mtface, dm->getNumTessFaces(dm), clear_flag);
+ clear_images_poly(mtexpoly, dm->getNumPolys(dm), clear_flag);
}
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 5746f9efd56..2c4f7a8e107 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -379,7 +379,10 @@ static bool bake_object_check(Object *ob, ReportList *reports)
if (node) {
if (BKE_node_is_connected_to_output(ntree, node)) {
- BKE_reportf(reports, RPT_ERROR,
+ /* we don't return false since this may be a false positive
+ * this can't be RPT_ERROR though, otherwise it prevents
+ * multiple highpoly objects to be baked at once */
+ BKE_reportf(reports, RPT_INFO,
"Circular dependency for image \"%s\" from object \"%s\"",
image->id.name + 2, ob->id.name + 2);
}
@@ -560,7 +563,7 @@ static int bake(
Object *ob_cage = NULL;
BakeHighPolyData *highpoly = NULL;
- int tot_highpoly;
+ int tot_highpoly = 0;
char restrict_flag_low = ob_low->restrictflag;
char restrict_flag_cage = 0;
@@ -571,6 +574,7 @@ static int bake(
float *result = NULL;
BakePixel *pixel_array_low = NULL;
+ BakePixel *pixel_array_high = NULL;
const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL);
const bool is_noncolor = is_noncolor_pass(pass_type);
@@ -679,10 +683,13 @@ static int bake(
}
pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
+ pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
/* get the mesh as it arrives in the renderer */
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_low);
+ BKE_mesh_tessface_ensure(me_low);
/* populate the pixel array with the face data */
if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -697,7 +704,9 @@ static int bake(
/* prepare cage mesh */
if (ob_cage) {
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_cage);
+ BKE_mesh_tessface_ensure(me_cage);
if (me_low->totface != me_cage->totface) {
BKE_report(reports, RPT_ERROR,
"Invalid cage object, the cage mesh must have the same number "
@@ -729,7 +738,9 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_cage);
+ BKE_mesh_tessface_ensure(me_cage);
RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
@@ -746,8 +757,6 @@ static int bake(
/* initialize highpoly_data */
highpoly[i].ob = ob_iter;
highpoly[i].restrict_flag = ob_iter->restrictflag;
- highpoly[i].pixel_array = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
-
/* triangulating so BVH returns the primitive_id that will be used for rendering */
highpoly[i].tri_mod = ED_object_modifier_add(
@@ -757,18 +766,16 @@ static int bake(
tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
- highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 1, 0);
+ highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0);
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
+ BKE_mesh_split_faces(highpoly[i].me);
+ BKE_mesh_tessface_ensure(highpoly[i].me);
/* lowpoly to highpoly transformation matrix */
copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
invert_m4_m4(highpoly[i].imat, highpoly[i].obmat);
- /* rotation */
- normalize_m4_m4(highpoly[i].rotmat, highpoly[i].imat);
- zero_v3(highpoly[i].rotmat[3]);
- if (is_negative_m4(highpoly[i].rotmat))
- negate_m3(highpoly[i].rotmat);
+ highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat);
i++;
}
@@ -779,7 +786,7 @@ static int bake(
/* populate the pixel arrays with the corresponding face data for each high poly object */
if (!RE_bake_pixels_populate_from_objects(
- me_low, pixel_array_low, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
+ me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage))
{
BKE_report(reports, RPT_ERROR, "Error handling selected objects");
@@ -788,8 +795,8 @@ static int bake(
/* the baking itself */
for (i = 0; i < tot_highpoly; i++) {
- ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
- depth, pass_type, result);
+ ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
+ num_pixels, depth, pass_type, result);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
goto cage_cleanup;
@@ -815,7 +822,7 @@ cage_cleanup:
ob_low->restrictflag &= ~OB_RESTRICT_RENDER;
if (RE_bake_has_engine(re)) {
- ok = RE_bake_engine(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
+ ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result);
}
else {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -864,7 +871,9 @@ cage_cleanup:
md->mode &= ~eModifierMode_Render;
}
- me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_nores);
+ BKE_mesh_tessface_ensure(me_nores);
RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
@@ -916,7 +925,7 @@ cage_cleanup:
BakeData *bake = &scene->r.bake;
char name[FILE_MAX];
- BKE_makepicstring_from_type(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);
+ BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL);
if (is_automatic_name) {
BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
@@ -977,9 +986,6 @@ cleanup:
for (i = 0; i < tot_highpoly; i++) {
highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;
- if (highpoly[i].pixel_array)
- MEM_freeN(highpoly[i].pixel_array);
-
if (highpoly[i].tri_mod)
ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod);
@@ -997,6 +1003,9 @@ cleanup:
if (pixel_array_low)
MEM_freeN(pixel_array_low);
+ if (pixel_array_high)
+ MEM_freeN(pixel_array_high);
+
if (bake_images.data)
MEM_freeN(bake_images.data);
@@ -1081,8 +1090,9 @@ static int bake_exec(bContext *C, wmOperator *op)
/* setup new render */
RE_test_break_cb(re, NULL, bake_break);
- if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active))
- return OPERATOR_CANCELLED;
+ if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
+ goto finally;
+ }
if (bkr.is_clear) {
const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT));
@@ -1117,6 +1127,8 @@ static int bake_exec(bContext *C, wmOperator *op)
RE_SetReports(re, NULL);
+
+finally:
BLI_freelistN(&bkr.selected_objects);
return result;
}
@@ -1208,7 +1220,7 @@ static void bake_set_props(wmOperator *op, Scene *scene)
prop = RNA_struct_find_property(op->ptr, "use_selected_to_active");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE));
+ RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
}
prop = RNA_struct_find_property(op->ptr, "cage_extrusion");
@@ -1248,22 +1260,22 @@ static void bake_set_props(wmOperator *op, Scene *scene)
prop = RNA_struct_find_property(op->ptr, "use_clear");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CLEAR));
+ RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CLEAR) != 0);
}
prop = RNA_struct_find_property(op->ptr, "use_cage");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CAGE));
+ RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CAGE) != 0);
}
prop = RNA_struct_find_property(op->ptr, "use_split_materials");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_SPLIT_MAT));
+ RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_SPLIT_MAT) != 0);
}
prop = RNA_struct_find_property(op->ptr, "use_automatic_name");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_AUTO_NAME));
+ RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_AUTO_NAME) != 0);
}
}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 92ed84b7f5e..2697a5e5fb1 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -40,7 +40,7 @@
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
@@ -226,14 +226,14 @@ static void update_pyconstraint_cb(void *arg1, void *arg2)
/* helper function for add_constriant - sets the last target for the active constraint */
static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
- num_targets = BLI_countlist(&targets);
+ num_targets = BLI_listbase_count(&targets);
if (index < 0) {
if (abs(index) < num_targets)
@@ -260,17 +260,221 @@ static void set_constraint_nth_target(bConstraint *con, Object *target, const ch
/* ------------- Constraint Sanity Testing ------------------- */
-/* checks validity of object pointers, and NULLs,
- * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag.
- */
-static void test_constraints(Object *owner, bPoseChannel *pchan)
+static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+ bool check_targets = true;
+
+ /* clear disabled-flag first */
+ con->flag &= ~CONSTRAINT_DISABLE;
+
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = con->data;
+
+ /* bad: we need a separate set of checks here as poletarget is
+ * optional... otherwise poletarget must exist too or else
+ * the constraint is deemed invalid
+ */
+ /* default IK check ... */
+ if (BKE_object_exists_check(data->tar) == 0) {
+ data->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ if (data->poletar) {
+ if (BKE_object_exists_check(data->poletar) == 0) {
+ data->poletar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->poletar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ /* ... can be overwritten here */
+ BIK_test_constraint(owner, con);
+ /* targets have already been checked for this */
+ check_targets = false;
+ }
+ else if (con->type == CONSTRAINT_TYPE_PIVOT) {
+ bPivotConstraint *data = con->data;
+
+ /* target doesn't have to exist, but if it is non-null, it must exist! */
+ if (data->tar && BKE_object_exists_check(data->tar) == 0) {
+ data->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* targets have already been checked for this */
+ check_targets = false;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = con->data;
+
+ /* validate action */
+ if (data->act == NULL) {
+ /* must have action */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->act->idroot != ID_OB) {
+ /* only object-rooted actions can be used */
+ data->act = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = con->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->upflag == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->upflag + 3 == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRACKTO) {
+ bTrackToConstraint *data = con->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->reserved2 == data->reserved1)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->reserved2 + 3 == data->reserved1)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_LOCKTRACK) {
+ bLockTrackConstraint *data = con->data;
+
+ if (data->lockflag == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->lockflag + 3 == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ bSplineIKConstraint *data = con->data;
+
+ /* if the number of points does not match the amount required by the chain length,
+ * free the points array and request a rebind...
+ */
+ if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) {
+ /* free the points array */
+ if (data->points) {
+ MEM_freeN(data->points);
+ data->points = NULL;
+ }
+
+ /* clear the bound flag, forcing a rebind next time this is evaluated */
+ data->flag &= ~CONSTRAINT_SPLINEIK_BOUND;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
+ if (data->clip != NULL && data->track[0]) {
+ MovieTracking *tracking = &data->clip->tracking;
+ MovieTrackingObject *tracking_object;
+
+ if (data->object[0])
+ tracking_object = BKE_tracking_object_get_named(tracking, data->object);
+ else
+ tracking_object = BKE_tracking_object_get_camera(tracking);
+
+ if (!tracking_object) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
+ bCameraSolverConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+
+ /* Check targets for constraints */
+ if (check_targets && cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ /* disable and clear constraints targets that are incorrect */
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* general validity checks (for those constraints that need this) */
+ if (BKE_object_exists_check(ct->tar) == 0) {
+ /* object doesn't exist, but constraint requires target */
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (ct->tar == owner) {
+ if (type == CONSTRAINT_OBTYPE_BONE) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) {
+ /* bone must exist in armature... */
+ /* TODO: clear subtarget? */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (STREQ(pchan->name, ct->subtarget)) {
+ /* cannot target self */
+ ct->subtarget[0] = '\0';
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else {
+ /* cannot use self as target */
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* target checks for specific constraints */
+ if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
+ if (ct->tar) {
+ if (ct->tar->type != OB_CURVE) {
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ Curve *cu = ct->tar->data;
+
+ /* auto-set 'Path' setting on curve so this works */
+ cu->flag |= CU_PATH;
+ }
+ }
+ }
+ }
+
+ /* free any temporary targets */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+}
+
+static int constraint_type_get(Object *owner, bPoseChannel *pchan)
{
- bConstraint *curcon;
- ListBase *conlist = NULL;
int type;
-
- if (owner == NULL) return;
-
/* Check parents */
if (pchan) {
switch (owner->type) {
@@ -284,7 +488,22 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
}
else
type = CONSTRAINT_OBTYPE_OBJECT;
+ return type;
+}
+
+/* checks validity of object pointers, and NULLs,
+ * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag.
+ */
+static void test_constraints(Object *owner, bPoseChannel *pchan)
+{
+ bConstraint *curcon;
+ ListBase *conlist = NULL;
+ int type;
+ if (owner == NULL) return;
+
+ type = constraint_type_get(owner, pchan);
+
/* Get the constraint list for this object */
switch (type) {
case CONSTRAINT_OBTYPE_OBJECT:
@@ -298,213 +517,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
/* Check all constraints - is constraint valid? */
if (conlist) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* clear disabled-flag first */
- curcon->flag &= ~CONSTRAINT_DISABLE;
-
- if (curcon->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = curcon->data;
-
- /* bad: we need a separate set of checks here as poletarget is
- * optional... otherwise poletarget must exist too or else
- * the constraint is deemed invalid
- */
- /* default IK check ... */
- if (BKE_object_exists_check(data->tar) == 0) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->tar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- if (data->poletar) {
- if (BKE_object_exists_check(data->poletar) == 0) {
- data->poletar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->poletar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- }
- /* ... can be overwritten here */
- BIK_test_constraint(owner, curcon);
- /* targets have already been checked for this */
- continue;
- }
- else if (curcon->type == CONSTRAINT_TYPE_PIVOT) {
- bPivotConstraint *data = curcon->data;
-
- /* target doesn't have to exist, but if it is non-null, it must exist! */
- if (data->tar && BKE_object_exists_check(data->tar) == 0) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->tar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- /* targets have already been checked for this */
- continue;
- }
- else if (curcon->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = curcon->data;
-
- /* validate action */
- if (data->act == NULL) {
- /* must have action */
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->act->idroot != ID_OB) {
- /* only object-rooted actions can be used */
- data->act = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_FOLLOWPATH) {
- bFollowPathConstraint *data = curcon->data;
-
- /* don't allow track/up axes to be the same */
- if (data->upflag == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->upflag + 3 == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_TRACKTO) {
- bTrackToConstraint *data = curcon->data;
-
- /* don't allow track/up axes to be the same */
- if (data->reserved2 == data->reserved1)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->reserved2 + 3 == data->reserved1)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_LOCKTRACK) {
- bLockTrackConstraint *data = curcon->data;
-
- if (data->lockflag == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->lockflag + 3 == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_SPLINEIK) {
- bSplineIKConstraint *data = curcon->data;
-
- /* if the number of points does not match the amount required by the chain length,
- * free the points array and request a rebind...
- */
- if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) {
- /* free the points array */
- if (data->points) {
- MEM_freeN(data->points);
- data->points = NULL;
- }
-
- /* clear the bound flag, forcing a rebind next time this is evaluated */
- data->flag &= ~CONSTRAINT_SPLINEIK_BOUND;
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
- if (data->clip != NULL && data->track[0]) {
- MovieTracking *tracking = &data->clip->tracking;
- MovieTrackingObject *tracking_object;
-
- if (data->object[0])
- tracking_object = BKE_tracking_object_get_named(tracking, data->object);
- else
- tracking_object = BKE_tracking_object_get_camera(tracking);
-
- if (!tracking_object) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else {
- if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- bCameraSolverConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
-
- /* Check targets for constraints */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- /* disable and clear constraints targets that are incorrect */
- for (ct = targets.first; ct; ct = ct->next) {
- /* general validity checks (for those constraints that need this) */
- if (BKE_object_exists_check(ct->tar) == 0) {
- /* object doesn't exist, but constraint requires target */
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (ct->tar == owner) {
- if (type == CONSTRAINT_OBTYPE_BONE) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) {
- /* bone must exist in armature... */
- /* TODO: clear subtarget? */
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (strcmp(pchan->name, ct->subtarget) == 0) {
- /* cannot target self */
- ct->subtarget[0] = '\0';
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else {
- /* cannot use self as target */
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- /* target checks for specific constraints */
- if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
- if (ct->tar) {
- if (ct->tar->type != OB_CURVE) {
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else {
- Curve *cu = ct->tar->data;
-
- /* auto-set 'Path' setting on curve so this works */
- cu->flag |= CU_PATH;
- }
- }
- }
- }
-
- /* free any temporary targets */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ test_constraint(owner, pchan, curcon, type);
}
}
}
@@ -524,6 +537,26 @@ void object_test_constraints(Object *owner)
}
}
+static void object_test_constraint(Object *owner, bConstraint *con)
+{
+ if (owner->type == OB_ARMATURE && owner->pose) {
+ if (BLI_findindex(&owner->constraints, con) != -1) {
+ test_constraint(owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT);
+ }
+ else {
+ bPoseChannel *pchan;
+ for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_findindex(&pchan->constraints, con) != -1) {
+ test_constraint(owner, pchan, con, CONSTRAINT_OBTYPE_BONE);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ test_constraint(owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT);
+ }
+}
/************************ generic functions for operators using constraint names and data context *********************/
@@ -1161,11 +1194,50 @@ void ED_object_constraint_update(Object *ob)
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
+static void object_pose_tag_update(Main *bmain, Object *ob)
+{
+ BKE_pose_tag_recalc(bmain, ob->pose); /* Checks & sort pose channels. */
+ if (ob->proxy && ob->adt) {
+ /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
+ * after calling `BKE_pose_rebuild()`, which causes T43872.
+ * Note that this is a bit wide here, since we cannot be sure whether there are some locked proxy bones
+ * or not...
+ * XXX Temp hack until new depsgraph hopefully solves this. */
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
+}
+
void ED_object_constraint_dependency_update(Main *bmain, Object *ob)
{
ED_object_constraint_update(ob);
- if (ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels
+ if (ob->pose) {
+ object_pose_tag_update(bmain, ob);
+ }
+ DAG_relations_tag_update(bmain);
+}
+
+void ED_object_constraint_tag_update(Object *ob, bConstraint *con)
+{
+ if (ob->pose) {
+ BKE_pose_tag_update_constraint_flags(ob->pose);
+ }
+
+ object_test_constraint(ob, con);
+
+ if (ob->type == OB_ARMATURE)
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ else
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+}
+
+void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con)
+{
+ ED_object_constraint_tag_update(ob, con);
+
+ if (ob->pose) {
+ object_pose_tag_update(bmain, ob);
+ }
DAG_relations_tag_update(bmain);
}
@@ -1182,20 +1254,16 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ptr.id.data;
bConstraint *con = ptr.data;
ListBase *lb = get_constraint_lb(ob, con, NULL);
- const bool is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK);
/* free the constraint */
- if (BKE_constraint_remove(lb, con)) {
+ if (BKE_constraint_remove_ex(lb, ob, con, true)) {
/* there's no active constraint now, so make sure this is the case */
- BKE_constraints_active_set(lb, NULL);
-
+ BKE_constraints_active_set(&ob->constraints, NULL);
ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
-
- /* ITASC needs to be rebuilt once a constraint is removed [#26920] */
- if (is_ik) {
- BIK_clear_data(ob->pose);
- }
-
+
+ /* relatiols */
+ DAG_relations_tag_update(CTX_data_main(C));
+
/* notifiers */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
@@ -1399,6 +1467,8 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ ListBase lb;
+ CollectionPointerLink *link;
/* don't do anything if bone doesn't exist or doesn't have any constraints */
if (ELEM(NULL, pchan, pchan->constraints.first)) {
@@ -1407,16 +1477,22 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
}
/* copy all constraints from active posebone to all selected posebones */
- CTX_DATA_BEGIN (C, bPoseChannel *, chan, selected_pose_bones)
- {
+ CTX_data_selected_pose_bones(C, &lb);
+ for (link = lb.first; link; link = link->next) {
+ Object *ob = link->ptr.id.data;
+ bPoseChannel *chan = link->ptr.data;
+
/* if we're not handling the object we're copying from, copy all constraints over */
if (pchan != chan) {
BKE_constraints_copy(&chan->constraints, &pchan->constraints, true);
/* update flags (need to add here, not just copy) */
chan->constflag |= pchan->constflag;
+
+ BKE_pose_tag_recalc(bmain, ob->pose);
+ DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
}
}
- CTX_DATA_END;
+ BLI_freelistN(&lb);
/* force depsgraph to get recalculated since new relationships added */
DAG_relations_tag_update(bmain);
@@ -1589,7 +1665,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
Object *obt;
/* add new target object */
- obt = BKE_object_add(bmain, scene, OB_EMPTY);
+ obt = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
/* set layers OK */
newbase = BASACT;
@@ -1723,7 +1799,13 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
DAG_relations_tag_update(bmain);
if ((ob->type == OB_ARMATURE) && (pchan)) {
- ob->pose->flag |= POSE_RECALC; /* sort pose channels */
+ BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */
+ if (BKE_constraints_proxylocked_owner(ob, pchan) && ob->adt) {
+ /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
+ * after calling `BKE_pose_rebuild()`, which causes T43872.
+ * XXX Temp hack until new depsgraph hopefully solves this. */
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
}
else
@@ -1889,8 +1971,8 @@ static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
}
/* prepare popup menu to choose targetting options */
- pup = uiPupMenuBegin(C, IFACE_("Add IK"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Add IK"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
/* the type of targets we'll set determines the menu entries to show... */
if (get_new_constraint_target(C, CONSTRAINT_TYPE_KINEMATIC, &tar_ob, &tar_pchan, 0)) {
@@ -1909,9 +1991,9 @@ static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
}
/* finish building the menu, and process it (should result in calling self again) */
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
/* call constraint_add_exec() to add the IK constraint */
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
new file mode 100644
index 00000000000..95e1204e122
--- /dev/null
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -0,0 +1,729 @@
+/*
+ * ***** 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 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_data_transfer.c
+ * \ingroup edobj
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_data_transfer.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_remap.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "object_intern.h"
+
+/* All possible data to transfer.
+ * Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */
+/* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */
+static EnumPropertyItem DT_layer_items[] = {
+ {0, "", 0, "Vertex Data", ""},
+ {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"},
+#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */
+ {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"},
+#endif
+#if 0 /* XXX When SkinModifier is enabled, it seems to erase its own CD_MVERT_SKIN layer from final DM :( */
+ {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"},
+#endif
+ {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"},
+ {0, "", 0, "Edge Data", ""},
+ {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"},
+ {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"},
+ {DT_TYPE_CREASE, "CREASE", 0, "Subsurf Crease", "Transfer crease values"},
+ {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"},
+ {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"},
+ {0, "", 0, "Face Corner Data", ""},
+ {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
+ {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"},
+ {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
+ {0, "", 0, "Face Data", ""},
+ {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"},
+ {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", 0, "Freestyle Mark", "Transfer Freestyle face mark"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Note: DT_layers_select_src_items enum is from rna_modifier.c */
+static EnumPropertyItem *dt_layers_select_src_itemf(
+ bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *item = NULL, tmp_item = {0};
+ int totitem = 0;
+
+ const int data_type = RNA_enum_get(ptr, "data_type");
+
+ if (!C) { /* needed for docs and i18n tools */
+ return DT_layers_select_src_items;
+ }
+
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC);
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ALL_SRC);
+
+ if (data_type == DT_TYPE_MDEFORMVERT) {
+ Object *ob_src = CTX_data_active_object(C);
+
+ if (BKE_object_pose_armature_get(ob_src)) {
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
+ }
+
+ if (ob_src) {
+ bDeformGroup *dg;
+ int i;
+
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = dg->name;
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
+ }
+ }
+ else if (data_type == DT_TYPE_SHAPEKEY) {
+ /* TODO */
+ }
+ else if (data_type == DT_TYPE_UV) {
+ Object *ob_src = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (ob_src) {
+ DerivedMesh *dm_src;
+ CustomData *pdata;
+ int num_data, i;
+
+ /* XXX Is this OK? */
+ dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY);
+ pdata = dm_src->getPolyDataLayout(dm_src);
+ num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ for (i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
+ }
+ }
+ else if (data_type == DT_TYPE_VCOL) {
+ Object *ob_src = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (ob_src) {
+ DerivedMesh *dm_src;
+ CustomData *ldata;
+ int num_data, i;
+
+ /* XXX Is this OK? */
+ dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
+ ldata = dm_src->getLoopDataLayout(dm_src);
+ num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ for (i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+/* Note: DT_layers_select_dst_items enum is from rna_modifier.c */
+static EnumPropertyItem *dt_layers_select_dst_itemf(
+ bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ const int layers_select_src = RNA_enum_get(ptr, "layers_select_src");
+
+ if (!C) { /* needed for docs and i18n tools */
+ return DT_layers_select_dst_items;
+ }
+
+ if (layers_select_src == DT_LAYERS_ACTIVE_SRC || layers_select_src >= 0) {
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST);
+ }
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_NAME_DST);
+ RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_INDEX_DST);
+
+ /* No 'specific' to-layers here, since we may transfer to several objects at once! */
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static EnumPropertyItem *dt_layers_select_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
+{
+ const bool reverse_transfer = RNA_boolean_get(ptr, "use_reverse_transfer");
+
+ if (STREQ(RNA_property_identifier(prop), "layers_select_dst")) {
+ if (reverse_transfer) {
+ return dt_layers_select_src_itemf(C, ptr, prop, r_free);
+ }
+ else {
+ return dt_layers_select_dst_itemf(C, ptr, prop, r_free);
+ }
+ }
+ else if (reverse_transfer) {
+ return dt_layers_select_dst_itemf(C, ptr, prop, r_free);
+ }
+ else {
+ return dt_layers_select_src_itemf(C, ptr, prop, r_free);
+ }
+}
+
+/* Note: DT_mix_mode_items enum is from rna_modifier.c */
+static EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ const int dtdata_type = RNA_enum_get(ptr, "data_type");
+ bool support_advanced_mixing, support_threshold;
+
+ if (!C) { /* needed for docs and i18n tools */
+ return DT_mix_mode_items;
+ }
+
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_TRANSFER);
+
+ BKE_object_data_transfer_get_dttypes_capacity(dtdata_type, &support_advanced_mixing, &support_threshold);
+
+ if (support_threshold) {
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD);
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD);
+ }
+
+ if (support_advanced_mixing) {
+ RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MIX);
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_ADD);
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_SUB);
+ RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MUL);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static bool data_transfer_check(bContext *UNUSED(C), wmOperator *op)
+{
+ const int layers_select_src = RNA_enum_get(op->ptr, "layers_select_src");
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "layers_select_dst");
+ const int layers_select_dst = RNA_property_enum_get(op->ptr, prop);
+
+ /* TODO: check for invalid layers_src select modes too! */
+
+ if ((layers_select_src != DT_LAYERS_ACTIVE_SRC) && (layers_select_dst == DT_LAYERS_ACTIVE_DST)) {
+ RNA_property_enum_set(op->ptr, prop, DT_LAYERS_NAME_DST);
+ return true;
+ }
+
+ return false;
+}
+
+/* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */
+static void data_transfer_exec_preprocess_objects(
+ bContext *C, wmOperator *op, Object *ob_src, ListBase *ctx_objects, const bool reverse_transfer)
+{
+ CollectionPointerLink *ctx_ob;
+ CTX_data_selected_editable_objects(C, ctx_objects);
+
+ if (reverse_transfer) {
+ return; /* Nothing else to do in this case... */
+ }
+
+ for (ctx_ob = ctx_objects->first; ctx_ob; ctx_ob = ctx_ob->next) {
+ Object *ob = ctx_ob->ptr.data;
+ Mesh *me;
+ if ((ob == ob_src) || (ob->type != OB_MESH)) {
+ continue;
+ }
+
+ me = ob->data;
+ if (me->id.lib) {
+ /* Do not transfer to linked data, not supported. */
+ BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified",
+ ob->id.name + 2, me->id.name + 2);
+ me->id.flag &= ~LIB_DOIT;
+ continue;
+ }
+
+ me->id.flag |= LIB_DOIT;
+ }
+}
+
+/* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */
+static bool data_transfer_exec_is_object_valid(
+ wmOperator *op, Object *ob_src, Object *ob_dst, const bool reverse_transfer)
+{
+ Mesh *me;
+ if ((ob_dst == ob_src) || (ob_src->type != OB_MESH) || (ob_dst->type != OB_MESH)) {
+ return false;
+ }
+
+ if (reverse_transfer) {
+ return true;
+ }
+
+ me = ob_dst->data;
+ if (me->id.flag & LIB_DOIT) {
+ me->id.flag &= ~LIB_DOIT;
+ return true;
+ }
+ else if (me->id.lib == NULL) {
+ /* Do not transfer apply operation more than once. */
+ /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Skipping object '%s', data '%s' has already been processed with a previous object",
+ ob_dst->id.name + 2, me->id.name + 2);
+ }
+ return false;
+}
+
+static int data_transfer_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob_src = ED_object_active_context(C);
+
+ ListBase ctx_objects;
+ CollectionPointerLink *ctx_ob_dst;
+
+ bool changed = false;
+
+ const bool is_frozen = RNA_boolean_get(op->ptr, "use_freeze");
+
+ const bool reverse_transfer = RNA_boolean_get(op->ptr, "use_reverse_transfer");
+
+ const int data_type = RNA_enum_get(op->ptr, "data_type");
+ const bool use_create = RNA_boolean_get(op->ptr, "use_create");
+
+ const int map_vert_mode = RNA_enum_get(op->ptr, "vert_mapping");
+ const int map_edge_mode = RNA_enum_get(op->ptr, "edge_mapping");
+ const int map_loop_mode = RNA_enum_get(op->ptr, "loop_mapping");
+ const int map_poly_mode = RNA_enum_get(op->ptr, "poly_mapping");
+
+ const bool use_auto_transform = RNA_boolean_get(op->ptr, "use_auto_transform");
+ const bool use_object_transform = RNA_boolean_get(op->ptr, "use_object_transform");
+ const bool use_max_distance = RNA_boolean_get(op->ptr, "use_max_distance");
+ const float max_distance = use_max_distance ? RNA_float_get(op->ptr, "max_distance") : FLT_MAX;
+ const float ray_radius = RNA_float_get(op->ptr, "ray_radius");
+ const float islands_precision = RNA_float_get(op->ptr, "islands_precision");
+
+ const int layers_src = RNA_enum_get(op->ptr, "layers_select_src");
+ const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst");
+ int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0};
+ int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0};
+ const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type);
+
+ const int mix_mode = RNA_enum_get(op->ptr, "mix_mode");
+ const float mix_factor = RNA_float_get(op->ptr, "mix_factor");
+
+ SpaceTransform space_transform_data;
+ SpaceTransform *space_transform = (use_object_transform && !use_auto_transform) ? &space_transform_data : NULL;
+
+ if (is_frozen) {
+ BKE_report(op->reports, RPT_INFO,
+ "Operator is frozen, changes to its settings won't take effect until you unfreeze it");
+ return OPERATOR_FINISHED;
+ }
+
+ if (reverse_transfer && ((ID *)(ob_src->data))->lib) {
+ /* Do not transfer to linked data, not supported. */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
+ layers_select_src[fromto_idx] = layers_src;
+ layers_select_dst[fromto_idx] = layers_dst;
+ }
+
+ data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, reverse_transfer);
+
+ for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) {
+ Object *ob_dst = ctx_ob_dst->ptr.data;
+
+ if (reverse_transfer) {
+ SWAP(Object *, ob_src, ob_dst);
+ }
+
+ if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, reverse_transfer)) {
+ if (space_transform) {
+ BLI_SPACE_TRANSFORM_SETUP(space_transform, ob_dst, ob_src);
+ }
+
+ if (BKE_object_data_transfer_mesh(
+ scene, ob_src, ob_dst, data_type, use_create,
+ map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode,
+ space_transform, use_auto_transform,
+ max_distance, ray_radius, islands_precision,
+ layers_select_src, layers_select_dst,
+ mix_mode, mix_factor, NULL, false, op->reports))
+ {
+ changed = true;
+ }
+ }
+
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+
+ if (reverse_transfer) {
+ SWAP(Object *, ob_src, ob_dst);
+ }
+ }
+
+ BLI_freelistN(&ctx_objects);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+#if 0 /* TODO */
+ /* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+#else
+ (void)changed;
+ return OPERATOR_FINISHED;
+#endif
+}
+
+/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */
+/* Note this context poll is only really partial, it cannot check for all possible invalid cases. */
+static int data_transfer_poll(bContext *C)
+{
+ Object *ob = ED_object_active_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ return (ob && ob->type == OB_MESH && data);
+}
+
+/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */
+static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
+{
+ PropertyRNA *prop_other;
+
+ const char *prop_id = RNA_property_identifier(prop);
+ const int data_type = RNA_enum_get(ptr, "data_type");
+ bool use_auto_transform = false;
+ bool use_max_distance = false;
+ bool use_modifier = false;
+
+ if ((prop_other = RNA_struct_find_property(ptr, "use_auto_transform"))) {
+ use_auto_transform = RNA_property_boolean_get(ptr, prop_other);
+ }
+ if ((prop_other = RNA_struct_find_property(ptr, "use_max_distance"))) {
+ use_max_distance = RNA_property_boolean_get(ptr, prop_other);
+ }
+ if ((prop_other = RNA_struct_find_property(ptr, "modifier"))) {
+ use_modifier = RNA_property_is_set(ptr, prop_other);
+ }
+
+ if (STREQ(prop_id, "modifier")) {
+ return use_modifier;
+ }
+
+ if (use_modifier) {
+ /* Hide everything but 'modifier' property, if set. */
+ return false;
+ }
+
+ if (STREQ(prop_id, "use_object_transform") && use_auto_transform) {
+ return false;
+ }
+ if (STREQ(prop_id, "max_distance") && !use_max_distance) {
+ return false;
+ }
+ if (STREQ(prop_id, "islands_precision") && !DT_DATATYPE_IS_LOOP(data_type)) {
+ return false;
+ }
+
+ if (STREQ(prop_id, "vert_mapping") && !DT_DATATYPE_IS_VERT(data_type)) {
+ return false;
+ }
+ if (STREQ(prop_id, "edge_mapping") && !DT_DATATYPE_IS_EDGE(data_type)) {
+ return false;
+ }
+ if (STREQ(prop_id, "loop_mapping") && !DT_DATATYPE_IS_LOOP(data_type)) {
+ return false;
+ }
+ if (STREQ(prop_id, "poly_mapping") && !DT_DATATYPE_IS_POLY(data_type)) {
+ return false;
+ }
+
+ if ((STREQ(prop_id, "layers_select_src") || STREQ(prop_id, "layers_select_dst")) &&
+ !DT_DATATYPE_IS_MULTILAYERS(data_type))
+ {
+ return false;
+ }
+
+ /* Else, show it! */
+ return true;
+}
+
+/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */
+static void data_transfer_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, data_transfer_draw_check_prop, '\0');
+}
+
+/* transfers weight from active to selected */
+void OBJECT_OT_data_transfer(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* Identifiers.*/
+ ot->name = "Transfer Mesh Data";
+ ot->idname = "OBJECT_OT_data_transfer";
+ ot->description = "Transfer data layer(s) (weights, edge sharp, ...) from active to selected meshes";
+
+ /* API callbacks.*/
+ ot->poll = data_transfer_poll;
+ ot->invoke = WM_menu_invoke;
+ ot->exec = data_transfer_exec;
+ ot->check = data_transfer_check;
+ ot->ui = data_transfer_ui;
+
+ /* Flags.*/
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties.*/
+ prop = RNA_def_boolean(ot->srna, "use_reverse_transfer", false, "Reverse Transfer",
+ "Transfer from selected objects to active one");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ RNA_def_boolean(ot->srna, "use_freeze", false, "Freeze Operator",
+ "Prevent changes to settings to re-run the operator, "
+ "handy to change several things at once with heavy geometry");
+
+ /* Data type to transfer. */
+ ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer");
+ RNA_def_boolean(ot->srna, "use_create", true, "Create Data", "Add data layers on destination meshes if needed");
+
+ /* Mapping methods. */
+ RNA_def_enum(ot->srna, "vert_mapping", DT_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping",
+ "Method used to map source vertices to destination ones");
+ RNA_def_enum(ot->srna, "edge_mapping", DT_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping",
+ "Method used to map source edges to destination ones");
+ RNA_def_enum(ot->srna, "loop_mapping", DT_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR,
+ "Face Corner Mapping", "Method used to map source faces' corners to destination ones");
+ RNA_def_enum(ot->srna, "poly_mapping", DT_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping",
+ "Method used to map source faces to destination ones");
+
+ /* Mapping options and filtering. */
+ RNA_def_boolean(ot->srna, "use_auto_transform", false, "Auto Transform",
+ "Automatically compute transformation to get the best possible match between source and "
+ "destination meshes (WARNING: results will never be as good as manual matching of objects)");
+ RNA_def_boolean(ot->srna, "use_object_transform", true, "Object Transform",
+ "Evaluate source and destination meshes in global space");
+ RNA_def_boolean(ot->srna, "use_max_distance", false, "Only Neighbor Geometry",
+ "Source elements must be closer than given distance from destination one");
+ prop = RNA_def_float(ot->srna, "max_distance", 1.0f, 0.0f, FLT_MAX, "Max Distance",
+ "Maximum allowed distance between source and destination element, for non-topology mappings",
+ 0.0f, 100.0f);
+ RNA_def_property_subtype(prop, PROP_DISTANCE);
+ prop = RNA_def_float(ot->srna, "ray_radius", 0.0f, 0.0f, FLT_MAX, "Ray Radius",
+ "'Width' of rays (especially useful when raycasting against vertices or edges)",
+ 0.0f, 10.0f);
+ RNA_def_property_subtype(prop, PROP_DISTANCE);
+ prop = RNA_def_float(ot->srna, "islands_precision", 0.1f, 0.0f, 10.0f, "Islands Precision",
+ "Factor controlling precision of islands handling (the higher, the better the results)",
+ 0.0f, 1.0f);
+ RNA_def_property_subtype(prop, PROP_FACTOR);
+
+ /* How to handle multi-layers types of data. */
+ prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC,
+ "Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf);
+
+ prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST,
+ "Destination Layers Matching", "How to match source and destination layers");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf);
+
+ prop = RNA_def_enum(ot->srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode",
+ "How to affect destination elements with source values");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_mix_mode_itemf);
+ RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor",
+ "Factor to use when applying data to destination (exact behavior depends on mix mode)", 0.0f, 1.0f);
+}
+
+/******************************************************************************/
+/* Note: This operator is hybrid, it can work as a usual standalone Object operator,
+ * or as a DataTransfer modifier tool.
+ */
+
+static int datalayout_transfer_poll(bContext *C)
+{
+ return (edit_modifier_poll_generic(C, &RNA_DataTransferModifier, (1 << OB_MESH)) || data_transfer_poll(C));
+}
+
+static int datalayout_transfer_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob_act = ED_object_active_context(C);
+ DataTransferModifierData *dtmd;
+
+ dtmd = (DataTransferModifierData *)edit_modifier_property_get(op, ob_act, eModifierType_DataTransfer);
+
+ /* If we have a modifier, we transfer data layout from this modifier's source object to active one.
+ * Else, we transfer data layout from active object to all selected ones. */
+ if (dtmd) {
+ Object *ob_src = dtmd->ob_source;
+ Object *ob_dst = ob_act;
+
+ const bool use_delete = false; /* Never when used from modifier, for now. */
+
+ if (!ob_src) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete,
+ dtmd->layers_select_src, dtmd->layers_select_dst);
+
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ }
+ else {
+ Object *ob_src = ob_act;
+
+ ListBase ctx_objects;
+ CollectionPointerLink *ctx_ob_dst;
+
+ const int data_type = RNA_enum_get(op->ptr, "data_type");
+ const bool use_delete = RNA_boolean_get(op->ptr, "use_delete");
+
+ const int layers_src = RNA_enum_get(op->ptr, "layers_select_src");
+ const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst");
+ int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0};
+ int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0};
+ const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type);
+
+ if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
+ layers_select_src[fromto_idx] = layers_src;
+ layers_select_dst[fromto_idx] = layers_dst;
+ }
+
+ data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, false);
+
+ for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) {
+ Object *ob_dst = ctx_ob_dst->ptr.data;
+ if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, false)) {
+ BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete,
+ layers_select_src, layers_select_dst);
+ }
+
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ }
+
+ BLI_freelistN(&ctx_objects);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int datalayout_transfer_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return datalayout_transfer_exec(C, op);
+ }
+ else {
+ return WM_menu_invoke(C, op, event);
+ }
+}
+
+void OBJECT_OT_datalayout_transfer(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Transfer Mesh Data Layout";
+ ot->description = "Transfer layout of data layer(s) from active to selected meshes";
+ ot->idname = "OBJECT_OT_datalayout_transfer";
+
+ ot->poll = datalayout_transfer_poll;
+ ot->invoke = datalayout_transfer_invoke;
+ ot->exec = datalayout_transfer_exec;
+ ot->check = data_transfer_check;
+ ot->ui = data_transfer_ui;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties.*/
+ edit_modifier_properties(ot);
+
+ /* Data type to transfer. */
+ ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer");
+ RNA_def_boolean(ot->srna, "use_delete", false, "Exact Match",
+ "Also delete some data layers from destination if necessary, so that it matches exactly source");
+
+ /* How to handle multi-layers types of data. */
+ prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC,
+ "Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf);
+
+ prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST,
+ "Destination Layers Matching", "How to match source and destination layers");
+ RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf);
+}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 93956128b84..c87eeaeb4a3 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -42,6 +42,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLT_translation.h"
+
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_group_types.h"
@@ -63,7 +65,9 @@
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -315,7 +319,7 @@ void OBJECT_OT_hide_render_set(wmOperatorType *ot)
* Load EditMode data back into the object,
* optionally freeing the editmode data.
*/
-static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
+static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool freedata)
{
if (obedit == NULL) {
return false;
@@ -345,6 +349,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
ED_armature_from_edit(obedit->data);
if (freedata)
ED_armature_edit_free(obedit->data);
+ /* TODO(sergey): Pose channels might have been changed, so need
+ * to inform dependency graph about this. But is it really the
+ * best place to do this?
+ */
+ DAG_relations_tag_update(bmain);
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
load_editNurb(obedit);
@@ -373,7 +382,8 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
bool ED_object_editmode_load(Object *obedit)
{
- return ED_object_editmode_load_ex(obedit, false);
+ /* TODO(sergey): use proper main here? */
+ return ED_object_editmode_load_ex(G.main, obedit, false);
}
void ED_object_editmode_exit(bContext *C, int flag)
@@ -386,7 +396,7 @@ void ED_object_editmode_exit(bContext *C, int flag)
if (flag & EM_WAITCURSOR) waitcursor(1);
- if (ED_object_editmode_load_ex(obedit, freedata) == false) {
+ if (ED_object_editmode_load_ex(CTX_data_main(C), obedit, freedata) == false) {
/* in rare cases (background mode) its possible active object
* is flagged for editmode, without 'obedit' being set [#35489] */
if (UNLIKELY(scene->basact && (scene->basact->object->mode & OB_MODE_EDIT))) {
@@ -565,11 +575,11 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
{
const int mode_flag = OB_MODE_EDIT;
const bool is_mode_set = (CTX_data_edit_object(C) != NULL);
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ Scene *scene = CTX_data_scene(C);
if (!is_mode_set) {
- Scene *scene = CTX_data_scene(C);
- if (!ED_object_mode_compat_set(C, scene->basact->object, mode_flag, op->reports)) {
+ Object *ob = CTX_data_active_object(C);
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
@@ -579,7 +589,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
else
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
- ED_space_image_uv_sculpt_update(CTX_wm_manager(C), toolsettings);
+ ED_space_image_uv_sculpt_update(CTX_wm_manager(C), scene);
return OPERATOR_FINISHED;
}
@@ -895,6 +905,8 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->rdamping = ob->rdamping;
base->object->min_vel = ob->min_vel;
base->object->max_vel = ob->max_vel;
+ base->object->min_angvel = ob->min_angvel;
+ base->object->max_angvel = ob->max_angvel;
if (ob->gameflag & OB_BOUNDS) {
base->object->collision_boundtype = ob->collision_boundtype;
}
@@ -1347,7 +1359,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
ID *data;
Curve *cu;
Nurb *nu;
- int clear = (strcmp(op->idname, "OBJECT_OT_shade_flat") == 0);
+ int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat"));
bool done = false, linked_data = false;
CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects)
@@ -1701,7 +1713,7 @@ static int game_property_new_exec(bContext *C, wmOperator *op)
BLI_strncpy(prop->name, name, sizeof(prop->name));
}
- BKE_bproperty_unique(NULL, prop, 0); // make_unique_prop_names(prop->name);
+ BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
WM_event_add_notifier(C, NC_LOGIC, NULL);
return OPERATOR_FINISHED;
@@ -1766,6 +1778,77 @@ void OBJECT_OT_game_property_remove(wmOperatorType *ot)
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX);
}
+#define GAME_PROPERTY_MOVE_UP 1
+#define GAME_PROPERTY_MOVE_DOWN -1
+
+static int game_property_move(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bProperty *prop;
+ bProperty *otherprop = NULL;
+ const int index = RNA_int_get(op->ptr, "index");
+ const int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ prop = BLI_findlink(&ob->prop, index);
+ /* invalid index */
+ if (prop == NULL)
+ return OPERATOR_CANCELLED;
+
+ if (dir == GAME_PROPERTY_MOVE_UP) {
+ otherprop = prop->prev;
+ }
+ else if (dir == GAME_PROPERTY_MOVE_DOWN) {
+ otherprop = prop->next;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (prop && otherprop) {
+ BLI_listbase_swaplinks(&ob->prop, prop, otherprop);
+
+ WM_event_add_notifier(C, NC_LOGIC, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_game_property_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_property_move[] = {
+ {GAME_PROPERTY_MOVE_UP, "UP", 0, "Up", ""},
+ {GAME_PROPERTY_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Move Game Property";
+ ot->description = "Move game property";
+ ot->idname = "OBJECT_OT_game_property_move";
+
+ /* api callbacks */
+ ot->exec = game_property_move;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to move", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_enum(ot->srna, "direction", direction_property_move, 0, "Direction",
+ "Direction for moving the property");
+}
+
+#undef GAME_PROPERTY_MOVE_UP
+#undef GAME_PROPERTY_MOVE_DOWN
+
#define COPY_PROPERTIES_REPLACE 1
#define COPY_PROPERTIES_MERGE 2
#define COPY_PROPERTIES_COPY 3
@@ -1963,6 +2046,8 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op))
ob_iter->rdamping = ob->rdamping;
ob_iter->min_vel = ob->min_vel;
ob_iter->max_vel = ob->max_vel;
+ ob_iter->min_angvel = ob->min_angvel;
+ ob_iter->max_angvel = ob->max_angvel;
ob_iter->obstacleRad = ob->obstacleRad;
ob_iter->mass = ob->mass;
copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction);
@@ -1997,3 +2082,67 @@ void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* generic utility function */
+
+bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3])
+{
+ switch (obedit->type) {
+ case OB_MESH:
+ {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMEditSelection ese;
+
+ if (BM_select_history_active_get(em->bm, &ese)) {
+ BM_editselection_center(&ese, r_center);
+ return true;
+ }
+ break;
+ }
+ case OB_ARMATURE:
+ {
+ bArmature *arm = obedit->data;
+ EditBone *ebo = arm->act_edbone;
+
+ if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) {
+ copy_v3_v3(r_center, ebo->head);
+ return true;
+ }
+
+ break;
+ }
+ case OB_CURVE:
+ case OB_SURF:
+ {
+ Curve *cu = obedit->data;
+
+ if (ED_curve_active_center(cu, r_center)) {
+ return true;
+ }
+ break;
+ }
+ case OB_MBALL:
+ {
+ MetaBall *mb = obedit->data;
+ MetaElem *ml_act = mb->lastelem;
+
+ if (ml_act && (!select_only || (ml_act->flag & SELECT))) {
+ copy_v3_v3(r_center, &ml_act->x);
+ return true;
+ }
+ break;
+ }
+ case OB_LATTICE:
+ {
+ BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
+
+ if (actbp) {
+ copy_v3_v3(r_center, actbp->vec);
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 20e2e22cdf8..3c43f2729bd 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -61,47 +61,6 @@
/********************* 3d view operators ***********************/
-static bool group_link_early_exit_check(Group *group, Object *object)
-{
- GroupObject *group_object;
-
- for (group_object = group->gobject.first; group_object; group_object = group_object->next) {
- if (group_object->ob == object) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool check_object_instances_group_recursive(Object *object, Group *group)
-{
- if (object->dup_group) {
- Group *dup_group = object->dup_group;
- if ((dup_group->id.flag & LIB_DOIT) == 0) {
- /* Cycle already exists in groups, let's prevent further crappyness */
- return true;
- }
- /* flag the object to identify cyclic dependencies in further dupli groups */
- dup_group->id.flag &= ~LIB_DOIT;
-
- if (dup_group == group)
- return true;
- else {
- GroupObject *gob;
- for (gob = dup_group->gobject.first; gob; gob = gob->next) {
- if (check_object_instances_group_recursive(gob->ob, group))
- return true;
- }
- }
-
- /* un-flag the object, it's allowed to have the same group multiple times in parallel */
- dup_group->id.flag |= LIB_DOIT;
- }
-
- return false;
-}
-
/* can be called with C == NULL */
static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -185,15 +144,12 @@ static int objects_add_active_exec(bContext *C, wmOperator *op)
if (!BKE_group_object_exists(group, ob))
continue;
- /* for recursive check */
- BKE_main_id_tag_listbase(&bmain->group, true);
-
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
- if (group_link_early_exit_check(group, base->object))
+ if (BKE_group_object_exists(group, base->object))
continue;
- if (!check_object_instances_group_recursive(base->object, group)) {
+ if (!BKE_group_object_cyclic_check(bmain, base->object, group)) {
BKE_group_object_add(group, base->object, scene, base);
updated = true;
}
@@ -486,7 +442,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
* we could sckip all the dependency check and just consider
* operator is finished.
*/
- if (group_link_early_exit_check(group, ob)) {
+ if (BKE_group_object_exists(group, ob)) {
return OPERATOR_FINISHED;
}
@@ -495,8 +451,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
* It is also bad idea to add object to group which is in group which
* contains our current object.
*/
- BKE_main_id_tag_listbase(&bmain->group, true);
- if (check_object_instances_group_recursive(ob, group)) {
+ if (BKE_group_object_cyclic_check(bmain, ob, group)) {
BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 9f9a647c9f1..7b7f91b974d 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -254,7 +254,7 @@ static int return_editcurve_indexar(
}
if (totvert == 0) return 0;
- *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
+ *r_indexar = index = MEM_mallocN(sizeof(*index) * totvert, "hook indexar");
*r_tot = totvert;
nr = 0;
zero_v3(r_cent);
@@ -448,11 +448,12 @@ static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit)
Base *base, *basedit;
Object *ob;
- ob = BKE_object_add(bmain, scene, OB_EMPTY);
+ ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
basedit = BKE_scene_base_find(scene, obedit);
- base = BKE_scene_base_find(scene, ob);
+ base = scene->basact;
base->lay = ob->lay = obedit->lay;
+ BLI_assert(scene->basact->object == ob);
/* icky, BKE_object_add sets new base as active.
* so set it back to the original edit object */
@@ -503,6 +504,15 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
unit_m4(pose_mat);
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ if (mode == OBJECT_ADDHOOK_NEWOB) {
+ /* pass */
+ }
+ else {
+ /* may overwrite with pose-bone location, below */
+ mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]);
+ }
+
if (mode == OBJECT_ADDHOOK_SELOB_BONE) {
bArmature *arm = ob->data;
BLI_assert(ob->type == OB_ARMATURE);
@@ -514,6 +524,8 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
pchan_act = BKE_pose_channel_active(ob);
if (LIKELY(pchan_act)) {
invert_m4_m4(pose_mat, pchan_act->pose_mat);
+ mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
+ mul_v3_m4v3(cent, obedit->imat, cent);
}
}
else {
@@ -521,6 +533,9 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
}
}
+ copy_v3_v3(hmd->cent, cent);
+
+
/* matrix calculus */
/* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
/* (parentinv ) */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 6fa3caa6172..6344e04ef1b 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -32,12 +32,12 @@
#define __OBJECT_INTERN_H__
struct wmOperatorType;
-struct KeyBlock;
-struct Lattice;
-struct Curve;
struct Object;
-struct Mesh;
-struct HookModifierData;
+struct bContext;
+struct StructRNA;
+struct wmOperator;
+
+struct ModifierData;
/* add hook menu */
enum eObject_Hook_Add_Mode {
@@ -94,6 +94,7 @@ void OBJECT_OT_game_property_new(struct wmOperatorType *ot);
void OBJECT_OT_game_property_remove(struct wmOperatorType *ot);
void OBJECT_OT_game_property_copy(struct wmOperatorType *ot);
void OBJECT_OT_game_property_clear(struct wmOperatorType *ot);
+void OBJECT_OT_game_property_move(struct wmOperatorType *ot);
void OBJECT_OT_logic_bricks_copy(struct wmOperatorType *ot);
void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot);
@@ -155,6 +156,12 @@ void GROUP_OT_objects_add_active(struct wmOperatorType *ot);
void GROUP_OT_objects_remove_active(struct wmOperatorType *ot);
/* object_modifier.c */
+int edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag);
+int edit_modifier_poll(struct bContext *C);
+void edit_modifier_properties(struct wmOperatorType *ot);
+int edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op);
+struct ModifierData *edit_modifier_property_get(struct wmOperator *op, struct Object *ob, int type);
+
void OBJECT_OT_modifier_add(struct wmOperatorType *ot);
void OBJECT_OT_modifier_remove(struct wmOperatorType *ot);
void OBJECT_OT_modifier_move_up(struct wmOperatorType *ot);
@@ -168,6 +175,7 @@ void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
+void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
@@ -214,7 +222,6 @@ void OBJECT_OT_vertex_group_remove_from(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_select(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_deselect(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_copy_to_linked(struct wmOperatorType *ot);
-void OBJECT_OT_vertex_group_transfer_weight(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_copy_to_selected(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_copy(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_normalize(struct wmOperatorType *ot);
@@ -223,7 +230,7 @@ void OBJECT_OT_vertex_group_levels(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_lock(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_fix(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_invert(struct wmOperatorType *ot);
-void OBJECT_OT_vertex_group_blend(struct wmOperatorType *ot);
+void OBJECT_OT_vertex_group_smooth(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_clean(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_quantize(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_limit_total(struct wmOperatorType *ot);
@@ -238,7 +245,7 @@ void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
/* object_warp.c */
-void OBJECT_OT_vertex_warp(struct wmOperatorType *ot);
+void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
/* object_shapekey.c */
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);
@@ -264,7 +271,11 @@ void OBJECT_OT_lod_add(struct wmOperatorType *ot);
void OBJECT_OT_lod_remove(struct wmOperatorType *ot);
/* object_random.c */
-void OBJECT_OT_vertex_random(struct wmOperatorType *ot);
+void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
+
+/* object_transfer_data.c */
+void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
+void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot);
#endif /* __OBJECT_INTERN_H__ */
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index c24a127ed8b..76d9facf701 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -100,7 +100,7 @@ void make_editLatt(Object *obedit)
actkey = BKE_keyblock_from_object(obedit);
if (actkey)
- BKE_key_convert_to_lattice(actkey, lt);
+ BKE_keyblock_convert_to_lattice(actkey, lt);
lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt");
lt->editlatt->latt = MEM_dupallocN(lt);
@@ -713,7 +713,7 @@ static int lattice_flip_exec(bContext *C, wmOperator *op)
break;
default:
- printf("lattice_flip(): Unknown flipping axis (%d)\n", axis);
+ printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c
index 48e980015a7..ced306178b8 100644
--- a/source/blender/editors/object/object_lod.c
+++ b/source/blender/editors/object/object_lod.c
@@ -32,18 +32,22 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
-#include "BKE_object.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "ED_screen.h"
#include "ED_object.h"
+#ifdef WITH_GAMEENGINE
+# include "BKE_object.h"
+
+# include "RNA_enum_types.h"
+#endif
+
#include "object_intern.h"
static int object_lod_add_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index b05840b5823..8ef2bd1b2af 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -68,6 +68,7 @@
#include "BKE_multires.h"
#include "BKE_report.h"
#include "BKE_object.h"
+#include "BKE_object_deform.h"
#include "BKE_ocean.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -95,7 +96,7 @@ static void modifier_skin_customdata_delete(struct Object *ob);
ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
ModifierData *md = NULL, *new_md = NULL;
- ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(type);
/* only geometry objects should be able to get modifiers [#25291] */
if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
@@ -151,10 +152,10 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ob->pd = object_add_collision_fields(0);
ob->pd->deflect = 1;
- DAG_relations_tag_update(bmain);
}
- else if (type == eModifierType_Surface)
- DAG_relations_tag_update(bmain);
+ else if (type == eModifierType_Surface) {
+ /* pass */
+ }
else if (type == eModifierType_Multires) {
/* set totlvl from existing MDISPS layer if object already had it */
multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob);
@@ -171,6 +172,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(bmain);
return new_md;
}
@@ -246,7 +248,7 @@ static bool object_has_modifier_cb(Object *ob, void *data)
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
ModifierData *md;
- int totlevel = *((int *)totlevel_v);
+ int totlevel = *((char *)totlevel_v);
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Multires) {
@@ -318,6 +320,8 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
}
+ DAG_relations_tag_update(bmain);
+
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
@@ -367,10 +371,10 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->prev) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->type != eModifierTypeType_OnlyDeform) {
- ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
+ const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) {
BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data");
@@ -388,10 +392,10 @@ int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md
int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
- ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
+ const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
if (nmti->type != eModifierTypeType_OnlyDeform) {
BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier");
@@ -439,9 +443,9 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
for (a = 0; a < totpart; a++) {
key = cache[a];
- if (key->steps > 0) {
- totvert += key->steps + 1;
- totedge += key->steps;
+ if (key->segments > 0) {
+ totvert += key->segments + 1;
+ totedge += key->segments;
}
}
@@ -449,16 +453,16 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
for (a = 0; a < totchild; a++) {
key = cache[a];
- if (key->steps > 0) {
- totvert += key->steps + 1;
- totedge += key->steps;
+ if (key->segments > 0) {
+ totvert += key->segments + 1;
+ totedge += key->segments;
}
}
if (totvert == 0) return 0;
/* add new mesh */
- obn = BKE_object_add(bmain, scene, OB_MESH);
+ obn = BKE_object_add(bmain, scene, OB_MESH, NULL);
me = obn->data;
me->totvert = totvert;
@@ -475,7 +479,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
cache = psys->pathcache;
for (a = 0; a < totpart; a++) {
key = cache[a];
- kmax = key->steps;
+ kmax = key->segments;
for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) {
copy_v3_v3(mvert->co, key->co);
if (k) {
@@ -494,7 +498,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
cache = psys->childcache;
for (a = 0; a < totchild; a++) {
key = cache[a];
- kmax = key->steps;
+ kmax = key->segments;
for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) {
copy_v3_v3(mvert->co, key->co);
if (k) {
@@ -517,7 +521,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -560,7 +564,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M
/* if that was the first key block added, then it was the basis.
* Initialize it with the mesh, and add another for the modifier */
kb = BKE_keyblock_add(key, NULL);
- BKE_key_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, kb);
}
kb = BKE_keyblock_add(key, md->name);
@@ -577,7 +581,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M
static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -613,9 +617,7 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
return 0;
}
- DM_to_mesh(dm, me, ob, CD_MASK_MESH);
-
- dm->release(dm);
+ DM_to_mesh(dm, me, ob, CD_MASK_MESH, true);
if (md->type == eModifierType_Multires)
multires_customdata_delete(me);
@@ -743,7 +745,7 @@ static EnumPropertyItem *modifier_add_itemf(bContext *C, PointerRNA *UNUSED(ptr)
{
Object *ob = ED_object_active_context(C);
EnumPropertyItem *item = NULL, *md_item, *group_item = NULL;
- ModifierTypeInfo *mti;
+ const ModifierTypeInfo *mti;
int totitem = 0, a;
if (!ob)
@@ -807,7 +809,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot)
/************************ generic functions for operators using mod names and data context *********************/
-static int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
+int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
@@ -819,17 +821,17 @@ static int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obty
return 1;
}
-static int edit_modifier_poll(bContext *C)
+int edit_modifier_poll(bContext *C)
{
return edit_modifier_poll_generic(C, &RNA_Modifier, 0);
}
-static void edit_modifier_properties(wmOperatorType *ot)
+void edit_modifier_properties(wmOperatorType *ot)
{
RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
}
-static int edit_modifier_invoke_properties(bContext *C, wmOperator *op)
+int edit_modifier_invoke_properties(bContext *C, wmOperator *op)
{
ModifierData *md;
@@ -848,7 +850,7 @@ static int edit_modifier_invoke_properties(bContext *C, wmOperator *op)
return false;
}
-static ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
+ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
{
char modifier_name[MAX_NAME];
ModifierData *md;
@@ -1353,8 +1355,8 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- WM_operator_properties_filesel(ot, FOLDERFILE | BTXFILE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
edit_modifier_properties(ot);
}
@@ -1667,7 +1669,7 @@ static void skin_armature_bone_create(Object *skin_ob,
BLI_snprintf(bone->name, sizeof(bone->name), "Bone.%.2d", endx);
/* add bDeformGroup */
- if ((dg = ED_vgroup_add_name(skin_ob, bone->name))) {
+ if ((dg = BKE_object_defgroup_add_name(skin_ob, bone->name))) {
ED_vgroup_vert_add(skin_ob, dg, parent_v, 1, WEIGHT_REPLACE);
ED_vgroup_vert_add(skin_ob, dg, v, 1, WEIGHT_REPLACE);
}
@@ -1705,7 +1707,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
NULL,
me->totvert);
- arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE);
+ arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL);
BKE_object_transform_copy(arm_ob, skin_ob);
arm = arm_ob->data;
arm->layer = 1;
@@ -1816,6 +1818,73 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+/************************ delta mush bind operator *********************/
+
+static int correctivesmooth_poll(bContext *C)
+{
+ return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0);
+}
+
+static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get(op, ob, eModifierType_CorrectiveSmooth);
+ bool is_bind;
+
+ if (!csmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
+ BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ is_bind = (csmd->bind_coords != NULL);
+
+ MEM_SAFE_FREE(csmd->bind_coords);
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ if (is_bind) {
+ /* toggle off */
+ csmd->bind_coords_num = 0;
+ }
+ else {
+ /* signal to modifier to recalculate */
+ csmd->bind_coords_num = (unsigned int)-1;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return correctivesmooth_bind_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Corrective Smooth Bind";
+ ot->description = "Bind base pose in Corrective Smooth modifier";
+ ot->idname = "OBJECT_OT_correctivesmooth_bind";
+
+ /* api callbacks */
+ ot->poll = correctivesmooth_poll;
+ ot->invoke = correctivesmooth_bind_invoke;
+ ot->exec = correctivesmooth_bind_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
/************************ mdef bind operator *********************/
@@ -1979,7 +2048,7 @@ static void init_ocean_modifier_bake(struct Ocean *oc, struct OceanModifierData
do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
- BKE_init_ocean(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
+ BKE_ocean_init(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
omd->depth, omd->time,
do_heightfield, do_chop, do_normals, do_jacobian,
@@ -2037,7 +2106,7 @@ static void oceanbake_startjob(void *customdata, short *stop, short *do_update,
G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
- BKE_bake_ocean(oj->ocean, oj->och, oceanbake_update, (void *)oj);
+ BKE_ocean_bake(oj->ocean, oj->och, oceanbake_update, (void *)oj);
*do_update = true;
*stop = 0;
@@ -2048,7 +2117,7 @@ static void oceanbake_endjob(void *customdata)
OceanBakeJob *oj = customdata;
if (oj->ocean) {
- BKE_free_ocean(oj->ocean);
+ BKE_ocean_free(oj->ocean);
oj->ocean = NULL;
}
@@ -2079,7 +2148,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- och = BKE_init_ocean_cache(omd->cachepath, modifier_path_relbase(ob),
+ och = BKE_ocean_init_cache(omd->cachepath, modifier_path_relbase(ob),
omd->bakestart, omd->bakeend, omd->wave_scale,
omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
@@ -2113,11 +2182,11 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
}
/* make a copy of ocean to use for baking - threadsafety */
- ocean = BKE_add_ocean();
+ ocean = BKE_ocean_add();
init_ocean_modifier_bake(ocean, omd);
#if 0
- BKE_bake_ocean(ocean, och);
+ BKE_ocean_bake(ocean, och);
omd->oceancache = och;
omd->cached = true;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 7cf661de52c..22cac8638d9 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -40,7 +40,6 @@
#include "BKE_context.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -145,6 +144,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
WM_operatortype_append(OBJECT_OT_ocean_bake);
@@ -178,7 +178,6 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_group_select);
WM_operatortype_append(OBJECT_OT_vertex_group_deselect);
WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_linked);
- WM_operatortype_append(OBJECT_OT_vertex_group_transfer_weight);
WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_selected);
WM_operatortype_append(OBJECT_OT_vertex_group_copy);
WM_operatortype_append(OBJECT_OT_vertex_group_normalize);
@@ -187,7 +186,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_group_fix);
WM_operatortype_append(OBJECT_OT_vertex_group_invert);
WM_operatortype_append(OBJECT_OT_vertex_group_levels);
- WM_operatortype_append(OBJECT_OT_vertex_group_blend);
+ WM_operatortype_append(OBJECT_OT_vertex_group_smooth);
WM_operatortype_append(OBJECT_OT_vertex_group_clean);
WM_operatortype_append(OBJECT_OT_vertex_group_quantize);
WM_operatortype_append(OBJECT_OT_vertex_group_limit_total);
@@ -201,12 +200,13 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_weight_normalize_active_vertex);
WM_operatortype_append(OBJECT_OT_vertex_weight_copy);
- WM_operatortype_append(OBJECT_OT_vertex_warp);
+ WM_operatortype_append(TRANSFORM_OT_vertex_warp);
WM_operatortype_append(OBJECT_OT_game_property_new);
WM_operatortype_append(OBJECT_OT_game_property_remove);
WM_operatortype_append(OBJECT_OT_game_property_copy);
WM_operatortype_append(OBJECT_OT_game_property_clear);
+ WM_operatortype_append(OBJECT_OT_game_property_move);
WM_operatortype_append(OBJECT_OT_logic_bricks_copy);
WM_operatortype_append(OBJECT_OT_game_physics_copy);
@@ -249,7 +249,10 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_lod_add);
WM_operatortype_append(OBJECT_OT_lod_remove);
- WM_operatortype_append(OBJECT_OT_vertex_random);
+ WM_operatortype_append(TRANSFORM_OT_vertex_random);
+
+ WM_operatortype_append(OBJECT_OT_data_transfer);
+ WM_operatortype_append(OBJECT_OT_datalayout_transfer);
}
void ED_operatormacros_object(void)
@@ -320,6 +323,7 @@ void ED_keymap_object(wmKeyConfig *keyconf)
ED_keymap_proportional_cycle(keyconf, keymap);
ED_keymap_proportional_obmode(keyconf, keymap);
+ /* game-engine only, leave free for users to define */
WM_keymap_add_item(keymap, "VIEW3D_OT_game_start", PKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_all", AKEY, KM_PRESS, 0, 0);
@@ -420,6 +424,10 @@ void ED_keymap_object(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0);
+ WM_keymap_verify_item(keymap, "OBJECT_OT_data_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ /* XXX No more available 'T' shortcuts... :/ */
+ /* WM_keymap_verify_item(keymap, "OBJECT_OT_datalayout_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); */
+
for (i = 0; i <= 5; i++) {
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0);
RNA_int_set(kmi->ptr, "level", i);
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index 41b26b98047..a293f7a950e 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -124,12 +124,12 @@ static int object_rand_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_vertex_random(struct wmOperatorType *ot)
+void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Randomize";
ot->description = "Randomize vertices";
- ot->idname = "OBJECT_OT_vertex_random";
+ ot->idname = "TRANSFORM_OT_vertex_random";
/* api callbacks */
ot->exec = object_rand_verts_exec;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 0d58eaee5fa..e21f58d8a38 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -56,7 +56,7 @@
#include "BLI_kdtree.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_action.h"
#include "BKE_animsys.h"
@@ -128,9 +128,9 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
BPoint *bp;
Object *par;
int a, v1 = 0, v2 = 0, v3 = 0, v4 = 0, nr = 1;
-
+
/* we need 1 to 3 selected vertices */
-
+
if (obedit->type == OB_MESH) {
Mesh *me = obedit->data;
BMEditMesh *em;
@@ -145,7 +145,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
/* derivedMesh might be needed for solving parenting,
* so re-create it here */
- makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, 0);
+ makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false);
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
@@ -160,7 +160,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
else if (ELEM(obedit->type, OB_SURF, OB_CURVE)) {
ListBase *editnurb = object_editcurve_get(obedit);
-
+
cu = obedit->data;
nu = editnurb->first;
@@ -169,7 +169,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
- if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
if (v1 == 0) v1 = nr;
else if (v2 == 0) v2 = nr;
else if (v3 == 0) v3 = nr;
@@ -200,7 +200,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
else if (obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
-
+
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
bp = lt->editlatt->latt->def;
while (a--) {
@@ -215,28 +215,24 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
bp++;
}
}
-
+
if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) {
BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to");
return OPERATOR_CANCELLED;
}
-
+
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
if (ob != obedit) {
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
par = obedit->parent;
-
- while (par) {
- if (par == ob) break;
- par = par->parent;
- }
- if (par) {
+
+ if (BKE_object_parent_loop_check(par, ob)) {
BKE_report(op->reports, RPT_ERROR, "Loop in parents");
}
else {
Object workob;
-
+
ob->parent = BASACT->object;
if (v3) {
ob->partype = PARVERT3;
@@ -260,7 +256,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
}
CTX_DATA_END;
-
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT, NULL);
@@ -274,12 +270,12 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot)
ot->name = "Make Vertex Parent";
ot->description = "Parent selected objects to the selected vertices";
ot->idname = "OBJECT_OT_vertex_parent_set";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->poll = vertex_parent_set_poll;
ot->exec = vertex_parent_set_exec;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -291,36 +287,38 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
-
+
/* sanity checks */
if (!scene || scene->id.lib || !ob)
return OPERATOR_CANCELLED;
-
+
/* Get object to work on - use a menu if we need to... */
if (ob->dup_group && ob->dup_group->id.lib) {
/* gives menu with list of objects in group */
- //proxy_group_objects_menu(C, op, ob, ob->dup_group);
+ /* proxy_group_objects_menu(C, op, ob, ob->dup_group); */
WM_enum_search_invoke(C, op, event);
return OPERATOR_CANCELLED;
-
}
else if (ob->id.lib) {
- uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("OK?"), ICON_QUESTION);
- uiLayout *layout = uiPupMenuLayout(pup);
-
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
/* create operator menu item with relevant properties filled in */
- uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
-
+ uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL,
+ WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
+
/* present the menu and be done... */
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
+
+ /* this invoke just calls another instance of this operator... */
+ return OPERATOR_INTERFACE;
}
else {
/* error.. cannot continue */
BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group");
+ return OPERATOR_CANCELLED;
}
-
- /* this invoke just calls another instance of this operator... */
- return OPERATOR_CANCELLED;
+
}
static int make_proxy_exec(bContext *C, wmOperator *op)
@@ -338,32 +336,30 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
ob = gob;
gob = NULL;
}
-
+
if (ob) {
Object *newob;
Base *newbase, *oldbase = BASACT;
char name[MAX_ID_NAME + 4];
-
- /* Add new object for the proxy */
- newob = BKE_object_add(bmain, scene, OB_EMPTY);
BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2);
- rename_id(&newob->id, name);
-
+ /* Add new object for the proxy */
+ newob = BKE_object_add(bmain, scene, OB_EMPTY, name);
+
/* set layers OK */
newbase = BASACT; /* BKE_object_add sets active... */
newbase->lay = oldbase->lay;
newob->lay = newbase->lay;
-
+
/* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */
if (gob == NULL) {
BKE_scene_base_unlink(scene, oldbase);
MEM_freeN(oldbase);
}
-
+
BKE_object_make_proxy(newob, ob, gob);
-
+
/* depsgraph flushes are needed for the new data */
DAG_relations_tag_update(bmain);
DAG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
@@ -373,12 +369,13 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No object to make proxy for");
return OPERATOR_CANCELLED;
}
-
+
return OPERATOR_FINISHED;
}
/* Generic itemf's for operators that take library args */
-static EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
int totitem = 0;
@@ -410,17 +407,19 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot)
ot->name = "Make Proxy";
ot->idname = "OBJECT_OT_proxy_make";
ot->description = "Add empty object to become local replacement data of a library-linked object";
-
+
/* callbacks */
ot->invoke = make_proxy_invoke;
ot->exec = make_proxy_exec;
ot->poll = ED_operator_object_active;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
- prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", "Name of lib-linked/grouped object to make a proxy for"); /* XXX, relies on hard coded ID at the moment */
+ /* XXX, relies on hard coded ID at the moment */
+ prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object",
+ "Name of lib-linked/grouped object to make a proxy for");
RNA_def_enum_funcs(prop, proxy_group_object_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
@@ -435,9 +434,12 @@ typedef enum eObClearParentTypes {
} eObClearParentTypes;
EnumPropertyItem prop_clear_parent_types[] = {
- {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", ""},
- {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", ""},
- {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", ""},
+ {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
+ "Completely clear the parenting relationship, including involved modifiers is any"},
+ {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
+ "As 'Clear Parent', but keep the current visual transformations of the object"},
+ {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
+ "Reset the transform corrections applied to the parenting relationship, does not remove parenting itself"},
{0, NULL, 0, NULL, NULL}
};
@@ -446,13 +448,13 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
{
if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) {
ModifierData *md, *mdn;
-
+
/* assume that we only need to remove the first instance of matching deform modifier here */
for (md = ob->modifiers.first; md; md = mdn) {
bool free = false;
-
+
mdn = md->next;
-
+
/* need to match types (modifier + parent) and references */
if ((md->type == eModifierType_Armature) && (par->type == OB_ARMATURE)) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -472,7 +474,7 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
free = true;
}
}
-
+
/* free modifier if match */
if (free) {
BLI_remlink(&ob->modifiers, md);
@@ -482,17 +484,17 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
}
}
-void ED_object_parent_clear(Object *ob, int type)
+void ED_object_parent_clear(Object *ob, const int type)
{
if (ob->parent == NULL)
return;
-
+
switch (type) {
case CLEAR_PARENT_ALL:
{
/* for deformers, remove corresponding modifiers to prevent a large number of modifiers building up */
object_remove_parent_deform_modifiers(ob, ob->parent);
-
+
/* clear parenting relationship completely */
ob->parent = NULL;
break;
@@ -506,12 +508,15 @@ void ED_object_parent_clear(Object *ob, int type)
}
case CLEAR_PARENT_INVERSE:
{
- /* object stays parented, but the parent inverse (i.e. offset from parent to retain binding state) is cleared */
- unit_m4(ob->parentinv);
+ /* object stays parented, but the parent inverse (i.e. offset from parent to retain binding state)
+ * is cleared. In other words: nothing to do here! */
break;
}
}
-
+
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
+
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
@@ -519,7 +524,7 @@ void ED_object_parent_clear(Object *ob, int type)
static int parent_clear_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
+ const int type = RNA_enum_get(op->ptr, "type");
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
@@ -539,23 +544,26 @@ void OBJECT_OT_parent_clear(wmOperatorType *ot)
ot->name = "Clear Parent";
ot->description = "Clear the object's parenting";
ot->idname = "OBJECT_OT_parent_clear";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = parent_clear_exec;
-
+
ot->poll = ED_operator_object_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_parent_types, CLEAR_PARENT_ALL, "Type", "");
}
/* ******************** Make Parent Operator *********************** */
-void ED_object_parent(Object *ob, Object *par, int type, const char *substr)
+void ED_object_parent(Object *ob, Object *par, const int type, const char *substr)
{
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
+
if (!par || BKE_object_parent_loop_check(par, ob)) {
ob->parent = NULL;
ob->partype = PAROBJECT;
@@ -563,6 +571,9 @@ void ED_object_parent(Object *ob, Object *par, int type, const char *substr)
return;
}
+ /* Other partypes are deprecated, do not use here! */
+ BLI_assert(ELEM(type & PARTYPE, PAROBJECT, PARSKEL, PARVERT1, PARVERT3, PARBONE));
+
/* this could use some more checks */
ob->parent = par;
@@ -589,21 +600,21 @@ EnumPropertyItem prop_make_parent_types[] = {
{0, NULL, 0, NULL, NULL}
};
-int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par,
- int partype, bool xmirror, bool keep_transform, const int vert_par[3])
+bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par,
+ int partype, const bool xmirror, const bool keep_transform, const int vert_par[3])
{
bPoseChannel *pchan = NULL;
- int pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
-
+ const bool pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
+
DAG_id_tag_update(&par->id, OB_RECALC_OB);
-
+
/* preconditions */
if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) {
if (par->type != OB_CURVE)
return 0;
else {
Curve *cu = par->data;
-
+
if ((cu->flag & CU_PATH) == 0) {
cu->flag |= CU_PATH | CU_FOLLOW;
BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */
@@ -617,12 +628,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* get or create F-Curve */
bAction *act = verify_adt_action(&cu->id, 1);
FCurve *fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
-
+
/* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first)
add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
}
-
+
/* fall back on regular parenting now (for follow only) */
if (partype == PAR_FOLLOW)
partype = PAR_OBJECT;
@@ -630,17 +641,17 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
}
else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) {
pchan = BKE_pose_channel_active(par);
-
+
if (pchan == NULL) {
BKE_report(reports, RPT_ERROR, "No active bone");
- return 0;
+ return false;
}
}
-
+
if (ob != par) {
if (BKE_object_parent_loop_check(par, ob)) {
BKE_report(reports, RPT_ERROR, "Loop in parents");
- return 0;
+ return false;
}
else {
Object workob;
@@ -655,14 +666,16 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* set the parent (except for follow-path constraint option) */
if (partype != PAR_PATH_CONST) {
ob->parent = par;
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
}
-
+
/* handle types */
if (pchan)
BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr));
else
ob->parsubstr[0] = 0;
-
+
if (partype == PAR_PATH_CONST) {
/* don't do anything here, since this is not technically "parenting" */
}
@@ -670,17 +683,18 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created
* NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers
*/
- ob->partype = PAROBJECT; /* note, dna define, not operator property */
- //ob->partype = PARSKEL; /* note, dna define, not operator property */
-
- /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses
+ ob->partype = PAROBJECT; /* note, dna define, not operator property */
+ /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */
+
+ /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses
* - We need to ensure that the modifier we're adding doesn't already exist, so we check this by
* assuming that the parent is selected too...
*/
- // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet
+ /* XXX currently this should only happen for meshes, curves, surfaces,
+ * and lattices - this stuff isn't available for metas yet */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
ModifierData *md;
-
+
switch (partype) {
case PAR_CURVE: /* curve deform */
if (modifiers_isDeformedByCurve(ob) != par) {
@@ -688,6 +702,9 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
if (md) {
((CurveModifierData *)md)->object = par;
}
+ if (par->curve_cache && par->curve_cache->path == NULL) {
+ DAG_id_tag_update(&par->id, OB_RECALC_DATA);
+ }
}
break;
case PAR_LATTICE: /* lattice deform */
@@ -730,21 +747,21 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
else {
ob->partype = PAROBJECT; /* note, dna define, not operator property */
}
-
+
/* constraint */
if (partype == PAR_PATH_CONST) {
bConstraint *con;
bFollowPathConstraint *data;
float cmat[4][4], vec[3];
-
+
con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
-
+
data = con->data;
data->tar = par;
-
+
BKE_constraint_target_matrix_get(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
-
+
copy_v3_v3(ob->loc, vec);
}
else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) {
@@ -760,7 +777,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* get corrected inverse */
ob->partype = PAROBJECT;
BKE_object_workob_calc_parent(scene, ob, &workob);
-
+
invert_m4_m4(ob->parentinv, workob.obmat);
}
else {
@@ -768,12 +785,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
BKE_object_workob_calc_parent(scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
-
+
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
}
}
- return 1;
+ return true;
}
@@ -787,6 +804,7 @@ static void parent_set_vert_find(KDTree *tree, Object *child, int vert_par[3], b
tot = BLI_kdtree_find_nearest_n(tree, co_find, nearest, 3);
BLI_assert(tot == 3);
+ UNUSED_VARS(tot);
vert_par[0] = nearest[0].index;
vert_par[1] = nearest[1].index;
@@ -808,8 +826,8 @@ static int parent_set_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *par = ED_object_active_context(C);
int partype = RNA_enum_get(op->ptr, "type");
- bool xmirror = RNA_boolean_get(op->ptr, "xmirror");
- bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
+ const bool xmirror = RNA_boolean_get(op->ptr, "xmirror");
+ const bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
bool ok = true;
/* vertex parent (kdtree) */
@@ -828,27 +846,25 @@ static int parent_set_exec(bContext *C, wmOperator *op)
if (tree_tot < (is_tri ? 3 : 1)) {
BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent");
ok = false;
- goto cleanup;
}
}
+ if (ok) {
+ /* Non vertex-parent */
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (is_vert_par) {
+ parent_set_vert_find(tree, ob, vert_par, is_tri);
+ }
- /* Non vertex-parent */
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
- {
- if (is_vert_par) {
- parent_set_vert_find(tree, ob, vert_par, is_tri);
- }
-
- if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
- ok = false;
- break;
+ if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
+ ok = false;
+ break;
+ }
}
+ CTX_DATA_END;
}
- CTX_DATA_END;
-
-cleanup:
if (is_vert_par) {
BLI_kdtree_free(tree);
}
@@ -867,8 +883,8 @@ cleanup:
static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
Object *ob = ED_object_active_context(C);
- uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_parent_set", true);
PointerRNA opptr;
@@ -902,22 +918,22 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
else if (ob->type == OB_LATTICE) {
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE);
}
-
+
/* vertex parenting */
if (OB_TYPE_SUPPORT_PARVERT(ob->type)) {
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX);
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX_TRI);
}
- uiPupMenuEnd(C, pup);
-
- return OPERATOR_CANCELLED;
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
}
static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
- int type = RNA_enum_get(ptr, "type");
+ const int type = RNA_enum_get(ptr, "type");
/* Only show XMirror for PAR_ARMATURE_ENVELOPE and PAR_ARMATURE_AUTO! */
if (STREQ(prop_id, "xmirror")) {
@@ -948,22 +964,21 @@ void OBJECT_OT_parent_set(wmOperatorType *ot)
ot->name = "Make Parent";
ot->description = "Set the object's parenting";
ot->idname = "OBJECT_OT_parent_set";
-
+
/* api callbacks */
ot->invoke = parent_set_invoke;
ot->exec = parent_set_exec;
ot->poll = ED_operator_object_active;
ot->ui = parent_set_ui;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
RNA_def_boolean(ot->srna, "xmirror", false, "X Mirror",
"Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation");
RNA_def_boolean(ot->srna, "keep_transform", false, "Keep Transform",
"Apply transformation before parenting");
-
}
/* ************ Make Parent Without Inverse Operator ******************* */
@@ -972,9 +987,9 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *par = ED_object_active_context(C);
-
+
DAG_id_tag_update(&par->id, OB_RECALC_OB);
-
+
/* context iterator */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
@@ -986,10 +1001,10 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
/* clear inverse matrix and also the object location */
unit_m4(ob->parentinv);
memset(ob->loc, 0, 3 * sizeof(float));
-
+
/* set recalc flags */
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
-
+
/* set parenting type for object - object only... */
ob->parent = par;
ob->partype = PAROBJECT; /* note, dna define, not operator property */
@@ -997,10 +1012,10 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
}
}
CTX_DATA_END;
-
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1010,12 +1025,12 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
ot->name = "Make Parent without Inverse";
ot->description = "Set the object's parenting without setting the inverse parent correction";
ot->idname = "OBJECT_OT_parent_no_inverse_set";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = parent_noinv_set_exec;
ot->poll = ED_operator_object_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -1040,23 +1055,22 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
WM_event_add_notifier(C, NC_SCENE, scene);
-
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_slow_parent_clear(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Clear Slow Parent";
ot->description = "Clear the object's slow parent";
ot->idname = "OBJECT_OT_slow_parent_clear";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = object_slow_parent_clear_exec;
ot->poll = ED_operator_view3d_active;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -1073,37 +1087,40 @@ static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
ob->partype |= PARSLOW;
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
-
}
CTX_DATA_END;
WM_event_add_notifier(C, NC_SCENE, scene);
-
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_slow_parent_set(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Set Slow Parent";
ot->description = "Set the object's slow parent";
ot->idname = "OBJECT_OT_slow_parent_set";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = object_slow_parent_set_exec;
ot->poll = ED_operator_view3d_active;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Clear Track Operator ******************* */
+enum {
+ CLEAR_TRACK = 1,
+ CLEAR_TRACK_KEEP_TRANSFORM = 2,
+};
+
static EnumPropertyItem prop_clear_track_types[] = {
- {0, "CLEAR", 0, "Clear Track", ""},
- {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
+ {CLEAR_TRACK, "CLEAR", 0, "Clear Track", ""},
+ {CLEAR_TRACK_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1111,7 +1128,7 @@ static EnumPropertyItem prop_clear_track_types[] = {
static int object_track_clear_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
+ const int type = RNA_enum_get(op->ptr, "type");
if (CTX_data_edit_object(C)) {
BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode");
@@ -1120,19 +1137,19 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
bConstraint *con, *pcon;
-
+
/* remove track-object for old track */
ob->track = NULL;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
+
/* also remove all tracking constraints */
for (con = ob->constraints.last; con; con = pcon) {
pcon = con->prev;
if (ELEM(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
BKE_constraint_remove(&ob->constraints, con);
}
-
- if (type == 1)
+
+ if (type == CLEAR_TRACK_KEEP_TRANSFORM)
BKE_object_apply_mat4(ob, ob->obmat, true, true);
}
CTX_DATA_END;
@@ -1149,25 +1166,31 @@ void OBJECT_OT_track_clear(wmOperatorType *ot)
ot->name = "Clear Track";
ot->description = "Clear tracking constraint or flag from object";
ot->idname = "OBJECT_OT_track_clear";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = object_track_clear_exec;
-
+
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", "");
}
/************************** Make Track Operator *****************************/
+enum {
+ CREATE_TRACK_DAMPTRACK = 1,
+ CREATE_TRACK_TRACKTO = 2,
+ CREATE_TRACK_LOCKTRACK = 3,
+};
+
static EnumPropertyItem prop_make_track_types[] = {
- {1, "DAMPTRACK", 0, "Damped Track Constraint", ""},
- {2, "TRACKTO", 0, "Track To Constraint", ""},
- {3, "LOCKTRACK", 0, "Lock Track Constraint", ""},
+ {CREATE_TRACK_DAMPTRACK, "DAMPTRACK", 0, "Damped Track Constraint", ""},
+ {CREATE_TRACK_TRACKTO, "TRACKTO", 0, "Track To Constraint", ""},
+ {CREATE_TRACK_LOCKTRACK, "LOCKTRACK", 0, "Lock Track Constraint", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1175,78 +1198,86 @@ static int track_set_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *obact = ED_object_active_context(C);
-
- int type = RNA_enum_get(op->ptr, "type");
-
- if (type == 1) {
- bConstraint *con;
- bDampTrackConstraint *data;
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ switch (type) {
+ case CREATE_TRACK_DAMPTRACK:
{
- if (ob != obact) {
- con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
+ bConstraint *con;
+ bDampTrackConstraint *data;
- data = con->data;
- data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* Lamp, Camera and Speaker track differently by default */
- if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- data->trackflag = TRACK_nZ;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (ob != obact) {
+ con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
+
+ data = con->data;
+ data->tar = obact;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ /* Lamp, Camera and Speaker track differently by default */
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ data->trackflag = TRACK_nZ;
+ }
}
}
+ CTX_DATA_END;
+ break;
}
- CTX_DATA_END;
- }
- else if (type == 2) {
- bConstraint *con;
- bTrackToConstraint *data;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ case CREATE_TRACK_TRACKTO:
{
- if (ob != obact) {
- con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
+ bConstraint *con;
+ bTrackToConstraint *data;
- data = con->data;
- data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* Lamp, Camera and Speaker track differently by default */
- if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- data->reserved1 = TRACK_nZ;
- data->reserved2 = UP_Y;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (ob != obact) {
+ con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
+
+ data = con->data;
+ data->tar = obact;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ /* Lamp, Camera and Speaker track differently by default */
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ data->reserved1 = TRACK_nZ;
+ data->reserved2 = UP_Y;
+ }
}
}
+ CTX_DATA_END;
+ break;
}
- CTX_DATA_END;
- }
- else if (type == 3) {
- bConstraint *con;
- bLockTrackConstraint *data;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ case CREATE_TRACK_LOCKTRACK:
{
- if (ob != obact) {
- con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
+ bConstraint *con;
+ bLockTrackConstraint *data;
- data = con->data;
- data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* Lamp, Camera and Speaker track differently by default */
- if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- data->trackflag = TRACK_nZ;
- data->lockflag = LOCK_Y;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (ob != obact) {
+ con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
+
+ data = con->data;
+ data->tar = obact;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ /* Lamp, Camera and Speaker track differently by default */
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ data->trackflag = TRACK_nZ;
+ data->lockflag = LOCK_Y;
+ }
}
}
+ CTX_DATA_END;
+ break;
}
- CTX_DATA_END;
}
-
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1254,18 +1285,18 @@ void OBJECT_OT_track_set(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Make Track";
- ot->description = "Make the object track another object, either by constraint or old way or locked track";
+ ot->description = "Make the object track another object, using various methods/constraints";
ot->idname = "OBJECT_OT_track_set";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = track_set_exec;
-
+
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", "");
}
@@ -1286,8 +1317,8 @@ static unsigned int move_to_layer_init(bContext *C, wmOperator *op)
CTX_DATA_END;
for (a = 0; a < 20; a++)
- values[a] = (lay & (1 << a));
-
+ values[a] = (lay & (1 << a)) != 0;
+
RNA_boolean_set_array(op->ptr, "layers", values);
}
else {
@@ -1320,12 +1351,12 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
unsigned int lay, local;
/* bool is_lamp = false; */ /* UNUSED */
-
+
lay = move_to_layer_init(C, op);
lay &= 0xFFFFFF;
if (lay == 0) return OPERATOR_CANCELLED;
-
+
if (v3d && v3d->localvd) {
/* now we can move out of localview. */
/* note: layers are set in bases, library objects work for this */
@@ -1353,9 +1384,9 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
}
-
+
/* warning, active object may be hidden now */
-
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
@@ -1370,15 +1401,15 @@ void OBJECT_OT_move_to_layer(wmOperatorType *ot)
ot->name = "Move to Layer";
ot->description = "Move the object to different layers";
ot->idname = "OBJECT_OT_move_to_layer";
-
+
/* api callbacks */
ot->invoke = move_to_layer_invoke;
ot->exec = move_to_layer_exec;
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
}
@@ -1390,13 +1421,12 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
{
Scene *sce = (Scene *) BLI_findlink(&bmain->scene, G.curscreen->scenenr - 1);
Base *base, *nbase;
-
- if (sce == 0) return;
+
+ if (sce == NULL) return;
if (sce->id.lib) return;
-
+
for (base = FIRSTBASE; base; base = base->next) {
if (TESTBASE(v3d, base)) {
-
nbase = MEM_mallocN(sizeof(Base), "newbase");
*nbase = *base;
BLI_addhead(&(sce->base), nbase);
@@ -1453,48 +1483,45 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
}
enum {
- MAKE_LINKS_OBDATA = 1,
- MAKE_LINKS_MATERIALS,
- MAKE_LINKS_ANIMDATA,
- MAKE_LINKS_GROUP,
- MAKE_LINKS_DUPLIGROUP,
- MAKE_LINKS_MODIFIERS,
- MAKE_LINKS_FONTS
+ MAKE_LINKS_OBDATA = 1,
+ MAKE_LINKS_MATERIALS = 2,
+ MAKE_LINKS_ANIMDATA = 3,
+ MAKE_LINKS_GROUP = 4,
+ MAKE_LINKS_DUPLIGROUP = 5,
+ MAKE_LINKS_MODIFIERS = 6,
+ MAKE_LINKS_FONTS = 7,
};
-/* Return 1 if make link data is allow, zero otherwise */
-static int allow_make_links_data(const int type, Object *ob_src, Object *ob_dst)
+/* Return true if make link data is allowed, false otherwise */
+static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst)
{
switch (type) {
case MAKE_LINKS_OBDATA:
- if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY)
- return 1;
+ if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY) {
+ return true;
+ }
break;
case MAKE_LINKS_MATERIALS:
- if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) &&
- OB_TYPE_SUPPORT_MATERIAL(ob_dst->type))
- {
- return 1;
+ if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) && OB_TYPE_SUPPORT_MATERIAL(ob_dst->type)) {
+ return true;
}
break;
case MAKE_LINKS_ANIMDATA:
case MAKE_LINKS_GROUP:
case MAKE_LINKS_DUPLIGROUP:
- return 1;
+ return true;
case MAKE_LINKS_MODIFIERS:
- if (ob_src->type != OB_EMPTY && ob_dst->type != OB_EMPTY)
- return 1;
+ if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) {
+ return true;
+ }
break;
case MAKE_LINKS_FONTS:
- if ((ob_src->data != ob_dst->data) &&
- (ob_src->type == OB_FONT) &&
- (ob_dst->type == OB_FONT))
- {
- return 1;
+ if ((ob_src->data != ob_dst->data) && (ob_src->type == OB_FONT) && (ob_dst->type == OB_FONT)) {
+ return true;
}
break;
}
- return 0;
+ return false;
}
static int make_links_data_exec(bContext *C, wmOperator *op)
@@ -1548,13 +1575,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob_dst->id, 0);
break;
case MAKE_LINKS_ANIMDATA:
- BKE_copy_animdata_id((ID *)ob_dst, (ID *)ob_src, false);
+ BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
if (ob_dst->data && ob_src->data) {
if (obdata_id->lib) {
is_lib = true;
break;
}
- BKE_copy_animdata_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
+ BKE_animdata_copy_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
}
DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
@@ -1697,13 +1724,13 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
-static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag, bool copy_groups)
+static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
{
Base *base;
Object *ob, *obn;
Group *group, *groupn;
GroupObject *go;
-
+
clear_sca_new_poins(); /* sensor/contr/act */
/* newid may still have some trash from Outliner tree building,
@@ -1714,7 +1741,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
/* duplicate (must set newid) */
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
-
+
if ((base->flag & flag) == flag) {
if (ob->id.lib == NULL && ob->id.us > 1) {
/* base gets copy of object */
@@ -1761,10 +1788,10 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
/* group pointers in scene */
BKE_scene_groups_relink(scene);
-
+
ID_NEW(scene->camera);
if (v3d) ID_NEW(v3d->camera);
-
+
/* object and group pointers */
for (base = FIRSTBASE; base; base = base->next) {
BKE_object_relink(base->object);
@@ -1778,7 +1805,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
Base *base;
- bool copy_groups = false;
+ const bool copy_groups = false;
for (base = FIRSTBASE; base; base = base->next) {
if (base->object == ob) base->flag |= OB_DONE;
@@ -1788,11 +1815,11 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
}
-static void new_id_matar(Material **matar, int totcol)
+static void new_id_matar(Material **matar, const int totcol)
{
ID *id;
int a;
-
+
for (a = 0; a < totcol; a++) {
id = (ID *)matar[a];
if (id && id->lib == NULL) {
@@ -1810,12 +1837,12 @@ static void new_id_matar(Material **matar, int totcol)
}
}
-static void single_obdata_users(Main *bmain, Scene *scene, int flag)
+static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
{
Object *ob;
Lamp *la;
Curve *cu;
- //Camera *cam;
+ /* Camera *cam; */
Base *base;
Mesh *me;
Lattice *lat;
@@ -1826,7 +1853,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
ob = base->object;
if (ob->id.lib == NULL && (base->flag & flag) == flag) {
id = ob->data;
-
+
if (id && id->us > 1 && id->lib == NULL) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -1845,7 +1872,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
case OB_MESH:
ob->data = me = BKE_mesh_copy(ob->data);
if (me->key)
- BKE_copy_animdata_id_action((ID *)me->key);
+ BKE_animdata_copy_id_action((ID *)me->key);
break;
case OB_MBALL:
ob->data = BKE_mball_copy(ob->data);
@@ -1857,12 +1884,12 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
ID_NEW(cu->bevobj);
ID_NEW(cu->taperobj);
if (cu->key)
- BKE_copy_animdata_id_action((ID *)cu->key);
+ BKE_animdata_copy_id_action((ID *)cu->key);
break;
case OB_LATTICE:
ob->data = lat = BKE_lattice_copy(ob->data);
if (lat->key)
- BKE_copy_animdata_id_action((ID *)lat->key);
+ BKE_animdata_copy_id_action((ID *)lat->key);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -1883,16 +1910,14 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
* AnimData structure, which is not what we want.
* (sergey)
*/
- BKE_copy_animdata_id_action((ID *)ob->data);
+ BKE_animdata_copy_id_action((ID *)ob->data);
id->us--;
id->newid = ob->data;
-
}
-
}
}
-
+
me = bmain->mesh.first;
while (me) {
ID_NEW(me->texcomesh);
@@ -1900,41 +1925,40 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
}
}
-static void single_object_action_users(Scene *scene, int flag)
+static void single_object_action_users(Scene *scene, const int flag)
{
Object *ob;
Base *base;
-
+
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BKE_copy_animdata_id_action(&ob->id);
+ BKE_animdata_copy_id_action(&ob->id);
}
}
}
-static void single_mat_users(Scene *scene, int flag, int do_textures)
+static void single_mat_users(Scene *scene, const int flag, const bool do_textures)
{
Object *ob;
Base *base;
Material *ma, *man;
Tex *tex;
int a, b;
-
+
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
-
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
/* do not test for LIB_NEW: this functions guaranteed delivers single_users! */
-
+
if (ma->id.us > 1) {
man = BKE_material_copy(ma);
- BKE_copy_animdata_id_action(&man->id);
-
+ BKE_animdata_copy_id_action(&man->id);
+
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -1944,7 +1968,7 @@ static void single_mat_users(Scene *scene, int flag, int do_textures)
if (tex->id.us > 1) {
tex->id.us--;
tex = BKE_texture_copy(tex);
- BKE_copy_animdata_id_action(&tex->id);
+ BKE_animdata_copy_id_action(&tex->id);
man->mtex[b]->tex = tex;
}
}
@@ -1960,10 +1984,10 @@ static void single_mat_users(Scene *scene, int flag, int do_textures)
static void do_single_tex_user(Tex **from)
{
Tex *tex, *texn;
-
+
tex = *from;
if (tex == NULL) return;
-
+
if (tex->id.newid) {
*from = (Tex *)tex->id.newid;
id_us_plus(tex->id.newid);
@@ -1971,7 +1995,7 @@ static void do_single_tex_user(Tex **from)
}
else if (tex->id.us > 1) {
texn = BKE_texture_copy(tex);
- BKE_copy_animdata_id_action(&texn->id);
+ BKE_animdata_copy_id_action(&texn->id);
tex->id.newid = (ID *)texn;
tex->id.us--;
*from = texn;
@@ -1985,7 +2009,7 @@ static void single_tex_users_expand(Main *bmain)
Lamp *la;
World *wo;
int b;
-
+
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
if (ma->id.flag & LIB_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
@@ -2026,7 +2050,7 @@ static void single_mat_users_expand(Main *bmain)
MetaBall *mb;
Material *ma;
int a;
-
+
for (ob = bmain->object.first; ob; ob = ob->id.next)
if (ob->id.flag & LIB_NEW)
new_id_matar(ob->mat, ob->totcol);
@@ -2052,7 +2076,7 @@ static void single_mat_users_expand(Main *bmain)
}
/* used for copying scenes */
-void ED_object_single_users(Main *bmain, Scene *scene, bool full, bool copy_groups)
+void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_groups)
{
single_object_users(bmain, scene, NULL, 0, copy_groups);
@@ -2073,13 +2097,13 @@ static void make_local_makelocalmaterial(Material *ma)
{
AnimData *adt;
int b;
-
+
id_make_local(&ma->id, false);
-
+
for (b = 0; b < MAX_MTEX; b++)
if (ma->mtex[b] && ma->mtex[b]->tex)
id_make_local(&ma->mtex[b]->tex->id, false);
-
+
adt = BKE_animdata_from_id(&ma->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2087,13 +2111,13 @@ static void make_local_makelocalmaterial(Material *ma)
}
enum {
- MAKE_LOCAL_SELECT_OB,
- MAKE_LOCAL_SELECT_OBDATA,
- MAKE_LOCAL_SELECT_OBDATA_MATERIAL,
- MAKE_LOCAL_ALL
+ MAKE_LOCAL_SELECT_OB = 1,
+ MAKE_LOCAL_SELECT_OBDATA = 2,
+ MAKE_LOCAL_SELECT_OBDATA_MATERIAL = 3,
+ MAKE_LOCAL_ALL = 4,
};
-static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, int UNUSED(cd_flag))
+static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, const int UNUSED(cd_flag))
{
if (*id_pointer) {
(*id_pointer)->flag &= ~LIB_DOIT;
@@ -2101,7 +2125,7 @@ static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, int
return true;
}
-static void tag_localizable_objects(bContext *C, int mode)
+static void tag_localizable_objects(bContext *C, const int mode)
{
Main *bmain = CTX_data_main(C);
Object *object;
@@ -2182,8 +2206,9 @@ static int make_local_exec(bContext *C, wmOperator *op)
Material *ma, ***matarar;
Lamp *la;
ID *id;
- int a, b, mode = RNA_enum_get(op->ptr, "type");
-
+ const int mode = RNA_enum_get(op->ptr, "type");
+ int a, b;
+
if (mode == MAKE_LOCAL_ALL) {
/* de-select so the user can differentiate newly instanced from existing objects */
BKE_scene_base_deselect_all(scene);
@@ -2200,7 +2225,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
tag_localizable_objects(C, mode);
BKE_main_id_clear_newpoins(bmain);
-
+
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if ((ob->id.flag & LIB_DOIT) == 0) {
@@ -2211,7 +2236,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
id_make_local(&ob->id, false);
}
CTX_DATA_END;
-
+
/* maybe object pointers */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
@@ -2228,12 +2253,12 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
id = ob->data;
-
+
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
id_make_local(id, false);
adt = BKE_animdata_from_id(id);
if (adt) BKE_animdata_make_local(adt);
-
+
/* tag indirect data direct */
matarar = give_matarar(ob);
if (matarar) {
@@ -2273,7 +2298,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
if (ma)
make_local_makelocalmaterial(ma);
}
-
+
matarar = (Material ***)give_matarar(ob);
if (matarar) {
for (a = 0; a < ob->totcol; a++) {
@@ -2306,26 +2331,31 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
ot->name = "Make Local";
ot->description = "Make library linked datablocks local to this file";
ot->idname = "OBJECT_OT_make_local";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = make_local_exec;
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
}
+enum {
+ MAKE_SINGLE_USER_ALL = 1,
+ MAKE_SINGLE_USER_SELECTED = 2,
+};
+
static int make_single_user_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */
- int flag = RNA_enum_get(op->ptr, "type"); /* 0==ALL, SELECTED==selected objecs */
- bool copy_groups = false;
+ const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0;
+ const bool copy_groups = false;
bool update_deps = false;
BKE_main_id_clear_newpoins(bmain);
@@ -2372,8 +2402,8 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
void OBJECT_OT_make_single_user(wmOperatorType *ot)
{
static EnumPropertyItem type_items[] = {
- {SELECT, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
- {0, "ALL", 0, "All", ""},
+ {MAKE_SINGLE_USER_SELECTED, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
+ {MAKE_SINGLE_USER_ALL, "ALL", 0, "All", ""},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
@@ -2390,12 +2420,13 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, SELECT, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, MAKE_SINGLE_USER_SELECTED, "Type", "");
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each datablock");
- RNA_def_boolean(ot->srna, "texture", 0, "Textures", "Make textures local to each material");
+ RNA_def_boolean(ot->srna, "texture", 0, "Textures",
+ "Make textures local to each material (needs 'Materials' to be set too)");
RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
}
@@ -2404,17 +2435,20 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
Material *ma;
char name[MAX_ID_NAME - 2];
-
+
RNA_string_get(op->ptr, "name", name);
ma = (Material *)BKE_libblock_find_name(ID_MA, name);
if (base == NULL || ma == NULL)
return OPERATOR_CANCELLED;
-
+
assign_material(base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF);
-
+
+ DAG_id_tag_update(&base->object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
-
+
return OPERATOR_FINISHED;
}
@@ -2422,19 +2456,18 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
/* assigns to object under cursor, only first material slot */
void OBJECT_OT_drop_named_material(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Drop Named Material on Object";
ot->description = "";
ot->idname = "OBJECT_OT_drop_named_material";
-
+
/* api callbacks */
ot->invoke = drop_named_material_invoke;
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
-
+
/* properties */
RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign");
}
@@ -2444,7 +2477,7 @@ static int object_unlink_data_exec(bContext *C, wmOperator *op)
ID *id;
PropertyPointerRNA pprop;
- uiIDContextProperty(C, &pprop.ptr, &pprop.prop);
+ UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop);
if (pprop.prop == NULL) {
BKE_report(op->reports, RPT_ERROR, "Incorrect context for running object data unlink");
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index e295a63848a..83334e4e6a3 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -47,7 +47,7 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_group.h"
@@ -618,15 +618,15 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in
}
/* build the menu. */
- pup = uiPupMenuBegin(C, IFACE_("Select Group"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Select Group"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
for (i = 0; i < group_count; i++) {
group = ob_groups[i];
uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name + 2);
}
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
return changed; /* The operator already handle this! */
}
@@ -929,11 +929,16 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot)
}
/************************* Select by Layer **********************/
+enum {
+ OB_SEL_LAYERMATCH_EXACT = 1,
+ OB_SEL_LAYERMATCH_SHARED = 2,
+};
static int object_select_by_layer_exec(bContext *C, wmOperator *op)
{
unsigned int layernum;
- bool extend, match;
+ bool extend;
+ int match;
extend = RNA_boolean_get(op->ptr, "extend");
layernum = RNA_int_get(op->ptr, "layers");
@@ -951,13 +956,21 @@ static int object_select_by_layer_exec(bContext *C, wmOperator *op)
{
bool ok = false;
- if (match == true) /* exact */
- ok = (base->lay == (1 << (layernum - 1)));
- else /* shared layers */
- ok = (base->lay & (1 << (layernum - 1))) != 0;
+ switch (match) {
+ case OB_SEL_LAYERMATCH_EXACT:
+ /* Mask out bits used for local view, only work on real layer ones, see T45783. */
+ ok = ((base->lay & ((1 << 20) - 1)) == (1 << (layernum - 1)));
+ break;
+ case OB_SEL_LAYERMATCH_SHARED:
+ ok = (base->lay & (1 << (layernum - 1))) != 0;
+ break;
+ default:
+ break;
+ }
- if (ok)
+ if (ok) {
ED_base_object_select(base, BA_SELECT);
+ }
}
CTX_DATA_END;
@@ -970,8 +983,8 @@ static int object_select_by_layer_exec(bContext *C, wmOperator *op)
void OBJECT_OT_select_by_layer(wmOperatorType *ot)
{
static EnumPropertyItem match_items[] = {
- {1, "EXACT", 0, "Exact Match", ""},
- {2, "SHARED", 0, "Shared Layers", ""},
+ {OB_SEL_LAYERMATCH_EXACT, "EXACT", 0, "Exact Match", ""},
+ {OB_SEL_LAYERMATCH_SHARED, "SHARED", 0, "Shared Layers", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -989,7 +1002,7 @@ void OBJECT_OT_select_by_layer(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "match", match_items, 0, "Match", "");
+ RNA_def_enum(ot->srna, "match", match_items, OB_SEL_LAYERMATCH_EXACT, "Match", "");
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
}
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 85104c14395..ed71af71ac9 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -48,7 +48,6 @@
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "BKE_context.h"
@@ -75,10 +74,10 @@
/*********************** add shape key ***********************/
-static void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob, const bool from_mix)
+static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix)
{
KeyBlock *kb;
- if ((kb = BKE_object_insert_shape_key(scene, ob, NULL, from_mix))) {
+ if ((kb = BKE_object_shapekey_insert(ob, NULL, from_mix))) {
Key *key = BKE_key_from_object(ob);
/* for absolute shape keys, new keys may not be added last */
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
@@ -89,82 +88,21 @@ static void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob, const
/*********************** remove shape key ***********************/
-static bool ED_object_shape_key_remove_all(Main *bmain, Object *ob)
+static bool object_shapekey_remove(Main *bmain, Object *ob)
{
- Key *key;
+ KeyBlock *kb;
+ Key *key = BKE_key_from_object(ob);
- key = BKE_key_from_object(ob);
- if (key == NULL)
+ if (key == NULL) {
return false;
-
- switch (GS(key->from->name)) {
- case ID_ME: ((Mesh *)key->from)->key = NULL; break;
- case ID_CU: ((Curve *)key->from)->key = NULL; break;
- case ID_LT: ((Lattice *)key->from)->key = NULL; break;
}
- BKE_libblock_free_us(bmain, key);
-
- return true;
-}
-
-static bool ED_object_shape_key_remove(Main *bmain, Object *ob)
-{
- KeyBlock *kb, *rkb;
- Key *key;
-
- key = BKE_key_from_object(ob);
- if (key == NULL)
- return false;
-
kb = BLI_findlink(&key->block, ob->shapenr - 1);
-
if (kb) {
- for (rkb = key->block.first; rkb; rkb = rkb->next)
- if (rkb->relative == ob->shapenr - 1)
- rkb->relative = 0;
-
- BLI_remlink(&key->block, kb);
- key->totkey--;
- if (key->refkey == kb) {
- key->refkey = key->block.first;
-
- if (key->refkey) {
- /* apply new basis key on original data */
- switch (ob->type) {
- case OB_MESH:
- BKE_key_convert_to_mesh(key->refkey, ob->data);
- break;
- case OB_CURVE:
- case OB_SURF:
- BKE_key_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
- break;
- case OB_LATTICE:
- BKE_key_convert_to_lattice(key->refkey, ob->data);
- break;
- }
- }
- }
-
- if (kb->data) MEM_freeN(kb->data);
- MEM_freeN(kb);
-
- if (ob->shapenr > 1) {
- ob->shapenr--;
- }
- }
-
- if (key->totkey == 0) {
- switch (GS(key->from->name)) {
- case ID_ME: ((Mesh *)key->from)->key = NULL; break;
- case ID_CU: ((Curve *)key->from)->key = NULL; break;
- case ID_LT: ((Lattice *)key->from)->key = NULL; break;
- }
-
- BKE_libblock_free_us(bmain, key);
+ return BKE_object_shapekey_remove(bmain, ob, kb);
}
- return true;
+ return false;
}
static bool object_shape_key_mirror(bContext *C, Object *ob,
@@ -301,6 +239,16 @@ static int shape_key_mode_exists_poll(bContext *C)
(BKE_keyblock_from_object(ob) != NULL);
}
+static int shape_key_move_poll(bContext *C)
+{
+ /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ Key *key = BKE_key_from_object(ob);
+
+ return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
+}
+
static int shape_key_poll(bContext *C)
{
Object *ob = ED_object_context(C);
@@ -310,11 +258,13 @@ static int shape_key_poll(bContext *C)
static int shape_key_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_context(C);
const bool from_mix = RNA_boolean_get(op->ptr, "from_mix");
- ED_object_shape_key_add(C, scene, ob, from_mix);
+ ED_object_shape_key_add(C, ob, from_mix);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(CTX_data_main(C));
return OPERATOR_FINISHED;
}
@@ -344,14 +294,15 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
bool changed = false;
if (RNA_boolean_get(op->ptr, "all")) {
- changed = ED_object_shape_key_remove_all(bmain, ob);
+ changed = BKE_object_shapekey_free(bmain, ob);
}
else {
- changed = ED_object_shape_key_remove(bmain, ob);
+ changed = object_shapekey_remove(bmain, ob);
}
if (changed) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -369,7 +320,6 @@ void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
ot->description = "Remove shape key from the object";
/* api callbacks */
- ot->poll = shape_key_mode_poll;
ot->poll = shape_key_mode_exists_poll;
ot->exec = shape_key_remove_exec;
@@ -482,86 +432,40 @@ void OBJECT_OT_shape_key_mirror(wmOperatorType *ot)
}
+enum {
+ KB_MOVE_TOP = -2,
+ KB_MOVE_UP = -1,
+ KB_MOVE_DOWN = 1,
+ KB_MOVE_BOTTOM = 2,
+};
+
static int shape_key_move_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- Key *key = BKE_key_from_object(ob);
- if (!key) {
- return OPERATOR_CANCELLED;
+ Key *key = BKE_key_from_object(ob);
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int totkey = key->totkey;
+ const int act_index = ob->shapenr - 1;
+ int new_index;
+
+ switch (type) {
+ case KB_MOVE_TOP:
+ /* Replace the ref key only if we're at the top already (only for relative keys) */
+ new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1;
+ break;
+ case KB_MOVE_BOTTOM:
+ new_index = totkey - 1;
+ break;
+ case KB_MOVE_UP:
+ case KB_MOVE_DOWN:
+ default:
+ new_index = (totkey + act_index + type) % totkey;
+ break;
}
- {
- KeyBlock *kb, *kb_other, *kb_iter;
- const int type = RNA_enum_get(op->ptr, "type");
- const int shape_tot = key->totkey;
- const int shapenr_act = ob->shapenr - 1;
- const int shapenr_swap = (shape_tot + shapenr_act + type) % shape_tot;
-
- kb = BLI_findlink(&key->block, shapenr_act);
- if (!kb || shape_tot == 1) {
- return OPERATOR_CANCELLED;
- }
-
- if (type == -1) {
- /* move back */
- kb_other = kb->prev;
- BLI_remlink(&key->block, kb);
- BLI_insertlinkbefore(&key->block, kb_other, kb);
- }
- else {
- /* move next */
- kb_other = kb->next;
- BLI_remlink(&key->block, kb);
- BLI_insertlinkafter(&key->block, kb_other, kb);
- }
-
- ob->shapenr = shapenr_swap + 1;
-
- /* for relative shape keys */
- if (kb_other) {
- for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) {
- if (kb_iter->relative == shapenr_act) {
- kb_iter->relative = shapenr_swap;
- }
- else if (kb_iter->relative == shapenr_swap) {
- kb_iter->relative = shapenr_act;
- }
- }
- }
- /* First key became last, or vice-versa, we have to change all keys' relative value. */
- else {
- for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) {
- if (kb_iter->relative == shapenr_act) {
- kb_iter->relative = shapenr_swap;
- }
- else {
- kb_iter->relative += type;
- }
- }
- }
-
- /* for absolute shape keys */
- if (kb_other) {
- SWAP(float, kb_other->pos, kb->pos);
- }
- /* First key became last, or vice-versa, we have to change all keys' pos value. */
- else {
- float pos = kb->pos;
- if (type == -1) {
- for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) {
- SWAP(float, kb_iter->pos, pos);
- }
- }
- else {
- for (kb_iter = key->block.last; kb_iter; kb_iter = kb_iter->prev) {
- SWAP(float, kb_iter->pos, pos);
- }
- }
- }
-
- /* First key is refkey, matches interface and BKE_key_sort */
- key->refkey = key->block.first;
+ if (!BKE_keyblock_move(ob, act_index, new_index)) {
+ return OPERATOR_CANCELLED;
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -573,9 +477,11 @@ static int shape_key_move_exec(bContext *C, wmOperator *op)
void OBJECT_OT_shape_key_move(wmOperatorType *ot)
{
static EnumPropertyItem slot_move[] = {
- {-1, "UP", 0, "Up", ""},
- {1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
+ {KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {KB_MOVE_UP, "UP", 0, "Up", ""},
+ {KB_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
+ { 0, NULL, 0, NULL, NULL }
};
/* identifiers */
@@ -584,7 +490,7 @@ void OBJECT_OT_shape_key_move(wmOperatorType *ot)
ot->description = "Move the active shape key up/down in the list";
/* api callbacks */
- ot->poll = shape_key_mode_poll;
+ ot->poll = shape_key_move_poll;
ot->exec = shape_key_move_exec;
/* flags */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index a1b8478a0e1..340b662c0ef 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -33,9 +33,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
-#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -69,7 +67,6 @@
#include "ED_armature.h"
#include "ED_keyframing.h"
-#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -942,8 +939,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* convert the offset to parent space */
BKE_object_to_mat4(ob, obmat);
- copy_v3_v3(centn, cent);
- mul_mat3_m4_v3(obmat, centn); /* omit translation part */
+ mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
add_v3_v3(ob->loc, centn);
@@ -973,8 +969,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
ob_other->flag |= OB_DONE;
DAG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA);
- copy_v3_v3(centn, cent);
- mul_mat3_m4_v3(ob_other->obmat, centn); /* ommit translation part */
+ mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
add_v3_v3(ob_other->loc, centn);
BKE_object_where_is_calc(scene, ob_other);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 777bbabb6e8..352c90e805a 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -36,16 +36,13 @@
#include "MEM_guardedalloc.h"
-#include "DNA_cloth_types.h"
#include "DNA_curve_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "DNA_object_force.h"
#include "DNA_scene_types.h"
-#include "DNA_particle_types.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
@@ -53,8 +50,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
+#include "BLI_stackdefines.h"
-#include "BLF_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -85,11 +82,6 @@
#include "object_intern.h"
/************************ Exported Functions **********************/
-static void vgroup_remap_update_users(Object *ob, int *map);
-static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup);
-static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
-static void vgroup_delete_all(Object *ob);
-
static bool vertex_group_use_vert_sel(Object *ob)
{
if (ob->mode == OB_MODE_EDIT) {
@@ -126,81 +118,6 @@ bool ED_vgroup_sync_from_pose(Object *ob)
return false;
}
-bool ED_vgroup_object_is_edit_mode(Object *ob)
-{
- if (ob->type == OB_MESH)
- return (BKE_editmesh_from_object(ob) != NULL);
- else if (ob->type == OB_LATTICE)
- return (((Lattice *)ob->data)->editlatt != NULL);
-
- return false;
-}
-
-bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name)
-{
- bDeformGroup *defgroup;
-
- if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type))
- return NULL;
-
- defgroup = BKE_defgroup_new(ob, name);
-
- ob->actdef = BLI_countlist(&ob->defbase);
-
- return defgroup;
-}
-
-bDeformGroup *ED_vgroup_add(Object *ob)
-{
- return ED_vgroup_add_name(ob, DATA_("Group"));
-}
-
-void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup)
-{
- BLI_assert(BLI_findindex(&ob->defbase, defgroup) != -1);
-
- if (ED_vgroup_object_is_edit_mode(ob))
- vgroup_delete_edit_mode(ob, defgroup);
- else
- vgroup_delete_object_mode(ob, defgroup);
-}
-
-void ED_vgroup_clear(Object *ob)
-{
- bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
- int edit_mode = ED_vgroup_object_is_edit_mode(ob);
-
- while (dg) {
- bDeformGroup *next_dg = dg->next;
-
- if (edit_mode)
- vgroup_delete_edit_mode(ob, dg);
- else
- vgroup_delete_object_mode(ob, dg);
-
- dg = next_dg;
- }
-}
-
-bool ED_vgroup_data_create(ID *id)
-{
- /* create deform verts */
-
- if (GS(id->name) == ID_ME) {
- Mesh *me = (Mesh *)id;
- me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
- return true;
- }
- else if (GS(id->name) == ID_LT) {
- Lattice *lt = (Lattice *)id;
- lt->dvert = MEM_callocN(sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw, "lattice deformVert");
- return true;
- }
- else {
- return false;
- }
-}
-
/**
* Removes out of range MDeformWeights
*/
@@ -327,34 +244,9 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co
return false;
}
-static bool ed_vgroup_dm_parray_alloc(DerivedMesh *dm, MDeformVert ***dvert_arr, int *dvert_tot)
-{
- *dvert_tot = 0;
- *dvert_arr = NULL;
-
- if (dm) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
-
- if (dvert) {
- int i, totvert = dm->getNumVerts(dm);
-
- *dvert_tot = totvert;
- *dvert_arr = MEM_mallocN(sizeof(void *) * totvert, "vgroup parray from me");
-
- for (i = 0; i < totvert; i++) {
- (*dvert_arr)[i] = dvert + i;
- }
-
- return true;
- }
- }
-
- return false;
-}
-
/**
* For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
- * This finds the unselected mirror deform verts and copys the weights to them from the selected.
+ * This finds the unselected mirror deform verts and copies the weights to them from the selected.
*
* \note \a dvert_array has mirrored weights filled in, incase cleanup operations are needed on both.
*/
@@ -465,34 +357,6 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot
}
}
-/* returns true if the id type supports weights */
-bool ED_vgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
-{
- if (id) {
- switch (GS(id->name)) {
- case ID_ME:
- {
- Mesh *me = (Mesh *)id;
- *dvert_arr = me->dvert;
- *dvert_tot = me->totvert;
- return true;
- }
- case ID_LT:
- {
- Lattice *lt = (Lattice *)id;
- lt = (lt->editlatt) ? lt->editlatt->latt : lt;
- *dvert_arr = lt->dvert;
- *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
- return true;
- }
- }
- }
-
- *dvert_arr = NULL;
- *dvert_tot = 0;
- return false;
-}
-
/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
@@ -501,8 +365,8 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
int dvert_tot_from;
int dvert_tot;
int i;
- int defbase_tot_from = BLI_countlist(&ob_from->defbase);
- int defbase_tot = BLI_countlist(&ob->defbase);
+ int defbase_tot_from = BLI_listbase_count(&ob_from->defbase);
+ int defbase_tot = BLI_listbase_count(&ob->defbase);
bool new_vgroup = false;
if (ob == ob_from)
@@ -511,7 +375,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
- if ((dvert_array == NULL) && (dvert_array_from != NULL) && ED_vgroup_data_create(ob->data)) {
+ if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
new_vgroup = true;
}
@@ -523,7 +387,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
if (new_vgroup == true) {
/* free the newly added vgroup since it wasn't compatible */
- vgroup_delete_all(ob);
+ BKE_object_defgroup_remove_all(ob);
}
/* if true: both are 0 and nothing needs changing, consider this a success */
@@ -541,7 +405,7 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
for (i = 0; i <= defbase_tot_from; i++) remap[i] = i;
for (; i <= defbase_tot; i++) remap[i] = 0; /* can't use these, so disable */
- vgroup_remap_update_users(ob, remap);
+ BKE_object_defgroup_remap_update_users(ob, remap);
MEM_freeN(remap);
}
@@ -564,6 +428,48 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
return true;
}
+void ED_vgroup_parray_to_weight_array(
+ const MDeformVert **dvert_array, const int dvert_tot,
+ float *dvert_weights, const int def_nr)
+{
+ int i;
+
+ for (i = 0; i < dvert_tot; i++) {
+ const MDeformVert *dv = dvert_array[i];
+ dvert_weights[i] = dv ? defvert_find_weight(dv, def_nr) : 0.0f;
+ }
+}
+
+void ED_vgroup_parray_from_weight_array(
+ MDeformVert **dvert_array, const int dvert_tot,
+ const float *dvert_weights, const int def_nr, const bool remove_zero)
+{
+ int i;
+
+ for (i = 0; i < dvert_tot; i++) {
+ MDeformVert *dv = dvert_array[i];
+ if (dv) {
+ if (dvert_weights[i] > 0.0f) {
+ MDeformWeight *dw = defvert_verify_index(dv, def_nr);
+ BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f));
+ dw->weight = dvert_weights[i];
+ }
+ else {
+ MDeformWeight *dw = defvert_find_index(dv, def_nr);
+ if (dw) {
+ if (remove_zero) {
+ defvert_remove_group(dv, dw);
+ }
+ else {
+ dw->weight = 0.0f;
+ }
+ }
+ }
+ }
+ }
+}
+
+
/* TODO, cache flip data to speedup calls within a loop. */
static void mesh_defvert_mirror_update_internal(Object *ob,
MDeformVert *dvert_dst, MDeformVert *dvert_src,
@@ -682,7 +588,7 @@ static void vgroup_normalize_active(Object *ob, eVGroupSelect subset_type)
return;
}
- vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot);
MEM_freeN((void *)vgroup_validmap);
@@ -703,7 +609,7 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
BMEditMesh *em = me->edit_btmesh;
MDeformVert *dvert_act;
int i, vgroup_tot, subset_count;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
if (em) {
@@ -747,51 +653,6 @@ static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
/***********************Start weight transfer (WT)*********************************/
-typedef enum WT_VertexGroupMode {
- WT_REPLACE_ACTIVE_VERTEX_GROUP = 1,
- WT_REPLACE_ALL_VERTEX_GROUPS = 2
-} WT_VertexGroupMode;
-
-typedef enum WT_Method {
- WT_BY_INDEX = 1,
- WT_BY_NEAREST_VERTEX = 2,
- WT_BY_NEAREST_FACE = 3,
- WT_BY_NEAREST_VERTEX_IN_FACE = 4
-} WT_Method;
-
-typedef enum WT_ReplaceMode {
- WT_REPLACE_ALL_WEIGHTS = 1,
- WT_REPLACE_EMPTY_WEIGHTS = 2
-} WT_ReplaceMode;
-
-static EnumPropertyItem WT_vertex_group_mode_item[] = {
- {WT_REPLACE_ACTIVE_VERTEX_GROUP,
- "WT_REPLACE_ACTIVE_VERTEX_GROUP", 0, "Active", "Transfer active vertex group from selected to active mesh"},
- {WT_REPLACE_ALL_VERTEX_GROUPS,
- "WT_REPLACE_ALL_VERTEX_GROUPS", 0, "All", "Transfer all vertex groups from selected to active mesh"},
- {0, NULL, 0, NULL, NULL}
-};
-
-static EnumPropertyItem WT_method_item[] = {
- {WT_BY_INDEX,
- "WT_BY_INDEX", 0, "Vertex index", "Copy for identical meshes"},
- {WT_BY_NEAREST_VERTEX,
- "WT_BY_NEAREST_VERTEX", 0, "Nearest vertex", "Copy weight from closest vertex"},
- {WT_BY_NEAREST_FACE,
- "WT_BY_NEAREST_FACE", 0, "Nearest face", "Barycentric interpolation from nearest face"},
- {WT_BY_NEAREST_VERTEX_IN_FACE,
- "WT_BY_NEAREST_VERTEX_IN_FACE", 0, "Nearest vertex in face", "Copy weight from closest vertex in nearest face"},
- {0, NULL, 0, NULL, NULL}
-};
-
-static EnumPropertyItem WT_replace_mode_item[] = {
- {WT_REPLACE_ALL_WEIGHTS,
- "WT_REPLACE_ALL_WEIGHTS", 0, "All", "Overwrite all weights"},
- {WT_REPLACE_EMPTY_WEIGHTS,
- "WT_REPLACE_EMPTY_WEIGHTS", 0, "Empty", "Add weights to vertices with no weight"},
- {0, NULL, 0, NULL, NULL}
-};
-
static EnumPropertyItem WT_vertex_group_select_item[] = {
{WT_VGROUP_ACTIVE,
"ACTIVE", 0, "Active Group", "The active Vertex Group"},
@@ -867,298 +728,6 @@ static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_act
ot->prop = prop;
}
-/* Copy weight.*/
-static void vgroup_transfer_weight(float *r_weight_dst, const float weight_src, const WT_ReplaceMode replace_mode)
-{
- switch (replace_mode) {
- case WT_REPLACE_ALL_WEIGHTS:
- *r_weight_dst = weight_src;
- break;
-
- case WT_REPLACE_EMPTY_WEIGHTS:
- if (*r_weight_dst == 0.0f) {
- *r_weight_dst = weight_src;
- }
- break;
-
- default:
- BLI_assert(0);
- break;
- }
-}
-
-/* Could be exposed externally by implementing it in header with the rest.
- * Simple refactoring will break something.
- * For now, naming is ed_ instead of ED_*/
-static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGroup *dg_src, Scene *scene,
- WT_Method method, WT_ReplaceMode replace_mode, wmOperator *op)
-{
- bDeformGroup *dg_dst;
- Mesh *me_dst;
- DerivedMesh *dmesh_src;
- BVHTreeFromMesh tree_mesh_vertices_src, tree_mesh_faces_src = {NULL};
- MDeformVert **dv_array_src, **dv_array_dst, **dv_src, **dv_dst;
- MVert *mv_dst, *mv_src;
- MFace *mface_src, *mf;
- BVHTreeNearest nearest;
- MDeformWeight *dw_dst, *dw_src;
- int dv_tot_src, dv_tot_dst, i, v_index, index_dst, index_src, index_nearest, index_nearest_vertex;
- unsigned int f_index;
- float weight, tmp_weight[4], tmp_co[3], normal[3], tmp_mat[4][4], dist_v1, dist_v2, dist_v3, dist_v4;
- const int use_vert_sel = vertex_group_use_vert_sel(ob_dst);
- bool is_dg_dst_new = false;
-
- /* Ensure vertex group on target.*/
- if ((dg_dst = defgroup_find_name(ob_dst, dg_src->name)) == NULL) {
- dg_dst = BKE_defgroup_new(ob_dst, dg_src->name);
- is_dg_dst_new = true;
- }
-
- /* Get meshes.*/
- dmesh_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MASK_MDEFORMVERT);
- me_dst = ob_dst->data;
-
- /* Get vertex group array from source mesh */
- if (!ed_vgroup_dm_parray_alloc(dmesh_src, &dv_array_src, &dv_tot_src)) {
- BKE_report(op->reports, RPT_ERROR, "Transfer failed (source mesh does not have any vertex groups)");
- return false;
- }
-
- /* Create data in memory when nothing there.*/
- if (!me_dst->dvert) ED_vgroup_data_create(&me_dst->id);
-
- /* Get vertex group for destination mesh */
- ED_vgroup_parray_alloc(&me_dst->id, &dv_array_dst, &dv_tot_dst, use_vert_sel);
-
- /* Get indexes of vertex groups.*/
- index_src = BLI_findindex(&ob_src->defbase, dg_src);
- index_dst = BLI_findindex(&ob_dst->defbase, dg_dst);
-
- /* Get vertices.*/
- mv_dst = me_dst->mvert;
- mv_src = dmesh_src->getVertArray(dmesh_src);
-
- /* Prepare transformation matrix.*/
- invert_m4_m4(ob_src->imat, ob_src->obmat);
- mul_m4_m4m4(tmp_mat, ob_src->imat, ob_dst->obmat);
-
- /* Clear weights.*/
- if (replace_mode == WT_REPLACE_ALL_WEIGHTS) {
- for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++) {
-
- if (*dv_dst == NULL) continue;
-
- dw_dst = defvert_find_index(*dv_dst, index_dst);
- /* Remove vertex from group.*/
- if (dw_dst) defvert_remove_group(*dv_dst, dw_dst);
- }
- }
-
- switch (method) {
-
- case WT_BY_INDEX:
- /* Check if indices are matching, delete and return if not.*/
- if (ob_dst == ob_src || dv_tot_dst == 0 || dv_tot_dst != dv_tot_src ||
- dv_array_src == NULL || dv_array_dst == NULL)
- {
- if (is_dg_dst_new) {
- ED_vgroup_delete(ob_dst, dg_dst);
- }
-
- if (dv_array_src) MEM_freeN(dv_array_src);
- if (dv_array_dst) MEM_freeN(dv_array_dst);
- dmesh_src->release(dmesh_src);
- BKE_report(op->reports, RPT_ERROR, "Transfer failed (indices are not matching)");
- return false;
- }
-
- /* Loop through the vertices.*/
- for (i = 0, dv_src = dv_array_src, dv_dst = dv_array_dst;
- i < me_dst->totvert;
- i++, dv_dst++, dv_src++, mv_src++, mv_dst++)
- {
-
- if (*dv_dst == NULL) {
- continue;
- }
-
- /* Copy weight.*/
- dw_src = defvert_find_index(*dv_src, index_src);
- if (dw_src && dw_src->weight) {
- dw_dst = defvert_verify_index(*dv_dst, index_dst);
- vgroup_transfer_weight(&dw_dst->weight, dw_src->weight, replace_mode);
- }
- }
- break;
-
- case WT_BY_NEAREST_VERTEX:
- /* Make node tree.*/
- bvhtree_from_mesh_verts(&tree_mesh_vertices_src, dmesh_src, FLT_EPSILON, 2, 6);
-
- /* Loop trough vertices.*/
- for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++, mv_dst++) {
-
- if (*dv_dst == NULL) {
- continue;
- }
-
- /* Reset nearest.*/
- nearest.dist_sq = FLT_MAX;
- /* It is faster to start searching at the top of the tree instead of previous search result.*/
- nearest.index = -1;
-
- /* Transform into target space.*/
- mul_v3_m4v3(tmp_co, tmp_mat, mv_dst->co);
-
- /* Node tree accelerated search for closest vetex.*/
- BLI_bvhtree_find_nearest(tree_mesh_vertices_src.tree, tmp_co,
- &nearest, tree_mesh_vertices_src.nearest_callback, &tree_mesh_vertices_src);
-
- /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are
- * overwritten prior to this. See the "Clear weights." step above.*/
- dw_src = defvert_find_index(dv_array_src[nearest.index], index_src);
- if (dw_src && dw_src->weight) {
- dw_dst = defvert_verify_index(*dv_dst, index_dst);
- vgroup_transfer_weight(&dw_dst->weight, dw_src->weight, replace_mode);
- }
- }
-
- /* Free memory.*/
- free_bvhtree_from_mesh(&tree_mesh_vertices_src);
- break;
-
- case WT_BY_NEAREST_FACE:
- /* Get faces.*/
- DM_ensure_tessface(dmesh_src);
- mface_src = dmesh_src->getTessFaceArray(dmesh_src);
-
- /* Make node tree.*/
- bvhtree_from_mesh_faces(&tree_mesh_faces_src, dmesh_src, FLT_EPSILON, 2, 6);
-
- /* Loop through the vertices.*/
- for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++, mv_dst++) {
-
- if (*dv_dst == NULL) {
- continue;
- }
-
- /* Reset nearest.*/
- nearest.dist_sq = FLT_MAX;
- /* It is faster to start searching at the top of the tree instead of previous search result.*/
- nearest.index = -1;
-
- /* Transform into target space.*/
- mul_v3_m4v3(tmp_co, tmp_mat, mv_dst->co);
-
- /* Node tree accelerated search for closest face.*/
- BLI_bvhtree_find_nearest(tree_mesh_faces_src.tree, tmp_co,
- &nearest, tree_mesh_faces_src.nearest_callback, &tree_mesh_faces_src);
- index_nearest = nearest.index;
-
- /* Project onto face.*/
- mf = &mface_src[index_nearest];
- normal_tri_v3(normal, mv_src[mf->v1].co, mv_src[mf->v2].co, mv_src[mf->v3].co);
- project_v3_plane(tmp_co, normal, mv_src[mf->v1].co);
-
- /* Interpolate weights over face.*/
- interp_weights_face_v3(tmp_weight,
- mv_src[mf->v1].co,
- mv_src[mf->v2].co,
- mv_src[mf->v3].co,
- mf->v4 ? mv_src[mf->v4].co : NULL,
- tmp_co);
-
- /* Get weights from face.*/
- f_index = mf->v4 ? 3 : 2;
- weight = 0.0f;
- do {
- v_index = (&mf->v1)[f_index];
- weight += tmp_weight[f_index] * defvert_find_weight(dv_array_src[v_index], index_src);
- } while (f_index--);
-
- /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are
- * overwritten prior to this. See the "Clear weights." step above.*/
- if (weight > 0.0f) {
- dw_dst = defvert_verify_index(*dv_dst, index_dst);
- vgroup_transfer_weight(&dw_dst->weight, weight, replace_mode);
- }
- }
-
- /* Free memory.*/
- free_bvhtree_from_mesh(&tree_mesh_faces_src);
- break;
-
- case WT_BY_NEAREST_VERTEX_IN_FACE:
- /* Get faces.*/
- DM_ensure_tessface(dmesh_src);
- mface_src = dmesh_src->getTessFaceArray(dmesh_src);
-
- /* Make node tree.*/
- bvhtree_from_mesh_faces(&tree_mesh_faces_src, dmesh_src, FLT_EPSILON, 2, 6);
-
- /* Loop through the vertices.*/
- for (i = 0, dv_dst = dv_array_dst; i < me_dst->totvert; i++, dv_dst++, mv_dst++) {
-
- if (*dv_dst == NULL) {
- continue;
- }
-
- /* Reset nearest.*/
- nearest.dist_sq = FLT_MAX;
- /* It is faster to start searching at the top of the tree instead of previous search result.*/
- nearest.index = -1;
-
- /* Transform into target space.*/
- mul_v3_m4v3(tmp_co, tmp_mat, mv_dst->co);
-
- /* Node tree accelerated search for closest face.*/
- BLI_bvhtree_find_nearest(tree_mesh_faces_src.tree, tmp_co,
- &nearest, tree_mesh_faces_src.nearest_callback, &tree_mesh_faces_src);
- index_nearest = nearest.index;
-
- /* Get distances.*/
- mf = &mface_src[index_nearest];
- dist_v1 = len_squared_v3v3(tmp_co, mv_src[mf->v1].co);
- dist_v2 = len_squared_v3v3(tmp_co, mv_src[mf->v2].co);
- dist_v3 = len_squared_v3v3(tmp_co, mv_src[mf->v3].co);
-
- /* Get closest vertex.*/
- f_index = mf->v4 ? 3 : 2;
- if (dist_v1 < dist_v2 && dist_v1 < dist_v3) index_nearest_vertex = mf->v1;
- else if (dist_v2 < dist_v3) index_nearest_vertex = mf->v2;
- else index_nearest_vertex = mf->v3;
- if (f_index == 3) {
- dist_v4 = len_squared_v3v3(tmp_co, mv_src[mf->v4].co);
- if (dist_v4 < dist_v1 && dist_v4 < dist_v2 && dist_v4 < dist_v3) {
- index_nearest_vertex = mf->v4;
- }
- }
-
- /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are
- * overwritten prior to this. See the "Clear weights." step above.*/
- dw_src = defvert_find_index(dv_array_src[index_nearest_vertex], index_src);
- if (dw_src && dw_src->weight) {
- dw_dst = defvert_verify_index(*dv_dst, index_dst);
- vgroup_transfer_weight(&dw_dst->weight, dw_src->weight, replace_mode);
- }
- }
-
- /* Free memory.*/
- free_bvhtree_from_mesh(&tree_mesh_faces_src);
- break;
-
- default:
- BLI_assert(0);
- break;
- }
-
- /* Free memory.*/
- if (dv_array_src) MEM_freeN(dv_array_src);
- if (dv_array_dst) MEM_freeN(dv_array_dst);
- dmesh_src->release(dmesh_src);
-
- return true;
-}
/***********************End weight transfer (WT)***********************************/
@@ -1175,7 +744,7 @@ static void ED_vgroup_nr_vert_add(Object *ob,
int tot;
/* get the vert */
- ED_vgroup_array_get(ob->data, &dvert, &tot);
+ BKE_object_defgroup_array_get(ob->data, &dvert, &tot);
if (dvert == NULL)
return;
@@ -1208,7 +777,7 @@ static void ED_vgroup_nr_vert_add(Object *ob,
break;
case WEIGHT_SUBTRACT:
dw->weight -= weight;
- /* if the weight is zero or less then
+ /* if the weight is zero or less than
* remove the vert from the deform group
*/
if (dw->weight <= 0.0f) {
@@ -1261,8 +830,8 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
/* if there's no deform verts then create some,
*/
- if (ED_vgroup_array_get(ob->data, &dv, &tot) && dv == NULL)
- ED_vgroup_data_create(ob->data);
+ if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL)
+ BKE_object_defgroup_data_create(ob->data);
/* call another function to do the work
*/
@@ -1287,7 +856,7 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
/* get the deform vertices corresponding to the
* vertnum
*/
- ED_vgroup_array_get(ob->data, &dvert, &tot);
+ BKE_object_defgroup_array_get(ob->data, &dvert, &tot);
if (dvert) {
MDeformVert *dv = &dvert[vertnum];
@@ -1476,7 +1045,7 @@ static void vgroup_duplicate(Object *ob)
BLI_addtail(&ob->defbase, cdg);
idg = (ob->actdef - 1);
- ob->actdef = BLI_countlist(&ob->defbase);
+ ob->actdef = BLI_listbase_count(&ob->defbase);
icdg = (ob->actdef - 1);
/* TODO, we might want to allow only copy selected verts here? - campbell */
@@ -1498,86 +1067,6 @@ static void vgroup_duplicate(Object *ob)
}
}
-/**
- * Return the subset type of the Vertex Group Selection
- */
-bool *ED_vgroup_subset_from_select_type(Object *ob, eVGroupSelect subset_type, int *r_vgroup_tot, int *r_subset_count)
-{
- bool *vgroup_validmap = NULL;
- *r_vgroup_tot = BLI_countlist(&ob->defbase);
-
- switch (subset_type) {
- case WT_VGROUP_ACTIVE:
- {
- const int def_nr_active = ob->actdef - 1;
- vgroup_validmap = MEM_mallocN(*r_vgroup_tot * sizeof(*vgroup_validmap), __func__);
- memset(vgroup_validmap, false, *r_vgroup_tot * sizeof(*vgroup_validmap));
- if ((def_nr_active >= 0) && (def_nr_active < *r_vgroup_tot)) {
- *r_subset_count = 1;
- vgroup_validmap[def_nr_active] = true;
- }
- else {
- *r_subset_count = 0;
- }
- break;
- }
- case WT_VGROUP_BONE_SELECT:
- {
- vgroup_validmap = BKE_objdef_selected_get(ob, *r_vgroup_tot, r_subset_count);
- break;
- }
- case WT_VGROUP_BONE_DEFORM:
- {
- int i;
- vgroup_validmap = BKE_objdef_validmap_get(ob, *r_vgroup_tot);
- *r_subset_count = 0;
- for (i = 0; i < *r_vgroup_tot; i++) {
- if (vgroup_validmap[i] == true) {
- *r_subset_count += 1;
- }
- }
- break;
- }
- case WT_VGROUP_BONE_DEFORM_OFF:
- {
- int i;
- vgroup_validmap = BKE_objdef_validmap_get(ob, *r_vgroup_tot);
- *r_subset_count = 0;
- for (i = 0; i < *r_vgroup_tot; i++) {
- vgroup_validmap[i] = !vgroup_validmap[i];
- if (vgroup_validmap[i] == true) {
- *r_subset_count += 1;
- }
- }
- break;
- }
- case WT_VGROUP_ALL:
- default:
- {
- vgroup_validmap = MEM_mallocN(*r_vgroup_tot * sizeof(*vgroup_validmap), __func__);
- memset(vgroup_validmap, true, *r_vgroup_tot * sizeof(*vgroup_validmap));
- *r_subset_count = *r_vgroup_tot;
- break;
- }
- }
-
- return vgroup_validmap;
-}
-
-/**
- * store indices from the vgroup_validmap (faster lookups in some cases)
- */
-void ED_vgroup_subset_to_index_array(const bool *vgroup_validmap, const int vgroup_tot,
- int *r_vgroup_subset_map)
-{
- int i, j = 0;
- for (i = 0; i < vgroup_tot; i++) {
- if (vgroup_validmap[i]) {
- r_vgroup_subset_map[j++] = i;
- }
- }
-}
-
static void vgroup_normalize(Object *ob)
{
MDeformWeight *dw;
@@ -1724,14 +1213,14 @@ static void getVerticalAndHorizontalChange(const float norm[3], float d, const f
plane_from_point_normal_v3(plane, coord, norm);
- closest_to_plane_v3(projA, plane, start);
- closest_to_plane_v3(projB, plane, end);
+ closest_to_plane_normalized_v3(projA, plane, start);
+ closest_to_plane_normalized_v3(projB, plane, end);
/* (vertical and horizontal refer to the plane's y and xz respectively)
* vertical distance */
dists[index] = dot_v3v3(norm, end) + d;
/* vertical change */
changes[index][0] = dists[index] - distToStart;
- //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
+ //printf("vc %f %f\n", distance(end, projB, 3) - distance(start, projA, 3), changes[index][0]);
/* horizontal change */
changes[index][1] = len_v3v3(projA, projB);
}
@@ -2051,8 +1540,8 @@ static void vgroup_normalize_all(Object *ob,
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
if (dvert_array) {
- const int defbase_tot = BLI_countlist(&ob->defbase);
- bool *lock_flags = BKE_objdef_lock_flags_get(ob, defbase_tot);
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
if ((lock_active == true) &&
(lock_flags != NULL) &&
@@ -2185,9 +1674,17 @@ static void vgroup_invert_subset(Object *ob,
}
}
-static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot,
- const int subset_count,
- const float fac)
+enum {
+ WEIGHT_SMOOTH_ALL = -1,
+ WEIGHT_SMOOTH_DESELECT = false,
+ WEIGHT_SMOOTH_SELECT = true,
+};
+
+static void vgroup_smooth_subset(
+ Object *ob, const bool *vgroup_validmap, const int vgroup_tot,
+ const int subset_count,
+ const float fac, const int repeat,
+ const float fac_expand, const int source)
{
const float ifac = 1.0f - fac;
MDeformVert **dvert_array = NULL;
@@ -2196,102 +1693,186 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count);
const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false;
+ const int expand_sign = signum_i(fac_expand);
+ const float expand = fabsf(fac_expand);
+ const float iexpand = 1.0f - expand;
+
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em ? em->bm : NULL;
Mesh *me = em ? NULL : ob->data;
- MeshElemMap *emap ;
+ MeshElemMap *emap;
int *emap_mem;
- BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *);
+ float *weight_accum_prev;
+ float *weight_accum_curr;
+
+ unsigned int subset_index;
+
+ /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */
+ unsigned int *verts_used;
+ STACK_DECLARE(verts_used);
- ED_vgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map);
+
+ BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map);
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count);
if (bm) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
emap = NULL;
emap_mem = NULL;
}
else {
- BKE_mesh_vert_edge_map_create(&emap, &emap_mem,
- me->medge, me->totvert, me->totedge);
+ BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
}
+ weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__);
+ weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__);
+
+ verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__);
+ STACK_INIT(verts_used, dvert_tot);
- for (i = 0; i < dvert_tot; i++) {
- MDeformVert *dv;
- int dv_stack_tot = 0;
- int j;
- /* in case its not selected */
- if (bm) {
+ /* initialize used verts */
+ if (bm) {
+ for (i = 0; i < dvert_tot; i++) {
BMVert *v = BM_vert_at_index(bm, i);
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
BMIter eiter;
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
BMVert *v_other = BM_edge_other_vert(e, v);
- const int i_other = BM_elem_index_get(v_other);
-
- if (BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) {
- dv = dvert_array[i_other];
- BLI_SMALLSTACK_PUSH(dv_stack, dv);
- dv_stack_tot++;
+ if ((source == WEIGHT_SMOOTH_ALL) ||
+ (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0)))
+ {
+ STACK_PUSH(verts_used, i);
+ break;
}
}
}
}
- else {
+ }
+ else {
+ for (i = 0; i < dvert_tot; i++) {
MVert *v = &me->mvert[i];
if (v->flag & SELECT) {
+ int j;
for (j = 0; j < emap[i].count; j++) {
MEdge *e = &me->medge[emap[i].indices[j]];
const int i_other = (e->v1 == i ? e->v2 : e->v1);
MVert *v_other = &me->mvert[i_other];
-
- if ((v_other->flag & SELECT) == 0) {
- dv = dvert_array[i_other];
- BLI_SMALLSTACK_PUSH(dv_stack, dv);
- dv_stack_tot++;
+ if ((source == WEIGHT_SMOOTH_ALL) ||
+ (source == ((v_other->flag & SELECT) != 0)))
+ {
+ STACK_PUSH(verts_used, i);
+ break;
}
}
}
}
+ }
- if (dv_stack_tot) {
- const float dv_mul = 1.0f / (float)dv_stack_tot;
+ for (subset_index = 0; subset_index < subset_count; subset_index++) {
+ const int def_nr = vgroup_subset_map[subset_index];
+ int iter;
- /* vgroup_subset_weights is zero'd at this point */
- while ((dv = BLI_SMALLSTACK_POP(dv_stack))) {
- for (j = 0; j < subset_count; j++) {
- vgroup_subset_weights[j] += dv_mul * defvert_find_weight(dv, vgroup_subset_map[j]);
- }
- }
+ ED_vgroup_parray_to_weight_array((const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr);
+ memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot);
- dv = dvert_array[i];
- for (j = 0; j < subset_count; j++) {
- MDeformWeight *dw;
- if (vgroup_subset_weights[j] > 0.0f) {
- dw = defvert_verify_index(dv, vgroup_subset_map[j]);
+ for (iter = 0; iter < repeat; iter++) {
+ unsigned *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used);
+
+ /* avoid looping over all verts */
+ // for (i = 0; i < dvert_tot; i++)
+ for (vi_step = verts_used; vi_step != vi_end; vi_step++) {
+ const unsigned int i = *vi_step;
+ float weight_tot = 0.0f;
+ float weight = 0.0f;
+
+#define WEIGHT_ACCUMULATE \
+ { \
+ float weight_other = weight_accum_prev[i_other]; \
+ float tot_factor = 1.0f; \
+ if (expand_sign == 1) { /* expand */ \
+ if (weight_other < weight_accum_prev[i]) { \
+ weight_other = (weight_accum_prev[i_other] * iexpand) + (weight_other * expand); \
+ tot_factor = iexpand; \
+ } \
+ } \
+ else if (expand_sign == -1) { /* contract */ \
+ if (weight_other > weight_accum_prev[i]) { \
+ weight_other = (weight_accum_prev[i_other] * iexpand) + (weight_other * expand); \
+ tot_factor = iexpand; \
+ } \
+ } \
+ weight += tot_factor * weight_other; \
+ weight_tot += tot_factor; \
+ } ((void)0)
+
+
+ if (bm) {
+ BMVert *v = BM_vert_at_index(bm, i);
+ BMIter eiter;
+ BMEdge *e;
+
+ /* checked already */
+ BLI_assert(BM_elem_flag_test(v, BM_ELEM_SELECT));
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if ((source == WEIGHT_SMOOTH_ALL) ||
+ (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0)))
+ {
+ const int i_other = BM_elem_index_get(v_other);
+
+ WEIGHT_ACCUMULATE;
+ }
+ }
}
else {
- dw = defvert_find_index(dv, vgroup_subset_map[j]);
- }
+ int j;
- if (dw) {
- dw->weight = (fac * vgroup_subset_weights[j]) + (ifac * dw->weight);
- CLAMP(dw->weight, 0.0f, 1.0f);
+ /* checked already */
+ BLI_assert(me->mvert[i].flag & SELECT);
+
+ for (j = 0; j < emap[i].count; j++) {
+ MEdge *e = &me->medge[emap[i].indices[j]];
+ const int i_other = (e->v1 == i ? e->v2 : e->v1);
+ MVert *v_other = &me->mvert[i_other];
+
+ if ((source == WEIGHT_SMOOTH_ALL) ||
+ (source == ((v_other->flag & SELECT) != 0)))
+ {
+ WEIGHT_ACCUMULATE;
+ }
+ }
}
- /* zero for next iteration */
- vgroup_subset_weights[j] = 0.0f;
+#undef WEIGHT_ACCUMULATE
+
+ if (weight_tot != 0.0f) {
+ weight /= weight_tot;
+ weight = (weight_accum_prev[i] * ifac) + (weight * fac);
+
+ /* should be within range, just clamp because of float precision */
+ CLAMP(weight, 0.0f, 1.0f);
+ weight_accum_curr[i] = weight;
+ }
}
+
+ SWAP(float *, weight_accum_curr, weight_accum_prev);
}
+
+ ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true);
}
+ MEM_freeN(weight_accum_curr);
+ MEM_freeN(weight_accum_prev);
+ MEM_freeN(verts_used);
+
if (bm) {
/* pass */
}
@@ -2616,7 +2197,7 @@ void ED_vgroup_mirror(Object *ob,
/* object mode / weight paint */
MVert *mv, *mv_mirr;
int vidx, vidx_mirr;
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
if (me->dvert == NULL) {
goto cleanup;
@@ -2725,298 +2306,13 @@ cleanup:
}
-static void vgroup_remap_update_users(Object *ob, int *map)
-{
- ExplodeModifierData *emd;
- ModifierData *md;
- ParticleSystem *psys;
- ClothModifierData *clmd;
- ClothSimSettings *clsim;
- int a;
-
- /* these cases don't use names to refer to vertex groups, so when
- * they get deleted the numbers get out of sync, this corrects that */
-
- if (ob->soft)
- ob->soft->vertgroup = map[ob->soft->vertgroup];
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Explode) {
- emd = (ExplodeModifierData *)md;
- emd->vgroup = map[emd->vgroup];
- }
- else if (md->type == eModifierType_Cloth) {
- clmd = (ClothModifierData *)md;
- clsim = clmd->sim_parms;
-
- if (clsim) {
- clsim->vgroup_mass = map[clsim->vgroup_mass];
- clsim->vgroup_bend = map[clsim->vgroup_bend];
- clsim->vgroup_struct = map[clsim->vgroup_struct];
- }
- }
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- for (a = 0; a < PSYS_TOT_VG; a++)
- psys->vgroup[a] = map[psys->vgroup[a]];
- }
-}
-
-
-static void vgroup_delete_update_users(Object *ob, int id)
-{
- int i, defbase_tot = BLI_countlist(&ob->defbase) + 1;
- int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del");
-
- map[id] = map[0] = 0;
- for (i = 1; i < id; i++) map[i] = i;
- for (i = id + 1; i < defbase_tot; i++) map[i] = i - 1;
-
- vgroup_remap_update_users(ob, map);
- MEM_freeN(map);
-}
-
-
-static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
-{
- MDeformVert *dvert_array = NULL;
- int dvert_tot = 0;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
-
- BLI_assert(def_nr != -1);
-
- ED_vgroup_array_get(ob->data, &dvert_array, &dvert_tot);
-
- if (dvert_array) {
- int i, j;
- MDeformVert *dv;
- for (i = 0, dv = dvert_array; i < dvert_tot; i++, dv++) {
- MDeformWeight *dw;
-
- dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
-
- /* inline, make into a function if anything else needs to do this */
- for (j = 0; j < dv->totweight; j++) {
- if (dv->dw[j].def_nr > def_nr) {
- dv->dw[j].def_nr--;
- }
- }
- /* done */
- }
- }
-
- vgroup_delete_update_users(ob, def_nr + 1);
-
- /* Remove the group */
- BLI_freelinkN(&ob->defbase, dg);
-
- /* Update the active deform index if necessary */
- if (ob->actdef > def_nr)
- ob->actdef--;
- if (ob->actdef < 1 && ob->defbase.first)
- ob->actdef = 1;
-
- /* remove all dverts */
- if (BLI_listbase_is_empty(&ob->defbase)) {
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
- me->dvert = NULL;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
- if (lt->dvert) {
- MEM_freeN(lt->dvert);
- lt->dvert = NULL;
- }
- }
- }
-}
-
-/* only in editmode */
-/* removes from active defgroup, if allverts==0 only selected vertices */
-static bool vgroup_active_remove_verts(Object *ob, const bool allverts, bDeformGroup *dg)
-{
- MDeformVert *dv;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
- bool changed = false;
-
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
-
- if (me->edit_btmesh) {
- BMEditMesh *em = me->edit_btmesh;
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
-
- if (cd_dvert_offset != -1) {
- BMVert *eve;
- BMIter iter;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
-
- if (dv && dv->dw && (allverts || BM_elem_flag_test(eve, BM_ELEM_SELECT))) {
- MDeformWeight *dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
- changed = true;
- }
- }
- }
- }
- else {
- if (me->dvert) {
- MVert *mv;
- int i;
-
- mv = me->mvert;
- dv = me->dvert;
-
- for (i = 0; i < me->totvert; i++, mv++, dv++) {
- if (mv->flag & SELECT) {
- if (dv->dw && (allverts || (mv->flag & SELECT))) {
- MDeformWeight *dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
- changed = true;
- }
- }
- }
- }
- }
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = vgroup_edit_lattice(ob);
-
- if (lt->dvert) {
- BPoint *bp;
- int i, tot = lt->pntsu * lt->pntsv * lt->pntsw;
-
- for (i = 0, bp = lt->def; i < tot; i++, bp++) {
- if (allverts || (bp->f1 & SELECT)) {
- MDeformWeight *dw;
-
- dv = &lt->dvert[i];
-
- dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
- changed = true;
- }
- }
- }
- }
-
- return changed;
-}
-
-static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
-{
- int i;
- const int dg_index = BLI_findindex(&ob->defbase, dg);
-
- BLI_assert(dg_index != -1);
-
- /* Make sure that no verts are using this group */
- if (vgroup_active_remove_verts(ob, true, dg) == false) {
- /* do nothing */
- }
- /* Make sure that any verts with higher indices are adjusted accordingly */
- else if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
-
- BMIter iter;
- BMVert *eve;
- MDeformVert *dvert;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
-
- if (dvert)
- for (i = 0; i < dvert->totweight; i++)
- if (dvert->dw[i].def_nr > dg_index)
- dvert->dw[i].def_nr--;
- }
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = vgroup_edit_lattice(ob);
- BPoint *bp;
- MDeformVert *dvert = lt->dvert;
- int a, tot;
-
- if (dvert) {
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- for (a = 0, bp = lt->def; a < tot; a++, bp++, dvert++) {
- for (i = 0; i < dvert->totweight; i++) {
- if (dvert->dw[i].def_nr > dg_index)
- dvert->dw[i].def_nr--;
- }
- }
- }
- }
-
- vgroup_delete_update_users(ob, dg_index + 1);
-
- /* Remove the group */
- BLI_freelinkN(&ob->defbase, dg);
-
- /* Update the active deform index if necessary */
- if (ob->actdef > dg_index)
- ob->actdef--;
- if (ob->actdef < 1 && ob->defbase.first)
- ob->actdef = 1;
-
- /* remove all dverts */
- if (BLI_listbase_is_empty(&ob->defbase)) {
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
- me->dvert = NULL;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = vgroup_edit_lattice(ob);
- if (lt->dvert) {
- MEM_freeN(lt->dvert);
- lt->dvert = NULL;
- }
- }
- }
-}
-
-static void vgroup_delete(Object *ob)
+static void vgroup_delete_active(Object *ob)
{
bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1);
if (!dg)
return;
- if (BKE_object_is_in_editmode_vgroup(ob))
- vgroup_delete_edit_mode(ob, dg);
- else
- vgroup_delete_object_mode(ob, dg);
-}
-
-static void vgroup_delete_all(Object *ob)
-{
- /* Remove all DVerts */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
- me->dvert = NULL;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = vgroup_edit_lattice(ob);
- if (lt->dvert) {
- MEM_freeN(lt->dvert);
- lt->dvert = NULL;
- }
- }
-
- /* Remove all DefGroups */
- BLI_freelistN(&ob->defbase);
-
- /* Fix counters/indices */
- ob->actdef = 0;
+ BKE_object_defgroup_remove(ob, dg);
}
/* only in editmode */
@@ -3061,7 +2357,7 @@ static void vgroup_assign_verts(Object *ob, const float weight)
int i;
if (!me->dvert) {
- ED_vgroup_data_create(&me->id);
+ BKE_object_defgroup_data_create(&me->id);
}
mv = me->mvert;
@@ -3085,7 +2381,7 @@ static void vgroup_assign_verts(Object *ob, const float weight)
int a, tot;
if (lt->dvert == NULL)
- ED_vgroup_data_create(&lt->id);
+ BKE_object_defgroup_data_create(&lt->id);
dv = lt->dvert;
@@ -3103,22 +2399,6 @@ static void vgroup_assign_verts(Object *ob, const float weight)
}
}
-/* only in editmode */
-/* removes from all defgroup, if allverts==0 only selected vertices */
-static bool vgroup_remove_verts(Object *ob, int allverts)
-{
- bool changed = false;
- /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
- * only operates on the active vgroup. So we iterate through all groups, by changing
- * active group index
- */
- bDeformGroup *dg;
- for (dg = ob->defbase.first; dg; dg = dg->next) {
- changed |= vgroup_active_remove_verts(ob, allverts, dg);
- }
- return changed;
-}
-
/********************** vertex group operators *********************/
static int vertex_group_poll(bContext *C)
@@ -3150,7 +2430,7 @@ static int vertex_group_mesh_poll(bContext *C)
ob->defbase.first);
}
-static int vertex_group_mesh_supported_poll(bContext *C)
+static int UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
@@ -3170,16 +2450,43 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
}
/* editmode _or_ weight paint vertex sel */
-static int vertex_group_vert_select_poll(bContext *C)
+static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_flag)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
if (!(ob && !ob->id.lib && data && !data->lib))
- return 0;
+ return false;
- return (BKE_object_is_in_editmode_vgroup(ob) ||
- BKE_object_is_in_wpaint_select_vert(ob));
+ if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) {
+ return false;
+ }
+
+ if (BKE_object_is_in_editmode_vgroup(ob)) {
+ return true;
+ }
+ else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ if (BKE_object_is_in_wpaint_select_vert(ob)) {
+ return true;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+}
+
+static int vertex_group_vert_select_poll(bContext *C)
+{
+ return vertex_group_vert_select_poll_ex(C, 0);
+}
+
+static int vertex_group_mesh_vert_select_poll(bContext *C)
+{
+ return vertex_group_vert_select_poll_ex(C, (1 << OB_MESH));
}
/* editmode _or_ weight paint vertex sel and active group unlocked */
@@ -3226,7 +2533,7 @@ static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
- ED_vgroup_add(ob);
+ BKE_object_defgroup_add(ob);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -3254,9 +2561,9 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
if (RNA_boolean_get(op->ptr, "all"))
- vgroup_delete_all(ob);
+ BKE_object_defgroup_remove_all(ob);
else
- vgroup_delete(ob);
+ vgroup_delete_active(ob);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data);
@@ -3321,7 +2628,7 @@ static int vertex_group_assign_new_exec(bContext *C, wmOperator *op)
{
/* create new group... */
Object *ob = ED_object_context(C);
- ED_vgroup_add(ob);
+ BKE_object_defgroup_add(ob);
/* assign selection to new group */
return vertex_group_assign_exec(C, op);
@@ -3353,14 +2660,14 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
if (use_all_groups) {
- if (vgroup_remove_verts(ob, 0) == false) {
+ if (BKE_object_defgroup_clear_all(ob, true) == false) {
return OPERATOR_CANCELLED;
}
}
else {
bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1);
- if ((dg == NULL) || (vgroup_active_remove_verts(ob, use_all_verts, dg) == false)) {
+ if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) {
return OPERATOR_CANCELLED;
}
}
@@ -3486,7 +2793,7 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain);
MEM_freeN((void *)vgroup_validmap);
@@ -3552,7 +2859,7 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, subset_count, lock_active);
MEM_freeN((void *)vgroup_validmap);
@@ -3674,7 +2981,7 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove);
MEM_freeN((void *)vgroup_validmap);
@@ -3706,17 +3013,19 @@ void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
"Remove verts from groups that have zero weight after inverting");
}
-
-static int vertex_group_blend_exec(bContext *C, wmOperator *op)
+static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- float fac = RNA_float_get(op->ptr, "factor");
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const int repeat = RNA_int_get(op->ptr, "repeat");
eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
+ const int source = RNA_enum_get(op->ptr, "source");
+ const float fac_expand = RNA_float_get(op->ptr, "expand");
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
- vgroup_blend_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand, source);
MEM_freeN((void *)vgroup_validmap);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -3726,60 +3035,34 @@ static int vertex_group_blend_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* check we have a vertex selection, either in weight paint or editmode */
-static int vertex_group_blend_poll(bContext *C)
+void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot)
{
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
-
- if (!(ob && !ob->id.lib && data && !data->lib))
- return false;
-
- if (ob->type != OB_MESH) {
- return false;
- }
-
- if (BKE_object_is_in_editmode_vgroup(ob)) {
- return true;
- }
- else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- if (ME_EDIT_PAINT_SEL_MODE(((Mesh *)data)) == SCE_SELECT_VERTEX) {
- return true;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
- return false;
- }
-
- }
- else {
- return false;
- }
-}
-
-void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
-{
- PropertyRNA *prop;
+ static EnumPropertyItem smooth_source_item[] = {
+ {WEIGHT_SMOOTH_ALL, "ALL", 0, "All", ""},
+ {WEIGHT_SMOOTH_SELECT, "SELECT", 0, "Only Selected", ""},
+ {WEIGHT_SMOOTH_DESELECT, "DESELECT", 0, "Only Deselected", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
/* identifiers */
- ot->name = "Blend Vertex Group";
- ot->idname = "OBJECT_OT_vertex_group_blend";
- ot->description = "Blend selected vertex weights with unselected for the active group";
+ ot->name = "Smooth Vertex Weights";
+ ot->idname = "OBJECT_OT_vertex_group_smooth";
+ ot->description = "Smooth weights for selected vertices";
/* api callbacks */
- ot->poll = vertex_group_blend_poll;
- ot->exec = vertex_group_blend_exec;
+ ot->poll = vertex_group_mesh_vert_select_poll;
+ ot->exec = vertex_group_smooth_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
vgroup_operator_subset_select_props(ot, true);
- prop = RNA_def_property(ot->srna, "factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_ui_text(prop, "Factor", "");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 1.0f);
-}
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
+ RNA_def_float(ot->srna, "expand", 0.0f, -1.0f, 1.0, "Expand/Contract", "Expand/contract weights", -1.0f, 1.0f);
+ RNA_def_enum(ot->srna, "source", smooth_source_item, -1, "Source", "Vertices to mix with");
+}
static int vertex_group_clean_exec(bContext *C, wmOperator *op)
{
@@ -3791,7 +3074,7 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single);
MEM_freeN((void *)vgroup_validmap);
@@ -3832,7 +3115,7 @@ static int vertex_group_quantize_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps);
MEM_freeN((void *)vgroup_validmap);
@@ -3870,7 +3153,7 @@ static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
int subset_count, vgroup_tot;
- const bool *vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
int remove_tot = vgroup_limit_total_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit);
MEM_freeN((void *)vgroup_validmap);
@@ -3934,7 +3217,7 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
/* identifiers */
ot->name = "Mirror Vertex Group";
ot->idname = "OBJECT_OT_vertex_group_mirror";
- ot->description = "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, "
+ ot->description = "Mirror vertex group, flip weights and/or names, editing only selected vertices, "
"flipping when both sides are selected otherwise copy from unselected";
/* api callbacks */
@@ -3983,7 +3266,7 @@ void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
/* identifiers */
ot->name = "Copy Vertex Groups to Linked";
ot->idname = "OBJECT_OT_vertex_group_copy_to_linked";
- ot->description = "Copy vertex groups to all users of the same geometry data";
+ ot->description = "Replace vertex groups of all users of the same geometry data by vertex groups of active object";
/* api callbacks */
ot->poll = vertex_group_poll;
@@ -4022,7 +3305,7 @@ void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
/* identifiers */
ot->name = "Copy Vertex Group to Selected";
ot->idname = "OBJECT_OT_vertex_group_copy_to_selected";
- ot->description = "Copy vertex groups to other selected objects with matching indices";
+ ot->description = "Replace vertex groups of selected objects by vertex groups of active object";
/* api callbacks */
ot->poll = vertex_group_poll;
@@ -4032,143 +3315,6 @@ void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob_act = CTX_data_active_object(C);
-
- bDeformGroup *dg_act = BLI_findlink(&ob_act->defbase, (ob_act->actdef - 1));
- char dg_act_name[MAX_VGROUP_NAME]; /* may be freed so copy */
-
- int fail = 0;
- bool changed = false;
-
- WT_VertexGroupMode vertex_group_mode = RNA_enum_get(op->ptr, "group_select_mode");
- WT_Method method = RNA_enum_get(op->ptr, "method");
- WT_ReplaceMode replace_mode = RNA_enum_get(op->ptr, "replace_mode");
-
- if (vertex_group_mode == WT_REPLACE_ACTIVE_VERTEX_GROUP) {
- if (!dg_act) {
- BKE_report(op->reports, RPT_WARNING, "Failed, active object has no active groups");
- return OPERATOR_FINISHED; /* to get the chance to make changes in the redo panel*/
- }
- }
-
- if (dg_act) {
- BLI_strncpy(dg_act_name, dg_act->name, sizeof(dg_act_name));
- }
-
- /* Macro to loop through selected objects and perform operation depending on function, option and method.*/
- CTX_DATA_BEGIN (C, Object *, ob_src, selected_editable_objects)
- {
- if (ob_act != ob_src) {
-
- if (BLI_listbase_is_empty(&ob_src->defbase)) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Skipping object '%s' it has no vertex groups", ob_src->id.name + 2);
- continue;
- }
- else if (ob_src->type != OB_MESH) {
- /* armatures can be in pose mode so ignore them */
- if (ob_src->type != OB_ARMATURE) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Skipping object '%s' only copying from meshes is supported", ob_src->id.name + 2);
- }
- continue;
- }
-
- switch (vertex_group_mode) {
-
- case WT_REPLACE_ACTIVE_VERTEX_GROUP:
- {
- bDeformGroup *dg_src;
- dg_src = defgroup_find_name(ob_src, dg_act_name);
-
- if (dg_src == NULL) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Skipping object '%s' no group '%s' found", ob_src->id.name + 2, dg_act_name);
- continue;
- }
-
- if (ed_vgroup_transfer_weight(ob_act, ob_src, dg_src, scene, method, replace_mode, op)) {
- changed = true;
- }
- else {
- fail++;
- }
- break;
- }
- case WT_REPLACE_ALL_VERTEX_GROUPS:
- {
- bDeformGroup *dg_src;
- for (dg_src = ob_src->defbase.first; dg_src; dg_src = dg_src->next) {
- if (ed_vgroup_transfer_weight(ob_act, ob_src, dg_src, scene, method, replace_mode, op)) {
- changed = true;
- }
- else {
- fail++;
- }
- }
- break;
- }
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- CTX_DATA_END;
-
- if (changed) {
-
- /* possible the active vertex group changed because of adding/removing */
- /* note!, dg_act may be realloc'd, only check its not NULL */
- if (dg_act) {
- ED_vgroup_select_by_name(ob_act, dg_act_name);
- }
- else {
- ED_vgroup_sync_from_pose(ob_act);
- }
-
- /* Event notifiers for correct display of data.*/
-
-
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_act); /* for buttons */
- WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_act);
- return OPERATOR_FINISHED;
- }
- else {
- if (BLI_listbase_is_empty(&op->reports->list)) {
- BKE_report(op->reports, RPT_WARNING, "Failed, no other selected objects with vertex groups found");
- }
-
- return OPERATOR_FINISHED; /* to get the chance to make changes in the redo panel */
- }
-}
-
-/* transfers weight from active to selected */
-void OBJECT_OT_vertex_group_transfer_weight(wmOperatorType *ot)
-{
- /* Identifiers.*/
- ot->name = "Transfer Weights";
- ot->idname = "OBJECT_OT_vertex_group_transfer_weight";
- ot->description = "Transfer weight paint to active from selected mesh";
-
- /* API callbacks.*/
- ot->poll = vertex_group_mesh_supported_poll;
- ot->exec = vertex_group_transfer_weight_exec;
-
- /* Flags.*/
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* Properties.*/
- /* TODO, use vgroup_operator_subset_select_props for group_select_mode */
- ot->prop = RNA_def_enum(ot->srna, "group_select_mode", WT_vertex_group_mode_item, WT_REPLACE_ALL_VERTEX_GROUPS, "Group", "");
- ot->prop = RNA_def_enum(ot->srna, "method", WT_method_item, WT_BY_NEAREST_FACE, "Method", "");
- ot->prop = RNA_def_enum(ot->srna, "replace_mode", WT_replace_mode_item, WT_REPLACE_ALL_WEIGHTS, "Replace", "");
-}
-
static int set_active_group_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
@@ -4237,7 +3383,7 @@ void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
static char *vgroup_init_remap(Object *ob)
{
bDeformGroup *def;
- int defbase_tot = BLI_countlist(&ob->defbase);
+ int defbase_tot = BLI_listbase_count(&ob->defbase);
char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups");
char *name;
@@ -4254,7 +3400,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
{
MDeformVert *dvert = NULL;
bDeformGroup *def;
- int defbase_tot = BLI_countlist(&ob->defbase);
+ int defbase_tot = BLI_listbase_count(&ob->defbase);
/* needs a dummy index at the start*/
int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups");
@@ -4297,7 +3443,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
else {
int dvert_tot = 0;
- ED_vgroup_array_get(ob->data, &dvert, &dvert_tot);
+ BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot);
/*create as necessary*/
if (dvert) {
@@ -4314,7 +3460,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
sort_map[i]++;
sort_map_update[0] = 0;
- vgroup_remap_update_users(ob, sort_map_update);
+ BKE_object_defgroup_remap_update_users(ob, sort_map_update);
BLI_assert(sort_map_update[ob->actdef] >= 0);
ob->actdef = sort_map_update[ob->actdef];
@@ -4378,7 +3524,7 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op)
/*sort vgroup names*/
switch (sort_type) {
case SORT_TYPE_NAME:
- BLI_sortlist(&ob->defbase, vgroup_sort_name);
+ BLI_listbase_sort(&ob->defbase, vgroup_sort_name);
break;
case SORT_TYPE_BONEHIERARCHY:
vgroup_sort_bone_hierarchy(ob, NULL);
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 8016dabf3a3..9f4da87903d 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -31,7 +31,6 @@
#include "BLI_math.h"
-#include "BKE_utildefines.h"
#include "BKE_context.h"
#include "RNA_access.h"
@@ -276,14 +275,14 @@ static int object_warp_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_vertex_warp(struct wmOperatorType *ot)
+void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Warp";
ot->description = "Warp vertices around the cursor";
- ot->idname = "OBJECT_OT_vertex_warp";
+ ot->idname = "TRANSFORM_OT_vertex_warp";
/* api callbacks */
ot->exec = object_warp_verts_exec;
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 892d71befb4..898422dac51 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -20,14 +20,16 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/elbeem/extern
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,4 +66,6 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_physics "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript
index 9436280de43..be399a58732 100644
--- a/source/blender/editors/physics/SConscript
+++ b/source/blender/editors/physics/SConscript
@@ -31,13 +31,15 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/rigidbody',
- '#/extern/glew/include',
'#/intern/elbeem/extern',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
@@ -45,6 +47,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 637af5d6536..93daa15e608 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -30,7 +30,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_modifier_types.h"
@@ -40,6 +40,7 @@
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_object_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
@@ -235,11 +236,11 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
/* Vertex Weight Layer */
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
if (!exists) {
- ED_vgroup_add_name(ob, name);
+ BKE_object_defgroup_add_name(ob, name);
}
else {
bDeformGroup *defgroup = defgroup_find_name(ob, name);
- if (defgroup) ED_vgroup_delete(ob, defgroup);
+ if (defgroup) BKE_object_defgroup_remove(ob, defgroup);
}
}
}
@@ -395,13 +396,8 @@ static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
/* Bake was successful:
* Report for ended bake and how long it took */
if (status) {
- /* Format time string */
- char time_str[30];
- double time = PIL_check_seconds_timer() - timer;
- BLI_timestr(time, time_str, sizeof(time_str));
-
/* Show bake info */
- BKE_reportf(op->reports, RPT_INFO, "Bake complete! (%s)", time_str);
+ BKE_reportf(op->reports, RPT_INFO, "Bake complete! (%.2f)", PIL_check_seconds_timer() - timer);
}
else {
if (strlen(canvas->error)) { /* If an error occurred */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 76344b77dd3..892545a8efd 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -61,7 +61,7 @@
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_report.h"
-
+#include "BKE_bvhutils.h"
#include "BKE_pointcache.h"
#include "BIF_gl.h"
@@ -83,9 +83,11 @@
#include "physics_intern.h"
-static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
-static void PTCacheUndo_clear(PTCacheEdit *edit);
-static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
+void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
+void PTCacheUndo_clear(PTCacheEdit *edit);
+void recalc_lengths(PTCacheEdit *edit);
+void recalc_emitter_field(Object *ob, ParticleSystem *psys);
+void update_world_cos(Object *ob, PTCacheEdit *edit);
#define KEY_K PTCacheEditKey *key; int k
#define POINT_P PTCacheEditPoint *point; int p
@@ -355,6 +357,7 @@ typedef struct PEData {
Object *ob;
DerivedMesh *dm;
PTCacheEdit *edit;
+ BVHTreeFromMesh shape_bvh;
const int *mval;
rcti *rect;
@@ -397,12 +400,12 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
/* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */
view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
- if ((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) {
+ if (V3D_IS_ZBUF(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- view3d_validate_backbuf(&data->vc);
+ ED_view3d_backbuf_validate(&data->vc);
/* we may need to force an update here by setting the rv3d as dirty
* for now it seems ok, but take care!:
* rv3d->depths->dirty = 1; */
@@ -411,6 +414,25 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
}
}
+static bool PE_create_shape_tree(PEData *data, Object *shapeob)
+{
+ DerivedMesh *dm = shapeob->derivedFinal;
+
+ memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
+
+ if (!dm) {
+ return false;
+ }
+
+ DM_ensure_looptri(dm);
+ return (bvhtree_from_mesh_looptri(&data->shape_bvh, dm, 0.0f, 4, 8) != NULL);
+}
+
+static void PE_free_shape_tree(PEData *data)
+{
+ free_bvhtree_from_mesh(&data->shape_bvh);
+}
+
/*************************** selection utilities *******************************/
static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2])
@@ -421,8 +443,8 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[
float depth;
/* nothing to do */
- if ((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
- return 1;
+ if (!V3D_IS_ZBUF(v3d))
+ return true;
/* used to calculate here but all callers have the screen_co already, so pass as arg */
#if 0
@@ -1055,7 +1077,7 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
}
}
/* set current distances to be kept between neighbouting keys */
-static void recalc_lengths(PTCacheEdit *edit)
+void recalc_lengths(PTCacheEdit *edit)
{
POINT_P; KEY_K;
@@ -1071,7 +1093,7 @@ static void recalc_lengths(PTCacheEdit *edit)
}
/* calculate a tree for finding nearest emitter's vertice */
-static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
+void recalc_emitter_field(Object *ob, ParticleSystem *psys)
{
DerivedMesh *dm=psys_get_modifier(ob, psys)->dm;
PTCacheEdit *edit= psys->edit;
@@ -1159,7 +1181,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag)
point->flag &= ~PEP_EDIT_RECALC;
}
-static void update_world_cos(Object *ob, PTCacheEdit *edit)
+void update_world_cos(Object *ob, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
@@ -1588,6 +1610,87 @@ void PARTICLE_OT_select_tips(wmOperatorType *ot)
WM_operator_properties_select_action(ot, SEL_SELECT);
}
+/*********************** select random operator ************************/
+
+enum { RAN_HAIR, RAN_POINTS };
+
+static EnumPropertyItem select_random_type_items[] = {
+ {RAN_HAIR, "HAIR", 0, "Hair", ""},
+ {RAN_POINTS, "POINTS", 0, "Points", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int select_random_exec(bContext *C, wmOperator *op)
+{
+ PEData data;
+ int type;
+ Scene *scene;
+ Object *ob;
+
+ /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
+ PTCacheEdit *edit;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ int p;
+ int k;
+
+ const float randf = RNA_float_get (op->ptr, "percent") / 100.0f;
+
+ type = RNA_enum_get(op->ptr, "type");
+
+ PE_set_data(C, &data);
+ data.select_action = SEL_SELECT;
+ scene = CTX_data_scene(C);
+ ob = CTX_data_active_object(C);
+ edit = PE_get_current(scene, ob);
+
+ switch (type) {
+ case RAN_HAIR:
+ LOOP_VISIBLE_POINTS {
+ int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT;
+ LOOP_KEYS {
+ select_action_apply (point, key, flag);
+ }
+ }
+ break;
+ case RAN_POINTS:
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
+ int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT;
+ select_action_apply (point, key, flag);
+ }
+ }
+ break;
+ }
+
+ PE_update_selection(data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_select_random(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Random";
+ ot->idname = "PARTICLE_OT_select_random";
+ ot->description = "Select a randomly distributed set of hair or points";
+
+ /* api callbacks */
+ ot->exec = select_random_exec;
+ ot->poll = PE_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float_percentage (ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent",
+ "Percentage (mean) of elements in randomly selected set",
+ 0.0f, 100.0f);
+ ot->prop = RNA_def_enum (ot->srna, "type", select_random_type_items, RAN_HAIR,
+ "Type", "Select either hair or points");
+}
+
/************************ select linked operator ************************/
static int select_linked_exec(bContext *C, wmOperator *op)
@@ -3148,7 +3251,7 @@ static void brush_puff(PEData *data, int point_index)
static void BKE_brush_weight_get(PEData *data, float UNUSED(mat[4][4]), float UNUSED(imat[4][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key))
{
- /* roots have full weight allways */
+ /* roots have full weight always */
if (key_index) {
PTCacheEdit *edit = data->edit;
ParticleSystem *psys = edit->psys;
@@ -3382,7 +3485,7 @@ static int brush_add(PEData *data, short number)
if (psmd->dm->deformedOnly || psys->part->use_modifier_stack)
dm = psmd->dm;
else {
- dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
release_dm = true;
}
@@ -3951,6 +4054,184 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot)
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
+/*********************** cut shape ***************************/
+
+static int shape_cut_poll(bContext *C)
+{
+ if (PE_hair_poll(C)) {
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+
+ if (pset->shape_object && (pset->shape_object->type == OB_MESH)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+typedef struct PointInsideBVH {
+ BVHTreeFromMesh bvhdata;
+ int num_hits;
+} PointInsideBVH;
+
+static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ PointInsideBVH *data = userdata;
+
+ data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
+
+ if (hit->index != -1)
+ ++data->num_hits;
+}
+
+/* true if the point is inside the shape mesh */
+static bool shape_cut_test_point(PEData *data, ParticleCacheKey *key)
+{
+ BVHTreeFromMesh *shape_bvh = &data->shape_bvh;
+ const float dir[3] = {1.0f, 0.0f, 0.0f};
+ PointInsideBVH userdata;
+
+ userdata.bvhdata = data->shape_bvh;
+ userdata.num_hits = 0;
+
+ BLI_bvhtree_ray_cast_all(shape_bvh->tree, key->co, dir, 0.0f, point_inside_bvh_cb, &userdata);
+
+ /* for any point inside a watertight mesh the number of hits is uneven */
+ return (userdata.num_hits % 2) == 1;
+}
+
+static void shape_cut(PEData *data, int pa_index)
+{
+ PTCacheEdit *edit = data->edit;
+ Object *ob = data->ob;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ ParticleCacheKey *key;
+
+ bool cut;
+ float cut_time = 1.0;
+ int k, totkeys = 1 << pset->draw_step;
+
+ /* don't cut hidden */
+ if (edit->points[pa_index].flag & PEP_HIDE)
+ return;
+
+ cut = false;
+
+ /* check if root is inside the cut shape */
+ key = edit->pathcache[pa_index];
+ if (!shape_cut_test_point(data, key)) {
+ cut_time = -1.0f;
+ cut = true;
+ }
+ else {
+ for (k = 0; k < totkeys; k++, key++) {
+ BVHTreeRayHit hit;
+ float dir[3];
+ float len;
+
+ sub_v3_v3v3(dir, (key+1)->co, key->co);
+ len = normalize_v3(dir);
+
+ memset(&hit, 0, sizeof(hit));
+ hit.index = -1;
+ hit.dist = len;
+ BLI_bvhtree_ray_cast(data->shape_bvh.tree, key->co, dir, 0.0f, &hit, data->shape_bvh.raycast_callback, &data->shape_bvh);
+ if (hit.index >= 0) {
+ if (hit.dist < len) {
+ cut_time = (hit.dist / len + (float)k) / (float)totkeys;
+ cut = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (cut) {
+ if (cut_time < 0.0f) {
+ edit->points[pa_index].flag |= PEP_TAG;
+ }
+ else {
+ rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
+ edit->points[pa_index].flag |= PEP_EDIT_RECALC;
+ }
+ }
+}
+
+static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ Object *shapeob = pset->shape_object;
+ int selected = count_selected_keys(scene, edit);
+ int lock_root = pset->flag & PE_LOCK_FIRST;
+
+ if (!PE_start_edit(edit))
+ return OPERATOR_CANCELLED;
+
+ /* disable locking temporatily for disconnected hair */
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ pset->flag &= ~PE_LOCK_FIRST;
+
+ if (edit->psys && edit->pathcache) {
+ PEData data;
+ int removed;
+
+ PE_set_data(C, &data);
+ if (!PE_create_shape_tree(&data, shapeob)) {
+ /* shapeob may not have faces... */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (selected)
+ foreach_selected_point(&data, shape_cut);
+ else
+ foreach_point(&data, shape_cut);
+
+ removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
+ recalc_lengths(edit);
+
+ if (removed) {
+ update_world_cos(ob, edit);
+ psys_free_path_cache(NULL, edit);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else
+ PE_update_object(scene, ob, 1);
+
+ if (edit->psys) {
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+ }
+ else {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+ }
+
+ PE_free_shape_tree(&data);
+ }
+
+ pset->flag |= lock_root;
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_shape_cut(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Shape Cut";
+ ot->idname = "PARTICLE_OT_shape_cut";
+ ot->description = "Cut hair to conform to the set shape object";
+
+ /* api callbacks */
+ ot->exec = shape_cut_exec;
+ ot->poll = shape_cut_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
/*********************** undo ***************************/
static void free_PTCacheUndo(PTCacheUndo *undo)
@@ -4168,7 +4449,7 @@ void PE_undo_step(Scene *scene, int step)
DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
}
-int PE_undo_valid(Scene *scene)
+bool PE_undo_is_valid(Scene *scene)
{
PTCacheEdit *edit= PE_get_current(scene, OBACT);
@@ -4178,7 +4459,7 @@ int PE_undo_valid(Scene *scene)
return 0;
}
-static void PTCacheUndo_clear(PTCacheEdit *edit)
+void PTCacheUndo_clear(PTCacheEdit *edit)
{
PTCacheUndo *undo;
@@ -4219,18 +4500,19 @@ void PE_undo_number(Scene *scene, int nr)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *PE_undo_get_name(Scene *scene, int nr, int *active)
+const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active)
{
PTCacheEdit *edit= PE_get_current(scene, OBACT);
PTCacheUndo *undo;
- if (active) *active= 0;
+ if (r_active) *r_active = false;
if (edit) {
undo= BLI_findlink(&edit->undo, nr);
if (undo) {
- if (active && undo==edit->curundo)
- *active= 1;
+ if (r_active && (undo == edit->curundo)) {
+ *r_active = true;
+ }
return undo->name;
}
}
@@ -4279,7 +4561,7 @@ int PE_minmax(Scene *scene, float min[3], float max[3])
/************************ particle edit toggle operator ************************/
/* initialize needed data for bake edit */
-static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
+void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
PTCacheEdit *edit;
ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 5a61f77e5a8..327ce060df9 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -40,18 +40,21 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -62,8 +65,37 @@
#include "ED_screen.h"
#include "ED_object.h"
+#include "UI_resources.h"
+
#include "physics_intern.h"
+extern void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
+extern void PTCacheUndo_clear(PTCacheEdit *edit);
+extern void recalc_lengths(PTCacheEdit *edit);
+extern void recalc_emitter_field(Object *ob, ParticleSystem *psys);
+extern void update_world_cos(Object *ob, PTCacheEdit *edit);
+
+#define KEY_K PTCacheEditKey *key; int k
+#define POINT_P PTCacheEditPoint *point; int p
+#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
+#if 0
+#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
+#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
+#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
+#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
+#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
+#endif
+#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
+#if 0
+#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
+#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
+#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
+
+#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
+#endif
+
+static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}};
+
/********************** particle system slot operators *********************/
static int particle_system_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -623,38 +655,50 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
}
-static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+/* from/to_world_space : whether from/to particles are in world or hair space
+ * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
+ */
+static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
+ Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
+ float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleData *pa;
- PTCacheEdit *edit;
- PTCacheEditPoint *point;
- PTCacheEditKey *ekey = NULL;
- HairKey *key;
+ ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
+ ParticleData *pa, *tpa;
+ PTCacheEditPoint *edit_point;
+ PTCacheEditKey *ekey;
BVHTreeFromMesh bvhtree= {NULL};
- BVHTreeNearest nearest;
MFace *mface = NULL, *mf;
MEdge *medge = NULL, *me;
MVert *mvert;
- DerivedMesh *dm = NULL;
+ DerivedMesh *dm, *target_dm;
int numverts;
int i, k;
- float hairmat[4][4], imat[4][4];
- float v[4][3], vec[3];
+ float from_ob_imat[4][4], to_ob_imat[4][4];
+ float from_imat[4][4], to_imat[4][4];
- if (!psys || !psys->part || psys->part->type != PART_HAIR || !psmd->dm)
+ if (!target_psmd->dm)
+ return false;
+ if (!psys->part || psys->part->type != PART_HAIR)
return false;
+ if (!target_psys->part || target_psys->part->type != PART_HAIR)
+ return false;
+
+ edit_point = target_edit ? target_edit->points : NULL;
- edit= psys->edit;
- point= edit ? edit->points : NULL;
+ invert_m4_m4(from_ob_imat, ob->obmat);
+ invert_m4_m4(to_ob_imat, target_ob->obmat);
+ invert_m4_m4(from_imat, from_mat);
+ invert_m4_m4(to_imat, to_mat);
- if (psmd->dm->deformedOnly) {
- /* we don't want to mess up psmd->dm when converting to global coordinates below */
- dm = psmd->dm;
+ if (target_psmd->dm->deformedOnly) {
+ /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
+ dm = target_psmd->dm;
}
else {
- dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ /* warning: this rebuilds target_psmd->dm! */
+ dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
}
+ target_dm = target_psmd->dm;
/* don't modify the original vertices */
dm = CDDM_copy(dm);
@@ -662,12 +706,11 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
DM_ensure_tessface(dm);
numverts = dm->getNumVerts(dm);
-
mvert = dm->getVertArray(dm);
/* convert to global coordinates */
for (i=0; i<numverts; i++)
- mul_m4_v3(ob->obmat, mvert[i].co);
+ mul_m4_v3(to_mat, mvert[i].co);
if (dm->getNumTessFaces(dm) != 0) {
mface = dm->getTessFaceArray(dm);
@@ -682,13 +725,23 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
return false;
}
- for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) {
- key = pa->hair;
+ for (i = 0, tpa = target_psys->particles, pa = psys->particles;
+ i < target_psys->totpart;
+ i++, tpa++, pa++) {
+
+ float from_co[3];
+ BVHTreeNearest nearest;
+
+ if (from_global)
+ mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
+ else
+ mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
+ mul_m4_v3(from_mat, from_co);
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);
+ BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index == -1) {
if (G.debug & G_DEBUG)
@@ -697,6 +750,8 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
}
if (mface) {
+ float v[4][3];
+
mf = &mface[nearest.index];
copy_v3_v3(v[0], mvert[mf->v1].co);
@@ -704,44 +759,80 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
copy_v3_v3(v[2], mvert[mf->v3].co);
if (mf->v4) {
copy_v3_v3(v[3], mvert[mf->v4].co);
- interp_weights_poly_v3(pa->fuv, v, 4, nearest.co);
+ interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
}
else
- interp_weights_poly_v3(pa->fuv, v, 3, nearest.co);
+ interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
+ tpa->foffset = 0.0f;
- pa->num = nearest.index;
- pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL);
+ tpa->num = nearest.index;
+ tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL);
}
else {
me = &medge[nearest.index];
- pa->fuv[1] = line_point_factor_v3(nearest.co,
- mvert[me->v2].co,
- mvert[me->v2].co);
- pa->fuv[0] = 1.0f - pa->fuv[1];
- pa->fuv[2] = pa->fuv[3] = 0.0f;
+ tpa->fuv[1] = line_point_factor_v3(nearest.co,
+ mvert[me->v1].co,
+ mvert[me->v2].co);
+ tpa->fuv[0] = 1.0f - tpa->fuv[1];
+ tpa->fuv[2] = tpa->fuv[3] = 0.0f;
+ tpa->foffset = 0.0f;
- pa->num = nearest.index;
- pa->num_dmcache = -1;
+ tpa->num = nearest.index;
+ tpa->num_dmcache = -1;
}
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
- invert_m4_m4(imat, hairmat);
-
- sub_v3_v3v3(vec, nearest.co, key->co);
-
- if (point) {
- ekey = point->keys;
- point++;
- }
-
- for (k=0, key=pa->hair; k<pa->totkey; k++, key++) {
- add_v3_v3(key->co, vec);
- mul_m4_v3(imat, key->co);
-
- if (ekey) {
- ekey->flag |= PEK_USE_WCO;
- ekey++;
+ /* translate hair keys */
+ {
+ HairKey *key, *tkey;
+ float hairmat[4][4], imat[4][4];
+ float offset[3];
+
+ if (to_global)
+ copy_m4_m4(imat, target_ob->obmat);
+ else {
+ /* note: using target_dm here, which is in target_ob object space and has full modifiers */
+ psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
+ invert_m4_m4(imat, hairmat);
+ }
+ mul_m4_m4m4(imat, imat, to_imat);
+
+ /* offset in world space */
+ sub_v3_v3v3(offset, nearest.co, from_co);
+
+ if (edit_point) {
+ for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) {
+ float co_orig[3];
+
+ if (from_global)
+ mul_v3_m4v3(co_orig, from_ob_imat, key->co);
+ else
+ mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
+ mul_m4_v3(from_mat, co_orig);
+
+ add_v3_v3v3(tkey->co, co_orig, offset);
+
+ mul_m4_v3(imat, tkey->co);
+
+ ekey->flag |= PEK_USE_WCO;
+ }
+
+ edit_point++;
+ }
+ else {
+ for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
+ float co_orig[3];
+
+ if (from_global)
+ mul_v3_m4v3(co_orig, from_ob_imat, key->co);
+ else
+ mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
+ mul_m4_v3(from_mat, co_orig);
+
+ add_v3_v3v3(tkey->co, co_orig, offset);
+
+ mul_m4_v3(imat, tkey->co);
+ }
}
}
}
@@ -749,15 +840,26 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
free_bvhtree_from_mesh(&bvhtree);
dm->release(dm);
- psys_free_path_cache(psys, psys->edit);
+ psys_free_path_cache(target_psys, target_edit);
- psys->flag &= ~PSYS_GLOBAL_HAIR;
-
- PE_update_object(scene, ob, 0);
+ PE_update_object(scene, target_ob, 0);
return true;
}
+static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+{
+ bool ok;
+
+ if (!psys)
+ return false;
+
+ ok = remap_hair_emitter(scene, ob, psys, ob, psys, psys->edit, ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+
+ return ok;
+}
+
static int connect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
@@ -805,3 +907,284 @@ void PARTICLE_OT_connect_hair(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
}
+/************************ particle system copy operator *********************/
+
+typedef enum eCopyParticlesSpace {
+ PAR_COPY_SPACE_OBJECT = 0,
+ PAR_COPY_SPACE_WORLD = 1,
+} eCopyParticlesSpace;
+
+static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
+{
+ PTCacheEdit *edit_from = psys_from->edit, *edit;
+ ParticleData *pa;
+ KEY_K;
+ POINT_P;
+
+ if (!edit_from)
+ return;
+
+ edit = MEM_dupallocN(edit_from);
+ edit->psys = psys;
+ psys->edit = edit;
+
+ edit->pathcache = NULL;
+ BLI_listbase_clear(&edit->pathcachebufs);
+
+ edit->emitter_field = NULL;
+ edit->emitter_cosnos = NULL;
+
+ BLI_listbase_clear(&edit->undo);
+ edit->curundo = NULL;
+
+ edit->points = MEM_dupallocN(edit_from->points);
+ pa = psys->particles;
+ LOOP_POINTS {
+ HairKey *hkey = pa->hair;
+
+ point->keys= MEM_dupallocN(point->keys);
+ LOOP_KEYS {
+ key->co = hkey->co;
+ key->time = &hkey->time;
+ key->flag = hkey->editflag;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
+ key->flag |= PEK_USE_WCO;
+ hkey->editflag |= PEK_USE_WCO;
+ }
+
+ hkey++;
+ }
+
+ pa++;
+ }
+ update_world_cos(ob, edit);
+
+ UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
+ UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
+
+ recalc_lengths(edit);
+ recalc_emitter_field(ob, psys);
+ PE_update_object(scene, ob, true);
+
+ PTCacheUndo_clear(edit);
+ PE_undo_push(scene, "Original");
+}
+
+static void remove_particle_systems_from_object(Object *ob_to)
+{
+ ModifierData *md, *md_next;
+
+ if (ob_to->type != OB_MESH)
+ return;
+ if (!ob_to->data || ((ID *)ob_to->data)->lib)
+ return;
+
+ for (md = ob_to->modifiers.first; md; md = md_next) {
+ md_next = md->next;
+
+ /* remove all particle system modifiers as well,
+ * these need to sync to the particle system list
+ */
+ if (ELEM(md->type, eModifierType_ParticleSystem, eModifierType_DynamicPaint, eModifierType_Smoke)) {
+ BLI_remlink(&ob_to->modifiers, md);
+ modifier_free(md);
+ }
+ }
+
+ BKE_object_free_particlesystems(ob_to);
+}
+
+/* single_psys_from is optional, if NULL all psys of ob_from are copied */
+static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space)
+{
+ ModifierData *md;
+ ParticleSystem *psys_start = NULL, *psys, *psys_from;
+ ParticleSystem **tmp_psys;
+ DerivedMesh *final_dm;
+ CustomDataMask cdmask;
+ int i, totpsys;
+
+ if (ob_to->type != OB_MESH)
+ return false;
+ if (!ob_to->data || ((ID *)ob_to->data)->lib)
+ return false;
+
+ /* For remapping we need a valid DM.
+ * Because the modifiers are appended at the end it's safe to use
+ * the final DM of the object without particles.
+ * However, when evaluating the DM all the particle modifiers must be valid,
+ * i.e. have the psys assigned already.
+ * To break this hen/egg problem we create all psys separately first (to collect required customdata masks),
+ * then create the DM, then add them to the object and make the psys modifiers ...
+ */
+ #define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first)
+ #define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next)
+ totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
+
+ tmp_psys = MEM_mallocN(sizeof(ParticleSystem*) * totpsys, "temporary particle system array");
+
+ cdmask = 0;
+ for (psys_from = PSYS_FROM_FIRST, i = 0;
+ psys_from;
+ psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+
+ psys = BKE_object_copy_particlesystem(psys_from);
+ tmp_psys[i] = psys;
+
+ if (psys_start == NULL)
+ psys_start = psys;
+
+ cdmask |= psys_emitter_customdata_mask(psys);
+ }
+ /* to iterate source and target psys in sync,
+ * we need to know where the newly added psys start
+ */
+ psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
+
+ /* get the DM (psys and their modifiers have not been appended yet) */
+ final_dm = mesh_get_derived_final(scene, ob_to, cdmask);
+
+ /* now append psys to the object and make modifiers */
+ for (i = 0, psys_from = PSYS_FROM_FIRST;
+ i < totpsys;
+ ++i, psys_from = PSYS_FROM_NEXT(psys_from)) {
+
+ ParticleSystemModifierData *psmd;
+
+ psys = tmp_psys[i];
+
+ /* append to the object */
+ BLI_addtail(&ob_to->particlesystem, psys);
+
+ /* add a particle system modifier for each system */
+ md = modifier_new(eModifierType_ParticleSystem);
+ psmd = (ParticleSystemModifierData *)md;
+ /* push on top of the stack, no use trying to reproduce old stack order */
+ BLI_addtail(&ob_to->modifiers, md);
+
+ BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
+ modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
+
+ psmd->psys = psys;
+ psmd->dm = CDDM_copy(final_dm);
+ CDDM_calc_normals(psmd->dm);
+ DM_ensure_tessface(psmd->dm);
+
+ if (psys_from->edit)
+ copy_particle_edit(scene, ob_to, psys, psys_from);
+ }
+ MEM_freeN(tmp_psys);
+
+ /* note: do this after creating DM copies for all the particle system modifiers,
+ * the remapping otherwise makes final_dm invalid!
+ */
+ for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0;
+ psys;
+ psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+
+ float (*from_mat)[4], (*to_mat)[4];
+
+ switch (space) {
+ case PAR_COPY_SPACE_OBJECT:
+ from_mat = I;
+ to_mat = I;
+ break;
+ case PAR_COPY_SPACE_WORLD:
+ from_mat = ob_from->obmat;
+ to_mat = ob_to->obmat;
+ break;
+ default:
+ /* should not happen */
+ BLI_assert(false);
+ break;
+ }
+
+ remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
+
+ /* tag for recalc */
+// psys->recalc |= PSYS_RECALC_RESET;
+ }
+
+ #undef PSYS_FROM_FIRST
+ #undef PSYS_FROM_NEXT
+
+ DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
+ return true;
+}
+
+static int copy_particle_systems_poll(bContext *C)
+{
+ Object *ob;
+ if (!ED_operator_object_active_editable(C))
+ return false;
+
+ ob = ED_object_active_context(C);
+ if (BLI_listbase_is_empty(&ob->particlesystem))
+ return false;
+
+ return true;
+}
+
+static int copy_particle_systems_exec(bContext *C, wmOperator *op)
+{
+ const int space = RNA_enum_get(op->ptr, "space");
+ const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
+ const bool use_active = RNA_boolean_get(op->ptr, "use_active");
+ Scene *scene = CTX_data_scene(C);
+ Object *ob_from = ED_object_active_context(C);
+ ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL;
+
+ int changed_tot = 0;
+ int fail = 0;
+
+ CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects)
+ {
+ if (ob_from != ob_to) {
+ bool changed = false;
+ if (remove_target_particles) {
+ remove_particle_systems_from_object(ob_to);
+ changed = true;
+ }
+ if (copy_particle_systems_to_object(scene, ob_from, psys_from, ob_to, space))
+ changed = true;
+ else
+ fail++;
+
+ if (changed)
+ changed_tot++;
+ }
+ }
+ CTX_DATA_END;
+
+ if ((changed_tot == 0 && fail == 0) || fail) {
+ BKE_reportf(op->reports, RPT_ERROR,
+ "Copy particle systems to selected: %d done, %d failed",
+ changed_tot, fail);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
+{
+ static EnumPropertyItem space_items[] = {
+ {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"},
+ {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ ot->name = "Copy Particle Systems";
+ ot->description = "Copy particle systems from the active object to selected objects";
+ ot->idname = "PARTICLE_OT_copy_particle_systems";
+
+ ot->poll = copy_particle_systems_poll;
+ ot->exec = copy_particle_systems_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "space", space_items, PAR_COPY_SPACE_OBJECT, "Space", "Space transform for copying from one object to another");
+ RNA_def_boolean(ot->srna, "remove_target_particles", true, "Remove Target Particles", "Remove particle systems on the target objects");
+ RNA_def_boolean(ot->srna, "use_active", false, "Use Active", "Use the active particle system from the context");
+}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index b53891f4880..b5adf38527b 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -72,8 +72,6 @@
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
-#include "PIL_time.h"
-
static float get_fluid_viscosity(FluidsimSettings *settings)
{
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 77ce5a334e6..666ed2397d2 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -39,6 +39,7 @@ struct wmOperatorType;
void PARTICLE_OT_select_all(struct wmOperatorType *ot);
void PARTICLE_OT_select_roots(struct wmOperatorType *ot);
void PARTICLE_OT_select_tips(struct wmOperatorType *ot);
+void PARTICLE_OT_select_random(struct wmOperatorType *ot);
void PARTICLE_OT_select_linked(struct wmOperatorType *ot);
void PARTICLE_OT_select_less(struct wmOperatorType *ot);
void PARTICLE_OT_select_more(struct wmOperatorType *ot);
@@ -55,6 +56,8 @@ void PARTICLE_OT_mirror(struct wmOperatorType *ot);
void PARTICLE_OT_brush_edit(struct wmOperatorType *ot);
+void PARTICLE_OT_shape_cut(struct wmOperatorType *ot);
+
void PARTICLE_OT_particle_edit_toggle(struct wmOperatorType *ot);
void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
@@ -69,6 +72,7 @@ void PARTICLE_OT_target_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
+void PARTICLE_OT_copy_particle_systems(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 48cc51ffb55..c765bff796e 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -29,10 +29,6 @@
#include <stdlib.h>
-#include "DNA_scene_types.h"
-
-#include "BLI_utildefines.h"
-
#include "RNA_access.h"
#include "WM_api.h"
@@ -51,6 +47,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_select_all);
WM_operatortype_append(PARTICLE_OT_select_roots);
WM_operatortype_append(PARTICLE_OT_select_tips);
+ WM_operatortype_append(PARTICLE_OT_select_random);
WM_operatortype_append(PARTICLE_OT_select_linked);
WM_operatortype_append(PARTICLE_OT_select_less);
WM_operatortype_append(PARTICLE_OT_select_more);
@@ -67,6 +64,8 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_brush_edit);
+ WM_operatortype_append(PARTICLE_OT_shape_cut);
+
WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
WM_operatortype_append(PARTICLE_OT_edited_clear);
@@ -81,6 +80,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_target_move_down);
WM_operatortype_append(PARTICLE_OT_connect_hair);
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
+ WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index dd0816e509d..85b059d5574 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -37,8 +37,6 @@
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 13a3d7a523f..949084973cf 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -33,24 +33,19 @@
#include <stdlib.h>
#include <string.h>
-#include "MEM_guardedalloc.h"
-#include "DNA_group_types.h"
#include "DNA_object_types.h"
-#include "DNA_mesh_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
-#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -353,6 +348,7 @@ static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
if (changed) {
/* send updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* done */
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c
index 1c893992cf2..0bd9ec5f4cd 100644
--- a/source/blender/editors/physics/rigidbody_world.c
+++ b/source/blender/editors/physics/rigidbody_world.c
@@ -37,8 +37,6 @@
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "BLI_math.h"
-
#ifdef WITH_BULLET
# include "RBI_api.h"
#endif
@@ -48,8 +46,6 @@
#include "BKE_rigidbody.h"
#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -171,7 +167,7 @@ static int rigidbody_world_export_exec(bContext *C, wmOperator *op)
static int rigidbody_world_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "relative_path"))
- RNA_boolean_set(op->ptr, "relative_path", (U.flag & USER_RELPATHS));
+ RNA_boolean_set(op->ptr, "relative_path", (U.flag & USER_RELPATHS) != 0);
if (RNA_struct_property_is_set(op->ptr, "filepath"))
return rigidbody_world_export_exec(C, op);
@@ -199,5 +195,5 @@ void RIGIDBODY_OT_world_export(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE, FILE_SPECIAL, FILE_SAVE, FILE_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_SPECIAL, FILE_SAVE, FILE_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 24015bd4ea3..971ab9f3458 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -20,10 +20,10 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
../../blenloader
+ ../../blentranslation
../../gpu
../../imbuf
../../bmesh
@@ -32,6 +32,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,6 +65,8 @@ if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_FREESTYLE)
list(APPEND INC
../../freestyle
diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript
index 41576f9b485..24270ca2324 100644
--- a/source/blender/editors/render/SConscript
+++ b/source/blender/editors/render/SConscript
@@ -31,13 +31,15 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/elbeem/extern',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../blenloader',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../imbuf',
@@ -49,6 +51,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index f9377d576bf..54429f9f066 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -32,9 +32,9 @@
#ifndef __RENDER_INTERN_H__
#define __RENDER_INTERN_H__
+struct bContext;
+struct RenderEngine;
struct wmOperatorType;
-struct RenderResult;
-struct Scene;
struct ScrArea;
/* render_shading.c */
@@ -44,6 +44,7 @@ void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_select(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_deselect(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_copy(struct wmOperatorType *ot);
+void OBJECT_OT_material_slot_move(struct wmOperatorType *ot);
void MATERIAL_OT_new(struct wmOperatorType *ot);
void TEXTURE_OT_new(struct wmOperatorType *ot);
@@ -55,6 +56,9 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
+void SCENE_OT_render_view_add(struct wmOperatorType *ot);
+void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
+
#ifdef WITH_FREESTYLE
void SCENE_OT_freestyle_module_add(struct wmOperatorType *ot);
void SCENE_OT_freestyle_module_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index baf25a49f7c..10de2d667ea 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -33,14 +33,16 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_timecode.h"
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "PIL_time.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -48,6 +50,7 @@
#include "DNA_userdef_types.h"
#include "BKE_blender.h"
+#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
@@ -75,10 +78,8 @@
#include "RE_engine.h"
#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "GPU_extensions.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -86,7 +87,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "wm_window.h"
#include "render_intern.h"
@@ -119,7 +119,7 @@ typedef struct RenderJob {
} RenderJob;
/* called inside thread! */
-static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect)
+static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect, const char *viewname)
{
Scene *scene = rj->scene;
const float *rectf = NULL;
@@ -191,11 +191,15 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
*/
/* TODO(sergey): Need to check has_combined here? */
if (iuser->pass == 0) {
+ RenderView *rv;
+ size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
+ rv = RE_RenderViewGetById(rr, view_id);
+
/* find current float rect for display, first case is after composite... still weak */
- if (rr->rectf)
- rectf = rr->rectf;
+ if (rv->rectf)
+ rectf = rv->rectf;
else {
- if (rr->rect32) {
+ if (rv->rect32) {
/* special case, currently only happens with sequencer rendering,
* which updates the whole frame, so we can only mark display buffer
* as invalid here (sergey)
@@ -204,8 +208,8 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
return;
}
else {
- if (rr->renlay == NULL || rr->renlay->rectf == NULL) return;
- rectf = rr->renlay->rectf;
+ if (rr->renlay == NULL) return;
+ rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname);
}
}
if (rectf == NULL) return;
@@ -343,7 +347,11 @@ static void render_freejob(void *rjv)
}
/* str is IMA_MAX_RENDER_TEXT in size */
-static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_override, char *str)
+static void make_renderinfo_string(const RenderStats *rs,
+ const Scene *scene,
+ const bool v3d_override,
+ const char *error,
+ char *str)
{
char info_time_str[32]; // used to be extern to header_info.c
uintptr_t mem_in_use, mmap_in_use, peak_memory;
@@ -368,7 +376,7 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr
spos += sprintf(spos, IFACE_("Frame:%d "), (scene->r.cfra));
/* previous and elapsed time */
- BLI_timestr(rs->lastframetime, info_time_str, sizeof(info_time_str));
+ BLI_timecode_string_from_time_simple(info_time_str, sizeof(info_time_str), rs->lastframetime);
if (rs->infostr && rs->infostr[0]) {
if (rs->lastframetime != 0.0)
@@ -376,7 +384,7 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr
else
spos += sprintf(spos, "| ");
- BLI_timestr(PIL_check_seconds_timer() - rs->starttime, info_time_str, sizeof(info_time_str));
+ BLI_timecode_string_from_time_simple(info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime);
}
else
spos += sprintf(spos, "| ");
@@ -416,8 +424,12 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr
spos += sprintf(spos, IFACE_("| Full Sample %d "), rs->curfsa);
/* extra info */
- if (rs->infostr && rs->infostr[0])
+ if (rs->infostr && rs->infostr[0]) {
spos += sprintf(spos, "| %s ", rs->infostr);
+ }
+ else if (error && error[0]) {
+ spos += sprintf(spos, "| %s ", error);
+ }
/* very weak... but 512 characters is quite safe */
if (spos >= str + IMA_MAX_RENDER_TEXT)
@@ -438,7 +450,8 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
if (rr->text == NULL)
rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
- make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->text);
+ make_renderinfo_string(rs, rj->scene, rj->v3d_override,
+ rr->error, rr->text);
}
RE_ReleaseResult(rj->re);
@@ -525,6 +538,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
+ const char *viewname = RE_GetActiveRenderView(rj->re);
/* only update if we are displaying the slot being rendered */
if (ima->render_slot != ima->last_render_slot) {
@@ -557,7 +571,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
ibuf->channels == 1 ||
U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
{
- image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect);
+ image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname);
}
/* make jobs timer to send notifier */
@@ -779,13 +793,13 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay)
if ((base->lay & renderlay) == 0) {
continue;
}
-
if (RE_allow_render_generic_object(base->object)) {
base->object->id.flag &= ~LIB_DOIT;
}
}
- for (object = bmain->object.first; object; object = object->id.next) {
+ for (SETLOOPER(scene, sce_iter, base)) {
+ object = base->object;
if ((object->id.flag & LIB_DOIT) == 0) {
continue;
}
@@ -1121,7 +1135,7 @@ static void render_view3d_renderinfo_cb(void *rjp, RenderStats *rs)
*rp->stop = 1;
}
else {
- make_renderinfo_string(rs, rp->scene, false, rp->engine->text);
+ make_renderinfo_string(rs, rp->scene, false, NULL, rp->engine->text);
/* make jobs timer to send notifier */
*(rp->do_update) = true;
@@ -1140,8 +1154,8 @@ BLI_INLINE void rcti_scale_coords(rcti *scaled_rect, const rcti *rect,
static void render_update_resolution(Render *re, const RenderPreview *rp,
bool use_border, const rcti *clip_rect)
{
- int winx = rp->ar->winx / rp->resolution_divider,
- winy = rp->ar->winy / rp->resolution_divider;
+ int winx = rp->ar->winx / rp->resolution_divider;
+ int winy = rp->ar->winy / rp->resolution_divider;
if (use_border) {
rcti scaled_cliprct;
rcti_scale_coords(&scaled_cliprct, clip_rect,
@@ -1221,10 +1235,10 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
RenderData rdata;
- /* no osa, blur, seq, layers, etc for preview render */
+ /* no osa, blur, seq, layers, savebuffer etc for preview render */
rdata = rp->scene->r;
rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA);
- rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE);
+ rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE | R_EXR_TILE_FILE | R_FULL_SAMPLE);
rdata.scemode |= R_VIEWPORT_PREVIEW;
/* we do use layers, but only active */
@@ -1439,7 +1453,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
rp->bmain = CTX_data_main(C);
rp->resolution_divider = divider;
rp->start_resolution_divider = divider;
- rp->has_freestyle = scene->r.mode & R_EDGE_FRS;
+ rp->has_freestyle = (scene->r.mode & R_EDGE_FRS) != 0;
copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
/* clear info text */
@@ -1455,7 +1469,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
engine->flag &= ~RE_ENGINE_DO_UPDATE;
}
-/* callback for render engine , on changes */
+/* callback for render engine, on changes */
void render_view3d_update(RenderEngine *engine, const bContext *C)
{
/* this shouldn't be needed and causes too many database rebuilds, but we
@@ -1481,7 +1495,8 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
if (re == NULL) return;
}
- RE_AcquireResultImage(re, &rres);
+ /* Viewport render preview doesn't support multiview, view hardcoded to 0 */
+ RE_AcquireResultImage(re, &rres, 0);
if (rres.rectf) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -1551,10 +1566,10 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
RE_ReleaseResultImage(re);
}
-void ED_viewport_render_kill_jobs(const bContext *C, bool free_database)
+void ED_viewport_render_kill_jobs(wmWindowManager *wm,
+ Main *bmain,
+ bool free_database)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
bScreen *sc;
ScrArea *sa;
ARegion *ar;
@@ -1611,7 +1626,17 @@ Scene *ED_render_job_get_scene(const bContext *C)
RenderJob *rj = (RenderJob *)WM_jobs_customdata_from_type(wm, WM_JOB_TYPE_RENDER);
if (rj)
- return rj->current_scene;
+ return rj->scene;
return NULL;
}
+
+Scene *ED_render_job_get_current_scene(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ RenderJob *rj = (RenderJob *)WM_jobs_customdata_from_type(wm, WM_JOB_TYPE_RENDER);
+ if (rj) {
+ return rj->current_scene;
+ }
+ return NULL;
+}
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index ecf5e962c80..fe4022709de 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -31,19 +31,20 @@
#include <string.h>
#include <stddef.h>
-#include <GL/glew.h>
-
#include "MEM_guardedalloc.h"
+#include "DNA_camera_types.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
+#include "BLI_threads.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -69,8 +70,9 @@
#include "RNA_define.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
+#include "GPU_compositing.h"
-#include "wm_window.h"
#include "render_intern.h"
@@ -94,6 +96,7 @@ typedef struct OGLRender {
ImageUser iuser;
GPUOffScreen *ofs;
+ GPUFX *fx;
int sizex, sizey;
int write_still;
@@ -101,11 +104,17 @@ typedef struct OGLRender {
bMovieHandle *mh;
int cfrao, nfra;
+ size_t totvideos;
+
+ /* quick lookup */
+ int view_id;
+
/* wm vars for timer and progress cursor */
wmWindowManager *wm;
wmWindow *win;
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
+ void **movie_ctx_arr;
} OGLRender;
/* added because v3d is not always valid */
@@ -119,25 +128,144 @@ static unsigned int screen_opengl_layers(OGLRender *oglrender)
}
}
-static void screen_opengl_render_apply(OGLRender *oglrender)
+static bool screen_opengl_is_multiview(OGLRender *oglrender)
+{
+ View3D *v3d = oglrender->v3d;
+ RegionView3D *rv3d = oglrender->rv3d;
+ RenderData *rd = &oglrender->scene->r;
+
+ if ((rd == NULL) || ((!oglrender->is_sequencer) && ((rv3d == NULL) || (v3d == NULL))))
+ return false;
+
+ return (rd->scemode & R_MULTIVIEW) && ((oglrender->is_sequencer) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+}
+
+static void screen_opengl_views_setup(OGLRender *oglrender)
+{
+ RenderResult *rr;
+ RenderView *rv;
+ SceneRenderView *srv;
+ bool is_multiview;
+ Object *camera;
+ View3D *v3d = oglrender->v3d;
+
+ RenderData *rd = &oglrender->scene->r;
+
+ rr = RE_AcquireResultWrite(oglrender->re);
+
+ is_multiview = screen_opengl_is_multiview(oglrender);
+
+ if (!is_multiview) {
+ /* we only have one view when multiview is off */
+ rv = rr->views.first;
+
+ if (rv == NULL) {
+ rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ BLI_addtail(&rr->views, rv);
+ }
+
+ while (rv->next) {
+ RenderView *rv_del = rv->next;
+ BLI_remlink(&rr->views, rv_del);
+
+ if (rv_del->rectf)
+ MEM_freeN(rv_del->rectf);
+
+ if (rv_del->rectz)
+ MEM_freeN(rv_del->rectz);
+
+ MEM_freeN(rv_del);
+ }
+ }
+ else {
+ if (!oglrender->is_sequencer)
+ RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
+
+ /* remove all the views that are not needed */
+ rv = rr->views.last;
+ while (rv) {
+ srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (rv->rectf == NULL)
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
+ rv = rv->prev;
+ }
+ else {
+ RenderView *rv_del = rv;
+ rv = rv_del->prev;
+
+ BLI_remlink(&rr->views, rv_del);
+
+ if (rv_del->rectf)
+ MEM_freeN(rv_del->rectf);
+
+ if (rv_del->rectz)
+ MEM_freeN(rv_del->rectz);
+
+ MEM_freeN(rv_del);
+ }
+ }
+
+ /* create all the views that are needed */
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+
+ rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+
+ if (rv == NULL) {
+ rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
+ BLI_addtail(&rr->views, rv);
+ }
+ }
+ }
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ if (rv->rectf == NULL) {
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
+ }
+ }
+
+ BLI_lock_thread(LOCK_DRAW_IMAGE);
+ if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
+ oglrender->ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+ oglrender->ima->flag &= ~IMA_IS_STEREO;
+ oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
+ }
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+
+ /* will only work for non multiview correctly */
+ if (v3d) {
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
+ BKE_render_result_stamp_info(oglrender->scene, camera, rr, false);
+ }
+ else {
+ BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false);
+ }
+
+ RE_ReleaseResult(oglrender->re);
+}
+
+static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
Scene *scene = oglrender->scene;
ARegion *ar = oglrender->ar;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- RenderResult *rr;
Object *camera = NULL;
ImBuf *ibuf;
- void *lock;
float winmat[4][4];
+ float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
const short view_context = (v3d != NULL);
bool draw_bgpic = true;
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
unsigned char *rect = NULL;
-
- rr = RE_AcquireResultRead(oglrender->re);
+ const char *viewname = RE_GetActiveRenderView(oglrender->re);
if (oglrender->is_sequencer) {
SeqRenderData context;
@@ -145,9 +273,12 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
int chanshown = sseq ? sseq->chanshown : 0;
struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;
- context = BKE_sequencer_new_render_data(oglrender->bmain->eval_ctx, oglrender->bmain,
- scene, oglrender->sizex, oglrender->sizey, 100.0f);
+ BKE_sequencer_new_render_data(
+ oglrender->bmain->eval_ctx, oglrender->bmain, scene,
+ oglrender->sizex, oglrender->sizey, 100.0f,
+ &context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
if (ibuf) {
@@ -171,7 +302,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
}
- memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
+ memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
IMB_freeImBuf(linear_ibuf);
}
@@ -180,7 +311,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
int i;
unsigned char *gp_rect;
- GPU_offscreen_bind(oglrender->ofs);
+ GPU_offscreen_bind(oglrender->ofs, true);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -188,32 +319,48 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
wmOrtho2(0, sizex, 0, sizey);
glTranslatef(sizex / 2, sizey / 2, 0.0f);
- ED_gpencil_draw_ex(gpd, sizex, sizey, scene->r.cfra);
+ G.f |= G_RENDER_OGL;
+ ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
+ G.f &= ~G_RENDER_OGL;
gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
+ BLI_assert(rectf != NULL);
+
for (i = 0; i < sizex * sizey * 4; i += 4) {
float col_src[4];
rgba_uchar_to_float(col_src, &gp_rect[i]);
- blend_color_mix_float(&rr->rectf[i], &rr->rectf[i], col_src);
+ blend_color_mix_float(&rectf[i], &rectf[i], col_src);
}
- GPU_offscreen_unbind(oglrender->ofs);
+ GPU_offscreen_unbind(oglrender->ofs, true);
MEM_freeN(gp_rect);
}
}
else if (view_context) {
+ bool is_persp;
+ /* full copy */
+ GPUFXSettings fx_settings = v3d->fx_settings;
+
ED_view3d_draw_offscreen_init(scene, v3d);
- GPU_offscreen_bind(oglrender->ofs); /* bind */
+ GPU_offscreen_bind(oglrender->ofs, true); /* bind */
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
- /*int is_ortho = scene->r.mode & R_ORTHO;*/
- camera = v3d->camera;
+#if 0
+ const bool is_ortho = (scene->r.mode & R_ORTHO) != 0;
+#endif
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
-
+ if (camera->type == OB_CAMERA) {
+ Camera *cam = camera->data;
+ is_persp = cam->type == CAM_PERSP;
+ }
+ else
+ is_persp = true;
+ BKE_camera_to_gpu_dof(camera, &fx_settings);
}
else {
rctf viewplane;
@@ -222,12 +369,17 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
bool is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+
+ is_persp = !is_ortho;
}
rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
if ((scene->r.mode & R_OSA) == 0) {
- ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky);
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, winmat,
+ draw_bgpic, draw_sky, is_persp,
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
}
else {
@@ -240,7 +392,10 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BLI_jitter_init(jit_ofs, scene->r.osa);
/* first sample buffer, also initializes 'rv3d->persmat' */
- ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky);
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, winmat,
+ draw_bgpic, draw_sky, is_persp,
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@@ -253,7 +408,10 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
(jit_ofs[j][0] * 2.0f) / sizex,
(jit_ofs[j][1] * 2.0f) / sizey);
- ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_bgpic, draw_sky);
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
+ draw_bgpic, draw_sky, is_persp,
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@@ -266,14 +424,14 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
MEM_freeN(accum_buffer);
}
- GPU_offscreen_unbind(oglrender->ofs); /* unbind */
+ GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */
}
else {
/* shouldnt suddenly give errors mid-render but possible */
char err_out[256] = "unknown";
ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
- IB_rect, OB_SOLID, false, true,
- (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out);
+ IB_rect, OB_SOLID, false, true, true,
+ (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
camera = scene->camera;
if (ibuf_view) {
@@ -298,7 +456,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
if (rect) {
int profile_to;
-
+ float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
+
if (BKE_scene_check_color_management_enabled(scene))
profile_to = IB_PROFILE_LINEAR_RGB;
else
@@ -306,45 +465,68 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* sequencer has got trickier conversion happened above
* also assume opengl's space matches byte buffer color space */
- IMB_buffer_float_from_byte(rr->rectf, rect,
+ IMB_buffer_float_from_byte(rectf, rect,
profile_to, IB_PROFILE_SRGB, true,
oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
+
+ /* rr->rectf is now filled with image data */
+
+ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
+ BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);
+
+ MEM_freeN(rect);
}
+}
- /* rr->rectf is now filled with image data */
+static void screen_opengl_render_write(OGLRender *oglrender)
+{
+ Scene *scene = oglrender->scene;
+ RenderResult *rr;
+ bool ok;
+ char name[FILE_MAX];
- if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
- BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
+ rr = RE_AcquireResultRead(oglrender->re);
- RE_ReleaseResult(oglrender->re);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
- /* update byte from float buffer */
- ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
+ /* write images as individual images or stereo */
+ BKE_render_result_stamp_info(scene, scene->camera, rr, false);
+ ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
- if (ibuf) {
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ RE_ReleaseResultImage(oglrender->re);
- /* write file for animation */
- if (oglrender->write_still) {
- char name[FILE_MAX];
- int ok;
+ if (ok) printf("OpenGL Render written to '%s'\n", name);
+ else printf("OpenGL Render failed to write '%s'\n", name);
+}
- if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) {
- IMB_color_to_bw(ibuf);
- }
+static void screen_opengl_render_apply(OGLRender *oglrender)
+{
+ RenderResult *rr;
+ RenderView *rv;
+ int view_id;
+ ImBuf *ibuf;
+ void *lock;
- BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
- ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */
- if (ok) printf("OpenGL Render written to '%s'\n", name);
- else printf("OpenGL Render failed to write '%s'\n", name);
- }
+ rr = RE_AcquireResultRead(oglrender->re);
+ for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ RE_SetActiveRenderView(oglrender->re, rv->name);
+ oglrender->view_id = view_id;
+ screen_opengl_render_doit(oglrender, rr);
+ }
+
+ RE_ReleaseResult(oglrender->re);
+
+ ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
+ if (ibuf) {
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}
-
BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
- if (rect)
- MEM_freeN(rect);
+ if (oglrender->write_still) {
+ screen_opengl_render_write(oglrender);
+ }
}
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
@@ -356,7 +538,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
- RenderResult *rr;
GPUOffScreen *ofs;
OGLRender *oglrender;
int sizex, sizey;
@@ -429,7 +610,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->sseq = CTX_wm_space_seq(C);
}
-
oglrender->prevsa = prevsa;
oglrender->prevar = prevar;
@@ -444,6 +624,9 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
* running notifiers again will overwrite */
oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal;
+ if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) {
+ oglrender->fx = GPU_fx_compositor_create();
+ }
}
/* create render */
@@ -460,15 +643,17 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create render result */
RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
- rr = RE_AcquireResultWrite(oglrender->re);
- if (rr->rectf == NULL)
- rr->rectf = MEM_callocN(sizeof(float) * 4 * sizex * sizey, "screen_opengl_render_init rect");
- RE_ReleaseResult(oglrender->re);
+ /* create render views */
+ screen_opengl_views_setup(oglrender);
/* wm vars */
oglrender->wm = wm;
oglrender->win = win;
+ oglrender->totvideos = 0;
+ oglrender->mh = NULL;
+ oglrender->movie_ctx_arr = NULL;
+
return true;
}
@@ -476,10 +661,19 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
{
Main *bmain = CTX_data_main(C);
Scene *scene = oglrender->scene;
+ size_t i;
if (oglrender->mh) {
- if (BKE_imtype_is_movie(scene->r.im_format.imtype))
- oglrender->mh->end_movie();
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ for (i = 0; i < oglrender->totvideos; i++) {
+ oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
+ oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
+ }
+ }
+
+ if (oglrender->movie_ctx_arr) {
+ MEM_freeN(oglrender->movie_ctx_arr);
+ }
}
if (oglrender->timer) { /* exec will not have a timer */
@@ -493,6 +687,9 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
+ if (oglrender->fx)
+ GPU_fx_compositor_destroy(oglrender->fx);
+
GPU_offscreen_free(oglrender->ofs);
oglrender->scene->customdata_mask_modal = 0;
@@ -509,7 +706,7 @@ static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
}
/* share between invoke and exec */
-static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
+static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
{
/* initialize animation */
OGLRender *oglrender;
@@ -517,13 +714,34 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender = op->customdata;
scene = oglrender->scene;
+ oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
oglrender->reports = op->reports;
- oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- if (!oglrender->mh->start_movie(scene, &scene->r, oglrender->sizex, oglrender->sizey, oglrender->reports)) {
+ size_t i, width, height;
+
+ BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
+ oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+
+ if (oglrender->mh == NULL) {
+ BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
screen_opengl_render_end(C, oglrender);
- return 0;
+ return false;
+ }
+
+ oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+
+ for (i = 0; i < oglrender->totvideos; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+
+ oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
+ if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i], scene, &scene->r, oglrender->sizex,
+ oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix))
+ {
+ screen_opengl_render_end(C, oglrender);
+ return false;
+ }
}
}
@@ -531,20 +749,19 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender->nfra = PSFRA;
scene->r.cfra = PSFRA;
- return 1;
+ return true;
}
+
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
OGLRender *oglrender = op->customdata;
Scene *scene = oglrender->scene;
- ImBuf *ibuf, *ibuf_save = NULL;
- void *lock;
char name[FILE_MAX];
bool ok = false;
const bool view_context = (oglrender->v3d != NULL);
- Object *camera = NULL;
bool is_movie;
+ RenderResult *rr;
/* go to next frame */
if (CFRA < oglrender->nfra)
@@ -562,8 +779,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
if (!is_movie) {
- BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
@@ -583,89 +801,41 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (BKE_scene_camera_switch_update(scene)) {
oglrender->v3d->camera = scene->camera;
}
-
- camera = oglrender->v3d->camera;
}
}
else {
BKE_scene_camera_switch_update(scene);
-
- camera = scene->camera;
}
/* render into offscreen buffer */
screen_opengl_render_apply(oglrender);
/* save to disk */
- ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
-
- if (ibuf) {
- bool needs_free = false;
-
- ibuf_save = ibuf;
-
- if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) {
- ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
-
- needs_free = true;
- }
-
- /* color -> grayscale */
- /* editing directly would alter the render view */
- if (scene->r.im_format.planes == R_IMF_PLANES_BW) {
- ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save);
- IMB_color_to_bw(ibuf_bw);
-
- if (needs_free)
- IMB_freeImBuf(ibuf_save);
-
- ibuf_save = ibuf_bw;
- }
- else {
- /* this is lightweight & doesnt re-alloc the buffers, only do this
- * to save the correct bit depth since the image is always RGBA */
- ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0);
-
- ibuf_cpy->rect = ibuf_save->rect;
- ibuf_cpy->rect_float = ibuf_save->rect_float;
- ibuf_cpy->zbuf_float = ibuf_save->zbuf_float;
-
- if (needs_free) {
- ibuf_cpy->mall = ibuf_save->mall;
- ibuf_save->mall = 0;
- IMB_freeImBuf(ibuf_save);
- }
+ rr = RE_AcquireResultRead(oglrender->re);
- ibuf_save = ibuf_cpy;
+ if (is_movie) {
+ ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex,
+ oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
+ if (ok) {
+ printf("Append frame %d", scene->r.cfra);
+ BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
}
-
- if (is_movie) {
- ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect,
- oglrender->sizex, oglrender->sizey, oglrender->reports);
- if (ok) {
- printf("Append frame %d", scene->r.cfra);
- BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
- }
+ }
+ else {
+ BKE_render_result_stamp_info(scene, scene->camera, rr, false);
+ ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
+ if (ok) {
+ printf("Saved: %s", name);
+ BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
}
else {
- ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format);
-
- if (ok == 0) {
- printf("Write error: cannot save %s\n", name);
- BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
- }
- else {
- printf("Saved: %s", name);
- BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
- }
+ printf("Write error: cannot save %s\n", name);
+ BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
}
-
- if (needs_free)
- IMB_freeImBuf(ibuf_save);
}
- BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
+ RE_ReleaseResult(oglrender->re);
+
/* movie stats prints have no line break */
printf("\n");
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index 0d334082a2b..f98083f7e74 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -47,6 +47,7 @@ void ED_operatortypes_render(void)
WM_operatortype_append(OBJECT_OT_material_slot_select);
WM_operatortype_append(OBJECT_OT_material_slot_deselect);
WM_operatortype_append(OBJECT_OT_material_slot_copy);
+ WM_operatortype_append(OBJECT_OT_material_slot_move);
WM_operatortype_append(MATERIAL_OT_new);
WM_operatortype_append(TEXTURE_OT_new);
@@ -58,6 +59,9 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);
+ WM_operatortype_append(SCENE_OT_render_view_add);
+ WM_operatortype_append(SCENE_OT_render_view_remove);
+
#ifdef WITH_FREESTYLE
WM_operatortype_append(SCENE_OT_freestyle_module_add);
WM_operatortype_append(SCENE_OT_freestyle_module_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 01f00a8458a..6dfd2b31d30 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -60,6 +60,7 @@
#include "DNA_brush_types.h"
#include "DNA_screen_types.h"
+#include "BKE_appdir.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
@@ -78,16 +79,14 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
-
-#include "GPU_extensions.h"
+#include "IMB_thumbs.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "PIL_time.h"
#include "RE_pipeline.h"
+#include "RE_engine.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -95,9 +94,10 @@
#include "ED_datafiles.h"
#include "ED_render.h"
-#include "UI_interface.h"
-
-#include "render_intern.h"
+#ifndef NDEBUG
+/* Used for database init assert(). */
+# include "BLI_threads.h"
+#endif
ImBuf *get_brush_icon(Brush *brush)
{
@@ -120,7 +120,7 @@ ImBuf *get_brush_icon(Brush *brush)
// otherwise lets try to find it in other directories
if (!(brush->icon_imbuf)) {
- folder = BLI_get_folder(BLENDER_DATAFILES, "brushicons");
+ folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
BLI_make_file_string(G.main->name, path, folder, brush->icon_filepath);
@@ -131,7 +131,7 @@ ImBuf *get_brush_icon(Brush *brush)
}
if (brush->icon_imbuf)
- BKE_icon_changed(BKE_icon_getid(&brush->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&brush->id));
}
}
}
@@ -164,6 +164,7 @@ typedef struct ShaderPreview {
unsigned int *pr_rect;
int pr_method;
+ Main *bmain;
Main *pr_main;
} ShaderPreview;
@@ -174,6 +175,7 @@ typedef struct IconPreviewSize {
} IconPreviewSize;
typedef struct IconPreview {
+ Main *bmain;
Scene *scene;
void *owner;
ID *id;
@@ -205,14 +207,25 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
}
#endif
-void ED_preview_init_dbase(void)
+void ED_preview_ensure_dbase(void)
{
#ifndef WITH_HEADLESS
- G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
- G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size);
+ static bool base_initialized = false;
+ BLI_assert(BLI_thread_is_main());
+ if (!base_initialized) {
+ G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
+ G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size);
+ base_initialized = true;
+ }
#endif
}
+static bool check_engine_supports_textures(Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return type->flag & RE_USE_TEXTURE_PREVIEW;
+}
+
void ED_preview_free_dbase(void)
{
if (G_pr_main)
@@ -258,12 +271,14 @@ static Scene *preview_get_scene(Main *pr_main)
/* call this with a pointer to initialize preview scene */
/* call this with NULL to restore assigned ID pointers in preview scene */
-static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPreview *sp)
+static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
Scene *sce;
Base *base;
Main *pr_main = sp->pr_main;
-
+
+ memcpy(pr_main->name, bmain->name, sizeof(pr_main->name));
+
sce = preview_get_scene(pr_main);
if (sce) {
@@ -299,12 +314,12 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
sce->r.cfra = scene->r.cfra;
- if (id_type == ID_TE) {
+ if (id_type == ID_TE && !check_engine_supports_textures(scene)) {
/* Force blender internal for texture icons and nodes render,
* seems commonly used render engines does not support
* such kind of rendering.
*/
- BLI_strncpy(sce->r.engine, "BLENDER_RENDER", sizeof(sce->r.engine));
+ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine));
}
else {
BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine));
@@ -356,7 +371,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
for (base = sce->base.first; base; base = base->next) {
if (base->object->type == OB_LAMP) {
/* if doesn't match 'Lamp.002' --> main key light */
- if (strcmp(base->object->id.name + 2, "Lamp.002") != 0) {
+ if (!STREQ(base->object->id.name + 2, "Lamp.002")) {
if (mat->material_type == MA_TYPE_VOLUME)
base->object->restrictflag |= OB_RESTRICT_RENDER;
else
@@ -420,7 +435,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
Tex *tex = NULL, *origtex = (Tex *)id;
if (origtex) {
- tex = localize_texture(origtex);
+ tex = BKE_texture_localize(origtex);
sp->texcopy = tex;
BLI_addtail(&pr_main->tex, tex);
}
@@ -518,10 +533,11 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
}
/* new UI convention: draw is in pixel space already. */
-/* uses ROUNDBOX button in block to get the rect */
+/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect)
{
Render *re;
+ RenderView *rv;
RenderResult rres;
char name[32];
int offx = 0;
@@ -545,9 +561,22 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
/* test if something rendered ok */
re = RE_GetRender(name);
- RE_AcquireResultImage(re, &rres);
- if (rres.rectf) {
+ if (re == NULL)
+ return false;
+
+ RE_AcquireResultImageViews(re, &rres);
+
+ if (!BLI_listbase_is_empty(&rres.views)) {
+ /* material preview only needs monoscopy (view 0) */
+ rv = RE_RenderViewGetById(&rres, 0);
+ }
+ else {
+ /* possible the job clears the views but we're still drawing T45496 */
+ rv = NULL;
+ }
+
+ if (rv && rv->rectf) {
if (ABS(rres.rectx - newx) < 2 && ABS(rres.recty - newy) < 2) {
@@ -558,8 +587,11 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
float fx = rect->xmin + offx;
float fy = rect->ymin;
-
- RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte);
+
+ /* material preview only needs monoscopy (view 0) */
+ if (re)
+ RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
+
glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
MEM_freeN(rect_byte);
@@ -569,7 +601,7 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
}
}
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImageViews(re, &rres);
return ok;
}
@@ -698,7 +730,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* get the stuff from the builtin preview dbase */
- sce = preview_prepare_scene(sp->scene, id, idtype, sp);
+ sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
if (sce == NULL) return;
if (!split || first) sprintf(name, "Preview %p", sp->owner);
@@ -751,15 +783,9 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
if (sp->pr_rect)
RE_ResultGet32(re, sp->pr_rect);
}
- else {
- /* validate owner */
- //if (ri->rect == NULL)
- // ri->rect= MEM_mallocN(sizeof(int) * ri->pr_rectx*ri->pr_recty, "BIF_previewrender");
- //RE_ResultGet32(re, ri->rect);
- }
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main */
// if (idtype == ID_TE) {
@@ -927,65 +953,87 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
ShaderPreview *sp = customdata;
- ID *id = sp->id;
- short idtype = GS(id->name);
-
- if (idtype == ID_IM) {
- Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
- ImageUser iuser = {NULL};
- /* ima->ok is zero when Image cannot load */
- if (ima == NULL || ima->ok == 0)
- return;
+ if (sp->pr_method == PR_ICON_DEFERRED) {
+ PreviewImage *prv = sp->owner;
+ ImBuf *thumb;
+ char *deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = deferred_data[0];
+ char *path = &deferred_data[1];
- /* setup dummy image user */
- iuser.ok = iuser.framenr = 1;
- iuser.scene = sp->scene;
-
- /* elubie: this needs to be changed: here image is always loaded if not
- * already there. Very expensive for large images. Need to find a way to
- * only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
+// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
- *do_update = true;
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect);
+ IMB_freeImBuf(thumb);
+ }
}
- else if (idtype == ID_BR) {
- Brush *br = (Brush *)id;
+ else {
+ ID *id = sp->id;
+ short idtype = GS(id->name);
+
+ if (idtype == ID_IM) {
+ Image *ima = (Image *)id;
+ ImBuf *ibuf = NULL;
+ ImageUser iuser = {NULL};
+
+ /* ima->ok is zero when Image cannot load */
+ if (ima == NULL || ima->ok == 0)
+ return;
+
+ /* setup dummy image user */
+ iuser.ok = iuser.framenr = 1;
+ iuser.scene = sp->scene;
+
+ /* elubie: this needs to be changed: here image is always loaded if not
+ * already there. Very expensive for large images. Need to find a way to
+ * only get existing ibuf */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
- br->icon_imbuf = get_brush_icon(br);
+ icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
- memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+ *do_update = true;
- if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
- return;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ else if (idtype == ID_BR) {
+ Brush *br = (Brush *)id;
- icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+ br->icon_imbuf = get_brush_icon(br);
- *do_update = true;
- }
- else {
- /* re-use shader job */
- shader_preview_startjob(customdata, stop, do_update);
+ memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+
+ if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
+ return;
- /* world is rendered with alpha=0, so it wasn't displayed
- * this could be render option for sky to, for later */
- if (idtype == ID_WO) {
- set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+
+ *do_update = true;
}
- else if (idtype == ID_MA) {
- Material *ma = (Material *)id;
+ else {
+ /* re-use shader job */
+ shader_preview_startjob(customdata, stop, do_update);
- if (ma->material_type == MA_TYPE_HALO)
+ /* world is rendered with alpha=0, so it wasn't displayed
+ * this could be render option for sky to, for later */
+ if (idtype == ID_WO) {
set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ }
+ else if (idtype == ID_MA) {
+ Material *ma = (Material *)id;
+
+ if (ma->material_type == MA_TYPE_HALO)
+ set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ }
}
}
}
@@ -997,7 +1045,7 @@ static void common_preview_startjob(void *customdata, short *stop, short *do_upd
{
ShaderPreview *sp = customdata;
- if (sp->pr_method == PR_ICON_RENDER)
+ if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED))
icon_preview_startjob(customdata, stop, do_update);
else
shader_preview_startjob(customdata, stop, do_update);
@@ -1033,29 +1081,35 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene);
while (cur_size) {
+ PreviewImage *prv = ip->owner;
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ const bool is_render = !prv->use_deferred;
/* construct shader preview from image size and previewcustomdata */
sp->scene = ip->scene;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
sp->sizey = cur_size->sizey;
- sp->pr_method = PR_ICON_RENDER;
+ sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED;
sp->pr_rect = cur_size->rect;
sp->id = ip->id;
-
- if (use_new_shading) {
- /* texture icon rendering is hardcoded to use BI,
- * so don't even think of using cycle's bmain for
- * texture icons
- */
- if (GS(ip->id->name) != ID_TE)
- sp->pr_main = G_pr_main_cycles;
- else
+ sp->bmain = ip->bmain;
+
+ if (is_render) {
+ BLI_assert(ip->id);
+ if (use_new_shading) {
+ /* texture icon rendering is hardcoded to use BI,
+ * so don't even think of using cycle's bmain for
+ * texture icons
+ */
+ if (GS(ip->id->name) != ID_TE)
+ sp->pr_main = G_pr_main_cycles;
+ else
+ sp->pr_main = G_pr_main;
+ }
+ else {
sp->pr_main = G_pr_main;
- }
- else {
- sp->pr_main = G_pr_main;
+ }
}
common_preview_startjob(sp, stop, do_update, progress);
@@ -1100,11 +1154,35 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
+void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
+{
+ IconPreview ip = {NULL};
+ short stop = false, update = false;
+ float progress = 0.0f;
+
+ ED_preview_ensure_dbase();
+
+ ip.bmain = bmain;
+ ip.scene = scene;
+ ip.owner = id;
+ ip.id = id;
+
+ icon_preview_add_size(&ip, rect, sizex, sizey);
+
+ icon_preview_startjob_all_sizes(&ip, &stop, &update, &progress);
+
+ icon_preview_endjob(&ip);
+
+ BLI_freelistN(&ip.sizes);
+}
+
void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
wmJob *wm_job;
IconPreview *ip, *old_ip;
-
+
+ ED_preview_ensure_dbase();
+
/* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview",
WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, WM_JOB_TYPE_RENDER_PREVIEW);
@@ -1117,8 +1195,9 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
/* customdata for preview thread */
+ ip->bmain = CTX_data_main(C);
ip->scene = CTX_data_scene(C);
- ip->owner = id;
+ ip->owner = owner;
ip->id = id;
icon_preview_add_size(ip, rect, sizex, sizey);
@@ -1145,6 +1224,8 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
return;
}
+ ED_preview_ensure_dbase();
+
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview",
WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
sp = MEM_callocN(sizeof(ShaderPreview), "shader preview");
@@ -1158,6 +1239,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
sp->id = id;
sp->parent = parent;
sp->slot = slot;
+ sp->bmain = CTX_data_main(C);
/* hardcoded preview .blend for cycles/internal, this should be solved
* once with custom preview .blend path for external engines */
@@ -1179,12 +1261,11 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-void ED_preview_kill_jobs(const struct bContext *C)
+void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
{
- wmWindowManager *wm = CTX_wm_manager(C);
if (wm)
WM_jobs_kill(wm, NULL, common_preview_startjob);
-
- ED_viewport_render_kill_jobs(C, false);
+
+ ED_viewport_render_kill_jobs(wm, bmain, false);
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 72b4da64c3e..2e07e19e366 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -41,40 +41,39 @@
#include "DNA_space_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_font.h"
-#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
#include "BKE_world.h"
#include "BKE_editmesh.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "GPU_material.h"
#ifdef WITH_FREESTYLE
+# include "BKE_freestyle.h"
# include "FRS_freestyle.h"
+# include "RNA_enum_types.h"
#endif
#include "RNA_access.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -102,8 +101,15 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob)
return OPERATOR_CANCELLED;
-
+
object_add_material_slot(ob);
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob);
@@ -138,8 +144,15 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode");
return OPERATOR_CANCELLED;
}
-
+
object_remove_material_slot(ob);
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
@@ -188,9 +201,11 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next)
- if (isNurbsel(nu))
- nu->mat_nr = nu->charidx = ob->actcol - 1;
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ if (ED_curve_nurb_select_check(ob->data, nu)) {
+ nu->mat_nr = ob->actcol - 1;
+ }
+ }
}
}
else if (ob->type == OB_FONT) {
@@ -369,6 +384,74 @@ void OBJECT_OT_material_slot_copy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+static int material_slot_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+
+ unsigned int *slot_remap;
+ int index_pair[2];
+
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (!ob || ob->totcol < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* up */
+ if (dir == 1 && ob->actcol > 1) {
+ index_pair[0] = ob->actcol - 2;
+ index_pair[1] = ob->actcol - 1;
+ ob->actcol--;
+ }
+ /* down */
+ else if (dir == -1 && ob->actcol < ob->totcol) {
+ index_pair[0] = ob->actcol - 1;
+ index_pair[1] = ob->actcol - 0;
+ ob->actcol++;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__);
+
+ range_vn_u(slot_remap, ob->totcol, 0);
+
+ slot_remap[index_pair[0]] = index_pair[1];
+ slot_remap[index_pair[1]] = index_pair[0];
+
+ BKE_material_remap_object(ob, slot_remap);
+
+ MEM_freeN(slot_remap);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_material_slot_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem material_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Material";
+ ot->idname = "OBJECT_OT_material_slot_move";
+ ot->description = "Move the active material up/down in the list";
+
+ /* api callbacks */
+ ot->exec = material_slot_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
/********************** new material operator *********************/
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
@@ -393,11 +476,11 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
}
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
ma->id.us--;
RNA_id_pointer_create(&ma->id, &idptr);
@@ -438,11 +521,11 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
tex = BKE_texture_copy(tex);
}
else {
- tex = add_texture(bmain, DATA_("Texture"));
+ tex = BKE_texture_add(bmain, DATA_("Texture"));
}
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
@@ -505,7 +588,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
}
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
@@ -543,7 +626,7 @@ static int render_layer_add_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
BKE_scene_add_render_layer(scene, NULL);
- scene->r.actlay = BLI_countlist(&scene->r.layers) - 1;
+ scene->r.actlay = BLI_listbase_count(&scene->r.layers) - 1;
DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -593,6 +676,70 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+/********************** render view operators *********************/
+
+static int render_view_remove_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* don't allow user to remove "left" and "right" views */
+ return scene->r.actview > 1;
+}
+
+static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ BKE_scene_add_render_view(scene, NULL);
+ scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_render_view_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Render View";
+ ot->idname = "SCENE_OT_render_view_add";
+ ot->description = "Add a render view";
+
+ /* api callbacks */
+ ot->exec = render_view_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+
+ if (!BKE_scene_remove_render_view(scene, rv))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_render_view_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Render View";
+ ot->idname = "SCENE_OT_render_view_remove";
+ ot->description = "Remove the selected render view";
+
+ /* api callbacks */
+ ot->exec = render_view_remove_exec;
+ ot->poll = render_view_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
#ifdef WITH_FREESTYLE
static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports)
@@ -719,10 +866,11 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- BKE_freestyle_lineset_add(&srl->freestyleConfig, NULL);
+ BKE_freestyle_lineset_add(bmain, &srl->freestyleConfig, NULL);
DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -881,6 +1029,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
@@ -891,10 +1040,10 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
}
if (lineset->linestyle) {
lineset->linestyle->id.us--;
- lineset->linestyle = BKE_linestyle_copy(lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
else {
- lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
}
DAG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
@@ -1374,11 +1523,15 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
static int save_envmap(wmOperator *op, Scene *scene, EnvMap *env, char *path, const char imtype)
{
+ PropertyRNA *prop;
float layout[12];
- if (RNA_struct_find_property(op->ptr, "layout") )
- RNA_float_get_array(op->ptr, "layout", layout);
- else
+
+ if ((prop = RNA_struct_find_property(op->ptr, "layout"))) {
+ RNA_property_float_get_array(op->ptr, prop, layout);
+ }
+ else {
memcpy(layout, default_envmap_layout, sizeof(layout));
+ }
if (RE_WriteEnvmapResult(op->reports, scene, env, path, imtype, layout)) {
return OPERATOR_FINISHED;
@@ -1400,7 +1553,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
if (scene->r.scemode & R_EXTENSION) {
- BKE_add_image_extension(path, &scene->r.im_format);
+ BKE_image_path_ensure_ext_from_imformat(path, &scene->r.im_format);
}
WM_cursor_wait(1);
@@ -1466,15 +1619,15 @@ void TEXTURE_OT_envmap_save(wmOperatorType *ot)
"(use -1 to skip a face)", 0.0f, 0.0f);
RNA_def_property_flag(prop, PROP_HIDDEN);
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
@@ -1517,7 +1670,7 @@ static int envmap_clear_all_exec(bContext *C, wmOperator *UNUSED(op))
for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->env)
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 6b58d3d55aa..f11a8177bf8 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -41,17 +41,18 @@
#include "DNA_world_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_scene.h"
#include "GPU_material.h"
#include "GPU_buffers.h"
@@ -61,6 +62,7 @@
#include "ED_node.h"
#include "ED_render.h"
+#include "ED_view3d.h"
#include "render_intern.h" // own include
@@ -85,7 +87,11 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
/* don't call this recursively for frame updates */
if (recursive_check)
return;
-
+
+ /* Do not call if no WM available, see T42688. */
+ if (BLI_listbase_is_empty(&bmain->wm))
+ return;
+
recursive_check = true;
C = CTX_create();
@@ -137,26 +143,36 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
recursive_check = false;
}
-void ED_render_engine_area_exit(ScrArea *sa)
+void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time)
+{
+ /* Blender internal might access to the data which is gonna to be freed
+ * by the scene update functions. This applies for example to simulation
+ * data like smoke and fire.
+ */
+ if (time && !BKE_scene_use_new_shading_nodes(scene)) {
+ bScreen *sc;
+ ScrArea *sa;
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ ED_render_engine_area_exit(bmain, sa);
+ }
+ }
+ }
+}
+
+void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
{
/* clear all render engines in this area */
ARegion *ar;
+ wmWindowManager *wm = bmain->wm.first;
if (sa->spacetype != SPACE_VIEW3D)
return;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- RegionView3D *rv3d;
-
if (ar->regiontype != RGN_TYPE_WINDOW || !(ar->regiondata))
continue;
-
- rv3d = ar->regiondata;
-
- if (rv3d->render_engine) {
- RE_engine_free(rv3d->render_engine);
- rv3d->render_engine = NULL;
- }
+ ED_view3d_stop_render_preview(wm, ar);
}
}
@@ -166,23 +182,15 @@ void ED_render_engine_changed(Main *bmain)
bScreen *sc;
ScrArea *sa;
Scene *scene;
- Material *ma;
for (sc = bmain->screen.first; sc; sc = sc->id.next)
for (sa = sc->areabase.first; sa; sa = sa->next)
- ED_render_engine_area_exit(sa);
+ ED_render_engine_area_exit(bmain, sa);
RE_FreePersistentData();
for (scene = bmain->scene.first; scene; scene = scene->id.next)
ED_render_id_flush_update(bmain, &scene->id);
-
- /* reset texture painting. Sending one dependency graph signal for any material should
- * refresh any texture slots */
- ma = bmain->mat.first;
- if (ma) {
- DAG_id_tag_update(&ma->id, 0);
- }
}
/***************************** Updates ***********************************
@@ -280,11 +288,11 @@ static void material_changed(Main *bmain, Material *ma)
int texture_draw = false;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&ma->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
/* glsl */
if (ma->gpumaterial.first)
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
/* find node materials using this */
for (parent = bmain->mat.first; parent; parent = parent->id.next) {
@@ -295,10 +303,10 @@ static void material_changed(Main *bmain, Material *ma)
continue;
}
- BKE_icon_changed(BKE_icon_getid(&parent->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&parent->id));
if (parent->gpumaterial.first)
- GPU_material_free(parent);
+ GPU_material_free(&parent->gpumaterial);
}
/* find if we have a scene with textured display */
@@ -310,7 +318,7 @@ static void material_changed(Main *bmain, Material *ma)
}
/* find textured objects */
- if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) {
+ if (texture_draw) {
for (ob = bmain->object.first; ob; ob = ob->id.next) {
DerivedMesh *dm = ob->derivedFinal;
Material ***material = give_matarar(ob);
@@ -335,7 +343,7 @@ static void lamp_changed(Main *bmain, Lamp *la)
Material *ma;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&la->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&la->id));
/* glsl */
for (ob = bmain->object.first; ob; ob = ob->id.next)
@@ -344,10 +352,10 @@ static void lamp_changed(Main *bmain, Lamp *la)
for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->gpumaterial.first)
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
if (defmaterial.gpumaterial.first)
- GPU_material_free(&defmaterial);
+ GPU_material_free(&defmaterial.gpumaterial);
}
static int material_uses_texture(Material *ma, Tex *tex)
@@ -371,7 +379,7 @@ static void texture_changed(Main *bmain, Tex *tex)
bool texture_draw = false;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&tex->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
/* paint overlays */
for (scene = bmain->scene.first; scene; scene = scene->id.next)
@@ -382,10 +390,10 @@ static void texture_changed(Main *bmain, Tex *tex)
if (!material_uses_texture(ma, tex))
continue;
- BKE_icon_changed(BKE_icon_getid(&ma->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
if (ma->gpumaterial.first)
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
}
/* find lamps */
@@ -413,7 +421,10 @@ static void texture_changed(Main *bmain, Tex *tex)
continue;
}
- BKE_icon_changed(BKE_icon_getid(&wo->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
+
+ if (wo->gpumaterial.first)
+ GPU_material_free(&wo->gpumaterial);
}
/* find compositing nodes */
@@ -430,7 +441,7 @@ static void texture_changed(Main *bmain, Tex *tex)
}
/* find textured objects */
- if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) {
+ if (texture_draw) {
for (ob = bmain->object.first; ob; ob = ob->id.next) {
DerivedMesh *dm = ob->derivedFinal;
Material ***material = give_matarar(ob);
@@ -458,15 +469,18 @@ static void world_changed(Main *bmain, World *wo)
Material *ma;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&wo->id));
-
+ BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
+
/* glsl */
for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->gpumaterial.first)
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
if (defmaterial.gpumaterial.first)
- GPU_material_free(&defmaterial);
+ GPU_material_free(&defmaterial.gpumaterial);
+
+ if (wo->gpumaterial.first)
+ GPU_material_free(&wo->gpumaterial);
}
static void image_changed(Main *bmain, Image *ima)
@@ -474,7 +488,7 @@ static void image_changed(Main *bmain, Image *ima)
Tex *tex;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&ima->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
for (tex = bmain->tex.first; tex; tex = tex->id.next)
@@ -482,22 +496,34 @@ static void image_changed(Main *bmain, Image *ima)
texture_changed(bmain, tex);
}
-static void scene_changed(Main *bmain, Scene *UNUSED(scene))
+static void scene_changed(Main *bmain, Scene *scene)
{
Object *ob;
Material *ma;
+ World *wo;
/* glsl */
- for (ob = bmain->object.first; ob; ob = ob->id.next)
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->gpulamp.first)
GPU_lamp_free(ob);
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ BKE_texpaint_slots_refresh_object(scene, ob);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ GPU_drawobject_free(ob->derivedFinal);
+ }
+ }
for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->gpumaterial.first)
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
+ for (wo = bmain->world.first; wo; wo = wo->id.next)
+ if (wo->gpumaterial.first)
+ GPU_material_free(&wo->gpumaterial);
+
if (defmaterial.gpumaterial.first)
- GPU_material_free(&defmaterial);
+ GPU_material_free(&defmaterial.gpumaterial);
}
void ED_render_id_flush_update(Main *bmain, ID *id)
@@ -539,7 +565,7 @@ void ED_render_id_flush_update(Main *bmain, ID *id)
void ED_render_internal_init(void)
{
- RenderEngineType *ret = RE_engines_find("BLENDER_RENDER");
+ RenderEngineType *ret = RE_engines_find(RE_engine_id_BLENDER_RENDER);
ret->view_update = render_view3d_update;
ret->view_draw = render_view3d_draw;
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 0beb5737ec7..f6690296890 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -63,7 +63,7 @@ static ScrArea *biggest_non_image_area(bContext *C)
for (sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->winx > 30 && sa->winy > 30) {
size = sa->winx * sa->winy;
- if (sa->spacetype == SPACE_BUTS) {
+ if (!sa->full && sa->spacetype == SPACE_BUTS) {
if (foundwin == 0 && size > bwmaxsize) {
bwmaxsize = size;
big = sa;
@@ -161,11 +161,19 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
}
else if (scene->r.displaymode == R_OUTPUT_SCREEN) {
sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE)
- area_was_image = true;
- /* this function returns with changed context */
- sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE);
+ /* if the active screen is already in fullscreen mode, skip this and
+ * unset the area, so that the fullscreen area is just changed later */
+ if (sa && sa->full) {
+ sa = NULL;
+ }
+ else {
+ if (sa && sa->spacetype == SPACE_IMAGE)
+ area_was_image = true;
+
+ /* this function returns with changed context */
+ sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE);
+ }
}
if (!sa) {
@@ -186,10 +194,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
+
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ if (sa->full) {
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ }
}
else {
/* use any area of decent size */
- sa = BKE_screen_find_big_area(CTX_wm_screen(C), -1, 0);
+ sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (sa->spacetype != SPACE_IMAGE) {
// XXX newspace(sa, SPACE_IMAGE);
sima = sa->spacedata.first;
@@ -232,6 +245,11 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
ScrArea *sa = CTX_wm_area(C);
SpaceImage *sima = sa->spacedata.first;
+ /* ensure image editor fullscreen and area fullscreen states are in sync */
+ if ((sima->flag & SI_FULLWINDOW) && !sa->full) {
+ sima->flag &= ~SI_FULLWINDOW;
+ }
+
/* test if we have a temp screen in front */
if (win->screen->temp) {
wm_window_lower(win);
@@ -243,16 +261,17 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, sa, false);
}
- else
+ else {
ED_area_prevspace(C, sa);
+ }
return OPERATOR_FINISHED;
}
else if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
return OPERATOR_FINISHED;
}
@@ -307,7 +326,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wm
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, sa, false);
}
else if (sima->next) {
/* workaround for case of double prevspace, render window
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 4ff1767f582..ed86ffa5e16 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../gpu
../../imbuf
@@ -30,6 +31,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -51,4 +53,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_screen "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript
index 28a6cbb02e6..5f48894c3e7 100644
--- a/source/blender/editors/screen/SConscript
+++ b/source/blender/editors/screen/SConscript
@@ -31,11 +31,13 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../imbuf',
@@ -46,6 +48,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 752f388c338..79d6b845361 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -41,7 +41,6 @@
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
-#include "BLF_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -62,7 +61,11 @@
#include "BIF_glutil.h"
#include "BLF_api.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -72,7 +75,7 @@ extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3,
/* general area and region code */
-static void region_draw_emboss(ARegion *ar, rcti *scirct)
+static void region_draw_emboss(const ARegion *ar, const rcti *scirct)
{
rcti rect;
@@ -149,6 +152,73 @@ void ED_area_do_refresh(bContext *C, ScrArea *sa)
}
/**
+ * Action zones are only updated if the mouse is inside of them, but in some cases (currently only fullscreen icon)
+ * it might be needed to update their properties and redraw if the mouse isn't inside.
+ */
+void ED_area_azones_update(ScrArea *sa, const int mouse_xy[2])
+{
+ AZone *az;
+ bool changed = false;
+
+ for (az = sa->actionzones.first; az; az = az->next) {
+ if (az->type == AZONE_FULLSCREEN) {
+ /* only if mouse is not hovering the azone */
+ if (BLI_rcti_isect_pt_v(&az->rect, mouse_xy) == false) {
+ az->alpha = 0.0f;
+ changed = true;
+
+ /* can break since currently only this is handled here */
+ break;
+ }
+ }
+ }
+
+ if (changed) {
+ sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ ED_area_tag_redraw(sa);
+ }
+}
+
+/**
+ * \brief Corner widget use for quitting fullscreen.
+ */
+static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, float alpha)
+{
+ int x = x2 - ((float) x2 - x1) * 0.5f / UI_DPI_FAC;
+ int y = y2 - ((float) y2 - y1) * 0.5f / UI_DPI_FAC;
+
+ /* adjust the icon distance from the corner */
+ x += 36.0f / UI_DPI_FAC;
+ y += 36.0f / UI_DPI_FAC;
+
+ /* draws from the left bottom corner of the icon */
+ x -= UI_DPI_ICON_SIZE;
+ y -= UI_DPI_ICON_SIZE;
+
+ alpha = min_ff(alpha, 0.75f);
+
+ UI_icon_draw_aspect(x, y, ICON_FULLSCREEN_EXIT, 0.7f / UI_DPI_FAC, alpha);
+
+ /* debug drawing :
+ * The click_rect is the same as defined in fullscreen_click_rcti_init
+ * Keep them both in sync */
+
+ if (G.debug_value == 1) {
+ rcti click_rect;
+ float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
+ char alpha_debug = 255 * alpha;
+
+ BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size);
+
+ glColor4ub(255, 0, 0, alpha_debug);
+ fdrawbox(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
+ glColor4ub(0, 255, 255, alpha_debug);
+ fdrawline(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
+ fdrawline(click_rect.xmin, click_rect.ymax, click_rect.xmax, click_rect.ymin);
+ }
+}
+
+/**
* \brief Corner widgets use for dragging and splitting the view.
*/
static void area_draw_azone(short x1, short y1, short x2, short y2)
@@ -231,21 +301,21 @@ static void region_draw_azone_tab_plus(AZone *az)
/* add code to draw region hidden as 'too small' */
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
break;
case AE_BOTTOM_TO_TOPLEFT:
- uiSetRoundBox(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
break;
case AE_LEFT_TO_TOPRIGHT:
- uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
break;
case AE_RIGHT_TO_TOPLEFT:
- uiSetRoundBox(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
break;
}
glColor4f(0.05f, 0.05f, 0.05f, 0.4f);
- uiRoundBox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
+ UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
glEnable(GL_BLEND);
@@ -266,32 +336,32 @@ static void region_draw_azone_tab(AZone *az)
/* add code to draw region hidden as 'too small' */
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_RB_ALPHA);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_RB_ALPHA);
- uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
+ UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
glColor4ub(0, 0, 0, 255);
- uiRoundRect((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f);
+ UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f);
break;
case AE_BOTTOM_TO_TOPLEFT:
- uiSetRoundBox(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA);
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA);
- uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
+ UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
glColor4ub(0, 0, 0, 255);
- uiRoundRect((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f);
+ UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f);
break;
case AE_LEFT_TO_TOPRIGHT:
- uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA);
- uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
+ UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
glColor4ub(0, 0, 0, 255);
- uiRoundRect((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
+ UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
break;
case AE_RIGHT_TO_TOPLEFT:
- uiSetRoundBox(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_RB_ALPHA);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_RB_ALPHA);
- uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
+ UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
glColor4ub(0, 0, 0, 255);
- uiRoundRect((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
+ UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
break;
}
@@ -327,6 +397,11 @@ static void region_draw_azone_tria(AZone *az)
glDisable(GL_BLEND);
}
+static void area_azone_tag_update(ScrArea *sa)
+{
+ sa->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
+}
+
static void region_draw_azones(ScrArea *sa, ARegion *ar)
{
AZone *az;
@@ -365,6 +440,13 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
}
}
}
+ else if (az->type == AZONE_FULLSCREEN) {
+ area_draw_azone_fullscreen(az->x1, az->y1, az->x2, az->y2, az->alpha);
+
+ if (az->alpha != 0.0f) {
+ area_azone_tag_update(sa);
+ }
+ }
}
}
@@ -451,13 +533,17 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
glDisable(GL_BLEND);
#endif
- ar->do_draw = 0;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
- uiFreeInactiveBlocks(C, &ar->uiblocks);
+ UI_blocklist_free_inactive(C, &ar->uiblocks);
- if (sa)
- region_draw_emboss(ar, &ar->winrct);
+ if (sa) {
+ /* disable emboss when the area is full,
+ * unless we need to see division between regions (quad-split for eg) */
+ if (((win->screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) {
+ region_draw_emboss(ar, &ar->winrct);
+ }
+ }
}
/* **********************************
@@ -490,7 +576,7 @@ void ED_region_tag_refresh_ui(ARegion *ar)
}
}
-void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct)
+void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
if (!(ar->do_draw & RGN_DRAW)) {
@@ -567,10 +653,10 @@ static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
{
AZone *az;
- /* reinitalize entirely, regions add azones too */
+ /* reinitalize entirely, regions and fullscreen add azones too */
BLI_freelistN(&sa->actionzones);
- if (screen->full != SCREENNORMAL) {
+ if (screen->state != SCREENNORMAL) {
return;
}
@@ -602,6 +688,26 @@ static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
+static void fullscreen_azone_initialize(ScrArea *sa, ARegion *ar)
+{
+ AZone *az;
+
+ if (ar->regiontype != RGN_TYPE_WINDOW)
+ return;
+
+ az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
+ BLI_addtail(&(sa->actionzones), az);
+ az->type = AZONE_FULLSCREEN;
+ az->ar = ar;
+ az->alpha = 0.0f;
+
+ az->x1 = ar->winrct.xmax - (AZONEFADEOUT - 1);
+ az->y1 = ar->winrct.ymax - (AZONEFADEOUT - 1);
+ az->x2 = ar->winrct.xmax;
+ az->y2 = ar->winrct.ymax;
+ BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
+}
+
#define AZONEPAD_EDGE (0.1f * U.widget_unit)
#define AZONEPAD_ICON (0.45f * U.widget_unit)
static void region_azone_edge(AZone *az, ARegion *ar)
@@ -710,7 +816,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2.5f * AZONEPAD_TAB_PLUSW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - 1.5f * AZONEPAD_TAB_PLUSW;
@@ -755,7 +861,7 @@ static void region_azone_tab(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TABW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - AZONEPAD_TABW;
@@ -800,7 +906,7 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TRIAW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - AZONEPAD_TRIAW;
@@ -830,25 +936,30 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
}
-static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge)
+static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
{
- AZone *az;
-
- az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
- az->type = AZONE_REGION;
- az->ar = ar;
- az->edge = edge;
+ AZone *az = NULL;
+ const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) == 0;
- if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- if (G.debug_value == 3)
- region_azone_icon(sa, az, ar);
- else if (G.debug_value == 2)
- region_azone_tria(sa, az, ar);
- else if (G.debug_value == 1)
- region_azone_tab(sa, az, ar);
- else
- region_azone_tab_plus(sa, az, ar);
+ if (is_hidden || !is_fullscreen) {
+ az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
+ BLI_addtail(&(sa->actionzones), az);
+ az->type = AZONE_REGION;
+ az->ar = ar;
+ az->edge = edge;
+ }
+
+ if (!is_hidden) {
+ if (!is_fullscreen) {
+ if (G.debug_value == 3)
+ region_azone_icon(sa, az, ar);
+ else if (G.debug_value == 2)
+ region_azone_tria(sa, az, ar);
+ else if (G.debug_value == 1)
+ region_azone_tab(sa, az, ar);
+ else
+ region_azone_tab_plus(sa, az, ar);
+ }
}
else {
region_azone_edge(az, ar);
@@ -859,22 +970,22 @@ static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge)
/* *************************************************************** */
-static void region_azone_add(ScrArea *sa, ARegion *ar, int alignment)
+static void region_azone_add(ScrArea *sa, ARegion *ar, const int alignment, const bool is_fullscreen)
{
/* edge code (t b l r) is along which area edge azone will be drawn */
if (alignment == RGN_ALIGN_TOP)
- region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT);
+ region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
else if (alignment == RGN_ALIGN_BOTTOM)
- region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT);
+ region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_RIGHT)
- region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT);
+ region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_LEFT)
- region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT);
+ region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
}
/* dir is direction to check, not the splitting edge direction! */
-static int rct_fits(rcti *rect, char dir, int size)
+static int rct_fits(const rcti *rect, char dir, int size)
{
if (dir == 'h') {
return BLI_rcti_size_x(rect) + 1 - size;
@@ -1156,16 +1267,22 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
ar->winrct = *remainder;
- if (alignment == RGN_ALIGN_TOP)
- ar->winrct.ymin = ar->winrct.ymax;
- else if (alignment == RGN_ALIGN_BOTTOM)
- ar->winrct.ymax = ar->winrct.ymin;
- else if (alignment == RGN_ALIGN_RIGHT)
- ar->winrct.xmin = ar->winrct.xmax;
- else if (alignment == RGN_ALIGN_LEFT)
- ar->winrct.xmax = ar->winrct.xmin;
- else /* prevent winrct to be valid */
- ar->winrct.xmax = ar->winrct.xmin;
+ switch (alignment) {
+ case RGN_ALIGN_TOP:
+ ar->winrct.ymin = ar->winrct.ymax;
+ break;
+ case RGN_ALIGN_BOTTOM:
+ ar->winrct.ymax = ar->winrct.ymin;
+ break;
+ case RGN_ALIGN_RIGHT:
+ ar->winrct.xmin = ar->winrct.xmax;
+ break;
+ case RGN_ALIGN_LEFT:
+ default:
+ /* prevent winrct to be valid */
+ ar->winrct.xmax = ar->winrct.xmin;
+ break;
+ }
}
/* restore prev-split exception */
@@ -1188,7 +1305,13 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
* must be minimum '4' */
}
else {
- region_azone_add(sa, ar, alignment);
+ if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
+ region_azone_add(sa, ar, alignment, false);
+ }
+ else {
+ region_azone_add(sa, ar, alignment, true);
+ fullscreen_azone_initialize(sa, ar);
+ }
}
region_rect_recursive(win, sa, ar->next, remainder, quad);
@@ -1240,7 +1363,7 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* XXX it would be good to have boundbox checks for some of these... */
if (flag & ED_KEYMAP_UI) {
/* user interface widgets */
- UI_add_region_handlers(handlers);
+ UI_region_handlers_add(handlers);
}
if (flag & ED_KEYMAP_VIEW2D) {
/* 2d-viewport handling+manipulation */
@@ -1256,7 +1379,7 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
ARegion *ar;
/* same local check for all areas */
static rcti rect = {0, 10000, 0, -1};
- rect.ymax = (30 * UI_DPI_FAC);
+ rect.ymax = UI_MARKER_MARGIN_Y;
ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar) {
WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
@@ -1277,8 +1400,18 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
}
if (flag & ED_KEYMAP_GPENCIL) {
/* grease pencil */
- wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
- WM_event_add_keymap_handler(handlers, keymap);
+ /* NOTE: This is now 2 keymaps - One for basic functionality,
+ * and one that only applies when "Edit Mode" is enabled
+ * for strokes.
+ *
+ * For now, it's easier to just include both,
+ * since you hardly want one without the other.
+ */
+ wmKeyMap *keymap_general = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
+ wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
+
+ WM_event_add_keymap_handler(handlers, keymap_general);
+ WM_event_add_keymap_handler(handlers, keymap_edit);
}
if (flag & ED_KEYMAP_HEADER) {
/* standard keymap for headers regions */
@@ -1334,7 +1467,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
}
else {
/* prevent uiblocks to run */
- uiFreeBlocks(NULL, &ar->uiblocks);
+ UI_blocklist_free(NULL, &ar->uiblocks);
}
}
}
@@ -1394,7 +1527,7 @@ void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
/* exported to all editors, uses fading default */
void ED_region_toggle_hidden(bContext *C, ARegion *ar)
{
- region_toggle_hidden(C, ar, 1);
+ region_toggle_hidden(C, ar, true);
}
/**
@@ -1438,10 +1571,10 @@ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
void ED_area_data_swap(ScrArea *sa_dst, ScrArea *sa_src)
{
- sa_dst->headertype = sa_src->headertype;
- sa_dst->spacetype = sa_src->spacetype;
- sa_dst->type = sa_src->type;
- sa_dst->butspacetype = sa_src->butspacetype;
+ SWAP(short, sa_dst->headertype, sa_src->headertype);
+ SWAP(char, sa_dst->spacetype, sa_src->spacetype);
+ SWAP(SpaceType *, sa_dst->type, sa_src->type);
+ SWAP(char, sa_dst->butspacetype, sa_src->butspacetype);
SWAP(ListBase, sa_dst->spacedata, sa_src->spacedata);
@@ -1547,7 +1680,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type)
void ED_area_prevspace(bContext *C, ScrArea *sa)
{
- SpaceLink *sl = (sa) ? sa->spacedata.first : CTX_wm_space_data(C);
+ SpaceLink *sl = sa->spacedata.first;
if (sl && sl->next) {
/* workaround for case of double prevspace, render window
@@ -1561,6 +1694,8 @@ void ED_area_prevspace(bContext *C, ScrArea *sa)
/* no change */
return;
}
+ sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
+
ED_area_tag_redraw(sa);
/* send space change notifier */
@@ -1577,7 +1712,7 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
- uiDefButR(block, MENU, 0, "", xco, yco, 1.5 * U.widget_unit, U.widget_unit,
+ uiDefButR(block, UI_BTYPE_MENU, 0, "", xco, yco, 1.5 * U.widget_unit, U.widget_unit,
&areaptr, "type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
return xco + 1.7 * U.widget_unit;
@@ -1585,10 +1720,10 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
/************************ standard UI regions ************************/
-void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *context, int contextnr)
+void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical)
{
ScrArea *sa = CTX_wm_area(C);
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
uiBlock *block;
PanelType *pt;
Panel *panel;
@@ -1686,16 +1821,16 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
w -= margin_x;
/* create panels */
- uiBeginPanels(C, ar);
+ UI_panels_begin(C, ar);
- /* set view2d view matrix - uiBeginBlock() stores it */
+ /* set view2d view matrix - UI_block_begin() stores it */
UI_view2d_view_ortho(v2d);
BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
{
bool open;
- panel = uiPanelFindByType(ar, pt);
+ panel = UI_panel_find_by_type(ar, pt);
if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
@@ -1704,20 +1839,21 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
}
/* draw panel */
- block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
- panel = uiBeginPanel(sa, ar, block, pt, panel, &open);
+ block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
+ panel = UI_panel_begin(sa, ar, block, pt, panel, &open);
/* bad fixed values */
triangle = (int)(UI_UNIT_Y * 1.1f);
if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
/* for enabled buttons */
- panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
- triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
pt->draw_header(C, panel);
- uiBlockLayoutResolve(block, &xco, &yco);
+ UI_block_layout_resolve(block, &xco, &yco);
panel->labelofs = xco - triangle;
panel->layout = NULL;
}
@@ -1734,28 +1870,29 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
else
panelContext = UI_LAYOUT_PANEL;
- panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext,
- style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, panelContext,
+ style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
pt->draw(C, panel);
- uiBlockLayoutResolve(block, &xco, &yco);
+ UI_block_layout_resolve(block, &xco, &yco);
panel->layout = NULL;
yco -= 2 * style->panelspace;
- uiEndPanel(block, w, -yco);
+ UI_panel_end(block, w, -yco);
}
else {
yco = 0;
- uiEndPanel(block, w, 0);
+ UI_panel_end(block, w, 0);
}
- uiEndBlock(C, block);
+ UI_block_end(C, block);
}
BLI_SMALLSTACK_ITER_END;
/* align panels and return size */
- uiEndPanels(C, ar, &x, &y);
+ UI_panels_end(C, ar, &x, &y);
/* before setting the view */
if (vertical) {
@@ -1780,7 +1917,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
* flip +1 or -1 pixel compared to redoing the entire layout again.
* Leaving in commented code for future tests */
#if 0
- uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur));
+ UI_panels_scale(ar, BLI_rctf_size_x(&v2d->cur));
break;
#endif
}
@@ -1795,7 +1932,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
UI_view2d_view_restore(C);
glEnable(GL_BLEND);
UI_ThemeColor4((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
- glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
+ glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1);
glDisable(GL_BLEND);
}
else {
@@ -1808,7 +1945,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
UI_view2d_view_ortho(v2d);
/* draw panels */
- uiDrawPanels(C, ar);
+ UI_panels_draw(C, ar);
/* restore view matrix */
UI_view2d_view_restore(C);
@@ -1835,7 +1972,7 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
void ED_region_header(const bContext *C, ARegion *ar)
{
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
uiBlock *block;
uiLayout *layout;
HeaderType *ht;
@@ -1855,8 +1992,8 @@ void ED_region_header(const bContext *C, ARegion *ar)
/* draw all headers types */
for (ht = ar->type->headertypes.first; ht; ht = ht->next) {
- block = uiBeginBlock(C, ar, ht->idname, UI_EMBOSS);
- layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, UI_UNIT_Y, 1, 0, style);
+ block = UI_block_begin(C, ar, ht->idname, UI_EMBOSS);
+ layout = UI_block_layout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, UI_UNIT_Y, 1, 0, style);
if (ht->draw) {
header.type = ht;
@@ -1869,14 +2006,14 @@ void ED_region_header(const bContext *C, ARegion *ar)
maxco = xco;
}
- uiBlockLayoutResolve(block, &xco, &yco);
+ UI_block_layout_resolve(block, &xco, &yco);
/* for view2d */
if (xco > maxco)
maxco = xco;
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
}
/* always as last */
@@ -1897,10 +2034,10 @@ int ED_area_headersize(void)
return (int)(HEADERY * UI_DPI_FAC);
}
-void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_color[4])
+void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], const bool full_redraw)
{
const int header_height = UI_UNIT_Y;
- uiStyle *style = UI_GetStyleDraw();
+ uiStyle *style = UI_style_get_dpi();
int fontid = style->widget.uifont_id;
GLint scissor[4];
rcti rect;
@@ -1910,7 +2047,7 @@ void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_co
rect.ymin = BLI_rcti_size_y(&ar->winrct) - header_height;
/* box fill entire width or just around text */
- if (!block)
+ if (!full_redraw)
rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, text, BLF_DRAW_STR_DUMMY_MAX) + 1.2f * U.widget_unit);
rect.ymax = BLI_rcti_size_y(&ar->winrct);
@@ -1940,6 +2077,196 @@ void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_co
glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
}
+#define MAX_METADATA_STR 1024
+
+static const char *meta_data_list[] =
+{
+ "File",
+ "Strip",
+ "Note",
+ "Date",
+ "RenderTime",
+ "Marker",
+ "Time",
+ "Frame",
+ "Camera",
+ "Scene"
+};
+
+BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset)
+{
+ return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]);
+}
+
+static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top)
+{
+ char temp_str[MAX_METADATA_STR];
+ int line_width;
+ int ofs_y = 0;
+ short i;
+ int len;
+ const float height = BLF_height_max(fontid);
+ const float vertical_offset = height + (0.1f * U.widget_unit);
+
+ if (is_top) {
+ for (i = 0; i < 4; i++) {
+ /* first line */
+ if (i == 0) {
+ bool do_newline = false;
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
+ if (metadata_is_valid(ibuf, temp_str, 0, len)) {
+ BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit),
+ rect->ymax - vertical_offset, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ do_newline = true;
+ }
+
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
+ if (metadata_is_valid(ibuf, temp_str, 1, len)) {
+ line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_position(fontid, rect->xmax - line_width - (0.2f * U.widget_unit),
+ rect->ymax - vertical_offset, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ do_newline = true;
+ }
+
+ if (do_newline)
+ ofs_y += vertical_offset;
+ }
+ else if (i == 1) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit),
+ rect->ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ ofs_y += vertical_offset;
+ }
+ }
+ else {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_position(fontid, rect->xmax - line_width - (0.2f * U.widget_unit),
+ rect->ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ ofs_y += vertical_offset;
+ }
+ }
+ }
+ }
+ else {
+ int ofs_x = 0;
+ for (i = 5; i < 10; i++) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
+ if (metadata_is_valid(ibuf, temp_str, i, len)) {
+ BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit) + ofs_x,
+ rect->ymin + (0.3f * U.widget_unit), 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+
+ ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
+ }
+ }
+ }
+}
+
+static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
+{
+ char str[MAX_METADATA_STR] = "";
+ short i, count = 0;
+ const float height = BLF_height_max(fontid) + 0.1f * U.widget_unit;
+
+ if (is_top) {
+ if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) {
+ count++;
+ }
+ for (i = 2; i < 5; i++) {
+ if (metadata_is_valid(ibuf, str, i, 0)) {
+ count++;
+ }
+ }
+ }
+ else {
+ for (i = 5; i < 10; i++) {
+ if (metadata_is_valid(ibuf, str, i, 0)) {
+ count = 1;
+ }
+ }
+ }
+
+ if (count) {
+ return (height * count + (0.1f * U.widget_unit));
+ }
+
+ return 0;
+}
+
+#undef MAX_METADATA_STR
+
+void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float zoomx, float zoomy)
+{
+ float box_y;
+ rctf rect;
+ uiStyle *style = UI_style_get_dpi();
+
+ if (!ibuf->metadata)
+ return;
+
+ /* find window pixel coordinates of origin */
+ glPushMatrix();
+
+ /* offset and zoom using ogl */
+ glTranslatef(x, y, 0.0f);
+ glScalef(zoomx, zoomy, 1.0f);
+
+ BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f, U.dpi);
+
+ /* *** upper box*** */
+
+ /* get needed box height */
+ box_y = metadata_box_height_get(ibuf, blf_mono_font, true);
+
+ if (box_y) {
+ UI_ThemeColor(TH_METADATA_BG);
+
+ /* set up rect */
+ BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymax, frame.ymax + box_y);
+ /* draw top box */
+ glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ BLF_enable(blf_mono_font, BLF_CLIPPING);
+
+ UI_ThemeColor(TH_METADATA_TEXT);
+ metadata_draw_imbuf(ibuf, &rect, blf_mono_font, true);
+
+ BLF_disable(blf_mono_font, BLF_CLIPPING);
+ }
+
+
+ /* *** lower box*** */
+
+ box_y = metadata_box_height_get(ibuf, blf_mono_font, false);
+
+ if (box_y) {
+ UI_ThemeColor(TH_METADATA_BG);
+
+ /* set up box rect */
+ BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymin - box_y, frame.ymin);
+ /* draw top box */
+ glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ BLF_enable(blf_mono_font, BLF_CLIPPING);
+
+ UI_ThemeColor(TH_METADATA_TEXT);
+ metadata_draw_imbuf(ibuf, &rect, blf_mono_font, false);
+
+ BLF_disable(blf_mono_font, BLF_CLIPPING);
+ }
+
+ glPopMatrix();
+}
+
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
{
float gridsize, gridstep = 1.0f / 32.0f;
@@ -2040,7 +2367,7 @@ void ED_region_cache_draw_background(const ARegion *ar)
void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y)
{
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
int fontid = style->widget.uifont_id;
char numstr[32];
float font_dims[2] = {0.0f, 0.0f};
@@ -2075,4 +2402,3 @@ void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segme
}
}
}
-
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 0edde66ffff..fd65d81baad 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -45,7 +45,6 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_extensions.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -224,15 +223,15 @@ void fdrawcheckerboard(float x1, float y1, float x2, float y2)
glDisable(GL_POLYGON_STIPPLE);
}
-void sdrawline(short x1, short y1, short x2, short y2)
+void sdrawline(int x1, int y1, int x2, int y2)
{
- short v[2];
+ int v[2];
glBegin(GL_LINE_STRIP);
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
glEnd();
}
@@ -246,25 +245,25 @@ void sdrawline(short x1, short y1, short x2, short y2)
* x1,y1-- x2,y1
*/
-static void sdrawtripoints(short x1, short y1, short x2, short y2)
+static void sdrawtripoints(int x1, int y1, int x2, int y2)
{
- short v[2];
+ int v[2];
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x1; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
}
-void sdrawtri(short x1, short y1, short x2, short y2)
+void sdrawtri(int x1, int y1, int x2, int y2)
{
glBegin(GL_LINE_STRIP);
sdrawtripoints(x1, y1, x2, y2);
glEnd();
}
-void sdrawtrifill(short x1, short y1, short x2, short y2)
+void sdrawtrifill(int x1, int y1, int x2, int y2)
{
glBegin(GL_TRIANGLES);
sdrawtripoints(x1, y1, x2, y2);
@@ -272,22 +271,22 @@ void sdrawtrifill(short x1, short y1, short x2, short y2)
}
#endif
-void sdrawbox(short x1, short y1, short x2, short y2)
+void sdrawbox(int x1, int y1, int x2, int y2)
{
- short v[2];
+ int v[2];
glBegin(GL_LINE_STRIP);
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x1; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
glEnd();
}
@@ -339,7 +338,7 @@ void sdrawXORline(int x0, int y0, int x1, int y1)
void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
{
- static short old[4][2][2];
+ static int old[4][2][2];
static char flags[4] = {0, 0, 0, 0};
/* with builtin memory, max 4 lines */
@@ -350,8 +349,8 @@ void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
if (nr == -1) { /* flush */
for (nr = 0; nr < 4; nr++) {
if (flags[nr]) {
- glVertex2sv(old[nr][0]);
- glVertex2sv(old[nr][1]);
+ glVertex2iv(old[nr][0]);
+ glVertex2iv(old[nr][1]);
flags[nr] = 0;
}
}
@@ -359,8 +358,8 @@ void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
else {
if (nr >= 0 && nr < 4) {
if (flags[nr]) {
- glVertex2sv(old[nr][0]);
- glVertex2sv(old[nr][1]);
+ glVertex2iv(old[nr][0]);
+ glVertex2iv(old[nr][1]);
}
old[nr][0][0] = x0;
@@ -580,25 +579,25 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
continue;
if (type == GL_FLOAT) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
/* add an extra border of pixels so linear looks ok at edges of full image. */
if (subpart_w < tex_w)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w && subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w && subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
glEnable(GL_TEXTURE_2D);
@@ -840,16 +839,16 @@ void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x
}
/**
- * Translate the \a world point from world coordiantes into screen space.
+ * Translate the \a world point from world coordinates into screen space.
*/
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2])
{
screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
}
/**
- * Restores the previous OpenGL state and free's the auxilary gla data.
+ * Restores the previous OpenGL state and frees the auxiliary gla data.
*/
void glaEnd2DDraw(gla2DDrawInfo *di)
{
@@ -992,7 +991,7 @@ void bgl_get_mats(bglMats *mats)
/**
* \note \a viewdist is only for ortho at the moment.
*/
-void bglPolygonOffset(float viewdist, float dist)
+void bglPolygonOffset(float viewdist, float dist)
{
static float winmat[16], offset = 0.0;
@@ -1008,8 +1007,25 @@ void bglPolygonOffset(float viewdist, float dist)
/* dist is from camera to center point */
- if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist; // ortho tweaking
- else offs = 0.0005f * dist; // should be clipping value or so...
+ if (winmat[15] > 0.5f) {
+#if 1
+ offs = 0.00001f * dist * viewdist; // ortho tweaking
+#else
+ static float depth_fac = 0.0f;
+ if (depth_fac == 0.0f) {
+ int depthbits;
+ glGetIntegerv(GL_DEPTH_BITS, &depthbits);
+ depth_fac = 1.0f / (float)((1 << depthbits) - 1);
+ }
+ offs = (-1.0 / winmat[10]) * dist * depth_fac;
+
+ UNUSED_VARS(viewdist);
+#endif
+ }
+ else {
+ /* should be clipping value or so... */
+ offs = 0.0005f * dist;
+ }
winmat[14] -= offs;
offset += offs;
@@ -1137,9 +1153,9 @@ void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int
void cpack(unsigned int x)
{
- glColor3ub( ( (x) & 0xFF),
- (((x) >> 8) & 0xFF),
- (((x) >> 16) & 0xFF) );
+ glColor3ub(( (x) & 0xFF),
+ (((x) >> 8) & 0xFF),
+ (((x) >> 16) & 0xFF));
}
void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy)
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 7c8987ae778..87c0ce398e5 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -26,12 +26,13 @@
* \ingroup edscr
*/
-
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -45,17 +46,32 @@
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_gpencil.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "RNA_access.h"
#include "ED_armature.h"
+#include "ED_gpencil.h"
#include "WM_api.h"
#include "UI_interface.h"
#include "screen_intern.h"
+static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx)
+{
+ /* needed for 'USE_ALLSELECT' define, otherwise we end up editing off-screen layers. */
+ if (sc && sa_ctx && (sa_ctx->spacetype == SPACE_BUTS)) {
+ const unsigned int lay = BKE_screen_view3d_layer_all(sc);
+ if (lay) {
+ return lay;
+ }
+ }
+ return scene->lay;
+}
+
const char *screen_context_dir[] = {
"scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"selected_objects", "selected_bases",
@@ -66,15 +82,18 @@ const char *screen_context_dir[] = {
"sculpt_object", "vertex_paint_object", "weight_paint_object",
"image_paint_object", "particle_edit_object",
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
+ "gpencil_data", "gpencil_data_owner", /* grease pencil data */
+ "visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
+ "active_gpencil_layer", "active_gpencil_frame",
"active_operator",
NULL};
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
bScreen *sc = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
Scene *scene = sc->scene;
Base *base;
- unsigned int lay = scene->lay;
#if 0 /* Using the context breaks adding objects in the UI. Need to find out why - campbell */
Object *obact = CTX_data_active_object(C);
@@ -95,10 +114,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int visible_objects = CTX_data_equals(member, "visible_objects");
for (base = scene->base.first; base; base = base->next) {
- if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & scene->lay)) {
+ if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
if (visible_objects)
CTX_data_id_list_add(result, &base->object->id);
else
@@ -109,6 +129,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selectable_objects = CTX_data_equals(member, "selectable_objects");
for (base = scene->base.first; base; base = base->next) {
@@ -125,10 +146,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selected_objects = CTX_data_equals(member, "selected_objects");
for (base = scene->base.first; base; base = base->next) {
- if ((base->flag & SELECT) && (base->lay & scene->lay)) {
+ if ((base->flag & SELECT) && (base->lay & lay)) {
if (selected_objects)
CTX_data_id_list_add(result, &base->object->id);
else
@@ -139,10 +161,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
for (base = scene->base.first; base; base = base->next) {
- if ((base->flag & SELECT) && (base->lay & scene->lay)) {
+ if ((base->flag & SELECT) && (base->lay & lay)) {
if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
if (0 == BKE_object_is_libdata(base->object)) {
if (selected_editable_objects)
@@ -392,6 +415,114 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
}
+ else if (CTX_data_equals(member, "gpencil_data")) {
+ /* FIXME: for some reason, CTX_data_active_object(C) returns NULL when called from these situations
+ * (as outlined above - see Campbell's #ifdefs). That causes the get_active function to fail when
+ * called from context. For that reason, we end up using an alternative where we pass everything in!
+ */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ CTX_data_id_pointer_set(result, &gpd->id);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "gpencil_data_owner")) {
+ /* pointer to which data/datablock owns the reference to the Grease Pencil data being used (as gpencil_data)
+ * XXX: see comment for gpencil_data case...
+ */
+ bGPdata **gpd_ptr = NULL;
+ PointerRNA ptr;
+
+ /* get pointer to Grease Pencil Data */
+ gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, scene, sa, obact, &ptr);
+
+ if (gpd_ptr) {
+ CTX_data_pointer_set(result, ptr.id.data, ptr.type, ptr.data);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "active_gpencil_layer")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ if (gpl) {
+ CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
+ return 1;
+ }
+ }
+ }
+ else if (CTX_data_equals(member, "active_gpencil_frame")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ if (gpl) {
+ CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe);
+ return 1;
+ }
+ }
+ }
+ else if (CTX_data_equals(member, "visible_gpencil_layers")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDlayer *gpl;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & GP_LAYER_HIDE) == 0) {
+ CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
+ }
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "editable_gpencil_layers")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDlayer *gpl;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
+ CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
+ }
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
+ /* XXX: see comment for gpencil_data case... */
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+
+ if (gpd) {
+ bGPDlayer *gpl;
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 && (gpl->actframe)) {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ }
+ }
+ }
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
else if (CTX_data_equals(member, "active_operator")) {
wmOperator *op = NULL;
@@ -399,8 +530,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
if (sfile) {
op = sfile->op;
}
- else if ((op = uiContextActiveOperator(C))) {
- /* do nothign */
+ else if ((op = UI_context_active_operator_get(C))) {
+ /* do nothing */
}
else {
/* note, this checks poll, could be a problem, but this also
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 5beab9fcc14..1a1cc8894e6 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -59,6 +59,7 @@
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
+#include "ED_node.h"
#include "ED_render.h"
#include "UI_interface.h"
@@ -1009,7 +1010,7 @@ static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir))
glDisable(GL_BLEND);
}
-static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, short a)
+static void drawscredge_area_draw(int sizex, int sizey, int x1, int y1, int x2, int y2, int a)
{
/* right border area */
if (x2 < sizex - 1)
@@ -1058,7 +1059,7 @@ bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
{
bScreen *newsc;
- if (sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
+ if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */
/* make new empty screen: */
newsc = ED_screen_add(win, sc->scene, sc->id.name + 2);
@@ -1313,7 +1314,8 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
if (screen->animtimer)
WM_event_remove_timer(wm, window, screen->animtimer);
screen->animtimer = NULL;
-
+ screen->scrubbing = false;
+
if (screen->mainwin)
wm_subwindow_close(window, screen->mainwin);
screen->mainwin = 0;
@@ -1439,7 +1441,7 @@ void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
/* this used to be a notifier, but needs to be done immediate
* because it can undo setting the right button as active due
* to delayed notifier handling */
- uiFreeActiveButtons(C, win->screen);
+ UI_screen_free_active_but(C, win->screen);
}
else
region_cursor_set(win, scr->subwinactive, false);
@@ -1467,25 +1469,26 @@ int ED_screen_area_active(const bContext *C)
return 0;
}
-/* operator call, WM + Window + screen already existed before */
-/* Do NOT call in area/region queues! */
-void ED_screen_set(bContext *C, bScreen *sc)
+/**
+ * operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns success.
+ */
+bool ED_screen_set(bContext *C, bScreen *sc)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
bScreen *oldscreen = CTX_wm_screen(C);
- ID *id;
/* validate screen, it's called with notifier reference */
- for (id = bmain->screen.first; id; id = id->next)
- if (sc == (bScreen *)id)
- break;
- if (id == NULL)
- return;
-
+ if (BLI_findindex(&bmain->screen, sc) == -1) {
+ return true;
+ }
- if (sc->full) { /* find associated full */
+ if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
+ /* find associated full */
bScreen *sc1;
for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) {
ScrArea *sa = sc1->areabase.first;
@@ -1497,8 +1500,9 @@ void ED_screen_set(bContext *C, bScreen *sc)
}
/* check for valid winid */
- if (sc->winid != 0 && sc->winid != win->winid)
- return;
+ if (sc->winid != 0 && sc->winid != win->winid) {
+ return false;
+ }
if (oldscreen != sc) {
wmTimer *wt = oldscreen->animtimer;
@@ -1558,60 +1562,75 @@ void ED_screen_set(bContext *C, bScreen *sc)
}
/* Always do visible update since it's possible new screen will
- * have different layers visible in 3D viewpots. This is possible
- * because of view3d.lock_camera_and_layers option.
+ * have different layers visible in 3D view-ports.
+ * This is possible because of view3d.lock_camera_and_layers option.
*/
DAG_on_visible_update(bmain, false);
}
+
+ return true;
}
-static int ed_screen_used(wmWindowManager *wm, bScreen *sc)
+static bool ed_screen_used(wmWindowManager *wm, bScreen *sc)
{
wmWindow *win;
- for (win = wm->windows.first; win; win = win->next)
- if (win->screen == sc)
- return 1;
-
- return 0;
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen == sc) {
+ return true;
+ }
+
+ if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ ScrArea *sa = win->screen->areabase.first;
+ if (sa->full == sc) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
/* only call outside of area/region loops */
-void ED_screen_delete(bContext *C, bScreen *sc)
+bool ED_screen_delete(bContext *C, bScreen *sc)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
bScreen *newsc;
- int delete = 1;
/* don't allow deleting temp fullscreens for now */
- if (sc->full == SCREENFULL) {
- return;
+ if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
+ return false;
}
-
-
+
/* screen can only be in use by one window at a time, so as
* long as we are able to find a screen that is unused, we
* can safely assume ours is not in use anywhere an delete it */
for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
- if (!ed_screen_used(wm, newsc))
+ if (!ed_screen_used(wm, newsc) && !newsc->temp)
break;
if (!newsc) {
for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
- if (!ed_screen_used(wm, newsc))
+ if (!ed_screen_used(wm, newsc) && !newsc->temp)
break;
}
- if (!newsc)
- return;
+ if (!newsc) {
+ return false;
+ }
ED_screen_set(C, newsc);
- if (delete && win->screen != sc)
+ if (win->screen != sc) {
BKE_libblock_free(bmain, sc);
+ return true;
+ }
+ else {
+ return false;
+ }
}
static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, View3D *v3d)
@@ -1705,8 +1724,11 @@ void ED_screen_set_scene(bContext *C, bScreen *screen, Scene *scene)
}
-/* only call outside of area/region loops */
-void ED_screen_delete_scene(bContext *C, Scene *scene)
+/**
+ * \note Only call outside of area/region loops
+ * \return true if successful
+ */
+bool ED_screen_delete_scene(bContext *C, Scene *scene)
{
Main *bmain = CTX_data_main(C);
Scene *newscene;
@@ -1716,11 +1738,13 @@ void ED_screen_delete_scene(bContext *C, Scene *scene)
else if (scene->id.next)
newscene = scene->id.next;
else
- return;
+ return false;
ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
BKE_scene_unlink(bmain, scene, newscene);
+
+ return true;
}
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
@@ -1730,11 +1754,11 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
ScrArea *newsa = NULL;
if (!sa || sa->full == NULL) {
- newsa = ED_screen_full_toggle(C, win, sa);
+ newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
}
if (!newsa) {
- if (sa->full) {
+ if (sa->full && (screen->state == SCREENMAXIMIZED)) {
/* if this has been called from the temporary info header generated in
* temp fullscreen layouts, find the correct fullscreen area to change
* to create a new space inside */
@@ -1747,20 +1771,54 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
newsa = sa;
}
}
-
+
+ BLI_assert(newsa);
+
+ if (sa && (sa->spacetype != type)) {
+ newsa->flag |= AREA_FLAG_TEMP_TYPE;
+ }
+ else {
+ newsa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ }
+
ED_area_newspace(C, newsa, type);
return newsa;
}
-void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
+/**
+ * \a was_prev_temp for the case previous space was a temporary fullscreen as well
+ */
+void ED_screen_full_prevspace(bContext *C, ScrArea *sa, const bool was_prev_temp)
{
- wmWindow *win = CTX_wm_window(C);
+ BLI_assert(sa->full);
+
+ if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
+ /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
+ ED_area_prevspace(C, sa);
+ /* only clear if previous space wasn't a temp fullscreen as well */
+ if (!was_prev_temp) {
+ sa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ }
+ }
+ else {
+ ED_screen_restore_temp_type(C, sa);
+ }
+}
- ED_area_prevspace(C, sa);
-
- if (sa->full)
- ED_screen_full_toggle(C, win, sa);
+void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
+{
+ /* incase nether functions below run */
+ ED_area_tag_redraw(sa);
+
+ if (sa->flag & AREA_FLAG_TEMP_TYPE) {
+ ED_area_prevspace(C, sa);
+ sa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ }
+
+ if (sa->full) {
+ ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ }
}
/* restore a screen / area back to default operation, after temp fullscreen modes */
@@ -1768,40 +1826,33 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
{
wmWindow *win = CTX_wm_window(C);
SpaceLink *sl = sa->spacedata.first;
+ bScreen *screen = CTX_wm_screen(C);
+ short state = (screen ? screen->state : SCREENMAXIMIZED);
- /* if fullscreen area has a secondary space (such as a file browser or fullscreen render
- * overlaid on top of a existing setup) then return to the previous space */
+ /* if fullscreen area has a temporary space (such as a file browser or fullscreen render
+ * overlaid on top of an existing setup) then return to the previous space */
if (sl->next) {
- /* specific checks for space types */
-
- /* Special check added for non-render image window (back from fullscreen through "Back to Previous" button) */
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
-
- if (sima->flag & (SI_PREVSPACE | SI_FULLWINDOW)) {
- sima->flag &= ~SI_PREVSPACE;
- sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
- }
- else
- ED_screen_full_toggle(C, win, sa);
- }
- else if (sl->spacetype == SPACE_FILE) {
- ED_screen_full_prevspace(C, sa);
+ if (sa->flag & AREA_FLAG_TEMP_TYPE) {
+ ED_screen_full_prevspace(C, sa, false);
}
else {
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, state);
}
+ /* warning: 'sa' may be freed */
}
/* otherwise just tile the area again */
else {
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, state);
}
}
-/* this function toggles: if area is full then the parent will be restored */
-ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
+/**
+ * this function toggles: if area is maximized/full then the parent will be restored
+ *
+ * \warning \a sa may be freed.
+ */
+ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1811,24 +1862,21 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
for (ar = sa->regionbase.first; ar; ar = ar->next)
- uiFreeBlocks(C, &ar->uiblocks);
-
+ UI_blocklist_free(C, &ar->uiblocks);
+
/* prevent hanging header prints */
ED_area_headerprint(sa, NULL);
}
if (sa && sa->full) {
+ /* restoring back to SCREENNORMAL */
ScrArea *old;
- /*short fulltype;*/ /*UNUSED*/
sc = sa->full; /* the old screen to restore */
oldscreen = win->screen; /* the one disappearing */
- /*fulltype = sc->full;*/
- sc->full = 0;
+ sc->state = SCREENNORMAL;
- /* removed: SCREENAUTOPLAY exception here */
-
/* find old area */
for (old = sc->areabase.first; old; old = old->next)
if (old->full) break;
@@ -1838,6 +1886,13 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
return NULL;
}
+ if (state == SCREENFULL) {
+ /* restore the old side panels/header visibility */
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ ar->flag = ar->flagfullscreen;
+ }
+ }
+
ED_area_data_swap(old, sa);
if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO;
old->full = NULL;
@@ -1851,46 +1906,74 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
BKE_screen_free(oldscreen);
BKE_libblock_free(CTX_data_main(C), oldscreen);
+ /* After we've restored back to SCREENNORMAL, we have to wait with
+ * screen handling as it uses the area coords which aren't updated yet.
+ * Without doing so, the screen handling gets wrong area coords,
+ * which in worst case can lead to crashes (see T43139) */
+ sc->skip_handling = true;
}
else {
+ /* change from SCREENNORMAL to new state */
ScrArea *newa;
char newname[MAX_ID_NAME - 2];
oldscreen = win->screen;
- /* nothing wrong with having only 1 area, as far as I can see...
- * is there only 1 area? */
-#if 0
- if (oldscreen->areabase.first == oldscreen->areabase.last)
- return NULL;
-#endif
-
- oldscreen->full = SCREENFULL;
- BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "full");
+ oldscreen->state = state;
+ BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
sc = ED_screen_add(win, oldscreen->scene, newname);
- sc->full = SCREENFULL; // XXX
+ sc->state = state;
+ sc->redraws_flag = oldscreen->redraws_flag;
/* timer */
sc->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- /* returns the top small area */
- newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
- ED_area_newspace(C, newa, SPACE_INFO);
-
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
if (!sa)
sa = oldscreen->areabase.first;
- /* copy area */
- newa = newa->prev;
- ED_area_data_swap(newa, sa);
- sa->flag |= AREA_TEMP_INFO;
+ if (state == SCREENMAXIMIZED) {
+ /* returns the top small area */
+ newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
+ ED_area_newspace(C, newa, SPACE_INFO);
+
+ /* copy area */
+ newa = newa->prev;
+ ED_area_data_swap(newa, sa);
+ sa->flag |= AREA_TEMP_INFO;
+
+ sa->full = oldscreen;
+ newa->full = oldscreen;
+ newa->next->full = oldscreen; // XXX
+ }
+ else if (state == SCREENFULL) {
+ newa = (ScrArea *)sc->areabase.first;
+
+ /* copy area */
+ ED_area_data_swap(newa, sa);
+ newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+
+ /* temporarily hide the side panels/header */
+ for (ar = newa->regionbase.first; ar; ar = ar->next) {
+ ar->flagfullscreen = ar->flag;
+
+ if (ELEM(ar->regiontype,
+ RGN_TYPE_UI,
+ RGN_TYPE_HEADER,
+ RGN_TYPE_TOOLS))
+ {
+ ar->flag |= RGN_FLAG_HIDDEN;
+ }
+ }
- sa->full = oldscreen;
- newa->full = oldscreen;
- newa->next->full = oldscreen; // XXX
+ sa->full = oldscreen;
+ newa->full = oldscreen;
+ }
+ else {
+ BLI_assert(false);
+ }
ED_screen_set(C, sc);
}
@@ -2049,7 +2132,7 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/* this function applies the changes too */
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, layers);
- //if ( (CFRA>1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB))
+ //if ((CFRA > 1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB))
// audiostream_scrub( CFRA );
/* 3d window, preview */
@@ -2073,4 +2156,85 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
}
+/*
+ * return true if any active area requires to see in 3D
+ */
+bool ED_screen_stereo3d_required(bScreen *screen)
+{
+ ScrArea *sa;
+ Scene *sce = screen->scene;
+ const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d;
+
+ if (!is_multiview)
+ continue;
+
+ v3d = sa->spacedata.first;
+ if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ return true;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima;
+
+ /* images should always show in stereo, even if
+ * the file doesn't have views enabled */
+ sima = sa->spacedata.first;
+ if (sima->image && (sima->image->flag & IMA_IS_STEREO) &&
+ (sima->iuser.flag & IMA_SHOW_STEREO))
+ {
+ return true;
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode;
+
+ if (!is_multiview)
+ continue;
+
+ snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ return true;
+ }
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq;
+
+ if (!is_multiview)
+ continue;
+
+ sseq = sa->spacedata.first;
+ if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
+ return true;
+ }
+
+ if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ return true;
+ }
+ break;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 9e0421b6e99..ccb6d5a6dca 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -32,10 +32,10 @@
#define __SCREEN_INTERN_H__
/* internal exports only */
-struct wmWindow;
-struct Scene;
#define AZONESPOT (0.6f * U.widget_unit)
+#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
+#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */
/* area.c */
void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 7c7574b3af3..4a1c1e34414 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -37,12 +37,13 @@
#include "BLI_dlrbTree.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_armature_types.h"
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_curve_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
#include "DNA_mask_types.h"
@@ -80,8 +81,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-
-#include "wm_window.h"
+#include "UI_view2d.h"
#include "screen_intern.h" /* own module include */
@@ -129,13 +129,31 @@ static int screen_active_editable(bContext *C)
{
if (ED_operator_screenactive(C)) {
/* no full window splitting allowed */
- if (CTX_wm_screen(C)->full != SCREENNORMAL)
+ if (CTX_wm_screen(C)->state != SCREENNORMAL)
return 0;
return 1;
}
return 0;
}
+static ARegion *screen_find_region_type(bContext *C, int type)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ /* find the header region
+ * - try context first, but upon failing, search all regions in area...
+ */
+ if ((ar == NULL) || (ar->regiontype != type)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ar = BKE_area_find_region_type(sa, type);
+ }
+ else {
+ ar = NULL;
+ }
+
+ return ar;
+}
+
/* when mouse is over area-edge */
int ED_operator_screen_mainwinactive(bContext *C)
{
@@ -374,7 +392,7 @@ int ED_operator_editarmature(bContext *C)
* \brief check for pose mode (no mixed modes)
*
* We want to enable most pose operations in weight paint mode,
- * when it comes to transforming bones, but managing bomes layers/groups
+ * when it comes to transforming bones, but managing bones layers/groups
* can be left for pose mode only. (not weight paint mode)
*/
int ED_operator_posemode_exclusive(bContext *C)
@@ -394,7 +412,7 @@ int ED_operator_posemode_exclusive(bContext *C)
}
/* allows for pinned pose objects to be used in the object buttons
- * and the the non-active pose object to be used in the 3D view */
+ * and the non-active pose object to be used in the 3D view */
int ED_operator_posemode_context(bContext *C)
{
Object *obpose = ED_pose_object_from_context(C);
@@ -581,19 +599,6 @@ typedef struct sActionzoneData {
int x, y, gesture_dir, modifier;
} sActionzoneData;
-/* used by other operators too */
-static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
-{
- ScrArea *sa = NULL;
- sa = scr->areabase.first;
- while (sa) {
- if (BLI_rcti_isect_pt(&sa->totrct, x, y)) break;
- sa = sa->next;
- }
-
- return sa;
-}
-
/* quick poll to save operators to be created and handled */
static int actionzone_area_poll(bContext *C)
{
@@ -611,6 +616,24 @@ static int actionzone_area_poll(bContext *C)
return 0;
}
+/* the debug drawing of the click_rect is in area_draw_azone_fullscreen, keep both in sync */
+static void fullscreen_click_rcti_init(rcti *rect, const short x1, const short y1, const short x2, const short y2)
+{
+ int x = x2 - ((float) x2 - x1) * 0.5f / UI_DPI_FAC;
+ int y = y2 - ((float) y2 - y1) * 0.5f / UI_DPI_FAC;
+ float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
+
+ /* adjust the icon distance from the corner */
+ x += 36.0f / UI_DPI_FAC;
+ y += 36.0f / UI_DPI_FAC;
+
+ /* draws from the left bottom corner of the icon */
+ x -= UI_DPI_ICON_SIZE;
+ y -= UI_DPI_ICON_SIZE;
+
+ BLI_rcti_init(rect, x, x + icon_size, y, y + icon_size);
+}
+
AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2])
{
AZone *az = NULL;
@@ -627,6 +650,42 @@ AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2])
else if (az->type == AZONE_REGION) {
break;
}
+ else if (az->type == AZONE_FULLSCREEN) {
+ int mouse_radius, spot_radius, fadein_radius, fadeout_radius;
+ rcti click_rect;
+
+ fullscreen_click_rcti_init(&click_rect, az->x1, az->y1, az->x2, az->y2);
+
+ if (BLI_rcti_isect_pt_v(&click_rect, xy)) {
+ az->alpha = 1.0f;
+ }
+ else {
+ mouse_radius = (xy[0] - az->x2) * (xy[0] - az->x2) + (xy[1] - az->y2) * (xy[1] - az->y2);
+ spot_radius = AZONESPOT * AZONESPOT;
+ fadein_radius = AZONEFADEIN * AZONEFADEIN;
+ fadeout_radius = AZONEFADEOUT * AZONEFADEOUT;
+
+ if (mouse_radius < spot_radius) {
+ az->alpha = 1.0f;
+ }
+ else if (mouse_radius < fadein_radius) {
+ az->alpha = 1.0f;
+ }
+ else if (mouse_radius < fadeout_radius) {
+ az->alpha = 1.0f - ((float)(mouse_radius - fadein_radius)) / ((float)(fadeout_radius - fadein_radius));
+ }
+ else {
+ az->alpha = 0.0f;
+ }
+
+ /* fade in/out but no click */
+ az = NULL;
+ }
+
+ /* XXX force redraw to show/hide the action zone */
+ ED_area_tag_redraw(sa);
+ break;
+ }
}
}
@@ -654,9 +713,12 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
if (type == AZONE_AREA)
event.type = EVT_ACTIONZONE_AREA;
+ else if (type == AZONE_FULLSCREEN)
+ event.type = EVT_ACTIONZONE_FULLSCREEN;
else
event.type = EVT_ACTIONZONE_REGION;
- event.val = 0;
+
+ event.val = KM_NOTHING;
event.customdata = op->customdata;
event.customdatafree = true;
op->customdata = NULL;
@@ -666,7 +728,8 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- AZone *az = is_in_area_actionzone(CTX_wm_area(C), &event->x);
+ ScrArea *sa = CTX_wm_area(C);
+ AZone *az = is_in_area_actionzone(sa, &event->x);
sActionzoneData *sad;
/* quick escape */
@@ -675,13 +738,13 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* ok we do the actionzone */
sad = op->customdata = MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
- sad->sa1 = CTX_wm_area(C);
+ sad->sa1 = sa;
sad->az = az;
sad->x = event->x; sad->y = event->y;
/* region azone directly reacts on mouse clicks */
- if (sad->az->type == AZONE_REGION) {
- actionzone_apply(C, op, AZONE_REGION);
+ if (ELEM(sad->az->type, AZONE_REGION, AZONE_FULLSCREEN)) {
+ actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
return OPERATOR_FINISHED;
}
@@ -734,7 +797,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = screen_areahascursor(sc, event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -855,7 +918,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
/* second area, for join */
- sad->sa2 = screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
break;
case LEFTMOUSE: /* release LMB */
if (event->val == KM_RELEASE) {
@@ -929,6 +992,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
newwin = WM_window_open(C, &rect);
+ *newwin->stereo3d_format = *win->stereo3d_format;
/* allocs new screen and adds to newly created window, using window size */
newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2);
@@ -1462,7 +1526,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int dir;
/* no full window splitting allowed */
- if (sc->full != SCREENNORMAL)
+ if (sc->state != SCREENNORMAL)
return OPERATOR_CANCELLED;
if (event->type == EVT_ACTIONZONE_AREA) {
@@ -1605,7 +1669,8 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V);
ED_area_tag_redraw(sd->sarea);
}
- sd->sarea = screen_areahascursor(CTX_wm_screen(C), event->x, event->y); /* area context not set */
+ /* area context not set */
+ sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
if (sd->sarea) {
ED_area_tag_redraw(sd->sarea);
@@ -1866,6 +1931,12 @@ static void region_scale_validate_size(RegionMoveData *rmd)
static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
{
+ /* hidden areas may have bad 'View2D.cur' value,
+ * correct before displaying. see T45156 */
+ if (rmd->ar->flag & RGN_FLAG_HIDDEN) {
+ UI_view2d_curRect_validate(&rmd->ar->v2d);
+ }
+
region_toggle_hidden(C, rmd->ar, 0);
region_scale_validate_size(rmd);
}
@@ -1980,6 +2051,48 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot)
/* ************** frame change operator ***************************** */
+static void areas_do_frame_follow(bContext *C, bool middle)
+{
+ bScreen *scr = CTX_wm_screen(C);
+ Scene *scene = CTX_data_scene(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *window;
+ for (window = wm->windows.first; window; window = window->next) {
+ ScrArea *sa;
+ for (sa = window->screen->areabase.first; sa; sa = sa->next) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ /* do follow here if editor type supports it */
+ if ((scr->redraws_flag & TIME_FOLLOW)) {
+ if ((ar->regiontype == RGN_TYPE_WINDOW &&
+ ELEM(sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ (sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
+ {
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+
+ if (middle) {
+ if ((scene->r.cfra < ar->v2d.cur.xmin) || (scene->r.cfra > ar->v2d.cur.xmax)) {
+ ar->v2d.cur.xmax = scene->r.cfra + (w / 2);
+ ar->v2d.cur.xmin = scene->r.cfra - (w / 2);
+ }
+ }
+ else {
+ if (scene->r.cfra < ar->v2d.cur.xmin) {
+ ar->v2d.cur.xmax = scene->r.cfra;
+ ar->v2d.cur.xmin = ar->v2d.cur.xmax - w;
+ }
+ else if (scene->r.cfra > ar->v2d.cur.xmax) {
+ ar->v2d.cur.xmin = scene->r.cfra;
+ ar->v2d.cur.xmax = ar->v2d.cur.xmin + w;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
/* function to be called outside UI context, or for redo */
static int frame_offset_exec(bContext *C, wmOperator *op)
{
@@ -1993,7 +2106,9 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
FRAMENUMBER_MIN_CLAMP(CFRA);
SUBFRA = 0.f;
- sound_seek_scene(bmain, scene);
+ areas_do_frame_follow(C, false);
+
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2043,7 +2158,9 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
else
CFRA = PSFRA;
- sound_seek_scene(bmain, scene);
+ areas_do_frame_follow(C, true);
+
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -2075,6 +2192,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
bDopeSheet ads = {NULL};
DLRBT_Tree keys;
ActKeyColumn *ak;
@@ -2102,7 +2220,9 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
if (ob)
ob_to_keylist(&ads, ob, &keys, NULL);
-
+
+ gpencil_to_keylist(&ads, gpd, &keys);
+
{
Mask *mask = CTX_data_edit_mask(C);
if (mask) {
@@ -2144,7 +2264,9 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- sound_seek_scene(bmain, scene);
+ areas_do_frame_follow(C, true);
+
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2204,7 +2326,9 @@ static int marker_jump_exec(bContext *C, wmOperator *op)
else {
CFRA = closest;
- sound_seek_scene(bmain, scene);
+ areas_do_frame_follow(C, true);
+
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2231,8 +2355,11 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev)
{
- return ((screen->winid == 0) &&
- (screen->full == 0) &&
+ return ((screen->winid == 0) &&
+ /* in typical usage these should have a nonzero winid
+ * (all temp screens should be used, or closed & freed). */
+ (screen->temp == false) &&
+ (screen->state == SCREENNORMAL) &&
(screen != screen_prev) &&
(screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
}
@@ -2245,12 +2372,13 @@ static int screen_set_exec(bContext *C, wmOperator *op)
bScreen *screen_prev = screen;
ScrArea *sa = CTX_wm_area(C);
- int tot = BLI_countlist(&bmain->screen);
+ int tot = BLI_listbase_count(&bmain->screen);
int delta = RNA_int_get(op->ptr, "delta");
/* temp screens are for userpref or render display */
- if (screen->temp)
+ if (screen->temp || (sa && sa->full && sa->full->temp)) {
return OPERATOR_CANCELLED;
+ }
if (delta == 1) {
while (tot--) {
@@ -2303,10 +2431,11 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot)
/* function to be called outside UI context, or for redo */
-static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
+static int screen_maximize_area_exec(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *sa = NULL;
+ const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
/* search current screen for 'fullscreen' areas */
/* prevents restoring info header, when mouse is over it */
@@ -2314,25 +2443,41 @@ static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
if (sa->full) break;
}
- if (sa == NULL) sa = CTX_wm_area(C);
+ if (sa == NULL) {
+ sa = CTX_wm_area(C);
+ }
- ED_screen_full_toggle(C, CTX_wm_window(C), sa);
+ if (hide_panels) {
+ if (!ELEM(screen->state, SCREENNORMAL, SCREENFULL)) {
+ return OPERATOR_CANCELLED;
+ }
+ ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENFULL);
+ }
+ else {
+ if (!ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
+ return OPERATOR_CANCELLED;
+ }
+ ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ }
+
return OPERATOR_FINISHED;
}
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
- ot->name = "Toggle Full Screen";
- ot->description = "Toggle display selected area as fullscreen";
+ PropertyRNA *prop;
+
+ ot->name = "Toggle Fullscreen Area";
+ ot->description = "Toggle display selected area as fullscreen/maximized";
ot->idname = "SCREEN_OT_screen_full_area";
- ot->exec = screen_full_area_exec;
+ ot->exec = screen_maximize_area_exec;
ot->poll = ED_operator_areaactive;
ot->flag = 0;
-
-}
-
+ prop = RNA_def_boolean(ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
/* ************** join area operator ********************************************** */
@@ -2388,8 +2533,8 @@ static int area_join_init(bContext *C, wmOperator *op)
x2 = RNA_int_get(op->ptr, "max_x");
y2 = RNA_int_get(op->ptr, "max_y");
- sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
- sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
+ sa1 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x1, y1);
+ sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x2, y2);
if (sa1 == NULL || sa2 == NULL || sa1 == sa2)
return 0;
@@ -2522,7 +2667,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
{
- ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
+ ScrArea *sa = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
int dir;
if (sa) {
@@ -2645,8 +2790,8 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
if (actedge == NULL) return OPERATOR_CANCELLED;
- pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
WM_operator_properties_create(&ptr1, "SCREEN_OT_area_join");
@@ -2665,9 +2810,9 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, ptr2.data, WM_OP_INVOKE_DEFAULT, 0);
uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, ptr1.data, WM_OP_INVOKE_DEFAULT, 0);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
static void SCREEN_OT_area_options(wmOperatorType *ot)
@@ -2703,7 +2848,7 @@ static int spacedata_cleanup_exec(bContext *C, wmOperator *op)
SpaceLink *sl = sa->spacedata.first;
BLI_remlink(&sa->spacedata, sl);
- tot += BLI_countlist(&sa->spacedata);
+ tot += BLI_listbase_count(&sa->spacedata);
BKE_spacedata_freelist(&sa->spacedata);
BLI_addtail(&sa->spacedata, sl);
}
@@ -2761,20 +2906,20 @@ static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
uiLayout *layout;
int items, i;
- items = BLI_countlist(&wm->operators);
+ items = BLI_listbase_count(&wm->operators);
if (items == 0)
return OPERATOR_CANCELLED;
- pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
for (i = items - 1, lastop = wm->operators.last; lastop; lastop = lastop->prev, i--)
if (WM_operator_repeat_check(C, lastop))
uiItemIntO(layout, RNA_struct_ui_name(lastop->type->srna), ICON_NONE, op->type->idname, "index", i);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
static int repeat_history_exec(bContext *C, wmOperator *op)
@@ -3027,23 +3172,44 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
ot->flag = 0;
}
+/* ************** header operator ***************************** */
+static int header_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ARegion *ar = screen_find_region_type(C, RGN_TYPE_HEADER);
+
+ if (ar == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ar->flag ^= RGN_FLAG_HIDDEN;
+
+ ED_area_tag_redraw(CTX_wm_area(C));
+
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_header(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Header";
+ ot->description = "Display header";
+ ot->idname = "SCREEN_OT_header";
+
+ /* api callbacks */
+ ot->exec = header_exec;
+}
+
/* ************** header flip operator ***************************** */
/* flip a header region alignment */
static int header_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
- ARegion *ar = CTX_wm_region(C);
-
- /* find the header region
- * - try context first, but upon failing, search all regions in area...
- */
- if ((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
- ScrArea *sa = CTX_wm_area(C);
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ARegion *ar = screen_find_region_type(C, RGN_TYPE_HEADER);
- /* don't do anything if no region */
- if (ar == NULL)
- return OPERATOR_CANCELLED;
+ if (ar == NULL) {
+ return OPERATOR_CANCELLED;
}
/* copied from SCREEN_OT_region_flip */
@@ -3142,14 +3308,14 @@ static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, IFACE_("Header"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
ED_screens_header_tools_menu_create(C, layout, NULL);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
static void SCREEN_OT_header_toolbox(wmOperatorType *ot)
@@ -3260,10 +3426,17 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 0;
}
+//#define PROFILE_AUDIO_SYNCH
+
static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
+#ifdef PROFILE_AUDIO_SYNCH
+ static int old_frame = 0;
+ int newfra_int;
+#endif
+
if (screen->animtimer && screen->animtimer == event->customdata) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -3282,9 +3455,27 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if ((scene->audio.flag & AUDIO_SYNC) &&
(sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
- finite(time = sound_sync_scene(scene)))
+ finite(time = BKE_sound_sync_scene(scene)))
{
- scene->r.cfra = (double)time * FPS + 0.5;
+ double newfra = (double)time * FPS;
+
+ /* give some space here to avoid jumps */
+ if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra)
+ scene->r.cfra++;
+ else
+ scene->r.cfra = newfra + 0.5;
+
+#ifdef PROFILE_AUDIO_SYNCH
+ newfra_int = scene->r.cfra;
+ if (newfra_int < old_frame) {
+ printf("back jump detected, frame %d!\n", newfra_int);
+ }
+ else if (newfra_int > old_frame + 1) {
+ printf("forward jump detected, frame %d!\n", newfra_int);
+ }
+ fflush(stdout);
+ old_frame = newfra_int;
+#endif
}
else {
if (sync) {
@@ -3351,8 +3542,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
sad->flag |= ANIMPLAY_FLAG_JUMPED;
}
- if (sad->flag & ANIMPLAY_FLAG_JUMPED)
- sound_seek_scene(bmain, scene);
+ if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
+ BKE_sound_seek_scene(bmain, scene);
+#ifdef PROFILE_AUDIO_SYNCH
+ old_frame = CFRA;
+#endif
+ }
/* since we follow drawflags, we can't send notifier but tag regions ourselves */
ED_update_for_newframe(bmain, scene, 1);
@@ -3361,11 +3556,33 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
for (sa = window->screen->areabase.first; sa; sa = sa->next) {
ARegion *ar;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ bool redraw = false;
if (ar == sad->ar) {
- ED_region_tag_redraw(ar);
+ redraw = true;
}
else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
+ redraw = true;
+ }
+
+ if (redraw) {
ED_region_tag_redraw(ar);
+ /* do follow here if editor type supports it */
+ if ((sad->redraws & TIME_FOLLOW)) {
+ if ((ar->regiontype == RGN_TYPE_WINDOW &&
+ ELEM(sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ (sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
+ {
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+ if (scene->r.cfra < ar->v2d.cur.xmin) {
+ ar->v2d.cur.xmax = scene->r.cfra;
+ ar->v2d.cur.xmin = ar->v2d.cur.xmax - w;
+ }
+ else if (scene->r.cfra > ar->v2d.cur.xmax) {
+ ar->v2d.cur.xmin = scene->r.cfra;
+ ar->v2d.cur.xmax = ar->v2d.cur.xmin + w;
+ }
+ }
+ }
}
}
@@ -3410,15 +3627,31 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
- wmWindow *window;
+ wmWindow *win;
+
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen->animtimer || win->screen->scrubbing) {
+ return win->screen;
+ }
+ }
- for (window = wm->windows.first; window; window = window->next)
- if (window->screen->animtimer)
- return window->screen;
-
return NULL;
}
+bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
+{
+ wmWindow *win;
+
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen->animtimer) {
+ return win->screen;
+ }
+ }
+
+ return NULL;
+}
+
+
/* toggle operator */
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
@@ -3428,13 +3661,15 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0, 0);
- sound_stop_scene(scene);
+ BKE_sound_stop_scene(scene);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
else {
int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) /* XXX only play audio forwards!? */
- sound_play_scene(scene);
+ BKE_sound_play_scene(scene);
ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);
@@ -3590,9 +3825,9 @@ static int fullscreen_back_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
return OPERATOR_CANCELLED;
}
-
- ED_screen_full_restore(C, sa);
-
+
+ ED_screen_full_prevspace(C, sa, false);
+
return OPERATOR_FINISHED;
}
@@ -3755,7 +3990,9 @@ static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- ED_screen_delete_scene(C, scene);
+ if (ED_screen_delete_scene(C, scene) == false) {
+ return OPERATOR_CANCELLED;
+ }
if (G.debug & G_DEBUG)
printf("scene delete %p\n", scene);
@@ -3945,6 +4182,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_region_scale);
WM_operatortype_append(SCREEN_OT_region_flip);
WM_operatortype_append(SCREEN_OT_header_flip);
+ WM_operatortype_append(SCREEN_OT_header);
WM_operatortype_append(SCREEN_OT_header_toggle_menus);
WM_operatortype_append(SCREEN_OT_header_toolbox);
WM_operatortype_append(SCREEN_OT_screen_set);
@@ -4042,11 +4280,14 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", EVT_ACTIONZONE_FULLSCREEN, 0, 0, 0);
+ RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
/* area move after action zones */
WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_area_options", RIGHTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "SCREEN_OT_header", F9KEY, KM_PRESS, KM_ALT, 0);
/* Header Editing ------------------------------------------------ */
keymap = WM_keymap_find(keyconf, "Header", 0, 0);
@@ -4066,6 +4307,9 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", F10KEY, KM_PRESS, KM_ALT, 0);
+ RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
+
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index be5fd48b41a..a701fc9ccb7 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -65,7 +65,6 @@
#include "PIL_time.h"
-#include "ED_screen_types.h"
#include "screen_intern.h"
@@ -287,8 +286,8 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
ot->flag = 0;
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "full", 1, "Full Screen",
"Capture the whole window (otherwise only capture the active area)");
}
@@ -304,6 +303,9 @@ typedef struct ScreenshotJob {
const short *stop;
const short *do_update;
ReportList reports;
+
+ bMovieHandle *movie_handle;
+ void *movie_ctx;
} ScreenshotJob;
@@ -313,7 +315,13 @@ static void screenshot_freejob(void *sjv)
if (sj->dumprect)
MEM_freeN(sj->dumprect);
-
+
+ if (sj->movie_handle) {
+ bMovieHandle *mh = sj->movie_handle;
+ mh->end_movie(sj->movie_ctx);
+ mh->context_free(sj->movie_ctx);
+ }
+
MEM_freeN(sj);
}
@@ -338,20 +346,26 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
{
ScreenshotJob *sj = sjv;
RenderData rd = sj->scene->r;
- bMovieHandle *mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
-
+ bMovieHandle *mh = NULL;
+
/* we need this as local variables for renderdata */
rd.frs_sec = U.scrcastfps;
rd.frs_sec_base = 1.0f;
if (BKE_imtype_is_movie(rd.im_format.imtype)) {
- if (!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports)) {
+ mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
+ if (mh == NULL) {
+ printf("Movie format unsupported\n");
+ return;
+ }
+ sj->movie_ctx = mh->context_create();
+ sj->movie_handle = mh;
+
+ if (!mh->start_movie(sj->movie_ctx, sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports, false, "")) {
printf("screencast job stopped\n");
return;
}
}
- else
- mh = NULL;
sj->stop = stop;
sj->do_update = do_update;
@@ -363,8 +377,8 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
if (sj->dumprect) {
if (mh) {
- if (mh->append_movie(&rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
- sj->dumpsx, sj->dumpsy, &sj->reports))
+ if (mh->append_movie(sj->movie_ctx, &rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
+ sj->dumpsx, sj->dumpsy, "", &sj->reports))
{
BKE_reportf(&sj->reports, RPT_INFO, "Appended frame: %d", rd.cfra);
printf("Appended frame %d\n", rd.cfra);
@@ -378,8 +392,9 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
char name[FILE_MAX];
int ok;
- BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra,
- &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ name, rd.pic, sj->bmain->name, rd.cfra,
+ &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true, NULL);
ibuf->rect = sj->dumprect;
ok = BKE_imbuf_write(ibuf, name, &rd.im_format);
@@ -410,8 +425,11 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
PIL_sleep_ms(U.scrcastwait);
}
- if (mh)
- mh->end_movie();
+ if (mh) {
+ mh->end_movie(sj->movie_ctx);
+ mh->context_free(sj->movie_ctx);
+ sj->movie_handle = NULL;
+ }
BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped");
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 18db57c9f21..46753df4e13 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -23,7 +23,7 @@ set(INC
../uvedit
../../blenkernel
../../blenlib
- ../../blenfont
+ ../../blentranslation
../../bmesh
../../gpu
../../imbuf
@@ -32,6 +32,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,4 +65,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_sculpt_paint "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index b0118fbbf53..52fab472189 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -30,15 +30,17 @@ Import ('env')
sources = env.Glob('*.c')
defs = []
+defs += env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../uvedit',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../imbuf',
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 7b9ede38b39..e19756c6a35 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -426,7 +426,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
len = sqrtf(x * x + y * y);
if (len <= 1) {
- float avg = BKE_brush_curve_strength_clamp(br, len, 1.0f); /* Falloff curve */
+ float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
buffer[index] = 255 - (GLubyte)(255 * avg);
@@ -521,14 +521,15 @@ static int project_brush_radius(ViewContext *vc,
}
}
-static int sculpt_get_brush_geometry(bContext *C, ViewContext *vc,
- int x, int y, int *pixel_radius,
- float location[3])
+static bool sculpt_get_brush_geometry(
+ bContext *C, ViewContext *vc,
+ int x, int y, int *pixel_radius,
+ float location[3])
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
float mouse[2];
- int hit;
+ bool hit;
mouse[0] = x;
mouse[1] = y;
@@ -594,7 +595,7 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush,
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
/* brush rotation */
glTranslatef(0.5, 0.5, 0);
- glRotatef((double)RAD2DEGF(ups->brush_rotation),
+ glRotatef((double)RAD2DEGF((primary) ? ups->brush_rotation : ups->brush_rotation_sec),
0.0, 0.0, 1.0);
glTranslatef(-0.5f, -0.5f, 0);
@@ -643,24 +644,20 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush,
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
if (primary)
- glTranslatef(brush->stencil_pos[0], brush->stencil_pos[1], 0);
+ glTranslate2fv(brush->stencil_pos);
else
- glTranslatef(brush->mask_stencil_pos[0], brush->mask_stencil_pos[1], 0);
+ glTranslate2fv(brush->mask_stencil_pos);
glRotatef(RAD2DEGF(mtex->rot), 0, 0, 1);
glMatrixMode(GL_TEXTURE);
}
/* set quad color. Colored overlay does not get blending */
- if (col)
- glColor4f(1.0,
- 1.0,
- 1.0,
- overlay_alpha / 100.0f);
- else
- glColor4f(U.sculpt_paint_overlay_col[0],
- U.sculpt_paint_overlay_col[1],
- U.sculpt_paint_overlay_col[2],
- overlay_alpha / 100.0f);
+ if (col) {
+ glColor4f(1.0, 1.0, 1.0, overlay_alpha / 100.0f);
+ }
+ else {
+ glColor4f(UNPACK3(U.sculpt_paint_overlay_col), overlay_alpha / 100.0f);
+ }
/* draw textured quad */
glBegin(GL_QUADS);
@@ -728,7 +725,7 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush,
do_pop = true;
glPushMatrix();
glLoadIdentity();
- glTranslatef(center[0], center[1], 0);
+ glTranslate2fv(center);
glScalef(ups->size_pressure_value, ups->size_pressure_value, 1);
glTranslatef(-center[0], -center[1], 0);
}
@@ -759,7 +756,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
ViewContext *vc, int x, int y, float zoom, PaintMode mode)
{
/* color means that primary brush texture is colured and secondary is used for alpha/mask control */
- bool col = ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false;
+ bool col = ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex) ? true : false;
OverlayControlFlags flags = BKE_paint_get_overlay_flags();
/* save lots of GL state
* TODO: check on whether all of these are needed? */
@@ -785,7 +782,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
else {
- if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY))
+ if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != ePaintWeight))
paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
@@ -958,21 +955,32 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewCon
}
}
+static bool ommit_cursor_drawing(Paint *paint, PaintMode mode, Brush *brush)
+{
+ if (paint->flags & PAINT_SHOW_BRUSH) {
+ if (ELEM(mode, ePaintTexture2D, ePaintTextureProjective) && brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
ViewContext vc;
- PaintMode mode;
float final_radius;
float translation[2];
float outline_alpha, *outline_col;
float zoomx, zoomy;
-
+
/* check that brush drawing is enabled */
- if (!(paint->flags & PAINT_SHOW_BRUSH))
+ if (ommit_cursor_drawing(paint, mode, brush))
return;
/* can't use stroke vc here because this will be called during
@@ -981,7 +989,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
get_imapaint_zoom(C, &zoomx, &zoomy);
zoomx = max_ff(zoomx, zoomy);
- mode = BKE_paintmode_get_active_from_context(C);
/* skip everything and draw brush here */
if (brush->flag & BRUSH_CURVE) {
@@ -999,9 +1006,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
if (!ups->stroke_active) {
- if (brush->flag & BRUSH_RAKE)
- /* here, translation contains the mouse coordinates. */
- paint_calculate_rake_rotation(ups, translation);
+ paint_calculate_rake_rotation(ups, brush, translation);
}
/* draw overlay */
@@ -1009,9 +1014,10 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* TODO: as sculpt and other paint modes are unified, this
* special mode of drawing will go away */
- if ((mode == PAINT_SCULPT) && vc.obact->sculpt) {
+ if ((mode == ePaintSculpt) && vc.obact->sculpt) {
float location[3];
- int pixel_radius, hit;
+ int pixel_radius;
+ bool hit;
/* test if brush is over the mesh */
hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location);
@@ -1022,8 +1028,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* check if brush is subtracting, use different color then */
/* TODO: no way currently to know state of pen flip or
* invert key modifier without starting a stroke */
- if ((!(ups->draw_inverted) ^
- !(brush->flag & BRUSH_DIR_IN)) &&
+ if (((ups->draw_inverted == 0) ^
+ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW,
SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
@@ -1050,7 +1056,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha);
/* draw brush outline */
- glTranslatef(translation[0], translation[1], 0);
+ glTranslate2fv(translation);
/* draw an inner brush */
if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 8c7c3b102e3..2f27db835f5 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -108,7 +108,7 @@ static void paintcurve_undo_restore(bContext *C, ListBase *lb)
uc = (UndoCurve *)lb->first;
- if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) {
+ if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) {
SWAP(PaintCurvePoint *, pc->points, uc->points);
SWAP(int, pc->tot_points, uc->tot_points);
SWAP(int, pc->add_index, uc->active_point);
@@ -134,12 +134,12 @@ static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc)
UndoCurve *uc;
switch (mode) {
- case PAINT_TEXTURE_2D:
- case PAINT_TEXTURE_PROJECTIVE:
+ case ePaintTexture2D:
+ case ePaintTextureProjective:
undo_stack_id = UNDO_PAINT_IMAGE;
break;
- case PAINT_SCULPT:
+ case ePaintSculpt:
undo_stack_id = UNDO_PAINT_MESH;
break;
@@ -222,6 +222,28 @@ static int paintcurve_point_co_index(char sel)
return i;
}
+static char paintcurve_point_side_index(const BezTriple *bezt, const bool is_first, const char fallback)
+{
+ /* when matching, guess based on endpoint side */
+ if (BEZT_ISSEL_ANY(bezt)) {
+ if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
+ return is_first ? SEL_F1 : SEL_F3;
+ }
+ else if (bezt->f1 & SELECT) {
+ return SEL_F1;
+ }
+ else if (bezt->f3 & SELECT) {
+ return SEL_F3;
+ }
+ else {
+ return fallback;
+ }
+ }
+ else {
+ return 0;
+ }
+}
+
/******************* Operators *********************************/
static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
@@ -295,10 +317,17 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
for (i = 0; i < pc->tot_points; i++) {
pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
}
- pcp[add_index].bez.f3 = SELECT;
- pcp[add_index].bez.h2 = HD_ALIGN;
- pc->add_index = add_index + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, add_index);
+
+ if (pc->add_index != 0) {
+ pcp[add_index].bez.f3 = SELECT;
+ pcp[add_index].bez.h2 = HD_ALIGN;
+ }
+ else {
+ pcp[add_index].bez.f1 = SELECT;
+ pcp[add_index].bez.h1 = HD_ALIGN;
+ }
WM_paint_cursor_tag_redraw(window, ar);
}
@@ -329,7 +358,7 @@ void PAINTCURVE_OT_add_point(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add New Paint Curve Point";
- ot->description = "Add new paint curve point";
+ ot->description = ot->name;
ot->idname = "PAINTCURVE_OT_add_point";
/* api callbacks */
@@ -366,7 +395,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
#define DELETE_TAG 2
for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
- if ((pcp->bez.f1 & SELECT) || (pcp->bez.f2 & SELECT) || (pcp->bez.f3 & SELECT)) {
+ if (BEZT_ISSEL_ANY(&pcp->bez)) {
pcp->bez.f2 |= DELETE_TAG;
tot_del++;
}
@@ -384,7 +413,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
points_new[j] = pc->points[i];
if ((i + 1) == pc->add_index) {
- pc->add_index = j + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, j);
}
j++;
}
@@ -410,8 +439,8 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
void PAINTCURVE_OT_delete_point(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add New Paint Curve Point";
- ot->description = "Add new paint curve point";
+ ot->name = "Remove Paint Curve Point";
+ ot->description = ot->name;
ot->idname = "PAINTCURVE_OT_delete_point";
/* api callbacks */
@@ -469,7 +498,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
if (pcp) {
- pc->add_index = (pcp - pc->points) + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
if (selflag == SEL_F2) {
if (extend)
@@ -599,9 +628,8 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
pcp = NULL;
/* just find first selected point */
for (i = 0; i < pc->tot_points; i++) {
- if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) {
+ if ((select = paintcurve_point_side_index(&pc->points[i].bez, i == 0, SEL_F3))) {
pcp = &pc->points[i];
- select = SEL_F3;
break;
}
}
@@ -631,7 +659,7 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* only select the active point */
PAINT_CURVE_POINT_SELECT(pcp, psd->select);
- pc->add_index = (pcp - pc->points) + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
WM_event_add_modal_handler(C, op);
WM_paint_cursor_tag_redraw(window, ar);
@@ -709,17 +737,17 @@ static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op))
const char *name;
switch (mode) {
- case PAINT_TEXTURE_2D:
- case PAINT_TEXTURE_PROJECTIVE:
+ case ePaintTexture2D:
+ case ePaintTextureProjective:
name = "PAINT_OT_image_paint";
break;
- case PAINT_WEIGHT:
+ case ePaintWeight:
name = "PAINT_OT_weight_paint";
break;
- case PAINT_VERTEX:
+ case ePaintVertex:
name = "PAINT_OT_vertex_paint";
break;
- case PAINT_SCULPT:
+ case ePaintSculpt:
name = "SCULPT_OT_brush_stroke";
break;
default:
@@ -749,7 +777,7 @@ static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const w
PaintMode mode = BKE_paintmode_get_active_from_context(C);
switch (mode) {
- case PAINT_TEXTURE_2D:
+ case ePaintTexture2D:
{
ARegion *ar = CTX_wm_region(C);
SpaceImage *sima = CTX_wm_space_image(C);
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index f1c91d0fcb5..2f1d4cd4194 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -98,7 +98,7 @@ static void partialvis_update_mesh(Object *ob,
Mesh *me = ob->data;
MVert *mvert;
const float *paint_mask;
- int *vert_indices;
+ const int *vert_indices;
int totvert, i;
bool any_changed = false, any_visible = false;
@@ -150,7 +150,7 @@ static void partialvis_update_grids(Object *ob,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node,
&grid_indices, &totgrid, NULL, NULL,
- &grids, NULL);
+ &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
BKE_pbvh_get_grid_key(pbvh, &key);
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 0e3592f59ee..f0c9c023876 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -45,31 +45,24 @@
#include "BLI_utildefines.h"
#include "BLI_threads.h"
-#include "PIL_time.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "DNA_brush_types.h"
-#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
-#include "BKE_mesh.h"
#include "BKE_node.h"
#include "BKE_paint.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_texture.h"
-#include "BKE_colortools.h"
-
-#include "BKE_editmesh.h"
#include "UI_view2d.h"
@@ -84,9 +77,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "GPU_draw.h"
+#include "GPU_buffers.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -99,7 +92,7 @@ typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
char idname[MAX_ID_NAME]; /* name instead of pointer*/
- char ibufname[IB_FILENAME_SIZE];
+ char ibufname[IMB_FILENAME_SIZE];
union {
float *fp;
@@ -165,9 +158,10 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, Cop
}
}
else {
- if (mode == RESTORE_COPY)
+ if (mode == RESTORE_COPY) {
IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ }
/* swap to the tmpbuf for easy copying */
if (ibuf->rect_float) {
SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
@@ -199,7 +193,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
for (tile = lb->first; tile; tile = tile->next) {
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
if (tile->use_float == use_float) {
- if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0) {
+ if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) {
if (mask) {
/* allocate mask if requested */
if (!tile->mask) {
@@ -221,7 +215,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
return NULL;
}
-void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -232,7 +226,7 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
/* check if tile is already pushed */
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (!proj) {
+ if (find_prev) {
data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
if (data)
return data;
@@ -334,7 +328,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
short use_float;
/* find image based on name, pointer becomes invalid with global undo */
- if (ima && strcmp(tile->idname, ima->id.name) == 0) {
+ if (ima && STREQ(tile->idname, ima->id.name)) {
/* ima is valid */
}
else {
@@ -343,7 +337,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ima && ibuf && strcmp(tile->ibufname, ibuf->name) != 0) {
+ if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
/* current ImBuf filename was changed, probably current frame
* was changed when painting on image sequence, rather than storing
* full image user (which isn't so obvious, btw) try to find ImBuf with
@@ -451,7 +445,7 @@ void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int
*ty = (y >> IMAPAINT_TILE_BITS);
}
-void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
{
ImBuf *tmpibuf = NULL;
int tilex, tiley, tilew, tileh, tx, ty;
@@ -480,7 +474,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false);
+ image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -505,7 +499,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int w = imapaintpartial.x2 - imapaintpartial.x1;
int h = imapaintpartial.y2 - imapaintpartial.y1;
/* Testing with partial update in uv editor too */
- GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
+ GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
}
}
@@ -527,8 +521,11 @@ BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
kernel->pixel_len = radius;
}
else {
- radius = br->blur_kernel_radius;
+ if (br->blur_kernel_radius <= 0)
+ br->blur_kernel_radius = 1;
+ radius = br->blur_kernel_radius;
+
side = kernel->side = radius * 2 + 1;
kernel->side_squared = kernel->side * kernel->side;
kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
@@ -543,11 +540,11 @@ BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
case KERNEL_GAUSSIAN:
{
- /* at standard deviation of 3.0 kernel is at about zero */
+ /* at 3.0 standard deviations distance, kernel is about zero */
float standard_dev = radius / 3.0f;
/* make the necessary adjustment to the value for use in the normal distribution formula */
- standard_dev = standard_dev * standard_dev * 2;
+ standard_dev = -standard_dev * standard_dev * 2;
for (i = 0; i < side; i++) {
for (j = 0; j < side; j++) {
@@ -666,22 +663,24 @@ void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_cor
copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
else {
if (br->flag & BRUSH_USE_GRADIENT) {
+ float color_gr[4];
switch (br->gradient_stroke_mode) {
case BRUSH_GRADIENT_PRESSURE:
- do_colorband(br->gradient, pressure, color);
+ do_colorband(br->gradient, pressure, color_gr);
break;
case BRUSH_GRADIENT_SPACING_REPEAT:
{
float coord = fmod(distance / br->gradient_spacing, 1.0);
- do_colorband(br->gradient, coord, color);
+ do_colorband(br->gradient, coord, color_gr);
break;
}
case BRUSH_GRADIENT_SPACING_CLAMP:
{
- do_colorband(br->gradient, distance / br->gradient_spacing, color);
+ do_colorband(br->gradient, distance / br->gradient_spacing, color_gr);
break;
}
}
+ copy_v3_v3(color, color_gr);
}
else
copy_v3_v3(color, BKE_brush_color_get(scene, br));
@@ -749,14 +748,16 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
copy_v2_v2(pop->prevmouse, mouse);
copy_v2_v2(pop->startmouse, mouse);
- if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
- pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop);
- }
-
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
Object *ob = OBACT;
- paint_proj_mesh_data_ensure(C, ob, op);
+ bool uvs, mat, tex, stencil;
+ if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) {
+ BKE_paint_data_warning(op->reports, uvs, mat, tex, stencil);
+ MEM_freeN(pop);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ return NULL;
+ }
pop->mode = PAINT_MODE_3D_PROJECT;
pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
}
@@ -770,6 +771,10 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
return NULL;
}
+ if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
+ pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop);
+ }
+
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
ED_image_undo_restore, ED_image_undo_free, NULL);
@@ -1040,8 +1045,9 @@ static void toggle_paint_cursor(bContext *C, int enable)
* purpose is to make sure the paint cursor is shown if paint
* mode is enabled in the image editor. the paint poll will
* ensure that the cursor is hidden when not in paint mode */
-void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings)
+void ED_space_image_paint_update(wmWindowManager *wm, Scene *scene)
{
+ ToolSettings *settings = scene->toolsettings;
wmWindow *win;
ScrArea *sa;
ImagePaintSettings *imapaint = &settings->imapaint;
@@ -1054,7 +1060,7 @@ void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings)
enabled = true;
if (enabled) {
- BKE_paint_init(&imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT);
+ BKE_paint_init(scene, ePaintTexture2D, PAINT_CURSOR_TEXTURE_PAINT);
paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
}
@@ -1207,7 +1213,7 @@ static int sample_color_exec(bContext *C, wmOperator *op)
RNA_int_get_array(op->ptr, "location", location);
use_palette = RNA_boolean_get(op->ptr, "palette");
- paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette);
+ paint_sample_color(C, ar, location[0], location[1], mode == ePaintTextureProjective, use_palette);
if (show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
@@ -1245,7 +1251,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, false);
WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
@@ -1284,7 +1290,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, false);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
break;
}
@@ -1293,11 +1299,12 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_PRESS) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, true);
if (!data->sample_palette) {
data->sample_palette = true;
sample_color_update_header(data, C);
}
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
}
break;
}
@@ -1378,29 +1385,31 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
* cache in case we are loading a file */
BKE_texpaint_slots_refresh_object(scene, ob);
- paint_proj_mesh_data_ensure(C, ob, op);
-
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
/* entering paint mode also sets image to editors */
if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
Material *ma = give_current_material(ob, ob->actcol); /* set the current material active paint slot on image editor */
- if (ma->texpaintslot)
+ if (ma && ma->texpaintslot)
ima = ma->texpaintslot[ma->paint_active_slot].ima;
}
- else if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
ima = imapaint->canvas;
}
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin)
- ED_space_image_set(sima, scene, scene->obedit, ima);
+ if (ima) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin)
+ ED_space_image_set(sima, scene, scene->obedit, ima);
+ }
}
}
}
@@ -1408,7 +1417,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
ob->mode |= mode_flag;
- BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT);
+ BKE_paint_init(scene, ePaintTextureProjective, PAINT_CURSOR_TEXTURE_PAINT);
if (U.glreslimit != 0)
GPU_free_images();
@@ -1417,7 +1426,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 1);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ GPU_drawobject_free(ob->derivedFinal);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 5530f947b8c..c5a066e9b14 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -38,9 +38,7 @@
#include "DNA_space_types.h"
#include "DNA_object_types.h"
-#include "BLI_math.h"
-#include "BLI_rect.h"
#include "BLI_math_color_blend.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
@@ -65,7 +63,6 @@
#include "UI_view2d.h"
-#include "RE_shader_ext.h"
#include "GPU_draw.h"
@@ -142,6 +139,7 @@ typedef struct ImagePaintState {
int faceindex;
float uv[2];
int do_facesel;
+ int symmetry;
bool need_redraw;
@@ -348,8 +346,8 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int d
{
Brush *brush = painter->brush;
- int xoff = -diameter * 0.5f + 0.5f;
- int yoff = -diameter * 0.5f + 0.5f;
+ int xoff = -radius;
+ int yoff = -radius;
unsigned short *mask, *m;
int x, y;
@@ -362,7 +360,7 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int d
float xy[2] = {x + xoff, y + yoff};
float len = len_v2(xy);
- *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamp(brush, len, radius));
+ *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
}
}
@@ -411,11 +409,11 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pre
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
- mul_v3_v3(rgba, brush_rgb);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
}
+ mul_v3_v3(rgba, brush_rgb);
}
else {
copy_v3_v3(rgba, brush_rgb);
@@ -485,11 +483,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
- mul_v3_v3(rgba, brush_rgb);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
}
+ mul_v3_v3(rgba, brush_rgb);
}
else {
copy_v3_v3(rgba, brush_rgb);
@@ -689,7 +687,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
bool do_partial_update_mask = false;
/* invalidate case for all mapping modes */
if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- mask_rotation += ups->brush_rotation;
+ mask_rotation += ups->brush_rotation_sec;
}
else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
renew_maxmask = true;
@@ -773,15 +771,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
}
/* keep these functions in sync */
-static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const bool is_torus, float r_rgb[4])
+static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
{
- if (is_torus) {
- x %= ibuf->x;
- if (x < 0) x += ibuf->x;
- y %= ibuf->y;
- if (y < 0) y += ibuf->y;
- }
-
if (ibuf->rect_float) {
const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
copy_v4_v4(r_rgb, rrgbf);
@@ -817,18 +808,30 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus
}
}
-static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w)
+static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
+{
+ if (tile & PAINT_TILE_X) {
+ *x %= ibuf->x;
+ if (*x < 0) *x += ibuf->x;
+ }
+ if (tile & PAINT_TILE_Y) {
+ *y %= ibuf->y;
+ if (*y < 0) *y += ibuf->y;
+ }
+}
+
+
+static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
{
float inrgb[4];
- // XXX: signed unsigned mismatch
- if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
- if (torus) paint_2d_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
- else return 0;
- }
- else {
- paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
+ if (tile) paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
+ /* need to also do clipping here always since tiled coordinates
+ * are not always within bounds */
+ if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
+ paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
}
+ else return 0;
mul_v4_fl(inrgb, w);
add_v4_v4(outrgb, inrgb);
@@ -836,7 +839,7 @@ static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, f
return w;
}
-static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
+static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
{
bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
float threshold = s->brush->sharp_threshold;
@@ -854,7 +857,7 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
in_off[1] = pos[1];
out_off[0] = out_off[1] = 0;
- if (!is_torus) {
+ if (!tile) {
IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
&out_off[1], &dim[0], &dim[1]);
@@ -872,13 +875,23 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
yi = in_off[1] + y;
count = 0.0;
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, rgba);
+ if (tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
+ if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
+ else
+ zero_v4(rgba);
+ }
+ else {
+ /* coordinates have been clipped properly here, it should be safe to do this */
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
+ }
zero_v4(outrgb);
for (yk = 0; yk < kernel->side; yk++) {
for (xk = 0; xk < kernel->side; xk++) {
count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len,
- yi + yk - kernel->pixel_len, outrgb, is_torus,
+ yi + yk - kernel->pixel_len, outrgb, tile,
kernel->wdata[xk + yk * kernel->side]);
}
}
@@ -892,7 +905,7 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- outrgb[0] = outrgb[1] = outrgb[2] = rgb_to_grayscale(outrgb);
+ outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
if (fabsf(outrgb[0]) > threshold) {
float mask = BKE_brush_alpha_get(s->scene, s->brush);
float alpha = rgba[3];
@@ -926,7 +939,7 @@ static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty,
region->height = height;
}
-static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf)
+static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short tile)
{
int destx = region->destx;
int desty = region->desty;
@@ -937,15 +950,18 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf,
int origw, origh, w, h, tot = 0;
/* convert destination and source coordinates to be within image */
- destx = destx % dbuf->x;
- if (destx < 0) destx += dbuf->x;
- desty = desty % dbuf->y;
- if (desty < 0) desty += dbuf->y;
- srcx = srcx % sbuf->x;
- if (srcx < 0) srcx += sbuf->x;
- srcy = srcy % sbuf->y;
- if (srcy < 0) srcy += sbuf->y;
-
+ if (tile & PAINT_TILE_X) {
+ destx = destx % dbuf->x;
+ if (destx < 0) destx += dbuf->x;
+ srcx = srcx % sbuf->x;
+ if (srcx < 0) srcx += sbuf->x;
+ }
+ if (tile & PAINT_TILE_Y) {
+ desty = desty % dbuf->y;
+ if (desty < 0) desty += dbuf->y;
+ srcy = srcy % sbuf->y;
+ if (srcy < 0) srcy += sbuf->y;
+ }
/* clip width of blending area to destination imbuf, to avoid writing the
* same pixel twice */
origw = w = (width > dbuf->x) ? dbuf->x : width;
@@ -956,23 +972,23 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf,
paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
/* do 3 other rects if needed */
- if (w < origw)
+ if ((tile & PAINT_TILE_X) && w < origw)
paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
- if (h < origh)
+ if ((tile & PAINT_TILE_Y) && h < origh)
paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
- if ((w < origw) && (h < origh))
+ if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
return tot;
}
-static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
{
ImagePaintRegion region[4];
int a, tot;
paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
- tot = paint_2d_torus_split_region(region, ibufb, ibuf);
+ tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
for (a = 0; a < tot; a++)
IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
@@ -999,8 +1015,8 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
{
- ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
+ ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
+ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
}
static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
@@ -1008,7 +1024,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
ImagePaintState *s = ((ImagePaintState *)state);
ImBuf *clonebuf = NULL, *frombuf;
ImagePaintRegion region[4];
- short torus = s->brush->flag & BRUSH_TORUS;
+ short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
short blend = s->blend;
const float *offset = s->brush->clone.offset;
float liftpos[2];
@@ -1020,14 +1036,14 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s, s->canvas, ibufb, bpos, torus);
+ paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
}
else if (s->tool == PAINT_TOOL_SMEAR) {
if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
return 0;
paint_2d_convert_brushco(ibufb, lastpos, blastpos);
- paint_2d_lift_smear(s->canvas, ibufb, blastpos);
+ paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
}
else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
liftpos[0] = pos[0] - offset[0] * s->canvas->x;
@@ -1039,9 +1055,9 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
frombuf = (clonebuf) ? clonebuf : ibufb;
- if (torus) {
+ if (tile) {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = paint_2d_torus_split_region(region, s->canvas, frombuf);
+ tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
}
else {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
@@ -1052,7 +1068,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image, s->canvas,
region[a].destx, region[a].desty,
- region[a].width, region[a].height);
+ region[a].width, region[a].height, true);
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
@@ -1112,7 +1128,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
if (ima == NULL) {
return 0;
}
- else if (ima->packedfile && ima->rr) {
+ else if (BKE_image_has_packedfile(ima) && ima->rr) {
s->warnpackedfile = ima->id.name + 2;
return 0;
}
@@ -1237,6 +1253,7 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
s->blend = brush->blend;
s->image = s->sima->image;
+ s->symmetry = settings->imapaint.paint.symmetry_flags;
if (!paint_2d_canvas_set(s, s->image)) {
if (s->warnmultifile)
@@ -1309,12 +1326,12 @@ static void paint_2d_fill_add_pixel_byte(
const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
const float color[4], float threshold_sq)
{
- int coordinate;
+ size_t coordinate;
if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
return;
- coordinate = y_px * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
if (!BLI_BITMAP_TEST(touched, coordinate)) {
float color_f[4];
@@ -1332,12 +1349,12 @@ static void paint_2d_fill_add_pixel_float(
const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
const float color[4], float threshold_sq)
{
- int coordinate;
+ size_t coordinate;
if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
return;
- coordinate = y_px * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
if (!BLI_BITMAP_TEST(touched, coordinate)) {
if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) {
@@ -1389,21 +1406,21 @@ void paint_2d_bucket_fill(
if (!mouse_init || !br) {
/* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
- ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), color_f);
+ blend_color_mix_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px), color_f);
}
}
}
else {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), (unsigned char *)&color_b);
+ blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px), (unsigned char *)&color_b);
}
}
}
@@ -1413,7 +1430,7 @@ void paint_2d_bucket_fill(
* value is within the brush fill threshold from the fill color */
BLI_Stack *stack;
BLI_bitmap *touched;
- int coordinate;
+ size_t coordinate;
int width = ibuf->x;
float image_init[2];
int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
@@ -1431,12 +1448,12 @@ void paint_2d_bucket_fill(
}
/* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
- stack = BLI_stack_new(sizeof(int), __func__);
- touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap");
+ stack = BLI_stack_new(sizeof(size_t), __func__);
+ touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
- coordinate = (y_px * ibuf->x + x_px);
+ coordinate = (((size_t)y_px) * ibuf->x + x_px);
if (do_float) {
copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
@@ -1569,7 +1586,7 @@ void paint_2d_gradient_fill(
do_float = (ibuf->rect_float != NULL);
/* this will be substituted by something else when selection is available */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -1584,6 +1601,7 @@ void paint_2d_gradient_fill(
break;
}
case BRUSH_GRADIENT_RADIAL:
+ default:
{
f = len_v2(p) / line_len;
break;
@@ -1593,8 +1611,8 @@ void paint_2d_gradient_fill(
/* convert to premultiplied */
mul_v3_fl(color_f, color_f[3]);
color_f[3] *= br->alpha;
- IMB_blend_color_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
- ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
+ IMB_blend_color_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
color_f, br->blend);
}
}
@@ -1612,6 +1630,7 @@ void paint_2d_gradient_fill(
break;
}
case BRUSH_GRADIENT_RADIAL:
+ default:
{
f = len_v2(p) / line_len;
break;
@@ -1619,10 +1638,11 @@ void paint_2d_gradient_fill(
}
do_colorband(br->gradient, f, color_f);
+ linearrgb_to_srgb_v3_v3(color_f, color_f);
rgba_float_to_uchar((unsigned char *)&color_b, color_f);
((unsigned char *)&color_b)[3] *= br->alpha;
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
(unsigned char *)&color_b, br->blend);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index ee9181b7d3f..f1489f2fd10 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -43,14 +43,14 @@
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_math_color_blend.h"
#include "BLI_memarena.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
-#include "PIL_time.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -62,8 +62,8 @@
#include "DNA_object_types.h"
#include "BKE_camera.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_idprop.h"
@@ -74,16 +74,16 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
-#include "UI_view2d.h"
#include "UI_interface.h"
-#include "ED_image.h"
#include "ED_mesh.h"
+#include "ED_node.h"
#include "ED_paint.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
@@ -99,10 +99,12 @@
#include "RNA_enum_types.h"
#include "GPU_draw.h"
-#include "GPU_buffers.h"
#include "IMB_colormanagement.h"
+#include "bmesh.h"
+//#include "bmesh_tools.h"
+
#include "paint_intern.h"
/* Defines and Structs */
@@ -133,23 +135,30 @@ BLI_INLINE unsigned char f_to_char(const float val)
//#define PROJ_DEBUG_PRINT_CLIP 1
#define PROJ_DEBUG_WINCLIP 1
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
/* projectFaceSeamFlags options */
//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
#define PROJ_FACE_SEAM1 (1 << 0) /* If this face has a seam on any of its edges */
#define PROJ_FACE_SEAM2 (1 << 1)
#define PROJ_FACE_SEAM3 (1 << 2)
-#define PROJ_FACE_SEAM4 (1 << 3)
#define PROJ_FACE_NOSEAM1 (1 << 4)
#define PROJ_FACE_NOSEAM2 (1 << 5)
#define PROJ_FACE_NOSEAM3 (1 << 6)
-#define PROJ_FACE_NOSEAM4 (1 << 7)
/* face winding */
#define PROJ_FACE_WINDING_INIT 1
#define PROJ_FACE_WINDING_CW 2
+/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
+ * as this number approaches 1.0f the likelihood increases of float precision errors where
+ * it is occluded by an adjacent face */
+#define PROJ_FACE_SCALE_SEAM 0.99f
+#endif /* PROJ_DEBUG_NOSEAMBLEED */
+
+
#define PROJ_SRC_VIEW 1
#define PROJ_SRC_IMAGE_CAM 2
#define PROJ_SRC_IMAGE_VIEW 3
@@ -158,12 +167,6 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_VIEW_DATA_ID "view_data"
#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
-
-/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
- * as this number approaches 1.0f the likelihood increases of float precision errors where
- * it is occluded by an adjacent face */
-#define PROJ_FACE_SCALE_SEAM 0.99f
-
#define PROJ_BUCKET_NULL 0
#define PROJ_BUCKET_INIT (1 << 0)
// #define PROJ_BUCKET_CLONE_INIT (1<<1)
@@ -187,11 +190,34 @@ typedef struct ProjPaintImage {
ImagePaintPartialRedraw *partRedrawRect;
volatile void **undoRect; /* only used to build undo tiles during painting */
unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket.
- * Here we store the mask rectangle */
+ * Here we store the mask rectangle */
bool **valid; /* store flag to enforce validation of undo rectangle */
- int touch;
+ bool touch;
} ProjPaintImage;
+/**
+ * Handle for stroke (operator customdata)
+ */
+typedef struct ProjStrokeHandle {
+ /* Support for painting from multiple views at once,
+ * currently used to impliment summetry painting,
+ * we can assume at least the first is set while painting. */
+ struct ProjPaintState *ps_views[8];
+ int ps_views_tot;
+ int symmetry_flags;
+
+ int orig_brush_size;
+
+ bool need_redraw;
+
+ /* trick to bypass regular paint and allow clone picking */
+ bool is_clone_cursor_pick;
+
+ /* In ProjPaintState, only here for convenience */
+ Scene *scene;
+ Brush *brush;
+} ProjStrokeHandle;
+
/* Main projection painting struct passed to all projection painting functions */
typedef struct ProjPaintState {
View3D *v3d;
@@ -203,25 +229,18 @@ typedef struct ProjPaintState {
/* the paint color. It can change depending of inverted mode or not */
float paint_color[3];
float paint_color_linear[3];
+ float dither;
Brush *brush;
short tool, blend, mode;
- int orig_brush_size;
+
float brush_size;
Object *ob;
+ /* for symmetry, we need to store modified object matrix */
+ float obmat[4][4];
+ float obmat_imat[4][4];
/* end similarities with ImagePaintState */
- DerivedMesh *dm;
- int dm_totface;
- int dm_totvert;
- int dm_release;
-
- MVert *dm_mvert;
- MFace *dm_mface;
- MTFace **dm_mtface;
- MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
- MTFace *dm_mtface_stencil;
-
Image *stencil_ima;
Image *canvas_ima;
Image *clone_ima;
@@ -232,24 +251,16 @@ typedef struct ProjPaintState {
LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */
unsigned char *bucketFlags; /* store if the bucks have been initialized */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
- char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
- float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
- LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
-#endif
+
char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */
int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */
int buckets_y;
- ProjPaintImage *projImages;
-
int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */
int image_tot; /* size of projectImages array */
float (*screenCoords)[4]; /* verts projected into floating point screen space */
-
float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */
float screenMax[2];
float screen_width; /* Calculated from screenMin & screenMax */
@@ -266,13 +277,17 @@ typedef struct ProjPaintState {
bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
bool do_mask_normal; /* mask out pixels based on their normals */
+ bool do_mask_cavity; /* mask out pixels based on cavity */
bool do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */
- float normal_angle; /* what angle to mask at*/
+ float normal_angle; /* what angle to mask at */
+ float normal_angle__cos; /* cos(normal_angle), faster to compare */
float normal_angle_inner;
+ float normal_angle_inner__cos;
float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */
bool do_face_sel; /* quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */
bool is_ortho;
+ bool is_flip_object; /* the object is negative scaled */
bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
bool is_texbrush; /* only to avoid running */
bool is_maskbrush; /* mask brush is applied before masking */
@@ -283,6 +298,7 @@ typedef struct ProjPaintState {
float cloneOffset[2];
float projectMat[4][4]; /* Projection matrix, use for getting screen coords */
+ float projectMatInv[4][4]; /* inverse of projectMat */
float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */
float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */
float clipsta, clipend;
@@ -297,12 +313,60 @@ typedef struct ProjPaintState {
int bucketMax[2];
int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
- /* redraw */
- bool need_redraw;
-
+ struct CurveMapping *cavity_curve;
BlurKernel *blurkernel;
+
+
+ /* -------------------------------------------------------------------- */
+ /* Vars shared between multiple views (keep last) */
+ /**
+ * This data is owned by ``ProjStrokeHandle.ps_views[0]``,
+ * all other views re-use the data.
+ */
+
+#define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
+ MEMCPY_STRUCT_OFS(ps_dst, ps_src, is_shared_user)
+
+#define PROJ_PAINT_STATE_SHARED_CLEAR(ps) \
+ MEMSET_STRUCT_OFS(ps, 0, is_shared_user)
+
+ bool is_shared_user;
+
+ ProjPaintImage *projImages;
+ float *cavities; /* cavity amount for vertices */
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
+ char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
+ float (*faceSeamUVs)[3][2]; /* expanded UVs for faces to use as seams */
+ LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
+#endif
+
SpinLock *tile_lock;
+
+ DerivedMesh *dm;
+ int dm_totlooptri;
+ int dm_totpoly;
+ int dm_totedge;
+ int dm_totvert;
+ bool dm_release;
+
+ const MVert *dm_mvert;
+ const MEdge *dm_medge;
+ const MPoly *dm_mpoly;
+ const MLoop *dm_mloop;
+ const MLoopTri *dm_mlooptri;
+
+ const MLoopUV *dm_mloopuv_stencil;
+
+ /**
+ * \note These UV layers are aligned to \a dm_mpoly
+ * but each pointer references the start of the layer,
+ * so a loop indirection is needed as well.
+ */
+ const MLoopUV **dm_mloopuv;
+ const MLoopUV **dm_mloopuv_clone; /* other UV map, use for cloning between layers */
} ProjPaintState;
typedef union pixelPointer {
@@ -320,25 +384,27 @@ typedef union pixelStore {
typedef struct ProjPixel {
float projCoSS[2]; /* the floating point screen projection of this pixel */
float worldCoSS[3];
+
+ short x_px, y_px;
+
+ unsigned short image_index; /* if anyone wants to paint onto more than 65535 images they can bite me */
+ unsigned char bb_cell_index;
+
+ /* for various reasons we may want to mask out painting onto this pixel */
+ unsigned short mask;
+
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
* new mask value is lower then mask_accum */
unsigned short *mask_accum;
- /* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
-
- short x_px, y_px;
/* horrible hack, store tile valid flag pointer here to re-validate tiles used for anchored and drag-dot strokes */
bool *valid;
PixelPointer origColor;
PixelStore newColor;
PixelPointer pixel;
-
- short image_index; /* if anyone wants to paint onto more than 32768 images they can bite me */
- unsigned char bb_cell_index;
} ProjPixel;
typedef struct ProjPixelClone {
@@ -356,40 +422,71 @@ typedef struct {
} TileInfo;
+
+/* -------------------------------------------------------------------- */
+
+/** \name MLoopTri accessor functions.
+ * \{ */
+
+BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_index)
+{
+ return &ps->dm_mpoly[ps->dm_mlooptri[tri_index].poly];
+}
+
+#define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) \
+ ps->dm_mloop[lt->tri[0]].v, \
+ ps->dm_mloop[lt->tri[1]].v, \
+ ps->dm_mloop[lt->tri[2]].v,
+
+#define PS_LOOPTRI_AS_UV_3(uvlayer, lt) \
+ uvlayer[lt->poly][lt->tri[0]].uv, \
+ uvlayer[lt->poly][lt->tri[1]].uv, \
+ uvlayer[lt->poly][lt->tri[2]].uv,
+
+#define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, lt) { \
+ (uv_tri)[0] = uvlayer[lt->poly][lt->tri[0]].uv; \
+ (uv_tri)[1] = uvlayer[lt->poly][lt->tri[1]].uv; \
+ (uv_tri)[2] = uvlayer[lt->poly][lt->tri[2]].uv; \
+} ((void)0)
+
+/** \} */
+
+
+
/* Finish projection painting structs */
-static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int face_index)
+static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
- MFace *mf = ps->dm_mface + face_index;
- Material *ma = ps->dm->mat[mf->mat_nr];
- return ma->texpaintslot + ma->paint_active_slot;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->dm->mat[mp->mat_nr];
+ return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
}
-static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_index)
+static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_index)
{
if (ps->do_stencil_brush) {
return ps->stencil_ima;
}
else {
- MFace *mf = ps->dm_mface + face_index;
- Material *ma = ps->dm->mat[mf->mat_nr];
- TexPaintSlot *slot = ma->texpaintslot + ma->paint_active_slot;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->dm->mat[mp->mat_nr];
+ TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
return slot ? slot->ima : ps->canvas_ima;
}
}
-static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index)
+static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{
- MFace *mf = ps->dm_mface + face_index;
- Material *ma = ps->dm->mat[mf->mat_nr];
- return ma->texpaintslot + ma->paint_clone_slot;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->dm->mat[mp->mat_nr];
+ return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
}
-static Image *project_paint_face_clone_image(const ProjPaintState *ps, int face_index)
+static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{
- MFace *mf = ps->dm_mface + face_index;
- Material *ma = ps->dm->mat[mf->mat_nr];
- TexPaintSlot *slot = ma->texpaintslot + ma->paint_clone_slot;
+ const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
+ Material *ma = ps->dm->mat[mp->mat_nr];
+ TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
return slot ? slot->ima : ps->clone_ima;
}
@@ -422,17 +519,19 @@ static int project_bucket_offset_safe(const ProjPaintState *ps, const float proj
}
}
-static float VecZDepthOrtho(const float pt[2],
- const float v1[3], const float v2[3], const float v3[3],
- float w[3])
+static float VecZDepthOrtho(
+ const float pt[2],
+ const float v1[3], const float v2[3], const float v3[3],
+ float w[3])
{
barycentric_weights_v2(v1, v2, v3, pt, w);
return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
}
-static float VecZDepthPersp(const float pt[2],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3])
+static float VecZDepthPersp(
+ const float pt[2],
+ const float v1[4], const float v2[4], const float v3[4],
+ float w[3])
{
float wtot_inv, wtot;
float w_tmp[3];
@@ -466,17 +565,15 @@ static float VecZDepthPersp(const float pt[2],
/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
-static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3], int *side)
+static int project_paint_PickFace(
+ const ProjPaintState *ps, const float pt[2],
+ float w[3])
{
LinkNode *node;
float w_tmp[3];
- const float *v1, *v2, *v3, *v4;
int bucket_index;
- int face_index;
- int best_side = -1;
- int best_face_index = -1;
+ int best_tri_index = -1;
float z_depth_best = FLT_MAX, z_depth;
- MFace *mf;
bucket_index = project_bucket_offset_safe(ps, pt);
if (bucket_index == -1)
@@ -488,43 +585,32 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
* that the point its testing is only every originated from an existing face */
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- face_index = GET_INT_FROM_POINTER(node->link);
- mf = ps->dm_mface + face_index;
+ const int tri_index = GET_INT_FROM_POINTER(node->link);
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const float *vtri_ss[3] = {
+ ps->screenCoords[ps->dm_mloop[lt->tri[0]].v],
+ ps->screenCoords[ps->dm_mloop[lt->tri[1]].v],
+ ps->screenCoords[ps->dm_mloop[lt->tri[2]].v],
+ };
- v1 = ps->screenCoords[mf->v1];
- v2 = ps->screenCoords[mf->v2];
- v3 = ps->screenCoords[mf->v3];
- if (isect_point_tri_v2(pt, v1, v2, v3)) {
- if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v2, v3, w_tmp);
- else z_depth = VecZDepthPersp(pt, v1, v2, v3, w_tmp);
+ if (isect_point_tri_v2(pt, UNPACK3(vtri_ss))) {
+ if (ps->is_ortho) {
+ z_depth = VecZDepthOrtho(pt, UNPACK3(vtri_ss), w_tmp);
+ }
+ else {
+ z_depth = VecZDepthPersp(pt, UNPACK3(vtri_ss), w_tmp);
+ }
if (z_depth < z_depth_best) {
- best_face_index = face_index;
- best_side = 0;
+ best_tri_index = tri_index;
z_depth_best = z_depth;
copy_v3_v3(w, w_tmp);
}
}
- else if (mf->v4) {
- v4 = ps->screenCoords[mf->v4];
-
- if (isect_point_tri_v2(pt, v1, v3, v4)) {
- if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v3, v4, w_tmp);
- else z_depth = VecZDepthPersp(pt, v1, v3, v4, w_tmp);
-
- if (z_depth < z_depth_best) {
- best_face_index = face_index;
- best_side = 1;
- z_depth_best = z_depth;
- copy_v3_v3(w, w_tmp);
- }
- }
- }
}
- *side = best_side;
- return best_face_index; /* will be -1 or a valid face */
+ return best_tri_index; /* will be -1 or a valid face */
}
/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
@@ -542,33 +628,29 @@ static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, floa
}
/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
-static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
- float *rgba_fp, unsigned char *rgba, const bool interp)
+static bool project_paint_PickColor(
+ const ProjPaintState *ps, const float pt[2],
+ float *rgba_fp, unsigned char *rgba, const bool interp)
{
+ const MLoopTri *lt;
+ const float *lt_tri_uv[3];
float w[3], uv[2];
- int side;
- int face_index;
- MTFace *tf;
+ int tri_index;
Image *ima;
ImBuf *ibuf;
int xi, yi;
+ tri_index = project_paint_PickFace(ps, pt, w);
- face_index = project_paint_PickFace(ps, pt, w, &side);
-
- if (face_index == -1)
+ if (tri_index == -1)
return 0;
- tf = *(ps->dm_mtface + face_index);
+ lt = &ps->dm_mlooptri[tri_index];
+ PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->dm_mloopuv, lt);
- if (side == 0) {
- interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
- }
- else { /* QUAD */
- interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
- }
+ interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
- ima = project_paint_face_paint_image(ps, face_index);
+ ima = project_paint_face_paint_image(ps, tri_index);
ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */
if (!ibuf) return 0;
@@ -630,16 +712,18 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
return 1;
}
-/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
- * return...
- * 0 : no occlusion
- * -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad)
- * 1 : occluded
- * 2 : occluded with w[3] weights set (need to know in some cases) */
-
-static int project_paint_occlude_ptv(const float pt[3],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3], const bool is_ortho)
+/**
+ * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test)
+ * \return
+ * - `0`: no occlusion
+ * - `-1`: no occlusion but 2D intersection is true
+ * - `1`: occluded
+ * - `2`: occluded with `w[3]` weights set (need to know in some cases)
+ */
+static int project_paint_occlude_ptv(
+ const float pt[3],
+ const float v1[4], const float v2[4], const float v3[4],
+ float w[3], const bool is_ortho)
{
/* if all are behind us, return false */
if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
@@ -669,26 +753,31 @@ static int project_paint_occlude_ptv(const float pt[3],
}
-static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf,
- const float pt[3], const float v1[4], const float v2[4], const float v3[4],
- const int side)
+static int project_paint_occlude_ptv_clip(
+ const float pt[3],
+ const float v1[4], const float v2[4], const float v3[4],
+ const float v1_3d[3], const float v2_3d[3], const float v3_3d[3],
+ float w[3], const bool is_ortho, RegionView3D *rv3d)
{
- float w[3], wco[3];
- int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho);
+ float wco[3];
+ int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, is_ortho);
if (ret <= 0)
return ret;
if (ret == 1) { /* weights not calculated */
- if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w);
- else barycentric_weights_v2_persp(v1, v2, v3, pt, w);
+ if (is_ortho) {
+ barycentric_weights_v2(v1, v2, v3, pt, w);
+ }
+ else {
+ barycentric_weights_v2_persp(v1, v2, v3, pt, w);
+ }
}
/* Test if we're in the clipped area, */
- if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
- else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+ interp_v3_v3v3v3(wco, v1_3d, v2_3d, v3_3d, w);
- if (!ED_view3d_clipping_test(ps->rv3d, wco, true)) {
+ if (!ED_view3d_clipping_test(rv3d, wco, true)) {
return 1;
}
@@ -699,35 +788,44 @@ static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace
/* Check if a screenspace location is occluded by any other faces
* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
* and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
-static bool project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace,
- const int orig_face, const float pixelScreenCo[4])
+static bool project_bucket_point_occluded(
+ const ProjPaintState *ps, LinkNode *bucketFace,
+ const int orig_face, const float pixelScreenCo[4])
{
- MFace *mf;
- int face_index;
int isect_ret;
- float w[3]; /* not needed when clipping */
- const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+ const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
/* we could return 0 for 1 face buckets, as long as this function assumes
* that the point its testing is only every originated from an existing face */
for (; bucketFace; bucketFace = bucketFace->next) {
- face_index = GET_INT_FROM_POINTER(bucketFace->link);
-
- if (orig_face != face_index) {
- mf = ps->dm_mface + face_index;
- if (do_clip)
- isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0);
- else
- isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho);
-
- /* Note, if (isect_ret == -1) then we don't want to test the other side of the quad */
- if (isect_ret == 0 && mf->v4) {
- if (do_clip)
- isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1);
- else
- isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho);
+ const int tri_index = GET_INT_FROM_POINTER(bucketFace->link);
+
+ if (orig_face != tri_index) {
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const float *vtri_ss[3] = {
+ ps->screenCoords[ps->dm_mloop[lt->tri[0]].v],
+ ps->screenCoords[ps->dm_mloop[lt->tri[1]].v],
+ ps->screenCoords[ps->dm_mloop[lt->tri[2]].v],
+ };
+ float w[3];
+
+ if (do_clip) {
+ const float *vtri_co[3] = {
+ ps->dm_mvert[ps->dm_mloop[lt->tri[0]].v].co,
+ ps->dm_mvert[ps->dm_mloop[lt->tri[1]].v].co,
+ ps->dm_mvert[ps->dm_mloop[lt->tri[2]].v].co,
+ };
+ isect_ret = project_paint_occlude_ptv_clip(
+ pixelScreenCo, UNPACK3(vtri_ss), UNPACK3(vtri_co),
+ w, ps->is_ortho, ps->rv3d);
+ }
+ else {
+ isect_ret = project_paint_occlude_ptv(
+ pixelScreenCo, UNPACK3(vtri_ss),
+ w, ps->is_ortho);
}
+
if (isect_ret >= 1) {
/* TODO - we may want to cache the first hit,
* it is not possible to swap the face order in the list anymore */
@@ -764,11 +862,11 @@ static int line_isect_y(const float p1[2], const float p2[2], const float y_leve
}
if (p1[1] > y_level && p2[1] < y_level) {
- *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /*(p1[1]-p2[1]);*/
+ *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /* (p1[1] - p2[1]); */
return ISECT_TRUE;
}
else if (p1[1] < y_level && p2[1] > y_level) {
- *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /*(p2[1]-p1[1]);*/
+ *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /* (p2[1] - p1[1]); */
return ISECT_TRUE;
}
else {
@@ -797,11 +895,11 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
}
if (p1[0] > x_level && p2[0] < x_level) {
- *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /*(p1[0]-p2[0]);*/
+ *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /* (p1[0] - p2[0]); */
return ISECT_TRUE;
}
else if (p1[0] < x_level && p2[0] > x_level) {
- *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /*(p2[0]-p1[0]);*/
+ *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /* (p2[0] - p1[0]); */
return ISECT_TRUE;
}
else {
@@ -837,21 +935,19 @@ static bool cmp_uv(const float vec2a[2], const float vec2b[2])
* return zero if there is no area in the returned rectangle */
#ifndef PROJ_DEBUG_NOSEAMBLEED
static bool pixel_bounds_uv(
- const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2],
+ const float uv_quad[4][2],
rcti *bounds_px,
- const int ibuf_x, const int ibuf_y,
- const bool is_quad
+ const int ibuf_x, const int ibuf_y
)
{
float min_uv[2], max_uv[2]; /* UV bounds */
INIT_MINMAX2(min_uv, max_uv);
- minmax_v2v2_v2(min_uv, max_uv, uv1);
- minmax_v2v2_v2(min_uv, max_uv, uv2);
- minmax_v2v2_v2(min_uv, max_uv, uv3);
- if (is_quad)
- minmax_v2v2_v2(min_uv, max_uv, uv4);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[0]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[1]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[2]);
+ minmax_v2v2_v2(min_uv, max_uv, uv_quad[3]);
bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
@@ -895,82 +991,77 @@ static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x
#ifndef PROJ_DEBUG_NOSEAMBLEED
-static void project_face_winding_init(const ProjPaintState *ps, const int face_index)
+static void project_face_winding_init(const ProjPaintState *ps, const int tri_index)
{
/* detect the winding of faces in uv space */
- MTFace *tf = ps->dm_mtface[face_index];
- float winding = cross_tri_v2(tf->uv[0], tf->uv[1], tf->uv[2]);
-
- if (ps->dm_mface[face_index].v4)
- winding += cross_tri_v2(tf->uv[2], tf->uv[3], tf->uv[0]);
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt) };
+ float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
if (winding > 0)
- ps->faceWindingFlags[face_index] |= PROJ_FACE_WINDING_CW;
+ ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_CW;
- ps->faceWindingFlags[face_index] |= PROJ_FACE_WINDING_INIT;
+ ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_INIT;
}
/* This function returns 1 if this face has a seam along the 2 face-vert indices
* 'orig_i1_fidx' and 'orig_i2_fidx' */
-static bool check_seam(const ProjPaintState *ps,
- const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx,
- int *other_face, int *orig_fidx)
+static bool check_seam(
+ const ProjPaintState *ps,
+ const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx,
+ int *other_face, int *orig_fidx)
{
+ const MLoopTri *orig_lt = &ps->dm_mlooptri[orig_face];
+ const float *orig_lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, orig_lt) };
+ /* vert indices from face vert order indices */
+ const unsigned int i1 = ps->dm_mloop[orig_lt->tri[orig_i1_fidx]].v;
+ const unsigned int i2 = ps->dm_mloop[orig_lt->tri[orig_i2_fidx]].v;
LinkNode *node;
- int face_index;
- unsigned int i1, i2;
int i1_fidx = -1, i2_fidx = -1; /* index in face */
- MFace *mf;
- MTFace *tf;
- const MFace *orig_mf = ps->dm_mface + orig_face;
- const MTFace *orig_tf = ps->dm_mtface[orig_face];
-
- /* vert indices from face vert order indices */
- i1 = (*(&orig_mf->v1 + orig_i1_fidx));
- i2 = (*(&orig_mf->v1 + orig_i2_fidx));
for (node = ps->vertFaces[i1]; node; node = node->next) {
- face_index = GET_INT_FROM_POINTER(node->link);
+ const int tri_index = GET_INT_FROM_POINTER(node->link);
- if (face_index != orig_face) {
- mf = ps->dm_mface + face_index;
+ if (tri_index != orig_face) {
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
/* could check if the 2 faces images match here,
* but then there wouldn't be a way to return the opposite face's info */
/* We need to know the order of the verts in the adjacent face
* set the i1_fidx and i2_fidx to (0,1,2,3) */
- i1_fidx = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, i1);
- i2_fidx = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, i2);
+ i1_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i1);
+ i2_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i2);
/* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
if (i2_fidx != -1) {
- Image *tpage = project_paint_face_paint_image(ps, face_index);
+ const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt) };
+ Image *tpage = project_paint_face_paint_image(ps, tri_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
BLI_assert(i1_fidx != -1);
/* This IS an adjacent face!, now lets check if the UVs are ok */
- tf = ps->dm_mtface[face_index];
/* set up the other face */
- *other_face = face_index;
+ *other_face = tri_index;
- /* we check if difference is 1 here, else we might have a case of edge 2-0 or 3-0 for quads */
+ /* we check if difference is 1 here, else we might have a case of edge 2-0 for a tri */
*orig_fidx = (i1_fidx < i2_fidx && (i2_fidx - i1_fidx == 1)) ? i1_fidx : i2_fidx;
/* initialize face winding if needed */
- if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_INIT) == 0)
- project_face_winding_init(ps, face_index);
+ if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0)
+ project_face_winding_init(ps, tri_index);
/* first test if they have the same image */
if ((orig_tpage == tpage) &&
- cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
- cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]))
+ cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
+ cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx]))
{
/* if faces don't have the same winding in uv space,
* they are on the same side so edge is boundary */
- if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_CW) !=
+ if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW) !=
(ps->faceWindingFlags[orig_face] & PROJ_FACE_WINDING_CW))
{
return 1;
@@ -992,16 +1083,25 @@ static bool check_seam(const ProjPaintState *ps,
return 1;
}
+#define SMALL_NUMBER 1.e-6f
+BLI_INLINE float shell_v2v2_normal_dir_to_dist(float n[2], float d[2])
+{
+ const float angle_cos = (normalize_v2(n) < SMALL_NUMBER) ? fabsf(dot_v2v2(d, n)) : 0.0f;
+ return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
+}
+#undef SMALL_NUMBER
+
/* Calculate outset UV's, this is not the same as simply scaling the UVs,
* since the outset coords are a margin that keep an even distance from the original UV's,
* note that the image aspect is taken into account */
-static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler,
- const int ibuf_x, const int ibuf_y, const bool is_quad)
+static void uv_image_outset(
+ float (*orig_uv)[2], float (*outset_uv)[2], const float scaler,
+ const int ibuf_x, const int ibuf_y, const bool cw)
{
- float a1, a2, a3, a4 = 0.0f;
- float puv[4][2]; /* pixelspace uv's */
- float no1[2], no2[2], no3[2], no4[2]; /* normals */
- float dir1[2], dir2[2], dir3[2], dir4[2];
+ float a1, a2, a3;
+ float puv[3][2]; /* pixelspace uv's */
+ float no1[2], no2[2], no3[2]; /* normals */
+ float dir1[2], dir2[2], dir3[2];
float ibuf_inv[2];
ibuf_inv[0] = 1.0f / (float)ibuf_x;
@@ -1017,80 +1117,47 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
puv[2][0] = orig_uv[2][0] * ibuf_x;
puv[2][1] = orig_uv[2][1] * ibuf_y;
- if (is_quad) {
- puv[3][0] = orig_uv[3][0] * ibuf_x;
- puv[3][1] = orig_uv[3][1] * ibuf_y;
- }
-
/* face edge directions */
sub_v2_v2v2(dir1, puv[1], puv[0]);
sub_v2_v2v2(dir2, puv[2], puv[1]);
+ sub_v2_v2v2(dir3, puv[0], puv[2]);
normalize_v2(dir1);
normalize_v2(dir2);
-
- if (is_quad) {
- sub_v2_v2v2(dir3, puv[3], puv[2]);
- sub_v2_v2v2(dir4, puv[0], puv[3]);
- normalize_v2(dir3);
- normalize_v2(dir4);
- }
- else {
- sub_v2_v2v2(dir3, puv[0], puv[2]);
- normalize_v2(dir3);
- }
-
- if (is_quad) {
- a1 = shell_v2v2_mid_normalized_to_dist(dir4, dir1);
- a2 = shell_v2v2_mid_normalized_to_dist(dir1, dir2);
- a3 = shell_v2v2_mid_normalized_to_dist(dir2, dir3);
- a4 = shell_v2v2_mid_normalized_to_dist(dir3, dir4);
- }
- else {
- a1 = shell_v2v2_mid_normalized_to_dist(dir3, dir1);
- a2 = shell_v2v2_mid_normalized_to_dist(dir1, dir2);
- a3 = shell_v2v2_mid_normalized_to_dist(dir2, dir3);
- }
-
- if (is_quad) {
- sub_v2_v2v2(no1, dir4, dir1);
- sub_v2_v2v2(no2, dir1, dir2);
- sub_v2_v2v2(no3, dir2, dir3);
- sub_v2_v2v2(no4, dir3, dir4);
- normalize_v2(no1);
- normalize_v2(no2);
- normalize_v2(no3);
- normalize_v2(no4);
- mul_v2_fl(no1, a1 * scaler);
- mul_v2_fl(no2, a2 * scaler);
- mul_v2_fl(no3, a3 * scaler);
- mul_v2_fl(no4, a4 * scaler);
- add_v2_v2v2(outset_uv[0], puv[0], no1);
- add_v2_v2v2(outset_uv[1], puv[1], no2);
- add_v2_v2v2(outset_uv[2], puv[2], no3);
- add_v2_v2v2(outset_uv[3], puv[3], no4);
- mul_v2_v2(outset_uv[0], ibuf_inv);
- mul_v2_v2(outset_uv[1], ibuf_inv);
- mul_v2_v2(outset_uv[2], ibuf_inv);
- mul_v2_v2(outset_uv[3], ibuf_inv);
+ normalize_v2(dir3);
+
+ /* here we just use the orthonormality property (a1, a2) dot (a2, -a1) = 0
+ * to get normals from the edge directions based on the winding */
+ if (cw) {
+ no1[0] = -dir3[1] - dir1[1];
+ no1[1] = dir3[0] + dir1[0];
+ no2[0] = -dir1[1] - dir2[1];
+ no2[1] = dir1[0] + dir2[0];
+ no3[0] = -dir2[1] - dir3[1];
+ no3[1] = dir2[0] + dir3[0];
}
else {
- sub_v2_v2v2(no1, dir3, dir1);
- sub_v2_v2v2(no2, dir1, dir2);
- sub_v2_v2v2(no3, dir2, dir3);
- normalize_v2(no1);
- normalize_v2(no2);
- normalize_v2(no3);
- mul_v2_fl(no1, a1 * scaler);
- mul_v2_fl(no2, a2 * scaler);
- mul_v2_fl(no3, a3 * scaler);
- add_v2_v2v2(outset_uv[0], puv[0], no1);
- add_v2_v2v2(outset_uv[1], puv[1], no2);
- add_v2_v2v2(outset_uv[2], puv[2], no3);
-
- mul_v2_v2(outset_uv[0], ibuf_inv);
- mul_v2_v2(outset_uv[1], ibuf_inv);
- mul_v2_v2(outset_uv[2], ibuf_inv);
- }
+ no1[0] = dir3[1] + dir1[1];
+ no1[1] = -dir3[0] - dir1[0];
+ no2[0] = dir1[1] + dir2[1];
+ no2[1] = -dir1[0] - dir2[0];
+ no3[0] = dir2[1] + dir3[1];
+ no3[1] = -dir2[0] - dir3[0];
+ }
+
+ a1 = shell_v2v2_normal_dir_to_dist(no1, dir3);
+ a2 = shell_v2v2_normal_dir_to_dist(no2, dir1);
+ a3 = shell_v2v2_normal_dir_to_dist(no3, dir2);
+
+ mul_v2_fl(no1, a1 * scaler);
+ mul_v2_fl(no2, a2 * scaler);
+ mul_v2_fl(no3, a3 * scaler);
+ add_v2_v2v2(outset_uv[0], puv[0], no1);
+ add_v2_v2v2(outset_uv[1], puv[1], no2);
+ add_v2_v2v2(outset_uv[2], puv[2], no3);
+
+ mul_v2_v2(outset_uv[0], ibuf_inv);
+ mul_v2_v2(outset_uv[1], ibuf_inv);
+ mul_v2_v2(outset_uv[2], ibuf_inv);
}
/*
@@ -1099,25 +1166,25 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
*
* If we're multithreadng, make sure threads are locked when this is called
*/
-static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad)
+static void project_face_seams_init(const ProjPaintState *ps, const int tri_index)
{
int other_face, other_fidx; /* vars for the other face, we also set its flag */
- int fidx1 = is_quad ? 3 : 2;
+ int fidx1 = 2;
int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
/* initialize face winding if needed */
- if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_INIT) == 0)
- project_face_winding_init(ps, face_index);
+ if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0)
+ project_face_winding_init(ps, tri_index);
do {
- if ((ps->faceSeamFlags[face_index] & (1 << fidx1 | 16 << fidx1)) == 0) {
- if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) {
- ps->faceSeamFlags[face_index] |= 1 << fidx1;
+ if ((ps->faceSeamFlags[tri_index] & (1 << fidx1 | 16 << fidx1)) == 0) {
+ if (check_seam(ps, tri_index, fidx1, fidx2, &other_face, &other_fidx)) {
+ ps->faceSeamFlags[tri_index] |= 1 << fidx1;
if (other_face != -1)
ps->faceSeamFlags[other_face] |= 1 << other_fidx;
}
else {
- ps->faceSeamFlags[face_index] |= 16 << fidx1;
+ ps->faceSeamFlags[tri_index] |= 16 << fidx1;
if (other_face != -1)
ps->faceSeamFlags[other_face] |= 16 << other_fidx; /* second 4 bits for disabled */
}
@@ -1181,28 +1248,66 @@ static void screen_px_from_persp(
}
-static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
- int side, unsigned char rgba_ub[4], float rgba_f[4])
+/**
+ * Set a direction vector based on a screen location.
+ * (use for perspective view, else we can simply use `ps->viewDir`)
+ *
+ * Similar functionality to #ED_view3d_win_to_vector
+ *
+ * \param r_dir: Resulting direction (length is undefined).
+ */
+static void screen_px_to_vector_persp(
+ int winx, int winy, const float projmat_inv[4][4], const float view_pos[3],
+ const float co_px[2],
+ float r_dir[3])
{
- const float *uvCo1, *uvCo2, *uvCo3;
- float uv_other[2], x, y;
+ r_dir[0] = 2.0f * (co_px[0] / winx) - 1.0f;
+ r_dir[1] = 2.0f * (co_px[1] / winy) - 1.0f;
+ r_dir[2] = -0.5f;
+ mul_project_m4_v3((float(*)[4])projmat_inv, r_dir);
+ sub_v3_v3(r_dir, view_pos);
+}
- uvCo1 = (float *)tf_other->uv[0];
- if (side == 1) {
- uvCo2 = (float *)tf_other->uv[2];
- uvCo3 = (float *)tf_other->uv[3];
- }
- else {
- uvCo2 = (float *)tf_other->uv[1];
- uvCo3 = (float *)tf_other->uv[2];
- }
+/**
+ * Special function to return the factor to a point along a line in pixel space.
+ *
+ * This is needed since we can't use #line_point_factor_v2 for perspective screen-space coords.
+ *
+ * \param p: 2D screen-space location.
+ * \param v1, v2: 3D object-space locations.
+ */
+static float screen_px_line_point_factor_v2_persp(
+ const ProjPaintState *ps,
+ const float p[2],
+ const float v1[3], const float v2[3])
+{
+ const float zero[3] = {0};
+ float v1_proj[3], v2_proj[3];
+ float dir[3];
+
+ screen_px_to_vector_persp(ps->winx, ps->winy, ps->projectMatInv, ps->viewPos, p, dir);
- interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w);
+ sub_v3_v3v3(v1_proj, v1, ps->viewPos);
+ sub_v3_v3v3(v2_proj, v2, ps->viewPos);
+
+ project_plane_v3_v3v3(v1_proj, v1_proj, dir);
+ project_plane_v3_v3v3(v2_proj, v2_proj, dir);
+
+ return line_point_factor_v2(zero, v1_proj, v2_proj);
+}
+
+
+static void project_face_pixel(
+ const float *lt_tri_uv[3], ImBuf *ibuf_other, const float w[3],
+ unsigned char rgba_ub[4], float rgba_f[4])
+{
+ float uv_other[2], x, y;
+
+ interp_v2_v2v2v2(uv_other, UNPACK3(lt_tri_uv), w);
/* use */
uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
-
if (ibuf_other->rect_float) { /* from float to float */
bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
}
@@ -1215,8 +1320,7 @@ static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const
/* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */
static float project_paint_uvpixel_mask(
const ProjPaintState *ps,
- const int face_index,
- const int side,
+ const int tri_index,
const float w[3])
{
float mask;
@@ -1226,14 +1330,16 @@ static float project_paint_uvpixel_mask(
/* another UV maps image is masking this one's */
ImBuf *ibuf_other;
Image *other_tpage = ps->stencil_ima;
- const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
+ const MLoopTri *lt_other = &ps->dm_mlooptri[tri_index];
+ const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt_other) };
+
/* BKE_image_acquire_ibuf - TODO - this may be slow */
unsigned char rgba_ub[4];
float rgba_f[4];
- project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f);
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
if (ibuf_other->rect_float) { /* from float to float */
mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) * (1.0f / 3.0f)) * rgba_f[3];
@@ -1259,21 +1365,32 @@ static float project_paint_uvpixel_mask(
mask = 1.0f;
}
+ if (ps->do_mask_cavity) {
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
+ float ca1, ca2, ca3, ca_mask;
+ ca1 = ps->cavities[lt_vtri[0]];
+ ca2 = ps->cavities[lt_vtri[1]];
+ ca3 = ps->cavities[lt_vtri[2]];
+
+ ca_mask = w[0] * ca1 + w[1] * ca2 + w[2] * ca3;
+ ca_mask = curvemapping_evaluateF(ps->cavity_curve, 0, ca_mask);
+ CLAMP(ca_mask, 0.0f, 1.0f);
+ mask *= ca_mask;
+ }
+
/* calculate mask */
if (ps->do_mask_normal) {
- MFace *mf = &ps->dm_mface[face_index];
- float no[3], angle;
- if (mf->flag & ME_SMOOTH) {
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
+ const MPoly *mp = &ps->dm_mpoly[lt->poly];
+ float no[3], angle_cos;
+
+ if (mp->flag & ME_SMOOTH) {
const short *no1, *no2, *no3;
- no1 = ps->dm_mvert[mf->v1].no;
- if (side == 1) {
- no2 = ps->dm_mvert[mf->v3].no;
- no3 = ps->dm_mvert[mf->v4].no;
- }
- else {
- no2 = ps->dm_mvert[mf->v2].no;
- no3 = ps->dm_mvert[mf->v3].no;
- }
+ no1 = ps->dm_mvert[lt_vtri[0]].no;
+ no2 = ps->dm_mvert[lt_vtri[1]].no;
+ no3 = ps->dm_mvert[lt_vtri[2]].no;
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@@ -1284,55 +1401,49 @@ static float project_paint_uvpixel_mask(
/* incase the */
#if 1
/* normalizing per pixel isn't optimal, we could cache or check ps->*/
- if (mf->v4)
- normal_quad_v3(no,
- ps->dm_mvert[mf->v1].co,
- ps->dm_mvert[mf->v2].co,
- ps->dm_mvert[mf->v3].co,
- ps->dm_mvert[mf->v4].co);
- else
- normal_tri_v3(no,
- ps->dm_mvert[mf->v1].co,
- ps->dm_mvert[mf->v2].co,
- ps->dm_mvert[mf->v3].co);
+ normal_tri_v3(no,
+ ps->dm_mvert[lt_vtri[0]].co,
+ ps->dm_mvert[lt_vtri[1]].co,
+ ps->dm_mvert[lt_vtri[2]].co);
#else
/* don't use because some modifiers dont have normal data (subsurf for eg) */
- copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, face_index, CD_NORMAL));
+ copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, tri_index, CD_NORMAL));
#endif
}
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
+
/* now we can use the normal as a mask */
if (ps->is_ortho) {
- angle = angle_normalized_v3v3((float *)ps->viewDir, no);
+ angle_cos = dot_v3v3(ps->viewDir, no);
}
else {
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
float viewDirPersp[3];
const float *co1, *co2, *co3;
- co1 = ps->dm_mvert[mf->v1].co;
- if (side == 1) {
- co2 = ps->dm_mvert[mf->v3].co;
- co3 = ps->dm_mvert[mf->v4].co;
- }
- else {
- co2 = ps->dm_mvert[mf->v2].co;
- co3 = ps->dm_mvert[mf->v3].co;
- }
+ co1 = ps->dm_mvert[lt_vtri[0]].co;
+ co2 = ps->dm_mvert[lt_vtri[1]].co;
+ co3 = ps->dm_mvert[lt_vtri[2]].co;
/* Get the direction from the viewPoint to the pixel and normalize */
viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
normalize_v3(viewDirPersp);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
- angle = angle_normalized_v3v3(viewDirPersp, no);
+ angle_cos = dot_v3v3(viewDirPersp, no);
}
- if (angle >= ps->normal_angle) {
+ if (angle_cos <= ps->normal_angle__cos) {
return 0.0f; /* outsize the normal limit*/
}
- else if (angle > ps->normal_angle_inner) {
- mask *= (ps->normal_angle - angle) / ps->normal_angle_range;
+ else if (angle_cos < ps->normal_angle_inner__cos) {
+ mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
} /* otherwise no mask normal is needed, were within the limit */
}
@@ -1375,10 +1486,14 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
if (generate_tile) {
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true);
+ undorect = image_undo_push_tile(
+ pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
+ tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false);
}
else {
- undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true);
+ undorect = image_undo_push_tile(
+ pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
+ tx, ty, NULL, &pjIma->valid[tile_index], true, false);
}
pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
@@ -1402,10 +1517,9 @@ static ProjPixel *project_paint_uvpixel_init(
const TileInfo *tinf,
int x_px, int y_px,
const float mask,
- const int face_index,
+ const int tri_index,
const float pixelScreenCo[4],
const float world_spaceCo[3],
- const int side,
const float w[3])
{
ProjPixel *projPixel;
@@ -1423,7 +1537,7 @@ static ProjPixel *project_paint_uvpixel_init(
y_px = mod_i(y_px, ibuf->y);
BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
- projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
+ projPixel = BLI_memarena_alloc(arena, ps->pixel_sizeof);
/* calculate the undo tile offset of the pixel, used to store the original
* pixel color and accumulated mask if any */
@@ -1479,22 +1593,24 @@ static ProjPixel *project_paint_uvpixel_init(
/* done with view3d_project_float inline */
if (ps->tool == PAINT_TOOL_CLONE) {
- if (ps->dm_mtface_clone) {
+ if (ps->dm_mloopuv_clone) {
ImBuf *ibuf_other;
- Image *other_tpage = project_paint_face_clone_image(ps, face_index);
- const MTFace *tf_other = ps->dm_mtface_clone[face_index];
+ Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
+ const MLoopTri *lt_other = &ps->dm_mlooptri[tri_index];
+ const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv_clone, lt_other) };
+
/* BKE_image_acquire_ibuf - TODO - this may be slow */
if (ibuf->rect_float) {
if (ibuf_other->rect_float) { /* from float to float */
- project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
}
else { /* from char to float */
unsigned char rgba_ub[4];
float rgba[4];
- project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL);
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
srgb_to_linearrgb_uchar4(rgba, rgba_ub);
straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
}
@@ -1502,12 +1618,13 @@ static ProjPixel *project_paint_uvpixel_init(
else {
if (ibuf_other->rect_float) { /* float to char */
float rgba[4];
- project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba);
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
premul_to_straight_v4(rgba);
linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
}
else { /* char to char */
- project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
+ project_face_pixel(lt_other_tri_uv, ibuf_other, w, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
}
}
@@ -1525,7 +1642,7 @@ static ProjPixel *project_paint_uvpixel_init(
}
else {
float co[2];
- sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset);
+ sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
/* no need to initialize the bucket, we're only checking buckets faces and for this
* the faces are already initialized in project_paint_delayed_face_init(...) */
@@ -1553,13 +1670,14 @@ static ProjPixel *project_paint_uvpixel_init(
}
static bool line_clip_rect2f(
- rctf *rect,
+ const rctf *cliprect,
+ const rctf *rect,
const float l1[2], const float l2[2],
float l1_clip[2], float l2_clip[2])
{
/* first account for horizontal, then vertical lines */
/* horiz */
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) {
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its Y axis? */
if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
return 0;
@@ -1570,7 +1688,7 @@ static bool line_clip_rect2f(
}
- if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@@ -1587,7 +1705,7 @@ static bool line_clip_rect2f(
CLAMP(l2_clip[0], rect->xmin, rect->xmax);
return 1;
}
- else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) {
+ else if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its X axis? */
if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
return 0;
@@ -1598,7 +1716,7 @@ static bool line_clip_rect2f(
return 0;
}
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@@ -1637,7 +1755,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* top/bottom */
- if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] < l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymin;
@@ -1652,7 +1770,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
- if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] > l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymax;
@@ -1668,7 +1786,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* left/right */
- if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] < l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmin;
l1_clip[1] = isect;
@@ -1683,7 +1801,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
- if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] > l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmax;
l1_clip[1] = isect;
@@ -1707,35 +1825,14 @@ static bool line_clip_rect2f(
-/* scale the quad & tri about its center
- * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the
- * edge of the face but slightly inside it occlusion tests don't return hits on adjacent faces */
+/**
+ * Scale the tri about its center
+ * scaling by #PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the
+ * edge of the face but slightly inside it occlusion tests don't return hits on adjacent faces
+ */
#ifndef PROJ_DEBUG_NOSEAMBLEED
-static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset)
-{
- float cent[3];
- cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) * (1.0f / 4.0f);
- cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) * (1.0f / 4.0f);
- cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) * (1.0f / 4.0f);
-
- sub_v3_v3v3(insetCos[0], origCos[0], cent);
- sub_v3_v3v3(insetCos[1], origCos[1], cent);
- sub_v3_v3v3(insetCos[2], origCos[2], cent);
- sub_v3_v3v3(insetCos[3], origCos[3], cent);
-
- mul_v3_fl(insetCos[0], inset);
- mul_v3_fl(insetCos[1], inset);
- mul_v3_fl(insetCos[2], inset);
- mul_v3_fl(insetCos[3], inset);
-
- add_v3_v3(insetCos[0], cent);
- add_v3_v3(insetCos[1], cent);
- add_v3_v3(insetCos[2], cent);
- add_v3_v3(insetCos[3], cent);
-}
-
-static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset)
+static void scale_tri(float insetCos[3][3], const float *origCos[4], const float inset)
{
float cent[3];
cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) * (1.0f / 3.0f);
@@ -1768,7 +1865,7 @@ static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const flo
/* note, use a squared value so we can use len_squared_v2v2
* be sure that you have done a bounds check first or this may fail */
/* only give bucket_bounds as an arg because we need it elsewhere */
-static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds)
+static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, const rctf *bucket_bounds)
{
/* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect
@@ -1823,7 +1920,7 @@ static bool project_bucket_isect_circle(const float cent[2], const float radius_
* however switching back to this for ortho is always an option */
static void rect_to_uvspace_ortho(
- rctf *bucket_bounds,
+ const rctf *bucket_bounds,
const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[4][2],
@@ -1856,7 +1953,7 @@ static void rect_to_uvspace_ortho(
/* same as above but use barycentric_weights_v2_persp */
static void rect_to_uvspace_persp(
- rctf *bucket_bounds,
+ const rctf *bucket_bounds,
const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[4][2],
@@ -1898,7 +1995,7 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
- return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
+ return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
}
#endif
@@ -1910,7 +2007,10 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
#define ISECT_ALL4 ((1 << 4) - 1)
/* limit must be a fraction over 1.0f */
-static bool IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
+static bool IsectPT2Df_limit(
+ const float pt[2],
+ const float v1[2], const float v2[2], const float v3[2],
+ const float limit)
{
return ((area_tri_v2(pt, v1, v2) +
area_tri_v2(pt, v2, v3) +
@@ -1930,27 +2030,88 @@ static int float_z_sort(const void *p1, const void *p2)
return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
}
+/* assumes one point is within the rectangle */
+static bool line_rect_clip(
+ const rctf *rect,
+ const float l1[4], const float l2[4],
+ const float uv1[2], const float uv2[2],
+ float uv[2], bool is_ortho)
+{
+ float min = FLT_MAX, tmp;
+ float xlen = l2[0] - l1[0];
+ float ylen = l2[1] - l1[1];
+
+ /* 0.1 might seem too much, but remember, this is pixels! */
+ if (xlen > 0.1f) {
+ if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) <= 0) {
+ tmp = rect->xmin;
+ min = min_ff((tmp - l1[0]) / xlen, min);
+ }
+ else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) {
+ tmp = rect->xmax;
+ min = min_ff((tmp - l1[0]) / xlen, min);
+ }
+ }
+
+ if (ylen > 0.1f) {
+ if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) <= 0) {
+ tmp = rect->ymin;
+ min = min_ff((tmp - l1[1]) / ylen, min);
+ }
+ else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) {
+ tmp = rect->ymax;
+ min = min_ff((tmp - l1[1]) / ylen, min);
+ }
+ }
+
+ if (min == FLT_MAX)
+ return false;
+
+ tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
+
+ uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0]));
+ uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1]));
+
+ return true;
+}
+
+
static void project_bucket_clip_face(
- const bool is_ortho,
- rctf *bucket_bounds,
- float *v1coSS, float *v2coSS, float *v3coSS,
+ const bool is_ortho, const bool is_flip_object,
+ const rctf *cliprect,
+ const rctf *bucket_bounds,
+ const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[8][2],
- int *tot)
+ int *tot, bool cull)
{
int inside_bucket_flag = 0;
int inside_face_flag = 0;
- const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
-
+ int flip;
+ bool collinear = false;
+
float bucket_bounds_ss[4][2];
+ /* detect pathological case where face the three vertices are almost collinear in screen space.
+ * mostly those will be culled but when flood filling or with smooth shading it's a possibility */
+ if (dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS) < 0.5f ||
+ dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS) < 0.5f)
+ {
+ collinear = true;
+ }
+
/* get the UV space bounding box */
inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
-
+
if (inside_bucket_flag == ISECT_ALL3) {
- /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */
+ /* is_flip_object is used here because we use the face winding */
+ flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
+ (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
+
+ /* all screenspace points are inside the bucket bounding box,
+ * this means we don't need to clip and can simply return the UVs */
if (flip) { /* facing the back? */
copy_v2_v2(bucket_bounds_uv[0], uv3co);
copy_v2_v2(bucket_bounds_uv[1], uv2co);
@@ -1960,9 +2121,55 @@ static void project_bucket_clip_face(
copy_v2_v2(bucket_bounds_uv[0], uv1co);
copy_v2_v2(bucket_bounds_uv[1], uv2co);
copy_v2_v2(bucket_bounds_uv[2], uv3co);
+ }
+
+ *tot = 3;
+ return;
+ }
+ /* handle pathological case here, no need for further intersections below since tringle area is almost zero */
+ if (collinear) {
+ int flag;
+
+ (*tot) = 0;
+
+ if (cull)
+ return;
+
+ if (inside_bucket_flag & ISECT_1) { copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++; }
+
+ flag = inside_bucket_flag & (ISECT_1 | ISECT_2);
+ if (flag && flag != (ISECT_1 | ISECT_2)) {
+ if (line_rect_clip(bucket_bounds, v1coSS, v2coSS, uv1co, uv2co, bucket_bounds_uv[*tot], is_ortho))
+ (*tot)++;
+ }
+
+ if (inside_bucket_flag & ISECT_2) { copy_v2_v2(bucket_bounds_uv[*tot], uv2co); (*tot)++; }
+
+ flag = inside_bucket_flag & (ISECT_2 | ISECT_3);
+ if (flag && flag != (ISECT_2 | ISECT_3)) {
+ if (line_rect_clip(bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho))
+ (*tot)++;
+ }
+
+ if (inside_bucket_flag & ISECT_3) { copy_v2_v2(bucket_bounds_uv[*tot], uv3co); (*tot)++; }
+
+ flag = inside_bucket_flag & (ISECT_3 | ISECT_1);
+ if (flag && flag != (ISECT_3 | ISECT_1)) {
+ if (line_rect_clip(bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho))
+ (*tot)++;
+ }
+
+ if ((*tot) < 3) {
+ /* no intersections to speak of, but more probable is that all face is just outside the
+ * rectangle and culled due to float precision issues. Since above teste have failed,
+ * just dump triangle as is for painting */
+ *tot = 0;
+ copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++;
+ copy_v2_v2(bucket_bounds_uv[*tot], uv2co); (*tot)++;
+ copy_v2_v2(bucket_bounds_uv[*tot], uv3co); (*tot)++;
+ return;
}
- *tot = 3;
return;
}
@@ -1984,11 +2191,18 @@ static void project_bucket_clip_face(
bucket_bounds_ss[3][1] = bucket_bounds->ymin;
inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0);
+ flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
+ (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
+
if (inside_face_flag == ISECT_ALL4) {
/* bucket is totally inside the screenspace face, we can safely use weights */
- if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
- else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+ if (is_ortho) {
+ rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+ }
+ else {
+ rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
+ }
*tot = 4;
return;
@@ -2019,7 +2233,7 @@ static void project_bucket_clip_face(
float cent[2] = {0.0f, 0.0f};
/*float up[2] = {0.0f, 1.0f};*/
int i;
- short doubles;
+ bool doubles;
(*tot) = 0;
@@ -2033,21 +2247,21 @@ static void project_bucket_clip_face(
if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
- if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
- if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
- if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
@@ -2085,53 +2299,39 @@ static void project_bucket_clip_face(
for (i = 0; i < (*tot); i++) {
v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
- isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
+ isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0],
+ v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
}
if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip);
else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort);
- /* remove doubles */
- /* first/last check */
- if (fabsf(isectVCosSS[0][0] - isectVCosSS[(*tot) - 1][0]) < PROJ_PIXEL_TOLERANCE &&
- fabsf(isectVCosSS[0][1] - isectVCosSS[(*tot) - 1][1]) < PROJ_PIXEL_TOLERANCE)
- {
- (*tot)--;
- }
-
- /* its possible there is only a few left after remove doubles */
- if ((*tot) < 3) {
- // printf("removed too many doubles A\n");
- *tot = 0;
- return;
- }
-
doubles = true;
while (doubles == true) {
doubles = false;
- for (i = 1; i < (*tot); i++) {
- if (fabsf(isectVCosSS[i - 1][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE &&
- fabsf(isectVCosSS[i - 1][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE)
+
+ for (i = 0; i < (*tot); i++) {
+ if (fabsf(isectVCosSS[(i + 1) % *tot][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE &&
+ fabsf(isectVCosSS[(i + 1) % *tot][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE)
{
int j;
- for (j = i + 1; j < (*tot); j++) {
- isectVCosSS[j - 1][0] = isectVCosSS[j][0];
- isectVCosSS[j - 1][1] = isectVCosSS[j][1];
+ for (j = i; j < (*tot) - 1; j++) {
+ isectVCosSS[j][0] = isectVCosSS[j + 1][0];
+ isectVCosSS[j][1] = isectVCosSS[j + 1][1];
}
doubles = true; /* keep looking for more doubles */
(*tot)--;
}
}
+
+ /* its possible there is only a few left after remove doubles */
+ if ((*tot) < 3) {
+ // printf("removed too many doubles B\n");
+ *tot = 0;
+ return;
+ }
}
- /* its possible there is only a few left after remove doubles */
- if ((*tot) < 3) {
- // printf("removed too many doubles B\n");
- *tot = 0;
- return;
- }
-
-
if (is_ortho) {
for (i = 0; i < (*tot); i++) {
barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
@@ -2155,7 +2355,9 @@ static void project_bucket_clip_face(
int i;
if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
- printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
+ printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ",
+ test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1],
+ test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]);
@@ -2242,7 +2444,7 @@ static bool IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
{
int i;
- int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
+ bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
for (i = 1; i < tot; i++) {
if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
@@ -2253,9 +2455,16 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
return 1;
}
-/* One of the most important function for projection painting, since it selects the pixels to be added into each bucket.
- * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
-static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
+/* One of the most important function for projection painting,
+ * since it selects the pixels to be added into each bucket.
+ *
+ * initialize pixels from this face where it intersects with the bucket_index,
+ * optionally initialize pixels for removing seams */
+static void project_paint_face_init(
+ const ProjPaintState *ps,
+ const int thread_index, const int bucket_index, const int tri_index, const int image_index,
+ const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf,
+ const bool clamp_u, const bool clamp_v)
{
/* Projection vars, to get the 3D locations into screen space */
MemArena *arena = ps->arena_mt[thread_index];
@@ -2271,8 +2480,9 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
ps->projImages + image_index
};
- const MFace *mf = ps->dm_mface + face_index;
- const MTFace *tf = ps->dm_mtface[face_index];
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
+ const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt) };
/* UV/pixel seeking data */
int x; /* Image X-Pixel */
@@ -2280,40 +2490,38 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
float mask;
float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
- int side;
- float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+ const float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to lt_vtri[0-2] */
- float *vCo[4]; /* vertex screenspace coords */
+ const float *vCo[3]; /* vertex screenspace coords */
float w[3], wco[3];
- float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
+ float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to lt_tri_uv[0],1,2 or lt_tri_uv[0],2,3 */
float pixelScreenCo[4];
bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
rcti bounds_px; /* ispace bounds */
/* vars for getting uvspace bounds */
- float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */
+ float lt_uv_pxoffset[3][2]; /* bucket bounds in UV space so we can init pixels only for this face, */
float xhalfpx, yhalfpx;
const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
int has_x_isect = 0, has_isect = 0; /* for early loop exit */
- int i1, i2, i3;
-
float uv_clip[8][2];
int uv_clip_tot;
const bool is_ortho = ps->is_ortho;
+ const bool is_flip_object = ps->is_flip_object;
const bool do_backfacecull = ps->do_backfacecull;
const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
- vCo[0] = ps->dm_mvert[mf->v1].co;
- vCo[1] = ps->dm_mvert[mf->v2].co;
- vCo[2] = ps->dm_mvert[mf->v3].co;
+ vCo[0] = ps->dm_mvert[lt_vtri[0]].co;
+ vCo[1] = ps->dm_mvert[lt_vtri[1]].co;
+ vCo[2] = ps->dm_mvert[lt_vtri[2]].co;
- /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel
+ /* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
* this is done so we can avoid offsetting all the pixels by 0.5 which causes
* problems when wrapping negative coords */
xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
@@ -2328,49 +2536,32 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
* but since the first thing most people try is painting onto a quad- better make it work.
*/
- tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx;
- tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx;
-
- tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx;
- tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx;
+ lt_uv_pxoffset[0][0] = lt_tri_uv[0][0] - xhalfpx;
+ lt_uv_pxoffset[0][1] = lt_tri_uv[0][1] - yhalfpx;
- tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx;
- tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx;
+ lt_uv_pxoffset[1][0] = lt_tri_uv[1][0] - xhalfpx;
+ lt_uv_pxoffset[1][1] = lt_tri_uv[1][1] - yhalfpx;
- if (mf->v4) {
- vCo[3] = ps->dm_mvert[mf->v4].co;
+ lt_uv_pxoffset[2][0] = lt_tri_uv[2][0] - xhalfpx;
+ lt_uv_pxoffset[2][1] = lt_tri_uv[2][1] - yhalfpx;
- tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx;
- tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx;
- side = 1;
- }
- else {
- side = 0;
- }
-
- do {
- if (side == 1) {
- i1 = 0; i2 = 2; i3 = 3;
- }
- else {
- i1 = 0; i2 = 1; i3 = 2;
- }
-
- uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1];
- uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2];
- uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3];
+ {
+ uv1co = lt_uv_pxoffset[0]; // was lt_tri_uv[i1];
+ uv2co = lt_uv_pxoffset[1]; // was lt_tri_uv[i2];
+ uv3co = lt_uv_pxoffset[2]; // was lt_tri_uv[i3];
- v1coSS = ps->screenCoords[(*(&mf->v1 + i1))];
- v2coSS = ps->screenCoords[(*(&mf->v1 + i2))];
- v3coSS = ps->screenCoords[(*(&mf->v1 + i3))];
+ v1coSS = ps->screenCoords[lt_vtri[0]];
+ v2coSS = ps->screenCoords[lt_vtri[1]];
+ v3coSS = ps->screenCoords[lt_vtri[2]];
- /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
+ /* This funtion gives is a concave polyline in UV space from the clipped tri*/
project_bucket_clip_face(
- is_ortho, bucket_bounds,
+ is_ortho, is_flip_object,
+ clip_rect, bucket_bounds,
v1coSS, v2coSS, v3coSS,
uv1co, uv2co, uv3co,
- uv_clip, &uv_clip_tot
- );
+ uv_clip, &uv_clip_tot,
+ do_backfacecull || ps->do_occlude);
/* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
#if 0
@@ -2391,10 +2582,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
CLAMP(bounds_px.ymax, 0, ibuf->y);
}
- /*
+#if 0
project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf,
tile_width, threaded, ps->do_masking);
- */
+#endif
/* clip face and */
has_isect = 0;
@@ -2420,7 +2611,12 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
/* a pity we need to get the worldspace pixel location here */
if (do_clip || do_3d_mapping) {
- interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w);
+ interp_v3_v3v3v3(
+ wco,
+ ps->dm_mvert[lt_vtri[0]].co,
+ ps->dm_mvert[lt_vtri[1]].co,
+ ps->dm_mvert[lt_vtri[2]].co,
+ w);
if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
continue; /* Watch out that no code below this needs to run */
}
@@ -2428,17 +2624,17 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
/* Is this UV visible from the view? - raytrace */
/* project_paint_PickFace is less complex, use for testing */
- //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) {
+ //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
if ((ps->do_occlude == false) ||
- !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
+ !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo))
{
- mask = project_paint_uvpixel_mask(ps, face_index, side, w);
+ mask = project_paint_uvpixel_mask(ps, tri_index, w);
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
- pixelScreenCo, wco, side, w),
+ project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, tri_index,
+ pixelScreenCo, wco, w),
arena
);
}
@@ -2462,8 +2658,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
#endif
}
}
- } while (side--);
-
+ }
#ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -2473,20 +2668,19 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (threaded)
BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
- face_seam_flag = ps->faceSeamFlags[face_index];
+ face_seam_flag = ps->faceSeamFlags[tri_index];
/* are any of our edges un-initialized? */
if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_NOSEAM1)) == 0 ||
(face_seam_flag & (PROJ_FACE_SEAM2 | PROJ_FACE_NOSEAM2)) == 0 ||
- (face_seam_flag & (PROJ_FACE_SEAM3 | PROJ_FACE_NOSEAM3)) == 0 ||
- (face_seam_flag & (PROJ_FACE_SEAM4 | PROJ_FACE_NOSEAM4)) == 0)
+ (face_seam_flag & (PROJ_FACE_SEAM3 | PROJ_FACE_NOSEAM3)) == 0)
{
- project_face_seams_init(ps, face_index, mf->v4);
- face_seam_flag = ps->faceSeamFlags[face_index];
- //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4);
+ project_face_seams_init(ps, tri_index);
+ face_seam_flag = ps->faceSeamFlags[tri_index];
+ //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3);
}
- if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) {
+ if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3)) == 0) {
if (threaded)
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
@@ -2496,65 +2690,58 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
/* we have a seam - deal with it! */
/* Now create new UV's for the seam face */
- float (*outset_uv)[2] = ps->faceSeamUVs[face_index];
- float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */
+ float (*outset_uv)[2] = ps->faceSeamUVs[tri_index];
+ float insetCos[3][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */
- float *vCoSS[4]; /* vertex screenspace coords */
+ const float *vCoSS[3]; /* vertex screenspace coords */
float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */
float edge_verts_inset_clip[2][3];
int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
float seam_subsection[4][2];
- float fac1, fac2, ftot;
-
+ float fac1, fac2;
if (outset_uv[0][0] == FLT_MAX) /* first time initialize */
- uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0);
+ uv_image_outset(
+ lt_uv_pxoffset, outset_uv, ps->seam_bleed_px,
+ ibuf->x, ibuf->y, (ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW) == 0);
/* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
if (threaded)
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
- vCoSS[0] = ps->screenCoords[mf->v1];
- vCoSS[1] = ps->screenCoords[mf->v2];
- vCoSS[2] = ps->screenCoords[mf->v3];
- if (mf->v4)
- vCoSS[3] = ps->screenCoords[mf->v4];
+ vCoSS[0] = ps->screenCoords[lt_vtri[0]];
+ vCoSS[1] = ps->screenCoords[lt_vtri[1]];
+ vCoSS[2] = ps->screenCoords[lt_vtri[2]];
/* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */
if (is_ortho) {
- if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
- else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
+ scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
}
else {
- if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
- else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
+ scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
}
- side = 0; /* for triangles this wont need to change */
-
- for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) {
- if (mf->v4) fidx2 = (fidx1 == 3) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
- else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
+ for (fidx1 = 0; fidx1 < 3; fidx1++) {
+ fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
- line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
+ line_clip_rect2f(clip_rect, bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
{
+ if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) { /* avoid div by zero */
- ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
-
- if (ftot > 0.0f) { /* avoid div by zero */
- if (mf->v4) {
- if (fidx1 == 2 || fidx2 == 2) side = 1;
- else side = 0;
+ if (is_ortho) {
+ fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
+ fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
+ }
+ else {
+ fac1 = screen_px_line_point_factor_v2_persp(ps, bucket_clip_edges[0], vCo[fidx1], vCo[fidx2]);
+ fac2 = screen_px_line_point_factor_v2_persp(ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]);
}
- fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
- fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
-
- interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
- interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
+ interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1);
+ interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2);
interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2);
interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1);
@@ -2565,7 +2752,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
- if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, true)) {
+ if (pixel_bounds_uv((const float (*)[2])seam_subsection, &bounds_px, ibuf->x, ibuf->y)) {
/* bounds between the seam rect and the uvspace bucket pixels */
has_isect = 0;
@@ -2579,7 +2766,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */
/* test we're inside uvspace bucket and triangle bounds */
- if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) {
+ if (isect_point_quad_v2(uv, UNPACK4(seam_subsection))) {
float fac;
/* We need to find the closest point along the face edge,
@@ -2593,11 +2780,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
/* Since this is a seam we need to work out where on the line this pixel is */
//fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]);
-
- fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]);
- if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); }
- else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); }
- else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
+ fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
+ interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
if (!is_ortho) {
pixelScreenCo[3] = 1.0f;
@@ -2608,57 +2792,41 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
}
if ((ps->do_occlude == false) ||
- !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
+ !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo))
{
/* Only bother calculating the weights if we intersect */
- if (ps->do_mask_normal || ps->dm_mtface_clone) {
-#if 1
+ if (ps->do_mask_normal || ps->dm_mloopuv_clone) {
+ const float uv_fac = fac1 + (fac * (fac2 - fac1));
+#if 0
/* get the UV on the line since we want to copy the pixels from there for bleeding */
float uv_close[2];
- float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]);
- if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]);
- else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]);
-
- if (side) {
- barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w);
- }
- else {
- barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w);
- }
-#else /* this is buggy with quads, don't use for now */
+ interp_v2_v2v2(uv_close, lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], uv_fac);
+ barycentric_weights_v2(lt_uv_pxoffset[0], lt_uv_pxoffset[1], lt_uv_pxoffset[2], uv_close, w);
+#else
/* Cheat, we know where we are along the edge so work out the weights from that */
- uv_fac = fac1 + (uv_fac * (fac2 - fac1));
-
w[0] = w[1] = w[2] = 0.0;
- if (side) {
- w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac;
- w[fidx2 ? fidx2 - 1 : 0] = uv_fac;
- }
- else {
- w[fidx1] = 1.0f - uv_fac;
- w[fidx2] = uv_fac;
- }
+ w[fidx1] = 1.0f - uv_fac;
+ w[fidx2] = uv_fac;
#endif
}
/* a pity we need to get the worldspace pixel location here */
if (do_clip || do_3d_mapping) {
- if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
- else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+ interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
continue; /* Watch out that no code below this needs to run */
}
}
- mask = project_paint_uvpixel_mask(ps, face_index, side, w);
+ mask = project_paint_uvpixel_mask(ps, tri_index, w);
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
- pixelScreenCo, wco, side, w),
+ project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, tri_index,
+ pixelScreenCo, wco, w),
arena
);
}
@@ -2684,6 +2852,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
}
}
}
+#else
+ UNUSED_VARS(vCo, threaded);
#endif // PROJ_DEBUG_NOSEAMBLEED
}
@@ -2720,10 +2890,12 @@ static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x,
/* Fill this bucket with pixels from the faces that intersect it.
*
* have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
-static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds)
+static void project_bucket_init(
+ const ProjPaintState *ps, const int thread_index, const int bucket_index,
+ const rctf *clip_rect, const rctf *bucket_bounds)
{
LinkNode *node;
- int face_index, image_index = 0;
+ int tri_index, image_index = 0;
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
Image *ima = NULL;
@@ -2735,17 +2907,20 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
ima = ps->projImages[0].ima;
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ project_paint_face_init(
+ ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0,
+ clip_rect, bucket_bounds, ibuf, &tmpibuf,
+ (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
else {
/* More complicated loop, switch between images */
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- face_index = GET_INT_FROM_POINTER(node->link);
+ tri_index = GET_INT_FROM_POINTER(node->link);
/* Image context switching */
- tpage = project_paint_face_paint_image(ps, face_index);
+ tpage = project_paint_face_paint_image(ps, tri_index);
if (tpage_last != tpage) {
tpage_last = tpage;
@@ -2759,7 +2934,10 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
}
/* context switching done */
- project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ project_paint_face_init(
+ ps, thread_index, bucket_index, tri_index, image_index,
+ clip_rect, bucket_bounds, ibuf, &tmpibuf,
+ (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
@@ -2776,66 +2954,47 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
* calculated when it might not be needed later, (at the moment at least)
* obviously it shouldn't have bugs though */
-static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf)
+static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MLoopTri *lt)
{
/* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
rctf bucket_bounds;
float p1[2], p2[2], p3[2], p4[2];
- const float *v, *v1, *v2, *v3, *v4 = NULL;
+ const float *v, *v1, *v2, *v3;
int fidx;
project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
-
+
/* Is one of the faces verts in the bucket bounds? */
- fidx = mf->v4 ? 3 : 2;
+ fidx = 2;
do {
- v = ps->screenCoords[(*(&mf->v1 + fidx))];
+ v = ps->screenCoords[lt_vtri[fidx]];
if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
return 1;
}
} while (fidx--);
- v1 = ps->screenCoords[mf->v1];
- v2 = ps->screenCoords[mf->v2];
- v3 = ps->screenCoords[mf->v3];
- if (mf->v4) {
- v4 = ps->screenCoords[mf->v4];
- }
+ v1 = ps->screenCoords[lt_vtri[0]];
+ v2 = ps->screenCoords[lt_vtri[1]];
+ v3 = ps->screenCoords[lt_vtri[2]];
p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin;
p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax;
p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax;
p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin;
- if (mf->v4) {
- if (isect_point_quad_v2(p1, v1, v2, v3, v4) ||
- isect_point_quad_v2(p2, v1, v2, v3, v4) ||
- isect_point_quad_v2(p3, v1, v2, v3, v4) ||
- isect_point_quad_v2(p4, v1, v2, v3, v4) ||
-
- /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
- (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) ||
- (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) ||
- (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) ||
- (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4)))
- {
- return 1;
- }
- }
- else {
- if (isect_point_tri_v2(p1, v1, v2, v3) ||
- isect_point_tri_v2(p2, v1, v2, v3) ||
- isect_point_tri_v2(p3, v1, v2, v3) ||
- isect_point_tri_v2(p4, v1, v2, v3) ||
- /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
- (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) ||
- (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) ||
- (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) ||
- (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3)))
- {
- return 1;
- }
+ if (isect_point_tri_v2(p1, v1, v2, v3) ||
+ isect_point_tri_v2(p2, v1, v2, v3) ||
+ isect_point_tri_v2(p3, v1, v2, v3) ||
+ isect_point_tri_v2(p4, v1, v2, v3) ||
+ /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
+ (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) ||
+ (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) ||
+ (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) ||
+ (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3)))
+ {
+ return 1;
}
return 0;
@@ -2843,8 +3002,9 @@ static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int buck
/* Add faces to the bucket but don't initialize its pixels
* TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */
-static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index)
+static void project_paint_delayed_face_init(ProjPaintState *ps, const MLoopTri *lt, const int tri_index)
{
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
float min[2], max[2], *vCoSS;
int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */
int fidx, bucket_x, bucket_y;
@@ -2853,9 +3013,9 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
INIT_MINMAX2(min, max);
- fidx = mf->v4 ? 3 : 2;
+ fidx = 2;
do {
- vCoSS = ps->screenCoords[*(&mf->v1 + fidx)];
+ vCoSS = ps->screenCoords[lt_vtri[fidx]];
minmax_v2v2_v2(min, max, vCoSS);
} while (fidx--);
@@ -2864,11 +3024,11 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
has_x_isect = 0;
for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
- if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) {
+ if (project_bucket_face_isect(ps, bucket_x, bucket_y, lt)) {
int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
BLI_linklist_prepend_arena(
&ps->bucketFaces[bucket_index],
- SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */
+ SET_INT_IN_POINTER(tri_index), /* cast to a pointer to shut up the compiler */
arena
);
@@ -2888,254 +3048,146 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
- if (!mf->v4) {
- ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */
- }
- **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized */
+ **ps->faceSeamUVs[tri_index] = FLT_MAX; /* set as uninitialized */
}
#endif
}
-/* run once per stroke before projection painting */
-static void project_paint_begin(ProjPaintState *ps)
+/**
+ * \note when using subsurf or multires, some arrays are thrown away, we need to keep a copy
+ */
+static void proj_paint_state_non_cddm_init(ProjPaintState *ps)
{
- /* Viewport vars */
- float mat[3][3];
-
- float no[3];
-
- float *projScreenCo; /* Note, we could have 4D vectors are only needed for */
- float projMargin;
-
- /* Image Vars - keep track of images we have used */
- LinkNode *image_LinkList = NULL;
- LinkNode *node;
-
- ProjPaintImage *projIma;
- Image *tpage_last = NULL, *tpage;
- TexPaintSlot *slot_last = NULL, *slot = NULL;
- TexPaintSlot *slot_last_clone = NULL, *slot_clone;
-
- /* Face vars */
- MPoly *mpoly_orig;
- MFace *mf;
- MTFace **tf;
- MTFace *tf_base;
-
- MTFace **tf_clone;
- MTFace *tf_clone_base = NULL;
-
- int a, i; /* generic looping vars */
- int image_index = -1, face_index;
-
- /* double lookup */
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
-
- MVert *mv;
-
- MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
-
- const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
-
- bool reset_threads = false;
-
- /* ---- end defines ---- */
-
- if (ps->source == PROJ_SRC_VIEW)
- ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
-
- ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
-
- /* paint onto the derived mesh */
-
- /* Workaround for subsurf selection, try the display mesh first */
- if (ps->source == PROJ_SRC_IMAGE_CAM) {
- /* using render mesh, assume only camera was rendered from */
- ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
- ps->dm_release = true;
- }
- else if (ps->ob->derivedFinal &&
- CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) &&
- (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX)))
- {
- ps->dm = ps->ob->derivedFinal;
- ps->dm_release = false;
- }
- else {
- ps->dm = mesh_get_derived_final(
- ps->scene, ps->ob,
- ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0));
- ps->dm_release = true;
- }
-
- if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) {
-
- if (ps->dm_release)
- ps->dm->release(ps->dm);
-
- ps->dm = NULL;
- return;
- }
-
- DM_update_materials(ps->dm, ps->ob);
-
- ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
- ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
-
- ps->dm_mvert = ps->dm->getVertArray(ps->dm);
- ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
- ps->dm_mtface = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
-
- if (ps->do_face_sel) {
- index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX);
- index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
- else {
- mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
- }
- }
- else {
- mpoly_orig = NULL;
- }
-
- /* use clone mtface? */
- if (ps->do_layer_clone) {
- ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
- }
-
- if (ps->do_layer_stencil || ps->do_stencil_brush) {
- //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
- int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
- if (layer_num != -1)
- ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
-
- if (ps->dm_mtface_stencil == NULL) {
- /* get active instead */
- ps->dm_mtface_stencil = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
- }
-
- if (ps->do_stencil_brush)
- tf_base = ps->dm_mtface_stencil;
- }
-
- if (ps->do_layer_clone) {
- int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
-
- if (layer_num != -1)
- tf_clone_base = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
-
- if (tf_clone_base == NULL) {
- /* get active instead */
- tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
- }
-
- }
-
- /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
if (ps->dm->type != DM_TYPE_CDDM) {
ps->dm_mvert = MEM_dupallocN(ps->dm_mvert);
- ps->dm_mface = MEM_dupallocN(ps->dm_mface);
+ ps->dm_mpoly = MEM_dupallocN(ps->dm_mpoly);
+ ps->dm_mloop = MEM_dupallocN(ps->dm_mloop);
/* looks like these are ok for now.*/
#if 0
- ps->dm_mtface = MEM_dupallocN(ps->dm_mtface);
- ps->dm_mtface_clone = MEM_dupallocN(ps->dm_mtface_clone);
- ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil);
+ ps->dm_mloopuv = MEM_dupallocN(ps->dm_mloopuv);
+ ps->dm_mloopuv_clone = MEM_dupallocN(ps->dm_mloopuv_clone);
+ ps->dm_mloopuv_stencil = MEM_dupallocN(ps->dm_mloopuv_stencil);
#endif
}
+}
+
+static void proj_paint_state_viewport_init(
+ ProjPaintState *ps, const char symmetry_flag)
+{
+ float mat[3][3];
+ float viewmat[4][4];
+ float viewinv[4][4];
ps->viewDir[0] = 0.0f;
ps->viewDir[1] = 0.0f;
ps->viewDir[2] = 1.0f;
- {
- float viewmat[4][4];
- float viewinv[4][4];
+ copy_m4_m4(ps->obmat, ps->ob->obmat);
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+ if (symmetry_flag) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if ((symmetry_flag >> i) & 1) {
+ negate_v3(ps->obmat[i]);
+ ps->is_flip_object = !ps->is_flip_object;
+ }
+ }
+ }
- if (ps->source == PROJ_SRC_VIEW) {
- /* normal drawing */
- ps->winx = ps->ar->winx;
- ps->winy = ps->ar->winy;
+ invert_m4_m4(ps->obmat_imat, ps->obmat);
- copy_m4_m4(viewmat, ps->rv3d->viewmat);
- copy_m4_m4(viewinv, ps->rv3d->viewinv);
+ if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
+ /* normal drawing */
+ ps->winx = ps->ar->winx;
+ ps->winy = ps->ar->winy;
- ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
+ copy_m4_m4(viewmat, ps->rv3d->viewmat);
+ copy_m4_m4(viewinv, ps->rv3d->viewinv);
- ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
- }
- else {
- /* re-projection */
- float winmat[4][4];
- float vmat[4][4];
+ ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
- ps->winx = ps->reproject_ibuf->x;
- ps->winy = ps->reproject_ibuf->y;
+ ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
+ }
+ else {
+ /* re-projection */
+ float winmat[4][4];
+ float vmat[4][4];
- if (ps->source == PROJ_SRC_IMAGE_VIEW) {
- /* image stores camera data, tricky */
- IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
- IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
+ ps->winx = ps->reproject_ibuf->x;
+ ps->winy = ps->reproject_ibuf->y;
- const float *array = (float *)IDP_Array(view_data);
+ if (ps->source == PROJ_SRC_IMAGE_VIEW) {
+ /* image stores camera data, tricky */
+ IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
+ IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
- /* use image array, written when creating image */
- memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
- memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
- ps->clipsta = array[0];
- ps->clipend = array[1];
- ps->is_ortho = array[2] ? 1 : 0;
+ const float *array = (float *)IDP_Array(view_data);
- invert_m4_m4(viewinv, viewmat);
- }
- else if (ps->source == PROJ_SRC_IMAGE_CAM) {
- Object *cam_ob = ps->scene->camera;
- CameraParams params;
-
- /* viewmat & viewinv */
- copy_m4_m4(viewinv, cam_ob->obmat);
- normalize_m4(viewinv);
- invert_m4_m4(viewmat, viewinv);
-
- /* window matrix, clipping and ortho */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob);
- BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
- BKE_camera_params_compute_matrix(&params);
-
- copy_m4_m4(winmat, params.winmat);
- ps->clipsta = params.clipsta;
- ps->clipend = params.clipend;
- ps->is_ortho = params.is_ortho;
- }
+ /* use image array, written when creating image */
+ memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
+ memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
+ ps->clipsta = array[0];
+ ps->clipend = array[1];
+ ps->is_ortho = array[2] ? 1 : 0;
- /* same as #ED_view3d_ob_project_mat_get */
- mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
- mul_m4_m4m4(ps->projectMat, winmat, vmat);
+ invert_m4_m4(viewinv, viewmat);
+ }
+ else if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ Object *cam_ob = ps->scene->camera;
+ CameraParams params;
+
+ /* viewmat & viewinv */
+ copy_m4_m4(viewinv, cam_ob->obmat);
+ normalize_m4(viewinv);
+ invert_m4_m4(viewmat, viewinv);
+
+ /* window matrix, clipping and ortho */
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, cam_ob);
+ BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
+ BKE_camera_params_compute_matrix(&params);
+
+ copy_m4_m4(winmat, params.winmat);
+ ps->clipsta = params.clipsta;
+ ps->clipend = params.clipend;
+ ps->is_ortho = params.is_ortho;
+ }
+ else {
+ BLI_assert(0);
}
+ /* same as #ED_view3d_ob_project_mat_get */
+ mul_m4_m4m4(vmat, viewmat, ps->obmat);
+ mul_m4_m4m4(ps->projectMat, winmat, vmat);
+ }
+
+ invert_m4_m4(ps->projectMatInv, ps->projectMat);
- /* viewDir - object relative */
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
- copy_m3_m4(mat, viewinv);
- mul_m3_v3(mat, ps->viewDir);
- copy_m3_m4(mat, ps->ob->imat);
- mul_m3_v3(mat, ps->viewDir);
- normalize_v3(ps->viewDir);
+ /* viewDir - object relative */
+ copy_m3_m4(mat, viewinv);
+ mul_m3_v3(mat, ps->viewDir);
+ copy_m3_m4(mat, ps->obmat_imat);
+ mul_m3_v3(mat, ps->viewDir);
+ normalize_v3(ps->viewDir);
- /* viewPos - object relative */
- copy_v3_v3(ps->viewPos, viewinv[3]);
- copy_m3_m4(mat, ps->ob->imat);
- mul_m3_v3(mat, ps->viewPos);
- add_v3_v3(ps->viewPos, ps->ob->imat[3]);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(ps->viewDir);
}
- /* calculate vert screen coords
- * run this early so we can calculate the x/y resolution of our bucket rect */
+ /* viewPos - object relative */
+ copy_v3_v3(ps->viewPos, viewinv[3]);
+ copy_m3_m4(mat, ps->obmat_imat);
+ mul_m3_v3(mat, ps->viewPos);
+ add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
+}
+
+static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
+{
+ const MVert *mv;
+ float *projScreenCo;
+ float projMargin;
+ int a;
+
INIT_MINMAX2(ps->screenMin, ps->screenMax);
ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
@@ -3176,7 +3228,7 @@ static void project_paint_begin(ProjPaintState *ps)
}
/* If this border is not added we get artifacts for faces that
- * have a parallel edge and at the bounds of the the 2D projected verts eg
+ * have a parallel edge and at the bounds of the 2D projected verts eg
* - a single screen aligned quad */
projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
ps->screenMax[0] += projMargin;
@@ -3192,47 +3244,74 @@ static void project_paint_begin(ProjPaintState *ps)
CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
+#else
+ UNUSED_VARS(diameter);
#endif
}
- else { /* re-projection, use bounds */
+ else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
ps->screenMin[0] = 0;
ps->screenMax[0] = (float)(ps->winx);
ps->screenMin[1] = 0;
ps->screenMax[1] = (float)(ps->winy);
}
+}
- /* only for convenience */
- ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
- ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
-
- ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
- ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+static void proj_paint_state_cavity_init(ProjPaintState *ps)
+{
+ const MVert *mv;
+ const MEdge *me;
+ float *cavities;
+ int a;
- /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
+ if (ps->do_mask_cavity) {
+ int *counter = MEM_callocN(sizeof(int) * ps->dm_totvert, "counter");
+ float (*edges)[3] = MEM_callocN(sizeof(float) * 3 * ps->dm_totvert, "edges");
+ ps->cavities = MEM_mallocN(sizeof(float) * ps->dm_totvert, "ProjectPaint Cavities");
+ cavities = ps->cavities;
+
+ for (a = 0, me = ps->dm_medge; a < ps->dm_totedge; a++, me++) {
+ float e[3];
+ sub_v3_v3v3(e, ps->dm_mvert[me->v1].co, ps->dm_mvert[me->v2].co);
+ normalize_v3(e);
+ add_v3_v3(edges[me->v2], e);
+ counter[me->v2]++;
+ sub_v3_v3(edges[me->v1], e);
+ counter[me->v1]++;
+ }
+ for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
+ if (counter[a] > 0) {
+ float no[3];
+ mul_v3_fl(edges[a], 1.0f / counter[a]);
+ normal_short_to_float_v3(no, mv->no);
+ /* augment the diffe*/
+ cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
+ }
+ else
+ cavities[a] = 0.0;
+ }
- if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
- reset_threads = true;
+ MEM_freeN(counter);
+ MEM_freeN(edges);
}
+}
- /* really high values could cause problems since it has to allocate a few
- * (ps->buckets_x*ps->buckets_y) sized arrays */
- CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
- CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
-
- ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
- ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
-
- ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
#ifndef PROJ_DEBUG_NOSEAMBLEED
+static void proj_paint_state_seam_bleed_init(ProjPaintState *ps)
+{
if (ps->seam_bleed_px > 0.0f) {
- ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
- ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags");
- ps->faceWindingFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceWindindFlags");
- ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs");
+ ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
+ ps->faceSeamFlags = MEM_callocN(sizeof(char) * ps->dm_totlooptri, "paint-faceSeamFlags");
+ ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->dm_totlooptri, "paint-faceWindindFlags");
+ ps->faceSeamUVs = MEM_mallocN(sizeof(float[3][2]) * ps->dm_totlooptri, "paint-faceSeamUVs");
}
+}
#endif
+static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads)
+{
+ int a;
+
/* Thread stuff
*
* very small brushes run a lot slower multithreaded since the advantage with
@@ -3246,85 +3325,364 @@ static void project_paint_begin(ProjPaintState *ps)
if (reset_threads)
ps->thread_tot = 1;
- if (ps->thread_tot > 1) {
- ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
- BLI_spin_init(ps->tile_lock);
- }
+ if (ps->is_shared_user == false) {
+ if (ps->thread_tot > 1) {
+ ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
+ BLI_spin_init(ps->tile_lock);
+ }
- image_undo_init_locks();
+ image_undo_init_locks();
+ }
for (a = 0; a < ps->thread_tot; a++) {
ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
}
+}
- arena = ps->arena_mt[0];
-
+static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
+{
if (ps->do_backfacecull && ps->do_mask_normal) {
float viewDirPersp[3];
+ const MVert *mv;
+ float no[3];
+ int a;
ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
normal_short_to_float_v3(no, mv->no);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
if (ps->is_ortho) {
- if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) { /* 1 vert of this face is towards us */
ps->vertFlags[a] |= PROJ_VERT_CULL;
}
}
else {
sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
normalize_v3(viewDirPersp);
- if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
+ if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) { /* 1 vert of this face is towards us */
ps->vertFlags[a] |= PROJ_VERT_CULL;
}
}
}
}
-
- for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
- bool is_face_sel;
+ else {
+ ps->vertFlags = NULL;
+ }
+}
#ifndef PROJ_DEBUG_NOSEAMBLEED
- /* add face user if we have bleed enabled, set the UV seam flags later */
- /* annoying but we need to add all faces even ones we never use elsewhere */
- if (ps->seam_bleed_px > 0.0f) {
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena);
- if (mf->v4) {
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena);
- }
- }
+static void project_paint_bleed_add_face_user(
+ const ProjPaintState *ps, MemArena *arena,
+ const MLoopTri *lt, const int tri_index)
+{
+ /* add face user if we have bleed enabled, set the UV seam flags later */
+ /* annoying but we need to add all faces even ones we never use elsewhere */
+ if (ps->seam_bleed_px > 0.0f) {
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
+ void *tri_index_p = SET_INT_IN_POINTER(tri_index);
+ BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[0]], tri_index_p, arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[1]], tri_index_p, arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[2]], tri_index_p, arena);
+ }
+}
#endif
- if (ps->do_face_sel) {
- int orig_index;
- if (index_mp_to_orig && ((orig_index = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig,
- face_index))) != ORIGINDEX_NONE)
- {
- MPoly *mp = &mpoly_orig[orig_index];
- is_face_sel = ((mp->flag & ME_FACE_SEL) != 0);
- }
- else {
- is_face_sel = ((mf->flag & ME_FACE_SEL) != 0);
+/* Return true if DM can be painted on, false otherwise */
+static bool proj_paint_state_dm_init(ProjPaintState *ps)
+{
+ /* Workaround for subsurf selection, try the display mesh first */
+ if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ /* using render mesh, assume only camera was rendered from */
+ ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
+ ps->dm_release = true;
+ }
+ else if (ps->ob->derivedFinal &&
+ CustomData_has_layer(&ps->ob->derivedFinal->loopData, CD_MLOOPUV) &&
+ (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX)))
+ {
+ ps->dm = ps->ob->derivedFinal;
+ ps->dm_release = false;
+ }
+ else {
+ ps->dm = mesh_get_derived_final(
+ ps->scene, ps->ob,
+ ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0));
+ ps->dm_release = true;
+ }
+
+ if (!CustomData_has_layer(&ps->dm->loopData, CD_MLOOPUV)) {
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+
+ ps->dm = NULL;
+ return false;
+ }
+
+ DM_update_materials(ps->dm, ps->ob);
+
+ ps->dm_mvert = ps->dm->getVertArray(ps->dm);
+
+ if (ps->do_mask_cavity)
+ ps->dm_medge = ps->dm->getEdgeArray(ps->dm);
+
+ ps->dm_mloop = ps->dm->getLoopArray(ps->dm);
+ ps->dm_mpoly = ps->dm->getPolyArray(ps->dm);
+
+ ps->dm_mlooptri = ps->dm->getLoopTriArray(ps->dm);
+
+ ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
+ ps->dm_totedge = ps->dm->getNumEdges(ps->dm);
+ ps->dm_totpoly = ps->dm->getNumPolys(ps->dm);
+ ps->dm_totlooptri = ps->dm->getNumLoopTri(ps->dm);
+
+ ps->dm_mloopuv = MEM_mallocN(ps->dm_totpoly * sizeof(MLoopUV *), "proj_paint_mtfaces");
+
+ return true;
+}
+
+typedef struct {
+ const MLoopUV *mloopuv_clone_base;
+ const TexPaintSlot *slot_last_clone;
+ const TexPaintSlot *slot_clone;
+} ProjPaintLayerClone;
+
+static void proj_paint_layer_clone_init(
+ ProjPaintState *ps,
+ ProjPaintLayerClone *layer_clone)
+{
+ MLoopUV *mloopuv_clone_base = NULL;
+
+ /* use clone mtface? */
+ if (ps->do_layer_clone) {
+ const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
+
+ ps->dm_mloopuv_clone = MEM_mallocN(ps->dm_totpoly * sizeof(MLoopUV *), "proj_paint_mtfaces");
+
+ if (layer_num != -1)
+ mloopuv_clone_base = CustomData_get_layer_n(&ps->dm->loopData, CD_MLOOPUV, layer_num);
+
+ if (mloopuv_clone_base == NULL) {
+ /* get active instead */
+ mloopuv_clone_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ }
+
+ }
+
+ memset(layer_clone, 0, sizeof(*layer_clone));
+ layer_clone->mloopuv_clone_base = mloopuv_clone_base;
+}
+
+/* Return true if face should be skipped, false otherwise */
+static bool project_paint_clone_face_skip(
+ ProjPaintState *ps,
+ ProjPaintLayerClone *lc,
+ const TexPaintSlot *slot,
+ const int tri_index)
+{
+ if (ps->do_layer_clone) {
+ if (ps->do_material_slots) {
+ lc->slot_clone = project_paint_face_clone_slot(ps, tri_index);
+ /* all faces should have a valid slot, reassert here */
+ if (ELEM(lc->slot_clone, NULL, slot))
+ return true;
+ }
+ else if (ps->clone_ima == ps->canvas_ima)
+ return true;
+
+ if (ps->do_material_slots) {
+ if (lc->slot_clone != lc->slot_last_clone) {
+ if (!slot->uvname ||
+ !(lc->mloopuv_clone_base = CustomData_get_layer_named(
+ &ps->dm->loopData, CD_MLOOPUV,
+ lc->slot_clone->uvname)))
+ {
+ lc->mloopuv_clone_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ }
+ lc->slot_last_clone = lc->slot_clone;
}
}
+
+ /* will set multiple times for 4+ sided poly */
+ ps->dm_mloopuv_clone[ps->dm_mlooptri[tri_index].poly] = lc->mloopuv_clone_base;
+ }
+ return false;
+}
+
+typedef struct {
+ const MPoly *mpoly_orig;
+
+ const int *index_mp_to_orig;
+} ProjPaintFaceLookup;
+
+static void proj_paint_face_lookup_init(
+ const ProjPaintState *ps,
+ ProjPaintFaceLookup *face_lookup)
+{
+ memset(face_lookup, 0, sizeof(*face_lookup));
+ if (ps->do_face_sel) {
+ face_lookup->index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
+ face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
+ }
+}
+
+/* Return true if face should be considered selected, false otherwise */
+static bool project_paint_check_face_sel(
+ const ProjPaintState *ps,
+ const ProjPaintFaceLookup *face_lookup,
+ const MLoopTri *lt)
+{
+ if (ps->do_face_sel) {
+ int orig_index;
+ const MPoly *mp;
+
+ if ((face_lookup->index_mp_to_orig != NULL) &&
+ (((orig_index = (face_lookup->index_mp_to_orig[lt->poly]))) != ORIGINDEX_NONE))
+ {
+ mp = &face_lookup->mpoly_orig[orig_index];
+ }
else {
- is_face_sel = true;
+ mp = &ps->dm_mpoly[lt->poly];
}
+ return ((mp->flag & ME_FACE_SEL) != 0);
+ }
+ else {
+ return true;
+ }
+}
+
+typedef struct {
+ const float *v1;
+ const float *v2;
+ const float *v3;
+} ProjPaintFaceCoSS;
+
+static void proj_paint_face_coSS_init(
+ const ProjPaintState *ps, const MLoopTri *lt,
+ ProjPaintFaceCoSS *coSS)
+{
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
+ coSS->v1 = ps->screenCoords[lt_vtri[0]];
+ coSS->v2 = ps->screenCoords[lt_vtri[1]];
+ coSS->v3 = ps->screenCoords[lt_vtri[2]];
+}
+
+/* Return true if face should be culled, false otherwise */
+static bool project_paint_flt_max_cull(
+ const ProjPaintState *ps,
+ const ProjPaintFaceCoSS *coSS)
+{
+ if (!ps->is_ortho) {
+ if (coSS->v1[0] == FLT_MAX ||
+ coSS->v2[0] == FLT_MAX ||
+ coSS->v3[0] == FLT_MAX)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef PROJ_DEBUG_WINCLIP
+/* Return true if face should be culled, false otherwise */
+static bool project_paint_winclip(
+ const ProjPaintState *ps,
+ const ProjPaintFaceCoSS *coSS)
+{
+ /* ignore faces outside the view */
+ return ((ps->source != PROJ_SRC_VIEW_FILL) &&
+ ((coSS->v1[0] < ps->screenMin[0] &&
+ coSS->v2[0] < ps->screenMin[0] &&
+ coSS->v3[0] < ps->screenMin[0]) ||
+
+ (coSS->v1[0] > ps->screenMax[0] &&
+ coSS->v2[0] > ps->screenMax[0] &&
+ coSS->v3[0] > ps->screenMax[0]) ||
+
+ (coSS->v1[1] < ps->screenMin[1] &&
+ coSS->v2[1] < ps->screenMin[1] &&
+ coSS->v3[1] < ps->screenMin[1]) ||
+
+ (coSS->v1[1] > ps->screenMax[1] &&
+ coSS->v2[1] > ps->screenMax[1] &&
+ coSS->v3[1] > ps->screenMax[1])));
+}
+#endif //PROJ_DEBUG_WINCLIP
+
+
+static void project_paint_build_proj_ima(
+ ProjPaintState *ps, MemArena *arena,
+ LinkNode *image_LinkList)
+{
+ ProjPaintImage *projIma;
+ LinkNode *node;
+ int i;
+
+ /* build an array of images we use */
+ projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
+
+ for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
+ int size;
+ projIma->ima = node->link;
+ projIma->touch = 0;
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
+ size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
+ memset(projIma->undoRect, 0, size);
+ projIma->maskRect = BLI_memarena_alloc(arena, size);
+ memset(projIma->maskRect, 0, size);
+ projIma->valid = BLI_memarena_alloc(arena, size);
+ memset(projIma->valid, 0, size);
+ }
+}
+
+static void project_paint_prepare_all_faces(
+ ProjPaintState *ps, MemArena *arena,
+ const ProjPaintFaceLookup *face_lookup,
+ ProjPaintLayerClone *layer_clone,
+ const MLoopUV *mloopuv_base,
+ const bool is_multi_view)
+{
+ /* Image Vars - keep track of images we have used */
+ LinkNodePair image_LinkList = {NULL, NULL};
+
+ Image *tpage_last = NULL, *tpage;
+ TexPaintSlot *slot_last = NULL;
+ TexPaintSlot *slot = NULL;
+ const MLoopTri *lt;
+ int image_index = -1, tri_index;
+ int prev_poly = -1;
+
+ for (tri_index = 0, lt = ps->dm_mlooptri; tri_index < ps->dm_totlooptri; tri_index++, lt++) {
+ bool is_face_sel;
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
+#endif
+
+ is_face_sel = project_paint_check_face_sel(ps, face_lookup, lt);
+
if (!ps->do_stencil_brush) {
- slot = project_paint_face_paint_slot(ps, face_index);
+ slot = project_paint_face_paint_slot(ps, tri_index);
/* all faces should have a valid slot, reassert here */
if (slot == NULL) {
- tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ mloopuv_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
tpage = ps->canvas_ima;
}
else {
if (slot != slot_last) {
- if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname)))
- tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(&ps->dm->loopData, CD_MLOOPUV, slot->uvname)))
+ mloopuv_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
slot_last = slot;
}
@@ -3339,110 +3697,68 @@ static void project_paint_begin(ProjPaintState *ps)
tpage = ps->stencil_ima;
}
- *tf = tf_base + face_index;
+ ps->dm_mloopuv[lt->poly] = mloopuv_base;
- if (ps->do_layer_clone) {
- if (ps->do_material_slots) {
- slot_clone = project_paint_face_clone_slot(ps, face_index);
- /* all faces should have a valid slot, reassert here */
- if (ELEM(slot_clone, NULL, slot))
- continue;
- }
- else if (ps->clone_ima == ps->canvas_ima)
- continue;
-
- tf_clone = ps->dm_mtface_clone + face_index;
-
- if (ps->do_material_slots) {
- if (slot_clone != slot_last_clone) {
- if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname)))
- tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
- slot_last_clone = slot_clone;
- }
- }
-
- *tf_clone = tf_clone_base + face_index;
+ if (project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
+ continue;
}
/* tfbase here should be non-null! */
- BLI_assert (tf_base != NULL);
+ BLI_assert (mloopuv_base != NULL);
if (is_face_sel && tpage) {
- const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
+ ProjPaintFaceCoSS coSS;
+ proj_paint_face_coSS_init(ps, lt, &coSS);
- v1coSS = ps->screenCoords[mf->v1];
- v2coSS = ps->screenCoords[mf->v2];
- v3coSS = ps->screenCoords[mf->v3];
- if (mf->v4) {
- v4coSS = ps->screenCoords[mf->v4];
- }
-
-
- if (!ps->is_ortho) {
- if (v1coSS[0] == FLT_MAX ||
- v2coSS[0] == FLT_MAX ||
- v3coSS[0] == FLT_MAX ||
- (mf->v4 && v4coSS[0] == FLT_MAX))
- {
+ if (is_multi_view == false) {
+ if (project_paint_flt_max_cull(ps, &coSS)) {
continue;
}
- }
#ifdef PROJ_DEBUG_WINCLIP
- /* ignore faces outside the view */
- if (
- (v1coSS[0] < ps->screenMin[0] &&
- v2coSS[0] < ps->screenMin[0] &&
- v3coSS[0] < ps->screenMin[0] &&
- (mf->v4 && v4coSS[0] < ps->screenMin[0])) ||
-
- (v1coSS[0] > ps->screenMax[0] &&
- v2coSS[0] > ps->screenMax[0] &&
- v3coSS[0] > ps->screenMax[0] &&
- (mf->v4 && v4coSS[0] > ps->screenMax[0])) ||
-
- (v1coSS[1] < ps->screenMin[1] &&
- v2coSS[1] < ps->screenMin[1] &&
- v3coSS[1] < ps->screenMin[1] &&
- (mf->v4 && v4coSS[1] < ps->screenMin[1])) ||
-
- (v1coSS[1] > ps->screenMax[1] &&
- v2coSS[1] > ps->screenMax[1] &&
- v3coSS[1] > ps->screenMax[1] &&
- (mf->v4 && v4coSS[1] > ps->screenMax[1]))
- )
- {
- continue;
- }
+ if (project_paint_winclip(ps, &coSS)) {
+ continue;
+ }
#endif //PROJ_DEBUG_WINCLIP
+ /* backface culls individual triangles but mask normal will use polygon */
+ if (ps->do_backfacecull) {
+ if (ps->do_mask_normal) {
+ if (prev_poly != lt->poly) {
+ int iloop;
+ bool culled = true;
+ const MPoly *poly = ps->dm_mpoly + lt->poly;
+ int poly_loops = poly->totloop;
+ prev_poly = lt->poly;
+ for (iloop = 0; iloop < poly_loops; iloop++) {
+ if (!(ps->vertFlags[ps->dm_mloop[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
+ culled = false;
+ break;
+ }
+ }
- if (ps->do_backfacecull) {
- if (ps->do_mask_normal) {
- /* Since we are interpolating the normals of faces, we want to make
- * sure all the verts are pointing away from the view,
- * not just the face */
- if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) &&
- (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) &&
- (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) &&
- (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL)
- )
- {
- continue;
+ if (culled) {
+ /* poly loops - 2 is number of triangles for poly,
+ * but counter gets incremented when continuing, so decrease by 3 */
+ int poly_tri = poly_loops - 3;
+ tri_index += poly_tri;
+ lt += poly_tri;
+ continue;
+ }
+ }
}
- }
- else {
- if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) {
- continue;
+ else {
+ if ((line_point_side_v2(coSS.v1, coSS.v2, coSS.v3) < 0.0f) != ps->is_flip_object) {
+ continue;
+ }
}
-
}
}
if (tpage_last != tpage) {
- image_index = BLI_linklist_index(image_LinkList, tpage);
+ image_index = BLI_linklist_index(image_LinkList.list, tpage);
if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */
BLI_linklist_append(&image_LinkList, tpage);
@@ -3456,32 +3772,115 @@ static void project_paint_begin(ProjPaintState *ps)
if (image_index != -1) {
/* Initialize the faces screen pixels */
/* Add this to a list to initialize later */
- project_paint_delayed_face_init(ps, mf, face_index);
+ project_paint_delayed_face_init(ps, lt, tri_index);
}
}
}
/* build an array of images we use*/
- projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
-
- for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
- int size;
- projIma->ima = node->link;
- projIma->touch = 0;
- projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
- projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
- projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
- memset(projIma->undoRect, 0, size);
- projIma->maskRect = (unsigned short **) BLI_memarena_alloc(arena, size);
- memset(projIma->maskRect, 0, size);
- projIma->valid = (bool **) BLI_memarena_alloc(arena, size);
- memset(projIma->valid, 0, size);
+ if (ps->is_shared_user == false) {
+ project_paint_build_proj_ima(ps, arena, image_LinkList.list);
}
/* we have built the array, discard the linked list */
- BLI_linklist_free(image_LinkList, NULL);
+ BLI_linklist_free(image_LinkList.list, NULL);
+}
+
+/* run once per stroke before projection painting */
+static void project_paint_begin(
+ ProjPaintState *ps,
+ const bool is_multi_view, const char symmetry_flag)
+{
+ ProjPaintLayerClone layer_clone;
+ ProjPaintFaceLookup face_lookup;
+ const MLoopUV *mloopuv_base = NULL;
+
+ MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
+
+ const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
+
+ bool reset_threads = false;
+
+ /* ---- end defines ---- */
+
+ if (ps->source == PROJ_SRC_VIEW)
+ ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
+
+ ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
+ ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
+
+ /* paint onto the derived mesh */
+ if (ps->is_shared_user == false) {
+ if (!proj_paint_state_dm_init(ps)) {
+ return;
+ }
+ }
+
+ proj_paint_face_lookup_init(ps, &face_lookup);
+ proj_paint_layer_clone_init(ps, &layer_clone);
+
+ if (ps->do_layer_stencil || ps->do_stencil_brush) {
+ //int layer_num = CustomData_get_stencil_layer(&ps->dm->loopData, CD_MLOOPUV);
+ int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
+ if (layer_num != -1)
+ ps->dm_mloopuv_stencil = CustomData_get_layer_n(&ps->dm->loopData, CD_MLOOPUV, layer_num);
+
+ if (ps->dm_mloopuv_stencil == NULL) {
+ /* get active instead */
+ ps->dm_mloopuv_stencil = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ }
+
+ if (ps->do_stencil_brush)
+ mloopuv_base = ps->dm_mloopuv_stencil;
+ }
+
+ /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+ if (ps->is_shared_user == false) {
+ proj_paint_state_non_cddm_init(ps);
+
+ proj_paint_state_cavity_init(ps);
+ }
+
+ proj_paint_state_viewport_init(ps, symmetry_flag);
+
+ /* calculate vert screen coords
+ * run this early so we can calculate the x/y resolution of our bucket rect */
+ proj_paint_state_screen_coords_init(ps, diameter);
+
+ /* only for convenience */
+ ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
+ ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
+
+ ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+ ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+
+ /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
+
+ if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
+ reset_threads = true;
+ }
+
+ /* really high values could cause problems since it has to allocate a few
+ * (ps->buckets_x*ps->buckets_y) sized arrays */
+ CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+ CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+
+ ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
+ ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+
+ ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ if (ps->is_shared_user == false) {
+ proj_paint_state_seam_bleed_init(ps);
+ }
+#endif
+
+ proj_paint_state_thread_init(ps, reset_threads);
+ arena = ps->arena_mt[0];
+
+ proj_paint_state_vert_flags_init(ps);
+
+ project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, mloopuv_base, is_multi_view);
}
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
@@ -3490,7 +3889,7 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
if (ps->tool == PAINT_TOOL_CLONE) {
float projCo[4];
copy_v3_v3(projCo, ED_view3d_cursor3d_get(ps->scene, ps->v3d));
- mul_m4_v3(ps->ob->imat, projCo);
+ mul_m4_v3(ps->obmat_imat, projCo);
projCo[3] = 1.0f;
mul_m4_v4(ps->projectMat, projCo);
@@ -3502,14 +3901,16 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
static void project_paint_end(ProjPaintState *ps)
{
int a;
- ProjPaintImage *projIma;
image_undo_remove_masks();
/* dereference used image buffers */
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
- DAG_id_tag_update(&projIma->ima->id, 0);
+ if (ps->is_shared_user == false) {
+ ProjPaintImage *projIma;
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
+ DAG_id_tag_update(&projIma->ima->id, 0);
+ }
}
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
@@ -3518,23 +3919,52 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN(ps->bucketRect);
MEM_freeN(ps->bucketFaces);
MEM_freeN(ps->bucketFlags);
- MEM_freeN(ps->dm_mtface);
- if (ps->do_layer_clone)
- MEM_freeN(ps->dm_mtface_clone);
- if (ps->thread_tot > 1) {
- BLI_spin_end(ps->tile_lock);
- MEM_freeN((void *)ps->tile_lock);
- }
- image_undo_end_locks();
+
+ if (ps->is_shared_user == false) {
+
+ /* must be set for non-shared */
+ BLI_assert(ps->dm_mloopuv || ps->is_shared_user);
+ if (ps->dm_mloopuv)
+ MEM_freeN(ps->dm_mloopuv);
+
+ if (ps->do_layer_clone)
+ MEM_freeN(ps->dm_mloopuv_clone);
+ if (ps->thread_tot > 1) {
+ BLI_spin_end(ps->tile_lock);
+ MEM_freeN((void *)ps->tile_lock);
+ }
+
+ image_undo_end_locks();
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- MEM_freeN(ps->vertFaces);
- MEM_freeN(ps->faceSeamFlags);
- MEM_freeN(ps->faceWindingFlags);
- MEM_freeN(ps->faceSeamUVs);
- }
+ if (ps->seam_bleed_px > 0.0f) {
+ MEM_freeN(ps->vertFaces);
+ MEM_freeN(ps->faceSeamFlags);
+ MEM_freeN(ps->faceWindingFlags);
+ MEM_freeN(ps->faceSeamUVs);
+ }
+#endif
+
+ if (ps->do_mask_cavity) {
+ MEM_freeN(ps->cavities);
+ }
+
+ /* copy for subsurf/multires, so throw away */
+ if (ps->dm->type != DM_TYPE_CDDM) {
+ if (ps->dm_mvert) MEM_freeN((void *)ps->dm_mvert);
+ if (ps->dm_mpoly) MEM_freeN((void *)ps->dm_mpoly);
+ if (ps->dm_mloop) MEM_freeN((void *)ps->dm_mloop);
+ /* looks like these don't need copying */
+#if 0
+ if (ps->dm_mloopuv) MEM_freeN(ps->dm_mloopuv);
+ if (ps->dm_mloopuv_clone) MEM_freeN(ps->dm_mloopuv_clone);
+ if (ps->dm_mloopuv_stencil) MEM_freeN(ps->dm_mloopuv_stencil);
#endif
+ }
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+ }
if (ps->blurkernel) {
paint_delete_blur_kernel(ps->blurkernel);
@@ -3546,36 +3976,25 @@ static void project_paint_end(ProjPaintState *ps)
for (a = 0; a < ps->thread_tot; a++) {
BLI_memarena_free(ps->arena_mt[a]);
}
+}
- /* copy for subsurf/multires, so throw away */
- if (ps->dm->type != DM_TYPE_CDDM) {
- if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
- if (ps->dm_mface) MEM_freeN(ps->dm_mface);
- /* looks like these don't need copying */
-#if 0
- if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
- if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
- if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
-#endif
- }
+/* 1 = an undo, -1 is a redo. */
+static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
+{
+ pr->x1 = 10000000;
+ pr->y1 = 10000000;
- if (ps->dm_release)
- ps->dm->release(ps->dm);
+ pr->x2 = -1;
+ pr->y2 = -1;
+
+ pr->enabled = 1;
}
-/* 1 = an undo, -1 is a redo. */
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
{
int tot = PROJ_BOUNDBOX_SQUARED;
while (tot--) {
- pr->x1 = 10000000;
- pr->y1 = 10000000;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
-
+ partial_redraw_single_init(pr);
pr++;
}
}
@@ -3619,6 +4038,8 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
redraw = 1;
}
+
+ partial_redraw_single_init(pr);
}
projIma->touch = 0; /* clear for reuse */
@@ -3669,7 +4090,9 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
}
-static bool project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
+static bool project_bucket_iter_next(
+ ProjPaintState *ps, int *bucket_index,
+ rctf *bucket_bounds, const float mval[2])
{
const int diameter = 2 * ps->brush_size;
@@ -3759,10 +4182,9 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
}
}
-/* do_projectpaint_smear*
- *
- * note, mask is used to modify the alpha here, this is not correct since it allows
- * accumulation of color greater then 'projPixel->mask' however in the case of smear its not
+/**
+ * \note mask is used to modify the alpha here, this is not correct since it allows
+ * accumulation of color greater than 'projPixel->mask' however in the case of smear its not
* really that important to be correct as it is with clone and painting
*/
static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float mask,
@@ -3825,7 +4247,7 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
float alpha = projPixel->pixel.f_pt[3];
projPixel->pixel.f_pt[3] = rgba[3] = mask;
@@ -3886,7 +4308,7 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
sub_v3_v3v3(rgba, rgba_pixel, rgba);
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
float alpha = rgba_pixel[3];
rgba[3] = rgba_pixel[3] = mask;
@@ -3908,20 +4330,28 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
}
}
-static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask)
+static void do_projectpaint_draw(
+ ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask,
+ float dither, float u, float v)
{
float rgb[3];
unsigned char rgba_ub[4];
- copy_v3_v3(rgb, ps->paint_color);
-
if (ps->is_texbrush) {
- mul_v3_v3(rgb, texrgb);
+ mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
/* TODO(sergey): Support texture paint color space. */
linearrgb_to_srgb_v3_v3(rgb, rgb);
}
+ else {
+ copy_v3_v3(rgb, ps->paint_color);
+ }
- rgb_float_to_uchar(rgba_ub, rgb);
+ if (dither > 0.0f) {
+ float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v);
+ }
+ else {
+ F3TOCHAR3(rgb, rgba_ub);
+ }
rgba_ub[3] = f_to_char(mask);
if (ps->do_masking) {
@@ -3980,6 +4410,16 @@ static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, flo
}
}
+static void image_paint_partial_redraw_expand(
+ ImagePaintPartialRedraw *cell,
+ const ProjPixel *projPixel)
+{
+ cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
+ cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
+
+ cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
+ cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
+}
/* run this for single and multithreaded painting */
static void *do_projectpaint_thread(void *ph_v)
@@ -4017,7 +4457,8 @@ static void *do_projectpaint_thread(void *ph_v)
const float brush_radius = ps->brush_size;
const float brush_radius_sq = brush_radius * brush_radius; /* avoid a square root with every dist comparison */
- short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA;
+ const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
+ 0 : (brush->flag & BRUSH_LOCK_ALPHA) != 0;
LinkNode *smearPixels = NULL;
LinkNode *smearPixels_f = NULL;
@@ -4043,8 +4484,13 @@ static void *do_projectpaint_thread(void *ph_v)
/* Check this bucket and its faces are initialized */
if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+ rctf clip_rect = bucket_bounds;
+ clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
/* No pixels initialized */
- project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
+ project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
}
if (ps->source != PROJ_SRC_VIEW) {
@@ -4086,6 +4532,7 @@ static void *do_projectpaint_thread(void *ph_v)
break;
}
case BRUSH_GRADIENT_RADIAL:
+ default:
{
f = len_v2(p) / line_len;
break;
@@ -4101,7 +4548,15 @@ static void *do_projectpaint_thread(void *ph_v)
color_f, ps->blend);
}
else {
- rgba_float_to_uchar(projPixel->newColor.ch, color_f);
+ linearrgb_to_srgb_v3_v3(color_f, color_f);
+
+ if (ps->dither > 0.0f) {
+ float_to_byte_dither_v3(projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px);
+ }
+ else {
+ F3TOCHAR3(color_f, projPixel->newColor.ch);
+ }
+ projPixel->newColor.ch[3] = FTOCHAR(color_f[3]);
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
projPixel->newColor.ch, ps->blend);
}
@@ -4126,16 +4581,21 @@ static void *do_projectpaint_thread(void *ph_v)
}
if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
}
last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
- last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px);
- last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px);
-
- last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1);
- last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1);
+ image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
}
else {
if (is_floatbuf) {
@@ -4182,7 +4642,7 @@ static void *do_projectpaint_thread(void *ph_v)
if (dist_sq <= brush_radius_sq) {
dist = sqrtf(dist_sq);
- falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, brush_radius);
+ falloff = BKE_brush_curve_strength_clamped(ps->brush, dist, brush_radius);
if (falloff > 0.0f) {
float texrgb[3];
@@ -4269,11 +4729,7 @@ static void *do_projectpaint_thread(void *ph_v)
*projPixel->valid = true;
last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
- last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px);
- last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px);
-
- last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1);
- last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1);
+ image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
/* texrgb is not used for clone, smear or soften */
switch (tool) {
@@ -4297,14 +4753,23 @@ static void *do_projectpaint_thread(void *ph_v)
break;
default:
if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
- else do_projectpaint_draw(ps, projPixel, texrgb, mask);
+ else do_projectpaint_draw(ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
break;
}
- }
- if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ if (lock_alpha) {
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
+ }
}
/* done painting */
@@ -4381,13 +4846,13 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
/* thread specific */
handles[a].thread_index = a;
- handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
+ handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
/* image bounds */
for (i = 0; i < ps->image_tot; i++) {
- handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
}
@@ -4417,38 +4882,53 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
touch_any = 1;
}
}
-
+
+ /* calculate pivot for rotation around seletion if needed */
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ float w[3];
+ int tri_index;
+
+ tri_index = project_paint_PickFace(ps, pos, w);
+
+ if (tri_index != -1) {
+ const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
+ float world[3];
+ UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;
+
+ interp_v3_v3v3v3(
+ world,
+ ps->dm_mvert[lt_vtri[0]].co,
+ ps->dm_mvert[lt_vtri[1]].co,
+ ps->dm_mvert[lt_vtri[2]].co,
+ w);
+
+ ups->average_stroke_counter++;
+ mul_m4_v3(ps->obmat, world);
+ add_v3_v3(ups->average_stroke_accum, world);
+ ups->last_stroke_valid = true;
+ }
+ }
+
return touch_any;
}
-void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size)
+static void paint_proj_stroke_ps(
+ const bContext *UNUSED(C), void *ps_handle_p, const float prev_pos[2], const float pos[2],
+ const bool eraser, float pressure, float distance, float size,
+ /* extra view */
+ ProjPaintState *ps
+ )
{
- ProjPaintState *ps = pps;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
Brush *brush = ps->brush;
Scene *scene = ps->scene;
- int a;
ps->brush_size = size;
ps->blend = brush->blend;
if (eraser)
ps->blend = IMB_BLEND_ERASE_ALPHA;
-
- /* clone gets special treatment here to avoid going through image initialization */
- if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
- View3D *v3d = ps->v3d;
- float *cursor = ED_view3d_cursor3d_get(scene, v3d);
- int mval_i[2] = {(int)pos[0], (int)pos[1]};
-
- view3d_operator_needs_opengl(C);
-
- if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false, NULL))
- return;
-
- ED_region_tag_redraw(ps->ar);
-
- return;
- }
/* handle gradient and inverted stroke color here */
if (ps->tool == PAINT_TOOL_DRAW) {
@@ -4469,14 +4949,42 @@ void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], co
}
}
- /* continue adding to existing partial redraw rects until redraw */
- if (!ps->need_redraw) {
- for (a = 0; a < ps->image_tot; a++)
- partial_redraw_array_init(ps->projImages[a].partRedrawRect);
+ if (project_paint_op(ps, prev_pos, pos)) {
+ ps_handle->need_redraw = true;
+ project_image_refresh_tagged(ps);
}
+}
+
- if (project_paint_op(ps, prev_pos, pos))
- ps->need_redraw = true;
+void paint_proj_stroke(
+ const bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2],
+ const bool eraser, float pressure, float distance, float size)
+{
+ int i;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+
+ /* clone gets special treatment here to avoid going through image initialization */
+ if (ps_handle->is_clone_cursor_pick) {
+ Scene *scene = ps_handle->scene;
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ int mval_i[2] = {(int)pos[0], (int)pos[1]};
+
+ view3d_operator_needs_opengl(C);
+
+ if (!ED_view3d_autodist(scene, ar, v3d, mval_i, cursor, false, NULL))
+ return;
+
+ ED_region_tag_redraw(ar);
+
+ return;
+ }
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
+ }
}
@@ -4495,7 +5003,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->blend = brush->blend;
/* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */
if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
- ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ?
+ ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL);
ps->blurkernel = paint_new_blur_kernel(brush, true);
@@ -4532,11 +5040,14 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->clone_ima = (!ps->do_material_slots) ?
settings->imapaint.clone : NULL;
+ ps->do_mask_cavity = (settings->imapaint.paint.flags & PAINT_USE_CAVITY_MASK) ? true : false;
+ ps->cavity_curve = settings->imapaint.paint.cavity_curve;
+
/* setup projection painting data */
if (ps->tool != PAINT_TOOL_FILL) {
- ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
- ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
- ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;
+ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? false : true;
+ ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? false : true;
+ ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? false : true;
}
else {
ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
@@ -4573,60 +5084,126 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
if (ps->normal_angle_range <= 0.0f)
ps->do_mask_normal = false; /* no need to do blending */
+ ps->normal_angle__cos = cosf(ps->normal_angle);
+ ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
+
+ ps->dither = settings->imapaint.dither;
+
return;
}
void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
{
- ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ProjStrokeHandle *ps_handle;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ int i;
+ bool is_multi_view;
+ char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
- project_state_init(C, ob, ps, mode);
+ ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
+ ps_handle->scene = scene;
+ ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
- if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) {
+ /* bypass regular stroke logic */
+ if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) &&
+ (mode == BRUSH_STROKE_INVERT))
+ {
view3d_operator_needs_opengl(C);
- return ps;
+ ps_handle->is_clone_cursor_pick = true;
+ return ps_handle;
}
- paint_brush_init_tex(ps->brush);
+ ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
- ps->source = PROJ_SRC_VIEW;
+ ps_handle->symmetry_flags = settings->imapaint.paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
+ is_multi_view = (ps_handle->ps_views_tot != 1);
- if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
- MEM_freeN(ps);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ps_handle->ps_views[i] = ps;
}
- ps->orig_brush_size = BKE_brush_size_get(ps->scene, ps->brush);
+ if (ps_handle->symmetry_flags) {
+ int index = 0;
+
+ int x = 0;
+ do {
+ int y = 0;
+ do {
+ int z = 0;
+ do {
+ symmetry_flag_views[index++] = (
+ (x ? PAINT_SYMM_X : 0) |
+ (y ? PAINT_SYMM_Y : 0) |
+ (z ? PAINT_SYMM_Z : 0));
+ BLI_assert(index <= ps_handle->ps_views_tot);
+ } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
+ } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
+ } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
+ BLI_assert(index == ps_handle->ps_views_tot);
+ }
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ project_state_init(C, ob, ps, mode);
+
+ if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
+ ps_handle->ps_views_tot = i + 1;
+ goto fail;
+ }
+ }
/* Don't allow brush size below 2 */
- if (BKE_brush_size_get(ps->scene, ps->brush) < 2)
- BKE_brush_size_set(ps->scene, ps->brush, 2);
+ if (BKE_brush_size_get(scene, ps_handle->brush) < 2)
+ BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
/* allocate and initialize spatial data structures */
- project_paint_begin(ps);
- if (ps->dm == NULL) {
- MEM_freeN(ps);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
+ project_image_refresh_tagged(ps);
+
+ /* re-use! */
+ if (i != 0) {
+ ps->is_shared_user = true;
+ PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
+ }
+
+ project_paint_begin(ps, is_multi_view, symmetry_flag_views[i]);
+
+ paint_proj_begin_clone(ps, mouse);
+
+ if (ps->dm == NULL) {
+ goto fail;
+ return NULL;
+ }
}
- paint_proj_begin_clone(ps, mouse);
+ paint_brush_init_tex(ps_handle->brush);
- /* special full screen draw mode for fill tool */
- if (ps->tool == PAINT_TOOL_FILL)
- ps->source = PROJ_SRC_VIEW_FILL;
+ return ps_handle;
- return ps;
+
+fail:
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ MEM_freeN(ps);
+ }
+ MEM_freeN(ps_handle);
+ return NULL;
}
-void paint_proj_redraw(const bContext *C, void *pps, bool final)
+void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
{
- ProjPaintState *ps = pps;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
- if (ps->need_redraw) {
- project_image_refresh_tagged(ps);
-
- ps->need_redraw = false;
+ if (ps_handle->need_redraw) {
+ ps_handle->need_redraw = false;
}
else if (!final) {
return;
@@ -4641,19 +5218,34 @@ void paint_proj_redraw(const bContext *C, void *pps, bool final)
}
}
-void paint_proj_stroke_done(void *pps)
+void paint_proj_stroke_done(void *ps_handle_p)
{
- ProjPaintState *ps = pps;
- if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
- MEM_freeN(ps);
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+ Scene *scene = ps_handle->scene;
+ int i;
+
+ if (ps_handle->is_clone_cursor_pick) {
+ MEM_freeN(ps_handle);
return;
}
- BKE_brush_size_set(ps->scene, ps->brush, ps->orig_brush_size);
- paint_brush_exit_tex(ps->brush);
+ for (i = 1; i < ps_handle->ps_views_tot; i++) {
+ PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
+ }
+
+ BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
+
+ paint_brush_exit_tex(ps_handle->brush);
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps;
+ ps = ps_handle->ps_views[i];
+ project_paint_end(ps);
+ MEM_freeN(ps);
+
+ }
- project_paint_end(ps);
- MEM_freeN(ps);
+ MEM_freeN(ps_handle);
}
/* use project paint to re-apply an image */
static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
@@ -4665,13 +5257,18 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
IDProperty *idgroup;
IDProperty *view_data = NULL;
Object *ob = OBACT;
+ bool uvs, mat, tex;
if (ob == NULL || ob->type != OB_MESH) {
BKE_report(op->reports, RPT_ERROR, "No active mesh object");
return OPERATOR_CANCELLED;
}
- paint_proj_mesh_data_ensure(C, ob, op);
+ if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
+ BKE_paint_data_warning(op->reports, uvs, mat, tex, true);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ return OPERATOR_CANCELLED;
+ }
project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL);
@@ -4718,7 +5315,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ps.is_maskbrush = false;
ps.do_masking = false;
orig_brush_size = BKE_brush_size_get(scene, ps.brush);
- BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */
+ BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize); /* cover the whole image */
ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */
@@ -4728,7 +5325,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ED_image_undo_restore, ED_image_undo_free, NULL);
/* allocate and initialize spatial data structures */
- project_paint_begin(&ps);
+ project_paint_begin(&ps, false, 0);
if (ps.dm == NULL) {
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
@@ -4802,7 +5399,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (w > maxsize) w = maxsize;
if (h > maxsize) h = maxsize;
- ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
if (!ibuf) {
/* Mostly happens when OpenGL offscreen buffer was failed to create, */
/* but could be other reasons. Should be handled in the future. nazgul */
@@ -4810,10 +5407,13 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- image = BKE_image_add_from_imbuf(ibuf);
+ image = BKE_image_add_from_imbuf(ibuf, "image_view");
+
+ /* Drop reference to ibuf so that the image owns it */
+ IMB_freeImBuf(ibuf);
if (image) {
- /* now for the trickyness. store the view projection here!
+ /* now for the trickiness. store the view projection here!
* re-projection will reuse this */
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -4832,11 +5432,11 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float);
memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float);
is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true);
- array[2] = is_ortho ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */
+ /* using float for a bool is dodgy but since its an extra member in the array...
+ * easier then adding a single bool prop */
+ array[2] = is_ortho ? 1.0f : 0.0f;
IDP_AddToGroup(idgroup, view_data);
-
- rename_id(&image->id, "image_view");
}
return OPERATOR_FINISHED;
@@ -4863,110 +5463,78 @@ void PAINT_OT_image_from_view(wmOperatorType *ot)
* Data generation for projective texturing *
* *******************************************/
+void BKE_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil)
+{
+ BKE_reportf(reports, RPT_WARNING, "Missing%s%s%s%s detected!",
+ !uvs ? " UVs," : "",
+ !mat ? " Materials," : "",
+ !tex ? " Textures," : "",
+ !stencil ? " Stencil," : ""
+ );
+}
/* Make sure that active object has a material, and assign UVs and image layers if they do not exist */
-void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op)
+bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
{
Mesh *me;
int layernum;
- ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint);
- bScreen *sc;
- Scene *scene = CTX_data_scene(C);
- Main *bmain = CTX_data_main(C);
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
Brush *br = BKE_paint_brush(&imapaint->paint);
+ bool hasmat = true;
+ bool hastex = true;
+ bool hasstencil = true;
+ bool hasuvs = true;
+ imapaint->missing_data = 0;
+
BLI_assert(ob->type == OB_MESH);
- /* no material, add one */
- if (ob->totcol == 0) {
- Material *ma = BKE_material_add(CTX_data_main(C), "Material");
- /* no material found, just assign to first slot */
- assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF);
- proj_paint_add_slot(C, ma, NULL);
- }
- else {
- /* there may be material slots but they may be empty, check */
- int i;
-
- for (i = 1; i < ob->totcol + 1; i++) {
- Material *ma = give_current_material(ob, i);
-
- if (ma) {
- if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ /* no material, add one */
+ if (ob->totcol == 0) {
+ hasmat = false;
+ hastex = false;
+ }
+ else {
+ /* there may be material slots but they may be empty, check */
+ int i;
+ hasmat = false;
+ hastex = false;
+
+ for (i = 1; i < ob->totcol + 1; i++) {
+ Material *ma = give_current_material(ob, i);
+
+ if (ma) {
+ hasmat = true;
if (!ma->texpaintslot) {
/* refresh here just in case */
- BKE_texpaint_slot_refresh_cache(scene, ma);
+ BKE_texpaint_slot_refresh_cache(scene, ma);
/* if still no slots, we have to add */
- if (!ma->texpaintslot) {
- proj_paint_add_slot(C, ma, NULL);
-
- if (ma->texpaintslot) {
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin)
- ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[0].ima);
- }
- }
- }
- }
- }
+ if (ma->texpaintslot) {
+ hastex = true;
+ break;
}
}
+ else {
+ hastex = true;
+ break;
+ }
}
}
- else {
- Material *ma = BKE_material_add(CTX_data_main(C), "Material");
- /* no material found, just assign to first slot */
- assign_material(ob, ma, i, BKE_MAT_ASSIGN_USERPREF);
- proj_paint_add_slot(C, ma, NULL);
- }
}
}
-
- if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
if (imapaint->canvas == NULL) {
- int width;
- int height;
- Main *bmain = CTX_data_main(C);
- float color[4] = {0.0, 0.0, 0.0, 1.0};
-
- width = 1024;
- height = 1024;
- imapaint->canvas = BKE_image_add_generated(bmain, width, height, "Canvas", 32, false, IMA_GENTYPE_BLANK, color);
-
- GPU_drawobject_free(ob->derivedFinal);
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin)
- ED_space_image_set(sima, scene, scene->obedit, imapaint->canvas);
- }
- }
- }
- }
- }
+ hastex = false;
+ }
}
-
+
me = BKE_mesh_from_object(ob);
layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
if (layernum == 0) {
- BKE_reportf(op->reports, RPT_WARNING, "Object did not have UV map, manual unwrap recommended");
-
- ED_mesh_uv_texture_add(me, "UVMap", true);
+ hasuvs = false;
}
/* Make sure we have a stencil to paint on! */
@@ -4974,16 +5542,29 @@ void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op)
imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL;
if (imapaint->stencil == NULL) {
- int width;
- int height;
- Main *bmain = CTX_data_main(C);
- float color[4] = {0.0, 0.0, 0.0, 1.0};
-
- width = 1024;
- height = 1024;
- imapaint->stencil = BKE_image_add_generated(bmain, width, height, "Stencil", 32, false, IMA_GENTYPE_BLANK, color);
+ hasstencil = false;
}
}
+
+ if (!hasuvs) imapaint->missing_data |= IMAGEPAINT_MISSING_UVS;
+ if (!hasmat) imapaint->missing_data |= IMAGEPAINT_MISSING_MATERIAL;
+ if (!hastex) imapaint->missing_data |= IMAGEPAINT_MISSING_TEX;
+ if (!hasstencil) imapaint->missing_data |= IMAGEPAINT_MISSING_STENCIL;
+
+ if (uvs) {
+ *uvs = hasuvs;
+ }
+ if (mat) {
+ *mat = hasmat;
+ }
+ if (tex) {
+ *tex = hastex;
+ }
+ if (stencil) {
+ *stencil = hasstencil;
+ }
+
+ return hasuvs && hasmat && hastex && hasstencil;
}
/* Add layer operator */
@@ -4997,7 +5578,7 @@ static EnumPropertyItem layer_type_items[] = {
{MAP_SPEC, "SPECULAR_INTENSITY", 0, "Specular Intensity", ""},
{MAP_HAR, "SPECULAR_HARDNESS", 0, "Specular Hardness", ""},
{MAP_AMB, "AMBIENT", 0, "Ambient", ""},
- {MAP_EMIT, "EMMIT", 0, "Emmit", ""},
+ {MAP_EMIT, "EMIT", 0, "Emit", ""},
{MAP_COLMIR, "MIRROR_COLOR", 0, "Mirror Color", ""},
{MAP_RAYMIRR, "RAYMIRROR", 0, "Ray Mirror", ""},
{MAP_NORM, "NORMAL", 0, "Normal", ""},
@@ -5006,30 +5587,74 @@ static EnumPropertyItem layer_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-bool proj_paint_add_slot(bContext *C, Material *ma, wmOperator *op)
+static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
+{
+ Image *ima;
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
+ int width = 1024;
+ int height = 1024;
+ bool use_float = false;
+ short gen_type = IMA_GENTYPE_BLANK;
+ bool alpha = false;
+
+ if (op) {
+ width = RNA_int_get(op->ptr, "width");
+ height = RNA_int_get(op->ptr, "height");
+ use_float = RNA_boolean_get(op->ptr, "float");
+ gen_type = RNA_enum_get(op->ptr, "generated_type");
+ RNA_float_get_array(op->ptr, "color", color);
+ alpha = RNA_boolean_get(op->ptr, "alpha");
+ RNA_string_get(op->ptr, "name", imagename);
+ }
+ ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
+ gen_type, color, false);
+
+ return ima;
+}
+
+static bool proj_paint_add_slot(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- bool is_bi = BKE_scene_uses_blender_internal(scene);
+ Material *ma;
+ bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
+ Image *ima = NULL;
if (!ob)
return false;
- if (!ma)
- ma = give_current_material(ob, ob->actcol);
+ ma = give_current_material(ob, ob->actcol);
if (ma) {
+ Main *bmain = CTX_data_main(C);
+
+ if (!is_bi && BKE_scene_use_new_shading_nodes(scene)) {
+ bNode *imanode;
+ bNodeTree *ntree = ma->nodetree;
- if (!is_bi || ma->use_nodes) {
- /* not supported for now */
+ if (!ntree) {
+ ED_node_shader_default(C, &ma->id);
+ ntree = ma->nodetree;
+ }
+
+ ma->use_nodes = true;
+
+ /* try to add an image node */
+ imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+
+ ima = proj_paint_image_create(op, bmain);
+ imanode->id = &ima->id;
+
+ nodeSetActive(ntree, imanode);
+
+ ntreeUpdateTree(CTX_data_main(C), ntree);
}
else {
- MTex *mtex = add_mtex_id(&ma->id, -1);
+ MTex *mtex = BKE_texture_mtex_add_id(&ma->id, -1);
/* successful creation of mtex layer, now create set */
if (mtex) {
- Main *bmain = CTX_data_main(C);
- Image *ima;
int type = MAP_COL;
int type_id = 0;
@@ -5045,51 +5670,41 @@ bool proj_paint_add_slot(bContext *C, Material *ma, wmOperator *op)
}
}
- mtex->tex = add_texture(bmain, DATA_(layer_type_items[type_id].name));
+ mtex->tex = BKE_texture_add(bmain, DATA_(layer_type_items[type_id].name));
mtex->mapto = type;
if (mtex->tex) {
- float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
- int width = 1024;
- int height = 1024;
- bool use_float = false;
- short gen_type = IMA_GENTYPE_BLANK;
- bool alpha = false;
-
- if (op) {
- width = RNA_int_get(op->ptr, "width");
- height = RNA_int_get(op->ptr, "height");
- use_float = RNA_boolean_get(op->ptr, "float");
- gen_type = RNA_enum_get(op->ptr, "generated_type");
- RNA_float_get_array(op->ptr, "color", color);
- alpha = RNA_boolean_get(op->ptr, "alpha");
- RNA_string_get(op->ptr, "name", imagename);
- }
-
- ima = mtex->tex->ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
- gen_type, color);
-
- BKE_texpaint_slot_refresh_cache(scene, ma);
- BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
- WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex);
- WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
- DAG_id_tag_update(&ma->id, 0);
- ED_area_tag_redraw(CTX_wm_area(C));
+ ima = mtex->tex->ima = proj_paint_image_create(op, bmain);
}
- WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
- return true;
+ WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex);
}
}
+
+ if (ima) {
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
+ WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
+ DAG_id_tag_update(&ma->id, 0);
+ ED_area_tag_redraw(CTX_wm_area(C));
+
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
+ return true;
+ }
}
-
+
return false;
}
static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
{
- return proj_paint_add_slot(C, NULL, op);
+ if (proj_paint_add_slot(C, op)) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
@@ -5100,6 +5715,12 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *
Material *ma = give_current_material(ob, ob->actcol);
int type = RNA_enum_get(op->ptr, "type");
+ if (!ma) {
+ ma = BKE_material_add(CTX_data_main(C), "Material");
+ /* no material found, just assign to first slot */
+ assign_material(ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+
type = RNA_enum_from_value(layer_type_items, type);
/* get the name of the texture layer type */
@@ -5131,7 +5752,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
ot->poll = ED_operator_region_view3d_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
@@ -5155,7 +5776,7 @@ static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
Material *ma;
- bool is_bi = BKE_scene_uses_blender_internal(scene);
+ bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
TexPaintSlot *slot;
/* not supported for node-based engines */
@@ -5169,16 +5790,21 @@ static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator
slot = ma->texpaintslot + ma->paint_active_slot;
- if (ma->mtex[slot->index]->tex)
+ if (ma->mtex[slot->index]->tex) {
id_us_min(&ma->mtex[slot->index]->tex->id);
+
+ if (ma->mtex[slot->index]->tex->ima) {
+ id_us_min(&ma->mtex[slot->index]->tex->ima->id);
+ }
+ }
MEM_freeN(ma->mtex[slot->index]);
ma->mtex[slot->index] = NULL;
BKE_texpaint_slot_refresh_cache(scene, ma);
DAG_id_tag_update(&ma->id, 0);
- WM_event_add_notifier(C, NC_MATERIAL, CTX_data_scene(C));
+ WM_event_add_notifier(C, NC_MATERIAL, ma);
/* we need a notifier for data change since we change the displayed modifier uvs */
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
}
@@ -5187,7 +5813,7 @@ void PAINT_OT_delete_texture_paint_slot(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Delete Texture Paint Slot";
- ot->description = "Add a texture paint slot";
+ ot->description = "Delete selected texture paint slot";
ot->idname = "PAINT_OT_delete_texture_paint_slot";
/* api callbacks */
@@ -5197,3 +5823,66 @@ void PAINT_OT_delete_texture_paint_slot(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* no checks here, poll function does them for us */
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Mesh *me = ob->data;
+ bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+
+ /* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */
+ scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
+
+ ED_mesh_uv_texture_ensure(me, NULL);
+
+ BM_mesh_bm_from_me(bm, me, true, false, 0);
+
+ /* select all uv loops first - pack parameters needs this to make sure charts are registered */
+ ED_uvedit_select_all(bm);
+ ED_uvedit_unwrap_cube_project(ob, bm, 1.0, false);
+ /* set the margin really quickly before the packing operation*/
+ scene->toolsettings->uvcalc_margin = 0.001f;
+ ED_uvedit_pack_islands(scene, ob, bm, false, false, true);
+ BM_mesh_bm_to_me(bm, me, false);
+ BM_mesh_free(bm);
+
+ if (synch_selection)
+ scene->toolsettings->uv_flag |= UV_SYNC_SELECTION;
+
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
+ DAG_id_tag_update(ob->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
+ return OPERATOR_FINISHED;
+}
+
+static int add_simple_uvs_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT)
+ return false;
+
+ return true;
+}
+
+void PAINT_OT_add_simple_uvs(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add simple UVs";
+ ot->description = "Add cube map uvs on mesh";
+ ot->idname = "PAINT_OT_add_simple_uvs";
+
+ /* api callbacks */
+ ot->exec = add_simple_uvs_exec;
+ ot->poll = add_simple_uvs_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 5e1ac0cf8a8..fd7e053fea3 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -34,14 +34,11 @@
struct ARegion;
struct bContext;
-struct bglMats;
struct Brush;
struct ImagePool;
struct ColorSpace;
struct ColorManagedDisplay;
struct ListBase;
-struct Material;
-struct Mesh;
struct MTex;
struct Object;
struct PaintStroke;
@@ -55,7 +52,6 @@ struct ViewContext;
struct wmEvent;
struct wmOperator;
struct wmOperatorType;
-struct ImagePaintState;
struct wmWindowManager;
struct DMCoNo;
enum PaintMode;
@@ -149,7 +145,7 @@ typedef struct ImagePaintPartialRedraw {
int image_texture_paint_poll(struct bContext *C);
void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate);
-void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj);
+void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj, bool find_prev);
void image_undo_remove_masks(void);
void image_undo_init_locks(void);
void image_undo_end_locks(void);
@@ -164,13 +160,11 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size);
void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
-void paint_2d_gradient_fill (const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
+void paint_2d_gradient_fill(const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], const bool eraser, float pressure, float distance, float size);
void paint_proj_redraw(const struct bContext *C, void *pps, bool final);
void paint_proj_stroke_done(void *ps);
-void paint_proj_mesh_data_ensure(bContext *C, struct Object *ob, struct wmOperator *op);
-bool proj_paint_add_slot(bContext *C, struct Material *ma, struct wmOperator *op);
void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display);
bool paint_use_opacity_masking(struct Brush *brush);
@@ -186,6 +180,7 @@ void PAINT_OT_image_from_view(struct wmOperatorType *ot);
void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
+void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
/* uv sculpting */
int uv_sculpt_poll(struct bContext *C);
@@ -246,6 +241,18 @@ typedef enum BrushStrokeMode {
BRUSH_STROKE_SMOOTH
} BrushStrokeMode;
+/* paint_ops.c */
+typedef enum {
+ RC_COLOR = 1,
+ RC_ROTATION = 2,
+ RC_ZOOM = 4,
+ RC_WEIGHT = 8,
+ RC_SECONDARY_ROTATION = 16
+} RCFlags;
+
+void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop,
+ RCFlags flags);
+
/* paint_undo.c */
struct ListBase *undo_paint_push_get_list(int type);
void undo_paint_push_count_alloc(int type, int size);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 8faa4cfaf33..118f3a7571f 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -69,7 +69,7 @@
static EnumPropertyItem mode_items[] = {
{PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"},
- {PAINT_MASK_FLOOD_VALUE_INVERSE, "VALUE_INVERSE", 0, "Value Inverted", "Set mask to the level specified by the inverted 'value' property"},
+ {PAINT_MASK_FLOOD_VALUE_INVERSE, "VALUE_INVERSE", 0, "Value Inverted", "Set mask to the level specified by the inverted 'value' property"},
{PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
{0}};
@@ -277,7 +277,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
typedef struct LassoMaskData {
struct ViewContext *vc;
float projviewobjmat[4][4];
- bool *px;
+ BLI_bitmap *px;
int width;
rcti rect; /* bounding box for scanfilling */
int symmpass;
@@ -290,7 +290,7 @@ typedef struct LassoMaskData {
static bool is_effected_lasso(LassoMaskData *data, float co[3])
{
float scr_co_f[2];
- short scr_co_s[2];
+ int scr_co_s[2];
float co_final[3];
flip_v3_v3(co_final, co, data->symmpass);
@@ -301,25 +301,30 @@ static bool is_effected_lasso(LassoMaskData *data, float co[3])
scr_co_s[1] = scr_co_f[1];
/* clip against screen, because lasso is limited to screen only */
- if (scr_co_s[0] < data->rect.xmin || scr_co_s[1] < data->rect.ymin || scr_co_s[0] >= data->rect.xmax || scr_co_s[1] >= data->rect.ymax)
+ if ((scr_co_s[0] < data->rect.xmin) ||
+ (scr_co_s[1] < data->rect.ymin) ||
+ (scr_co_s[0] >= data->rect.xmax) ||
+ (scr_co_s[1] >= data->rect.ymax))
+ {
return false;
+ }
scr_co_s[0] -= data->rect.xmin;
scr_co_s[1] -= data->rect.ymin;
- return data->px[scr_co_s[1] * data->width + scr_co_s[0]];
+ return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]);
}
static void mask_lasso_px_cb(int x, int y, void *user_data)
{
struct LassoMaskData *data = user_data;
- data->px[(y * data->width) + x] = true;
+ BLI_BITMAP_ENABLE(data->px, (y * data->width) + x);
}
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
{
int mcords_tot;
- int (*mcords)[2] = (int (*)[2])WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
float clip_planes[4][4], clip_planes_final[4][4];
@@ -349,13 +354,13 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
ob = vc.obact;
ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
- BLI_lasso_boundbox(&data.rect, (const int (*)[2])mcords, mcords_tot);
+ BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
data.width = data.rect.xmax - data.rect.xmin;
- data.px = MEM_callocN(sizeof(*data.px) * data.width * (data.rect.ymax - data.rect.ymin), "lasso_mask_pixel_buffer");
+ data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
fill_poly_v2i_n(
data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax,
- (const int (*)[2])mcords, mcords_tot,
+ mcords, mcords_tot,
mask_lasso_px_cb, &data);
ED_view3d_clipping_calc(&bb, clip_planes, &mats, &data.rect);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index dc6be9caa53..05eda4da63b 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -66,11 +66,12 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *br = BKE_paint_brush(paint);
Main *bmain = CTX_data_main(C);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
if (br)
br = BKE_brush_copy(br);
else
- br = BKE_brush_add(bmain, "Brush");
+ br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode));
BKE_paint_brush_set(paint, br);
@@ -106,15 +107,14 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
const int old_size = BKE_brush_size_get(scene, brush);
int size = (int)(scalar * old_size);
- if (old_size == size) {
+ if (abs(old_size - size) < U.pixelsize) {
if (scalar > 1) {
- size++;
+ size += U.pixelsize;
}
else if (scalar < 1) {
- size--;
+ size -= U.pixelsize;
}
}
- CLAMP(size, 1, 2000); // XXX magic number
BKE_brush_size_set(scene, brush, size);
}
@@ -128,6 +128,8 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
BKE_brush_unprojected_radius_set(scene, brush, unprojected_radius);
}
+
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
}
return OPERATOR_FINISHED;
@@ -195,13 +197,16 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
Brush *brush = paint->brush;
PaintMode mode = BKE_paintmode_get_active_from_context(C);
Palette *palette = paint->palette;
- PaletteColor *color = BKE_palette_color_add(palette);
+ PaletteColor *color;
+
+ color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
- if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) {
+ if (ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex)) {
copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
color->value = 0.0;
}
- else if (mode == PAINT_WEIGHT) {
+ else if (mode == ePaintWeight) {
zero_v3(color->rgb);
color->value = brush->weight;
}
@@ -230,7 +235,9 @@ static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
Palette *palette = paint->palette;
PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
- BKE_palette_color_remove(palette, color);
+ if (color) {
+ BKE_palette_color_remove(palette, color);
+ }
return OPERATOR_FINISHED;
}
@@ -425,9 +432,8 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool,
brush = brush_tool_cycle(bmain, brush_orig, tool, tool_offset, ob_mode);
if (!brush && brush_tool(brush_orig, tool_offset) != tool && create_missing) {
- brush = BKE_brush_add(bmain, tool_name);
+ brush = BKE_brush_add(bmain, tool_name, ob_mode);
brush_tool_set(brush, tool_offset, tool);
- brush->ob_mode = ob_mode;
brush->toggle_brush = brush_orig;
}
@@ -1085,6 +1091,7 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_brush_colors_flip);
WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
WM_operatortype_append(PAINT_OT_delete_texture_paint_slot);
+ WM_operatortype_append(PAINT_OT_add_simple_uvs);
/* weight */
WM_operatortype_append(PAINT_OT_weight_paint_toggle);
@@ -1148,14 +1155,6 @@ static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *UNUSED(path
RNA_float_set(kmi->ptr, "scalar", 10.0 / 9.0); // 1.1111....
}
-typedef enum {
- RC_COLOR = 1,
- RC_ROTATION = 2,
- RC_ZOOM = 4,
- RC_WEIGHT = 8,
- RC_SECONDARY_ROTATION = 16
-} RCFlags;
-
static void set_brush_rc_path(PointerRNA *ptr, const char *brush_path,
const char *output_name, const char *input_name)
{
@@ -1166,9 +1165,9 @@ static void set_brush_rc_path(PointerRNA *ptr, const char *brush_path,
MEM_freeN(path);
}
-static void set_brush_rc_props(PointerRNA *ptr, const char *paint,
- const char *prop, const char *secondary_prop,
- RCFlags flags)
+void set_brush_rc_props(PointerRNA *ptr, const char *paint,
+ const char *prop, const char *secondary_prop,
+ RCFlags flags)
{
const char *ups_path = "tool_settings.unified_paint_settings";
char *brush_path;
@@ -1324,9 +1323,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
*
* This should be improved further, perhaps by showing a triangle
* grid rather than brush alpha */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", DKEY, KM_PRESS, KM_SHIFT, 0);
- set_brush_rc_props(kmi->ptr, "sculpt", "detail_size", NULL, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
+ kmi = WM_keymap_add_item(keymap, "SCULPT_OT_set_detail_size", DKEY, KM_PRESS, KM_SHIFT, 0);
/* multires switch */
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", PAGEUPKEY, KM_PRESS, 0, 0);
@@ -1364,8 +1361,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.use_smooth_stroke");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.texture_angle_source_random");
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_angle_control", RKEY, KM_PRESS, 0, 0);
/* Vertex Paint mode */
keymap = WM_keymap_find(keyconf, "Vertex Paint", 0, 0);
@@ -1389,8 +1385,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.use_smooth_stroke");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.texture_angle_source_random");
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_angle_control", RKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
@@ -1466,8 +1461,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.use_smooth_stroke");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.texture_angle_source_random");
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_angle_control", RKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.stroke_method");
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 1ed5ad8160c..b1ddf1172c8 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -68,6 +68,12 @@
#include <float.h>
#include <math.h>
+#define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
typedef struct PaintSample {
float mouse[2];
float pressure;
@@ -116,6 +122,10 @@ typedef struct PaintStroke {
float zoom_2d;
int pen_flip;
+
+ /* line constraint */
+ bool constrain_line;
+ float constrained_pos[2];
StrokeGetLocation get_location;
StrokeTestStart test_start;
@@ -155,13 +165,25 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
glLineWidth(3.0);
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- x, y);
+ if (stroke->constrain_line) {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ stroke->constrained_pos[0], stroke->constrained_pos[1]);
+ }
+ else {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
+ }
glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
glLineWidth(1.0);
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- x, y);
+ if (stroke->constrain_line) {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ stroke->constrained_pos[0], stroke->constrained_pos[1]);
+ }
+ else {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
+ }
glDisable(GL_LINE_STIPPLE);
@@ -172,7 +194,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
static bool paint_tool_require_location(Brush *brush, PaintMode mode)
{
switch (mode) {
- case PAINT_SCULPT:
+ case ePaintSculpt:
if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB))
{
@@ -201,6 +223,8 @@ static bool paint_brush_update(bContext *C,
UnifiedPaintSettings *ups = stroke->ups;
bool location_sampled = false;
bool location_success = false;
+ bool do_random = false;
+ bool do_random_mask = false;
/* XXX: Use pressure value from first brush step for brushes which don't
* support strokes (grab, thumb). They depends on initial state and
* brush coord/pressure/etc.
@@ -248,27 +272,34 @@ static bool paint_brush_update(bContext *C,
}
if (paint_supports_dynamic_tex_coords(brush, mode)) {
- if (((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) ||
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) ||
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) &&
- !(brush->flag & BRUSH_RAKE))
+
+ if (ELEM(brush->mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_RANDOM))
{
- if (brush->flag & BRUSH_RANDOM_ROTATION)
- ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand();
- else
- ups->brush_rotation = 0.0f;
+ do_random = true;
}
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coordinates(ups, false);
+ BKE_brush_randomize_texture_coords(ups, false);
else {
copy_v2_v2(ups->tex_mouse, mouse);
}
/* take care of mask texture, if any */
if (brush->mask_mtex.tex) {
+
+ if (ELEM(brush->mask_mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_RANDOM))
+ {
+ do_random_mask = true;
+ }
+
if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coordinates(ups, true);
+ BKE_brush_randomize_texture_coords(ups, true);
else {
copy_v2_v2(ups->mask_tex_mouse, mouse);
}
@@ -285,7 +316,7 @@ static bool paint_brush_update(bContext *C,
ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
- ups->brush_rotation = atan2f(dx, dy) + M_PI;
+ ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
@@ -322,13 +353,30 @@ static bool paint_brush_update(bContext *C,
ups->pixel_radius /= stroke->zoom_2d;
ups->draw_anchored = true;
}
- else if (brush->flag & BRUSH_RAKE) {
+ else {
/* here we are using the initial mouse coordinate because we do not want the rake
* result to depend on jittering */
- if (!stroke->brush_init)
+ if (!stroke->brush_init) {
copy_v2_v2(ups->last_rake, mouse_init);
- else
- paint_calculate_rake_rotation(ups, mouse_init);
+ }
+ /* curve strokes do their own rake calculation */
+ else if (!(brush->flag & BRUSH_CURVE)) {
+ paint_calculate_rake_rotation(ups, brush, mouse_init);
+ }
+ }
+
+ if (do_random) {
+ if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
+ ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
+ brush->mtex.random_angle * BLI_frand();
+ }
+ }
+
+ if (do_random_mask) {
+ if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
+ ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
+ brush->mask_mtex.random_angle * BLI_frand();
+ }
}
if (!location_sampled) {
@@ -355,7 +403,7 @@ static bool paint_stroke_use_jitter(PaintMode mode, Brush *brush, bool invert)
/* jitter-ed brush gives weird and unpredictable result for this
* kinds of stroke, so manually disable jitter usage (sergey) */
use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
- use_jitter &= (!ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) ||
+ use_jitter &= (!ELEM(mode, ePaintTexture2D, ePaintTextureProjective) ||
!(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
@@ -523,7 +571,7 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
g = 1.0f / m;
max = 0;
for (i = 0; i < m; i++) {
- float overlap = paint_stroke_overlapped_curve(br, i * g, spacing);
+ float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
if (overlap > max)
max = overlap;
@@ -618,7 +666,8 @@ PaintStroke *paint_stroke_new(bContext *C,
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
- Brush *br = stroke->brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = stroke->brush = BKE_paint_brush(p);
float zoomx, zoomy;
view3d_set_viewcontext(C, &stroke->vc);
@@ -637,18 +686,23 @@ PaintStroke *paint_stroke_new(bContext *C,
get_imapaint_zoom(C, &zoomx, &zoomy);
stroke->zoom_2d = max_ff(zoomx, zoomy);
- if ((br->flag & BRUSH_CURVE) &&
- RNA_struct_property_is_set(op->ptr, "mode"))
- {
- RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
+ if (br->flag & (BRUSH_CURVE)) {
+ RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ }
}
/* initialize here */
ups->overlap_factor = 1.0;
ups->stroke_active = true;
-
+
+ zero_v3(ups->average_stroke_accum);
+ ups->average_stroke_counter = 0;
+
/* initialize here to avoid initialization conflict with threaded strokes */
curvemapping_initialize(br->curve);
-
+ if (p->flags & PAINT_USE_CAVITY_MASK)
+ curvemapping_initialize(p->cavity_curve);
+
BKE_paint_set_overlay_override(br->overlay_flags);
return stroke;
@@ -669,9 +723,12 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
ups->stroke_active = false;
/* reset rotation here to avoid doing so in cursor display */
- if (!(stroke->brush->flag & BRUSH_RAKE))
+ if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
ups->brush_rotation = 0.0f;
+ if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ ups->brush_rotation_sec = 0.0f;
+
if (stroke->stroke_started) {
if (stroke->redraw)
stroke->redraw(C, stroke, true);
@@ -717,13 +774,13 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
return false;
switch (mode) {
- case PAINT_SCULPT:
+ case ePaintSculpt:
if (sculpt_is_grab_tool(br))
return false;
break;
- case PAINT_TEXTURE_2D: /* fall through */
- case PAINT_TEXTURE_PROJECTIVE:
+ case ePaintTexture2D: /* fall through */
+ case ePaintTextureProjective:
if ((br->imagepaint_tool == PAINT_TOOL_FILL) &&
(br->flag & BRUSH_USE_GRADIENT))
{
@@ -746,7 +803,7 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
}
switch (mode) {
- case PAINT_SCULPT:
+ case ePaintSculpt:
if (sculpt_is_grab_tool(br))
return false;
break;
@@ -758,8 +815,8 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
bool paint_supports_texture(PaintMode mode)
{
- /* ommit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
- return ELEM(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
+ /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
+ return ELEM(mode, ePaintSculpt, ePaintVertex, ePaintTextureProjective, ePaintTexture2D);
}
/* return true if the brush size can change during paint (normally used for pressure) */
@@ -769,7 +826,7 @@ bool paint_supports_dynamic_tex_coords(Brush *br, PaintMode mode)
return false;
switch (mode) {
- case PAINT_SCULPT:
+ case ePaintSculpt:
if (sculpt_is_grab_tool(br))
return false;
break;
@@ -910,7 +967,9 @@ static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stro
static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke)
{
Brush *br = stroke->brush;
+
if (br->flag & BRUSH_CURVE) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
PaintCurve *pc = br->paint_curve;
@@ -921,24 +980,49 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (!pc)
return true;
+#ifdef DEBUG_TIME
+ TIMEIT_START(stroke);
+#endif
+
pcp = pc->points;
stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
int j;
float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
PaintCurvePoint *pcp_next = pcp + 1;
+ bool do_rake = false;
- for (j = 0; j < 2; j++)
+ for (j = 0; j < 2; j++) {
BKE_curve_forward_diff_bezier(
pcp->bez.vec[1][j],
pcp->bez.vec[2][j],
pcp_next->bez.vec[0][j],
pcp_next->bez.vec[1][j],
data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+ }
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ {
+ do_rake = true;
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_tangent_bezier(
+ pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ tangents + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+ }
+ }
for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (do_rake) {
+ float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
+ paint_update_brush_rake_rotation(ups, br, rotation);
+ }
+
if (!stroke->stroke_started) {
stroke->last_pressure = 1.0;
copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
@@ -956,12 +1040,45 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
}
stroke_done(C, op);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(stroke);
+#endif
+
return true;
}
return false;
}
+static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
+{
+ if (stroke->constrain_line) {
+ float line[2];
+ float angle, len, res;
+
+ sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
+ angle = atan2f(line[1], line[0]);
+ len = len_v2(line);
+
+ /* divide angle by PI/4 */
+ angle = 4.0f * angle / (float)M_PI;
+
+ /* now take residue */
+ res = angle - floorf(angle);
+
+ /* residue decides how close we are at a certain angle */
+ if (res <= 0.5f) {
+ angle = floorf(angle) * (float)M_PI_4;
+ }
+ else {
+ angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
+ }
+
+ mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
+ mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
+ }
+}
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -1035,7 +1152,9 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == stroke->event_type && !first_modal) {
if (event->val == KM_RELEASE) {
- paint_stroke_line_end (C, op, stroke, sample_average.mouse);
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+ paint_stroke_line_end (C, op, stroke, mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
@@ -1045,12 +1164,20 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
stroke_done(C, op);
return OPERATOR_FINISHED;
}
- else if ((br->flag & BRUSH_LINE) && stroke->stroke_started &&
- (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
- {
- if (br->flag & BRUSH_RAKE) {
- copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
- paint_calculate_rake_rotation(stroke->ups, sample_average.mouse);
+ else if (br->flag & BRUSH_LINE) {
+ if (event->alt)
+ stroke->constrain_line = true;
+ else
+ stroke->constrain_line = false;
+
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+
+ if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ }
+ paint_calculate_rake_rotation(stroke->ups, br, mouse);
}
}
else if (first_modal ||
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index 20e3155c01d..42f0aaab173 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -210,7 +210,7 @@ static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *
/* pass */
}
else {
- if (!name || strcmp(stack->current->name, name) == 0) {
+ if (!name || STREQ(stack->current->name, name)) {
if (G.debug & G_DEBUG_WM) {
printf("%s: undo '%s'\n", __func__, stack->current->name);
}
@@ -225,7 +225,7 @@ static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *
/* pass */
}
else {
- if (!name || strcmp(stack->current->name, name) == 0) {
+ if (!name || STREQ(stack->current->name, name)) {
undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first;
undo_restore(C, stack, undo);
stack->current = undo;
@@ -331,32 +331,33 @@ void ED_undo_paint_step_num(bContext *C, int type, int step)
undo_step_num(C, &MeshUndoStack, step);
}
-static char *undo_stack_get_name(UndoStack *stack, int nr, int *active)
+static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active)
{
UndoElem *uel;
- if (active) *active = 0;
+ if (r_active) *r_active = false;
uel = BLI_findlink(&stack->elems, nr);
if (uel) {
- if (active && uel == stack->current)
- *active = 1;
+ if (r_active && (uel == stack->current)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
}
-const char *ED_undo_paint_get_name(bContext *C, int type, int nr, int *active)
+const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active)
{
if (type == UNDO_PAINT_IMAGE) {
undo_stack_cleanup(&ImageUndoStack, C);
- return undo_stack_get_name(&ImageUndoStack, nr, active);
+ return undo_stack_get_name(&ImageUndoStack, nr, r_active);
}
else if (type == UNDO_PAINT_MESH) {
undo_stack_cleanup(&MeshUndoStack, C);
- return undo_stack_get_name(&MeshUndoStack, nr, active);
+ return undo_stack_get_name(&MeshUndoStack, nr, r_active);
}
return NULL;
}
@@ -379,7 +380,7 @@ bool ED_undo_paint_empty(int type)
return false;
}
-int ED_undo_paint_valid(int type, const char *name)
+bool ED_undo_paint_is_valid(int type, const char *name)
{
UndoStack *stack;
@@ -394,7 +395,7 @@ int ED_undo_paint_valid(int type, const char *name)
/* pass */
}
else {
- if (name && strcmp(stack->current->name, name) == 0)
+ if (name && STREQ(stack->current->name, name))
return 1;
else
return stack->elems.first != stack->elems.last;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index f34d0ff3f7b..7b66632fa42 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -46,17 +46,15 @@
#include "BLI_listbase.h"
#include "BLI_rect.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
-#include "BKE_scene.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_material.h"
#include "BKE_image.h"
+#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_image.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -66,16 +64,12 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
-#include "RE_shader_ext.h"
#include "RE_render_ext.h"
#include "ED_view3d.h"
#include "ED_screen.h"
-#include "ED_uvedit.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
#include "BLI_sys_types.h"
#include "ED_mesh.h" /* for face mask functions */
@@ -183,7 +177,7 @@ float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool,
float co[3] = {u, v, 0.0f};
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
return intensity;
}
@@ -195,7 +189,7 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct
float intensity;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
if (!hasrgb) {
rgba[0] = intensity;
rgba[1] = intensity;
@@ -283,24 +277,16 @@ static void imapaint_tri_weights(float matrix[4][4], GLint view[4],
static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- MTFace *tf_base, *tf;
- Material *ma;
- TexPaintSlot *slot;
- int numfaces = dm->getNumTessFaces(dm), a, findex;
+ const int tottri = dm->getNumLoopTri(dm);
+ int i, findex;
float p[2], w[3], absw, minabsw;
- MFace mf;
- MVert mv[4];
float matrix[4][4], proj[4][4];
GLint view[4];
-
- /* compute barycentric coordinates */
-
- /* double lookup */
- const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ const ImagePaintMode mode = scene->toolsettings->imapaint.mode;
+ const MLoopTri *lt = dm->getLoopTriArray(dm);
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
/* get the needed opengl matrices */
glGetIntegerv(GL_VIEWPORT, view);
@@ -314,56 +300,50 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c
uv[0] = uv[1] = 0.0;
/* test all faces in the derivedmesh with the original index of the picked face */
- for (a = 0; a < numfaces; a++) {
- findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+ /* face means poly here, not triangle, indeed */
+ for (i = 0; i < tottri; i++, lt++) {
+ findex = index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
if (findex == faceindex) {
- dm->getTessFace(dm, a, &mf);
-
- ma = dm->mat[mf.mat_nr];
- slot = &ma->texpaintslot[ma->paint_active_slot];
-
- dm->getVert(dm, mf.v1, &mv[0]);
- dm->getVert(dm, mf.v2, &mv[1]);
- dm->getVert(dm, mf.v3, &mv[2]);
- if (mf.v4)
- dm->getVert(dm, mf.v4, &mv[3]);
-
- if (!(slot && slot->uvname && (tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))))
- tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ const MLoopUV *mloopuv;
+ const MPoly *mp = &mpoly[lt->poly];
+ const MLoopUV *tri_uv[3];
+ float tri_co[3][3];
+
+ dm->getVertCo(dm, mloop[lt->tri[0]].v, tri_co[0]);
+ dm->getVertCo(dm, mloop[lt->tri[1]].v, tri_co[1]);
+ dm->getVertCo(dm, mloop[lt->tri[2]].v, tri_co[2]);
+
+ if (mode == IMAGEPAINT_MODE_MATERIAL) {
+ const Material *ma;
+ const TexPaintSlot *slot;
+
+ ma = dm->mat[mp->mat_nr];
+ slot = &ma->texpaintslot[ma->paint_active_slot];
+
+ if (!(slot && slot->uvname &&
+ (mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, slot->uvname))))
+ {
+ mloopuv = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
+ }
+ }
+ else {
+ mloopuv = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
+ }
- tf = &tf_base[a];
+ tri_uv[0] = &mloopuv[lt->tri[0]];
+ tri_uv[1] = &mloopuv[lt->tri[1]];
+ tri_uv[2] = &mloopuv[lt->tri[2]];
p[0] = xy[0];
p[1] = xy[1];
- if (mf.v4) {
- /* the triangle with the largest absolute values is the one
- * with the most negative weights */
- imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w);
- absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
- if (absw < minabsw) {
- uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2];
- uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2];
- minabsw = absw;
- }
-
- imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w);
- absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
- if (absw < minabsw) {
- uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2];
- uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2];
- minabsw = absw;
- }
- }
- else {
- imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w);
- absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
- if (absw < minabsw) {
- uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2];
- uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2];
- minabsw = absw;
- }
+ imapaint_tri_weights(matrix, view, UNPACK3(tri_co), p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tri_uv[0]->uv[0] * w[0] + tri_uv[1]->uv[0] * w[1] + tri_uv[2]->uv[0] * w[2];
+ uv[1] = tri_uv[0]->uv[1] * w[0] + tri_uv[1]->uv[1] * w[1] + tri_uv[2]->uv[1] * w[2];
+ minabsw = absw;
}
}
}
@@ -372,15 +352,15 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c
}
/* returns 0 if not found, otherwise 1 */
-static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface)
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totpoly)
{
- if (totface == 0)
+ if (totpoly == 0)
return 0;
/* sample only on the exact position */
- *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
+ *r_index = ED_view3d_backbuf_sample(vc, mval[0], mval[1]);
- if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) {
+ if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
return 0;
}
@@ -390,12 +370,12 @@ static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *
}
-static Image *imapaint_face_image(DerivedMesh *dm, int face_index)
+static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
{
Image *ima;
- MFace *mf = dm->getTessFaceArray(dm) + face_index;
- Material *ma = dm->mat[mf->mat_nr];
- ima = ma->texpaintslot[ma->paint_active_slot].ima;
+ MPoly *mp = me->mpoly + face_index;
+ Material *ma = give_current_material(ob, mp->mat_nr + 1);
+ ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
return ima;
}
@@ -438,6 +418,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
}
@@ -449,26 +430,24 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
if (ob) {
+ Mesh *me = (Mesh *)ob->data;
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
ViewContext vc;
const int mval[2] = {x, y};
unsigned int faceindex;
- unsigned int totface = dm->getNumTessFaces(dm);
- MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
-
- DM_update_materials(dm, ob);
+ unsigned int totpoly = me->totpoly;
- if (dm_mtface) {
+ if (dm->getLoopDataArray(dm, CD_MLOOPUV)) {
view3d_set_viewcontext(C, &vc);
view3d_operator_needs_opengl(C);
- if (imapaint_pick_face(&vc, mval, &faceindex, totface)) {
+ if (imapaint_pick_face(&vc, mval, &faceindex, totpoly)) {
Image *image;
if (use_material)
- image = imapaint_face_image(dm, faceindex);
+ image = imapaint_face_image(ob, me, faceindex);
else
image = imapaint->canvas;
@@ -486,12 +465,15 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
if (u < 0.0f) u += 1.0f;
if (v < 0.0f) v += 1.0f;
- u = u * ibuf->x - 0.5f;
- v = v * ibuf->y - 0.5f;
+ u = u * ibuf->x;
+ v = v * ibuf->y;
if (ibuf->rect_float) {
float rgba_f[4];
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ if (U.gameflags & USER_DISABLE_MIPMAP)
+ nearest_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ else
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
straight_to_premul_v4(rgba_f);
if (use_palette) {
linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
@@ -503,7 +485,10 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
else {
unsigned char rgba[4];
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (U.gameflags & USER_DISABLE_MIPMAP)
+ nearest_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ else
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
}
@@ -587,7 +572,7 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
ot->poll = brush_curve_preset_poll;
prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
- RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 509a7f31f5b..8daad9deea9 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -37,6 +37,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
@@ -66,8 +67,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "GPU_buffers.h"
-
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_mesh.h"
@@ -84,53 +83,14 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
if (dm) {
Mesh *me = BKE_mesh_from_object(ob);
- if (me && me->mcol) {
- return (me->mcol == CustomData_get_layer(&dm->faceData, CD_MCOL));
+ if (me && me->mloopcol) {
+ return (me->mloopcol == CustomData_get_layer(&dm->loopData, CD_MLOOPCOL));
}
}
return false;
}
-/* if the polygons from the mesh and the 'derivedFinal' match
- * we can assume that no modifiers are applied and that its worth adding tessellated faces
- * so 'vertex_paint_use_fast_update_check()' returns true */
-static bool vertex_paint_use_tessface_check(Object *ob, Mesh *me)
-{
- DerivedMesh *dm = ob->derivedFinal;
-
- if (me && dm) {
- return (me->mpoly == CustomData_get_layer(&dm->polyData, CD_MPOLY));
- }
-
- return false;
-}
-
-static void update_tessface_data(Object *ob, Mesh *me)
-{
- if (vertex_paint_use_tessface_check(ob, me)) {
- /* assume if these exist, that they are up to date & valid */
- if (!me->mcol || !me->mface) {
- /* should always be true */
- /* XXX Why this clearing? tessface_calc will reset it anyway! */
-#if 0
- if (me->mcol) {
- memset(me->mcol, 255, 4 * sizeof(MCol) * me->totface);
- }
-#endif
-
- /* create tessfaces because they will be used for drawing & fast updates */
- BKE_mesh_tessface_calc(me); /* does own call to update pointers */
- }
- }
- else {
- if (me->totface) {
- /* this wont be used, theres no need to keep it */
- BKE_mesh_tessface_clear(me);
- }
- }
-
-}
/* polling - retrieve whether cursor should be set or operator should be done */
/* Returns true if vertex paint mode is active */
@@ -206,82 +166,9 @@ unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp)
return *(unsigned int *)col;
}
-static void do_shared_vertex_tesscol(Mesh *me, bool *mfacetag)
-{
- /* if no mcol: do not do */
- /* if tface: only the involved faces, otherwise all */
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
- MFace *mface;
- int a;
- short *scolmain, *scol;
- char *mcol;
- const bool *mftag;
-
- if (me->mcol == NULL || me->totvert == 0 || me->totface == 0) return;
-
- scolmain = MEM_callocN(4 * sizeof(short) * me->totvert, "colmain");
-
- mface = me->mface;
- mcol = (char *)me->mcol;
- for (a = me->totface; a > 0; a--, mface++, mcol += 16) {
- if ((use_face_sel == false) || (mface->flag & ME_FACE_SEL)) {
- scol = scolmain + 4 * mface->v1;
- scol[0]++; scol[1] += mcol[1]; scol[2] += mcol[2]; scol[3] += mcol[3];
- scol = scolmain + 4 * mface->v2;
- scol[0]++; scol[1] += mcol[5]; scol[2] += mcol[6]; scol[3] += mcol[7];
- scol = scolmain + 4 * mface->v3;
- scol[0]++; scol[1] += mcol[9]; scol[2] += mcol[10]; scol[3] += mcol[11];
- if (mface->v4) {
- scol = scolmain + 4 * mface->v4;
- scol[0]++; scol[1] += mcol[13]; scol[2] += mcol[14]; scol[3] += mcol[15];
- }
- }
- }
-
- a = me->totvert;
- scol = scolmain;
- while (a--) {
- if (scol[0] > 1) {
- scol[1] = divide_round_i(scol[1], scol[0]);
- scol[2] = divide_round_i(scol[2], scol[0]);
- scol[3] = divide_round_i(scol[3], scol[0]);
- }
- scol += 4;
- }
-
- mface = me->mface;
- mcol = (char *)me->mcol;
- mftag = mfacetag;
- for (a = me->totface; a > 0; a--, mface++, mcol += 16, mftag += 4) {
- if ((use_face_sel == false) || (mface->flag & ME_FACE_SEL)) {
- if (mftag[0]) {
- scol = scolmain + 4 * mface->v1;
- mcol[1] = scol[1]; mcol[2] = scol[2]; mcol[3] = scol[3];
- }
-
- if (mftag[1]) {
- scol = scolmain + 4 * mface->v2;
- mcol[5] = scol[1]; mcol[6] = scol[2]; mcol[7] = scol[3];
- }
-
- if (mftag[2]) {
- scol = scolmain + 4 * mface->v3;
- mcol[9] = scol[1]; mcol[10] = scol[2]; mcol[11] = scol[3];
- }
-
- if (mface->v4 && mftag[3]) {
- scol = scolmain + 4 * mface->v4;
- mcol[13] = scol[1]; mcol[14] = scol[2]; mcol[15] = scol[3];
- }
- }
- }
-
- MEM_freeN(scolmain);
-}
-
-static void do_shared_vertexcol(Mesh *me, bool *mlooptag, bool *mfacetag, const bool do_tessface)
+static void do_shared_vertexcol(Mesh *me, bool *mlooptag)
{
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
MPoly *mp;
int (*scol)[4];
int i, j;
@@ -333,10 +220,6 @@ static void do_shared_vertexcol(Mesh *me, bool *mlooptag, bool *mfacetag, const
}
MEM_freeN(scol);
-
- if (has_shared && do_tessface) {
- do_shared_vertex_tesscol(me, mfacetag);
- }
}
static bool make_vertexcol(Object *ob) /* single ob */
@@ -353,17 +236,12 @@ static bool make_vertexcol(Object *ob) /* single ob */
/* copies from shadedisplist to mcol */
if (!me->mloopcol && me->totloop) {
- if (!me->mcol) {
- CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
- }
if (!me->mloopcol) {
CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
}
BKE_mesh_update_customdata_pointers(me, true);
}
- update_tessface_data(ob, me);
-
DAG_id_tag_update(&me->id, 0);
return (me->mloopcol != NULL);
@@ -382,12 +260,12 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
mirrdef = defgroup_name_index(ob, name_flip);
if (mirrdef == -1) {
if (BKE_defgroup_new(ob, name_flip)) {
- mirrdef = BLI_countlist(&ob->defbase) - 1;
+ mirrdef = BLI_listbase_count(&ob->defbase) - 1;
}
}
/* curdef should never be NULL unless this is
- * a lamp and ED_vgroup_add_name fails */
+ * a lamp and BKE_object_defgroup_add_name fails */
return mirrdef;
}
@@ -594,7 +472,7 @@ bool ED_vpaint_smooth(Object *ob)
/* remove stale me->mcol, will be added later */
BKE_mesh_tessface_clear(me);
- do_shared_vertexcol(me, mlooptag, NULL, false);
+ do_shared_vertexcol(me, mlooptag);
MEM_freeN(mlooptag);
@@ -770,7 +648,7 @@ BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int f
/* See if are lighter, if so mix, else don't do anything.
* if the paint col is darker then the original, then ignore */
- if (rgb_to_grayscale_byte(cp1) > rgb_to_grayscale_byte(cp2)) {
+ if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) {
return col1;
}
@@ -803,7 +681,7 @@ BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fa
/* See if were darker, if so mix, else don't do anything.
* if the paint col is brighter then the original, then ignore */
- if (rgb_to_grayscale_byte(cp1) < rgb_to_grayscale_byte(cp2)) {
+ if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) {
return col1;
}
@@ -870,7 +748,7 @@ static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colo
}
-static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
+static int sample_backbuf_area(ViewContext *vc, int *indexar, int totpoly, int x, int y, float size)
{
struct ImBuf *ibuf;
int a, tot = 0, index;
@@ -879,26 +757,29 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
* brushes with size > 64, why is this here? */
/*if (size > 64.0) size = 64.0;*/
- ibuf = view3d_read_backbuf(vc, x - size, y - size, x + size, y + size);
+ ibuf = ED_view3d_backbuf_read(vc, x - size, y - size, x + size, y + size);
if (ibuf) {
unsigned int *rt = ibuf->rect;
- memset(indexar, 0, sizeof(int) * (totface + 1));
+ memset(indexar, 0, sizeof(int) * (totpoly + 1));
size = ibuf->x * ibuf->y;
while (size--) {
if (*rt) {
- index = WM_framebuffer_to_index(*rt);
- if (index > 0 && index <= totface)
+ index = *rt;
+ if (index > 0 && index <= totpoly) {
indexar[index] = 1;
+ }
}
rt++;
}
- for (a = 1; a <= totface; a++) {
- if (indexar[a]) indexar[tot++] = a;
+ for (a = 1; a <= totpoly; a++) {
+ if (indexar[a]) {
+ indexar[tot++] = a;
+ }
}
IMB_freeImBuf(ibuf);
@@ -919,7 +800,7 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co
{
const float dist_sq = len_squared_v2v2(mval, co_ss);
- if (dist_sq <= brush_size_pressure * brush_size_pressure) {
+ if (dist_sq <= SQUARE(brush_size_pressure)) {
Brush *brush = BKE_paint_brush(&vp->paint);
const float dist = sqrtf(dist_sq);
float factor;
@@ -937,7 +818,7 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co
else {
factor = 1.0f;
}
- return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure);
+ return factor * BKE_brush_curve_strength_clamped(brush, dist, brush_size_pressure);
}
}
if (rgba)
@@ -1092,7 +973,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d) {
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int v_idx_best = -1;
unsigned int index;
@@ -1177,8 +1058,8 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
- const int defbase_tot = BLI_countlist(&vc.obact->defbase);
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
bool found = false;
unsigned int index;
@@ -1577,8 +1458,8 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
change_status[i] = 1; /* can be altered while redistributing */
}
}
- /* if there was any change, redistribute it */
- if (total_changed) {
+ /* if there was any change, and somewhere to redistribute it, do it */
+ if (total_changed && total_valid) {
/* auto normalize will allow weights to temporarily go above 1 in redistribution */
if (vgroup_validmap && total_changed < 0 && total_valid) {
totchange_allowed = total_valid;
@@ -1742,7 +1623,8 @@ static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi,
}
clamp_weights(dv);
- enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags, wpi->vgroup_validmap, wpi->do_auto_normalize, wpi->do_multipaint);
+ enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags, wpi->vgroup_validmap,
+ wpi->do_auto_normalize, wpi->do_multipaint);
if (wpi->do_auto_normalize) {
/* XXX - should we pass the active group? - currently '-1' */
@@ -2074,7 +1956,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
paint_cursor_start(C, weight_paint_poll);
- BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
+ BKE_paint_init(scene, ePaintWeight, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
ED_mesh_mirror_spatial_table(ob, NULL, NULL, 's');
@@ -2159,7 +2041,7 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op)
/* if nothing was added yet, we make dverts and a vertex deform group */
if (!me->dvert) {
- ED_vgroup_data_create(&me->id);
+ BKE_object_defgroup_data_create(&me->id);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
@@ -2174,7 +2056,7 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op)
if (pchan) {
bDeformGroup *dg = defgroup_find_name(ob, pchan->name);
if (dg == NULL) {
- dg = ED_vgroup_add_name(ob, pchan->name); /* sets actdef */
+ dg = BKE_object_defgroup_add_name(ob, pchan->name); /* sets actdef */
}
else {
int actdef = 1 + BLI_findindex(&ob->defbase, dg);
@@ -2186,7 +2068,7 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op)
}
}
if (BLI_listbase_is_empty(&ob->defbase)) {
- ED_vgroup_add(ob);
+ BKE_object_defgroup_add(ob);
}
/* ensure we don't try paint onto an invalid group */
@@ -2235,10 +2117,10 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN
/* set up auto-normalize, and generate map for detecting which
* vgroups affect deform bones */
- wpd->defbase_tot = BLI_countlist(&ob->defbase);
- wpd->lock_flags = BKE_objdef_lock_flags_get(ob, wpd->defbase_tot);
+ wpd->defbase_tot = BLI_listbase_count(&ob->defbase);
+ wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) {
- wpd->vgroup_validmap = BKE_objdef_validmap_get(ob, wpd->defbase_tot);
+ wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
}
/* painting on subsurfs should give correct points too, this returns me->totvert amount */
@@ -2318,7 +2200,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
wpi.defbase_tot = wpd->defbase_tot;
- wpi.defbase_sel = BKE_objdef_selected_get(ob, wpi.defbase_tot, &wpi.defbase_tot_sel);
+ wpi.defbase_sel = BKE_object_defgroup_selected_get(ob, wpi.defbase_tot, &wpi.defbase_tot_sel);
if (wpi.defbase_tot_sel == 0 && ob->actdef > 0) {
wpi.defbase_tot_sel = 1;
}
@@ -2682,7 +2564,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
paint_cursor_start(C, vertex_paint_poll);
- BKE_paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
+ BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT);
}
/* update modifier stack for mapping requirements */
@@ -2750,35 +2632,13 @@ typedef struct VPaintData {
* array, otherwise we need to refresh the modifier stack */
bool use_fast_update;
- /* mpoly -> mface mapping */
- MeshElemMap *polyfacemap;
- void *polyfacemap_mem;
-
/* loops tagged as having been painted, to apply shared vertex color
* blending only to modified loops */
bool *mlooptag;
- bool *mfacetag;
bool is_texbrush;
} VPaintData;
-static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
-{
- const int *tessface_origindex;
-
- vd->polyfacemap = NULL;
- vd->polyfacemap_mem = NULL;
-
- tessface_origindex = CustomData_get_layer(&me->fdata, CD_ORIGINDEX);
-
- if (!tessface_origindex)
- return;
-
- BKE_mesh_origindex_map_create(&vd->polyfacemap, (int **)&vd->polyfacemap_mem,
- me->totpoly,
- tessface_origindex, me->totface);
-}
-
static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2]))
{
Scene *scene = CTX_data_scene(C);
@@ -2801,11 +2661,6 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
if (me->mloopcol == NULL)
return false;
- /* Update tessface data if needed
- * Added here too because e.g. switching to/from edit mode would remove tessface data,
- * yet "fast_update" could still be used! */
- update_tessface_data(ob, me);
-
/* make mode data storage */
vpd = MEM_callocN(sizeof(struct VPaintData), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
@@ -2820,9 +2675,8 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
brush->mtex.tex;
/* are we painting onto a modified mesh?,
- * if not we can skip face map trickyness */
+ * if not we can skip face map trickiness */
if (vertex_paint_use_fast_update_check(ob)) {
- vpaint_build_poly_facemap(vpd, me);
vpd->use_fast_update = true;
/* printf("Fast update!\n");*/
}
@@ -2834,8 +2688,6 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* to keep tracked of modified loops for shared vertex color blending */
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
- if (vpd->use_fast_update)
- vpd->mfacetag = MEM_mallocN(sizeof(bool) * me->totface * 4, "VPaintData mfacetag");
}
/* for filtering */
@@ -2856,14 +2708,10 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
ViewContext *vc = &vpd->vc;
Brush *brush = BKE_paint_brush(&vp->paint);
MPoly *mpoly = &me->mpoly[index];
- MFace *mf;
- MCol *mc;
MLoop *ml;
- MLoopCol *mlc;
unsigned int *lcol = ((unsigned int *)me->mloopcol) + mpoly->loopstart;
unsigned int *lcolorig = ((unsigned int *)vp->vpaint_prev) + mpoly->loopstart;
bool *mlooptag = (vpd->mlooptag) ? vpd->mlooptag + mpoly->loopstart : NULL;
- bool *mftag;
float alpha;
int i, j;
int totloop = mpoly->totloop;
@@ -2920,35 +2768,6 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
if (mlooptag) mlooptag[i] = 1;
}
}
-
- if (vpd->use_fast_update) {
- const MeshElemMap *map = &vpd->polyfacemap[index];
-
- /* update vertex colors for tessellations incrementally,
- * rather then regenerating the tessellation altogether */
- for (i = 0; i < map->count; i++) {
- const int index_tessface = map->indices[i];
-
- mf = &me->mface[index_tessface];
- mc = &me->mcol[index_tessface * 4];
- mftag = &vpd->mfacetag[index_tessface * 4];
-
- ml = me->mloop + mpoly->loopstart;
- mlc = me->mloopcol + mpoly->loopstart;
-
- for (j = 0; j < totloop; j++, ml++, mlc++) {
- /* search for the loop vertex within the tessface */
- const int fidx = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml->v);
- if (fidx != -1) {
- MESH_MLOOPCOL_TO_MCOL(mlc, mc + fidx);
- if (mlooptag) {
- mftag[fidx] = mlooptag[j];
- }
- }
- }
- }
- }
-
}
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
@@ -2984,8 +2803,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) {
for (index = 0; index < totindex; index++) {
if (indexar[index] && indexar[index] <= me->totpoly) {
- MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
-
+ const MPoly *mpoly = &me->mpoly[indexar[index] - 1];
+
if ((mpoly->flag & ME_FACE_SEL) == 0)
indexar[index] = 0;
}
@@ -3000,8 +2819,6 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* clear modified tag for blur tool */
if (vpd->mlooptag)
memset(vpd->mlooptag, 0, sizeof(bool) * me->totloop);
- if (vpd->mfacetag)
- memset(vpd->mfacetag, 0, sizeof(bool) * me->totface * 4);
for (index = 0; index < totindex; index++) {
if (indexar[index] && indexar[index] <= me->totpoly) {
@@ -3013,8 +2830,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* was disabled because it is slow, but necessary for blur */
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- int do_tessface = vpd->use_fast_update;
- do_shared_vertexcol(me, vpd->mlooptag, vpd->mfacetag, do_tessface);
+ do_shared_vertexcol(me, vpd->mlooptag);
}
ED_region_tag_redraw(vc->ar);
@@ -3024,7 +2840,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
* avoid this if we can! */
DAG_id_tag_update(ob->data, 0);
}
- else if (!GPU_buffer_legacy(ob->derivedFinal)) {
+ else {
/* If using new VBO drawing, mark mcol as dirty to force colors gpu buffer refresh! */
ob->derivedFinal->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW;
}
@@ -3043,20 +2859,9 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
/* frees prev buffer */
copy_vpaint_prev(ts->vpaint, NULL, 0);
- if (vpd->polyfacemap) {
- MEM_freeN(vpd->polyfacemap);
- }
-
- if (vpd->polyfacemap_mem) {
- MEM_freeN(vpd->polyfacemap_mem);
- }
-
if (vpd->mlooptag)
MEM_freeN(vpd->mlooptag);
- if (vpd->mfacetag)
- MEM_freeN(vpd->mfacetag);
-
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
MEM_freeN(vpd);
@@ -3217,7 +3022,7 @@ static void gradientVert_update(DMGradient_userData *grad_data, int index)
/* no need to clamp 'alpha' yet */
/* adjust weight */
- alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f);
+ alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
if (alpha != 0.0f) {
MDeformVert *dv = &me->dvert[index];
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index ae729248f7e..c939eb6df35 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -186,7 +186,7 @@ static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle,
/* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */
if (LIKELY(dm->foreachMappedVert)) {
- fill_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
+ copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7e518242b00..07511e1924e 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -40,9 +40,8 @@
#include "BLI_dial.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLI_threads.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
@@ -56,8 +55,8 @@
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
-#include "BKE_crazyspace.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -85,9 +84,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RE_render_ext.h"
-
#include "GPU_buffers.h"
+#include "GPU_extensions.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -106,6 +104,8 @@
#if defined(__APPLE__) && defined _OPENMP
#include <sys/sysctl.h>
+#include "BLI_threads.h"
+
/* Query how many cores not counting HT aka physical cores we've got. */
static int system_physical_thread_count(void)
{
@@ -116,32 +116,12 @@ static int system_physical_thread_count(void)
}
#endif /* __APPLE__ */
-void ED_sculpt_stroke_get_average(Object *ob, float stroke[3])
-{
- if (ob->sculpt->last_stroke_valid && ob->sculpt->average_stroke_counter > 0) {
- float fac = 1.0f / ob->sculpt->average_stroke_counter;
- mul_v3_v3fl(stroke, ob->sculpt->average_stroke_accum, fac);
- }
- else {
- copy_v3_v3(stroke, ob->obmat[3]);
- }
-}
-
-bool ED_sculpt_minmax(bContext *C, float min[3], float max[3])
-{
- Object *ob = CTX_data_active_object(C);
-
- if (ob && ob->sculpt && ob->sculpt->last_stroke_valid) {
- copy_v3_v3(min, ob->sculpt->last_stroke);
- copy_v3_v3(max, ob->sculpt->last_stroke);
-
- return 1;
- }
- else {
- return 0;
- }
-}
-
+/** \name Tool Capabilities
+ *
+ * Avoid duplicate checks, internal logic only,
+ * share logic with #rna_def_sculpt_capabilities where possible.
+ *
+ * \{ */
/* Check if there are any active modifiers in stack (used for flushing updates at enter/exit sculpt mode) */
static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
@@ -160,6 +140,43 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
return 0;
}
+static bool sculpt_tool_needs_original(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER);
+}
+
+static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_LAYER);
+}
+
+/**
+ * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
+ */
+static int sculpt_brush_needs_normal(const Brush *brush)
+{
+ return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
+ (brush->normal_weight > 0)) ||
+
+ ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB) ||
+
+ (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
+}
+
+/** \} */
typedef enum StrokeFlags {
@@ -192,8 +209,8 @@ typedef struct StrokeCache {
float true_location[3];
float location[3];
- float pen_flip;
- float invert;
+ bool pen_flip;
+ bool invert;
float pressure;
float mouse[2];
float bstrength;
@@ -209,8 +226,6 @@ typedef struct StrokeCache {
ViewContext *vc;
Brush *brush;
- float (*face_norms)[3]; /* Copy of the mesh faces' normals */
-
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
@@ -231,6 +246,9 @@ typedef struct StrokeCache {
* calc_brush_local_mat() and used in tex_strength(). */
float brush_local_mat[4][4];
+ float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
+ int tile_pass;
+
float last_center[3];
int radial_symmetry_pass;
float symm_rot_mat[4][4];
@@ -268,8 +286,8 @@ typedef struct {
/* Original coordinate, normal, and mask */
const float *co;
- float mask;
const short *no;
+ float mask;
} SculptOrigVertData;
@@ -312,30 +330,70 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
- if (orig_data->coords) {
- orig_data->co = orig_data->coords[iter->i];
+ if (orig_data->bm_log) {
+ BM_log_original_vert_data(
+ orig_data->bm_log, iter->bm_vert,
+ &orig_data->co, &orig_data->no);
}
else {
- orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
- }
-
- if (orig_data->normals) {
+ orig_data->co = orig_data->coords[iter->i];
orig_data->no = orig_data->normals[iter->i];
}
- else {
- orig_data->no = BM_log_original_vert_no(orig_data->bm_log, iter->bm_vert);
- }
}
else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
- if (orig_data->vmasks) {
- orig_data->mask = orig_data->vmasks[iter->i];
+ if (orig_data->bm_log) {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
}
else {
- orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ orig_data->mask = orig_data->vmasks[iter->i];
}
}
}
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ *
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+/**
+ * \param plane Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(
+ SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(
+ const SculptProjectVector *spvc, const float vec[3],
+ float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+/** \} */
+
+
/**********************************************************************/
/* Returns true if the stroke will use dynamic topology, false
@@ -344,8 +402,8 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
- const Brush *brush)
+static bool sculpt_stroke_is_dynamic_topology(
+ const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -355,20 +413,8 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
* dynamic-topology */
!(brush->flag & BRUSH_ANCHORED) &&
!(brush->flag & BRUSH_DRAG_DOT) &&
-
- (!ELEM(brush->sculpt_tool,
- /* These brushes, as currently coded, cannot
- * support dynamic topology */
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER,
-
- /* These brushes could handle dynamic topology,
- * but user feedback indicates it's better not
- * to */
- SCULPT_TOOL_SMOOTH,
- SCULPT_TOOL_MASK)));
+
+ SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
/*** paint mesh ***/
@@ -376,17 +422,11 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
const Brush *brush = BKE_paint_brush(&sd->paint);
- int i;
PBVHNode **nodes;
int n, totnode;
-#ifndef _OPENMP
- (void)sd; /* quied unused warning */
-#endif
-
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
/* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
@@ -431,12 +471,6 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
}
}
- if (ss->face_normals) {
- for (i = 0; i < ss->totpoly; i++) {
- copy_v3_v3(ss->face_normals[i], cache->face_norms[i]);
- }
- }
-
if (nodes)
MEM_freeN(nodes);
}
@@ -536,7 +570,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
}
}
-BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3])
+BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const float co[3])
{
RegionView3D *rv3d = test->clip_rv3d;
return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
@@ -574,7 +608,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
}
}
-static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
+static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3])
{
if (sculpt_brush_test_clipping(test, co)) {
return 0;
@@ -582,7 +616,7 @@ static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
-static bool sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
+static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{
float side = M_SQRT1_2;
float local_co[3];
@@ -635,7 +669,7 @@ static float frontface(Brush *br, const float sculpt_normal[3],
#if 0
-static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
+static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], const float area_no[3])
{
if (sculpt_brush_test_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
@@ -643,7 +677,7 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
sub_v3_v3v3(t1, location, co);
sub_v3_v3v3(t2, x2, location);
- cross_v3_v3v3(t3, an, t1);
+ cross_v3_v3v3(t3, area_no, t1);
dist = len_v3(t3) / len_v3(t2);
@@ -729,18 +763,447 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
}
}
+/** \name Calculate Normal and Center
+ *
+ * Calculate geometry surrounding the brush center.
+ * (optionally using original coordinates).
+ *
+ * Functions are:
+ * - #calc_area_center
+ * - #calc_area_normal
+ * - #calc_area_normal_and_center
+ *
+ * \note These are all _very_ similar, when changing one, check others.
+ * \{ */
+
+static void calc_area_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_co[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_co[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ cross_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for flatten center */
+ add_v3_v3(area_co[0], private_co[0]);
+ add_v3_v3(area_co[1], private_co[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+}
+
+
+static void calc_area_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_no[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/* this calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time */
+static void calc_area_normal_and_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_co[2][3] = {{0.0f}};
+ float area_no[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_co[2][3] = {{0.0f}};
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for flatten center */
+ add_v3_v3(area_co[0], private_co[0]);
+ add_v3_v3(area_co[1], private_co[1]);
+
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups)
+static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
const float root_alpha = BKE_brush_alpha_get(scene, brush);
float alpha = root_alpha * root_alpha;
- float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
+ float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
@@ -809,10 +1272,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, Unifi
return alpha * pressure * feather;
case SCULPT_TOOL_SNAKE_HOOK:
- return feather;
+ return root_alpha * feather;
case SCULPT_TOOL_GRAB:
- return feather;
+ return root_alpha * feather;
case SCULPT_TOOL_ROTATE:
return alpha * pressure * feather;
@@ -954,132 +1417,34 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
-static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
-{
- if ((dot_v3v3(view_vec, fno)) > 0) {
- add_v3_v3(out, fno);
- }
- else {
- add_v3_v3(out_flip, fno); /* out_flip is used when out is {0,0,0} */
- }
-}
-
-static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
-{
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
- int n;
- bool original;
-
- /* Grab brush requires to test on original data (see r33888 and
- * bug #25371) */
- original = (BKE_paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
- true : ss->cache->original);
-
- /* In general the original coords are not available with dynamic
- * topology
- *
- * Mask tool could not use undo nodes to get coordinates from
- * since the coordinates are not stored in those odes.
- * And mask tool is not gonna to modify vertex coordinates,
- * so we don't actually need to use modified coords.
- */
- if (ss->bm || brush->sculpt_tool == SCULPT_TOOL_MASK)
- original = false;
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(an);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (original) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- else {
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
- }
- }
-
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-}
-
/* Calculate primary direction of movement for many brushes */
-static void calc_sculpt_normal(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3])
+static void calc_sculpt_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
const SculptSession *ss = ob->sculpt;
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, r_area_no);
break;
default:
@@ -1180,27 +1545,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
-/* Test whether the StrokeCache.sculpt_normal needs update in
- * do_brush_action() */
-static int brush_needs_sculpt_normal(const Brush *brush)
-{
- return ((ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_SNAKE_HOOK) &&
- (brush->normal_weight > 0)) ||
-
- ELEM(brush->sculpt_tool,
- SCULPT_TOOL_BLOB,
- SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW,
- SCULPT_TOOL_LAYER,
- SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB) ||
-
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
-}
-
/* For the smooth brush, uses the neighboring vertices around vert to calculate
* a smoothed location for vert. Skips corner vertices (used by only one
* polygon.) */
@@ -1210,20 +1554,19 @@ static void neighbor_average(SculptSession *ss, float avg[3], unsigned vert)
const MVert *mvert = ss->mvert;
float (*deform_co)[3] = ss->deform_cos;
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vert_map->count > 1) {
int i, total = 0;
+ zero_v3(avg);
+
for (i = 0; i < vert_map->count; i++) {
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
- if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] :
mvert[f_adj_v[j]].co);
@@ -1254,12 +1597,11 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
for (i = 0; i < ss->pmap[vert].count; i++) {
const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
- if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
avg += vmask[f_adj_v[j]];
total++;
}
@@ -1275,22 +1617,24 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
/* Same logic as neighbor_average(), but for bmesh rather than mesh */
static void bmesh_neighbor_average(float avg[3], BMVert *v)
{
- const int vfcount = BM_vert_face_count(v);
+ /* logic for 3 or more is identical */
+ const int vfcount = BM_vert_face_count_ex(v, 3);
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vfcount > 1) {
BMIter liter;
BMLoop *l;
int i, total = 0;
+ zero_v3(avg);
+
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) {
- add_v3_v3(avg, adj_v[i]->co);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
total++;
}
}
@@ -1306,7 +1650,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
-static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
{
BMIter liter;
BMLoop *l;
@@ -1314,13 +1658,12 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
int i, total = 0;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ /* skip this vertex */
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- BMVert *v2 = adj_v[i];
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v2->head.data,
- CD_PAINT_MASK);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
avg += (*vmask);
total++;
}
@@ -1330,9 +1673,7 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
return avg / (float)total;
}
else {
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v->head.data,
- CD_PAINT_MASK);
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
return (*vmask);
}
}
@@ -1395,7 +1736,7 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
vd.no, vd.fno,
smooth_mask ? 0 : *vd.mask);
if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask;
+ float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
CLAMP(*vd.mask, 0, 1);
@@ -1426,12 +1767,11 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
SculptBrushTest test;
CCGElem **griddata, *data;
CCGKey key;
- DMGridAdjacency *gridadj, *adj;
float (*tmpgrid_co)[3], (*tmprow_co)[3];
float *tmpgrid_mask, *tmprow_mask;
int v1, v2, v3, v4;
int thread_num;
- BLI_bitmap **grid_hidden;
+ BLI_bitmap * const *grid_hidden;
int *grid_indices, totgrid, gridsize, i, x, y;
sculpt_brush_test_init(ss, &test);
@@ -1439,7 +1779,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
CLAMP(bstrength, 0.0f, 1.0f);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata, &gridadj);
+ NULL, &gridsize, &griddata);
BKE_pbvh_get_grid_key(ss->pbvh, &key);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -1456,9 +1796,8 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
for (i = 0; i < totgrid; ++i) {
int gi = grid_indices[i];
- BLI_bitmap *gh = grid_hidden[gi];
+ const BLI_bitmap *gh = grid_hidden[gi];
data = griddata[gi];
- adj = &gridadj[gi];
if (smooth_mask)
memset(tmpgrid_mask, 0, sizeof(float) * gridsize * gridsize);
@@ -1524,18 +1863,6 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
continue;
}
- if (x == 0 && adj->index[0] == -1)
- continue;
-
- if (x == gridsize - 1 && adj->index[2] == -1)
- continue;
-
- if (y == 0 && adj->index[3] == -1)
- continue;
-
- if (y == gridsize - 1 && adj->index[1] == -1)
- continue;
-
index = x + y * gridsize;
co = CCG_elem_offset_co(&key, data, index);
fno = CCG_elem_offset_no(&key, data, index);
@@ -1726,6 +2053,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float brush_alpha;
int n;
+ SculptProjectVector spvc;
+
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
@@ -1742,6 +2071,10 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single point.
+ * Without this we get a 'flat' surface surrounding the pinch */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
/* threaded loop over nodes */
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -1766,6 +2099,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
sub_v3_v3v3(val1, test.location, vd.co);
mul_v3_fl(val1, fade * flippedbstrength);
+ sculpt_project_v3(&spvc, val1, val1);
+
/* then we draw */
mul_v3_v3fl(val2, offset, fade);
@@ -2159,266 +2494,38 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
-static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- int count = 0;
- int count_flip = 0;
-
- float fc_flip[3] = {0.0, 0.0, 0.0};
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(fc);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flip += private_count_flip;
- }
- }
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flip != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flip);
- else
- zero_v3(fc);
-}
-
-/* this calculates flatten center and area normal together,
- * amortizing the memory bandwidth and loop overhead to calculate both at the same time */
-static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3], float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- /* for area normal */
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
- float fc_flip[3] = {0.0f, 0.0f, 0.0f};
-
- /* for flatten center */
- int count = 0;
- int count_flipped = 0;
-
- (void)sd; /* unused w/o openmp */
-
- /* for area normal */
- zero_v3(an);
-
- /* for flatten center */
- zero_v3(fc);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- /* for area normal */
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_an, vd.fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, vd.fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- /* for area normal */
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
-
- /* for flatten center */
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flipped += private_count_flip;
- }
- }
-
- /* for area normal */
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-
- /* for flatten center */
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flipped != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flipped);
- else
- zero_v3(fc);
-}
-
-static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
if (ss->cache->mirror_symmetry_pass == 0 &&
ss->cache->radial_symmetry_pass == 0 &&
+ ss->cache->tile_pass == 0 &&
(ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc);
+ calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
break;
default:
@@ -2428,50 +2535,57 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
/* for flatten center */
/* flatten center has not been calculated yet if we are not using the area normal */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
- calc_flatten_center(sd, ob, nodes, totnode, fc);
+ calc_area_center(sd, ob, nodes, totnode, r_area_co);
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, an);
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, fc);
+ copy_v3_v3(ss->cache->last_center, r_area_co);
}
else {
/* for area normal */
- copy_v3_v3(an, ss->cache->sculpt_normal);
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
/* for flatten center */
- copy_v3_v3(fc, ss->cache->last_center);
+ copy_v3_v3(r_area_co, ss->cache->last_center);
/* for area normal */
- flip_v3(an, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
/* for flatten center */
- flip_v3(fc, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
/* for area normal */
- mul_m4_v3(ss->cache->symm_rot_mat, an);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
/* for flatten center */
- mul_m4_v3(ss->cache->symm_rot_mat, fc);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
+
+ /* shift the plane for the current tile */
+ add_v3_v3(r_area_co, ss->cache->plane_offset);
}
}
/* Projects a point onto a plane along the plane's normal */
-static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
+static void point_plane_project(
+ float intr[3],
+ const float co[3], const float plane_normal[3], const float plane_center[3])
{
sub_v3_v3v3(intr, co, plane_center);
mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
sub_v3_v3v3(intr, co, intr);
}
-static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
+static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
+static bool plane_point_side_flip(
+ const float co[3], const float plane_normal[3], const float plane_center[3],
+ const bool flip)
{
float delta[3];
float d;
@@ -2484,7 +2598,7 @@ static int plane_point_side_flip(float co[3], float plane_normal[3], float plane
return d <= 0.0f;
}
-static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
+static int plane_point_side(const float co[3], const float plane_normal[3], const float plane_center[3])
{
float delta[3];
@@ -2513,8 +2627,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
@@ -2524,13 +2638,13 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2548,7 +2662,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2578,16 +2692,16 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float displace;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
int n;
float temp[3];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
flip = bstrength < 0;
@@ -2598,11 +2712,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
- /* add_v3_v3v3(p, ss->cache->location, an); */
+ /* add_v3_v3v3(p, ss->cache->location, area_no); */
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2617,15 +2731,17 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, an, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -2652,9 +2768,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float displace;
- float sn[3];
- float an[3];
- float fc[3];
+ float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
+ float area_no[3]; /* geometry normal */
+ float area_co[3];
int n;
@@ -2663,14 +2779,14 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float scale[4][4];
float tmat[4][4];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, area_no);
else
- copy_v3_v3(an, sn);
+ copy_v3_v3(area_no, area_no_sp);
/* delay the first daub because grab delta is not setup */
if (ss->cache->first_time)
@@ -2685,16 +2801,16 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, sn, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
/* init mat */
- cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry);
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
mat[0][3] = 0;
- cross_v3_v3v3(mat[1], an, mat[0]);
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
mat[1][3] = 0;
- copy_v3_v3(mat[2], an);
+ copy_v3_v3(mat[2], area_no);
mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location);
mat[3][3] = 1;
@@ -2718,15 +2834,17 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, sn, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, sn, fc);
+ point_plane_project(intr, vd.co, area_no_sp, area_co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(ss, brush, vd.co,
ss->cache->radius * test.dist,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -2751,8 +2869,8 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2761,13 +2879,13 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2782,11 +2900,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side(vd.co, an, fc)) {
+ if (plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2815,8 +2933,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2825,13 +2943,13 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = -radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2846,11 +2964,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (!plane_point_side(vd.co, an, fc)) {
+ if (!plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2876,7 +2994,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3]/*, an[3]*/;
+ float offset[3]/*, area_no[3]*/;
int n;
float gravity_vector[3];
@@ -2917,19 +3035,13 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
Mesh *me = (Mesh *)ob->data;
float (*ofs)[3] = NULL;
- int a, is_basis = 0;
+ int a;
+ const int kb_act_idx = ob->shapenr - 1;
KeyBlock *currkey;
/* for relative keys editing of base should update other keys */
- if (me->key->type == KEY_RELATIVE)
- for (currkey = me->key->block.first; currkey; currkey = currkey->next)
- if (ob->shapenr - 1 == currkey->relative) {
- is_basis = 1;
- break;
- }
-
- if (is_basis) {
- ofs = BKE_key_convert_to_vertcos(ob, kb);
+ if (BKE_keyblock_is_basis(me->key, kb_act_idx)) {
+ ofs = BKE_keyblock_convert_to_vertcos(ob, kb);
/* calculate key coord offsets (from previous location) */
for (a = 0; a < me->totvert; a++) {
@@ -2937,14 +3049,10 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
}
/* apply offsets on other keys */
- currkey = me->key->block.first;
- while (currkey) {
- int apply_offset = ((currkey != kb) && (ob->shapenr - 1 == currkey->relative));
-
- if (apply_offset)
- BKE_key_convert_from_offset(ob, currkey, ofs);
-
- currkey = currkey->next;
+ for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ if ((currkey != kb) && (currkey->relative == kb_act_idx)) {
+ BKE_keyblock_update_from_offset(ob, currkey, ofs);
+ }
}
MEM_freeN(ofs);
@@ -2960,14 +3068,14 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
BKE_mesh_calc_normals(me);
}
- /* apply new coords on active key block */
- BKE_key_convert_from_vertcos(ob, kb, vertCos);
+ /* apply new coords on active key block, no need to re-allocate kb->data here! */
+ BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
}
/* Note: we do the topology update before any brush actions to avoid
* issues with the proxies. The size of the proxy can't change, so
* topology must be updated first. */
-static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
+static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *UNUSED(ups))
{
SculptSession *ss = ob->sculpt;
SculptSearchSphereData data;
@@ -2983,11 +3091,7 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
radius = ss->cache->radius * 1.25f;
data.radius_squared = radius * radius;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
@@ -3018,9 +3122,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
- ss->cache->location,
- ss->cache->radius);
+ BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, mode,
+ ss->cache->location,
+ (brush->flag & BRUSH_FRONTFACE) ? ss->cache->view_normal : NULL,
+ ss->cache->radius);
}
MEM_freeN(nodes);
@@ -3028,13 +3134,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
mul_m4_v3(ob->obmat, location);
-
- add_v3_v3(ob->sculpt->average_stroke_accum, location);
- ob->sculpt->average_stroke_counter++;
}
}
-static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
+static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
SculptSearchSphereData data;
@@ -3045,11 +3148,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius_squared;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
@@ -3064,7 +3163,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
BKE_pbvh_node_mark_update(nodes[n]);
}
- if (brush_needs_sculpt_normal(brush))
+ if (sculpt_brush_needs_normal(brush))
update_sculpt_normal(sd, ob, nodes, totnode);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
@@ -3148,8 +3247,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
copy_v3_v3(location, ss->cache->true_location);
mul_m4_v3(ob->obmat, location);
- add_v3_v3(ob->sculpt->average_stroke_accum, location);
- ob->sculpt->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, location);
+ ups->average_stroke_counter++;
+ /* update last stroke position */
+ ups->last_stroke_valid = true;
}
}
@@ -3182,8 +3283,8 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
/* first line is tools that don't support proxies */
- if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER) ||
- ss->cache->supports_gravity)
+ if (ss->cache->supports_gravity ||
+ (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
{
/* these brushes start from original coordinates */
const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
@@ -3261,7 +3362,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
+ if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
@@ -3343,6 +3444,7 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
unit_m4(cache->symm_rot_mat);
unit_m4(cache->symm_rot_mat_inv);
+ zero_v3(cache->plane_offset);
if (axis) { /* expects XYZ */
rotate_m4(cache->symm_rot_mat, axis, angle);
@@ -3358,9 +3460,61 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
}
}
-typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush);
+typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
+
+static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action)
+{
+ SculptSession *ss = ob->sculpt;
+ StrokeCache *cache = ss->cache;
+ const float radius = cache->radius;
+ const float *bbMin = ob->bb->vec[0];
+ const float *bbMax = ob->bb->vec[6];
+ const float *step = sd->paint.tile_offset;
+ int dim;
+
+ /* These are integer locations, for real location: multiply with step and add orgLoc. So 0,0,0 is at orgLoc. */
+ int start[3];
+ int end[3];
+ int cur[3];
+
+ float orgLoc[3]; /* position of the "prototype" stroke for tiling */
+ copy_v3_v3(orgLoc, cache->location);
+
+ for (dim = 0; dim < 3; ++dim) {
+ if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
+ start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
+ end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
+ }
+ else
+ start[dim] = end[dim] = 0;
+ }
-static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
+ /* first do the "untiled" position to initialize the stroke for this location */
+ cache->tile_pass = 0;
+ action(sd, ob, brush, ups);
+
+ /* now do it for all the tiles */
+ copy_v3_v3_int(cur, start);
+ for (cur[0] = start[0]; cur[0] <= end[0]; ++cur[0]) {
+ for (cur[1] = start[1]; cur[1] <= end[1]; ++cur[1]) {
+ for (cur[2] = start[2]; cur[2] <= end[2]; ++cur[2]) {
+ if (!cur[0] && !cur[1] && !cur[2])
+ continue; /* skip tile at orgLoc, this was already handled before all others */
+
+ ++cache->tile_pass;
+
+ for (dim = 0; dim < 3; ++dim) {
+ cache->location[dim] = cur[dim] * step[dim] + orgLoc[dim];
+ cache->plane_offset[dim] = cur[dim] * step[dim];
+ }
+ action(sd, ob, brush, ups);
+ }
+ }
+ }
+}
+
+
+static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups,
BrushActionFunc action,
const char symm, const int axis,
const float feather)
@@ -3372,7 +3526,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
ss->cache->radial_symmetry_pass = i;
calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
- action(sd, ob, brush);
+ do_tiled(sd, ob, brush, ups, action);
}
}
@@ -3410,11 +3564,11 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
cache->radial_symmetry_pass = 0;
calc_brushdata_symm(sd, cache, i, 0, 0, feather);
- action(sd, ob, brush);
+ do_tiled(sd, ob, brush, ups, action);
- do_radial_symmetry(sd, ob, brush, action, i, 'X', feather);
- do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather);
- do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather);
+ do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather);
+ do_radial_symmetry(sd, ob, brush, ups, action, i, 'Y', feather);
+ do_radial_symmetry(sd, ob, brush, ups, action, i, 'Z', feather);
}
}
}
@@ -3522,8 +3676,6 @@ static const char *sculpt_tool_name(Sculpt *sd)
static void sculpt_cache_free(StrokeCache *cache)
{
- if (cache->face_norms)
- MEM_freeN(cache->face_norms);
if (cache->dial)
MEM_freeN(cache->dial);
MEM_freeN(cache);
@@ -3595,7 +3747,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
if (ss->multires) {
int i, gridsize, array_mem_size;
BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
- &gridsize, NULL, NULL);
+ &gridsize, NULL);
array_mem_size = cache->num_threads * sizeof(void *);
@@ -3783,21 +3935,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- if (ss->face_normals) {
- cache->face_norms = MEM_mallocN(sizeof(float) * 3 * ss->totpoly, "Sculpt face norms");
- for (i = 0; i < ss->totpoly; ++i) {
- copy_v3_v3(cache->face_norms[i], ss->face_normals[i]);
- }
- }
-
cache->original = 1;
}
- if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB,
- SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN))
- {
+ if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = 1;
}
@@ -3921,7 +4062,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
* brush coord/pressure/etc.
* It's more an events design issue, which doesn't split coordinate/pressure/angle
* changing events. We should avoid this after events system re-design */
- if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) {
+ if (paint_supports_dynamic_size(brush, ePaintSculpt) || cache->first_time) {
cache->pressure = RNA_float_get(ptr, "pressure");
}
@@ -3938,7 +4079,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
}
}
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) {
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, ePaintSculpt)) {
cache->radius = cache->initial_radius * cache->pressure;
}
else {
@@ -4006,14 +4147,14 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob)
typedef struct {
SculptSession *ss;
const float *ray_start, *ray_normal;
- int hit;
+ bool hit;
float dist;
- int original;
+ bool original;
} SculptRaycastData;
typedef struct {
const float *ray_start, *ray_normal;
- int hit;
+ bool hit;
float dist;
float detail;
} SculptDetailRaycastData;
@@ -4051,7 +4192,7 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
if (BKE_pbvh_node_get_tmin(node) < *tmin) {
SculptDetailRaycastData *srd = data_v;
if (BKE_pbvh_bmesh_node_raycast_detail(node, srd->ray_start, srd->ray_normal,
- &srd->detail, &srd->dist))
+ &srd->dist, &srd->detail))
{
srd->hit = 1;
*tmin = srd->dist;
@@ -4076,7 +4217,10 @@ static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ra
sub_v3_v3v3(ray_normal, ray_end, ray_start);
dist = normalize_v3(ray_normal);
- if (!rv3d->is_persp) {
+ if ((rv3d->is_persp == false) &&
+ /* if the ray is clipped, don't adjust its start/end */
+ ((rv3d->rflag & RV3D_CLIPPING) == 0))
+ {
BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal);
/* recalculate the normal */
@@ -4145,7 +4289,7 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession
sculpt_update_tex(scene, sd, ss);
}
-static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
+static bool sculpt_brush_stroke_init(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -4166,9 +4310,6 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
is_smooth = sculpt_any_smooth_mode(brush, NULL, mode);
BKE_sculpt_update_mesh_elements(scene, sd, ob, is_smooth, need_mask);
- zero_v3(ob->sculpt->average_stroke_accum);
- ob->sculpt->average_stroke_counter = 0;
-
return 1;
}
@@ -4290,17 +4431,20 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
sculpt_restore_mesh(sd, ob);
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
}
else {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- (ss->cache->radius /
- (float)ups->pixel_radius) *
- (float)sd->detail_size / 0.4f);
+ BKE_pbvh_bmesh_detail_size_set(
+ ss->pbvh,
+ (ss->cache->radius /
+ (float)ups->pixel_radius) *
+ (float)(sd->detail_size * U.pixelsize) / 0.4f);
}
- if (sculpt_stroke_dynamic_topology(ss, brush)) {
+ if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
@@ -4375,10 +4519,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
}
}
- /* update last stroke position */
- ob->sculpt->last_stroke_valid = 1;
- ED_sculpt_stroke_get_average(ob, ob->sculpt->last_stroke);
-
sculpt_cache_free(ss->cache);
ss->cache = NULL;
@@ -4714,8 +4854,8 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers)
{
- uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Warning!"), ICON_ERROR);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
+ uiLayout *layout = UI_popup_menu_layout(pup);
if (vdata) {
const char *msg_error = TIP_("Vertex Data Detected!");
@@ -4736,9 +4876,9 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo
uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
@@ -4760,7 +4900,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
(CustomData_has_layer(&me->vdata, i) ||
CustomData_has_layer(&me->edata, i) ||
- CustomData_has_layer(&me->fdata, i)))
+ CustomData_has_layer(&me->ldata, i)))
{
vdata = true;
break;
@@ -4771,7 +4911,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
@@ -4863,6 +5003,9 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sd->symmetrize_direction, 0.00001f);
sculpt_dynamic_topology_triangulate(ss->bm);
+ /* bisect operator flags edges (keep tags clean for edge queue) */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end();
@@ -4937,7 +5080,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Leave sculptmode */
ob->mode &= ~mode_flag;
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
paint_cursor_delete_textures();
}
@@ -4966,16 +5109,22 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
- if (!ts->sculpt->detail_size) {
+ if (!ts->sculpt->detail_size)
ts->sculpt->detail_size = 12;
- }
-
+ if (!ts->sculpt->detail_percent)
+ ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
ts->sculpt->constant_detail = 30.0f;
+ /* Set sane default tiling offsets */
+ if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f;
+ if (!ts->sculpt->paint.tile_offset[1]) ts->sculpt->paint.tile_offset[1] = 1.0f;
+ if (!ts->sculpt->paint.tile_offset[2]) ts->sculpt->paint.tile_offset[2] = 1.0f;
+
+
/* Create sculpt mode session data */
if (ob->sculpt)
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
sculpt_init_session(scene, ob);
@@ -4995,7 +5144,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
"Object has negative scale, sculpting may be unpredictable");
}
- BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
+ BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
paint_cursor_start(C, sculpt_poll_view3d);
}
@@ -5058,7 +5207,10 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
- while (BKE_pbvh_bmesh_update_topology(ss->pbvh, PBVH_Collapse | PBVH_Subdivide, bb_min, size)) {
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide,
+ bb_min, NULL, size))
+ {
for (i = 0; i < totnodes; i++)
BKE_pbvh_node_mark_topology_update(nodes[i]);
}
@@ -5188,6 +5340,50 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
}
+
+static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+
+ if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
+ else {
+ set_brush_rc_props(&props_ptr, "sculpt", "detail_size", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
+ }
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+
+ WM_operator_properties_free(&props_ptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_detail_size(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Detail Size";
+ ot->idname = "SCULPT_OT_set_detail_size";
+ ot->description = "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
+
+ /* api callbacks */
+ ot->exec = sculpt_set_detail_size_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
void ED_operatortypes_sculpt(void)
{
WM_operatortype_append(SCULPT_OT_brush_stroke);
@@ -5198,4 +5394,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_symmetrize);
WM_operatortype_append(SCULPT_OT_detail_flood_fill);
WM_operatortype_append(SCULPT_OT_sample_detail_size);
+ WM_operatortype_append(SCULPT_OT_set_detail_size);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index a61f571fdf6..8f1a4655c37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -41,14 +41,8 @@
#include "BKE_pbvh.h"
struct bContext;
-struct Brush;
struct KeyBlock;
-struct Mesh;
-struct MultiresModifierData;
struct Object;
-struct Scene;
-struct Sculpt;
-struct SculptStroke;
struct SculptUndoNode;
int sculpt_mode_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 91f80a4fc40..1f1be51b9a6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -104,7 +104,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
if (unode->maxvert) {
/* regular mesh restore */
- if (ss->kb && strcmp(ss->kb->name, unode->shapeName)) {
+ if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key = BKE_key_from_object(ob);
@@ -127,7 +127,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
if (ss->kb) {
float (*vertCos)[3];
- vertCos = BKE_key_convert_to_vertcos(ob, ss->kb);
+ vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
for (i = 0; i < unode->totvert; i++) {
if (ss->modifiers_active) {
@@ -279,7 +279,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
unode->applied = true;
}
- if (ELEM(unode->type, SCULPT_UNDO_MASK, SCULPT_UNDO_MASK)) {
+ if (unode->type == SCULPT_UNDO_MASK) {
int i, totnode;
PBVHNode **nodes;
@@ -404,7 +404,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
bool need_mask = false;
for (unode = lb->first; unode; unode = unode->next) {
- if (strcmp(unode->idname, ob->id.name) == 0) {
+ if (STREQ(unode->idname, ob->id.name)) {
if (unode->type == SCULPT_UNDO_MASK) {
/* is possible that we can't do the mask undo (below)
* because of the vertex count */
@@ -423,7 +423,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
return;
for (unode = lb->first; unode; unode = unode->next) {
- if (!(strcmp(unode->idname, ob->id.name) == 0))
+ if (!STREQ(unode->idname, ob->id.name))
continue;
/* check if undo data matches current data well enough to
@@ -484,7 +484,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
BKE_mesh_calc_normals_tessface(mesh->mvert, mesh->totvert,
mesh->mface, mesh->totface, NULL);
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
tag_update |= true;
}
@@ -550,7 +550,7 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
unode = lb->first;
- if (unode && strcmp(unode->idname, ob->id.name) != 0) {
+ if (unode && !STREQ(unode->idname, ob->id.name)) {
if (unode->bm_entry)
BM_log_cleanup_entry(unode->bm_entry);
@@ -581,7 +581,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL);
unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid,
"unode->grid_hidden");
@@ -610,7 +610,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
if (node) {
BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- &maxgrid, &gridsize, NULL, NULL);
+ &maxgrid, &gridsize, NULL);
unode->totvert = totvert;
}
@@ -695,7 +695,8 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
}
else {
MVert *mvert;
- int *vert_indices, allvert;
+ const int *vert_indices;
+ int allvert;
int i;
BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
@@ -842,11 +843,12 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
if (unode->grids) {
int totgrid, *grids;
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL);
memcpy(unode->grids, grids, sizeof(int) * totgrid);
}
else {
- int *vert_indices, allvert;
+ const int *vert_indices;
+ int allvert;
BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index d90eaafa379..405ac3f6808 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -60,7 +60,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "paint_intern.h"
#include "uvedit_intern.h"
@@ -225,8 +224,9 @@ static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(cu
}
-void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings)
+void ED_space_image_uv_sculpt_update(wmWindowManager *wm, Scene *scene)
{
+ ToolSettings *settings = scene->toolsettings;
if (settings->use_uv_sculpt) {
if (!settings->uvsculpt) {
settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint");
@@ -237,7 +237,7 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings
settings->uvsculpt->paint.flags |= PAINT_SHOW_BRUSH;
}
- BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
+ BKE_paint_init(scene, ePaintSculptUV, PAINT_CURSOR_SCULPT);
settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
brush_drawcursor_uvsculpt, NULL);
@@ -316,7 +316,7 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata,
if ((dist = dot_v2v2(diff, diff)) <= radius) {
UvElement *element;
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * (tmp_uvdata[i].p[0] - 0.5f * (tmp_uvdata[i].b[0] + tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter));
sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * (tmp_uvdata[i].p[1] - 0.5f * (tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter));
@@ -380,7 +380,7 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *scul
if ((dist = dot_v2v2(diff, diff)) <= radius) {
UvElement *element;
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * tmp_uvdata[i].p[0];
sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * tmp_uvdata[i].p[1];
@@ -455,7 +455,7 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *e
if ((dist = dot_v2v2(diff, diff)) <= radius) {
UvElement *element;
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
normalize_v2(diff);
sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
@@ -558,15 +558,15 @@ static int uv_element_offset_from_face_get(UvElementMap *map, BMFace *efa, BMLoo
static unsigned int uv_edge_hash(const void *key)
{
- UvEdge *edge = (UvEdge *)key;
+ const UvEdge *edge = key;
return (BLI_ghashutil_uinthash(edge->uv2) +
BLI_ghashutil_uinthash(edge->uv1));
}
static bool uv_edge_compare(const void *a, const void *b)
{
- UvEdge *edge1 = (UvEdge *)a;
- UvEdge *edge2 = (UvEdge *)b;
+ const UvEdge *edge1 = a;
+ const UvEdge *edge2 = b;
if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
return 0;
@@ -599,7 +599,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
UvEdge *edges;
GHash *edgeHash;
- GHashIterator *ghi;
+ GHashIterator gh_iter;
bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
int island_index = 0;
@@ -613,18 +613,18 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
/* We will need island information */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true);
+ data->elementMap = BM_uv_element_map_create(bm, false, true, true);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, true);
+ data->elementMap = BM_uv_element_map_create(bm, true, true, true);
}
}
else {
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, false);
+ data->elementMap = BM_uv_element_map_create(bm, false, true, false);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, false);
+ data->elementMap = BM_uv_element_map_create(bm, true, true, false);
}
}
@@ -755,21 +755,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
uv_sculpt_stroke_exit(C, op);
return NULL;
}
- ghi = BLI_ghashIterator_new(edgeHash);
- if (!ghi) {
- BLI_ghash_free(edgeHash, NULL, NULL);
- MEM_freeN(edges);
- uv_sculpt_stroke_exit(C, op);
- return NULL;
- }
+
/* fill the edges with data */
- for (i = 0; !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) {
- data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
+ i = 0;
+ GHASH_ITER (gh_iter, edgeHash) {
+ data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
}
data->totalUvEdges = BLI_ghash_size(edgeHash);
/* cleanup temporary stuff */
- BLI_ghashIterator_free(ghi);
BLI_ghash_free(edgeHash, NULL, NULL);
MEM_freeN(edges);
@@ -829,7 +823,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
diff[1] /= aspectRatio;
if ((dist = dot_v2v2(diff, diff)) <= radius) {
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
data->initial_stroke->initialSelection[counter].uv = i;
data->initial_stroke->initialSelection[counter].strength = strength;
diff --git a/source/blender/editors/sound/CMakeLists.txt b/source/blender/editors/sound/CMakeLists.txt
index 245ee657bc3..535cd579030 100644
--- a/source/blender/editors/sound/CMakeLists.txt
+++ b/source/blender/editors/sound/CMakeLists.txt
@@ -39,10 +39,11 @@ set(SRC
)
if(WITH_AUDASPACE)
- list(APPEND INC
- ../../../../intern/audaspace/intern
+ add_definitions(${AUDASPACE_DEFINITIONS})
+
+ list(APPEND INC_SYS
+ ${AUDASPACE_C_INCLUDE_DIRS}
)
- add_definitions(-DWITH_AUDASPACE)
endif()
if(WITH_CODEC_FFMPEG)
diff --git a/source/blender/editors/sound/SConscript b/source/blender/editors/sound/SConscript
index 33feedf51cc..fad52c64df1 100644
--- a/source/blender/editors/sound/SConscript
+++ b/source/blender/editors/sound/SConscript
@@ -31,7 +31,6 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/intern/audaspace/intern',
'../include',
'../../blenkernel',
'../../blenlib',
@@ -44,6 +43,10 @@ incs = ' '.join(incs)
defs = []
+if env['WITH_BF_AUDASPACE']:
+ defs += env['BF_AUDASPACE_DEF']
+ incs += ' ' + env['BF_AUDASPACE_C_INC']
+
if env['WITH_BF_FFMPEG']:
defs.append('WITH_FFMPEG')
diff --git a/source/blender/editors/sound/sound_intern.h b/source/blender/editors/sound/sound_intern.h
index e8a8ec55ab5..ace173abdee 100644
--- a/source/blender/editors/sound/sound_intern.h
+++ b/source/blender/editors/sound/sound_intern.h
@@ -32,7 +32,6 @@
#ifndef __SOUND_INTERN_H__
#define __SOUND_INTERN_H__
-struct wmOperatorType;
#endif /* __SOUND_INTERN_H__ */
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 619fbd7f4c8..f8d84cc0276 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -51,6 +51,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_library.h"
#include "BKE_packedFile.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
@@ -66,13 +67,12 @@
#include "WM_types.h"
#ifdef WITH_AUDASPACE
-# include "AUD_C-API.h"
+# include AUD_SPECIAL_H
#endif
#include "ED_sound.h"
#include "ED_util.h"
-#include "sound_intern.h"
/******************** open sound operator ********************/
@@ -87,7 +87,7 @@ static void sound_open_init(bContext *C, wmOperator *op)
PropertyPointerRNA *pprop;
op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
- uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
+ UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
}
#ifdef WITH_AUDASPACE
@@ -101,13 +101,14 @@ static int sound_open_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
RNA_string_get(op->ptr, "filepath", path);
- sound = sound_new_file(bmain, path);
+ sound = BKE_sound_new_file(bmain, path);
if (!op->customdata)
sound_open_init(C, op);
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
if (op->customdata) MEM_freeN(op->customdata);
+ BKE_libblock_free(bmain, sound);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
}
@@ -115,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- sound_delete(bmain, sound);
+ BKE_sound_delete(bmain, sound);
if (op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
@@ -123,11 +124,11 @@ static int sound_open_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "mono")) {
sound->flags |= SOUND_FLAGS_MONO;
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
}
if (RNA_boolean_get(op->ptr, "cache")) {
- sound_cache(sound);
+ BKE_sound_cache(sound);
}
/* hook into UI */
@@ -143,7 +144,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &pprop->ptr, pprop->prop);
}
- if (op->customdata) MEM_freeN(op->customdata);
+ MEM_freeN(op->customdata);
return OPERATOR_FINISHED;
}
@@ -184,8 +185,8 @@ static void SOUND_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
RNA_def_boolean(ot->srna, "mono", false, "Mono", "Mixdown the sound to mono");
}
@@ -206,8 +207,8 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
RNA_def_boolean(ot->srna, "mono", true, "Mono", "Mixdown the sound to mono");
}
@@ -243,7 +244,7 @@ static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)
}
SEQ_END
- fcu = id_data_find_fcurve(&scene->id, scene, &RNA_Scene, "audio_volume", 0, &driven);
+ fcu = id_data_find_fcurve(&scene->id, scene, &RNA_Scene, "audio_volume", 0, &driven);
if (fcu || driven)
scene->audio.flag |= AUDIO_VOLUME_ANIMATED;
else
@@ -400,7 +401,7 @@ static bool sound_mixdown_check(bContext *UNUSED(C), wmOperator *op)
if (item->value == container) {
const char **ext = snd_ext_sound;
while (*ext != NULL) {
- if (!strcmp(*ext + 1, item->name)) {
+ if (STREQ(*ext + 1, item->name)) {
extension = *ext;
break;
}
@@ -450,9 +451,9 @@ static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *even
static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
- return !(strcmp(prop_id, "filepath") == 0 ||
- strcmp(prop_id, "directory") == 0 ||
- strcmp(prop_id, "filename") == 0);
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename"));
}
static void sound_mixdown_draw(bContext *C, wmOperator *op)
@@ -651,8 +652,8 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
#ifdef WITH_AUDASPACE
RNA_def_int(ot->srna, "accuracy", 1024, 1, 16777216, "Accuracy", "Sample accuracy, important for animation data (the lower the value, the more accurate)", 1, 16777216);
RNA_def_enum(ot->srna, "container", container_items, AUD_CONTAINER_FLAC, "Container", "File format");
@@ -691,7 +692,7 @@ static int sound_pack_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
sound->packedfile = newPackedFile(op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id));
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt
index e0dc2709cf3..839071d1330 100644
--- a/source/blender/editors/space_action/CMakeLists.txt
+++ b/source/blender/editors/space_action/CMakeLists.txt
@@ -22,10 +22,13 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -33,6 +36,7 @@ set(INC_SYS
)
set(SRC
+ action_data.c
action_draw.c
action_edit.c
action_ops.c
@@ -42,4 +46,6 @@ set(SRC
action_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_action "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_action/SConscript b/source/blender/editors/space_action/SConscript
index 2776bd2989a..346324e129d 100644
--- a/source/blender/editors/space_action/SConscript
+++ b/source/blender/editors/space_action/SConscript
@@ -29,16 +29,22 @@ Import ('env')
sources = env.Glob('*.c')
+defs = []
+defs += env['BF_GL_DEFINITIONS']
+
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
incs = ' '.join(incs)
-env.BlenderLib ( 'bf_editors_space_action', sources, Split(incs), [], libtype=['core'], priority=[40] )
+env.BlenderLib ( 'bf_editors_space_action', sources, Split(incs), defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
new file mode 100644
index 00000000000..c3519423773
--- /dev/null
+++ b/source/blender/editors/space_action/action_data.c
@@ -0,0 +1,963 @@
+/*
+ * ***** 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) 2015 Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_action/action_data.c
+ * \ingroup spaction
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_mask_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_scene.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "UI_view2d.h"
+
+#include "ED_anim_api.h"
+#include "ED_gpencil.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+#include "ED_screen.h"
+#include "ED_markers.h"
+#include "ED_mask.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+
+#include "action_intern.h"
+
+/* ************************************************************************** */
+/* ACTION CREATION */
+
+/* Helper function to find the active AnimData block from the Action Editor context */
+AnimData *ED_actedit_animdata_from_context(bContext *C)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Object *ob = CTX_data_active_object(C);
+ AnimData *adt = NULL;
+
+ /* Get AnimData block to use */
+ if (saction->mode == SACTCONT_ACTION) {
+ /* Currently, "Action Editor" means object-level only... */
+ if (ob) {
+ adt = ob->adt;
+ }
+ }
+ else if (saction->mode == SACTCONT_SHAPEKEY) {
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ adt = key->adt;
+ }
+ }
+
+ return adt;
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Create new action */
+static bAction *action_create_new(bContext *C, bAction *oldact)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ bAction *action;
+
+ /* create action - the way to do this depends on whether we've got an
+ * existing one there already, in which case we make a copy of it
+ * (which is useful for "versioning" actions within the same file)
+ */
+ if (oldact && GS(oldact->id.name) == ID_AC) {
+ /* make a copy of the existing action */
+ action = BKE_action_copy(oldact);
+ }
+ else {
+ /* just make a new (empty) action */
+ action = add_empty_action(CTX_data_main(C), "Action");
+ }
+
+ /* when creating new ID blocks, there is already 1 user (as for all new datablocks),
+ * but the RNA pointer code will assign all the proper users instead, so we compensate
+ * for that here
+ */
+ BLI_assert(action->id.us == 1);
+ action->id.us--;
+
+ /* set ID-Root type */
+ if (sa->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+
+ if (saction->mode == SACTCONT_SHAPEKEY)
+ action->idroot = ID_KE;
+ else
+ action->idroot = ID_OB;
+ }
+
+ return action;
+}
+
+/* Change the active action used by the action editor */
+static void actedit_change_action(bContext *C, bAction *act)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers and get the property */
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ /* NOTE: act may be NULL here, so better to just use a cast here */
+ RNA_id_pointer_create((ID *)act, &idptr);
+
+ /* set the new pointer, and force a refresh */
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ RNA_property_update(C, &ptr, prop);
+}
+
+/* ******************** New Action Operator *********************** */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
+ * OR
+ * The NLA Editor is active (i.e. Animation Data panel -> new action)
+ * 2) The associated AnimData block must not be in tweakmode
+ */
+static int action_new_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* For now, actions are only for the active object, and on object and shapekey levels... */
+ if (saction->mode == SACTCONT_ACTION) {
+ /* XXX: This assumes that actions are assigned to the active object in this mode */
+ if (ob) {
+ if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return true;
+ }
+ }
+ else if (saction->mode == SACTCONT_SHAPEKEY) {
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return true;
+ }
+ }
+ }
+ else if (ED_operator_nla_active(C)) {
+ if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+ return true;
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* hook into UI */
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
+
+ if (prop) {
+ bAction *action = NULL, *oldact = NULL;
+ AnimData *adt = NULL;
+ PointerRNA oldptr;
+
+ oldptr = RNA_property_pointer_get(&ptr, prop);
+ oldact = (bAction *)oldptr.id.data;
+
+ /* stash the old action to prevent it from being lost */
+ if (ptr.type == &RNA_AnimData) {
+ adt = ptr.data;
+ }
+ else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
+ adt = ED_actedit_animdata_from_context(C);
+ }
+
+ /* Perform stashing operation - But only if there is an action */
+ if (adt && oldact) {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ /* The stash operation will remove the user already
+ * (and unlink the action from the AnimData action slot).
+ * Hence, we must unset the ref to the action in the
+ * action editor too (if this is where we're being called from)
+ * first before setting the new action once it is created,
+ * or else the user gets decremented twice!
+ */
+ if (ptr.type == &RNA_SpaceDopeSheetEditor) {
+ SpaceAction *saction = (SpaceAction *)ptr.data;
+ saction->action = NULL;
+ }
+ }
+ else {
+ //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name);
+ }
+ }
+
+ /* 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);
+ RNA_property_update(C, &ptr, prop);
+ }
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Action";
+ ot->idname = "ACTION_OT_new";
+ ot->description = "Create new action";
+
+ /* api callbacks */
+ ot->exec = action_new_exec;
+ ot->poll = action_new_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Action Push-Down Operator ******************** */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
+ * 2) There must be an action active
+ * 3) The associated AnimData block must not be in tweakmode
+ */
+static int action_pushdown_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check for AnimData, Actions, and that tweakmode is off */
+ if (adt && saction->action) {
+ /* NOTE: We check this for the AnimData block in question and not the global flag,
+ * as the global flag may be left dirty by some of the browsing ops here.
+ */
+ if (!(adt->flag & ADT_NLA_EDIT_ON))
+ return true;
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_pushdown_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Do the deed... */
+ if (adt) {
+ /* Perform the pushdown operation
+ * - This will deal with all the AnimData-side usercounts
+ */
+ if (action_has_motion(adt->action) == 0) {
+ /* action may not be suitable... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* action can be safely added */
+ BKE_nla_action_pushdown(adt);
+ }
+
+ /* Stop displaying this action in this editor
+ * NOTE: The editor itself doesn't set a user...
+ */
+ saction->action = NULL;
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_push_down(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Push Down Action";
+ ot->idname = "ACTION_OT_push_down";
+ ot->description = "Push action down on to the NLA stack as a new strip";
+
+ /* callbacks */
+ ot->exec = action_pushdown_exec;
+ ot->poll = action_pushdown_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Action Stash Operator ******************** */
+
+static int action_stash_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Perform stashing operation */
+ if (adt) {
+ /* don't do anything if this action is empty... */
+ if (action_has_motion(adt->action) == 0) {
+ /* action may not be suitable... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ /* The stash operation will remove the user already,
+ * so the flushing step later shouldn't double up
+ * the usercount fixes. Hence, we must unset this ref
+ * first before setting the new action.
+ */
+ saction->action = NULL;
+ }
+ else {
+ /* action has already been added - simply warn about this, and clear */
+ BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+ }
+
+ /* clear action refs from editor, and then also the backing data (not necessary) */
+ actedit_change_action(C, NULL);
+ }
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stash Action";
+ ot->idname = "ACTION_OT_stash";
+ ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
+
+ /* callbacks */
+ ot->exec = action_stash_exec;
+ ot->poll = action_pushdown_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action",
+ "Create a new action once the existing one has been safely stored");
+}
+
+/* ----------------- */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
+ * 2) The associated AnimData block must not be in tweakmode
+ */
+static int action_stash_create_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+ if (adt) {
+ if (!(adt->flag & ADT_NLA_EDIT_ON))
+ return true;
+ }
+ else {
+ /* There may not be any action/animdata yet, so, just fallback to the global setting
+ * (which may not be totally valid yet if the action editor was used and things are
+ * now in an inconsistent state)
+ */
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+ /* For now, actions are only for the active object, and on object and shapekey levels... */
+ return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_stash_create_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check for no action... */
+ if (saction->action == NULL) {
+ /* just create a new action */
+ bAction *action = action_create_new(C, NULL);
+ actedit_change_action(C, action);
+ }
+ else if (adt) {
+ /* Perform stashing operation */
+ if (action_has_motion(adt->action) == 0) {
+ /* don't do anything if this action is empty... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ bAction *new_action = NULL;
+
+ /* create new action not based on the old one (since the "new" operator already does that) */
+ new_action = action_create_new(C, NULL);
+
+ /* The stash operation will remove the user already,
+ * so the flushing step later shouldn't double up
+ * the usercount fixes. Hence, we must unset this ref
+ * first before setting the new action.
+ */
+ saction->action = NULL;
+ actedit_change_action(C, new_action);
+ }
+ else {
+ /* action has already been added - simply warn about this, and clear */
+ BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+ actedit_change_action(C, NULL);
+ }
+ }
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash_and_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stash Action";
+ ot->idname = "ACTION_OT_stash_and_create";
+ ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
+
+ /* callbacks */
+ ot->exec = action_stash_create_exec;
+ ot->poll = action_stash_create_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************************** */
+/* ACTION UNLINK */
+
+/* ******************* Action Unlink Operator ******************** */
+/* We use a custom unlink operator here, as there are some technicalities which need special care:
+ * 1) When in Tweak Mode, it shouldn't be possible to unlink the active action,
+ * or else, everything turns to custard.
+ * 2) If the Action doesn't have any other users, the user should at least get
+ * a warning that it is going to get lost.
+ * 3) We need a convenient way to exit Tweak Mode from the Action Editor
+ */
+
+void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* If the old action only has a single user (that it's about to lose),
+ * warn user about it
+ *
+ * TODO: Maybe we should just save it for them? But then, there's the problem of
+ * trying to get rid of stuff that's actually unwanted!
+ */
+ if (act->id.us == 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain",
+ act->id.name + 2);
+ }
+
+ /* Clear Fake User and remove action stashing strip (if present) */
+ if (force_delete) {
+ /* Remove stashed strip binding this action to this datablock */
+ /* XXX: we cannot unlink it from *OTHER* datablocks that may also be stashing it,
+ * but GE users only seem to use/care about single-object binding for now so this
+ * should be fine
+ */
+ if (adt) {
+ NlaTrack *nlt, *nlt_next;
+ NlaStrip *strip, *nstrip;
+
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt_next) {
+ nlt_next = nlt->next;
+
+ if (strstr(nlt->name, DATA_("[Action Stash]"))) {
+ for (strip = nlt->strips.first; strip; strip = nstrip) {
+ nstrip = strip->next;
+
+ if (strip->act == act) {
+ /* Remove this strip, and the track too if it doesn't have anything else */
+ free_nlastrip(&nlt->strips, strip);
+
+ if (nlt->strips.first == NULL) {
+ BLI_assert(nstrip == NULL);
+ free_nlatrack(&adt->nla_tracks, nlt);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Clear Fake User */
+ if (act->id.flag & LIB_FAKEUSER) {
+ act->id.flag &= ~LIB_FAKEUSER;
+ act->id.us--;
+ }
+ }
+
+ /* If in Tweak Mode, don't unlink. Instead, this
+ * becomes a shortcut to exit Tweak Mode instead
+ */
+ if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
+ /* Exit Tweak Mode */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Flush this to the Action Editor (if that's where this change was initiated) */
+ if (sa->spacetype == SPACE_ACTION) {
+ actedit_change_action(C, NULL);
+ }
+ }
+ else {
+ /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
+ if (sa->spacetype == SPACE_ACTION) {
+ /* clear action editor -> action */
+ actedit_change_action(C, NULL);
+ }
+ else {
+ /* clear AnimData -> action */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create AnimData RNA pointers */
+ RNA_pointer_create(id, &RNA_AnimData, adt, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ /* clear... */
+ RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL);
+ RNA_property_update(C, &ptr, prop);
+ }
+ }
+}
+
+/* -------------------------- */
+
+static int action_unlink_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Only when there's an active action, in the right modes... */
+ if (saction->action && adt)
+ return true;
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_unlink_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ bool force_delete = RNA_boolean_get(op->ptr, "force_delete");
+
+ if (adt && adt->action) {
+ ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports, force_delete);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+{
+ /* NOTE: this is hardcoded to match the behaviour for the unlink button (in interface_templates.c) */
+ RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0);
+ return action_unlink_exec(C, op);
+}
+
+void ACTION_OT_unlink(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Unlink Action";
+ ot->idname = "ACTION_OT_unlink";
+ ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
+
+ /* callbacks */
+ ot->invoke = action_unlink_invoke;
+ ot->exec = action_unlink_exec;
+ ot->poll = action_unlink_poll;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete",
+ "Clear Fake User and remove copy stashed in this datablock's NLA stack");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ************************************************************************** */
+/* ACTION BROWSING */
+
+/* Try to find NLA Strip to use for action layer up/down tool */
+static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
+{
+ NlaStrip *strip;
+
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* Can we use this? */
+ if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
+ /* in range - use this one */
+ return strip;
+ }
+ else if ((ctime < strip->start) && (strip->prev == NULL)) {
+ /* before first - use this one */
+ return strip;
+ }
+ else if ((ctime > strip->end) && (strip->next == NULL)) {
+ /* after last - use this one */
+ return strip;
+ }
+ }
+
+ /* nothing suitable found... */
+ return NULL;
+}
+
+/* Switch NLA Strips/Actions */
+static void action_layer_switch_strip(AnimData *adt,
+ NlaTrack *old_track, NlaStrip *old_strip,
+ NlaTrack *nlt, NlaStrip *strip)
+{
+ /* Exit tweakmode on old strip
+ * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ if (old_strip) {
+ old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
+ }
+ if (old_track) {
+ old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED);
+ }
+
+ /* Make this one the active one instead */
+ strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
+ nlt->flag |= NLATRACK_ACTIVE;
+
+ /* Copy over "solo" flag - This is useful for stashed actions... */
+ if (old_track) {
+ if (old_track->flag & NLATRACK_SOLO) {
+ old_track->flag &= ~NLATRACK_SOLO;
+ nlt->flag |= NLATRACK_SOLO;
+ }
+ }
+ else {
+ /* NLA muting <==> Solo Tracks */
+ if (adt->flag & ADT_NLA_EVAL_OFF) {
+ /* disable NLA muting */
+ adt->flag &= ~ADT_NLA_EVAL_OFF;
+
+ /* mark this track as being solo */
+ adt->flag |= ADT_NLA_SOLO_TRACK;
+ nlt->flag |= NLATRACK_SOLO;
+
+ // TODO: Needs restpose flushing (when we get reference track)
+ }
+ }
+
+ /* Enter tweakmode again - hopefully we're now "it" */
+ BKE_nla_tweakmode_enter(adt);
+ BLI_assert(adt->actstrip == strip);
+}
+
+/* ********************** One Layer Up Operator ************************** */
+
+static int action_layer_next_poll(bContext *C)
+{
+ /* Action Editor's action editing modes only */
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ if (adt) {
+ /* only allow if we're in tweakmode, and there's something above us... */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* We need to check if there are any tracks above the active one
+ * since the track the action comes from is not stored in AnimData
+ */
+ if (adt->nla_tracks.last) {
+ NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last;
+
+ if (nlt->flag & NLATRACK_DISABLED) {
+ /* A disabled track will either be the track itself,
+ * or one of the ones above it.
+ *
+ * If this is the top-most one, there is the possibility
+ * that there is no active action. For now, we let this
+ * case return true too, so that there is a natural way
+ * to "move to an empty layer", even though this means
+ * that we won't actually have an action.
+ */
+ // return (adt->tmpact != NULL);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_layer_next_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ NlaTrack *act_track;
+
+ Scene *scene = CTX_data_scene(C);
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* Get active track */
+ act_track = BKE_nlatrack_find_tweaked(adt);
+
+ if (act_track == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Find next action, and hook it up */
+ if (act_track->next) {
+ NlaTrack *nlt;
+
+ /* Find next action to use */
+ for (nlt = act_track->next; nlt; nlt = nlt->next) {
+ NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
+
+ if (strip) {
+ action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
+ break;
+ }
+ }
+ }
+ else {
+ /* No more actions (strips) - Go back to editing the original active action
+ * NOTE: This will mean exiting tweakmode...
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Deal with solo flags...
+ * Assume: Solo Track == NLA Muting
+ */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* turn off solo flags on tracks */
+ act_track->flag &= ~NLATRACK_SOLO;
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
+
+ /* turn on NLA muting (to keep same effect) */
+ adt->flag |= ADT_NLA_EVAL_OFF;
+
+ // TODO: Needs restpose flushing (when we get reference track)
+ }
+ }
+
+ /* Update the action that this editor now uses
+ * NOTE: The calls above have already handled the usercount/animdata side of things
+ */
+ actedit_change_action(C, adt->action);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_layer_next(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Next Layer";
+ ot->idname = "ACTION_OT_layer_next";
+ ot->description = "Switch to editing action in animation layer above the current action in the NLA Stack";
+
+ /* callbacks */
+ ot->exec = action_layer_next_exec;
+ ot->poll = action_layer_next_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************* One Layer Down Operator ************************* */
+
+static int action_layer_prev_poll(bContext *C)
+{
+ /* Action Editor's action editing modes only */
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ if (adt) {
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* Tweak Mode: We need to check if there are any tracks below the active one that we can move to */
+ if (adt->nla_tracks.first) {
+ NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first;
+
+ /* Since the first disabled track is the track being tweaked/edited,
+ * we can simplify things by only checking the first track:
+ * - If it is disabled, this is the track being tweaked,
+ * so there can't be anything below it
+ * - Otherwise, there is at least 1 track below the tweaking
+ * track that we can descend to
+ */
+ if ((nlt->flag & NLATRACK_DISABLED) == 0) {
+ /* not disabled = there are actions below the one being tweaked */
+ return true;
+ }
+ }
+ }
+ else {
+ /* Normal Mode: If there are any tracks, we can try moving to those */
+ return (adt->nla_tracks.first != NULL);
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_layer_prev_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ NlaTrack *act_track;
+ NlaTrack *nlt;
+
+ Scene *scene = CTX_data_scene(C);
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* Sanity Check */
+ if (adt == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get active track */
+ act_track = BKE_nlatrack_find_tweaked(adt);
+
+ /* If there is no active track, that means we are using the active action... */
+ if (act_track) {
+ /* Active Track - Start from the one below it */
+ nlt = act_track->prev;
+ }
+ else {
+ /* Active Action - Use the top-most track */
+ nlt = adt->nla_tracks.last;
+ }
+
+ /* Find previous action and hook it up */
+ for (; nlt; nlt = nlt->prev) {
+ NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
+
+ if (strip) {
+ action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
+ break;
+ }
+ }
+
+ /* Update the action that this editor now uses
+ * NOTE: The calls above have already handled the usercount/animdata side of things
+ */
+ actedit_change_action(C, adt->action);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_layer_prev(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Previous Layer";
+ ot->idname = "ACTION_OT_layer_prev";
+ ot->description = "Switch to editing action in animation layer below the current action in the NLA Stack";
+
+ /* callbacks */
+ ot->exec = action_layer_prev_exec;
+ ot->poll = action_layer_prev_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************************** */
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 335949e8495..10748c2fe15 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -93,6 +93,8 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -104,15 +106,16 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
+ channel_index++;
}
}
{ /* second pass: widgets */
- uiBlock *block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
y = (float)ACHANNEL_FIRST;
@@ -134,8 +137,8 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
channel_index++;
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
}
/* free tempolary channels */
@@ -210,7 +213,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int sel = 0;
/* determine if any need to draw channel */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 091d3fe56b4..e351fb57d9a 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -40,8 +40,12 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_anim_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -52,6 +56,8 @@
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_context.h"
@@ -74,72 +80,6 @@
#include "action_intern.h"
-/* ************************************************************************** */
-/* ACTION MANAGEMENT */
-
-/* ******************** New Action Operator *********************** */
-
-static int act_new_exec(bContext *C, wmOperator *UNUSED(op))
-{
- PointerRNA ptr, idptr;
- PropertyRNA *prop;
-
- /* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
-
- if (prop) {
- bAction *action = NULL, *oldact = NULL;
- PointerRNA oldptr;
-
- /* create action - the way to do this depends on whether we've got an
- * existing one there already, in which case we make a copy of it
- * (which is useful for "versioning" actions within the same file)
- */
- oldptr = RNA_property_pointer_get(&ptr, prop);
- oldact = (bAction *)oldptr.id.data;
-
- if (oldact && GS(oldact->id.name) == ID_AC) {
- /* make a copy of the existing action */
- action = BKE_action_copy(oldact);
- }
- else {
- Main *bmain = CTX_data_main(C);
-
- /* just make a new (empty) action */
- action = add_empty_action(bmain, "Action");
- }
-
- /* when creating new ID blocks, use is already 1 (fake user),
- * but RNA pointer use also increases user, so this compensates it
- */
- action->id.us--;
-
- RNA_id_pointer_create(&action->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr);
- RNA_property_update(C, &ptr, prop);
- }
-
- /* set notifier that keyframes have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_new(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "New Action";
- ot->idname = "ACTION_OT_new";
- ot->description = "Create new action";
-
- /* api callbacks */
- ot->exec = act_new_exec;
- /* NOTE: this is used in the NLA too... */
- //ot->poll = ED_operator_action_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
/* ************************************************************************** */
/* POSE MARKERS STUFF */
@@ -283,7 +223,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
float tmin, tmax;
/* get range and apply necessary scaling before processing */
- if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, true)) {
+ if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) {
if (adt) {
tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
@@ -297,7 +237,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
}
}
}
-
+
/* free memory */
ANIM_animdata_freelist(&anim_data);
}
@@ -335,8 +275,12 @@ static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
/* set the range directly */
get_keyframe_extents(&ac, &min, &max, false);
scene->r.flag |= SCER_PRV_RANGE;
- scene->r.psfra = iroundf(min);
- scene->r.pefra = iroundf(max);
+ scene->r.psfra = floorf(min);
+ scene->r.pefra = ceilf(max);
+
+ if (scene->r.psfra == scene->r.pefra) {
+ scene->r.pefra = scene->r.psfra + 1;
+ }
/* set notifier that things have changed */
// XXX err... there's nothing for frame ranges yet, but this should do fine too
@@ -386,7 +330,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* must be selected... */
if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
@@ -485,7 +429,15 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
/* only selected */
return actkeys_viewall(C, true);
}
-
+
+static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
void ACTION_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
@@ -516,6 +468,21 @@ void ACTION_OT_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+void ACTION_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "ACTION_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = actkeys_view_frame_exec;
+ ot->poll = ED_operator_action_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ************************************************************************** */
/* GENERAL STUFF */
@@ -545,7 +512,7 @@ static short copy_action_keys(bAnimContext *ac)
static short paste_action_keys(bAnimContext *ac,
- const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
+ const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
{
ListBase anim_data = {NULL, NULL};
int filter, ok = 0;
@@ -562,7 +529,7 @@ static short paste_action_keys(bAnimContext *ac,
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* paste keyframes */
- ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode);
+ ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
/* clean up */
ANIM_animdata_freelist(&anim_data);
@@ -622,6 +589,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
+ const bool flipped = RNA_boolean_get(op->ptr, "flipped");
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -638,7 +606,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
}
else {
/* non-zero return means an error occurred while trying to paste */
- if (paste_action_keys(&ac, offset_mode, merge_mode)) {
+ if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) {
return OPERATOR_CANCELLED;
}
}
@@ -651,6 +619,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
void ACTION_OT_paste(wmOperatorType *ot)
{
+ PropertyRNA *prop;
/* identifiers */
ot->name = "Paste Keyframes";
ot->idname = "ACTION_OT_paste";
@@ -667,6 +636,8 @@ void ACTION_OT_paste(wmOperatorType *ot)
/* props */
RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
+ prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************** Insert Keyframes Operator ************************* */
@@ -712,8 +683,13 @@ static void insert_action_keys(bAnimContext *ac, short mode)
else
cfra = (float)CFRA;
- /* if there's an id */
- if (ale->id)
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner)
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
@@ -786,7 +762,7 @@ static void duplicate_action_keys(bAnimContext *ac)
/* loop through filtered data and delete selected keys */
for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
duplicate_fcurve_keys((FCurve *)ale->key_data);
else if (ale->type == ANIMTYPE_GPLAYER)
ED_gplayer_frames_duplicate((bGPDlayer *)ale->data);
@@ -820,13 +796,6 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-
-static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- actkeys_duplicate_exec(C, op);
-
- return OPERATOR_FINISHED;
-}
void ACTION_OT_duplicate(wmOperatorType *ot)
{
@@ -836,7 +805,6 @@ void ACTION_OT_duplicate(wmOperatorType *ot)
ot->description = "Make a copy of all selected keyframes";
/* api callbacks */
- ot->invoke = actkeys_duplicate_invoke;
ot->exec = actkeys_duplicate_exec;
ot->poll = ED_operator_action_active;
@@ -934,7 +902,7 @@ void ACTION_OT_delete(wmOperatorType *ot)
/* ******************** Clean Keyframes Operator ************************* */
-static void clean_action_keys(bAnimContext *ac, float thresh)
+static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -946,7 +914,7 @@ static void clean_action_keys(bAnimContext *ac, float thresh)
/* loop through filtered data and clean curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- clean_fcurve((FCurve *)ale->key_data, thresh);
+ clean_fcurve(ac, ale, thresh, clean_chan);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -961,18 +929,23 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
float thresh;
+ bool clean_chan;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented");
return OPERATOR_PASS_THROUGH;
+ }
/* get cleaning threshold */
thresh = RNA_float_get(op->ptr, "threshold");
+ clean_chan = RNA_boolean_get(op->ptr, "channels");
/* clean keyframes */
- clean_action_keys(&ac, thresh);
+ clean_action_keys(&ac, thresh, clean_chan);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -997,6 +970,7 @@ void ACTION_OT_clean(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
+ RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
}
/* ******************** Sample Keyframes Operator *********************** */
@@ -1025,15 +999,18 @@ static void sample_action_keys(bAnimContext *ac)
/* ------------------- */
-static int actkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
+static int actkeys_sample_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented");
return OPERATOR_PASS_THROUGH;
+ }
/* sample keyframes */
sample_action_keys(&ac);
@@ -1138,8 +1115,11 @@ static int actkeys_expo_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented");
return OPERATOR_PASS_THROUGH;
+ }
/* get handle setting mode */
mode = RNA_enum_get(op->ptr, "type");
@@ -1209,8 +1189,11 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented");
return OPERATOR_PASS_THROUGH;
+ }
/* get handle setting mode */
mode = RNA_enum_get(op->ptr, "type");
@@ -1288,8 +1271,11 @@ static int actkeys_handletype_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented");
return OPERATOR_PASS_THROUGH;
+ }
/* get handle setting mode */
mode = RNA_enum_get(op->ptr, "type");
@@ -1324,7 +1310,7 @@ void ACTION_OT_handle_type(wmOperatorType *ot)
/* ******************** Set Keyframe-Type Operator *********************** */
-/* this function is responsible for setting interpolation mode for keyframes */
+/* this function is responsible for setting keyframe type for keyframes */
static void setkeytype_action_keys(bAnimContext *ac, short mode)
{
ListBase anim_data = {NULL, NULL};
@@ -1349,6 +1335,29 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
ANIM_animdata_freelist(&anim_data);
}
+/* this function is responsible for setting the keyframe type for Grease Pencil frames */
+static void setkeytype_gpencil_keys(bAnimContext *ac, short mode)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* loop through each layer */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ ED_gplayer_frames_keytype_set(ale->data, mode);
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
/* ------------------- */
static int actkeys_keytype_exec(bContext *C, wmOperator *op)
@@ -1359,14 +1368,22 @@ static int actkeys_keytype_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ac.datatype == ANIMCONT_MASK) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks");
return OPERATOR_PASS_THROUGH;
+ }
/* get handle setting mode */
mode = RNA_enum_get(op->ptr, "type");
/* set handle type */
- setkeytype_action_keys(&ac, mode);
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ setkeytype_gpencil_keys(&ac, mode);
+ }
+ else {
+ setkeytype_action_keys(&ac, mode);
+ }
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 8f39a38157a..17f1f404225 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -35,10 +35,7 @@ struct bContext;
struct bAnimContext;
struct SpaceAction;
struct ARegion;
-struct wmWindowManager;
struct wmOperatorType;
-struct ActKeysInc;
-struct bAnimListElem;
/* internal exports only */
@@ -80,6 +77,7 @@ enum eActKeys_ColumnSelect_Mode {
void ACTION_OT_previewrange_set(struct wmOperatorType *ot);
void ACTION_OT_view_all(struct wmOperatorType *ot);
void ACTION_OT_view_selected(struct wmOperatorType *ot);
+void ACTION_OT_view_frame(struct wmOperatorType *ot);
void ACTION_OT_copy(struct wmOperatorType *ot);
void ACTION_OT_paste(struct wmOperatorType *ot);
@@ -101,6 +99,14 @@ void ACTION_OT_snap(struct wmOperatorType *ot);
void ACTION_OT_mirror(struct wmOperatorType *ot);
void ACTION_OT_new(struct wmOperatorType *ot);
+void ACTION_OT_unlink(struct wmOperatorType *ot);
+
+void ACTION_OT_push_down(struct wmOperatorType *ot);
+void ACTION_OT_stash(struct wmOperatorType *ot);
+void ACTION_OT_stash_and_create(struct wmOperatorType *ot);
+
+void ACTION_OT_layer_next(struct wmOperatorType *ot);
+void ACTION_OT_layer_prev(struct wmOperatorType *ot);
void ACTION_OT_markers_make_local(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index b99419dec20..59b147c6f6c 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -35,7 +35,6 @@
#include "DNA_space_types.h"
-#include "BLI_utildefines.h"
#include "ED_anim_api.h"
#include "ED_markers.h"
@@ -44,7 +43,6 @@
#include "action_intern.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -79,12 +77,22 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_keyframe_insert);
WM_operatortype_append(ACTION_OT_copy);
WM_operatortype_append(ACTION_OT_paste);
+
WM_operatortype_append(ACTION_OT_new);
+ WM_operatortype_append(ACTION_OT_unlink);
+
+ WM_operatortype_append(ACTION_OT_push_down);
+ WM_operatortype_append(ACTION_OT_stash);
+ WM_operatortype_append(ACTION_OT_stash_and_create);
+
+ WM_operatortype_append(ACTION_OT_layer_next);
+ WM_operatortype_append(ACTION_OT_layer_prev);
WM_operatortype_append(ACTION_OT_previewrange_set);
WM_operatortype_append(ACTION_OT_view_all);
WM_operatortype_append(ACTION_OT_view_selected);
-
+ WM_operatortype_append(ACTION_OT_view_frame);
+
WM_operatortype_append(ACTION_OT_markers_make_local);
}
@@ -99,6 +107,7 @@ void ED_operatormacros_action(void)
WM_operatortype_macro_define(ot, "ACTION_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform");
RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE);
+ RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
}
/* ************************** registration - keymaps **********************************/
@@ -195,11 +204,10 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0);
/* destructive */
- WM_keymap_add_item(keymap, "ACTION_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
@@ -207,9 +215,13 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* copy/paste */
WM_keymap_add_item(keymap, "ACTION_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "flipped", true);
#ifdef __APPLE__
WM_keymap_add_item(keymap, "ACTION_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "flipped", true);
#endif
/* auto-set range */
@@ -217,6 +229,8 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ACTION_OT_view_frame", PAD0, KM_PRESS, 0, 0);
+
/* animation module */
/* channels list
@@ -230,6 +244,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_ACTION);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_action");
+
/* special markers hotkeys for anim editors: see note in definition of this function */
ED_marker_keymap_animedit_conflictfree(keymap);
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index ddfca98a119..3c9c88a0ae6 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -632,7 +632,7 @@ void ACTION_OT_select_linked(wmOperatorType *ot)
ot->poll = ED_operator_action_active;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Select More/Less Operators *********************** */
@@ -709,7 +709,7 @@ void ACTION_OT_select_more(wmOperatorType *ot)
ot->poll = ED_operator_action_active;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ----------------- */
@@ -743,7 +743,7 @@ void ACTION_OT_select_less(wmOperatorType *ot)
ot->poll = ED_operator_action_active;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Select Left/Right Operator ************************* */
@@ -1221,11 +1221,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
agrp->flag |= AGRP_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
}
- else if (ale->type == ANIMTYPE_FCURVE) {
+ else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = ale->data;
fcu->flag |= FCURVE_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
}
}
}
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 7ca8968a705..5d0b34a2e0c 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -197,8 +197,8 @@ static void action_main_area_draw(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
- flag = (ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0;
- draw_markers_time(C, flag);
+ flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) | DRAW_MARKERS_MARGIN;
+ ED_markers_draw(C, flag);
/* preview range */
UI_view2d_view_ortho(v2d);
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index c8431d58bf5..01f0d1ae54f 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -32,7 +32,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
@@ -61,7 +60,6 @@
#include "ED_space_api.h"
#include "ED_sound.h"
#include "ED_uvedit.h"
-#include "ED_view3d.h"
#include "ED_mball.h"
#include "ED_logic.h"
#include "ED_clip.h"
@@ -122,7 +120,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_io();
ED_operatortypes_view2d();
- UI_buttons_operatortypes();
+ ED_button_operatortypes();
/* register operators */
spacetypes = BKE_spacetypes_list();
@@ -155,6 +153,7 @@ void ED_spacemacros_init(void)
ED_operatormacros_mask();
ED_operatormacros_sequencer();
ED_operatormacros_paint();
+ ED_operatormacros_gpencil();
/* register dropboxes (can use macros) */
spacetypes = BKE_spacetypes_list();
@@ -318,7 +317,3 @@ void ED_spacetype_xxx(void)
}
/* ****************************** end template *********************** */
-
-
-
-
diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt
index 9e045a39a0c..397d79e1dbe 100644
--- a/source/blender/editors/space_buttons/CMakeLists.txt
+++ b/source/blender/editors/space_buttons/CMakeLists.txt
@@ -20,13 +20,15 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -46,6 +48,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
index 61f9b6f496e..c39df449647 100644
--- a/source/blender/editors/space_buttons/SConscript
+++ b/source/blender/editors/space_buttons/SConscript
@@ -31,12 +31,14 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -44,7 +46,9 @@ incs = [
'../../windowmanager',
]
incs = ' '.join(incs)
+
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 524a42ba388..42e2d6b90f0 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -36,7 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_armature_types.h"
#include "DNA_lamp_types.h"
@@ -59,6 +59,7 @@
#include "RNA_access.h"
+#include "ED_buttons.h"
#include "ED_armature.h"
#include "ED_screen.h"
#include "ED_physics.h"
@@ -1103,11 +1104,11 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
block = uiLayoutGetBlock(row);
- uiBlockSetEmboss(block, UI_EMBOSSN);
- but = uiDefIconButBitC(block, ICONTOG, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ but = uiDefIconButBitC(block, UI_BTYPE_ICON_TOGGLE, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
0, 0, 0, 0, TIP_("Follow context or keep fixed datablock displayed"));
- uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
- uiButSetFunc(but, pin_cb, NULL, NULL);
+ UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
+ UI_but_func_set(but, pin_cb, NULL, NULL);
for (a = 0; a < path->len; a++) {
ptr = &path->ptr[a];
@@ -1146,7 +1147,7 @@ void buttons_context_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
strcpy(pt->idname, "BUTTONS_PT_context");
strcpy(pt->label, N_("Context")); /* XXX C panels are not available through RNA (bpy.types)! */
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = buttons_panel_context;
pt->flag = PNL_NO_HEADER;
BLI_addtail(&art->paneltypes, pt);
@@ -1179,3 +1180,33 @@ ID *buttons_context_id_path(const bContext *C)
return NULL;
}
+
+void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id)
+{
+ if (sbuts->pinid == id) {
+ sbuts->pinid = NULL;
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+
+ if (sbuts->path) {
+ ButsContextPath *path = sbuts->path;
+ int i;
+
+ for (i = 0; i < path->len; i++) {
+ if (path->ptr[i].id.data == id) {
+ break;
+ }
+ }
+
+ if (i == path->len) {
+ /* pass */
+ }
+ else if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+}
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index f294729ae97..7fc35a6b1e7 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -34,7 +34,6 @@
#include "DNA_listBase.h"
#include "RNA_types.h"
-struct ARegion;
struct ARegionType;
struct ID;
struct SpaceButs;
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index b651d684bf6..b8b56f8f848 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -40,7 +40,7 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -72,12 +72,12 @@ static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UN
RNA_pointer_create(&sc->id, &RNA_SpaceProperties, sbuts, &ptr);
- pup = uiPupMenuBegin(C, IFACE_("Align"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Align"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemsEnumR(layout, &ptr, "align");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
void BUTTONS_OT_toolbox(wmOperatorType *ot)
@@ -97,6 +97,7 @@ void BUTTONS_OT_toolbox(wmOperatorType *ot)
typedef struct FileBrowseOp {
PointerRNA ptr;
PropertyRNA *prop;
+ bool is_undo;
} FileBrowseOp;
static int file_browse_exec(bContext *C, wmOperator *op)
@@ -142,6 +143,10 @@ static int file_browse_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &fbo->ptr, fbo->prop);
MEM_freeN(str);
+ if (fbo->is_undo) {
+ const char *undostr = RNA_property_identifier(fbo->prop);
+ ED_undo_push(C, undostr);
+ }
/* special, annoying exception, filesel on redo panel [#26618] */
{
@@ -168,6 +173,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PointerRNA ptr;
PropertyRNA *prop;
+ bool is_undo;
FileBrowseOp *fbo;
char *str;
@@ -176,7 +182,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- uiFileBrowseContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_filebrowser(C, &ptr, &prop, &is_undo);
if (!prop)
return OPERATOR_CANCELLED;
@@ -186,6 +192,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* useful yet irritating feature, Shift+Click to open the file
* Alt+Click to browse a folder in the OS's browser */
if (event->shift || event->alt) {
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
PointerRNA props_ptr;
if (event->alt) {
@@ -195,19 +202,21 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
- WM_operator_properties_create(&props_ptr, "WM_OT_path_open");
+ WM_operator_properties_create_ptr(&props_ptr, ot);
RNA_string_set(&props_ptr, "filepath", str);
- WM_operator_name_call(C, "WM_OT_path_open", WM_OP_EXEC_DEFAULT, &props_ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
MEM_freeN(str);
return OPERATOR_CANCELLED;
}
else {
+ PropertyRNA *prop_relpath;
const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath";
fbo = MEM_callocN(sizeof(FileBrowseOp), "FileBrowseOp");
fbo->ptr = ptr;
fbo->prop = prop;
+ fbo->is_undo = is_undo;
op->customdata = fbo;
RNA_string_set(op->ptr, path_prop, str);
@@ -215,10 +224,10 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* normally ED_fileselect_get_params would handle this but we need to because of stupid
* user-prefs exception - campbell */
- if (RNA_struct_find_property(op->ptr, "relative_path")) {
- if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
+ if ((prop_relpath = RNA_struct_find_property(op->ptr, "relative_path"))) {
+ if (!RNA_property_is_set(op->ptr, prop_relpath)) {
/* annoying exception!, if were dealing with the user prefs, default relative to be off */
- RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS && (ptr.data != &U));
+ RNA_property_boolean_set(op->ptr, prop_relpath, U.flag & USER_RELPATHS && (ptr.data != &U));
}
}
WM_event_add_fileselect(C, op);
@@ -239,11 +248,12 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
- ot->flag |= OPTYPE_UNDO;
+ /* conditional undo based on button flag */
+ ot->flag = 0;
/* properties */
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/* second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY */
@@ -259,9 +269,10 @@ void BUTTONS_OT_directory_browse(wmOperatorType *ot)
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
- ot->flag |= OPTYPE_UNDO;
+ /* conditional undo based on button flag */
+ ot->flag = 0;
/* properties */
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 020d477fc39..b56ff850c35 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -37,7 +37,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_brush_types.h"
#include "DNA_ID.h"
@@ -61,7 +61,9 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_freestyle.h"
+#ifdef WITH_FREESTYLE
+# include "BKE_freestyle.h"
+#endif
#include "RNA_access.h"
@@ -256,7 +258,7 @@ static void buttons_texture_user_property_add(ListBase *users, ID *id,
user->category = category;
user->icon = icon;
user->name = name;
- user->index = BLI_countlist(users);
+ user->index = BLI_listbase_count(users);
BLI_addtail(users, user);
}
@@ -273,7 +275,7 @@ static void buttons_texture_user_node_add(ListBase *users, ID *id,
user->category = category;
user->icon = icon;
user->name = name;
- user->index = BLI_countlist(users);
+ user->index = BLI_listbase_count(users);
BLI_addtail(users, user);
}
@@ -468,7 +470,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
}
else {
/* set one user as active based on active index */
- if (ct->index >= BLI_countlist(&ct->users))
+ if (ct->index == BLI_listbase_count_ex(&ct->users, ct->index + 1))
ct->index = 0;
ct->user = BLI_findlink(&ct->users, ct->index);
@@ -557,7 +559,7 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
char name[UI_MAX_NAME_STR];
/* add label per category */
- if (!last_category || strcmp(last_category, user->category) != 0) {
+ if (!last_category || !STREQ(last_category, user->category)) {
uiItemL(layout, user->category, ICON_NONE);
but = block->buttons.last;
but->drawflag = UI_BUT_TEXT_LEFT;
@@ -576,9 +578,9 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
else
BLI_snprintf(name, UI_MAX_NAME_STR, " %s", user->name);
- but = uiDefIconTextBut(block, BUT, 0, user->icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, user->icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, "");
- uiButSetNFunc(but, template_texture_select, MEM_dupallocN(user), NULL);
+ UI_but_funcN_set(but, template_texture_select, MEM_dupallocN(user), NULL);
last_category = user->category;
}
@@ -620,9 +622,9 @@ void uiTemplateTextureUser(uiLayout *layout, bContext *C)
}
/* some cosmetic tweaks */
- uiButSetMenuFromPulldown(but);
+ UI_but_type_set_menu_from_pulldown(but);
- but->flag &= ~UI_ICON_SUBMENU;
+ but->flag &= ~UI_BUT_ICON_SUBMENU;
}
/************************* Texture Show **************************/
@@ -675,9 +677,9 @@ void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, Prope
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
- but = uiDefIconBut(block, BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, "Show texture in texture tab");
- uiButSetFunc(but, template_texture_show, user->ptr.data, user->prop);
+ UI_but_func_set(but, template_texture_show, user->ptr.data, user->prop);
}
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 4d62f528915..e28ad686d2a 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -28,7 +28,6 @@
* \ingroup spbuttons
*/
-
#include <string.h>
#include <stdio.h>
@@ -46,10 +45,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "UI_resources.h"
-#include "UI_view2d.h"
-
-
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
@@ -142,38 +137,38 @@ static void buttons_main_area_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceButs *sbuts = CTX_wm_space_buts(C);
- int vertical = (sbuts->align == BUT_VERTICAL);
+ const bool vertical = (sbuts->align == BUT_VERTICAL);
buttons_context_compute(C, sbuts);
if (sbuts->mainb == BCONTEXT_SCENE)
- ED_region_panels(C, ar, vertical, "scene", sbuts->mainb);
+ ED_region_panels(C, ar, "scene", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_RENDER)
- ED_region_panels(C, ar, vertical, "render", sbuts->mainb);
+ ED_region_panels(C, ar, "render", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_RENDER_LAYER)
- ED_region_panels(C, ar, vertical, "render_layer", sbuts->mainb);
+ ED_region_panels(C, ar, "render_layer", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_WORLD)
- ED_region_panels(C, ar, vertical, "world", sbuts->mainb);
+ ED_region_panels(C, ar, "world", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_OBJECT)
- ED_region_panels(C, ar, vertical, "object", sbuts->mainb);
+ ED_region_panels(C, ar, "object", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_DATA)
- ED_region_panels(C, ar, vertical, "data", sbuts->mainb);
+ ED_region_panels(C, ar, "data", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_MATERIAL)
- ED_region_panels(C, ar, vertical, "material", sbuts->mainb);
+ ED_region_panels(C, ar, "material", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_TEXTURE)
- ED_region_panels(C, ar, vertical, "texture", sbuts->mainb);
+ ED_region_panels(C, ar, "texture", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_PARTICLE)
- ED_region_panels(C, ar, vertical, "particle", sbuts->mainb);
+ ED_region_panels(C, ar, "particle", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_PHYSICS)
- ED_region_panels(C, ar, vertical, "physics", sbuts->mainb);
+ ED_region_panels(C, ar, "physics", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_BONE)
- ED_region_panels(C, ar, vertical, "bone", sbuts->mainb);
+ ED_region_panels(C, ar, "bone", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_MODIFIER)
- ED_region_panels(C, ar, vertical, "modifier", sbuts->mainb);
+ ED_region_panels(C, ar, "modifier", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_CONSTRAINT)
- ED_region_panels(C, ar, vertical, "constraint", sbuts->mainb);
+ ED_region_panels(C, ar, "constraint", sbuts->mainb, vertical);
else if (sbuts->mainb == BCONTEXT_BONE_CONSTRAINT)
- ED_region_panels(C, ar, vertical, "bone_constraint", sbuts->mainb);
+ ED_region_panels(C, ar, "bone_constraint", sbuts->mainb, vertical);
sbuts->re_align = 0;
sbuts->mainbo = sbuts->mainb;
@@ -376,9 +371,11 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
}
break;
/* Listener for preview render, when doing an global undo. */
- case NC_WINDOW:
- ED_area_tag_redraw(sa);
- sbuts->preview = 1;
+ case NC_WM:
+ if (wmn->data == ND_UNDO) {
+ ED_area_tag_redraw(sa);
+ sbuts->preview = 1;
+ }
break;
#ifdef WITH_FREESTYLE
case NC_LINESTYLE:
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index 7689aa28169..d17d1856502 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -23,15 +23,17 @@
set(INC
../include
- ../../blenkernel
../../blenfont
+ ../../blenkernel
../../blenlib
+ ../../blentranslation
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
- ../../gpu
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -56,6 +58,8 @@ set(SRC
clip_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/space_clip/SConscript b/source/blender/editors/space_clip/SConscript
index d4483eda6e3..37b83946e93 100644
--- a/source/blender/editors/space_clip/SConscript
+++ b/source/blender/editors/space_clip/SConscript
@@ -28,14 +28,19 @@
Import ('env')
sources = env.Glob('*.c')
+
defs = []
+defs += env['BF_GL_DEFINITIONS']
+
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../gpu',
'../../imbuf',
'../../makesdna',
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index 889613b5d13..0378c68d12c 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -44,7 +44,7 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -69,26 +69,9 @@
/* Panels */
-static int clip_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt))
+void ED_clip_buttons_register(ARegionType *UNUSED(art))
{
- SpaceClip *sc = CTX_wm_space_clip(C);
- return sc->view == SC_VIEW_CLIP;
-}
-
-void ED_clip_buttons_register(ARegionType *art)
-{
- PanelType *pt;
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel gpencil");
- strcpy(pt->idname, "CLIP_PT_gpencil");
- strcpy(pt->label, N_("Grease Pencil"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = ED_gpencil_panel_standard_header;
- pt->draw = ED_gpencil_panel_standard;
- pt->flag |= PNL_DEFAULT_CLOSED;
- pt->poll = clip_grease_pencil_panel_poll;
- BLI_addtail(&art->paneltypes, pt);
}
/********************* MovieClip Template ************************/
@@ -130,7 +113,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
row = uiLayoutRow(layout, false);
block = uiLayoutGetBlock(row);
- uiDefBut(block, LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
row = uiLayoutRow(layout, false);
split = uiLayoutSplit(row, 0.0f, false);
@@ -183,10 +166,10 @@ void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname)
col = uiLayoutColumn(layout, true);
block = uiLayoutGetBlock(col);
- uiDefBut(block, TRACKPREVIEW, 0, "", 0, 0, UI_UNIT_X * 10, scopes->track_preview_height, scopes, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_TRACK_PREVIEW, 0, "", 0, 0, UI_UNIT_X * 10, scopes->track_preview_height, scopes, 0, 0, 0, 0, "");
/* Resize grip. */
- uiDefIconButI(block, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.8f),
+ uiDefIconButI(block, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.8f),
&scopes->track_preview_height, UI_UNIT_Y, UI_UNIT_Y * 20.0f, 0.0f, 0.0f, "");
}
@@ -403,9 +386,9 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, P
else
tip = TIP_("Marker is enabled at current frame");
- bt = uiDefIconButBitI(block, TOGN, MARKER_DISABLED, 0, ICON_RESTRICT_VIEW_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE_N, MARKER_DISABLED, 0, ICON_RESTRICT_VIEW_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y,
&cb->marker_flag, 0, 0, 1, 0, tip);
- uiButSetNFunc(bt, marker_update_cb, cb, NULL);
+ UI_but_funcN_set(bt, marker_update_cb, cb, NULL);
}
else {
int width, height, step, digits;
@@ -417,7 +400,7 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, P
if (track->flag & TRACK_LOCKED) {
uiLayoutSetActive(layout, false);
block = uiLayoutAbsoluteBlock(layout);
- uiDefBut(block, LABEL, 0, IFACE_("Track is locked"), 0, 0, UI_UNIT_X * 15.0f, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Track is locked"), 0, 0, UI_UNIT_X * 15.0f, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
return;
}
@@ -442,53 +425,53 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, P
cb->marker_flag = marker->flag;
block = uiLayoutAbsoluteBlock(layout);
- uiBlockSetHandleFunc(block, marker_block_handler, cb);
- uiBlockSetNFunc(block, marker_update_cb, cb, NULL);
+ UI_block_func_handle_set(block, marker_block_handler, cb);
+ UI_block_funcN_set(block, marker_update_cb, cb, NULL);
if (cb->marker_flag & MARKER_DISABLED)
tip = TIP_("Marker is disabled at current frame");
else
tip = TIP_("Marker is enabled at current frame");
- uiDefButBitI(block, OPTIONN, MARKER_DISABLED, B_MARKER_FLAG, IFACE_("Enabled"), 0.5 * UI_UNIT_X, 9.5 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y,
+ uiDefButBitI(block, UI_BTYPE_CHECKBOX_N, MARKER_DISABLED, B_MARKER_FLAG, IFACE_("Enabled"), 0.5 * UI_UNIT_X, 9.5 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y,
&cb->marker_flag, 0, 0, 0, 0, tip);
col = uiLayoutColumn(layout, true);
uiLayoutSetActive(col, (cb->marker_flag & MARKER_DISABLED) == 0);
block = uiLayoutAbsoluteBlock(col);
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
- uiDefBut(block, LABEL, 0, IFACE_("Position:"), 0, 10 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiDefButF(block, NUM, B_MARKER_POS, IFACE_("X:"), 0.5 * UI_UNIT_X, 9 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pos[0],
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Position:"), 0, 10 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_POS, IFACE_("X:"), 0.5 * UI_UNIT_X, 9 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pos[0],
-10 * width, 10.0 * width, step, digits, TIP_("X-position of marker at frame in screen coordinates"));
- uiDefButF(block, NUM, B_MARKER_POS, IFACE_("Y:"), 8.25 * UI_UNIT_X, 9 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pos[1],
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_POS, IFACE_("Y:"), 8.25 * UI_UNIT_X, 9 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pos[1],
-10 * height, 10.0 * height, step, digits,
TIP_("Y-position of marker at frame in screen coordinates"));
- uiDefBut(block, LABEL, 0, IFACE_("Offset:"), 0, 8 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiDefButF(block, NUM, B_MARKER_OFFSET, IFACE_("X:"), 0.5 * UI_UNIT_X, 7 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->track_offset[0],
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Offset:"), 0, 8 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_OFFSET, IFACE_("X:"), 0.5 * UI_UNIT_X, 7 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->track_offset[0],
-10 * width, 10.0 * width, step, digits, TIP_("X-offset to parenting point"));
- uiDefButF(block, NUM, B_MARKER_OFFSET, IFACE_("Y:"), 8.25 * UI_UNIT_X, 7 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->track_offset[1],
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_OFFSET, IFACE_("Y:"), 8.25 * UI_UNIT_X, 7 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->track_offset[1],
-10 * height, 10.0 * height, step, digits, TIP_("Y-offset to parenting point"));
- uiDefBut(block, LABEL, 0, IFACE_("Pattern Area:"), 0, 6 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiDefButF(block, NUM, B_MARKER_PAT_DIM, IFACE_("Width:"), 0.5 * UI_UNIT_X, 5 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pat[0], 3.0f,
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Pattern Area:"), 0, 6 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_PAT_DIM, IFACE_("Width:"), 0.5 * UI_UNIT_X, 5 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pat[0], 3.0f,
10.0 * width, step, digits, TIP_("Width of marker's pattern in screen coordinates"));
- uiDefButF(block, NUM, B_MARKER_PAT_DIM, IFACE_("Height:"), 0.5 * UI_UNIT_X, 4 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pat[1], 3.0f,
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_PAT_DIM, IFACE_("Height:"), 0.5 * UI_UNIT_X, 4 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_pat[1], 3.0f,
10.0 * height, step, digits, TIP_("Height of marker's pattern in screen coordinates"));
- uiDefBut(block, LABEL, 0, IFACE_("Search Area:"), 0, 3 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiDefButF(block, NUM, B_MARKER_SEARCH_POS, IFACE_("X:"), 0.5 * UI_UNIT_X, 2 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search_pos[0],
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Search Area:"), 0, 3 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_SEARCH_POS, IFACE_("X:"), 0.5 * UI_UNIT_X, 2 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search_pos[0],
-width, width, step, digits, TIP_("X-position of search at frame relative to marker's position"));
- uiDefButF(block, NUM, B_MARKER_SEARCH_POS, IFACE_("Y:"), 8.25 * UI_UNIT_X, 2 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search_pos[1],
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_SEARCH_POS, IFACE_("Y:"), 8.25 * UI_UNIT_X, 2 * UI_UNIT_Y, 7.25 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search_pos[1],
-height, height, step, digits, TIP_("Y-position of search at frame relative to marker's position"));
- uiDefButF(block, NUM, B_MARKER_SEARCH_DIM, IFACE_("Width:"), 0.5 * UI_UNIT_X, 1 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search[0], 3.0f,
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_SEARCH_DIM, IFACE_("Width:"), 0.5 * UI_UNIT_X, 1 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search[0], 3.0f,
10.0 * width, step, digits, TIP_("Width of marker's search in screen coordinates"));
- uiDefButF(block, NUM, B_MARKER_SEARCH_DIM, IFACE_("Height:"), 0.5 * UI_UNIT_X, 0 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search[1], 3.0f,
+ uiDefButF(block, UI_BTYPE_NUM, B_MARKER_SEARCH_DIM, IFACE_("Height:"), 0.5 * UI_UNIT_X, 0 * UI_UNIT_Y, 15 * UI_UNIT_X, UI_UNIT_Y, &cb->marker_search[1], 3.0f,
10.0 * height, step, digits, TIP_("Height of marker's search in screen coordinates"));
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
}
@@ -557,7 +540,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout, PointerRNA *ptr, const cha
uiItemL(col, str, ICON_NONE);
/* Display current frame number. */
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr) ;
+ framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
if (framenr <= clip->len)
BLI_snprintf(str, sizeof(str), IFACE_("Frame: %d / %d"), framenr, clip->len);
else
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index 2a457bf503f..4bf4c1e7baa 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -30,7 +30,6 @@
*/
#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
@@ -283,7 +282,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
MovieTracking *tracking;
MovieTrackingDopesheet *dopesheet;
MovieTrackingDopesheetChannel *channel;
- uiStyle *style = UI_GetStyle();
+ uiStyle *style = UI_style_get();
uiBlock *block;
int fontid = style->widget.uifont_id;
int height;
@@ -348,7 +347,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
}
/* second pass: widgets */
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
y = (float) CHANNEL_FIRST;
/* get RNA properties (once) */
@@ -370,11 +369,11 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, &ptr);
- uiBlockSetEmboss(block, UI_EMBOSSN);
- uiDefIconButR_prop(block, ICONTOG, 1, icon,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 1, icon,
v2d->cur.xmax - UI_UNIT_X - CHANNEL_PAD, y - UI_UNIT_Y / 2.0f,
UI_UNIT_X, UI_UNIT_Y, &ptr, chan_prop_lock, 0, 0, 0, 0, 0, NULL);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
/* adjust y-position for next one */
@@ -382,6 +381,6 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
}
glDisable(GL_BLEND);
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
}
diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c
index 7ae5eda7139..d2f2fdd0b46 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_ops.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c
@@ -29,7 +29,6 @@
* \ingroup spclip
*/
-#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index a35251e71ef..62bb372514b 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -43,6 +43,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_math_base.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
#include "BKE_image.h"
@@ -63,7 +64,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "RNA_access.h"
#include "BLF_api.h"
@@ -252,11 +252,11 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
char str[256] = {0};
- bool block = false;
+ bool full_redraw = false;
if (tracking->stats) {
BLI_strncpy(str, tracking->stats->message, sizeof(str));
- block = true;
+ full_redraw = true;
}
else {
if (sc->flag & SC_LOCK_SELECTION)
@@ -265,7 +265,7 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar)
if (str[0]) {
float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.6f};
- ED_region_info_draw(ar, str, block, fill_color);
+ ED_region_info_draw(ar, str, fill_color, full_redraw);
}
}
@@ -286,6 +286,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
MovieClip *clip = ED_space_clip_get_clip(sc);
int filter = GL_LINEAR;
int x, y;
+ rctf frame;
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
@@ -309,10 +310,14 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y);
glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter);
-
/* reset zoom */
glPixelZoom(1.0f, 1.0f);
+ BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
+
+ if (sc->flag & SC_SHOW_METADATA)
+ ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
+
if (ibuf->planes == 32)
glDisable(GL_BLEND);
}
@@ -515,7 +520,7 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
/* pattern and search outline */
glPushMatrix();
- glTranslatef(marker_pos[0], marker_pos[1], 0);
+ glTranslate2fv(marker_pos);
if (!tiny)
glLineWidth(3.0f);
@@ -647,7 +652,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
/* pattern */
glPushMatrix();
- glTranslatef(marker_pos[0], marker_pos[1], 0);
+ glTranslate2fv(marker_pos);
if (tiny) {
glLineStipple(3, 0xaaaa);
@@ -800,7 +805,7 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
}
glPushMatrix();
- glTranslatef(marker_pos[0], marker_pos[1], 0);
+ glTranslate2fv(marker_pos);
dx = 6.0f / width / sc->zoom;
dy = 6.0f / height / sc->zoom;
@@ -1123,8 +1128,10 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
bool draw_outline, int width, int height)
{
bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
- bool is_selected_track = plane_track->flag & SELECT;
- bool draw_plane_quad = plane_track->image == NULL || plane_track->image_opacity == 0.0f;
+ bool is_selected_track = (plane_track->flag & SELECT) != 0;
+ const bool has_image = plane_track->image != NULL &&
+ BKE_image_has_ibuf(plane_track->image, NULL);
+ const bool draw_plane_quad = !has_image || plane_track->image_opacity == 0.0f;
float px[2];
if (draw_outline) {
@@ -1693,29 +1700,29 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
}
if (sc->flag & SC_SHOW_STABLE) {
+ float translation[2];
+ float aspect = clip->tracking.camera.pixel_aspect;
float smat[4][4], ismat[4][4];
- ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc, &sc->scale, &sc->angle);
-
- if (ibuf) {
- float translation[2];
- float aspect = clip->tracking.camera.pixel_aspect;
+ if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
+ ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc,
+ &sc->scale, &sc->angle);
+ }
- if (width != ibuf->x)
- mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x);
- else
- copy_v2_v2(translation, sc->loc);
+ if (ibuf != NULL && width != ibuf->x)
+ mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x);
+ else
+ copy_v2_v2(translation, sc->loc);
- BKE_tracking_stabilization_data_to_mat4(width, height, aspect,
- translation, sc->scale, sc->angle, sc->stabmat);
+ BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation,
+ sc->scale, sc->angle, sc->stabmat);
- unit_m4(smat);
- smat[0][0] = 1.0f / width;
- smat[1][1] = 1.0f / height;
- invert_m4_m4(ismat, smat);
+ unit_m4(smat);
+ smat[0][0] = 1.0f / width;
+ smat[1][1] = 1.0f / height;
+ invert_m4_m4(ismat, smat);
- mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
- }
+ mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
}
else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
ibuf = ED_space_clip_get_buffer(sc);
@@ -1779,7 +1786,7 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d)
int framenr = ED_space_clip_get_clip_frame_number(sc);
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- glTranslatef(marker->pos[0], marker->pos[1], 0.0f);
+ glTranslate2fv(marker->pos);
}
}
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index b7860643e1a..dbedfaa1de4 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -48,16 +48,16 @@
#include "BLI_fileops.h"
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_threads.h"
+#include "BLI_task.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_movieclip.h"
#include "BKE_context.h"
#include "BKE_tracking.h"
#include "BKE_library.h"
-#include "GPU_extensions.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -65,6 +65,7 @@
#include "ED_screen.h"
#include "ED_clip.h"
+#include "ED_mask.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -220,6 +221,7 @@ int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
+ /* Caller must ensure space does have a valid clip, otherwise it will crash, see T45017. */
return BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
}
@@ -330,7 +332,7 @@ void ED_clip_update_frame(const Main *mainp, int cfra)
}
}
-static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2])
+static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTrackingTrack *track;
@@ -378,6 +380,29 @@ static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2])
return ok;
}
+static bool selected_boundbox(const bContext *C, float min[2], float max[2])
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc->mode == SC_MODE_TRACKING) {
+ return selected_tracking_boundbox(sc, min, max);
+ }
+ else {
+ if (ED_mask_selected_minmax(C, min, max)) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int width, height;
+ ED_space_clip_get_size(sc, &width, &height);
+ BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
+ BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
+ min[0] *= width;
+ min[1] *= height;
+ max[0] *= width;
+ max[1] *= height;
+ return true;
+ }
+ return false;
+ }
+}
+
bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -389,7 +414,7 @@ bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit)
if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL))
return false;
- if (!selected_boundbox(sc, min, max))
+ if (!selected_boundbox(C, min, max))
return false;
/* center view */
@@ -620,11 +645,6 @@ typedef struct PrefetchQueue {
float *progress;
} PrefetchQueue;
-typedef struct PrefetchThread {
- MovieClip *clip;
- PrefetchQueue *queue;
-} PrefetchThread;
-
/* check whether pre-fetching is allowed */
static bool check_prefetch_break(void)
{
@@ -632,8 +652,9 @@ static bool check_prefetch_break(void)
}
/* read file for specified frame number to the memory */
-static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_frame, short render_size,
- short render_flag, size_t *size_r)
+static unsigned char *prefetch_read_file_to_memory(
+ MovieClip *clip, int current_frame, short render_size, short render_flag,
+ size_t *r_size)
{
MovieClipUser user = {0};
char name[FILE_MAX];
@@ -666,7 +687,7 @@ static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_
return NULL;
}
- *size_r = size;
+ *r_size = size;
close(file);
@@ -704,8 +725,9 @@ static int prefetch_find_uncached_frame(MovieClip *clip, int from_frame, int end
}
/* get memory buffer for first uncached frame within prefetch frame range */
-static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip *clip,
- size_t *size_r, int *current_frame_r)
+static unsigned char *prefetch_thread_next_frame(
+ PrefetchQueue *queue, MovieClip *clip,
+ size_t *r_size, int *r_current_frame)
{
unsigned char *mem = NULL;
@@ -734,9 +756,9 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip
int frames_processed;
mem = prefetch_read_file_to_memory(clip, current_frame, queue->render_size,
- queue->render_flag, size_r);
+ queue->render_flag, r_size);
- *current_frame_r = current_frame;
+ *r_current_frame = current_frame;
queue->current_frame = current_frame;
@@ -757,33 +779,35 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip
return mem;
}
-static void *do_prefetch_thread(void *data_v)
+static void prefetch_task_func(TaskPool *pool, void *task_data, int UNUSED(threadid))
{
- PrefetchThread *data = (PrefetchThread *) data_v;
- MovieClip *clip = data->clip;
+ PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
+ MovieClip *clip = (MovieClip *)task_data;
unsigned char *mem;
size_t size;
int current_frame;
- while ((mem = prefetch_thread_next_frame(data->queue, data->clip, &size, &current_frame))) {
+ while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
ImBuf *ibuf;
MovieClipUser user = {0};
int flag = IB_rect | IB_alphamode_detect;
int result;
char *colorspace_name = NULL;
+ const bool use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
+ (queue->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
user.framenr = current_frame;
- user.render_size = data->queue->render_size;
- user.render_flag = data->queue->render_flag;
+ user.render_size = queue->render_size;
+ user.render_flag = queue->render_flag;
/* Proxies are stored in the display space. */
- if (data->queue->render_flag & MCLIP_USE_PROXY) {
+ if (!use_proxy) {
colorspace_name = clip->colorspace_settings.name;
}
ibuf = IMB_ibImageFromMemory(mem, size, flag, colorspace_name, "prefetch frame");
- result = BKE_movieclip_put_frame_if_possible(data->clip, &user, ibuf);
+ result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
IMB_freeImBuf(ibuf);
@@ -791,27 +815,20 @@ static void *do_prefetch_thread(void *data_v)
if (!result) {
/* no more space in the cache, stop reading frames */
- *data->queue->stop = 1;
+ *queue->stop = 1;
break;
}
}
-
- return NULL;
}
static void start_prefetch_threads(MovieClip *clip, int start_frame, int current_frame, int end_frame,
short render_size, short render_flag, short *stop, short *do_update,
float *progress)
{
- ListBase threads;
PrefetchQueue queue;
- PrefetchThread *handles;
- int tot_thread = BLI_system_thread_count();
- int i;
-
- /* reserve one thread for the interface */
- if (tot_thread > 1)
- tot_thread--;
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
/* initialize queue */
BLI_spin_init(&queue.spin);
@@ -828,29 +845,18 @@ static void start_prefetch_threads(MovieClip *clip, int start_frame, int current
queue.do_update = do_update;
queue.progress = progress;
- /* fill in thread handles */
- handles = MEM_callocN(sizeof(PrefetchThread) * tot_thread, "prefetch threaded handles");
-
- if (tot_thread > 1)
- BLI_init_threads(&threads, do_prefetch_thread, tot_thread);
-
+ task_pool = BLI_task_pool_create(task_scheduler, &queue);
for (i = 0; i < tot_thread; i++) {
- PrefetchThread *handle = &handles[i];
-
- handle->clip = clip;
- handle->queue = &queue;
-
- if (tot_thread > 1)
- BLI_insert_thread(&threads, handle);
+ BLI_task_pool_push(task_pool,
+ prefetch_task_func,
+ clip,
+ false,
+ TASK_PRIORITY_LOW);
}
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
- /* run the threads */
- if (tot_thread > 1)
- BLI_end_threads(&threads);
- else
- do_prefetch_thread(handles);
-
- MEM_freeN(handles);
+ BLI_spin_end(&queue.spin);
}
static bool prefetch_movie_frame(MovieClip *clip, int frame, short render_size,
diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c
index 723c8bd144a..2c3b8acf672 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -50,7 +50,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "BLF_api.h"
#include "clip_intern.h" // own include
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index d1e2c770ade..e781d199d35 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -45,8 +45,6 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "UI_interface.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -202,10 +200,18 @@ static bool mouse_select_knot(bContext *C, float co[2], bool extend)
toggle_selection_cb);
}
- if (userdata.coord == 0)
- userdata.marker->flag |= MARKER_GRAPH_SEL_X;
- else
- userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
+ if (userdata.coord == 0) {
+ if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_X) != 0)
+ userdata.marker->flag &= ~MARKER_GRAPH_SEL_X;
+ else
+ userdata.marker->flag |= MARKER_GRAPH_SEL_X;
+ }
+ else {
+ if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_Y) != 0)
+ userdata.marker->flag &= ~MARKER_GRAPH_SEL_Y;
+ else
+ userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
+ }
return true;
}
@@ -240,10 +246,12 @@ static bool mouse_select_curve(bContext *C, float co[2], bool extend)
else if (act_track != userdata.track) {
SelectUserData selectdata = {SEL_DESELECT};
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
tracking->act_track = userdata.track;
- BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, true);
+ if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false);
+ }
/* deselect all knots on newly selected curve */
clip_graph_tracking_iterate(sc,
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 87efaa615ee..55805e0b907 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -49,10 +49,10 @@
#include "BLI_path_util.h"
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_threads.h"
+#include "BLI_task.h"
#include "BLI_string.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -79,6 +79,8 @@
#include "UI_view2d.h"
+#include "PIL_time.h"
+
#include "clip_intern.h" // own include
/******************** view navigation utilities *********************/
@@ -166,7 +168,7 @@ static void open_init(bContext *C, wmOperator *op)
PropertyPointerRNA *pprop;
op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
- uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
+ UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
}
static void open_cancel(bContext *UNUSED(C), wmOperator *op)
@@ -272,7 +274,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
return open_exec(C, op);
if (!RNA_struct_property_is_set(op->ptr, "relative_path"))
- RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
+ RNA_boolean_set(op->ptr, "relative_path", (U.flag & USER_RELPATHS) != 0);
open_init(C, op);
@@ -297,8 +299,8 @@ void CLIP_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************* reload clip operator *********************/
@@ -486,18 +488,25 @@ typedef struct ViewZoomData {
float zoom;
int event_type;
float location[2];
+ wmTimer *timer;
+ double timer_lastdraw;
} ViewZoomData;
static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
-
ViewZoomData *vpd;
op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ClipViewZoomData");
WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
+ if (U.viewzoom == USER_ZOOM_CONT) {
+ /* needs a timer to continue redrawing */
+ vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+ vpd->timer_lastdraw = PIL_check_seconds_timer();
+ }
+
vpd->x = event->x;
vpd->y = event->y;
vpd->zoom = sc->zoom;
@@ -518,6 +527,10 @@ static void view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
ED_region_tag_redraw(CTX_wm_region(C));
}
+ if (vpd->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
+ }
+
WM_cursor_modal_restore(CTX_wm_window(C));
MEM_freeN(op->customdata);
}
@@ -555,22 +568,61 @@ static int view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+static void view_zoom_apply(bContext *C,
+ ViewZoomData *vpd,
+ wmOperator *op,
+ const wmEvent *event)
+{
+ float factor;
+
+ if (U.viewzoom == USER_ZOOM_CONT) {
+ SpaceClip *sclip = CTX_wm_space_clip(C);
+ double time = PIL_check_seconds_timer();
+ float time_step = (float)(time - vpd->timer_lastdraw);
+ float fac;
+ float zfac;
+
+ if (U.uiflag & USER_ZOOM_HORIZ) {
+ fac = (float)(event->x - vpd->x);
+ }
+ else {
+ fac = (float)(event->y - vpd->y);
+ }
+
+ if (U.uiflag & USER_ZOOM_INVERT) {
+ fac = -fac;
+ }
+
+ zfac = 1.0f + ((fac / 20.0f) * time_step);
+ vpd->timer_lastdraw = time;
+ factor = (sclip->zoom * zfac) / vpd->zoom;
+ }
+ else {
+ float delta = event->x - vpd->x + event->y - vpd->y;
+
+ if (U.uiflag & USER_ZOOM_INVERT) {
+ delta *= -1;
+ }
+
+ factor = 1.0f + delta / 300.0f;
+ }
+
+ RNA_float_set(op->ptr, "factor", factor);
+ sclip_zoom_set(C, vpd->zoom * factor, vpd->location);
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
static int view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewZoomData *vpd = op->customdata;
- float delta, factor;
-
switch (event->type) {
+ case TIMER:
+ if (event->customdata == vpd->timer) {
+ view_zoom_apply(C, vpd, op, event);
+ }
+ break;
case MOUSEMOVE:
- delta = event->x - vpd->x + event->y - vpd->y;
-
- if (U.uiflag & USER_ZOOM_INVERT)
- delta *= -1;
-
- factor = 1.0f + delta / 300.0f;
- RNA_float_set(op->ptr, "factor", factor);
- sclip_zoom_set(C, vpd->zoom * factor, vpd->location);
- ED_region_tag_redraw(CTX_wm_region(C));
+ view_zoom_apply(C, vpd, op, event);
break;
default:
if (event->type == vpd->event_type && event->val == KM_RELEASE) {
@@ -606,7 +658,7 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* properties */
prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
@@ -860,7 +912,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -1071,10 +1123,7 @@ typedef struct ProxyQueue {
typedef struct ProxyThread {
MovieClip *clip;
- ProxyQueue *queue;
-
struct MovieDistortion *distortion;
-
int *build_sizes, build_count;
int *build_undistort_sizes, build_undistort_count;
} ProxyThread;
@@ -1130,14 +1179,15 @@ static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip
return mem;
}
-static void *do_proxy_thread(void *data_v)
+static void proxy_task_func(TaskPool *pool, void *task_data, int UNUSED(threadid))
{
- ProxyThread *data = (ProxyThread *) data_v;
+ ProxyThread *data = (ProxyThread *)task_data;
+ ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool);
unsigned char *mem;
size_t size;
int cfra;
- while ((mem = proxy_thread_next_frame(data->queue, data->clip, &size, &cfra))) {
+ while ((mem = proxy_thread_next_frame(queue, data->clip, &size, &cfra))) {
ImBuf *ibuf;
ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect,
@@ -1153,8 +1203,6 @@ static void *do_proxy_thread(void *data_v)
MEM_freeN(mem);
}
-
- return NULL;
}
static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
@@ -1164,12 +1212,18 @@ static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
int sfra = SFRA, efra = EFRA;
ProxyThread *handles;
- ListBase threads;
- int i, tot_thread = BLI_system_thread_count();
+ int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int width, height;
ProxyQueue queue;
+ if (build_undistort_count) {
+ BKE_movieclip_get_size(clip, NULL, &width, &height);
+ }
+
BLI_spin_init(&queue.spin);
queue.cfra = sfra;
@@ -1179,16 +1233,13 @@ static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
queue.do_update = do_update;
queue.progress = progress;
- handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
-
- if (tot_thread > 1)
- BLI_init_threads(&threads, do_proxy_thread, tot_thread);
-
+ task_pool = BLI_task_pool_create(task_scheduler, &queue);
+ handles = MEM_callocN(sizeof(ProxyThread) * tot_thread,
+ "proxy threaded handles");
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
handle->clip = clip;
- handle->queue = &queue;
handle->build_count = build_count;
handle->build_sizes = build_sizes;
@@ -1197,29 +1248,29 @@ static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
handle->build_undistort_sizes = build_undistort_sizes;
if (build_undistort_count) {
- int width, height;
- BKE_movieclip_get_size(clip, NULL, &width, &height);
- handle->distortion = BKE_tracking_distortion_new(&clip->tracking, width, height);
+ handle->distortion = BKE_tracking_distortion_new(&clip->tracking,
+ width, height);
}
- if (tot_thread > 1)
- BLI_insert_thread(&threads, handle);
+ BLI_task_pool_push(task_pool,
+ proxy_task_func,
+ handle,
+ false,
+ TASK_PRIORITY_LOW);
}
- if (tot_thread > 1)
- BLI_end_threads(&threads);
- else
- do_proxy_thread(handles);
-
- MEM_freeN(handles);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
if (build_undistort_count) {
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
-
BKE_tracking_distortion_free(handle->distortion);
}
}
+
+ BLI_spin_end(&queue.spin);
+ MEM_freeN(handles);
}
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
@@ -1256,7 +1307,14 @@ static void proxy_endjob(void *pjv)
if (pj->index_context)
IMB_anim_index_rebuild_finish(pj->index_context, pj->stop);
- BKE_movieclip_reload(pj->clip);
+ if (pj->clip->source == MCLIP_SRC_MOVIE) {
+ /* Timecode might have changed, so do a full reload to deal with this. */
+ BKE_movieclip_reload(pj->clip);
+ }
+ else {
+ /* For image sequences we'll preserve original cache. */
+ BKE_movieclip_clear_proxy_cache(pj->clip);
+ }
WM_main_add_notifier(NC_MOVIECLIP | ND_DISPLAY, pj->clip);
}
@@ -1284,7 +1342,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
if (clip->anim) {
pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag,
- clip->proxy.build_size_flag, clip->proxy.quality);
+ clip->proxy.build_size_flag, clip->proxy.quality,
+ true, NULL);
}
WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index 55b78219770..d31d7f53b30 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -38,7 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -242,7 +242,7 @@ static void clip_panel_operator_redo(const bContext *C, Panel *pa)
uiLayoutSetEnabled(pa->layout, false);
/* note, blockfunc is a default but->func, use Handle func to allow button callbacks too */
- uiBlockSetHandleFunc(block, ED_undo_operator_repeat_cb_evt, op);
+ UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
clip_panel_operator_redo_operator(C, pa, op);
}
@@ -258,7 +258,7 @@ void ED_clip_tool_props_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel last operator");
strcpy(pt->idname, "CLIP_PT_last_operator");
strcpy(pt->label, N_("Operator"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw_header = clip_panel_operator_redo_header;
pt->draw = clip_panel_operator_redo;
BLI_addtail(&art->paneltypes, pt);
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index a79ac1f7b82..48f8f587106 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -30,12 +30,10 @@
*/
#include "DNA_scene_types.h"
-#include "DNA_object_types.h" /* SELECT */
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -54,8 +52,6 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -181,9 +177,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- MovieTrackingPlaneTrack *plane_track, *next_plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
bool has_bundle = false, update_stab = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
@@ -201,49 +195,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
has_bundle = true;
/* Make sure no plane will use freed track */
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = next_plane_track)
- {
- bool found = false;
- int i;
-
- next_plane_track = plane_track->next;
-
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == track) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- continue;
- }
-
- if (plane_track->point_tracksnr > 4) {
- int track_index;
- MovieTrackingTrack **new_point_tracks;
-
- new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * plane_track->point_tracksnr,
- "new point tracks array");
-
- for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] != track) {
- new_point_tracks[track_index++] = plane_track->point_tracks[i];
- }
- }
-
- MEM_freeN(plane_track->point_tracks);
- plane_track->point_tracks = new_point_tracks;
- plane_track->point_tracksnr--;
- }
- else {
- /* Delete planes with less than 3 point tracks in it. */
- BKE_tracking_plane_track_free(plane_track);
- BLI_freelinkN(plane_tracks_base, plane_track);
- }
- }
+ BKE_tracking_plane_tracks_remove_point_track(tracking, track);
/* Delete f-curves associated with the track (such as weight, i.e.) */
BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index a797a60f74c..f119fe23c12 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -55,7 +55,7 @@
#include "ED_screen.h"
#include "ED_clip.h"
#include "ED_transform.h"
-#include "ED_uvedit.h" /* just for draw_image_cursor */
+#include "ED_uvedit.h" /* just for ED_image_draw_cursor */
#include "IMB_imbuf.h"
@@ -206,7 +206,7 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
if (sc->mode != SC_MODE_TRACKING)
return;
- /* only while proeprties are visible */
+ /* only while properties are visible */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_UI && ar->flag & RGN_FLAG_HIDDEN)
return;
@@ -420,6 +420,9 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
clip_scopes_check_gpencil_change(sa);
ED_area_tag_redraw(sa);
}
+ else if (wmn->data & ND_GPENCIL_EDITMODE) {
+ ED_area_tag_redraw(sa);
+ }
break;
}
}
@@ -1159,7 +1162,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar)
/* if tracking is in progress, we should synchronize framenr from clipuser
* so latest tracked frame would be shown */
if (clip && clip->tracking_context)
- BKE_tracking_context_sync_user(clip->tracking_context, &sc->user);
+ BKE_autotrack_context_sync_user(clip->tracking_context, &sc->user);
if (sc->flag & SC_LOCK_SELECTION) {
ImBuf *tmpibuf = NULL;
@@ -1218,7 +1221,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar)
glScalef(zoomx, zoomy, 0);
glMultMatrixf(sc->stabmat);
glScalef(width, height, 0);
- draw_image_cursor(ar, sc->cursor);
+ ED_image_draw_cursor(ar, sc->cursor);
glPopMatrix();
}
@@ -1245,6 +1248,8 @@ static void clip_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR
case NC_GPENCIL:
if (wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
+ else if (wmn->data & ND_GPENCIL_EDITMODE)
+ ED_region_tag_redraw(ar);
break;
}
}
@@ -1440,7 +1445,7 @@ static void clip_tools_area_init(wmWindowManager *wm, ARegion *ar)
static void clip_tools_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
/****************** tool properties region ******************/
@@ -1487,7 +1492,7 @@ static void clip_properties_area_draw(const bContext *C, ARegion *ar)
BKE_movieclip_update_scopes(sc->clip, &sc->user, &sc->scopes);
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void clip_properties_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -1495,7 +1500,7 @@ static void clip_properties_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->data == ND_DATA)
+ if (ELEM(wmn->data, ND_DATA, ND_GPENCIL_EDITMODE))
ED_region_tag_redraw(ar);
break;
case NC_BRUSH:
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index fb6b1a0033c..a19fa97965a 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -41,7 +41,6 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
-#include "BLI_rect.h"
#include "BLI_blenlib.h"
#include "BKE_main.h"
@@ -65,16 +64,14 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "UI_interface.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "PIL_time.h"
-#include "UI_view2d.h"
#include "clip_intern.h" // own include
@@ -828,12 +825,8 @@ static void apply_mouse_slide(bContext *C, SlideMarkerData *data)
plane_track = plane_track->next)
{
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == data->track) {
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
- break;
- }
+ if (BKE_tracking_plane_track_has_point_track(plane_track, data->track)) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
}
}
}
@@ -1073,7 +1066,7 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
ot->modal = slide_marker_modal;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -1083,7 +1076,7 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
/********************** track operator *********************/
typedef struct TrackMarkersJob {
- struct MovieTrackingContext *context; /* tracking context */
+ struct AutoTrackContext *context; /* tracking context */
int sfra, efra, lastfra; /* Start, end and recently tracked frames */
int backwards; /* Backwards tracking flag */
MovieClip *clip; /* Clip which is tracking */
@@ -1231,7 +1224,7 @@ static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backward
tmj->delay /= 2;
}
- tmj->context = BKE_tracking_context_new(clip, &sc->user, backwards, 1);
+ tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1);
clip->tracking_context = tmj->context;
@@ -1265,14 +1258,14 @@ static void track_markers_startjob(void *tmv, short *stop, short *do_update, flo
double start_time = PIL_check_seconds_timer(), exec_time;
- if (!BKE_tracking_context_step(tmj->context))
+ if (!BKE_autotrack_context_step(tmj->context))
break;
exec_time = PIL_check_seconds_timer() - start_time;
if (tmj->delay > (float)exec_time)
PIL_sleep_ms(tmj->delay - (float)exec_time);
}
- else if (!BKE_tracking_context_step(tmj->context))
+ else if (!BKE_autotrack_context_step(tmj->context))
break;
*do_update = true;
@@ -1296,7 +1289,7 @@ static void track_markers_updatejob(void *tmv)
{
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- BKE_tracking_context_sync(tmj->context);
+ BKE_autotrack_context_sync(tmj->context);
}
static void track_markers_endjob(void *tmv)
@@ -1310,8 +1303,8 @@ static void track_markers_endjob(void *tmv)
ED_update_for_newframe(tmj->main, tmj->scene, 0);
}
- BKE_tracking_context_sync(tmj->context);
- BKE_tracking_context_finish(tmj->context);
+ BKE_autotrack_context_sync(tmj->context);
+ BKE_autotrack_context_finish(tmj->context);
WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene);
}
@@ -1319,7 +1312,7 @@ static void track_markers_endjob(void *tmv)
static void track_markers_freejob(void *tmv)
{
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- BKE_tracking_context_free(tmj->context);
+ BKE_autotrack_context_free(tmj->context);
MEM_freeN(tmj);
}
@@ -1328,7 +1321,7 @@ static int track_markers_exec(bContext *C, wmOperator *op)
SpaceClip *sc;
MovieClip *clip;
Scene *scene = CTX_data_scene(C);
- struct MovieTrackingContext *context;
+ struct AutoTrackContext *context;
MovieClipUser *user, fake_user = {0};
int framenr, sfra, efra;
const bool backwards = RNA_boolean_get(op->ptr, "backwards");
@@ -1388,10 +1381,10 @@ static int track_markers_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* do not disable tracks due to threshold when tracking frame-by-frame */
- context = BKE_tracking_context_new(clip, user, backwards, sequence);
+ context = BKE_autotrack_context_new(clip, user, backwards, sequence);
while (framenr != efra) {
- if (!BKE_tracking_context_step(context))
+ if (!BKE_autotrack_context_step(context))
break;
if (backwards) framenr--;
@@ -1401,9 +1394,9 @@ static int track_markers_exec(bContext *C, wmOperator *op)
break;
}
- BKE_tracking_context_sync(context);
- BKE_tracking_context_finish(context);
- BKE_tracking_context_free(context);
+ BKE_autotrack_context_sync(context);
+ BKE_autotrack_context_finish(context);
+ BKE_autotrack_context_free(context);
/* update scene current frame to the lastes tracked frame */
scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
@@ -1433,6 +1426,7 @@ static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
}
clip = ED_space_clip_get_clip(sc);
+ BLI_assert(clip != NULL);
framenr = ED_space_clip_get_clip_frame_number(sc);
if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
@@ -1511,6 +1505,7 @@ void CLIP_OT_track_markers(wmOperatorType *ot)
ot->exec = track_markers_exec;
ot->invoke = track_markers_invoke;
ot->modal = track_markers_modal;
+ ot->poll = ED_space_clip_tracking_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -1886,7 +1881,7 @@ void CLIP_OT_clear_track_path(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* proeprties */
+ /* properties */
RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
RNA_def_boolean(ot->srna, "clear_active", 0, "Clear Active", "Clear active track only instead of all selected tracks");
}
@@ -2045,7 +2040,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat
bool found = false;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti)
continue;
@@ -2076,7 +2071,7 @@ static Object *object_solver_camera(Scene *scene, Object *ob)
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti)
continue;
@@ -3057,7 +3052,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
if (CFRA != sc->user.framenr) {
CFRA = sc->user.framenr;
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -3120,6 +3115,12 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
if (tracking->stabilization.rot_track == track)
tracking->stabilization.rot_track = act_track;
+ /* TODO(sergey): Re-evaluate planes with auto-key. */
+ BKE_tracking_plane_tracks_replace_point_track(tracking,
+ track,
+ act_track);
+
+
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
}
@@ -4184,7 +4185,7 @@ void CLIP_OT_slide_plane_marker(wmOperatorType *ot)
ot->modal = slide_plane_marker_modal;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
}
/********************** Insert track keyframe operator *********************/
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 860d9dc6b3c..8a2bf17c667 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -36,7 +36,6 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_lasso.h"
@@ -49,16 +48,9 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
-#include "UI_interface.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
-#include "PIL_time.h"
-
#include "UI_view2d.h"
#include "clip_intern.h" // own include
@@ -70,7 +62,6 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
{
if (x1 > x2)
-
SWAP(float, x1, x2);
if (y1 > y2)
@@ -1006,6 +997,6 @@ void CLIP_OT_select_grouped(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* proeprties */
+ /* properties */
RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
}
diff --git a/source/blender/editors/space_console/CMakeLists.txt b/source/blender/editors/space_console/CMakeLists.txt
index 241a48c1e2d..ecfb1f0e0df 100644
--- a/source/blender/editors/space_console/CMakeLists.txt
+++ b/source/blender/editors/space_console/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -45,4 +47,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_console "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_console/SConscript b/source/blender/editors/space_console/SConscript
index 0395a33cd97..f189cd3920a 100644
--- a/source/blender/editors/space_console/SConscript
+++ b/source/blender/editors/space_console/SConscript
@@ -28,16 +28,20 @@
Import ('env')
sources = env.Glob('*.c')
+
defs = []
+defs += env['BF_GL_DEFINITIONS']
incs = [
'../include',
- '#/extern/glew/include',
'#/intern/guardedalloc',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../../makesdna',
'../../makesrna',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../windowmanager',
'../../blenfont',
]
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 635d5ea07fd..d206ce4699e 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -30,7 +30,6 @@
#include <sys/stat.h>
#include <limits.h>
-#include "BLF_api.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h
index 00f1f8c21c9..d8a4a6fd2bb 100644
--- a/source/blender/editors/space_console/console_intern.h
+++ b/source/blender/editors/space_console/console_intern.h
@@ -31,7 +31,6 @@
struct ConsoleLine;
struct wmOperatorType;
-struct ReportList;
struct bContext;
/* console_draw.c */
@@ -66,6 +65,7 @@ void CONSOLE_OT_history_cycle(struct wmOperatorType *ot);
void CONSOLE_OT_copy(struct wmOperatorType *ot);
void CONSOLE_OT_paste(struct wmOperatorType *ot);
void CONSOLE_OT_select_set(struct wmOperatorType *ot);
+void CONSOLE_OT_select_word(struct wmOperatorType *ot);
enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD };
enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index b44e942527c..92731c2f135 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -95,7 +95,7 @@ static void console_scrollback_limit(SpaceConsole *sc)
if (U.scrollback < 32) U.scrollback = 256; // XXX - save in user defaults
- for (tot = BLI_countlist(&sc->scrollback); tot > U.scrollback; tot--)
+ for (tot = BLI_listbase_count(&sc->scrollback); tot > U.scrollback; tot--)
console_scrollback_free(sc, sc->scrollback.first);
}
@@ -107,7 +107,7 @@ static ConsoleLine *console_history_find(SpaceConsole *sc, const char *str, Cons
if (cl == cl_ignore)
continue;
- if (strcmp(str, cl->line) == 0)
+ if (STREQ(str, cl->line))
return cl;
}
@@ -136,7 +136,7 @@ static void console_lb_debug__internal(ListBase *lb)
{
ConsoleLine *cl;
- printf("%d: ", BLI_countlist(lb));
+ printf("%d: ", BLI_listbase_count(lb));
for (cl = lb->first; cl; cl = cl->next)
printf("<%s> ", cl->line);
printf("\n");
@@ -262,6 +262,40 @@ static int console_line_insert(ConsoleLine *ci, char *str)
return len;
}
+/**
+ * Take an absolute index and give the line/column info.
+ *
+ * \note be sure to call console_scrollback_prompt_begin first
+ */
+static bool console_line_column_from_index(
+ SpaceConsole *sc, const int pos,
+ ConsoleLine **r_cl, int *r_cl_offset, int *r_col)
+{
+ ConsoleLine *cl;
+ int offset = 0;
+
+ for (cl = sc->scrollback.last; cl; cl = cl->prev) {
+ offset += cl->len + 1;
+ if (offset >= pos) {
+ break;
+ }
+ }
+
+ if (cl) {
+ offset -= 1;
+ *r_cl = cl;
+ *r_cl_offset = offset;
+ *r_col = offset - pos;
+ return true;
+ }
+ else {
+ *r_cl = NULL;
+ *r_cl_offset = -1;
+ *r_col = -1;
+ return false;
+ }
+}
+
/* static funcs for text editing */
/* similar to the text editor, with some not used. keep compatible */
@@ -722,7 +756,7 @@ static int console_history_cycle_exec(bContext *C, wmOperator *op)
if (ci->prev) {
ConsoleLine *ci_prev = (ConsoleLine *)ci->prev;
- if (strcmp(ci->line, ci_prev->line) == 0)
+ if (STREQ(ci->line, ci_prev->line))
console_history_free(sc, ci_prev);
}
@@ -791,7 +825,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op)
while ((cl = console_history_find(sc, ci->line, ci)))
console_history_free(sc, cl);
- if (strcmp(str, ci->line) == 0) {
+ if (STREQ(str, ci->line)) {
MEM_freeN(str);
return OPERATOR_FINISHED;
}
@@ -1134,3 +1168,57 @@ void CONSOLE_OT_select_set(wmOperatorType *ot)
ot->cancel = console_modal_select_cancel;
ot->poll = ED_operator_console_active;
}
+
+static int console_selectword_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ SpaceConsole *sc = CTX_wm_space_console(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ ConsoleLine cl_dummy = {NULL};
+ ConsoleLine *cl;
+ int ret = OPERATOR_CANCELLED;
+ int pos, offset, n;
+
+ pos = console_char_pick(sc, ar, event->mval);
+
+ console_scrollback_prompt_begin(sc, &cl_dummy);
+
+ if (console_line_column_from_index(sc, pos, &cl, &offset, &n)) {
+ int sel[2] = {n, n};
+
+ BLI_str_cursor_step_utf8(
+ cl->line, cl->len,
+ &sel[0], STRCUR_DIR_NEXT,
+ STRCUR_JUMP_DELIM, true);
+
+ BLI_str_cursor_step_utf8(
+ cl->line, cl->len,
+ &sel[1], STRCUR_DIR_PREV,
+ STRCUR_JUMP_DELIM, true);
+
+ sel[0] = offset - sel[0];
+ sel[1] = offset - sel[1];
+
+ if ((sel[0] != sc->sel_start) || (sel[1] != sc->sel_end)) {
+ sc->sel_start = sel[0];
+ sc->sel_end = sel[1];
+ ED_area_tag_redraw(CTX_wm_area(C));
+ ret = OPERATOR_FINISHED;
+ }
+ }
+
+ console_scrollback_prompt_end(sc, &cl_dummy);
+ return ret;
+}
+
+void CONSOLE_OT_select_word(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Word";
+ ot->description = "Select word at cursor position";
+ ot->idname = "CONSOLE_OT_select_word";
+
+ /* api callbacks */
+ ot->invoke = console_selectword_invoke;
+ ot->poll = ED_operator_console_active;
+}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index e4a61a8f06e..a592f35f629 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -270,6 +270,7 @@ static void console_operatortypes(void)
WM_operatortype_append(CONSOLE_OT_copy);
WM_operatortype_append(CONSOLE_OT_paste);
WM_operatortype_append(CONSOLE_OT_select_set);
+ WM_operatortype_append(CONSOLE_OT_select_word);
}
static void console_keymap(struct wmKeyConfig *keyconf)
@@ -348,6 +349,7 @@ static void console_keymap(struct wmKeyConfig *keyconf)
#endif
WM_keymap_add_item(keymap, "CONSOLE_OT_select_set", LEFTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "CONSOLE_OT_select_word", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
RNA_string_set(WM_keymap_add_item(keymap, "CONSOLE_OT_insert", TABKEY, KM_PRESS, KM_CTRL, 0)->ptr, "text", "\t"); /* fake tabs */
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 3b2db3ee7bc..fd701a8be4c 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -24,12 +24,16 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../blentranslation
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/atomic
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -40,6 +44,7 @@ set(SRC
file_draw.c
file_ops.c
file_panels.c
+ file_utils.c
filelist.c
filesel.c
fsmenu.c
@@ -86,6 +91,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
diff --git a/source/blender/editors/space_file/SConscript b/source/blender/editors/space_file/SConscript
index d42394454eb..a66a14a32de 100644
--- a/source/blender/editors/space_file/SConscript
+++ b/source/blender/editors/space_file/SConscript
@@ -29,13 +29,17 @@ Import ('env')
sources = env.Glob('*.c')
incs = [
+ '#/intern/atomic',
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../blenloader',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -45,6 +49,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_OPENJPEG']:
defs.append('WITH_OPENJPEG')
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 3e099b43a4b..2d9ecbdf415 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -35,6 +35,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
+#include "BLI_math.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -47,8 +48,9 @@
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLO_readfile.h"
+
+#include "BLT_translation.h"
#include "IMB_imbuf_types.h"
@@ -65,13 +67,20 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "WM_api.h"
#include "WM_types.h"
-#include "fsmenu.h"
#include "filelist.h"
#include "file_intern.h" // own include
+/* Dummy helper - we need dynamic tooltips here. */
+static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+{
+ char *dyn_tooltip = argN;
+ return BLI_strdup(dyn_tooltip);
+}
+
/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d.
* The controls are laid out as follows:
*
@@ -113,31 +122,37 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
ARegion *artmp;
+ const bool is_browse_only = (sfile->op == NULL);
/* Initialize UI block. */
BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar);
- block = uiBeginBlock(C, ar, uiblockstr, UI_EMBOSS);
+ block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS);
/* exception to make space for collapsed region icon */
for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) {
- if (artmp->regiontype == RGN_TYPE_CHANNELS && artmp->flag & RGN_FLAG_HIDDEN) {
+ if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) {
chan_offs = 16;
min_x += chan_offs;
available_w -= chan_offs;
}
}
-
+
/* Is there enough space for the execute / cancel buttons? */
- loadbutton = UI_GetStringWidth(sfile->params->title) + btn_margin;
- if (loadbutton < btn_minw) {
- loadbutton = MAX2(btn_minw,
- btn_margin + UI_GetStringWidth(params->title));
- }
-
- if (available_w <= loadbutton + separator + input_minw || params->title[0] == 0) {
+
+
+ if (is_browse_only) {
loadbutton = 0;
}
else {
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin;
+ CLAMP_MIN(loadbutton, btn_minw);
+ if (available_w <= loadbutton + separator + input_minw) {
+ loadbutton = 0;
+ }
+ }
+
+ if (loadbutton) {
line1_w -= (loadbutton + separator);
line2_w = line1_w;
}
@@ -150,127 +165,105 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
else {
line2_w -= (fnumbuttons + separator);
}
-
+
/* Text input fields for directory and file. */
if (available_w > 0) {
+ const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL;
int overwrite_alert = file_draw_check_exists(sfile);
+ const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER);
+
/* callbacks for operator check functions */
- uiBlockSetFunc(block, file_draw_check_cb, NULL, NULL);
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
- but = uiDefBut(block, TEX, -1, "",
+ but = uiDefBut(block, UI_BTYPE_TEXT, -1, "",
min_x, line1_y, line1_w - chan_offs, btn_h,
params->dir, 0.0, (float)FILE_MAX, 0, 0,
TIP_("File path"));
- uiButSetCompleteFunc(but, autocomplete_directory, NULL);
- uiButSetFlag(but, UI_BUT_NO_UTF8);
- uiButClearFlag(but, UI_BUT_UNDO);
- uiButSetNFunc(but, file_directory_enter_handle, NULL, but);
+ UI_but_func_complete_set(but, autocomplete_directory, NULL);
+ UI_but_flag_enable(but, UI_BUT_NO_UTF8);
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+ UI_but_funcN_set(but, file_directory_enter_handle, NULL, but);
/* TODO, directory editing is non-functional while a library is loaded
* until this is properly supported just disable it. */
if (sfile->files && filelist_lib(sfile->files))
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
- but = uiDefBut(block, TEX, -1, "",
+ but = uiDefBut(block, UI_BTYPE_TEXT, -1, "",
min_x, line2_y, line2_w - chan_offs, btn_h,
- params->file, 0.0, (float)FILE_MAXFILE, 0, 0,
+ is_active_dir ? (char *)"" : params->file,
+ 0.0, (float)FILE_MAXFILE, 0, 0,
TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
- uiButSetCompleteFunc(but, autocomplete_file, NULL);
- uiButSetFlag(but, UI_BUT_NO_UTF8);
- uiButClearFlag(but, UI_BUT_UNDO);
+ UI_but_func_complete_set(but, autocomplete_file, NULL);
+ UI_but_flag_enable(but, UI_BUT_NO_UTF8);
+ UI_but_flag_disable(but, UI_BUT_UNDO);
/* silly workaround calling NFunc to ensure this does not get called
* immediate ui_apply_but_func but only after button deactivates */
- uiButSetNFunc(but, file_filename_enter_handle, NULL, but);
+ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
/* check if this overrides a file and if the operator option is used */
if (overwrite_alert) {
- uiButSetFlag(but, UI_BUT_REDALERT);
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
}
}
/* clear func */
- uiBlockSetFunc(block, NULL, NULL, NULL);
+ UI_block_func_set(block, NULL, NULL, NULL);
}
/* Filename number increment / decrement buttons. */
if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) {
- uiBlockBeginAlign(block);
- but = uiDefIconButO(block, BUT, "FILE_OT_filenum", 0, ICON_ZOOMOUT,
+ UI_block_align_begin(block);
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ZOOMOUT,
min_x + line2_w + separator - chan_offs, line2_y,
btn_fn_w, btn_h,
TIP_("Decrement the filename number"));
- RNA_int_set(uiButGetOperatorPtrRNA(but), "increment", -1);
+ RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1);
- but = uiDefIconButO(block, BUT, "FILE_OT_filenum", 0, ICON_ZOOMIN,
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ZOOMIN,
min_x + line2_w + separator + btn_fn_w - chan_offs, line2_y,
btn_fn_w, btn_h,
TIP_("Increment the filename number"));
- RNA_int_set(uiButGetOperatorPtrRNA(but), "increment", 1);
- uiBlockEndAlign(block);
+ RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1);
+ UI_block_align_end(block);
}
/* Execute / cancel buttons. */
if (loadbutton) {
- /* params->title is already translated! */
- uiDefButO(block, BUT, "FILE_OT_execute", WM_OP_EXEC_REGION_WIN, params->title,
+ const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL;
+ char const *str_exec;
+
+ if (file && FILENAME_IS_PARENT(file->relpath)) {
+ str_exec = IFACE_("Parent Directory");
+ }
+ else if (file && file->typeflag & FILE_TYPE_DIR) {
+ str_exec = IFACE_("Open Directory");
+ }
+ else {
+ str_exec = params->title; /* params->title is already translated! */
+ }
+
+ uiDefButO(block, UI_BTYPE_BUT, "FILE_OT_execute", WM_OP_EXEC_REGION_WIN, str_exec,
max_x - loadbutton, line1_y, loadbutton, btn_h, "");
- uiDefButO(block, BUT, "FILE_OT_cancel", WM_OP_EXEC_REGION_WIN, IFACE_("Cancel"),
+ uiDefButO(block, UI_BTYPE_BUT, "FILE_OT_cancel", WM_OP_EXEC_REGION_WIN, IFACE_("Cancel"),
max_x - loadbutton, line2_y, loadbutton, btn_h, "");
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
}
static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade)
{
UI_ThemeColorShade(colorid, shade);
- uiSetRoundBox(UI_CNR_ALL);
- uiRoundBox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f);
}
-static int get_file_icon(struct direntry *file)
-{
- if (file->type & S_IFDIR) {
- if (strcmp(file->relname, "..") == 0) {
- return ICON_FILE_PARENT;
- }
- if (file->flags & APPLICATIONBUNDLE) {
- return ICON_UGLYPACKAGE;
- }
- if (file->flags & BLENDERFILE) {
- return ICON_FILE_BLEND;
- }
- return ICON_FILE_FOLDER;
- }
- else if (file->flags & BLENDERFILE)
- return ICON_FILE_BLEND;
- else if (file->flags & BLENDERFILE_BACKUP)
- return ICON_FILE_BACKUP;
- else if (file->flags & IMAGEFILE)
- return ICON_FILE_IMAGE;
- else if (file->flags & MOVIEFILE)
- return ICON_FILE_MOVIE;
- else if (file->flags & PYSCRIPTFILE)
- return ICON_FILE_SCRIPT;
- else if (file->flags & SOUNDFILE)
- return ICON_FILE_SOUND;
- else if (file->flags & FTFONTFILE)
- return ICON_FILE_FONT;
- else if (file->flags & BTXFILE)
- return ICON_FILE_BLANK;
- else if (file->flags & COLLADAFILE)
- return ICON_FILE_BLANK;
- else if (file->flags & TEXTFILE)
- return ICON_FILE_TEXT;
- else
- return ICON_FILE_BLANK;
-}
-
-static void file_draw_icon(uiBlock *block, char *path, int sx, int sy, int icon, int width, int height, bool drag)
+static void file_draw_icon(uiBlock *block, const char *path, int sx, int sy, int icon, int width, int height, bool drag)
{
uiBut *but;
int x, y;
@@ -281,32 +274,42 @@ static void file_draw_icon(uiBlock *block, char *path, int sx, int sy, int icon,
/*if (icon == ICON_FILE_BLANK) alpha = 0.375f;*/
- but = uiDefIconBut(block, LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, "");
+ but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL);
+ UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
- if (drag)
- uiButSetDragPath(but, path);
+ if (drag) {
+ /* path is no more static, cannot give it directly to but... */
+ UI_but_drag_set_path(but, BLI_strdup(path), true);
+ }
}
static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align)
{
- uiStyle *style = UI_GetStyle();
- uiFontStyle fs = style->widgetlabel;
+ uiStyle *style;
+ uiFontStyle fs;
rcti rect;
char fname[FILE_MAXFILE];
+ if (string[0] == '\0') {
+ return;
+ }
+
+ style = UI_style_get();
+ fs = style->widgetlabel;
+
fs.align = align;
BLI_strncpy(fname, string, FILE_MAXFILE);
- file_shorten_string(fname, width + 1.0f, 0);
+ UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0');
- /* no text clipping needed, uiStyleFontDraw does it but is a bit too strict (for buttons it works) */
+ /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict (for buttons it works) */
rect.xmin = sx;
- rect.xmax = (int)(sx + ceil(width + 4.0f));
+ rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC));
rect.ymin = sy - height;
rect.ymax = sy;
-
- uiStyleFontDraw(&fs, &rect, fname);
+
+ UI_fontstyle_draw(&fs, &rect, fname);
}
void file_calc_previews(const bContext *C, ARegion *ar)
@@ -318,72 +321,92 @@ void file_calc_previews(const bContext *C, ARegion *ar)
UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
}
-static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool dropshadow, bool drag)
+static void file_draw_preview(
+ uiBlock *block, const char *path, int sx, int sy, const float icon_aspect,
+ ImBuf *imb, const int icon, FileLayout *layout, const bool is_icon, const int typeflags, const bool drag)
{
- if (imb) {
- uiBut *but;
- float fx, fy;
- float dx, dy;
- int xco, yco;
- float scaledx, scaledy;
- float scale;
- int ex, ey;
-
- if ((imb->x * UI_DPI_FAC > layout->prv_w) ||
- (imb->y * UI_DPI_FAC > layout->prv_h))
- {
- if (imb->x > imb->y) {
- scaledx = (float)layout->prv_w;
- scaledy = ( (float)imb->y / (float)imb->x) * layout->prv_w;
- scale = scaledx / imb->x;
- }
- else {
- scaledy = (float)layout->prv_h;
- scaledx = ( (float)imb->x / (float)imb->y) * layout->prv_h;
- scale = scaledy / imb->y;
- }
+ uiBut *but;
+ float fx, fy;
+ float dx, dy;
+ int xco, yco;
+ float ui_imbx, ui_imby;
+ float scaledx, scaledy;
+ float scale;
+ int ex, ey;
+ bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE);
+
+ BLI_assert(imb != NULL);
+
+ ui_imbx = imb->x * UI_DPI_FAC;
+ ui_imby = imb->y * UI_DPI_FAC;
+ /* Unlike thumbnails, icons are not scaled up. */
+ if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) ||
+ (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h))))
+ {
+ if (imb->x > imb->y) {
+ scaledx = (float)layout->prv_w;
+ scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w;
+ scale = scaledx / imb->x;
}
else {
- scaledx = (float)imb->x * UI_DPI_FAC;
- scaledy = (float)imb->y * UI_DPI_FAC;
- scale = UI_DPI_FAC;
+ scaledy = (float)layout->prv_h;
+ scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h;
+ scale = scaledy / imb->y;
}
+ }
+ else {
+ scaledx = ui_imbx;
+ scaledy = ui_imby;
+ scale = UI_DPI_FAC;
+ }
- ex = (int)scaledx;
- ey = (int)scaledy;
- fx = ((float)layout->prv_w - (float)ex) / 2.0f;
- fy = ((float)layout->prv_h - (float)ey) / 2.0f;
- dx = (fx + 0.5f + layout->prv_border_x);
- dy = (fy + 0.5f - layout->prv_border_y);
- xco = sx + (int)dx;
- yco = sy - layout->prv_h + (int)dy;
-
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- /* shadow */
- if (dropshadow)
- uiDrawBoxShadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ ex = (int)scaledx;
+ ey = (int)scaledy;
+ fx = ((float)layout->prv_w - (float)ex) / 2.0f;
+ fy = ((float)layout->prv_h - (float)ey) / 2.0f;
+ dx = (fx + 0.5f + layout->prv_border_x);
+ dy = (fy + 0.5f - layout->prv_border_y);
+ xco = sx + (int)dx;
+ yco = sy - layout->prv_h + (int)dy;
- glEnable(GL_BLEND);
-
- /* the image */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* shadow */
+ if (use_dropshadow) {
+ UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ }
+
+ glEnable(GL_BLEND);
+
+ /* the image */
+ if (!is_icon && typeflags & FILE_TYPE_FTFONT) {
+ UI_ThemeColor(TH_TEXT);
+ }
+ else {
glColor4f(1.0, 1.0, 1.0, 1.0);
- glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
-
- /* border */
- if (dropshadow) {
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
- }
-
- /* dragregion */
- if (drag) {
- but = uiDefBut(block, LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, "");
- uiButSetDragImage(but, file->path, get_file_icon(file), imb, scale);
- }
-
- glDisable(GL_BLEND);
}
+ glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
+
+ if (icon) {
+ UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f);
+ }
+
+ /* border */
+ if (use_dropshadow) {
+ glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ }
+
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL);
+ UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
+
+ /* dragregion */
+ if (drag) {
+ /* path is no more static, cannot give it directly to but... */
+ UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true);
+ }
+
+ glDisable(GL_BLEND);
}
static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
@@ -393,17 +416,19 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
char filename[FILE_MAX + 12];
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
+ ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
BLI_make_file_string(G.main->name, orgname, sfile->params->dir, oldname);
BLI_strncpy(filename, sfile->params->renameedit, sizeof(filename));
+ BLI_filename_make_safe(filename);
BLI_make_file_string(G.main->name, newname, sfile->params->dir, filename);
- if (strcmp(orgname, newname) != 0) {
+ if (!STREQ(orgname, newname)) {
if (!BLI_exists(newname)) {
BLI_rename(orgname, newname);
/* to make sure we show what is on disk */
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
}
ED_region_tag_redraw(ar);
@@ -468,9 +493,10 @@ void file_draw_list(const bContext *C, ARegion *ar)
FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
View2D *v2d = &ar->v2d;
struct FileList *files = sfile->files;
- struct direntry *file;
+ struct FileDirEntry *file;
+ const char *root = filelist_dir(files);
ImBuf *imb;
- uiBlock *block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
int numfiles;
int numfiles_layout;
int sx, sy;
@@ -481,8 +507,11 @@ void file_draw_list(const bContext *C, ARegion *ar)
short align;
bool do_drag;
int column_space = 0.6f * UI_UNIT_X;
+ const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
+ const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
- numfiles = filelist_numfiles(files);
+ numfiles = filelist_files_ensure(files);
if (params->display != FILE_IMGDISPLAY) {
@@ -504,105 +533,168 @@ void file_draw_list(const bContext *C, ARegion *ar)
numfiles_layout += layout->columns;
}
+ filelist_file_cache_slidingwindow_set(files, numfiles_layout);
+
textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w : (int)layout->column_widths[COLUMN_NAME];
textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5);
align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT;
+ if (numfiles > 0) {
+ const bool success = filelist_file_cache_block(files, min_ii(offset + (numfiles_layout / 2), numfiles - 1));
+ BLI_assert(success);
+ UNUSED_VARS_NDEBUG(success);
+
+ filelist_cache_previews_update(files);
+
+ /* Handle preview timer here, since it's filelist_file_cache_block() and filelist_cache_previews_update()
+ * which controlls previews task. */
+ {
+ const bool previews_running = filelist_cache_previews_running(files);
+// printf("%s: preview task: %d\n", __func__, previews_running);
+ if (previews_running && !sfile->previews_timer) {
+ sfile->previews_timer = WM_event_add_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C),
+ NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01);
+ }
+ if (!previews_running && sfile->previews_timer) {
+ /* Preview is not running, no need to keep generating update events! */
+// printf("%s: Inactive preview task, sleeping!\n", __func__);
+ WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer);
+ sfile->previews_timer = NULL;
+ }
+ }
+ }
+
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
+ unsigned int file_selflag;
+ char path[FILE_MAX_LIBEXTRA];
ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X);
sy = (int)(v2d->tot.ymax - sy);
file = filelist_file(files, i);
-
+ file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL);
+
+ BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+
UI_ThemeColor4(TH_TEXT);
- if (!(file->selflag & EDITING_FILE)) {
- if ((params->active_file == i) || (file->selflag & HILITED_FILE) || (file->selflag & SELECTED_FILE)) {
- int colorid = (file->selflag & SELECTED_FILE) ? TH_HILITE : TH_BACK;
- int shade = (params->active_file == i) || (file->selflag & HILITED_FILE) ? 20 : 0;
+ if (!(file_selflag & FILE_SEL_EDITING)) {
+ if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ||
+ (file_selflag & FILE_SEL_SELECTED))
+ {
+ int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
+ int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0;
+
+ BLI_assert(i > 0 || FILENAME_IS_CURRPAR(file->relpath));
+
draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
}
- uiSetRoundBox(UI_CNR_NONE);
+ UI_draw_roundbox_corner_set(UI_CNR_NONE);
/* don't drag parent or refresh items */
- do_drag = !(STREQ(file->relname, "..") || STREQ(file->relname, "."));
+ do_drag = !(FILENAME_IS_CURRPAR(file->relpath));
if (FILE_IMGDISPLAY == params->display) {
+ const int icon = filelist_geticon(files, i, false);
is_icon = 0;
imb = filelist_getimage(files, i);
if (!imb) {
- imb = filelist_geticon(files, i);
+ imb = filelist_geticon_image(files, i);
is_icon = 1;
}
-
- file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & IMAGEFILE), do_drag);
+
+ file_draw_preview(block, path, sx, sy, thumb_icon_aspect,
+ imb, icon, layout, is_icon, file->typeflag, do_drag);
}
else {
- file_draw_icon(block, file->path, sx, sy - (UI_UNIT_Y / 6), get_file_icon(file), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag);
+ file_draw_icon(block, path, sx, sy - (UI_UNIT_Y / 6), filelist_geticon(files, i, true),
+ ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag);
sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}
UI_ThemeColor4(TH_TEXT);
- if (file->selflag & EDITING_FILE) {
- uiBut *but = uiDefBut(block, TEX, 1, "", sx, sy - layout->tile_h - 0.15f * UI_UNIT_X,
- textwidth, textheight, sfile->params->renameedit, 1.0f, (float)sizeof(sfile->params->renameedit), 0, 0, "");
- uiButSetRenameFunc(but, renamebutton_cb, file);
- uiButSetFlag(but, UI_BUT_NO_UTF8); /* allow non utf8 names */
- uiButClearFlag(but, UI_BUT_UNDO);
- if (false == uiButActiveOnly(C, ar, block, but)) {
- file->selflag &= ~EDITING_FILE;
+ if (file_selflag & FILE_SEL_EDITING) {
+ uiBut *but;
+ short width;
+
+ if (params->display == FILE_SHORTDISPLAY) {
+ width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X);
+ }
+ else if (params->display == FILE_LONGDISPLAY) {
+ width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f);
+ }
+ else {
+ BLI_assert(params->display == FILE_IMGDISPLAY);
+ width = textwidth;
+ }
+
+ but = uiDefBut(block, UI_BTYPE_TEXT, 1, "", sx, sy - layout->tile_h - 0.15f * UI_UNIT_X,
+ width, textheight, sfile->params->renameedit, 1.0f,
+ (float)sizeof(sfile->params->renameedit), 0, 0, "");
+ UI_but_func_rename_set(but, renamebutton_cb, file);
+ UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+ if (false == UI_but_active_only(C, ar, block, but)) {
+ file_selflag = filelist_entry_select_set(
+ sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
}
}
- if (!(file->selflag & EDITING_FILE)) {
+ if (!(file_selflag& FILE_SEL_EDITING)) {
int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy;
- file_draw_string(sx + 1, tpos, file->relname, (float)textwidth, textheight, align);
+ file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align);
}
+ sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
if (params->display == FILE_SHORTDISPLAY) {
- sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
- if (!(file->type & S_IFDIR)) {
- file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
+ !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB)))
+ {
+ if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
+ BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str);
+ }
+ file_draw_string(
+ sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
}
+ sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
else if (params->display == FILE_LONGDISPLAY) {
- sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
-
-#ifndef WIN32
- /* rwx rwx rwx */
- file_draw_string(sx, sy, file->mode1, layout->column_widths[COLUMN_MODE1], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_MODE1] + column_space;
-
- file_draw_string(sx, sy, file->mode2, layout->column_widths[COLUMN_MODE2], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_MODE2] + column_space;
-
- file_draw_string(sx, sy, file->mode3, layout->column_widths[COLUMN_MODE3], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_MODE3] + column_space;
-
- file_draw_string(sx, sy, file->owner, layout->column_widths[COLUMN_OWNER], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_OWNER] + column_space;
-#endif
-
- file_draw_string(sx, sy, file->date, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
-
- file_draw_string(sx, sy, file->time, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
+ if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if ((file->entry->date_str[0] == '\0') || update_stat_strings) {
+ BLI_filelist_entry_datetime_to_string(
+ NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str);
+ }
+ file_draw_string(
+ sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
+ sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
+ file_draw_string(
+ sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
+ sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
+ }
+ else {
+ sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
+ sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
+ }
- if (!(file->type & S_IFDIR)) {
- file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
+ !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB)))
+ {
+ if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
+ BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str);
+ }
+ file_draw_string(
+ sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
}
+ sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
+ layout->curr_size = params->thumbnail_size;
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 7147353b3f1..baafefab1f6 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -38,7 +38,7 @@ struct ARegionType;
struct SpaceFile;
/* file_ops.c */
-struct ARegion *file_buttons_region(struct ScrArea *sa);
+struct ARegion *file_tools_region(struct ScrArea *sa);
/* file_draw.c */
#define TILE_BORDER_X (UI_UNIT_X / 4)
@@ -48,24 +48,37 @@ struct ARegion *file_buttons_region(struct ScrArea *sa);
#define IMASEL_BUTTONS_HEIGHT (UI_UNIT_Y * 2)
#define IMASEL_BUTTONS_MARGIN (UI_UNIT_Y / 6)
+#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
+
void file_draw_buttons(const bContext *C, ARegion *ar);
void file_calc_previews(const bContext *C, ARegion *ar);
void file_draw_list(const bContext *C, ARegion *ar);
+void file_draw_check(bContext *C);
void file_draw_check_cb(bContext *C, void *arg1, void *arg2);
bool file_draw_check_exists(SpaceFile *sfile);
/* file_ops.h */
struct wmOperatorType;
struct wmOperator;
-struct wmEvent;
+
+typedef enum WalkSelectDirection {
+ FILE_SELECT_WALK_UP,
+ FILE_SELECT_WALK_DOWN,
+ FILE_SELECT_WALK_LEFT,
+ FILE_SELECT_WALK_RIGHT,
+} WalkSelectDirections;
+
void FILE_OT_highlight(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
+void FILE_OT_select_walk(struct wmOperatorType *ot);
void FILE_OT_select_all_toggle(struct wmOperatorType *ot);
void FILE_OT_select_border(struct wmOperatorType *ot);
void FILE_OT_select_bookmark(struct wmOperatorType *ot);
void FILE_OT_bookmark_add(struct wmOperatorType *ot);
void FILE_OT_bookmark_delete(struct wmOperatorType *ot);
+void FILE_OT_bookmark_cleanup(struct wmOperatorType *ot);
+void FILE_OT_bookmark_move(struct wmOperatorType *ot);
void FILE_OT_reset_recent(wmOperatorType *ot);
void FILE_OT_hidedot(struct wmOperatorType *ot);
void FILE_OT_execute(struct wmOperatorType *ot);
@@ -99,11 +112,10 @@ void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
-float file_shorten_string(char *string, float w, int front);
+void fileselect_file_set(SpaceFile *sfile, const int index);
float file_string_width(const char *str);
float file_font_pointsize(void);
-void file_change_dir(bContext *C, int checkdir);
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file);
int autocomplete_directory(struct bContext *C, char *str, void *arg_v);
int autocomplete_file(struct bContext *C, char *str, void *arg_v);
@@ -111,5 +123,8 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
/* file_panels.c */
void file_panels_register(struct ARegionType *art);
+/* file_utils.c */
+void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
+
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 27d6fabba4e..8347ad87258 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -31,9 +31,11 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
+#include "BLI_linklist.h"
#include "BLO_readfile.h"
+#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
@@ -97,9 +99,9 @@ static void file_deselect_all(SpaceFile *sfile, unsigned int flag)
{
FileSelection sel;
sel.first = 0;
- sel.last = filelist_numfiles(sfile->files) - 1;
+ sel.last = filelist_files_ensure(sfile->files) - 1;
- filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
}
typedef enum FileSelect {
@@ -137,7 +139,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- int numfiles = filelist_numfiles(sfile->files);
+ int numfiles = filelist_files_ensure(sfile->files);
FileSelection sel;
sel = find_file_mouse_rect(sfile, ar, rect);
@@ -150,7 +152,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
if (fill && (sel.last >= 0) && (sel.last < numfiles) ) {
int f = sel.last;
while (f >= 0) {
- if (filelist_is_selected(sfile->files, f, CHECK_ALL) )
+ if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) )
break;
f--;
}
@@ -166,50 +168,118 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
FileSelect retval = FILE_SELECT_NOTHING;
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
- int numfiles = filelist_numfiles(sfile->files);
- struct direntry *file;
+ int numfiles = filelist_files_ensure(sfile->files);
+ const FileDirEntry *file;
/* make the selected file active */
if ((selected_idx >= 0) &&
(selected_idx < numfiles) &&
(file = filelist_file(sfile->files, selected_idx)))
{
+ params->highlight_file = selected_idx;
params->active_file = selected_idx;
- if (S_ISDIR(file->type)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
+
if (do_diropen == false) {
params->file[0] = '\0';
retval = FILE_SELECT_DIR;
}
/* the path is too long and we are not going up! */
- else if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) {
+ else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
// XXX error("Path too long, cannot enter this directory");
}
else {
- if (strcmp(file->relname, "..") == 0) {
+ if (is_parent_dir) {
/* avoids /../../ */
BLI_parent_dir(params->dir);
+
+ if (params->recursion_level > 1) {
+ /* Disable 'dirtree' recursion when going up in tree. */
+ params->recursion_level = 0;
+ filelist_setrecursion(sfile->files, params->recursion_level);
+ }
}
else {
BLI_cleanup_dir(G.main->name, params->dir);
- strcat(params->dir, file->relname);
+ strcat(params->dir, file->relpath);
BLI_add_slash(params->dir);
}
- file_change_dir(C, 0);
+ ED_file_change_dir(C, false);
retval = FILE_SELECT_DIR;
}
}
else {
- if (file->relname) {
- BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
- }
retval = FILE_SELECT_FILE;
}
+ fileselect_file_set(sfile, selected_idx);
}
return retval;
}
+/**
+ * \warning: loops over all files so better use cautiously
+ */
+static bool file_is_any_selected(struct FileList *files)
+{
+ const int numfiles = filelist_files_ensure(files);
+ int i;
+
+ /* Is any file selected ? */
+ for (i = 0; i < numfiles; ++i) {
+ if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * If \a file is outside viewbounds, this adjusts view to make sure it's inside
+ */
+static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const int file)
+{
+ FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+ rctf *cur = &ar->v2d.cur;
+ rcti rect;
+ bool changed = true;
+
+ file_tile_boundbox(ar, layout, file, &rect);
+
+ /* down - also use if tile is higher than viewbounds so view is aligned to file name */
+ if (cur->ymin > rect.ymin || layout->tile_h > ar->winy) {
+ cur->ymin = rect.ymin - (2 * layout->tile_border_y);
+ cur->ymax = cur->ymin + ar->winy;
+ }
+ /* up */
+ else if (cur->ymax < rect.ymax) {
+ cur->ymax = rect.ymax + layout->tile_border_y;
+ cur->ymin = cur->ymax - ar->winy;
+ }
+ /* left - also use if tile is wider than viewbounds so view is aligned to file name */
+ else if (cur->xmin > rect.xmin || layout->tile_w > ar->winx) {
+ cur->xmin = rect.xmin - layout->tile_border_x;
+ cur->xmax = cur->xmin + ar->winx;
+ }
+ /* right */
+ else if (cur->xmax < rect.xmax) {
+ cur->xmax = rect.xmax + (2 * layout->tile_border_x);
+ cur->xmin = cur->xmax - ar->winx;
+ }
+ else {
+ BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax &&
+ cur->ymin <= rect.ymin && cur->ymax >= rect.ymax);
+ changed = false;
+ }
+
+ if (changed) {
+ UI_view2d_curRect_validate(&ar->v2d);
+ }
+}
+
static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
{
@@ -219,25 +289,76 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
/* flag the files as selected in the filelist */
- filelist_select(sfile->files, &sel, select, SELECTED_FILE, check_type);
+ filelist_entries_select_index_range_set(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
/* Don't act on multiple selected files */
if (sel.first != sel.last) select = 0;
/* Do we have a valid selection and are we actually selecting */
- if ((sel.last >= 0) && ((select == FILE_SEL_ADD) || (select == FILE_SEL_TOGGLE))) {
+ if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
/* Check last selection, if selected, act on the file or dir */
- if (filelist_is_selected(sfile->files, sel.last, check_type)) {
+ if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) {
retval = file_select_do(C, sel.last, do_diropen);
}
}
+ if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
+ sfile->params->active_file = -1;
+ }
+ else {
+ ARegion *ar = CTX_wm_region(C);
+ const FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+
+ /* Adjust view to display selection. Doing iterations for first and last
+ * selected item makes view showing as much of the selection possible.
+ * Not really useful if tiles are (almost) bigger than viewbounds though. */
+ if (((layout->flag & FILE_LAYOUT_HOR) && ar->winx > (1.2f * layout->tile_w)) ||
+ ((layout->flag & FILE_LAYOUT_VER) && ar->winy > (2.0f * layout->tile_h)))
+ {
+ file_ensure_inside_viewbounds(ar, sfile, sel.last);
+ file_ensure_inside_viewbounds(ar, sfile, sel.first);
+ }
+ }
+
/* update operator for name change event */
- file_draw_check_cb(C, NULL, NULL);
+ file_draw_check(C);
return retval;
}
+static int file_border_select_find_last_selected(
+ SpaceFile *sfile, ARegion *ar, const FileSelection *sel,
+ const int mouse_xy[2])
+{
+ FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+ rcti bounds_first, bounds_last;
+ int dist_first, dist_last;
+ float mouseco_view[2];
+
+ UI_view2d_region_to_view(&ar->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]);
+
+ file_tile_boundbox(ar, layout, sel->first, &bounds_first);
+ file_tile_boundbox(ar, layout, sel->last, &bounds_last);
+
+ /* are first and last in the same column (horizontal layout)/row (vertical layout)? */
+ if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) ||
+ (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin))
+ {
+ /* use vertical distance */
+ const int my_loc = (int)mouseco_view[1];
+ dist_first = BLI_rcti_length_y(&bounds_first, my_loc);
+ dist_last = BLI_rcti_length_y(&bounds_last, my_loc);
+ }
+ else {
+ /* use horizontal distance */
+ const int mx_loc = (int)mouseco_view[0];
+ dist_first = BLI_rcti_length_x(&bounds_first, mx_loc);
+ dist_last = BLI_rcti_length_x(&bounds_last, mx_loc);
+ }
+
+ return (dist_first < dist_last) ? sel->first : sel->last;
+}
+
static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
@@ -251,24 +372,40 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
result = WM_border_select_modal(C, op, event);
if (result == OPERATOR_RUNNING_MODAL) {
-
WM_operator_properties_border_to_rcti(op, &rect);
BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
sel = file_selection_get(C, &rect, 0);
- if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) {
- file_deselect_all(sfile, HILITED_FILE);
- filelist_select(sfile->files, &sel, FILE_SEL_ADD, HILITED_FILE, CHECK_ALL);
+ if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
+ int idx;
+
+ file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ for (idx = sel.last; idx >= 0; idx--) {
+ const FileDirEntry *file = filelist_file(sfile->files, idx);
+
+ /* dont highlight readonly file (".." or ".") on border select */
+ if (FILENAME_IS_CURRPAR(file->relpath)) {
+ filelist_entry_select_set(sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
+ }
+
+ /* make sure highlight_file is no readonly file */
+ if (sel.last == idx) {
+ params->highlight_file = idx;
+ }
+ }
}
params->sel_first = sel.first; params->sel_last = sel.last;
-
+ params->active_file = file_border_select_find_last_selected(sfile, ar, &sel, event->mval);
}
else {
- params->active_file = -1;
+ params->highlight_file = -1;
params->sel_first = params->sel_last = -1;
- file_deselect_all(sfile, HILITED_FILE);
+ fileselect_file_set(sfile, params->active_file);
+ file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -278,6 +415,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
static int file_border_select_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
rcti rect;
FileSelect ret;
const bool select = (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
@@ -286,14 +424,16 @@ static int file_border_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rcti(op, &rect);
if (!extend) {
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- file_deselect_all(sfile, SELECTED_FILE);
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
}
BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
+
+ /* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
+ filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+
if (FILE_SELECT_DIR == ret) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -340,10 +480,25 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin))
return OPERATOR_CANCELLED;
- /* single select, deselect all selected first */
- if (!extend) file_deselect_all(sfile, SELECTED_FILE);
+ if (sfile && sfile->params) {
+ int idx = sfile->params->highlight_file;
+ int numfiles = filelist_files_ensure(sfile->files);
+
+ if ((idx >= 0) && (idx < numfiles)) {
+ /* single select, deselect all selected first */
+ if (!extend) {
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+ }
+ }
+ }
ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
+
+ if (extend) {
+ /* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
+ filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+
if (FILE_SELECT_DIR == ret)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
else if (FILE_SELECT_FILE == ret)
@@ -377,34 +532,267 @@ void FILE_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/**
+ * \returns true if selection has changed
+ */
+static bool file_walk_select_selection_set(
+ bContext *C, SpaceFile *sfile,
+ const int direction, const int numfiles,
+ const int active_old, const int active_new, const int other_site,
+ const bool has_selection, const bool extend, const bool fill)
+{
+ FileSelectParams *params = sfile->params;
+ struct FileList *files = sfile->files;
+ const int last_sel = params->active_file; /* store old value */
+ int active = active_old; /* could use active_old instead, just for readability */
+ bool deselect = false;
+
+ BLI_assert(params);
+
+ if (has_selection) {
+ if (extend &&
+ filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
+ filelist_entry_select_index_get(files, active_new, CHECK_ALL))
+ {
+ /* conditions for deselecting: initial file is selected, new file is
+ * selected and either other_side isn't selected/found or we use fill */
+ deselect = (fill || other_site == -1 ||
+ !filelist_entry_select_index_get(files, other_site, CHECK_ALL));
+
+ /* don't change highlight_file here since we either want to deselect active or we want to
+ * walk through a block of selected files without selecting/deselecting anything */
+ params->active_file = active_new;
+ /* but we want to change active if we use fill (needed to get correct selection bounds) */
+ if (deselect && fill) {
+ active = active_new;
+ }
+ }
+ else {
+ /* regular selection change */
+ params->active_file = active = active_new;
+ }
+ }
+ else {
+ /* select last file */
+ if (ELEM(direction, FILE_SELECT_WALK_UP, FILE_SELECT_WALK_LEFT)) {
+ params->active_file = active = numfiles - 1;
+ }
+ /* select first file */
+ else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) {
+ params->active_file = active = extend ? 1 : 0;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (active < 0) {
+ return false;
+ }
+
+ if (extend) {
+ /* highlight the active walker file for extended selection for better visual feedback */
+ params->highlight_file = params->active_file;
+
+ /* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
+ filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+ else {
+ /* deselect all first */
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+
+ /* highlight file under mouse pos */
+ params->highlight_file = -1;
+ WM_event_add_mousemove(C);
+ }
+
+ /* do the actual selection */
+ if (fill) {
+ FileSelection sel = { MIN2(active, last_sel), MAX2(active, last_sel) };
+
+ /* clamping selection to not include '..' parent entry */
+ if (sel.first == 0) {
+ sel.first = 1;
+ }
+
+ /* fill selection between last and first selected file */
+ filelist_entries_select_index_range_set(
+ files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ /* entire sel is cleared here, so select active again */
+ if (deselect) {
+ filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+ }
+ else {
+ filelist_entry_select_index_set(
+ files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+
+ BLI_assert(IN_RANGE(active, -1, numfiles));
+ fileselect_file_set(sfile, params->active_file);
+
+ /* ensure newly selected file is inside viewbounds */
+ file_ensure_inside_viewbounds(CTX_wm_region(C), sfile, params->active_file);
+
+ /* selection changed */
+ return true;
+}
+
+/**
+ * \returns true if selection has changed
+ */
+static bool file_walk_select_do(
+ bContext *C, SpaceFile *sfile,
+ FileSelectParams *params, const int direction,
+ const bool extend, const bool fill)
+{
+ struct FileList *files = sfile->files;
+ const int numfiles = filelist_files_ensure(files);
+ const bool has_selection = file_is_any_selected(files);
+ const int active_old = params->active_file;
+ int active_new = -1;
+ int other_site = -1; /* file on the other site of active_old */
+
+
+ /* *** get all needed files for handling selection *** */
+
+ if (has_selection) {
+ ARegion *ar = CTX_wm_region(C);
+ FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+ const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns;
+
+ if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT))
+ {
+ active_new = active_old - 1;
+ other_site = active_old + 1;
+ }
+ else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_DOWN) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_RIGHT))
+ {
+ active_new = active_old + 1;
+ other_site = active_old - 1;
+ }
+ else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_LEFT) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_UP))
+ {
+ active_new = active_old - idx_shift;
+ other_site = active_old + idx_shift;
+ }
+ else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_RIGHT) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_DOWN))
+ {
+
+ active_new = active_old + idx_shift;
+ other_site = active_old - idx_shift;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (!IN_RANGE(active_new, 0, numfiles)) {
+ if (extend) {
+ /* extend to invalid file -> abort */
+ return false;
+ }
+ /* if we don't extend, selecting '..' (index == 0) is allowed so
+ * using key selection to go to parent directory is possible */
+ else if (active_new != 0) {
+ /* select initial file */
+ active_new = active_old;
+ }
+ }
+ if (!IN_RANGE(other_site, 0, numfiles)) {
+ other_site = -1;
+ }
+ }
+
+ return file_walk_select_selection_set(
+ C, sfile, direction, numfiles, active_old, active_new, other_site, has_selection, extend, fill);
+}
+
+static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
+ FileSelectParams *params = sfile->params;
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool fill = RNA_boolean_get(op->ptr, "fill");
+
+ if (file_walk_select_do(C, sfile, params, direction, extend, fill)) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void FILE_OT_select_walk(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {FILE_SELECT_WALK_UP, "UP", 0, "Prev", ""},
+ {FILE_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""},
+ {FILE_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""},
+ {FILE_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Walk Select/Deselect File";
+ ot->description = "Select/Deselect files by walking through them";
+ ot->idname = "FILE_OT_select_walk";
+
+ /* api callbacks */
+ ot->invoke = file_walk_select_invoke;
+ ot->poll = ED_operator_file_active;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "direction", direction_items, 0, "Walk Direction",
+ "Select/Deselect file in this direction");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend",
+ "Extend selection instead of deselecting everything first");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *sa = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelection sel;
- int numfiles = filelist_numfiles(sfile->files);
- int i;
- bool is_selected = false;
+ const int numfiles = filelist_files_ensure(sfile->files);
+ const bool has_selection = file_is_any_selected(sfile->files);
sel.first = 0;
sel.last = numfiles - 1;
- /* Is any file selected ? */
- for (i = 0; i < numfiles; ++i) {
- if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
- is_selected = true;
- break;
- }
- }
/* select all only if previously no file was selected */
- if (is_selected) {
- filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, SELECTED_FILE, CHECK_ALL);
+ if (has_selection) {
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ sfile->params->active_file = -1;
}
else {
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
- filelist_select(sfile->files, &sel, FILE_SEL_ADD, SELECTED_FILE, check_type);
+ int i;
+
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type);
+
+ /* set active_file to first selected */
+ for (i = 0; i < numfiles; i++) {
+ if (filelist_entry_select_index_get(sfile->files, i, check_type)) {
+ sfile->params->active_file = i;
+ break;
+ }
+ }
}
+
+ file_draw_check(C);
+ WM_event_add_mousemove(C);
ED_area_tag_redraw(sa);
+
return OPERATOR_FINISHED;
}
@@ -424,18 +812,20 @@ void FILE_OT_select_all_toggle(wmOperatorType *ot)
/* ---------- BOOKMARKS ----------- */
+/* Note we could get rid of this one, but it's used by some addon so... Does not hurt keeping it around for now. */
static int bookmark_select_exec(bContext *C, wmOperator *op)
{
SpaceFile *sfile = CTX_wm_space_file(C);
+ PropertyRNA *prop;
- if (RNA_struct_find_property(op->ptr, "dir")) {
+ if ((prop = RNA_struct_find_property(op->ptr, "dir"))) {
char entry[256];
FileSelectParams *params = sfile->params;
- RNA_string_get(op->ptr, "dir", entry);
+ RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -465,17 +855,18 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *sa = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- struct FSMenu *fsmenu = fsmenu_get();
+ struct FSMenu *fsmenu = ED_fsmenu_get();
struct FileSelectParams *params = ED_fileselect_get_params(sfile);
if (params->dir[0] != '\0') {
char name[FILE_MAX];
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, FS_INSERT_SAVE);
- BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, FS_INSERT_SAVE);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
}
+ ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
return OPERATOR_FINISHED;
}
@@ -495,17 +886,27 @@ void FILE_OT_bookmark_add(wmOperatorType *ot)
static int bookmark_delete_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
- struct FSMenu *fsmenu = fsmenu_get();
- int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
-
- if (RNA_struct_find_property(op->ptr, "index")) {
- int index = RNA_int_get(op->ptr, "index");
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index");
+
+ if (prop) {
+ int index;
+ if (RNA_property_is_set(op->ptr, prop)) {
+ index = RNA_property_int_get(op->ptr, prop);
+ }
+ else { /* if index unset, use active bookmark... */
+ index = sfile->bookmarknr;
+ }
if ((index > -1) && (index < nentries)) {
char name[FILE_MAX];
fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
- BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
+ ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
}
}
@@ -531,19 +932,150 @@ void FILE_OT_bookmark_delete(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ScrArea *sa = CTX_wm_area(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
+ int index;
+ bool changed = false;
+
+ for (index = 0; fsme; fsme = fsme_next) {
+ fsme_next = fsme->next;
+
+ if (!BLI_is_dir(fsme->path)) {
+ fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
+ changed = true;
+ }
+ else {
+ index++;
+ }
+ }
+
+ if (changed) {
+ char name[FILE_MAX];
+
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(fsmenu, name);
+ fsmenu_refresh_bookmarks_status(fsmenu);
+ ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(sa);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_bookmark_cleanup(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cleanup Bookmarks";
+ ot->description = "Delete all invalid bookmarks";
+ ot->idname = "FILE_OT_bookmark_cleanup";
+
+ /* api callbacks */
+ ot->exec = bookmark_cleanup_exec;
+ ot->poll = ED_operator_file_active;
+
+ /* properties */
+}
+
+enum {
+ FILE_BOOKMARK_MOVE_TOP = -2,
+ FILE_BOOKMARK_MOVE_UP = -1,
+ FILE_BOOKMARK_MOVE_DOWN = 1,
+ FILE_BOOKMARK_MOVE_BOTTOM = 2,
+};
+
+static int bookmark_move_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
+ const struct FSMenuEntry *fsmentry_org = fsmentry;
+
+ char fname[FILE_MAX];
+
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
+ const int act_index = sfile->bookmarknr;
+ int new_index;
+
+ if (totitems < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (direction) {
+ case FILE_BOOKMARK_MOVE_TOP:
+ new_index = 0;
+ break;
+ case FILE_BOOKMARK_MOVE_BOTTOM:
+ new_index = totitems - 1;
+ break;
+ case FILE_BOOKMARK_MOVE_UP:
+ case FILE_BOOKMARK_MOVE_DOWN:
+ default:
+ new_index = (totitems + act_index + direction) % totitems;
+ break;
+ }
+
+ if (new_index == act_index) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index);
+ if (fsmentry != fsmentry_org) {
+ ED_fsmenu_set_category(fsmenu, FS_CATEGORY_BOOKMARKS, fsmentry);
+ }
+
+ /* Need to update active bookmark number. */
+ sfile->bookmarknr = new_index;
+
+ BLI_make_file_string("/", fname, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(fsmenu, fname);
+
+ ED_area_tag_redraw(sa);
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_bookmark_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
+ {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Move Bookmark";
+ ot->idname = "FILE_OT_bookmark_move";
+ ot->description = "Move the active bookmark up/down in the list";
+
+ /* api callbacks */
+ ot->poll = ED_operator_file_active;
+ ot->exec = bookmark_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER; /* No undo! */
+
+ RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *sa = CTX_wm_area(C);
char name[FILE_MAX];
- struct FSMenu *fsmenu = fsmenu_get();
+ struct FSMenu *fsmenu = ED_fsmenu_get();
- while (fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) {
+ while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) {
fsmenu_remove_entry(fsmenu, FS_CATEGORY_RECENT, 0);
}
- BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
ED_area_tag_redraw(sa);
-
+
return OPERATOR_FINISHED;
}
@@ -568,31 +1100,31 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
if (sfile == NULL || sfile->files == NULL) return 0;
- numfiles = filelist_numfiles(sfile->files);
+ numfiles = filelist_files_ensure(sfile->files);
params = ED_fileselect_get_params(sfile);
- origfile = params->active_file;
+ origfile = params->highlight_file;
mx -= ar->winrct.xmin;
my -= ar->winrct.ymin;
if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) {
float fx, fy;
- int active_file;
+ int highlight_file;
UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
- active_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
+ highlight_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
- if ((active_file >= 0) && (active_file < numfiles))
- params->active_file = active_file;
+ if ((highlight_file >= 0) && (highlight_file < numfiles))
+ params->highlight_file = highlight_file;
else
- params->active_file = -1;
+ params->highlight_file = -1;
}
else
- params->active_file = -1;
+ params->highlight_file = -1;
- return (params->active_file != origfile);
+ return (params->highlight_file != origfile);
}
static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -658,65 +1190,67 @@ void FILE_OT_cancel(struct wmOperatorType *ot)
void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
{
+ PropertyRNA *prop;
+
BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */
- if (RNA_struct_find_property(op->ptr, "relative_path")) {
- if (RNA_boolean_get(op->ptr, "relative_path")) {
+
+ if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
BLI_path_rel(filepath, G.main->name);
}
}
- if (RNA_struct_find_property(op->ptr, "filename")) {
- RNA_string_set(op->ptr, "filename", sfile->params->file);
+ if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
+ RNA_property_string_set(op->ptr, prop, sfile->params->file);
}
- if (RNA_struct_find_property(op->ptr, "directory")) {
- RNA_string_set(op->ptr, "directory", sfile->params->dir);
+ if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
+ RNA_property_string_set(op->ptr, prop, sfile->params->dir);
}
- if (RNA_struct_find_property(op->ptr, "filepath")) {
- RNA_string_set(op->ptr, "filepath", filepath);
+ if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
+ RNA_property_string_set(op->ptr, prop, filepath);
}
/* some ops have multiple files to select */
/* this is called on operators check() so clear collections first since
* they may be already set. */
{
- PointerRNA itemptr;
- PropertyRNA *prop_files = RNA_struct_find_property(op->ptr, "files");
- PropertyRNA *prop_dirs = RNA_struct_find_property(op->ptr, "dirs");
- int i, numfiles = filelist_numfiles(sfile->files);
+ int i, numfiles = filelist_files_ensure(sfile->files);
- if (prop_files) {
+ if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
+ PointerRNA itemptr;
int num_files = 0;
- RNA_property_collection_clear(op->ptr, prop_files);
+ RNA_property_collection_clear(op->ptr, prop);
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
- struct direntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop_files, &itemptr);
- RNA_string_set(&itemptr, "name", file->relname);
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
+ FileDirEntry *file = filelist_file(sfile->files, i);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
num_files++;
}
}
/* make sure the file specified in the filename button is added even if no files selected */
if (0 == num_files) {
- RNA_property_collection_add(op->ptr, prop_files, &itemptr);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
RNA_string_set(&itemptr, "name", sfile->params->file);
}
}
- if (prop_dirs) {
+ if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
+ PointerRNA itemptr;
int num_dirs = 0;
- RNA_property_collection_clear(op->ptr, prop_dirs);
+ RNA_property_collection_clear(op->ptr, prop);
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_DIRS)) {
- struct direntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
- RNA_string_set(&itemptr, "name", file->relname);
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) {
+ FileDirEntry *file = filelist_file(sfile->files, i);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
num_dirs++;
}
}
/* make sure the directory specified in the button is added even if no directory selected */
if (0 == num_dirs) {
- RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
RNA_string_set(&itemptr, "name", sfile->params->dir);
}
}
@@ -751,7 +1285,7 @@ void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
/* XXX, files and dirs updates missing, not really so important though */
}
-void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
+void file_draw_check(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
@@ -771,11 +1305,18 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
}
}
+/* for use with; UI_block_func_set */
+void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
+{
+ file_draw_check(C);
+}
+
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- if (RNA_struct_find_property(sfile->op->ptr, "check_existing")) {
- if (RNA_boolean_get(sfile->op->ptr, "check_existing")) {
+ PropertyRNA *prop;
+ if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) {
+ if (RNA_property_boolean_get(sfile->op->ptr, prop)) {
char filepath[FILE_MAX];
BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
if (BLI_is_file(filepath)) {
@@ -788,23 +1329,42 @@ bool file_draw_check_exists(SpaceFile *sfile)
return false;
}
-/* sends events now, so things get handled on windowqueue level */
int file_exec(bContext *C, wmOperator *exec_op)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
char filepath[FILE_MAX];
-
- if (sfile->op) {
+
+ /* directory change */
+ if (file && (file->typeflag & FILE_TYPE_DIR)) {
+ if (!file->relpath) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (FILENAME_IS_PARENT(file->relpath)) {
+ BLI_parent_dir(sfile->params->dir);
+ }
+ else {
+ BLI_cleanup_dir(G.main->name, sfile->params->dir);
+ strcat(sfile->params->dir, file->relpath);
+ BLI_add_slash(sfile->params->dir);
+ }
+
+ ED_file_change_dir(C, false);
+ }
+ /* opening file - sends events now, so things get handled on windowqueue level */
+ else if (sfile->op) {
wmOperator *op = sfile->op;
/* when used as a macro, for doubleclick,
* to prevent closing when doubleclicking on .. item */
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
+ const int numfiles = filelist_files_ensure(sfile->files);
int i, active = 0;
- for (i = 0; i < filelist_numfiles(sfile->files); i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
+ for (i = 0; i < numfiles; i++) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
active = 1;
break;
}
@@ -818,15 +1378,17 @@ int file_exec(bContext *C, wmOperator *exec_op)
file_sfile_to_operator(op, sfile, filepath);
if (BLI_exists(sfile->params->dir)) {
- fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, FS_INSERT_SAVE | FS_INSERT_FIRST);
+ fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL,
+ FS_INSERT_SAVE | FS_INSERT_FIRST);
}
- BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
- fsmenu_write_file(fsmenu_get(), filepath);
+ BLI_make_file_string(G.main->name, filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(ED_fsmenu_get(), filepath);
WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
}
-
+
return OPERATOR_FINISHED;
}
@@ -859,16 +1421,21 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
BLI_cleanup_dir(G.main->name, sfile->params->dir);
/* if not browsing in .blend file, we still want to check whether the path is a directory */
if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX], tgroup[FILE_MAX];
- if (BLO_is_a_library(sfile->params->dir, tdir, tgroup)) {
- file_change_dir(C, 0);
+ char tdir[FILE_MAX];
+ if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
+ ED_file_change_dir(C, false);
}
else {
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
}
else {
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
+ }
+ if (sfile->params->recursion_level > 1) {
+ /* Disable 'dirtree' recursion when going up in tree. */
+ sfile->params->recursion_level = 0;
+ filelist_setrecursion(sfile->files, sfile->params->recursion_level);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -896,9 +1463,10 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- struct FSMenu *fsmenu = fsmenu_get();
+ ScrArea *sa = CTX_wm_area(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
/* refresh system directory menu */
fsmenu_refresh_system_category(fsmenu);
@@ -933,7 +1501,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -965,7 +1533,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -988,11 +1556,11 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata)
return OPERATOR_PASS_THROUGH;
- numfiles = filelist_numfiles(sfile->files);
+ numfiles = filelist_files_ensure(sfile->files);
/* check if we are editing a name */
for (i = 0; i < numfiles; ++i) {
- if (filelist_is_selected(sfile->files, i, CHECK_ALL) ) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) ) {
edit_idx = i;
break;
}
@@ -1110,10 +1678,12 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
{
char name[FILE_MAXFILE];
char path[FILE_MAX];
- int generate_name = 1;
+ bool generate_name = true;
+ PropertyRNA *prop;
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ ScrArea *sa = CTX_wm_area(C);
if (!sfile->params) {
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
@@ -1122,9 +1692,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
path[0] = '\0';
- if (RNA_struct_find_property(op->ptr, "directory")) {
- RNA_string_get(op->ptr, "directory", path);
- if (path[0] != '\0') generate_name = 0;
+ if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
+ RNA_property_string_get(op->ptr, prop, path);
+ if (path[0] != '\0') {
+ generate_name = false;
+ }
}
if (generate_name) {
@@ -1134,10 +1706,23 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
}
+ else { /* We assume we are able to generate a valid name! */
+ char org_path[FILE_MAX];
+
+ BLI_strncpy(org_path, path, sizeof(org_path));
+ if (BLI_path_make_safe(path)) {
+ BKE_reportf(op->reports, RPT_WARNING, "'%s' given path is OS-invalid, creating '%s' path instead",
+ org_path, path);
+ }
+ }
/* create the file */
- BLI_dir_create_recursive(path);
+ if (!BLI_dir_create_recursive(path)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not create new folder");
+ return OPERATOR_CANCELLED;
+ }
+ /* Should no more be needed, now that BLI_dir_create_recursive returns a success state - but kept just in case. */
if (!BLI_exists(path)) {
BKE_report(op->reports, RPT_ERROR, "Could not create new folder");
return OPERATOR_CANCELLED;
@@ -1151,11 +1736,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
sfile->scroll_offset = 0;
/* reload dir to make sure we're seeing what's in the directory */
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1185,6 +1770,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
}
+/* TODO This should go to BLI_path_utils. */
static void file_expand_directory(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -1197,7 +1783,7 @@ static void file_expand_directory(bContext *C)
else if (sfile->params->dir[0] == '~') {
char tmpstr[sizeof(sfile->params->dir) - 1];
BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr));
- BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BLI_getDefaultDocumentFolder(), tmpstr);
+ BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr);
}
else if (sfile->params->dir[0] == '\0')
@@ -1225,6 +1811,7 @@ static void file_expand_directory(bContext *C)
}
}
+/* TODO check we still need this, it's annoying to have OS-specific code here... :/ */
#if defined(WIN32)
static bool can_create_dir(const char *dir)
{
@@ -1260,7 +1847,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
if (BLI_exists(sfile->params->dir)) {
/* if directory exists, enter it immediately */
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1311,6 +1898,9 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
matches = file_select_match(sfile, sfile->params->file, matched_file);
+ /* *After* file_select_match! */
+ BLI_filename_make_safe(sfile->params->file);
+
if (matches) {
/* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
sfile->params->file[0] = '\0';
@@ -1329,23 +1919,26 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX], tgroup[FILE_MAX];
+ char tdir[FILE_MAX];
BLI_add_slash(filepath);
- if (BLO_is_a_library(filepath, tdir, tgroup)) {
+ if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- file_change_dir(C, 0);
+ ED_file_change_dir(C, false);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
}
}
+ else if (matches > 1) {
+ file_draw_check(C);
+ }
}
}
@@ -1365,10 +1958,11 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ ScrArea *sa = CTX_wm_area(C);
if (sfile->params) {
sfile->params->flag ^= FILE_HIDE_DOT;
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1388,37 +1982,37 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_buttons_region(ScrArea *sa)
+ARegion *file_tools_region(ScrArea *sa)
{
ARegion *ar, *arnew;
-
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_CHANNELS)
- return ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL)
+ return ar;
/* add subdiv level; after header */
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_HEADER)
- break;
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
/* is error! */
- if (ar == NULL) return NULL;
-
- arnew = MEM_callocN(sizeof(ARegion), "buttons for file panels");
+ if (ar == NULL)
+ return NULL;
+ arnew = MEM_callocN(sizeof(ARegion), "tools for file");
BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_CHANNELS;
+ arnew->regiontype = RGN_TYPE_TOOLS;
arnew->alignment = RGN_ALIGN_LEFT;
-
- arnew->flag = RGN_FLAG_HIDDEN;
-
+
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, arnew, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
+
return arnew;
}
static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
{
ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_buttons_region(sa);
+ ARegion *ar = file_tools_region(sa);
if (ar)
ED_region_toggle_hidden(C, ar);
@@ -1448,7 +2042,7 @@ static int file_filenum_exec(bContext *C, wmOperator *op)
if (sfile->params && (inc != 0)) {
BLI_newname(sfile->params->file, inc);
ED_area_tag_redraw(sa);
- file_draw_check_cb(C, NULL, NULL);
+ file_draw_check(C);
// WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -1477,12 +2071,12 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
if (sfile->params) {
- int idx = sfile->params->active_file;
- int numfiles = filelist_numfiles(sfile->files);
- if ( (0 <= idx) && (idx < numfiles) ) {
- struct direntry *file = filelist_file(sfile->files, idx);
- filelist_select_file(sfile->files, idx, FILE_SEL_ADD, EDITING_FILE, CHECK_ALL);
- BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
+ int idx = sfile->params->highlight_file;
+ int numfiles = filelist_files_ensure(sfile->files);
+ if ((0 <= idx) && (idx < numfiles)) {
+ FileDirEntry *file = filelist_file(sfile->files, idx);
+ filelist_entry_select_index_set(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
+ BLI_strncpy(sfile->params->renameedit, file->relpath, FILE_MAXFILE);
sfile->params->renamefile[0] = '\0';
}
ED_area_tag_redraw(sa);
@@ -1494,20 +2088,34 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
static int file_rename_poll(bContext *C)
{
- int poll = ED_operator_file_active(C);
+ bool poll = ED_operator_file_active(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
- if (sfile->params->active_file < 0) {
- poll = 0;
+ int idx = sfile->params->highlight_file;
+ int numfiles = filelist_files_ensure(sfile->files);
+
+ if ((0 <= idx) && (idx < numfiles)) {
+ FileDirEntry *file = filelist_file(sfile->files, idx);
+ if (FILENAME_IS_CURRPAR(file->relpath)) {
+ poll = false;
+ }
+ }
+
+ if (sfile->params->highlight_file < 0) {
+ poll = false;
}
else {
- char dir[FILE_MAX], group[FILE_MAX];
- if (filelist_islibrary(sfile->files, dir, group)) poll = 0;
+ char dir[FILE_MAX];
+ if (filelist_islibrary(sfile->files, dir, NULL)) {
+ poll = false;
+ }
}
}
- else
- poll = 0;
+ else {
+ poll = false;
+ }
+
return poll;
}
@@ -1530,14 +2138,14 @@ static int file_delete_poll(bContext *C)
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
- char dir[FILE_MAX], group[FILE_MAX];
- int numfiles = filelist_numfiles(sfile->files);
+ char dir[FILE_MAX];
+ int numfiles = filelist_files_ensure(sfile->files);
int i;
int num_selected = 0;
- if (filelist_islibrary(sfile->files, dir, group)) poll = 0;
+ if (filelist_islibrary(sfile->files, dir, NULL)) poll = 0;
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
num_selected++;
}
}
@@ -1556,19 +2164,20 @@ int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
char str[FILE_MAX];
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- struct direntry *file;
- int numfiles = filelist_numfiles(sfile->files);
+ ScrArea *sa = CTX_wm_area(C);
+ FileDirEntry *file;
+ int numfiles = filelist_files_ensure(sfile->files);
int i;
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
- BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
+ BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relpath);
BLI_delete(str, false, false);
}
}
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 8fad17e1210..7acf2564fb2 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -34,7 +34,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -44,6 +44,8 @@
#include "RNA_access.h"
+#include "ED_fileselect.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -55,140 +57,6 @@
#include <string.h>
-static void file_panel_cb(bContext *C, void *arg_entry, void *UNUSED(arg_v))
-{
- wmOperatorType *ot = WM_operatortype_find("FILE_OT_select_bookmark", false);
- PointerRNA ptr;
- const char *entry = (char *)arg_entry;
-
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_string_set(&ptr, "dir", entry);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_REGION_WIN, &ptr);
- WM_operator_properties_free(&ptr);
-}
-
-static void file_panel_category(const bContext *C, Panel *pa, FSMenuCategory category, short *nr, int icon, int allow_delete)
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
- uiBlock *block;
- uiBut *but;
- uiLayout *box, *col;
- struct FSMenu *fsmenu = fsmenu_get();
- int i, nentries = fsmenu_get_nentries(fsmenu, category);
-
- /* reset each time */
- *nr = -1;
-
- /* hide if no entries */
- if (nentries == 0)
- return;
-
- /* layout */
- uiLayoutSetAlignment(pa->layout, UI_LAYOUT_ALIGN_LEFT);
- block = uiLayoutGetBlock(pa->layout);
- box = uiLayoutBox(pa->layout);
- col = uiLayoutColumn(box, true);
-
- for (i = 0; i < nentries; ++i) {
- char dir[FILE_MAX];
- char temp[FILE_MAX];
- uiLayout *layout = uiLayoutRow(col, false);
- char *entry;
-
- entry = fsmenu_get_entry(fsmenu, category, i);
-
- /* set this list item as active if we have a match */
- if (sfile->params) {
- if (BLI_path_cmp(sfile->params->dir, entry) == 0) {
- *nr = i;
- }
- }
-
- /* create nice bookmark name, shows last directory in the full path currently */
- BLI_strncpy(temp, entry, FILE_MAX);
- BLI_add_slash(temp);
- BLI_getlastdir(temp, dir, FILE_MAX);
- BLI_del_slash(dir);
-
- if (dir[0] == 0)
- BLI_strncpy(dir, entry, FILE_MAX);
-
- /* create list item */
- but = uiDefIconTextButS(block, LISTROW, 0, icon, dir, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nr, 0, i, 0, 0, entry);
- uiButSetFunc(but, file_panel_cb, entry, NULL);
- uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
- uiButSetDrawFlag(but, UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT);
-
- /* create delete button */
- if (allow_delete && fsmenu_can_save(fsmenu, category, i)) {
- uiBlockSetEmboss(block, UI_EMBOSSN);
- uiItemIntO(layout, "", ICON_X, "FILE_OT_bookmark_delete", "index", i);
- uiBlockSetEmboss(block, UI_EMBOSS);
- }
- }
-}
-
-static void file_panel_system(const bContext *C, Panel *pa)
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- if (sfile)
- file_panel_category(C, pa, FS_CATEGORY_SYSTEM, &sfile->systemnr, ICON_DISK_DRIVE, 0);
-}
-
-static int file_panel_system_bookmarks_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
- return (sfile && !(U.uiflag & USER_HIDE_SYSTEM_BOOKMARKS));
-}
-
-static void file_panel_system_bookmarks(const bContext *C, Panel *pa)
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- if (sfile && !(U.uiflag & USER_HIDE_SYSTEM_BOOKMARKS)) {
- file_panel_category(C, pa, FS_CATEGORY_SYSTEM_BOOKMARKS, &sfile->systemnr, ICON_BOOKMARKS, 0);
- }
-
-}
-
-static void file_panel_bookmarks(const bContext *C, Panel *pa)
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
- uiLayout *row;
-
- if (sfile) {
- row = uiLayoutRow(pa->layout, false);
- uiItemO(row, IFACE_("Add"), ICON_ZOOMIN, "file.bookmark_add");
- uiItemL(row, NULL, ICON_NONE);
-
- file_panel_category(C, pa, FS_CATEGORY_BOOKMARKS, &sfile->bookmarknr, ICON_BOOKMARKS, 1);
- }
-}
-
-static int file_panel_recent_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
- return (sfile && !(U.uiflag & USER_HIDE_RECENT));
-}
-
-static void file_panel_recent(const bContext *C, Panel *pa)
-{
- SpaceFile *sfile = CTX_wm_space_file(C);
- uiLayout *row;
-
- if (sfile) {
- if (!(U.uiflag & USER_HIDE_RECENT)) {
- row = uiLayoutRow(pa->layout, false);
- uiItemO(row, IFACE_("Reset"), ICON_X, "file.reset_recent");
- uiItemL(row, NULL, ICON_NONE);
-
- file_panel_category(C, pa, FS_CATEGORY_RECENT, &sfile->recentnr, ICON_FILE_FOLDER, 0);
- }
- }
-}
-
-
static int file_panel_operator_poll(const bContext *C, PanelType *UNUSED(pt))
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -217,52 +85,22 @@ static void file_panel_operator(const bContext *C, Panel *pa)
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
// int empty = 1, flag;
-
- uiBlockSetFunc(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL);
+
+ UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL);
uiLayoutOperatorButs(C, pa->layout, op, file_panel_check_prop, '\0', UI_LAYOUT_OP_SHOW_EMPTY);
- uiBlockSetFunc(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
+ UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
}
void file_panels_register(ARegionType *art)
{
PanelType *pt;
- pt = MEM_callocN(sizeof(PanelType), "spacetype file system directories");
- strcpy(pt->idname, "FILE_PT_system");
- strcpy(pt->label, N_("System"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = file_panel_system;
- BLI_addtail(&art->paneltypes, pt);
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype file system bookmarks");
- strcpy(pt->idname, "FILE_PT_system_bookmarks");
- strcpy(pt->label, N_("System Bookmarks"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = file_panel_system_bookmarks;
- pt->poll = file_panel_system_bookmarks_poll;
- BLI_addtail(&art->paneltypes, pt);
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype file bookmarks");
- strcpy(pt->idname, "FILE_PT_bookmarks");
- strcpy(pt->label, N_("Bookmarks"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = file_panel_bookmarks;
- BLI_addtail(&art->paneltypes, pt);
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype file recent directories");
- strcpy(pt->idname, "FILE_PT_recent");
- strcpy(pt->label, N_("Recent"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = file_panel_recent;
- pt->poll = file_panel_recent_poll;
- BLI_addtail(&art->paneltypes, pt);
-
pt = MEM_callocN(sizeof(PanelType), "spacetype file operator properties");
strcpy(pt->idname, "FILE_PT_operator");
strcpy(pt->label, N_("Operator"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->poll = file_panel_operator_poll;
pt->draw_header = file_panel_operator_header;
pt->draw = file_panel_operator;
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
new file mode 100644
index 00000000000..3c007f25da3
--- /dev/null
+++ b/source/blender/editors/space_file/file_utils.c
@@ -0,0 +1,47 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_file/file_utils.c
+ * \ingroup spfile
+ */
+
+#include "BLI_rect.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+#include "ED_fileselect.h"
+
+#include "WM_types.h"
+
+#include "file_intern.h"
+
+
+void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds)
+{
+ int xmin, ymax;
+
+ ED_fileselect_layout_tilepos(layout, file, &xmin, &ymax);
+ ymax = (int)ar->v2d.tot.ymax - ymax; /* real, view space ymax */
+ BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
+ ymax - layout->tile_h - layout->tile_border_y, ymax);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 871abbda48a..0d1aff09e9c 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -35,19 +35,29 @@
#include <stdlib.h>
#include <math.h>
#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
#ifndef WIN32
-#include <unistd.h>
+# include <unistd.h>
#else
-#include <io.h>
-#include <direct.h>
+# include <io.h>
+# include <direct.h>
#endif
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_fnmatch.h"
+#include "BLI_ghash.h"
+#include "BLI_hash_md5.h"
#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_stack.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
-#include "BLI_fileops_types.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -57,15 +67,15 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_icons.h"
+#include "BKE_idcode.h"
#include "BKE_main.h"
-#include "BKE_report.h"
#include "BLO_readfile.h"
-#include "BKE_idcode.h"
#include "DNA_space_types.h"
-#include "ED_fileselect.h"
#include "ED_datafiles.h"
+#include "ED_fileselect.h"
+#include "ED_screen.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -77,315 +87,687 @@
#include "WM_types.h"
#include "UI_resources.h"
+#include "UI_interface_icons.h"
+
+#include "atomic_ops.h"
#include "filelist.h"
-struct FileList;
-typedef struct FileImage {
- struct FileImage *next, *prev;
+/* ----------------- FOLDERLIST (previous/next) -------------- */
+
+typedef struct FolderList {
+ struct FolderList *next, *prev;
+ char *foldername;
+} FolderList;
+
+ListBase *folderlist_new(void)
+{
+ ListBase *p = MEM_callocN(sizeof(*p), __func__);
+ return p;
+}
+
+void folderlist_popdir(struct ListBase *folderlist, char *dir)
+{
+ const char *prev_dir;
+ struct FolderList *folder;
+ folder = folderlist->last;
+
+ if (folder) {
+ /* remove the current directory */
+ MEM_freeN(folder->foldername);
+ BLI_freelinkN(folderlist, folder);
+
+ folder = folderlist->last;
+ if (folder) {
+ prev_dir = folder->foldername;
+ BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
+ }
+ }
+ /* delete the folder next or use setdir directly before PREVIOUS OP */
+}
+
+void folderlist_pushdir(ListBase *folderlist, const char *dir)
+{
+ struct FolderList *folder, *previous_folder;
+ previous_folder = folderlist->last;
+
+ /* check if already exists */
+ if (previous_folder && previous_folder->foldername) {
+ if (BLI_path_cmp(previous_folder->foldername, dir) == 0) {
+ return;
+ }
+ }
+
+ /* create next folder element */
+ folder = MEM_mallocN(sizeof(*folder), __func__);
+ folder->foldername = BLI_strdup(dir);
+
+ /* add it to the end of the list */
+ BLI_addtail(folderlist, folder);
+}
+
+const char *folderlist_peeklastdir(ListBase *folderlist)
+{
+ struct FolderList *folder;
+
+ if (!folderlist->last)
+ return NULL;
+
+ folder = folderlist->last;
+ return folder->foldername;
+}
+
+int folderlist_clear_next(struct SpaceFile *sfile)
+{
+ struct FolderList *folder;
+
+ /* if there is no folder_next there is nothing we can clear */
+ if (!sfile->folders_next)
+ return 0;
+
+ /* if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next */
+ folder = sfile->folders_prev->last;
+ if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0))
+ return 0;
+
+ /* eventually clear flist->folders_next */
+ return 1;
+}
+
+/* not listbase itself */
+void folderlist_free(ListBase *folderlist)
+{
+ if (folderlist) {
+ FolderList *folder;
+ for (folder = folderlist->first; folder; folder = folder->next)
+ MEM_freeN(folder->foldername);
+ BLI_freelistN(folderlist);
+ }
+}
+
+ListBase *folderlist_duplicate(ListBase *folderlist)
+{
+
+ if (folderlist) {
+ ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__);
+ FolderList *folder;
+
+ BLI_duplicatelist(folderlistn, folderlist);
+
+ for (folder = folderlistn->first; folder; folder = folder->next) {
+ folder->foldername = MEM_dupallocN(folder->foldername);
+ }
+ return folderlistn;
+ }
+ return NULL;
+}
+
+
+/* ------------------FILELIST------------------------ */
+
+typedef struct FileListInternEntry {
+ struct FileListInternEntry *next, *prev;
+
+ char uuid[16]; /* ASSET_UUID_LENGTH */
+
+ int typeflag; /* eFileSel_File_Types */
+ int blentype; /* ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */
+
+ char *relpath;
+ char *name; /* not striclty needed, but used during sorting, avoids to have to recompute it there... */
+
+ BLI_stat_t st;
+} FileListInternEntry;
+
+typedef struct FileListIntern {
+ ListBase entries; /* FileListInternEntry items. */
+ FileListInternEntry **filtered;
+
+ char curr_uuid[16]; /* Used to generate uuid during internal listing. */
+} FileListIntern;
+
+#define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */
+typedef struct FileListEntryCache {
+ size_t size; /* The size of the cache... */
+
+ int flags;
+
+ /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */
+ ListBase cached_entries;
+
+ /* Block cache: all entries between start and end index. used for part of the list on diplay. */
+ FileDirEntry **block_entries;
+ int block_start_index, block_end_index, block_center_index, block_cursor;
+
+ /* Misc cache: random indices, FIFO behavior.
+ * Note: Not 100% sure we actually need that, time will say. */
+ int misc_cursor;
+ int *misc_entries_indices;
+ GHash *misc_entries;
+
+ /* Allows to quickly get a cached entry from its UUID. */
+ GHash *uuids;
+
+ /* Previews handling. */
+ TaskScheduler *previews_scheduler;
+ TaskPool *previews_pool;
+ ThreadQueue *previews_todo;
+ ThreadQueue *previews_done;
+ double previews_timestamp;
+ int previews_pending;
+} FileListEntryCache;
+
+/* FileListCache.flags */
+enum {
+ FLC_IS_INIT = 1 << 0,
+ FLC_PREVIEWS_ACTIVE = 1 << 1,
+};
+
+typedef struct FileListEntryPreview {
char path[FILE_MAX];
unsigned int flags;
int index;
- short done;
ImBuf *img;
-} FileImage;
+} FileListEntryPreview;
-typedef struct ThumbnailJob {
- ListBase loadimages;
- const short *stop;
- const short *do_update;
- struct FileList *filelist;
- ReportList reports;
-} ThumbnailJob;
+typedef struct FileListFilter {
+ unsigned int filter;
+ unsigned int filter_id;
+ char filter_glob[64];
+ char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
+ short flags;
+} FileListFilter;
+
+/* FileListFilter.flags */
+enum {
+ FLF_HIDE_DOT = 1 << 0,
+ FLF_HIDE_PARENT = 1 << 1,
+ FLF_HIDE_LIB_DIR = 1 << 2,
+};
typedef struct FileList {
- struct direntry *filelist;
- int *fidx;
- int numfiles;
- int numfiltered;
- char dir[FILE_MAX];
+ FileDirEntryArr filelist;
+
short prv_w;
short prv_h;
- short hide_dot;
- unsigned int filter;
- char filter_glob[64];
- short changed;
+
+ short flags;
+
+ short sort;
+
+ FileListFilter filter_data;
+
+ struct FileListIntern filelist_intern;
+
+ struct FileListEntryCache filelist_cache;
+
+ /* We need to keep those info outside of actual filelist items, because those are no more persistent
+ * (only generated on demand, and freed as soon as possible).
+ * Persistent part (mere list of paths + stat info) is kept as small as possible, and filebrowser-agnostic.
+ */
+ GHash *selection_state;
+
+ short max_recursion;
+ short recursion_level;
struct BlendHandle *libfiledata;
- short hide_parent;
- void (*readf)(struct FileList *);
- bool (*filterf)(struct direntry *file, const char *dir, unsigned int filter, short hide_dot);
+ /* Set given path as root directory, may change given string in place to a valid value. */
+ void (*checkdirf)(struct FileList *, char *);
+
+ /* Fill filelist (to be called by read job). */
+ void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
+ /* Filter an entry of current filelist. */
+ bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *);
} FileList;
-typedef struct FolderList {
- struct FolderList *next, *prev;
- char *foldername;
-} FolderList;
+/* FileList.flags */
+enum {
+ FL_FORCE_RESET = 1 << 0,
+ FL_IS_READY = 1 << 1,
+ FL_IS_PENDING = 1 << 2,
+ FL_NEED_SORTING = 1 << 3,
+ FL_NEED_FILTERING = 1 << 4,
+};
#define SPECIAL_IMG_SIZE 48
#define SPECIAL_IMG_ROWS 4
#define SPECIAL_IMG_COLS 4
-#define SPECIAL_IMG_FOLDER 0
-#define SPECIAL_IMG_PARENT 1
-#define SPECIAL_IMG_REFRESH 2
-#define SPECIAL_IMG_BLENDFILE 3
-#define SPECIAL_IMG_SOUNDFILE 4
-#define SPECIAL_IMG_MOVIEFILE 5
-#define SPECIAL_IMG_PYTHONFILE 6
-#define SPECIAL_IMG_TEXTFILE 7
-#define SPECIAL_IMG_FONTFILE 8
-#define SPECIAL_IMG_UNKNOWNFILE 9
-#define SPECIAL_IMG_LOADING 10
-#define SPECIAL_IMG_BACKUP 11
-#define SPECIAL_IMG_MAX SPECIAL_IMG_BACKUP + 1
+enum {
+ SPECIAL_IMG_FOLDER = 0,
+ SPECIAL_IMG_PARENT = 1,
+ SPECIAL_IMG_REFRESH = 2,
+ SPECIAL_IMG_BLENDFILE = 3,
+ SPECIAL_IMG_SOUNDFILE = 4,
+ SPECIAL_IMG_MOVIEFILE = 5,
+ SPECIAL_IMG_PYTHONFILE = 6,
+ SPECIAL_IMG_TEXTFILE = 7,
+ SPECIAL_IMG_FONTFILE = 8,
+ SPECIAL_IMG_UNKNOWNFILE = 9,
+ SPECIAL_IMG_LOADING = 10,
+ SPECIAL_IMG_BACKUP = 11,
+ SPECIAL_IMG_MAX
+};
static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX];
-/* ******************* SORT ******************* */
+static void filelist_readjob_main(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
+static void filelist_readjob_lib(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
+static void filelist_readjob_dir(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
-static bool compare_is_directory(const struct direntry *entry)
-{
- /* for library browse .blend files may be treated as directories, but
- * for sorting purposes they should be considered regular files */
- if (S_ISDIR(entry->type))
- return !(entry->flags & (BLENDERFILE | BLENDERFILE_BACKUP));
-
- return false;
-}
+/* helper, could probably go in BKE actually? */
+static int groupname_to_code(const char *group);
+static unsigned int groupname_to_filter_id(const char *group);
-static int compare_name(const void *a1, const void *a2)
-{
- const struct direntry *entry1 = a1, *entry2 = a2;
+static void filelist_filter_clear(FileList *filelist);
+static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
+/* ********** Sort helpers ********** */
+
+static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
+{
/* type is equal to stat.st_mode */
- if (compare_is_directory(entry1)) {
- if (compare_is_directory(entry2) == 0) return (-1);
- }
- else {
- if (compare_is_directory(entry2)) return (1);
- }
- if (S_ISREG(entry1->type)) {
- if (S_ISREG(entry2->type) == 0) return (-1);
+ if (entry1->typeflag & FILE_TYPE_DIR) {
+ if (entry2->typeflag & FILE_TYPE_DIR) {
+ /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs,
+ * then libs (.blend files), then categories in libs. */
+ if (entry1->typeflag & FILE_TYPE_BLENDERLIB) {
+ if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
+ return 1;
+ }
+ }
+ else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) {
+ return -1;
+ }
+ else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ return 1;
+ }
+ }
+ else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ return -1;
+ }
+ }
+ else {
+ return -1;
+ }
}
- else {
- if (S_ISREG(entry2->type)) return (1);
+ else if (entry2->typeflag & FILE_TYPE_DIR) {
+ return 1;
}
- if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
- if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
-
+
/* make sure "." and ".." are always first */
- if (strcmp(entry1->relname, ".") == 0) return (-1);
- if (strcmp(entry2->relname, ".") == 0) return (1);
- if (strcmp(entry1->relname, "..") == 0) return (-1);
- if (strcmp(entry2->relname, "..") == 0) return (1);
+ if (FILENAME_IS_CURRENT(entry1->relpath)) return -1;
+ if (FILENAME_IS_CURRENT(entry2->relpath)) return 1;
+ if (FILENAME_IS_PARENT(entry1->relpath)) return -1;
+ if (FILENAME_IS_PARENT(entry2->relpath)) return 1;
- return (BLI_natstrcmp(entry1->relname, entry2->relname));
+ return 0;
}
-static int compare_date(const void *a1, const void *a2)
+static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
{
- const struct direntry *entry1 = a1, *entry2 = a2;
-
- /* type is equal to stat.st_mode */
+ const FileListInternEntry *entry1 = a1;
+ const FileListInternEntry *entry2 = a2;
+ char *name1, *name2;
+ int ret;
- if (compare_is_directory(entry1)) {
- if (compare_is_directory(entry2) == 0) return (-1);
+ if ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
}
- else {
- if (compare_is_directory(entry2)) return (1);
- }
- if (S_ISREG(entry1->type)) {
- if (S_ISREG(entry2->type) == 0) return (-1);
- }
- else {
- if (S_ISREG(entry2->type)) return (1);
- }
- if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
- if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
- /* make sure "." and ".." are always first */
- if (strcmp(entry1->relname, ".") == 0) return (-1);
- if (strcmp(entry2->relname, ".") == 0) return (1);
- if (strcmp(entry1->relname, "..") == 0) return (-1);
- if (strcmp(entry2->relname, "..") == 0) return (1);
-
- if (entry1->s.st_mtime < entry2->s.st_mtime) return 1;
- if (entry1->s.st_mtime > entry2->s.st_mtime) return -1;
-
- else return BLI_natstrcmp(entry1->relname, entry2->relname);
+ name1 = entry1->name;
+ name2 = entry2->name;
+
+ return BLI_natstrcmp(name1, name2);
}
-static int compare_size(const void *a1, const void *a2)
+static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
{
- const struct direntry *entry1 = a1, *entry2 = a2;
-
- /* type is equal to stat.st_mode */
+ const FileListInternEntry *entry1 = a1;
+ const FileListInternEntry *entry2 = a2;
+ char *name1, *name2;
+ int64_t time1, time2;
+ int ret;
- if (compare_is_directory(entry1)) {
- if (compare_is_directory(entry2) == 0) return (-1);
- }
- else {
- if (compare_is_directory(entry2)) return (1);
- }
- if (S_ISREG(entry1->type)) {
- if (S_ISREG(entry2->type) == 0) return (-1);
- }
- else {
- if (S_ISREG(entry2->type)) return (1);
+ if ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
}
- if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
- if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
-
- /* make sure "." and ".." are always first */
- if (strcmp(entry1->relname, ".") == 0) return (-1);
- if (strcmp(entry2->relname, ".") == 0) return (1);
- if (strcmp(entry1->relname, "..") == 0) return (-1);
- if (strcmp(entry2->relname, "..") == 0) return (1);
- if (entry1->s.st_size < entry2->s.st_size) return 1;
- if (entry1->s.st_size > entry2->s.st_size) return -1;
- else return BLI_natstrcmp(entry1->relname, entry2->relname);
+ time1 = (int64_t)entry1->st.st_mtime;
+ time2 = (int64_t)entry2->st.st_mtime;
+ if (time1 < time2) return 1;
+ if (time1 > time2) return -1;
+
+ name1 = entry1->name;
+ name2 = entry2->name;
+
+ return BLI_natstrcmp(name1, name2);
}
-static int compare_extension(const void *a1, const void *a2)
+static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
{
- const struct direntry *entry1 = a1, *entry2 = a2;
- const char *sufix1, *sufix2;
- const char *nil = "";
+ const FileListInternEntry *entry1 = a1;
+ const FileListInternEntry *entry2 = a2;
+ char *name1, *name2;
+ uint64_t size1, size2;
+ int ret;
- if (!(sufix1 = strstr(entry1->relname, ".blend.gz")))
- sufix1 = strrchr(entry1->relname, '.');
- if (!(sufix2 = strstr(entry2->relname, ".blend.gz")))
- sufix2 = strrchr(entry2->relname, '.');
- if (!sufix1) sufix1 = nil;
- if (!sufix2) sufix2 = nil;
+ if ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
+ }
+
+ size1 = entry1->st.st_size;
+ size2 = entry2->st.st_size;
+ if (size1 < size2) return 1;
+ if (size1 > size2) return -1;
- /* type is equal to stat.st_mode */
+ name1 = entry1->name;
+ name2 = entry2->name;
- if (compare_is_directory(entry1)) {
- if (compare_is_directory(entry2) == 0) return (-1);
+ return BLI_natstrcmp(name1, name2);
+}
+
+static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2)
+{
+ const FileListInternEntry *entry1 = a1;
+ const FileListInternEntry *entry2 = a2;
+ char *name1, *name2;
+ int ret;
+
+ if ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
+ }
+
+ if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) return -1;
+ if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) return 1;
+ if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
+ if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) return 1;
+ if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) return -1;
+ if (entry1->blentype < entry2->blentype) return -1;
+ if (entry1->blentype > entry2->blentype) return 1;
}
else {
- if (compare_is_directory(entry2)) return (1);
+ const char *sufix1, *sufix2;
+
+ if (!(sufix1 = strstr(entry1->relpath, ".blend.gz")))
+ sufix1 = strrchr(entry1->relpath, '.');
+ if (!(sufix2 = strstr(entry2->relpath, ".blend.gz")))
+ sufix2 = strrchr(entry2->relpath, '.');
+ if (!sufix1) sufix1 = "";
+ if (!sufix2) sufix2 = "";
+
+ if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
+ return ret;
+ }
}
- if (S_ISREG(entry1->type)) {
- if (S_ISREG(entry2->type) == 0) return (-1);
+
+ name1 = entry1->name;
+ name2 = entry2->name;
+
+ return BLI_natstrcmp(name1, name2);
+}
+
+void filelist_sort(struct FileList *filelist)
+{
+ if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) {
+ switch (filelist->sort) {
+ case FILE_SORT_ALPHA:
+ BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL);
+ break;
+ case FILE_SORT_TIME:
+ BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL);
+ break;
+ case FILE_SORT_SIZE:
+ BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL);
+ break;
+ case FILE_SORT_EXTENSION:
+ BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL);
+ break;
+ case FILE_SORT_NONE: /* Should never reach this point! */
+ default:
+ BLI_assert(0);
+ }
+
+ filelist_filter_clear(filelist);
+ filelist->flags &= ~FL_NEED_SORTING;
}
- else {
- if (S_ISREG(entry2->type)) return (1);
+}
+
+void filelist_setsorting(struct FileList *filelist, const short sort)
+{
+ if (filelist->sort != sort) {
+ filelist->sort = sort;
+ filelist->flags |= FL_NEED_SORTING;
}
- if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
- if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
-
- /* make sure "." and ".." are always first */
- if (strcmp(entry1->relname, ".") == 0) return (-1);
- if (strcmp(entry2->relname, ".") == 0) return (1);
- if (strcmp(entry1->relname, "..") == 0) return (-1);
- if (strcmp(entry2->relname, "..") == 0) return (1);
-
- return (BLI_strcasecmp(sufix1, sufix2));
}
-static bool is_hidden_file(const char *filename, short hide_dot)
+/* ********** Filter helpers ********** */
+
+static bool is_hidden_file(const char *filename, FileListFilter *filter)
{
+ char *sep = (char *)BLI_last_slash(filename);
bool is_hidden = false;
- if (hide_dot) {
- if (filename[0] == '.' && filename[1] != '.' && filename[1] != 0) {
- is_hidden = 1; /* ignore .file */
- }
- else if (((filename[0] == '.') && (filename[1] == 0))) {
- is_hidden = 1; /* ignore . */
+ if (filter->flags & FLF_HIDE_DOT) {
+ if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') {
+ is_hidden = true; /* ignore .file */
}
else {
int len = strlen(filename);
if ((len > 0) && (filename[len - 1] == '~')) {
- is_hidden = 1; /* ignore file~ */
+ is_hidden = true; /* ignore file~ */
}
}
}
- else {
- if (((filename[0] == '.') && (filename[1] == 0))) {
- is_hidden = 1; /* ignore . */
+ if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) {
+ if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
+ is_hidden = true; /* ignore .. */
+ }
+ }
+ if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) {
+ is_hidden = true; /* ignore . */
+ }
+ /* filename might actually be a piece of path, in which case we have to check all its parts. */
+ if (!is_hidden && sep) {
+ char tmp_filename[FILE_MAX_LIBEXTRA];
+
+ BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename));
+ sep = tmp_filename + (sep - filename);
+ while (sep) {
+ BLI_assert(sep[1] != '\0');
+ if (is_hidden_file(sep + 1, filter)) {
+ is_hidden = true;
+ break;
+ }
+ *sep = '\0';
+ sep = (char *)BLI_last_slash(tmp_filename);
}
}
return is_hidden;
}
-static bool is_filtered_file(struct direntry *file, const char *UNUSED(dir), unsigned int filter, short hide_dot)
+static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter)
{
- bool is_filtered = false;
- if (filter) {
- if (file->flags & filter) {
- is_filtered = 1;
+ bool is_filtered = !is_hidden_file(file->relpath, filter);
+
+ if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ is_filtered = false;
+ }
+ }
+ else {
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ is_filtered = false;
+ }
+ }
}
- else if (file->type & S_IFDIR) {
- if (filter & FOLDERFILE) {
- is_filtered = 1;
+ else {
+ if (!(file->typeflag & filter->filter)) {
+ is_filtered = false;
+ }
+ }
+ if (is_filtered && (filter->filter_search[0] != '\0')) {
+ if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
+ is_filtered = false;
}
}
}
- else {
- is_filtered = 1;
- }
- return is_filtered && !is_hidden_file(file->relname, hide_dot);
+
+ return is_filtered;
}
-static bool is_filtered_lib(struct direntry *file, const char *dir, unsigned int filter, short hide_dot)
+static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
{
- bool is_filtered = false;
- char tdir[FILE_MAX], tgroup[BLO_GROUP_MAX];
- if (BLO_is_a_library(dir, tdir, tgroup)) {
- is_filtered = !is_hidden_file(file->relname, hide_dot);
+ bool is_filtered;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
+
+ BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+
+ if (BLO_library_path_explode(path, dir, &group, &name)) {
+ is_filtered = !is_hidden_file(file->relpath, filter);
+ if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ is_filtered = false;
+ }
+ }
+ else {
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
+ is_filtered = false;
+ }
+ }
+ }
+ if (is_filtered && group) {
+ if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
+ is_filtered = false;
+ }
+ else {
+ unsigned int filter_id = groupname_to_filter_id(group);
+ if (!(filter_id & filter->filter_id)) {
+ is_filtered = false;
+ }
+ }
+ }
+ if (is_filtered && (filter->filter_search[0] != '\0')) {
+ if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
+ is_filtered = false;
+ }
+ }
+ }
}
else {
- is_filtered = is_filtered_file(file, dir, filter, hide_dot);
+ is_filtered = is_filtered_file(file, root, filter);
}
+
return is_filtered;
}
-static bool is_filtered_main(struct direntry *file, const char *UNUSED(dir), unsigned int UNUSED(filter), short hide_dot)
+static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter)
+{
+ return !is_hidden_file(file->relpath, filter);
+}
+
+static void filelist_filter_clear(FileList *filelist)
{
- return !is_hidden_file(file->relname, hide_dot);
+ filelist->flags |= FL_NEED_FILTERING;
}
void filelist_filter(FileList *filelist)
{
int num_filtered = 0;
- int i, j;
+ const int num_files = filelist->filelist.nbr_entries;
+ FileListInternEntry **filtered_tmp, *file;
- if (!filelist->filelist)
+ if (filelist->filelist.nbr_entries == 0) {
return;
+ }
- /* How many files are left after filter ? */
- for (i = 0; i < filelist->numfiles; ++i) {
- struct direntry *file = &filelist->filelist[i];
- if (filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot)) {
- num_filtered++;
- }
+ if (!(filelist->flags & FL_NEED_FILTERING)) {
+ /* Assume it has already been filtered, nothing else to do! */
+ return;
}
-
- if (filelist->fidx) {
- MEM_freeN(filelist->fidx);
- filelist->fidx = NULL;
+
+ filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR;
+ if (filelist->max_recursion) {
+ /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
+ * root path is a blend file. */
+ char dir[FILE_MAXDIR];
+ if (!filelist_islibrary(filelist, dir, NULL)) {
+ filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
+ }
}
- filelist->fidx = (int *)MEM_callocN(num_filtered * sizeof(int), "filteridx");
- filelist->numfiltered = num_filtered;
- for (i = 0, j = 0; i < filelist->numfiles; ++i) {
- struct direntry *file = &filelist->filelist[i];
- if (filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot)) {
- filelist->fidx[j++] = i;
+ filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__);
+
+ /* Filter remap & count how many files are left after filter in a single loop. */
+ for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
+ if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) {
+ filtered_tmp[num_filtered++] = file;
}
}
+
+ if (filelist->filelist_intern.filtered) {
+ MEM_freeN(filelist->filelist_intern.filtered);
+ }
+ filelist->filelist_intern.filtered = MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered,
+ __func__);
+ memcpy(filelist->filelist_intern.filtered, filtered_tmp,
+ sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered);
+ filelist->filelist.nbr_entries_filtered = num_filtered;
+// printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries);
+
+ filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
+ filelist->flags &= ~FL_NEED_FILTERING;
+
+ MEM_freeN(filtered_tmp);
}
+void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
+ const unsigned int filter, const unsigned int filter_id,
+ const char *filter_glob, const char *filter_search)
+{
+ bool update = false;
+
+ if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) {
+ filelist->filter_data.flags ^= FLF_HIDE_DOT;
+ update = true;
+ }
+ if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) {
+ filelist->filter_data.flags ^= FLF_HIDE_PARENT;
+ update = true;
+ }
+ if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) {
+ filelist->filter_data.filter = filter;
+ filelist->filter_data.filter_id = filter_id;
+ update = true;
+ }
+ if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) {
+ BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob));
+ update = true;
+ }
+ if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) {
+ BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, filter_search, '*',
+ sizeof(filelist->filter_data.filter_search));
+ update = true;
+ }
+
+ if (update) {
+ /* And now, free filtered data so that we know we have to filter again. */
+ filelist_filter_clear(filelist);
+ }
+}
+
+/* ********** Icon/image helpers ********** */
+
void filelist_init_icons(void)
{
short x, y, k;
@@ -428,136 +810,517 @@ void filelist_free_icons(void)
}
}
-/* -----------------FOLDERLIST (previous/next) -------------- */
-ListBase *folderlist_new(void)
+void filelist_imgsize(struct FileList *filelist, short w, short h)
{
- ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist");
- return p;
+ filelist->prv_w = w;
+ filelist->prv_h = h;
}
-void folderlist_popdir(struct ListBase *folderlist, char *dir)
+static FileDirEntry *filelist_geticon_get_file(struct FileList *filelist, const int index)
{
- const char *prev_dir;
- struct FolderList *folder;
- folder = folderlist->last;
+ BLI_assert(G.background == false);
- if (folder) {
- /* remove the current directory */
- MEM_freeN(folder->foldername);
- BLI_freelinkN(folderlist, folder);
+ return filelist_file(filelist, index);
+}
- folder = folderlist->last;
- if (folder) {
- prev_dir = folder->foldername;
- BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
+ImBuf *filelist_getimage(struct FileList *filelist, const int index)
+{
+ FileDirEntry *file = filelist_geticon_get_file(filelist, index);
+
+ return file->image;
+}
+
+static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char *relpath)
+{
+ ImBuf *ibuf = NULL;
+
+ if (typeflag & FILE_TYPE_DIR) {
+ if (FILENAME_IS_PARENT(relpath)) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
+ }
+ else if (FILENAME_IS_CURRENT(relpath)) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
+ }
+ else {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
}
}
- /* delete the folder next or use setdir directly before PREVIOUS OP */
+ else if (typeflag & FILE_TYPE_BLENDER) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
+ }
+ else if (typeflag & FILE_TYPE_BLENDERLIB) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ }
+ else if (typeflag & (FILE_TYPE_MOVIE)) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
+ }
+ else if (typeflag & FILE_TYPE_SOUND) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
+ }
+ else if (typeflag & FILE_TYPE_PYSCRIPT) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
+ }
+ else if (typeflag & FILE_TYPE_FTFONT) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
+ }
+ else if (typeflag & FILE_TYPE_TEXT) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
+ }
+ else if (typeflag & FILE_TYPE_IMAGE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
+ }
+ else if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
+ }
+ else {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ }
+
+ return ibuf;
}
-void folderlist_pushdir(ListBase *folderlist, const char *dir)
+ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
{
- struct FolderList *folder, *previous_folder;
- previous_folder = folderlist->last;
+ FileDirEntry *file = filelist_geticon_get_file(filelist, index);
- /* check if already exists */
- if (previous_folder && previous_folder->foldername) {
- if (BLI_path_cmp(previous_folder->foldername, dir) == 0) {
- return;
+ return filelist_geticon_image_ex(file->typeflag, file->relpath);
+}
+
+static int filelist_geticon_ex(
+ const int typeflag, const int blentype, const char *relpath, const bool is_main, const bool ignore_libdir)
+{
+ if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) {
+ if (FILENAME_IS_PARENT(relpath)) {
+ return is_main ? ICON_FILE_PARENT : ICON_NONE;
+ }
+ else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) {
+ return ICON_UGLYPACKAGE;
+ }
+ else if (typeflag & FILE_TYPE_BLENDER) {
+ return ICON_FILE_BLEND;
+ }
+ else if (is_main) {
+ /* Do not return icon for folders if icons are not 'main' draw type (e.g. when used over previews). */
+ return ICON_FILE_FOLDER;
}
}
- /* create next folder element */
- folder = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList");
- folder->foldername = BLI_strdup(dir);
+ if (typeflag & FILE_TYPE_BLENDER)
+ return ICON_FILE_BLEND;
+ else if (typeflag & FILE_TYPE_BLENDER_BACKUP)
+ return ICON_FILE_BACKUP;
+ else if (typeflag & FILE_TYPE_IMAGE)
+ return ICON_FILE_IMAGE;
+ else if (typeflag & FILE_TYPE_MOVIE)
+ return ICON_FILE_MOVIE;
+ else if (typeflag & FILE_TYPE_PYSCRIPT)
+ return ICON_FILE_SCRIPT;
+ else if (typeflag & FILE_TYPE_SOUND)
+ return ICON_FILE_SOUND;
+ else if (typeflag & FILE_TYPE_FTFONT)
+ return ICON_FILE_FONT;
+ else if (typeflag & FILE_TYPE_BTX)
+ return ICON_FILE_BLANK;
+ else if (typeflag & FILE_TYPE_COLLADA)
+ return ICON_FILE_BLANK;
+ else if (typeflag & FILE_TYPE_TEXT)
+ return ICON_FILE_TEXT;
+ else if (typeflag & FILE_TYPE_BLENDERLIB) {
+ const int ret = UI_idcode_icon_get(blentype);
+ if (ret != ICON_NONE) {
+ return ret;
+ }
+ }
+ return is_main ? ICON_FILE_BLANK : ICON_NONE;
+}
- /* add it to the end of the list */
- BLI_addtail(folderlist, folder);
+int filelist_geticon(struct FileList *filelist, const int index, const bool is_main)
+{
+ FileDirEntry *file = filelist_geticon_get_file(filelist, index);
+
+ return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false);
}
-const char *folderlist_peeklastdir(ListBase *folderlist)
+/* ********** Main ********** */
+
+static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir)
{
- struct FolderList *folder;
+ BLI_make_exist(r_dir);
+}
- if (!folderlist->last)
- return NULL;
+static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
+{
+ char dir[FILE_MAXDIR];
+ if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
+ /* if not a valid library, we need it to be a valid directory! */
+ BLI_make_exist(r_dir);
+ }
+}
- folder = folderlist->last;
- return folder->foldername;
+static void filelist_checkdir_main(struct FileList *filelist, char *r_dir)
+{
+ /* TODO */
+ filelist_checkdir_lib(filelist, r_dir);
}
-int folderlist_clear_next(struct SpaceFile *sfile)
+static void filelist_entry_clear(FileDirEntry *entry)
{
- struct FolderList *folder;
+ if (entry->name) {
+ MEM_freeN(entry->name);
+ }
+ if (entry->description) {
+ MEM_freeN(entry->description);
+ }
+ if (entry->relpath) {
+ MEM_freeN(entry->relpath);
+ }
+ if (entry->image) {
+ IMB_freeImBuf(entry->image);
+ }
+ /* For now, consider FileDirEntryRevision::poin as not owned here, so no need to do anything about it */
- /* if there is no folder_next there is nothing we can clear */
- if (!sfile->folders_next)
- return 0;
+ if (!BLI_listbase_is_empty(&entry->variants)) {
+ FileDirEntryVariant *var;
- /* if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next */
- folder = sfile->folders_prev->last;
- if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0))
- return 0;
+ for (var = entry->variants.first; var; var = var->next) {
+ if (var->name) {
+ MEM_freeN(var->name);
+ }
+ if (var->description) {
+ MEM_freeN(var->description);
+ }
- /* eventually clear flist->folders_next */
- return 1;
+ if (!BLI_listbase_is_empty(&var->revisions)) {
+ FileDirEntryRevision *rev;
+
+ for (rev = var->revisions.first; rev; rev = rev->next) {
+ if (rev->comment) {
+ MEM_freeN(rev->comment);
+ }
+ }
+
+ BLI_freelistN(&var->revisions);
+ }
+ }
+
+ /* TODO: tags! */
+
+ BLI_freelistN(&entry->variants);
+ }
+ else if (entry->entry) {
+ MEM_freeN(entry->entry);
+ }
}
-/* not listbase itself */
-void folderlist_free(ListBase *folderlist)
+static void filelist_entry_free(FileDirEntry *entry)
{
- if (folderlist) {
- FolderList *folder;
- for (folder = folderlist->first; folder; folder = folder->next)
- MEM_freeN(folder->foldername);
- BLI_freelistN(folderlist);
+ filelist_entry_clear(entry);
+ MEM_freeN(entry);
+}
+
+static void filelist_direntryarr_free(FileDirEntryArr *array)
+{
+#if 0
+ FileDirEntry *entry, *entry_next;
+
+ for (entry = array->entries.first; entry; entry = entry_next) {
+ entry_next = entry->next;
+ filelist_entry_free(entry);
}
+ BLI_listbase_clear(&array->entries);
+#else
+ BLI_assert(BLI_listbase_is_empty(&array->entries));
+#endif
+ array->nbr_entries = 0;
+ array->nbr_entries_filtered = -1;
+ array->entry_idx_start = -1;
+ array->entry_idx_end = -1;
}
-ListBase *folderlist_duplicate(ListBase *folderlist)
+static void filelist_intern_entry_free(FileListInternEntry *entry)
{
-
- if (folderlist) {
- ListBase *folderlistn = MEM_callocN(sizeof(ListBase), "copy folderlist");
- FolderList *folder;
-
- BLI_duplicatelist(folderlistn, folderlist);
-
- for (folder = folderlistn->first; folder; folder = folder->next) {
- folder->foldername = MEM_dupallocN(folder->foldername);
+ if (entry->relpath) {
+ MEM_freeN(entry->relpath);
+ }
+ if (entry->name) {
+ MEM_freeN(entry->name);
+ }
+ MEM_freeN(entry);
+}
+
+static void filelist_intern_free(FileListIntern *filelist_intern)
+{
+ FileListInternEntry *entry, *entry_next;
+
+ for (entry = filelist_intern->entries.first; entry; entry = entry_next) {
+ entry_next = entry->next;
+ filelist_intern_entry_free(entry);
+ }
+ BLI_listbase_clear(&filelist_intern->entries);
+
+ MEM_SAFE_FREE(filelist_intern->filtered);
+}
+
+static void filelist_cache_previewf(TaskPool *pool, void *taskdata, int UNUSED(threadid))
+{
+ FileListEntryCache *cache = taskdata;
+ FileListEntryPreview *preview;
+
+// printf("%s: Start (%d)...\n", __func__, threadid);
+
+ /* Note we wait on queue here. */
+ while (!BLI_task_pool_canceled(pool) && (preview = BLI_thread_queue_pop(cache->previews_todo))) {
+ ThumbSource source = 0;
+
+// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ BLI_assert(preview->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
+ FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
+ if (preview->flags & FILE_TYPE_IMAGE) {
+ source = THB_SOURCE_IMAGE;
}
- return folderlistn;
+ else if (preview->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ source = THB_SOURCE_BLEND;
+ }
+ else if (preview->flags & FILE_TYPE_MOVIE) {
+ source = THB_SOURCE_MOVIE;
+ }
+ else if (preview->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
+ }
+
+ IMB_thumb_path_lock(preview->path);
+ preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->path);
+
+ BLI_thread_queue_push(cache->previews_done, preview);
}
- return NULL;
+
+// printf("%s: End (%d)...\n", __func__, threadid);
}
+static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
+{
+ if (!cache->previews_pool) {
+ TaskScheduler *scheduler;
+ TaskPool *pool;
+ int num_tasks = max_ii(1, (BLI_system_thread_count() / 2) + 1);
+
+ scheduler = cache->previews_scheduler = BLI_task_scheduler_create(num_tasks + 1);
+ pool = cache->previews_pool = BLI_task_pool_create(scheduler, NULL);
+ cache->previews_todo = BLI_thread_queue_init();
+ cache->previews_done = BLI_thread_queue_init();
+
+ while (num_tasks--) {
+ BLI_task_pool_push(pool, filelist_cache_previewf, cache, false, TASK_PRIORITY_HIGH);
+ }
+ IMB_thumb_locks_acquire();
+ }
+ cache->previews_timestamp = 0.0;
+}
-static void filelist_read_main(struct FileList *filelist);
-static void filelist_read_library(struct FileList *filelist);
-static void filelist_read_dir(struct FileList *filelist);
+static void filelist_cache_previews_clear(FileListEntryCache *cache)
+{
+ FileListEntryPreview *preview;
+
+ if (cache->previews_pool) {
+ while ((preview = BLI_thread_queue_pop_timeout(cache->previews_todo, 0))) {
+// printf("%s: TODO %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ MEM_freeN(preview);
+ cache->previews_pending--;
+ }
+ while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
+// printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ if (preview->img) {
+ IMB_freeImBuf(preview->img);
+ }
+ MEM_freeN(preview);
+ cache->previews_pending--;
+ }
+ }
+// printf("%s: remaining pending previews: %d\n", __func__, cache->previews_pending);
+}
+
+static void filelist_cache_previews_free(FileListEntryCache *cache, const bool set_inactive)
+{
+ if (cache->previews_pool) {
+ BLI_thread_queue_nowait(cache->previews_todo);
+ BLI_thread_queue_nowait(cache->previews_done);
+ BLI_task_pool_cancel(cache->previews_pool);
+
+ filelist_cache_previews_clear(cache);
+
+ BLI_thread_queue_free(cache->previews_done);
+ BLI_thread_queue_free(cache->previews_todo);
+ BLI_task_pool_free(cache->previews_pool);
+ BLI_task_scheduler_free(cache->previews_scheduler);
+ cache->previews_scheduler = NULL;
+ cache->previews_pool = NULL;
+ cache->previews_todo = NULL;
+ cache->previews_done = NULL;
+
+ IMB_thumb_locks_release();
+ }
+ if (set_inactive) {
+ cache->flags &= ~FLC_PREVIEWS_ACTIVE;
+ }
+ BLI_assert(cache->previews_pending == 0);
+ cache->previews_timestamp = 0.0;
+}
+
+static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
+{
+ FileListEntryCache *cache = &filelist->filelist_cache;
+
+ BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE);
+
+ if (!entry->image &&
+ !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) &&
+ (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
+ FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)))
+ {
+ FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
+ BLI_join_dirfile(preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ preview->index = index;
+ preview->flags = entry->typeflag;
+ preview->img = NULL;
+// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+
+ filelist_cache_preview_ensure_running(cache);
+ BLI_thread_queue_push(cache->previews_todo, preview);
+ cache->previews_pending++;
+ }
+}
+
+static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
+{
+ BLI_listbase_clear(&cache->cached_entries);
+
+ cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0;
+ cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__);
+
+ cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size);
+ cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, __func__);
+ copy_vn_i(cache->misc_entries_indices, cache_size, -1);
+ cache->misc_cursor = 0;
+
+ /* XXX This assumes uint is 32 bits and uuid is 128 bits (char[16]), be careful! */
+ cache->uuids = BLI_ghash_new_ex(
+ BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__, cache_size * 2);
+
+ cache->size = cache_size;
+ cache->flags = FLC_IS_INIT;
+}
+
+static void filelist_cache_free(FileListEntryCache *cache)
+{
+ FileDirEntry *entry, *entry_next;
+
+ if (!(cache->flags & FLC_IS_INIT)) {
+ return;
+ }
+
+ filelist_cache_previews_free(cache, true);
+
+ MEM_freeN(cache->block_entries);
+
+ BLI_ghash_free(cache->misc_entries, NULL, NULL);
+ MEM_freeN(cache->misc_entries_indices);
+
+ BLI_ghash_free(cache->uuids, NULL, NULL);
+
+ for (entry = cache->cached_entries.first; entry; entry = entry_next) {
+ entry_next = entry->next;
+ filelist_entry_free(entry);
+ }
+ BLI_listbase_clear(&cache->cached_entries);
+}
+
+static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
+{
+ FileDirEntry *entry, *entry_next;
+
+ if (!(cache->flags & FLC_IS_INIT)) {
+ return;
+ }
+
+ filelist_cache_previews_clear(cache);
+
+ cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0;
+ if (new_size != cache->size) {
+ cache->block_entries = MEM_reallocN(cache->block_entries, sizeof(*cache->block_entries) * new_size);
+ }
+
+ BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size);
+ if (new_size != cache->size) {
+ cache->misc_entries_indices = MEM_reallocN(cache->misc_entries_indices,
+ sizeof(*cache->misc_entries_indices) * new_size);
+ }
+ copy_vn_i(cache->misc_entries_indices, new_size, -1);
+
+ BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2);
+
+ cache->size = new_size;
+
+ for (entry = cache->cached_entries.first; entry; entry = entry_next) {
+ entry_next = entry->next;
+ filelist_entry_free(entry);
+ }
+ BLI_listbase_clear(&cache->cached_entries);
+}
-/* ------------------FILELIST------------------------ */
FileList *filelist_new(short type)
{
- FileList *p = MEM_callocN(sizeof(FileList), "filelist");
+ FileList *p = MEM_callocN(sizeof(*p), __func__);
+
+ filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT);
+
+ p->selection_state = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
+
switch (type) {
case FILE_MAIN:
- p->readf = filelist_read_main;
+ p->checkdirf = filelist_checkdir_main;
+ p->read_jobf = filelist_readjob_main;
p->filterf = is_filtered_main;
break;
case FILE_LOADLIB:
- p->readf = filelist_read_library;
+ p->checkdirf = filelist_checkdir_lib;
+ p->read_jobf = filelist_readjob_lib;
p->filterf = is_filtered_lib;
break;
default:
- p->readf = filelist_read_dir;
+ p->checkdirf = filelist_checkdir_dir;
+ p->read_jobf = filelist_readjob_dir;
p->filterf = is_filtered_file;
break;
-
}
return p;
}
+void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection)
+{
+ if (!filelist) {
+ return;
+ }
+
+ filelist_filter_clear(filelist);
+
+ if (do_cache) {
+ filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
+ }
+
+ filelist_intern_free(&filelist->filelist_intern);
+
+ filelist_direntryarr_free(&filelist->filelist);
+
+ if (do_selection && filelist->selection_state) {
+ BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL);
+ }
+}
+
+void filelist_clear(struct FileList *filelist)
+{
+ filelist_clear_ex(filelist, true, true);
+}
void filelist_free(struct FileList *filelist)
{
@@ -566,18 +1329,18 @@ void filelist_free(struct FileList *filelist)
return;
}
- if (filelist->fidx) {
- MEM_freeN(filelist->fidx);
- filelist->fidx = NULL;
+ filelist_clear_ex(filelist, false, false); /* No need to clear cache & selection_state, we free them anyway. */
+ filelist_cache_free(&filelist->filelist_cache);
+
+ if (filelist->selection_state) {
+ BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL);
+ filelist->selection_state = NULL;
}
- BLI_free_filelist(filelist->filelist, filelist->numfiles);
- filelist->numfiles = 0;
- filelist->filelist = NULL;
- filelist->filter = 0;
- filelist->filter_glob[0] = '\0';
- filelist->numfiltered = 0;
- filelist->hide_dot = 0;
+ memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
+
+ filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
+ filelist->sort = FILE_SORT_NONE;
}
void filelist_freelib(struct FileList *filelist)
@@ -592,155 +1355,575 @@ BlendHandle *filelist_lib(struct FileList *filelist)
return filelist->libfiledata;
}
-int filelist_numfiles(struct FileList *filelist)
+static const char *fileentry_uiname(const char *root, const char *relpath, const int typeflag, char *buff)
{
- return filelist->numfiltered;
+ char *name = NULL;
+
+ if (typeflag & FILE_TYPE_BLENDERLIB) {
+ char abspath[FILE_MAX_LIBEXTRA];
+ char *group;
+
+ BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
+ BLO_library_path_explode(abspath, buff, &group, &name);
+ if (!name) {
+ name = group;
+ }
+ }
+ /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */
+ if (!name) {
+ if (typeflag & FILE_TYPE_DIR) {
+ name = (char *)relpath;
+ }
+ else {
+ name = (char *)BLI_path_basename(relpath);
+ }
+ }
+ BLI_assert(name);
+
+ return name;
}
const char *filelist_dir(struct FileList *filelist)
{
- return filelist->dir;
+ return filelist->filelist.root;
}
-void filelist_setdir(struct FileList *filelist, const char *dir)
+/**
+ * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
+ */
+void filelist_setdir(struct FileList *filelist, char *r_dir)
{
- BLI_strncpy(filelist->dir, dir, sizeof(filelist->dir));
+ BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
+
+ BLI_cleanup_dir(G.main->name, r_dir);
+ filelist->checkdirf(filelist, r_dir);
+
+ if (!STREQ(filelist->filelist.root, r_dir)) {
+ BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
+ filelist->flags |= FL_FORCE_RESET;
+ }
}
-void filelist_imgsize(struct FileList *filelist, short w, short h)
+void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
{
- filelist->prv_w = w;
- filelist->prv_h = h;
+ if (filelist->max_recursion != recursion_level) {
+ filelist->max_recursion = recursion_level;
+ filelist->flags |= FL_FORCE_RESET;
+ }
}
-short filelist_changed(struct FileList *filelist)
+bool filelist_force_reset(struct FileList *filelist)
{
- return filelist->changed;
+ return (filelist->flags & FL_FORCE_RESET) != 0;
}
-ImBuf *filelist_getimage(struct FileList *filelist, int index)
+bool filelist_is_ready(struct FileList *filelist)
{
- ImBuf *ibuf = NULL;
- int fidx = 0;
+ return (filelist->flags & FL_IS_READY) != 0;
+}
- BLI_assert(G.background == false);
+bool filelist_pending(struct FileList *filelist)
+{
+ return (filelist->flags & FL_IS_PENDING) != 0;
+}
- if ((index < 0) || (index >= filelist->numfiltered)) {
- return NULL;
+/**
+ * Limited version of full update done by space_file's file_refresh(), to be used by operators and such.
+ * Ensures given filelist is ready to be used (i.e. it is filtered and sorted), unless it is tagged for a full refresh.
+ */
+int filelist_files_ensure(FileList *filelist)
+{
+ if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) {
+ filelist_sort(filelist);
+ filelist_filter(filelist);
}
- fidx = filelist->fidx[index];
- ibuf = filelist->filelist[fidx].image;
- return ibuf;
+ return filelist->filelist.nbr_entries_filtered;;
}
-ImBuf *filelist_geticon(struct FileList *filelist, int index)
+static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
{
- ImBuf *ibuf = NULL;
- struct direntry *file = NULL;
- int fidx = 0;
+ FileListInternEntry *entry = filelist->filelist_intern.filtered[index];
+ FileListEntryCache *cache = &filelist->filelist_cache;
+ FileDirEntry *ret;
+ FileDirEntryRevision *rev;
- BLI_assert(G.background == false);
+ ret = MEM_callocN(sizeof(*ret), __func__);
+ rev = MEM_callocN(sizeof(*rev), __func__);
- if ((index < 0) || (index >= filelist->numfiltered)) {
- return NULL;
+ rev->size = (uint64_t)entry->st.st_size;
+
+ rev->time = (int64_t)entry->st.st_mtime;
+
+ ret->entry = rev;
+ ret->relpath = BLI_strdup(entry->relpath);
+ ret->name = BLI_strdup(entry->name);
+ ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath);
+ memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid));
+ ret->blentype = entry->blentype;
+ ret->typeflag = entry->typeflag;
+
+ BLI_addtail(&cache->cached_entries, ret);
+ return ret;
+}
+
+static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
+{
+ BLI_remlink(&filelist->filelist_cache.cached_entries, entry);
+ filelist_entry_free(entry);
+}
+
+static FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
+{
+ FileDirEntry *ret = NULL, *old;
+ FileListEntryCache *cache = &filelist->filelist_cache;
+ const size_t cache_size = cache->size;
+ int old_index;
+
+ if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) {
+ return ret;
}
- fidx = filelist->fidx[index];
- file = &filelist->filelist[fidx];
- if (file->type & S_IFDIR) {
- if (strcmp(filelist->filelist[fidx].relname, "..") == 0) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
- }
- else if (strcmp(filelist->filelist[fidx].relname, ".") == 0) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
- }
- else {
- ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
- }
+
+ if (index >= cache->block_start_index && index < cache->block_end_index) {
+ const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size;
+ return cache->block_entries[idx];
}
- else {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+
+ if ((ret = BLI_ghash_lookup(cache->misc_entries, SET_INT_IN_POINTER(index)))) {
+ return ret;
}
- if (file->flags & BLENDERFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
+ if (!use_request) {
+ return NULL;
}
- else if ((file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
+
+// printf("requesting file %d (not yet cached)\n", index);
+
+ /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */
+ ret = filelist_file_create_entry(filelist, index);
+ old_index = cache->misc_entries_indices[cache->misc_cursor];
+ if ((old = BLI_ghash_popkey(cache->misc_entries, SET_INT_IN_POINTER(old_index), NULL))) {
+ BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL);
+ filelist_file_release_entry(filelist, old);
}
- else if (file->flags & SOUNDFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
+ BLI_ghash_insert(cache->misc_entries, SET_INT_IN_POINTER(index), ret);
+ BLI_ghash_insert(cache->uuids, ret->uuid, ret);
+
+ cache->misc_entries_indices[cache->misc_cursor] = index;
+ cache->misc_cursor = (cache->misc_cursor + 1) % cache_size;
+
+#if 0 /* Actually no, only block cached entries should have preview imho. */
+ if (cache->previews_pool) {
+ filelist_cache_previews_push(filelist, ret, index);
}
- else if (file->flags & PYSCRIPTFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
+#endif
+
+ return ret;
+}
+
+FileDirEntry *filelist_file(struct FileList *filelist, int index)
+{
+ return filelist_file_ex(filelist, index, true);
+}
+
+int filelist_file_findpath(struct FileList *filelist, const char *filename)
+{
+ int fidx = -1;
+
+ if (filelist->filelist.nbr_entries_filtered < 0) {
+ return fidx;
}
- else if (file->flags & FTFONTFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
+
+ /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though.
+ * This is only used to find again renamed entry, annoying but looks hairy to get rid of it currently. */
+
+ for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
+ if (STREQ(entry->relpath, filename)) {
+ return fidx;
+ }
}
- else if (file->flags & TEXTFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
+
+ return -1;
+}
+
+FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4])
+{
+ if (filelist->filelist.nbr_entries_filtered < 0) {
+ return NULL;
}
- else if (file->flags & IMAGEFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
+
+ if (filelist->filelist_cache.uuids) {
+ FileDirEntry *entry = BLI_ghash_lookup(filelist->filelist_cache.uuids, uuid);
+ if (entry) {
+ return entry;
+ }
}
- else if (file->flags & BLENDERFILE_BACKUP) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
+
+ {
+ int fidx;
+
+ for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
+ if (memcmp(entry->uuid, uuid, sizeof(entry->uuid)) == 0) {
+ return filelist_file(filelist, fidx);
+ }
+ }
}
- return ibuf;
+ return NULL;
}
-struct direntry *filelist_file(struct FileList *filelist, int index)
+void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
{
- int fidx = 0;
-
- if ((index < 0) || (index >= filelist->numfiltered)) {
- return NULL;
+ /* Always keep it power of 2, in [256, 8192] range for now, cache being app. twice bigger than requested window. */
+ size_t size = 256;
+ window_size *= 2;
+
+ while (size < window_size && size < 8192) {
+ size *= 2;
}
- fidx = filelist->fidx[index];
- return &filelist->filelist[fidx];
+ if (size != filelist->filelist_cache.size) {
+ filelist_cache_clear(&filelist->filelist_cache, size);
+ }
}
-int filelist_find(struct FileList *filelist, const char *filename)
+/* Helpers, low-level, they assume cursor + size <= cache_size */
+static bool filelist_file_cache_block_create(FileList *filelist, const int start_index, const int size, int cursor)
{
- int index = -1;
+ FileListEntryCache *cache = &filelist->filelist_cache;
+
+ {
+ int i, idx;
+
+ for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) {
+ FileDirEntry *entry;
+
+ /* That entry might have already been requested and stored in misc cache... */
+ if ((entry = BLI_ghash_popkey(cache->misc_entries, SET_INT_IN_POINTER(idx), NULL)) == NULL) {
+ entry = filelist_file_create_entry(filelist, idx);
+ BLI_ghash_insert(cache->uuids, entry->uuid, entry);
+ }
+ cache->block_entries[cursor] = entry;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor)
+{
+ FileListEntryCache *cache = &filelist->filelist_cache;
+
+ {
+ int i;
+
+ for (i = 0; i < size; i++, cursor++) {
+ FileDirEntry *entry = cache->block_entries[cursor];
+// printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/);
+ BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL);
+ filelist_file_release_entry(filelist, entry);
+#ifndef NDEBUG
+ cache->block_entries[cursor] = NULL;
+#endif
+ }
+ }
+}
+
+/* Load in cache all entries "around" given index (as much as block cache may hold). */
+bool filelist_file_cache_block(struct FileList *filelist, const int index)
+{
+ FileListEntryCache *cache = &filelist->filelist_cache;
+ const size_t cache_size = cache->size;
+
+ const int nbr_entries = filelist->filelist.nbr_entries_filtered;
+ int start_index = max_ii(0, index - (cache_size / 2));
+ int end_index = min_ii(nbr_entries, index + (cache_size / 2));
int i;
- int fidx = -1;
-
- if (!filelist->fidx)
- return fidx;
-
- for (i = 0; i < filelist->numfiles; ++i) {
- if (strcmp(filelist->filelist[i].relname, filename) == 0) { /* not dealing with user input so don't need BLI_path_cmp */
- index = i;
- break;
+ if ((index < 0) || (index >= nbr_entries)) {
+// printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries);
+ return false;
+ }
+
+ /* Maximize cached range! */
+ if ((end_index - start_index) < cache_size) {
+ if (start_index == 0) {
+ end_index = min_ii(nbr_entries, start_index + cache_size);
+ }
+ else if (end_index == nbr_entries) {
+ start_index = max_ii(0, end_index - cache_size);
}
}
- for (i = 0; i < filelist->numfiltered; ++i) {
- if (filelist->fidx[i] == index) {
- fidx = i;
- break;
+ BLI_assert((end_index - start_index) <= cache_size) ;
+
+// printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__,
+// start_index, end_index, index, cache->block_start_index, cache->block_end_index);
+
+ /* If we have something to (re)cache... */
+ if ((start_index != cache->block_start_index) || (end_index != cache->block_end_index)) {
+ if ((start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) {
+ int size1 = cache->block_end_index - cache->block_start_index;
+ int size2 = 0;
+ int idx1 = cache->block_cursor, idx2 = 0;
+
+// printf("Full Recaching!\n");
+
+ if (cache->flags & FLC_PREVIEWS_ACTIVE) {
+ filelist_cache_previews_clear(cache);
+ }
+
+ if (idx1 + size1 > cache_size) {
+ size2 = idx1 + size1 - cache_size;
+ size1 -= size2;
+ filelist_file_cache_block_release(filelist, size2, idx2);
+ }
+ filelist_file_cache_block_release(filelist, size1, idx1);
+
+ cache->block_start_index = cache->block_end_index = cache->block_cursor = 0;
+
+ /* New cached block does not overlap existing one, simple. */
+ if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) {
+ return false;
+ }
+
+ cache->block_start_index = start_index;
+ cache->block_end_index = end_index;
+ }
+ else {
+// printf("Partial Recaching!\n");
+
+ /* At this point, we know we keep part of currently cached entries, so update previews if needed,
+ * and remove everything from working queue - we'll add all newly needed entries at the end. */
+ if (cache->flags & FLC_PREVIEWS_ACTIVE) {
+ filelist_cache_previews_update(filelist);
+ filelist_cache_previews_clear(cache);
+ }
+
+// printf("\tpreview cleaned up...\n");
+
+ if (start_index > cache->block_start_index) {
+ int size1 = start_index - cache->block_start_index;
+ int size2 = 0;
+ int idx1 = cache->block_cursor, idx2 = 0;
+
+// printf("\tcache releasing: [%d:%d] (%d, %d)\n", cache->block_start_index, cache->block_start_index + size1, cache->block_cursor, size1);
+
+ if (idx1 + size1 > cache_size) {
+ size2 = idx1 + size1 - cache_size;
+ size1 -= size2;
+ filelist_file_cache_block_release(filelist, size2, idx2);
+ }
+ filelist_file_cache_block_release(filelist, size1, idx1);
+
+ cache->block_cursor = (idx1 + size1 + size2) % cache_size;
+ cache->block_start_index = start_index;
+ }
+ if (end_index < cache->block_end_index) {
+ int size1 = cache->block_end_index - end_index;
+ int size2 = 0;
+ int idx1, idx2 = 0;
+
+// printf("\tcache releasing: [%d:%d] (%d)\n", cache->block_end_index - size1, cache->block_end_index, cache->block_cursor);
+
+ idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size;
+ if (idx1 + size1 > cache_size) {
+ size2 = idx1 + size1 - cache_size;
+ size1 -= size2;
+ filelist_file_cache_block_release(filelist, size2, idx2);
+ }
+ filelist_file_cache_block_release(filelist, size1, idx1);
+
+ cache->block_end_index = end_index;
+ }
+
+// printf("\tcache cleaned up...\n");
+
+ if (start_index < cache->block_start_index) {
+ /* Add (request) needed entries before already cached ones. */
+ /* Note: We need some index black magic to wrap around (cycle) inside our cache_size array... */
+ int size1 = cache->block_start_index - start_index;
+ int size2 = 0;
+ int idx1, idx2;
+
+ if (size1 > cache->block_cursor) {
+ size2 = size1;
+ size1 -= cache->block_cursor;
+ size2 -= size1;
+ idx2 = 0;
+ idx1 = cache_size - size1;
+ }
+ else {
+ idx1 = cache->block_cursor - size1;
+ }
+
+ if (size2) {
+ if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) {
+ return false;
+ }
+ }
+ if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) {
+ return false;
+ }
+
+ cache->block_cursor = idx1;
+ cache->block_start_index = start_index;
+ }
+// printf("\tstart-extended...\n");
+ if (end_index > cache->block_end_index) {
+ /* Add (request) needed entries after already cached ones. */
+ /* Note: We need some index black magic to wrap around (cycle) inside our cache_size array... */
+ int size1 = end_index - cache->block_end_index;
+ int size2 = 0;
+ int idx1, idx2;
+
+ idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size;
+ if ((idx1 + size1) > cache_size) {
+ size2 = size1;
+ size1 = cache_size - idx1;
+ size2 -= size1;
+ idx2 = 0;
+ }
+
+ if (size2) {
+ if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) {
+ return false;
+ }
+ }
+ if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) {
+ return false;
+ }
+
+ cache->block_end_index = end_index;
+ }
+
+// printf("\tend-extended...\n");
+ }
+ }
+ else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) {
+ /* We try to always preview visible entries first, so 'restart' preview background task. */
+ filelist_cache_previews_update(filelist);
+ filelist_cache_previews_clear(cache);
+ }
+
+// printf("Re-queueing previews...\n");
+
+ /* Note we try to preview first images around given index - i.e. assumed visible ones. */
+ if (cache->flags & FLC_PREVIEWS_ACTIVE) {
+ for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) {
+ if ((index - i) >= start_index) {
+ const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size;
+ filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i);
+ }
+ if ((index + i) < end_index) {
+ const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size;
+ filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i);
+ }
}
}
- return fidx;
+
+ cache->block_center_index = index;
+
+// printf("%s Finished!\n", __func__);
+
+ return true;
}
-void filelist_hidedot(struct FileList *filelist, short hide)
+void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
{
- filelist->hide_dot = hide;
+ FileListEntryCache *cache = &filelist->filelist_cache;
+
+ if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) {
+ return;
+ }
+ /* Do not start preview work while listing, gives nasty flickering! */
+ else if (use_previews && (filelist->flags & FL_IS_READY)) {
+ cache->flags |= FLC_PREVIEWS_ACTIVE;
+
+ BLI_assert((cache->previews_pool == NULL) && (cache->previews_todo == NULL) && (cache->previews_done == NULL));
+
+// printf("%s: Init Previews...\n", __func__);
+
+ /* No need to populate preview queue here, filelist_file_cache_block() handles this. */
+ }
+ else {
+// printf("%s: Clear Previews...\n", __func__);
+
+ filelist_cache_previews_free(cache, true);
+ }
}
-void filelist_setfilter(struct FileList *filelist, unsigned int filter)
+bool filelist_cache_previews_update(FileList *filelist)
{
- filelist->filter = filter;
+ FileListEntryCache *cache = &filelist->filelist_cache;
+ TaskPool *pool = cache->previews_pool;
+ bool changed = false;
+
+ if (!pool) {
+ return changed;
+ }
+
+// printf("%s: Update Previews...\n", __func__);
+
+ while (!BLI_thread_queue_is_empty(cache->previews_done)) {
+ FileListEntryPreview *preview = BLI_thread_queue_pop(cache->previews_done);
+ FileDirEntry *entry;
+
+ /* Paranoid (should never happen currently since we consume this queue from a single thread), but... */
+ if (!preview) {
+ continue;
+ }
+ /* entry might have been removed from cache in the mean while, we do not want to cache it again here. */
+ entry = filelist_file_ex(filelist, preview->index, false);
+
+// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+
+ if (preview->img) {
+ /* Due to asynchronous process, a preview for a given image may be generated several times, i.e.
+ * entry->image may already be set at this point. */
+ if (entry && !entry->image) {
+ entry->image = preview->img;
+ changed = true;
+ }
+ else {
+ IMB_freeImBuf(preview->img);
+ }
+ }
+ else if (entry) {
+ /* We want to avoid re-processing this entry continuously!
+ * Note that, since entries only live in cache, preview will be retried quite often anyway. */
+ entry->flags |= FILE_ENTRY_INVALID_PREVIEW;
+ }
+
+ MEM_freeN(preview);
+ cache->previews_pending--;
+ BLI_assert(cache->previews_pending >= 0);
+ }
+
+// printf("%s: Previews pending: %d\n", __func__, cache->previews_pending);
+ if (cache->previews_pending == 0) {
+ if (cache->previews_timestamp == 0.0) {
+ cache->previews_timestamp = PIL_check_seconds_timer();
+ }
+ else if (PIL_check_seconds_timer() - cache->previews_timestamp > 1.0) {
+ /* Preview task is IDLE since more than (approximatively) 1000ms,
+ * kill workers & task for now - they will be automatically restarted when needed. */
+// printf("%s: Inactive preview task, sleeping (%f vs %f)!\n", __func__, PIL_check_seconds_timer(), cache->previews_timestamp);
+ filelist_cache_previews_free(cache, false);
+ }
+ }
+
+ return changed;
}
-void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob)
+bool filelist_cache_previews_running(FileList *filelist)
{
- BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob));
+ FileListEntryCache *cache = &filelist->filelist_cache;
+
+ return (cache->previews_pool != NULL);
}
/* would recognize .blend as well */
@@ -772,55 +1955,55 @@ static bool file_is_blend_backup(const char *str)
static int path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
- return BLENDERFILE;
+ return FILE_TYPE_BLENDER;
}
else if (file_is_blend_backup(path)) {
- return BLENDERFILE_BACKUP;
+ return FILE_TYPE_BLENDER_BACKUP;
}
else if (BLI_testextensie(path, ".app")) {
- return APPLICATIONBUNDLE;
+ return FILE_TYPE_APPLICATIONBUNDLE;
}
else if (BLI_testextensie(path, ".py")) {
- return PYSCRIPTFILE;
+ return FILE_TYPE_PYSCRIPT;
}
else if (BLI_testextensie_n(path, ".txt", ".glsl", ".osl", ".data", NULL)) {
- return TEXTFILE;
+ return FILE_TYPE_TEXT;
}
else if (BLI_testextensie_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) {
- return FTFONTFILE;
+ return FILE_TYPE_FTFONT;
}
else if (BLI_testextensie(path, ".btx")) {
- return BTXFILE;
+ return FILE_TYPE_BTX;
}
else if (BLI_testextensie(path, ".dae")) {
- return COLLADAFILE;
+ return FILE_TYPE_COLLADA;
}
else if (BLI_testextensie_array(path, imb_ext_image) ||
(G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt)))
{
- return IMAGEFILE;
+ return FILE_TYPE_IMAGE;
}
else if (BLI_testextensie(path, ".ogg")) {
if (IMB_isanim(path)) {
- return MOVIEFILE;
+ return FILE_TYPE_MOVIE;
}
else {
- return SOUNDFILE;
+ return FILE_TYPE_SOUND;
}
}
else if (BLI_testextensie_array(path, imb_ext_movie)) {
- return MOVIEFILE;
+ return FILE_TYPE_MOVIE;
}
else if (BLI_testextensie_array(path, imb_ext_audio)) {
- return SOUNDFILE;
+ return FILE_TYPE_SOUND;
}
return 0;
}
-static int file_extension_type(const char *dir, const char *relname)
+static int file_extension_type(const char *dir, const char *relpath)
{
char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), dir, relname);
+ BLI_join_dirfile(path, sizeof(path), dir, relpath);
return path_extension_type(path);
}
@@ -828,213 +2011,146 @@ int ED_file_extension_icon(const char *path)
{
int type = path_extension_type(path);
- if (type == BLENDERFILE)
- return ICON_FILE_BLEND;
- else if (type == BLENDERFILE_BACKUP)
- return ICON_FILE_BACKUP;
- else if (type == IMAGEFILE)
- return ICON_FILE_IMAGE;
- else if (type == MOVIEFILE)
- return ICON_FILE_MOVIE;
- else if (type == PYSCRIPTFILE)
- return ICON_FILE_SCRIPT;
- else if (type == SOUNDFILE)
- return ICON_FILE_SOUND;
- else if (type == FTFONTFILE)
- return ICON_FILE_FONT;
- else if (type == BTXFILE)
- return ICON_FILE_BLANK;
- else if (type == COLLADAFILE)
- return ICON_FILE_BLANK;
- else if (type == TEXTFILE)
- return ICON_FILE_TEXT;
-
- return ICON_FILE_BLANK;
-}
-
-static void filelist_setfiletypes(struct FileList *filelist)
-{
- struct direntry *file;
- int num;
-
- file = filelist->filelist;
-
- for (num = 0; num < filelist->numfiles; num++, file++) {
- file->type = file->s.st_mode; /* restore the mess below */
-#ifndef __APPLE__
- /* Don't check extensions for directories, allow in OSX cause bundles have extensions*/
- if (file->type & S_IFDIR) {
- continue;
- }
-#endif
- file->flags = file_extension_type(filelist->dir, file->relname);
-
- if (filelist->filter_glob[0] &&
- BLI_testextensie_glob(file->relname, filelist->filter_glob))
- {
- file->flags = OPERATORFILE;
- }
-
+ switch (type) {
+ case FILE_TYPE_BLENDER:
+ return ICON_FILE_BLEND;
+ case FILE_TYPE_BLENDER_BACKUP:
+ return ICON_FILE_BACKUP;
+ case FILE_TYPE_IMAGE:
+ return ICON_FILE_IMAGE;
+ case FILE_TYPE_MOVIE:
+ return ICON_FILE_MOVIE;
+ case FILE_TYPE_PYSCRIPT:
+ return ICON_FILE_SCRIPT;
+ case FILE_TYPE_SOUND:
+ return ICON_FILE_SOUND;
+ case FILE_TYPE_FTFONT:
+ return ICON_FILE_FONT;
+ case FILE_TYPE_BTX:
+ return ICON_FILE_BLANK;
+ case FILE_TYPE_COLLADA:
+ return ICON_FILE_BLANK;
+ case FILE_TYPE_TEXT:
+ return ICON_FILE_TEXT;
+ default:
+ return ICON_FILE_BLANK;
}
}
-static void filelist_read_dir(struct FileList *filelist)
-{
- if (!filelist) return;
-
- filelist->fidx = NULL;
- filelist->filelist = NULL;
-
- BLI_cleanup_dir(G.main->name, filelist->dir);
- filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist));
-
- filelist_setfiletypes(filelist);
- filelist_filter(filelist);
-}
-
-static void filelist_read_main(struct FileList *filelist)
+int filelist_empty(struct FileList *filelist)
{
- if (!filelist) return;
- filelist_from_main(filelist);
+ return (filelist->filelist.nbr_entries == 0);
}
-static void filelist_read_library(struct FileList *filelist)
+unsigned int filelist_entry_select_set(
+ const FileList *filelist, const FileDirEntry *entry, FileSelType select, unsigned int flag, FileCheckType check)
{
- if (!filelist) return;
- BLI_cleanup_dir(G.main->name, filelist->dir);
- filelist_from_library(filelist);
- if (!filelist->libfiledata) {
- int num;
- struct direntry *file;
+ /* Default NULL pointer if not found is fine here! */
+ void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid);
+ unsigned int entry_flag = es_p ? GET_UINT_FROM_POINTER(*es_p) : 0;
+ const unsigned int org_entry_flag = entry_flag;
- BLI_make_exist(filelist->dir);
- filelist_read_dir(filelist);
- file = filelist->filelist;
- for (num = 0; num < filelist->numfiles; num++, file++) {
- if (BLO_has_bfile_extension(file->relname)) {
- char name[FILE_MAX];
+ BLI_assert(entry);
+ BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL));
- BLI_join_dirfile(name, sizeof(name), filelist->dir, file->relname);
+ if (((check == CHECK_ALL)) ||
+ ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
+ ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR)))
+ {
+ switch (select) {
+ case FILE_SEL_REMOVE:
+ entry_flag &= ~flag;
+ break;
+ case FILE_SEL_ADD:
+ entry_flag |= flag;
+ break;
+ case FILE_SEL_TOGGLE:
+ entry_flag ^= flag;
+ break;
+ }
+ }
- /* prevent current file being used as acceptable dir */
- if (BLI_path_cmp(G.main->name, name) != 0) {
- file->type &= ~S_IFMT;
- file->type |= S_IFDIR;
- }
+ if (entry_flag != org_entry_flag) {
+ if (es_p) {
+ if (entry_flag) {
+ *es_p = SET_UINT_IN_POINTER(entry_flag);
+ }
+ else {
+ BLI_ghash_remove(filelist->selection_state, entry->uuid, MEM_freeN, NULL);
}
}
+ else if (entry_flag) {
+ void *key = MEM_mallocN(sizeof(entry->uuid), __func__);
+ memcpy(key, entry->uuid, sizeof(entry->uuid));
+ BLI_ghash_insert(filelist->selection_state, key, SET_UINT_IN_POINTER(entry_flag));
+ }
}
-}
-void filelist_readdir(struct FileList *filelist)
-{
- filelist->readf(filelist);
-}
-
-int filelist_empty(struct FileList *filelist)
-{
- return filelist->filelist == NULL;
+ return entry_flag;
}
-void filelist_parent(struct FileList *filelist)
+void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, unsigned int flag, FileCheckType check)
{
- BLI_parent_dir(filelist->dir);
- BLI_make_exist(filelist->dir);
- filelist_readdir(filelist);
-}
+ FileDirEntry *entry = filelist_file(filelist, index);
-void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check)
-{
- struct direntry *file = filelist_file(filelist, index);
- if (file != NULL) {
- int check_ok = 0;
- switch (check) {
- case CHECK_DIRS:
- check_ok = S_ISDIR(file->type);
- break;
- case CHECK_ALL:
- check_ok = 1;
- break;
- case CHECK_FILES:
- default:
- check_ok = !S_ISDIR(file->type);
- break;
- }
- if (check_ok) {
- switch (select) {
- case FILE_SEL_REMOVE:
- file->selflag &= ~flag;
- break;
- case FILE_SEL_ADD:
- file->selflag |= flag;
- break;
- case FILE_SEL_TOGGLE:
- file->selflag ^= flag;
- break;
- }
- }
+ if (entry) {
+ filelist_entry_select_set(filelist, entry, select, flag, check);
}
}
-void filelist_select(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check)
+void filelist_entries_select_index_range_set(
+ FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check)
{
/* select all valid files between first and last indicated */
- if ((sel->first >= 0) && (sel->first < filelist->numfiltered) && (sel->last >= 0) && (sel->last < filelist->numfiltered)) {
+ if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) &&
+ (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered))
+ {
int current_file;
for (current_file = sel->first; current_file <= sel->last; current_file++) {
- filelist_select_file(filelist, current_file, select, flag, check);
+ filelist_entry_select_index_set(filelist, current_file, select, flag, check);
}
}
}
-bool filelist_is_selected(struct FileList *filelist, int index, FileCheckType check)
+unsigned int filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
{
- struct direntry *file = filelist_file(filelist, index);
- if (!file) {
- return 0;
- }
- switch (check) {
- case CHECK_DIRS:
- return S_ISDIR(file->type) && (file->selflag & SELECTED_FILE);
- case CHECK_FILES:
- return S_ISREG(file->type) && (file->selflag & SELECTED_FILE);
- case CHECK_ALL:
- default:
- return (file->selflag & SELECTED_FILE) != 0;
+ BLI_assert(entry);
+ BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL));
+
+ if (((check == CHECK_ALL)) ||
+ ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
+ ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR)))
+ {
+ /* Default NULL pointer if not found is fine here! */
+ return GET_UINT_FROM_POINTER(BLI_ghash_lookup(filelist->selection_state, entry->uuid));
}
+
+ return 0;
}
-void filelist_sort(struct FileList *filelist, short sort)
+unsigned int filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
{
- switch (sort) {
- case FILE_SORT_ALPHA:
- qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);
- break;
- case FILE_SORT_TIME:
- qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);
- break;
- case FILE_SORT_SIZE:
- qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);
- break;
- case FILE_SORT_EXTENSION:
- qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);
- break;
+ FileDirEntry *entry = filelist_file(filelist, index);
+
+ if (entry) {
+ return filelist_entry_select_get(filelist, entry, check);
}
- filelist_filter(filelist);
+ return 0;
}
-
-bool filelist_islibrary(struct FileList *filelist, char *dir, char *group)
+bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
- return BLO_is_a_library(filelist->dir, dir, group);
+ return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
}
static int groupname_to_code(const char *group)
{
char buf[BLO_GROUP_MAX];
char *lslash;
-
+
+ BLI_assert(group);
+
BLI_strncpy(buf, group, sizeof(buf));
lslash = (char *)BLI_last_slash(buf);
if (lslash)
@@ -1042,371 +2158,556 @@ static int groupname_to_code(const char *group)
return buf[0] ? BKE_idcode_from_name(buf) : 0;
}
-
-void filelist_from_library(struct FileList *filelist)
+
+static unsigned int groupname_to_filter_id(const char *group)
{
- LinkNode *l, *names, *previews;
- struct ImBuf *ima;
- int ok, i, nprevs, nnames, idcode;
- char filename[FILE_MAX];
- char dir[FILE_MAX], group[BLO_GROUP_MAX];
-
+ int id_code = groupname_to_code(group);
+
+ return BKE_idcode_to_idfilter(id_code);
+}
+
+/**
+ * From here, we are in 'Job Context', i.e. have to be careful about sharing stuff between background working thread
+ * and main one (used by UI among other things).
+ */
+typedef struct TodoDir {
+ int level;
+ char *dir;
+} TodoDir;
+
+static int filelist_readjob_list_dir(
+ const char *root, ListBase *entries, const char *filter_glob,
+ const bool do_lib, const char *main_name, const bool skip_currpar)
+{
+ struct direntry *files;
+ int nbr_files, nbr_entries = 0;
+
+ nbr_files = BLI_filelist_dir_contents(root, &files);
+ if (files) {
+ int i = nbr_files;
+ while (i--) {
+ FileListInternEntry *entry;
+
+ if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) {
+ continue;
+ }
+
+ entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = MEM_dupallocN(files[i].relname);
+ entry->st = files[i].s;
+
+ /* Set file type. */
+ if (S_ISDIR(files[i].s.st_mode)) {
+ entry->typeflag = FILE_TYPE_DIR;
+ }
+ else if (do_lib && BLO_has_bfile_extension(entry->relpath)) {
+ /* If we are considering .blend files as libs, promote them to directory status. */
+ char name[FILE_MAX];
+
+ entry->typeflag = FILE_TYPE_BLENDER;
+
+ BLI_join_dirfile(name, sizeof(name), root, entry->relpath);
+
+ /* prevent current file being used as acceptable dir */
+ if (BLI_path_cmp(main_name, name) != 0) {
+ entry->typeflag |= FILE_TYPE_DIR;
+ }
+ }
+ /* Otherwise, do not check extensions for directories! */
+ else if (!(entry->typeflag & FILE_TYPE_DIR)) {
+ if (filter_glob[0] && BLI_testextensie_glob(entry->relpath, filter_glob)) {
+ entry->typeflag = FILE_TYPE_OPERATOR;
+ }
+ else {
+ entry->typeflag = file_extension_type(root, entry->relpath);
+ }
+ }
+
+ BLI_addtail(entries, entry);
+ nbr_entries++;
+ }
+ BLI_filelist_free(files, nbr_files);
+ }
+ return nbr_entries;
+}
+
+static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar)
+{
+ FileListInternEntry *entry;
+ LinkNode *ln, *names;
+ int i, nnames, idcode = 0, nbr_entries = 0;
+ char dir[FILE_MAX], *group;
+ bool ok;
+
+ struct BlendHandle *libfiledata = NULL;
+
/* name test */
- ok = filelist_islibrary(filelist, dir, group);
+ ok = BLO_library_path_explode(root, dir, &group, NULL);
if (!ok) {
- /* free */
- if (filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata);
- filelist->libfiledata = NULL;
- return;
+ return nbr_entries;
}
-
- BLI_strncpy(filename, G.main->name, sizeof(filename));
/* there we go */
- /* for the time being only read filedata when libfiledata==0 */
- if (filelist->libfiledata == NULL) {
- filelist->libfiledata = BLO_blendhandle_from_file(dir, NULL);
- if (filelist->libfiledata == NULL) return;
+ libfiledata = BLO_blendhandle_from_file(dir, NULL);
+ if (libfiledata == NULL) {
+ return nbr_entries;
}
-
- idcode = groupname_to_code(group);
-
- /* memory for strings is passed into filelist[i].relname
- * and freed in freefilelist */
- if (idcode) {
- previews = BLO_blendhandle_get_previews(filelist->libfiledata, idcode, &nprevs);
- names = BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode, &nnames);
- /* ugh, no rewind, need to reopen */
- BLO_blendhandle_close(filelist->libfiledata);
- filelist->libfiledata = BLO_blendhandle_from_file(dir, NULL);
-
+
+ /* memory for strings is passed into filelist[i].entry->relpath and freed in filelist_entry_free. */
+ if (group) {
+ idcode = groupname_to_code(group);
+ names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames);
}
else {
- previews = NULL;
- nprevs = 0;
- names = BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
- nnames = BLI_linklist_length(names);
+ names = BLO_blendhandle_get_linkable_groups(libfiledata);
+ nnames = BLI_linklist_count(names);
}
- filelist->numfiles = nnames + 1;
- filelist->filelist = malloc(filelist->numfiles * sizeof(*filelist->filelist));
- memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
+ BLO_blendhandle_close(libfiledata);
- filelist->filelist[0].relname = BLI_strdup("..");
- filelist->filelist[0].type |= S_IFDIR;
-
- for (i = 0, l = names; i < nnames; i++, l = l->next) {
- const char *blockname = l->link;
+ if (!skip_currpar) {
+ entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = BLI_strdup(FILENAME_PARENT);
+ entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ BLI_addtail(entries, entry);
+ nbr_entries++;
+ }
+
+ for (i = 0, ln = names; i < nnames; i++, ln = ln->next) {
+ const char *blockname = ln->link;
- filelist->filelist[i + 1].relname = BLI_strdup(blockname);
- if (idcode) {
- filelist->filelist[i + 1].type |= S_IFREG;
+ entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = BLI_strdup(blockname);
+ entry->typeflag |= FILE_TYPE_BLENDERLIB;
+ if (!(group && idcode)) {
+ entry->typeflag |= FILE_TYPE_DIR;
+ entry->blentype = groupname_to_code(blockname);
}
else {
- filelist->filelist[i + 1].type |= S_IFDIR;
- }
- }
-
- if (previews && (nnames != nprevs)) {
- printf("filelist_from_library: error, found %d items, %d previews\n", nnames, nprevs);
- }
- else if (previews) {
- for (i = 0, l = previews; i < nnames; i++, l = l->next) {
- PreviewImage *img = l->link;
-
- if (img) {
- unsigned int w = img->w[ICON_SIZE_PREVIEW];
- unsigned int h = img->h[ICON_SIZE_PREVIEW];
- unsigned int *rect = img->rect[ICON_SIZE_PREVIEW];
-
- /* first allocate imbuf for copying preview into it */
- if (w > 0 && h > 0 && rect) {
- ima = IMB_allocImBuf(w, h, 32, IB_rect);
- memcpy(ima->rect, rect, w * h * sizeof(unsigned int));
- filelist->filelist[i + 1].image = ima;
- filelist->filelist[i + 1].flags = IMAGEFILE;
- }
- }
+ entry->blentype = idcode;
}
+ BLI_addtail(entries, entry);
+ nbr_entries++;
}
BLI_linklist_free(names, free);
- if (previews) BLI_linklist_free(previews, BKE_previewimg_freefunc);
-
- filelist_sort(filelist, FILE_SORT_ALPHA);
- BLI_strncpy(G.main->name, filename, sizeof(filename)); /* prevent G.main->name to change */
-
- filelist->filter = 0;
- filelist_filter(filelist);
+ return nbr_entries;
}
-void filelist_hideparent(struct FileList *filelist, short hide)
-{
- filelist->hide_parent = hide;
-}
-
-void filelist_from_main(struct FileList *filelist)
+#if 0
+/* Kept for reference here, in case we want to add back that feature later. We do not need it currently. */
+/* Code ***NOT*** updated for job stuff! */
+static void filelist_readjob_main_rec(struct FileList *filelist)
{
ID *id;
- struct direntry *files, *firstlib = NULL;
+ FileDirEntry *files, *firstlib = NULL;
ListBase *lb;
int a, fake, idcode, ok, totlib, totbl;
- // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser
+ // filelist->type = FILE_MAIN; // XXX TODO: add modes to filebrowser
- if (filelist->dir[0] == '/') filelist->dir[0] = 0;
-
- if (filelist->dir[0]) {
- idcode = groupname_to_code(filelist->dir);
- if (idcode == 0) filelist->dir[0] = 0;
+ BLI_assert(filelist->filelist.entries == NULL);
+
+ if (filelist->filelist.root[0] == '/') filelist->filelist.root[0] = '\0';
+
+ if (filelist->filelist.root[0]) {
+ idcode = groupname_to_code(filelist->filelist.root);
+ if (idcode == 0) filelist->filelist.root[0] = '\0';
}
-
+
if (filelist->dir[0] == 0) {
-
/* make directories */
#ifdef WITH_FREESTYLE
- filelist->numfiles = 25;
+ filelist->filelist.nbr_entries = 24;
#else
- filelist->numfiles = 24;
+ filelist->filelist.nbr_entries = 23;
#endif
- filelist->filelist = (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
-
- for (a = 0; a < filelist->numfiles; a++) {
- memset(&(filelist->filelist[a]), 0, sizeof(struct direntry));
- filelist->filelist[a].type |= S_IFDIR;
+ filelist_resize(filelist, filelist->filelist.nbr_entries);
+
+ for (a = 0; a < filelist->filelist.nbr_entries; a++) {
+ filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR;
}
-
- filelist->filelist[0].relname = BLI_strdup("..");
- filelist->filelist[2].relname = BLI_strdup("Scene");
- filelist->filelist[3].relname = BLI_strdup("Object");
- filelist->filelist[4].relname = BLI_strdup("Mesh");
- filelist->filelist[5].relname = BLI_strdup("Curve");
- filelist->filelist[6].relname = BLI_strdup("Metaball");
- filelist->filelist[7].relname = BLI_strdup("Material");
- filelist->filelist[8].relname = BLI_strdup("Texture");
- filelist->filelist[9].relname = BLI_strdup("Image");
- filelist->filelist[10].relname = BLI_strdup("Ika");
- filelist->filelist[11].relname = BLI_strdup("Wave");
- filelist->filelist[12].relname = BLI_strdup("Lattice");
- filelist->filelist[13].relname = BLI_strdup("Lamp");
- filelist->filelist[14].relname = BLI_strdup("Camera");
- filelist->filelist[15].relname = BLI_strdup("Ipo");
- filelist->filelist[16].relname = BLI_strdup("World");
- filelist->filelist[17].relname = BLI_strdup("Screen");
- filelist->filelist[18].relname = BLI_strdup("VFont");
- filelist->filelist[19].relname = BLI_strdup("Text");
- filelist->filelist[20].relname = BLI_strdup("Armature");
- filelist->filelist[21].relname = BLI_strdup("Action");
- filelist->filelist[22].relname = BLI_strdup("NodeTree");
- filelist->filelist[23].relname = BLI_strdup("Speaker");
+
+ filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT);
+ filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene");
+ filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object");
+ filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh");
+ filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve");
+ filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball");
+ filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material");
+ filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture");
+ filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image");
+ filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika");
+ filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave");
+ filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice");
+ filelist->filelist.entries[12].entry->relpath = BLI_strdup("Lamp");
+ filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera");
+ filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo");
+ filelist->filelist.entries[15].entry->relpath = BLI_strdup("World");
+ filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen");
+ filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont");
+ filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text");
+ filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature");
+ filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action");
+ filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree");
+ filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker");
#ifdef WITH_FREESTYLE
- filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle");
+ filelist->filelist.entries[23].entry->relpath = BLI_strdup("FreestyleLineStyle");
#endif
- filelist_sort(filelist, FILE_SORT_ALPHA);
}
else {
-
/* make files */
- idcode = groupname_to_code(filelist->dir);
-
+ idcode = groupname_to_code(filelist->filelist.root);
+
lb = which_libbase(G.main, idcode);
if (lb == NULL) return;
-
- id = lb->first;
- filelist->numfiles = 0;
- while (id) {
- if (!filelist->hide_dot || id->name[2] != '.') {
- filelist->numfiles++;
+
+ filelist->filelist.nbr_entries = 0;
+ for (id = lb->first; id; id = id->next) {
+ if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
+ filelist->filelist.nbr_entries++;
}
-
- id = id->next;
}
-
- /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */
- if (!filelist->hide_parent) filelist->numfiles += 1;
- filelist->filelist = filelist->numfiles > 0 ? (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)) : NULL;
- files = filelist->filelist;
-
- if (!filelist->hide_parent) {
- memset(&(filelist->filelist[0]), 0, sizeof(struct direntry));
- filelist->filelist[0].relname = BLI_strdup("..");
- filelist->filelist[0].type |= S_IFDIR;
+ /* XXX TODO: if databrowse F4 or append/link filelist->flags & FLF_HIDE_PARENT has to be set */
+ if (!(filelist->filter_data.flags & FLF_HIDE_PARENT))
+ filelist->filelist.nbr_entries++;
+
+ if (filelist->filelist.nbr_entries > 0) {
+ filelist_resize(filelist, filelist->filelist.nbr_entries);
+ }
+
+ files = filelist->filelist.entries;
+ if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
+ files->entry->relpath = BLI_strdup(FILENAME_PARENT);
+ files->typeflag |= FILE_TYPE_DIR;
+
files++;
}
-
- id = lb->first;
+
totlib = totbl = 0;
-
- while (id) {
+ for (id = lb->first; id; id = id->next) {
ok = 1;
if (ok) {
- if (!filelist->hide_dot || id->name[2] != '.') {
- memset(files, 0, sizeof(struct direntry));
+ if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
if (id->lib == NULL) {
- files->relname = BLI_strdup(id->name + 2);
+ files->entry->relpath = BLI_strdup(id->name + 2);
}
else {
- files->relname = MEM_mallocN(FILE_MAX + (MAX_ID_NAME - 2), "filename for lib");
- BLI_snprintf(files->relname, FILE_MAX + (MAX_ID_NAME - 2) + 3, "%s | %s", id->lib->name, id->name + 2);
+ char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3];
+ BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->name, id->name + 2);
+ files->entry->relpath = BLI_strdup(relname);
}
- files->type |= S_IFREG;
-#if 0 /* XXXXX TODO show the selection status of the objects */
+// files->type |= S_IFREG;
+#if 0 /* XXX TODO show the selection status of the objects */
if (!filelist->has_func) { /* F4 DATA BROWSE */
if (idcode == ID_OB) {
- if ( ((Object *)id)->flag & SELECT) files->selflag |= SELECTED_FILE;
+ if ( ((Object *)id)->flag & SELECT) files->entry->selflag |= FILE_SEL_SELECTED;
}
else if (idcode == ID_SCE) {
- if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->selflag |= SELECTED_FILE;
+ if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->entry->selflag |= FILE_SEL_SELECTED;
}
}
#endif
- files->nr = totbl + 1;
- files->poin = id;
+// files->entry->nr = totbl + 1;
+ files->entry->poin = id;
fake = id->flag & LIB_FAKEUSER;
if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
- files->flags |= IMAGEFILE;
+ files->typeflag |= FILE_TYPE_IMAGE;
}
- if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->extra), "LF %d", id->us);
- else if (id->lib) BLI_snprintf(files->extra, sizeof(files->extra), "L %d", id->us);
- else if (fake) BLI_snprintf(files->extra, sizeof(files->extra), "F %d", id->us);
- else BLI_snprintf(files->extra, sizeof(files->extra), " %d", id->us);
-
+// if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us);
+// else if (id->lib) BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us);
+// else if (fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us);
+// else BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us);
+
if (id->lib) {
if (totlib == 0) firstlib = files;
totlib++;
}
-
+
files++;
}
totbl++;
}
-
- id = id->next;
}
-
+
/* only qsort of library blocks */
if (totlib > 1) {
- qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
+ qsort(firstlib, totlib, sizeof(*files), compare_name);
}
}
- filelist->filter = 0;
- filelist_filter(filelist);
}
+#endif
-static void thumbnail_joblist_free(ThumbnailJob *tj)
+static void filelist_readjob_do(
+ const bool do_lib,
+ FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
{
- FileImage *limg = tj->loadimages.first;
-
- /* free the images not yet copied to the filelist -> these will get freed with the filelist */
- for (; limg; limg = limg->next) {
- if ((limg->img) && (!limg->done)) {
- IMB_freeImBuf(limg->img);
+ ListBase entries = {0};
+ BLI_Stack *todo_dirs;
+ TodoDir *td_dir;
+ char dir[FILE_MAX_LIBEXTRA];
+ char filter_glob[64]; /* TODO should be define! */
+ const char *root = filelist->filelist.root;
+ const int max_recursion = filelist->max_recursion;
+ int nbr_done_dirs = 0, nbr_todo_dirs = 1;
+
+// BLI_assert(filelist->filtered == NULL);
+ BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && (filelist->filelist.nbr_entries == 0));
+
+ todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__);
+ td_dir = BLI_stack_push_r(todo_dirs);
+ td_dir->level = 1;
+
+ BLI_strncpy(dir, filelist->filelist.root, sizeof(dir));
+ BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob));
+
+ BLI_cleanup_dir(main_name, dir);
+ td_dir->dir = BLI_strdup(dir);
+
+ while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
+ FileListInternEntry *entry;
+ int nbr_entries = 0;
+ bool is_lib = do_lib;
+
+ char *subdir;
+ int recursion_level;
+ bool skip_currpar;
+
+ td_dir = BLI_stack_peek(todo_dirs);
+ subdir = td_dir->dir;
+ recursion_level = td_dir->level;
+ skip_currpar = (recursion_level > 1);
+
+ BLI_stack_discard(todo_dirs);
+
+ if (do_lib) {
+ nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar);
+ }
+ if (!nbr_entries) {
+ is_lib = false;
+ nbr_entries = filelist_readjob_list_dir(subdir, &entries, filter_glob, do_lib, main_name, skip_currpar);
+ }
+
+ for (entry = entries.first; entry; entry = entry->next) {
+ BLI_join_dirfile(dir, sizeof(dir), subdir, entry->relpath);
+ BLI_cleanup_file(root, dir);
+
+ /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here,
+ * things would crash way before we overflow that counter!
+ * Using an atomic operation to avoid having to lock thread...
+ * Note that we do not really need this here currently, since there is a single listing thread, but better
+ * remain consistent about threading! */
+ *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
+
+ BLI_path_rel(dir, root);
+ /* Only thing we change in direntry here, so we need to free it first. */
+ MEM_freeN(entry->relpath);
+ entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' added by BLI_path_rel */
+ entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir));
+
+ /* Here we decide whether current filedirentry is to be listed too, or not. */
+ if (max_recursion && (is_lib || (recursion_level <= max_recursion))) {
+ if (((entry->typeflag & FILE_TYPE_DIR) == 0) || FILENAME_IS_CURRPAR(entry->relpath)) {
+ /* Skip... */
+ }
+ else if (!is_lib && (recursion_level >= max_recursion) &&
+ ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0))
+ {
+ /* Do not recurse in real directories in this case, only in .blend libs. */
+ }
+ else {
+ /* We have a directory we want to list, add it to todo list! */
+ BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
+ BLI_cleanup_dir(main_name, dir);
+ td_dir = BLI_stack_push_r(todo_dirs);
+ td_dir->level = recursion_level + 1;
+ td_dir->dir = BLI_strdup(dir);
+ nbr_todo_dirs++;
+ }
+ }
+ }
+
+ if (nbr_entries) {
+ BLI_mutex_lock(lock);
+
+ *do_update = true;
+
+ BLI_movelisttolist(&filelist->filelist.entries, &entries);
+ filelist->filelist.nbr_entries += nbr_entries;
+
+ BLI_mutex_unlock(lock);
}
+
+ nbr_done_dirs++;
+ *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs;
+ MEM_freeN(subdir);
}
- BLI_freelistN(&tj->loadimages);
+
+ /* If we were interrupted by stop, stack may not be empty and we need to free pending dir paths. */
+ while (!BLI_stack_is_empty(todo_dirs)) {
+ td_dir = BLI_stack_peek(todo_dirs);
+ MEM_freeN(td_dir->dir);
+ BLI_stack_discard(todo_dirs);
+ }
+ BLI_stack_free(todo_dirs);
}
-static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *UNUSED(progress))
+static void filelist_readjob_dir(
+ FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
{
- ThumbnailJob *tj = tjv;
- FileImage *limg = tj->loadimages.first;
+ filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock);
+}
- tj->stop = stop;
- tj->do_update = do_update;
+static void filelist_readjob_lib(
+ FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
+{
+ filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock);
+}
- while ((*stop == 0) && (limg)) {
- if (limg->flags & IMAGEFILE) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
- }
- else if (limg->flags & (BLENDERFILE | BLENDERFILE_BACKUP)) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
- }
- else if (limg->flags & MOVIEFILE) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
- if (!limg->img) {
- /* remember that file can't be loaded via IMB_open_anim */
- limg->flags &= ~MOVIEFILE;
- limg->flags |= MOVIEFILE_ICON;
- }
- }
- *do_update = true;
- PIL_sleep_ms(10);
- limg = limg->next;
- }
+static void filelist_readjob_main(
+ FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
+{
+ /* TODO! */
+ filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock);
}
-static void thumbnails_update(void *tjv)
+
+typedef struct FileListReadJob {
+ ThreadMutex lock;
+ char main_name[FILE_MAX];
+ struct FileList *filelist;
+ struct FileList *tmp_filelist; /* XXX We may use a simpler struct here... just a linked list and root path? */
+} FileListReadJob;
+
+static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
{
- ThumbnailJob *tj = tjv;
+ FileListReadJob *flrj = flrjv;
- if (tj->filelist && tj->filelist->filelist) {
- FileImage *limg = tj->loadimages.first;
- while (limg) {
- if (!limg->done && limg->img) {
- tj->filelist->filelist[limg->index].image = limg->img;
- /* update flag for movie files where thumbnail can't be created */
- if (limg->flags & MOVIEFILE_ICON) {
- tj->filelist->filelist[limg->index].flags &= ~MOVIEFILE;
- tj->filelist->filelist[limg->index].flags |= MOVIEFILE_ICON;
- }
- limg->done = true;
- }
- limg = limg->next;
- }
+// printf("START filelist reading (%d files, main thread: %d)\n",
+// flrj->filelist->filelist.nbr_entries, BLI_thread_is_main());
+
+ BLI_mutex_lock(&flrj->lock);
+
+ BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist);
+
+ flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
+
+ BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries);
+ flrj->tmp_filelist->filelist.nbr_entries = 0;
+
+ flrj->tmp_filelist->filelist_intern.filtered = NULL;
+ BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries);
+ memset(flrj->tmp_filelist->filelist_intern.curr_uuid, 0, sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid));
+
+ flrj->tmp_filelist->libfiledata = NULL;
+ memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
+ flrj->tmp_filelist->selection_state = NULL;
+
+ BLI_mutex_unlock(&flrj->lock);
+
+ flrj->tmp_filelist->read_jobf(flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock);
+}
+
+static void filelist_readjob_update(void *flrjv)
+{
+ FileListReadJob *flrj = flrjv;
+ FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
+ ListBase new_entries = {NULL};
+ int nbr_entries, new_nbr_entries = 0;
+
+ BLI_movelisttolist(&new_entries, &fl_intern->entries);
+ nbr_entries = flrj->filelist->filelist.nbr_entries;
+
+ BLI_mutex_lock(&flrj->lock);
+
+ if (flrj->tmp_filelist->filelist.nbr_entries) {
+ /* We just move everything out of 'thread context' into final list. */
+ new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries;
+ BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
+ flrj->tmp_filelist->filelist.nbr_entries = 0;
}
+
+ BLI_mutex_unlock(&flrj->lock);
+
+ if (new_nbr_entries) {
+ /* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */
+ filelist_clear_ex(flrj->filelist, true, false);
+
+ flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING);
+ }
+
+ /* if no new_nbr_entries, this is NOP */
+ BLI_movelisttolist(&fl_intern->entries, &new_entries);
+ flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries;
}
-static void thumbnails_free(void *tjv)
+static void filelist_readjob_endjob(void *flrjv)
{
- ThumbnailJob *tj = tjv;
- thumbnail_joblist_free(tj);
- MEM_freeN(tj);
+ FileListReadJob *flrj = flrjv;
+
+ /* In case there would be some dangling update... */
+ filelist_readjob_update(flrjv);
+
+ flrj->filelist->flags &= ~FL_IS_PENDING;
+ flrj->filelist->flags |= FL_IS_READY;
}
+static void filelist_readjob_free(void *flrjv)
+{
+ FileListReadJob *flrj = flrjv;
+
+// printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries);
+
+ if (flrj->tmp_filelist) {
+ /* tmp_filelist shall never ever be filtered! */
+ BLI_assert(flrj->tmp_filelist->filelist.nbr_entries == 0);
+ BLI_assert(BLI_listbase_is_empty(&flrj->tmp_filelist->filelist.entries));
-void thumbnails_start(FileList *filelist, const bContext *C)
+ filelist_freelib(flrj->tmp_filelist);
+ filelist_free(flrj->tmp_filelist);
+ MEM_freeN(flrj->tmp_filelist);
+ }
+
+ BLI_mutex_end(&flrj->lock);
+
+ MEM_freeN(flrj);
+}
+
+void filelist_readjob_start(FileList *filelist, const bContext *C)
{
wmJob *wm_job;
- ThumbnailJob *tj;
- int idx;
-
+ FileListReadJob *flrj;
+
/* prepare job data */
- tj = MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n");
- tj->filelist = filelist;
- for (idx = 0; idx < filelist->numfiles; idx++) {
- if (!filelist->filelist[idx].image) {
- if ((filelist->filelist[idx].flags & (IMAGEFILE | MOVIEFILE | BLENDERFILE | BLENDERFILE_BACKUP))) {
- FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage");
- BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX);
- limg->index = idx;
- limg->flags = filelist->filelist[idx].flags;
- BLI_addtail(&tj->loadimages, limg);
- }
- }
- }
+ flrj = MEM_callocN(sizeof(*flrj), __func__);
+ flrj->filelist = filelist;
+ BLI_strncpy(flrj->main_name, G.main->name, sizeof(flrj->main_name));
+
+ filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY);
+ filelist->flags |= FL_IS_PENDING;
- BKE_reports_init(&tj->reports, RPT_PRINT);
+ BLI_mutex_init(&flrj->lock);
/* setup job */
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails",
- 0, WM_JOB_TYPE_FILESEL_THUMBNAIL);
- WM_jobs_customdata_set(wm_job, tj, thumbnails_free);
- WM_jobs_timer(wm_job, 0.5, NC_WINDOW, NC_WINDOW);
- WM_jobs_callbacks(wm_job, thumbnails_startjob, NULL, thumbnails_update, NULL);
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Listing Dirs...",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_FILESEL_READDIR);
+ WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
+ WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
+ WM_jobs_callbacks(wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
/* start the job */
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-void thumbnails_stop(wmWindowManager *wm, FileList *filelist)
+void filelist_readjob_stop(wmWindowManager *wm, ScrArea *sa)
{
- WM_jobs_kill(wm, filelist, NULL);
+ WM_jobs_kill_type(wm, sa, WM_JOB_TYPE_FILESEL_READDIR);
}
-int thumbnails_running(wmWindowManager *wm, FileList *filelist)
+int filelist_readjob_running(wmWindowManager *wm, ScrArea *sa)
{
- return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL);
+ return WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR);
}
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index c37bb882168..d70faab1d6a 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -40,14 +40,10 @@ extern "C" {
struct BlendHandle;
struct FileList;
struct FileSelection;
-struct FolderList;
-struct Main;
-struct ReportList;
-struct Scene;
-struct direntry;
-struct rcti;
struct wmWindowManager;
+struct FileDirEntry;
+
typedef enum FileSelType {
FILE_SEL_REMOVE = 0,
FILE_SEL_ADD = 1,
@@ -60,50 +56,69 @@ typedef enum FileCheckType {
CHECK_ALL = 3
} FileCheckType;
-struct FileList * filelist_new(short type);
+struct ListBase * folderlist_new(void);
+void folderlist_free(struct ListBase *folderlist);
+struct ListBase * folderlist_duplicate(ListBase *folderlist);
+void folderlist_popdir(struct ListBase *folderlist, char *dir);
+void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
+const char * folderlist_peeklastdir(struct ListBase *folderdist);
+int folderlist_clear_next(struct SpaceFile *sfile);
+
+
+void filelist_setsorting(struct FileList *filelist, const short sort);
+void filelist_sort(struct FileList *filelist);
+
+void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent,
+ const unsigned int filter, const unsigned int filter_id,
+ const char *filter_glob, const char *filter_search);
+void filelist_filter(struct FileList *filelist);
+
void filelist_init_icons(void);
void filelist_free_icons(void);
-int filelist_find(struct FileList *filelist, const char *file);
+void filelist_imgsize(struct FileList *filelist, short w, short h);
+struct ImBuf * filelist_getimage(struct FileList *filelist, const int index);
+struct ImBuf * filelist_geticon_image(struct FileList *filelist, const int index);
+int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
+
+struct FileList * filelist_new(short type);
+void filelist_clear(struct FileList *filelist);
+void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection);
void filelist_free(struct FileList *filelist);
-void filelist_sort(struct FileList *filelist, short sort);
-int filelist_numfiles(struct FileList *filelist);
+
const char * filelist_dir(struct FileList *filelist);
-void filelist_setdir(struct FileList *filelist, const char *dir);
-struct direntry * filelist_file(struct FileList *filelist, int index);
-void filelist_select(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check);
-void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check);
-bool filelist_is_selected(struct FileList *filelist, int index, FileCheckType check);
-void filelist_hidedot(struct FileList *filelist, short hide);
-void filelist_setfilter(struct FileList *filelist, unsigned int filter);
-void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob);
-void filelist_filter(struct FileList *filelist);
-void filelist_imgsize(struct FileList *filelist, short w, short h);
-struct ImBuf * filelist_getimage(struct FileList *filelist, int index);
-struct ImBuf * filelist_geticon(struct FileList *filelist, int index);
-short filelist_changed(struct FileList *filelist);
-void filelist_readdir(struct FileList *filelist);
+void filelist_setdir(struct FileList *filelist, char *r_dir);
+int filelist_files_ensure(struct FileList *filelist);
int filelist_empty(struct FileList *filelist);
-void filelist_parent(struct FileList *filelist);
+FileDirEntry * filelist_file(struct FileList *filelist, int index);
+int filelist_file_findpath(struct FileList *filelist, const char *file);
+FileDirEntry * filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
+void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
+bool filelist_file_cache_block(struct FileList *filelist, const int index);
+
+bool filelist_force_reset(struct FileList *filelist);
+bool filelist_pending(struct FileList *filelist);
+bool filelist_is_ready(struct FileList *filelist);
+
+unsigned int filelist_entry_select_set(const struct FileList *filelist, const struct FileDirEntry *entry, FileSelType select, unsigned int flag, FileCheckType check);
+void filelist_entry_select_index_set(struct FileList *filelist, const int index, FileSelType select, unsigned int flag, FileCheckType check);
+void filelist_entries_select_index_range_set(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check);
+unsigned int filelist_entry_select_get(struct FileList *filelist, struct FileDirEntry *entry, FileCheckType check);
+unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check);
+
+void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
struct BlendHandle *filelist_lib(struct FileList *filelist);
-bool filelist_islibrary(struct FileList *filelist, char *dir, char *group);
-void filelist_from_main(struct FileList *filelist);
-void filelist_from_library(struct FileList *filelist);
+bool filelist_islibrary(struct FileList *filelist, char *dir, char **group);
void filelist_freelib(struct FileList *filelist);
-void filelist_hideparent(struct FileList *filelist, short hide);
-struct ListBase * folderlist_new(void);
-void folderlist_free(struct ListBase *folderlist);
-struct ListBase * folderlist_duplicate(ListBase *folderlist);
-void folderlist_popdir(struct ListBase *folderlist, char *dir);
-void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
-const char * folderlist_peeklastdir(struct ListBase *folderdist);
-int folderlist_clear_next(struct SpaceFile *sfile);
+void filelist_readjob_start(struct FileList *filelist, const struct bContext *C);
+void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa);
+int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa);
-void thumbnails_start(struct FileList *filelist, const struct bContext *C);
-void thumbnails_stop(struct wmWindowManager *wm, struct FileList *filelist);
-int thumbnails_running(struct wmWindowManager *wm, struct FileList *filelist);
+bool filelist_cache_previews_update(struct FileList *filelist);
+void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);
+bool filelist_cache_previews_running(struct FileList *filelist);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index afe3f29e9bc..da24f1ce95d 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -58,6 +58,7 @@
#include "BLI_fileops_types.h"
#include "BLI_fnmatch.h"
+#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -101,6 +102,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
/* set path to most recently opened .blend */
BLI_split_dirfile(G.main->name, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
+ /* set the default thumbnails size */
+ sfile->params->thumbnail_size = 128;
}
params = sfile->params;
@@ -116,10 +119,12 @@ short ED_fileselect_set_params(SpaceFile *sfile)
BLI_strncpy_utf8(params->title, RNA_struct_ui_name(op->type->srna), sizeof(params->title));
- if (RNA_struct_find_property(op->ptr, "filemode"))
- params->type = RNA_int_get(op->ptr, "filemode");
- else
+ if ((prop = RNA_struct_find_property(op->ptr, "filemode"))) {
+ params->type = RNA_property_int_get(op->ptr, prop);
+ }
+ else {
params->type = FILE_SPECIAL;
+ }
if (is_filepath && RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
char name[FILE_MAX];
@@ -157,30 +162,32 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->filter = 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_blender")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0;
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_blenlib")))
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDERLIB : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_backup")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE_BACKUP : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER_BACKUP : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_image")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? IMAGEFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_IMAGE : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_movie")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? MOVIEFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_MOVIE : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_python")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? PYSCRIPTFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_PYSCRIPT : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_font")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FTFONTFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FTFONT : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_sound")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? SOUNDFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_SOUND : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_text")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? TEXTFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_folder")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FOLDERFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_btx")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BTXFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_collada")))
- params->filter |= RNA_property_boolean_get(op->ptr, prop) ? COLLADAFILE : 0;
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
RNA_property_string_get(op->ptr, prop, params->filter_glob);
- params->filter |= (OPERATORFILE | FOLDERFILE);
+ params->filter |= (FILE_TYPE_OPERATOR | FILE_TYPE_FOLDER);
}
else {
params->filter_glob[0] = '\0';
@@ -195,6 +202,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
}
+ /* For now, always init filterid to 'all true' */
+ params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD |
+ FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA |
+ FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB |
+ FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO |
+ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO;
+
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
}
@@ -209,12 +223,20 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag |= RNA_boolean_get(op->ptr, "active_layer") ? FILE_ACTIVELAY : 0;
}
- if (RNA_struct_find_property(op->ptr, "display_type"))
- params->display = RNA_enum_get(op->ptr, "display_type");
+ if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
+ params->display = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "sort_method"))) {
+ params->sort = RNA_property_enum_get(op->ptr, prop);
+ }
+ else {
+ params->sort = FILE_SORT_ALPHA;
+ }
if (params->display == FILE_DEFAULTDISPLAY) {
if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (IMAGEFILE | MOVIEFILE))
+ if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE))
params->display = FILE_IMGDISPLAY;
else
params->display = FILE_SHORTDISPLAY;
@@ -225,8 +247,10 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
if (is_relative_path) {
- if (!RNA_struct_property_is_set_ex(op->ptr, "relative_path", false)) {
- RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
+ if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
+ if (!RNA_property_is_set_ex(op->ptr, prop, false)) {
+ RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_RELPATHS) != 0);
+ }
}
}
}
@@ -241,7 +265,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
/* operator has no setting for this */
- params->sort = FILE_SORT_ALPHA;
+ params->active_file = -1;
/* initialize the list with previous folders */
@@ -253,7 +277,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
BLI_split_dir_part(G.main->name, sfile->params->dir, sizeof(sfile->params->dir));
}
else {
- const char *doc_path = BLI_getDefaultDocumentFolder();
+ const char *doc_path = BKE_appdir_folder_default();
if (doc_path) {
BLI_strncpy(sfile->params->dir, doc_path, sizeof(sfile->params->dir));
}
@@ -275,6 +299,18 @@ void ED_fileselect_reset_params(SpaceFile *sfile)
sfile->params->type = FILE_UNIX;
sfile->params->flag = 0;
sfile->params->title[0] = '\0';
+ sfile->params->active_file = -1;
+}
+
+/**
+ * Sets FileSelectParams->file (name of selected file)
+ */
+void fileselect_file_set(SpaceFile *sfile, const int index)
+{
+ const struct FileDirEntry *file = filelist_file(sfile->files, index);
+ if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) {
+ BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE);
+ }
}
int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar)
@@ -390,63 +426,23 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
}
}
-/* Shorten a string to a given width w.
- * If front is set, shorten from the front,
- * otherwise shorten from the end. */
-float file_shorten_string(char *string, float w, int front)
-{
- char temp[FILE_MAX];
- short shortened = 0;
- float sw = 0;
- float pad = 0;
-
- if (w <= 0) {
- *string = '\0';
- return 0.0;
- }
+float file_string_width(const char *str)
+{
+ uiStyle *style = UI_style_get();
+ float width;
- sw = file_string_width(string);
- if (front == 1) {
- const char *s = string;
- BLI_strncpy(temp, "...", 4);
- pad = file_string_width(temp);
- while ((*s) && (sw + pad > w)) {
- s++;
- sw = file_string_width(s);
- shortened = 1;
- }
- if (shortened) {
- int slen = strlen(s);
- BLI_strncpy(temp + 3, s, slen + 1);
- temp[slen + 4] = '\0';
- BLI_strncpy(string, temp, slen + 4);
- }
+ UI_fontstyle_set(&style->widget);
+ if (style->widget.kerning == 1) { /* for BLF_width */
+ BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
}
- else {
- const char *s = string;
- while (sw > w) {
- int slen = strlen(string);
- string[slen - 1] = '\0';
- sw = file_string_width(s);
- shortened = 1;
- }
- if (shortened) {
- int slen = strlen(string);
- if (slen > 3) {
- BLI_strncpy(string + slen - 3, "...", 4);
- }
- }
+ width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (style->widget.kerning == 1) {
+ BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
}
-
- return sw;
-}
-float file_string_width(const char *str)
-{
- uiStyle *style = UI_GetStyle();
- uiStyleFontSet(&style->widget);
- return BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ return width;
}
float file_font_pointsize(void)
@@ -454,48 +450,31 @@ float file_font_pointsize(void)
#if 0
float s;
char tmp[2] = "X";
- uiStyle *style = UI_GetStyle();
- uiStyleFontSet(&style->widget);
+ uiStyle *style = UI_style_get();
+ UI_fontstyle_set(&style->widget);
s = BLF_height(style->widget.uifont_id, tmp);
return style->widget.points;
#else
- uiStyle *style = UI_GetStyle();
- uiStyleFontSet(&style->widget);
+ uiStyle *style = UI_style_get();
+ UI_fontstyle_set(&style->widget);
return style->widget.points * UI_DPI_FAC;
#endif
}
-static void column_widths(struct FileList *files, struct FileLayout *layout)
+static void column_widths(FileSelectParams *params, struct FileLayout *layout)
{
int i;
- int numfiles = filelist_numfiles(files);
+ const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
for (i = 0; i < MAX_FILE_COLUMN; ++i) {
layout->column_widths[i] = 0;
}
- for (i = 0; (i < numfiles); ++i) {
- struct direntry *file = filelist_file(files, i);
- if (file) {
- float len;
- len = file_string_width(file->relname);
- if (len > layout->column_widths[COLUMN_NAME]) layout->column_widths[COLUMN_NAME] = len;
- len = file_string_width(file->date);
- if (len > layout->column_widths[COLUMN_DATE]) layout->column_widths[COLUMN_DATE] = len;
- len = file_string_width(file->time);
- if (len > layout->column_widths[COLUMN_TIME]) layout->column_widths[COLUMN_TIME] = len;
- len = file_string_width(file->size);
- if (len > layout->column_widths[COLUMN_SIZE]) layout->column_widths[COLUMN_SIZE] = len;
- len = file_string_width(file->mode1);
- if (len > layout->column_widths[COLUMN_MODE1]) layout->column_widths[COLUMN_MODE1] = len;
- len = file_string_width(file->mode2);
- if (len > layout->column_widths[COLUMN_MODE2]) layout->column_widths[COLUMN_MODE2] = len;
- len = file_string_width(file->mode3);
- if (len > layout->column_widths[COLUMN_MODE3]) layout->column_widths[COLUMN_MODE3] = len;
- len = file_string_width(file->owner);
- if (len > layout->column_widths[COLUMN_OWNER]) layout->column_widths[COLUMN_OWNER] = len;
- }
- }
+ layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;;
+ /* Biggest possible reasonable values... */
+ layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89");
+ layout->column_widths[COLUMN_TIME] = file_string_width("23:59");
+ layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB");
}
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
@@ -515,14 +494,14 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
return;
}
- numfiles = filelist_numfiles(sfile->files);
+ numfiles = filelist_files_ensure(sfile->files);
textheight = (int)file_font_pointsize();
layout = sfile->layout;
layout->textheight = textheight;
if (params->display == FILE_IMGDISPLAY) {
- layout->prv_w = 4.8f * UI_UNIT_X;
- layout->prv_h = 4.8f * UI_UNIT_Y;
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.3f * UI_UNIT_X;
layout->tile_border_y = 0.3f * UI_UNIT_X;
layout->prv_border_x = 0.3f * UI_UNIT_X;
@@ -554,7 +533,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
layout->rows = layout->height / (layout->tile_h + 2 * layout->tile_border_y);
- column_widths(sfile->files, layout);
+ column_widths(params, layout);
if (params->display == FILE_SHORTDISPLAY) {
maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
@@ -564,12 +543,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
else {
maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
(int)layout->column_widths[COLUMN_NAME] + column_space +
-#ifndef WIN32
- (int)layout->column_widths[COLUMN_MODE1] + column_space +
- (int)layout->column_widths[COLUMN_MODE2] + column_space +
- (int)layout->column_widths[COLUMN_MODE3] + column_space +
- (int)layout->column_widths[COLUMN_OWNER] + column_space +
-#endif
(int)layout->column_widths[COLUMN_DATE] + column_space +
(int)layout->column_widths[COLUMN_TIME] + column_space +
(int)layout->column_widths[COLUMN_SIZE] + column_space;
@@ -596,27 +569,32 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
return sfile->layout;
}
-void file_change_dir(bContext *C, int checkdir)
+void ED_file_change_dir(bContext *C, const bool checkdir)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ ScrArea *sa = CTX_wm_area(C);
if (sfile->params) {
+ ED_fileselect_clear(wm, sa, sfile);
- ED_fileselect_clear(wm, sfile);
+ /* Clear search string, it is very rare to want to keep that filter while changing dir,
+ * and usually very annoying to keep it actually! */
+ sfile->params->filter_search[0] = '\0';
+ sfile->params->active_file = -1;
if (checkdir && !BLI_is_dir(sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
filelist_setdir(sfile->files, sfile->params->dir);
-
+
if (folderlist_clear_next(sfile))
folderlist_free(sfile->folders_next);
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- file_draw_check_cb(C, NULL, NULL);
+ file_draw_check(C);
}
}
@@ -625,18 +603,19 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
int match = 0;
int i;
- struct direntry *file;
- int n = filelist_numfiles(sfile->files);
+ FileDirEntry *file;
+ int n = filelist_files_ensure(sfile->files);
/* select any file that matches the pattern, this includes exact match
* if the user selects a single file by entering the filename
*/
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
- if (fnmatch(pattern, file->relname, 0) == 0) {
- file->selflag |= SELECTED_FILE;
+ /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
+ if (fnmatch(pattern, file->relpath, 0) == 0) {
+ filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
if (!match) {
- BLI_strncpy(matched_file, file->relname, FILE_MAX);
+ BLI_strncpy(matched_file, file->relpath, FILE_MAX);
}
match++;
}
@@ -662,10 +641,10 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
dir = opendir(dirname);
if (dir) {
- AutoComplete *autocpl = autocomplete_begin(str, FILE_MAX);
+ AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX);
while ((de = readdir(dir)) != NULL) {
- if (strcmp(".", de->d_name) == 0 || strcmp("..", de->d_name) == 0) {
+ if (FILENAME_IS_CURRPAR(de->d_name)) {
/* pass */
}
else {
@@ -676,21 +655,16 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
if (BLI_stat(path, &status) == 0) {
if (S_ISDIR(status.st_mode)) { /* is subdir */
- autocomplete_do_name(autocpl, path);
+ UI_autocomplete_update_name(autocpl, path);
}
}
}
}
closedir(dir);
- match = autocomplete_end(autocpl, str);
- if (match) {
- if (match == AUTOCOMPLETE_FULL_MATCH) {
- BLI_add_slash(str);
- }
- else {
- BLI_strncpy(sfile->params->dir, str, sizeof(sfile->params->dir));
- }
+ match = UI_autocomplete_end(autocpl, str);
+ if (match == AUTOCOMPLETE_FULL_MATCH) {
+ BLI_add_slash(str);
}
}
}
@@ -705,36 +679,34 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
/* search if str matches the beginning of name */
if (str[0] && sfile->files) {
- AutoComplete *autocpl = autocomplete_begin(str, FILE_MAX);
- int nentries = filelist_numfiles(sfile->files);
+ AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX);
+ int nentries = filelist_files_ensure(sfile->files);
int i;
for (i = 0; i < nentries; ++i) {
- struct direntry *file = filelist_file(sfile->files, i);
- if (file && (S_ISREG(file->type) || S_ISDIR(file->type))) {
- autocomplete_do_name(autocpl, file->relname);
- }
+ FileDirEntry *file = filelist_file(sfile->files, i);
+ UI_autocomplete_update_name(autocpl, file->relpath);
}
- match = autocomplete_end(autocpl, str);
+ match = UI_autocomplete_end(autocpl, str);
}
return match;
}
-void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile)
+void ED_fileselect_clear(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
{
/* only NULL in rare cases - [#29734] */
if (sfile->files) {
- thumbnails_stop(wm, sfile->files);
+ filelist_readjob_stop(wm, sa);
filelist_freelib(sfile->files);
- filelist_free(sfile->files);
+ filelist_clear(sfile->files);
}
- sfile->params->active_file = -1;
+ sfile->params->highlight_file = -1;
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
-void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile)
+void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
{
if (!sfile) return;
if (sfile->op) {
@@ -746,7 +718,8 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile)
folderlist_free(sfile->folders_next);
if (sfile->files) {
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
+ filelist_free(sfile->files);
MEM_freeN(sfile->files);
sfile->files = NULL;
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index d049a45fd90..2142368f758 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -40,6 +40,12 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
+#include "BKE_appdir.h"
+
+#include "DNA_space_types.h"
+
+#include "ED_fileselect.h"
+
#ifdef WIN32
# include <windows.h> /* need to include windows.h so _WIN32_IE is defined */
# ifndef _WIN32_IE
@@ -63,15 +69,6 @@
/* FSMENU HANDLING */
-/* FSMenuEntry's without paths indicate seperators */
-typedef struct _FSMenuEntry FSMenuEntry;
-struct _FSMenuEntry {
- FSMenuEntry *next;
-
- char *path;
- short save;
-};
-
typedef struct FSMenu {
FSMenuEntry *fsmenu_system;
FSMenuEntry *fsmenu_system_bookmarks;
@@ -81,7 +78,7 @@ typedef struct FSMenu {
static FSMenu *g_fsmenu = NULL;
-FSMenu *fsmenu_get(void)
+FSMenu *ED_fsmenu_get(void)
{
if (!g_fsmenu) {
g_fsmenu = MEM_callocN(sizeof(struct FSMenu), "fsmenu");
@@ -89,7 +86,7 @@ FSMenu *fsmenu_get(void)
return g_fsmenu;
}
-static FSMenuEntry *fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
+struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
{
FSMenuEntry *fsm_head = NULL;
@@ -110,7 +107,7 @@ static FSMenuEntry *fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory ca
return fsm_head;
}
-static void fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
+void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
{
switch (category) {
case FS_CATEGORY_SYSTEM:
@@ -128,47 +125,141 @@ static void fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category,
}
}
-int fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category)
+int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category)
{
FSMenuEntry *fsm_iter;
int count = 0;
- for (fsm_iter = fsmenu_get_category(fsmenu, category); fsm_iter; fsm_iter = fsm_iter->next) {
+ for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter; fsm_iter = fsm_iter->next) {
count++;
}
return count;
}
-char *fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
+FSMenuEntry *ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index)
{
FSMenuEntry *fsm_iter;
- for (fsm_iter = fsmenu_get_category(fsmenu, category); fsm_iter && idx; fsm_iter = fsm_iter->next) {
- idx--;
+ for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && index; fsm_iter = fsm_iter->next) {
+ index--;
+ }
+
+ return fsm_iter;
+}
+
+char *ED_fsmenu_entry_get_path(struct FSMenuEntry *fsentry)
+{
+ return fsentry->path;
+}
+
+void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
+{
+ if ((!fsentry->path || !path || !STREQ(path, fsentry->path)) && (fsentry->path != path)) {
+ char tmp_name[FILE_MAXFILE];
+
+ MEM_SAFE_FREE(fsentry->path);
+
+ fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL;
+
+ BLI_make_file_string("/", tmp_name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(ED_fsmenu_get(), tmp_name);
+ }
+}
+
+static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
+{
+ char temp[FILE_MAX];
+
+ BLI_strncpy(temp, fsentry->path, FILE_MAX);
+ BLI_add_slash(temp);
+ BLI_getlastdir(temp, name, name_size);
+ BLI_del_slash(name);
+ if (!name[0]) {
+ name[0] = '/';
+ name[1] = '\0';
+ }
+}
+
+char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry)
+{
+ if (fsentry->name[0]) {
+ return fsentry->name;
}
+ else {
+ /* Here we abuse fsm_iter->name, keeping first char NULL. */
+ char *name = fsentry->name + 1;
+ size_t name_size = sizeof(fsentry->name) - 1;
- return fsm_iter ? fsm_iter->path : NULL;
+ fsmenu_entry_generate_name(fsentry, name, name_size);
+ return name;
+ }
+}
+
+void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name)
+{
+ if (!STREQ(name, fsentry->name)) {
+ char tmp_name[FILE_MAXFILE];
+ size_t tmp_name_size = sizeof(tmp_name);
+
+ fsmenu_entry_generate_name(fsentry, tmp_name, tmp_name_size);
+ if (!name[0] || STREQ(tmp_name, name)) {
+ /* reset name to default behavior. */
+ fsentry->name[0] = '\0';
+ }
+ else {
+ BLI_strncpy(fsentry->name, name, sizeof(fsentry->name));
+ }
+
+ BLI_make_file_string("/", tmp_name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(ED_fsmenu_get(), tmp_name);
+ }
+}
+
+void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry)
+{
+ if (fsentry->path && fsentry->path[0]) {
+#ifdef WIN32
+ /* XXX Special case, always consider those as valid.
+ * Thanks to Windows, which can spend five seconds to perform a mere stat() call on those paths...
+ * See T43684.
+ */
+ const char *exceptions[] = {"A:\\", "B:\\", NULL};
+ const size_t exceptions_len[] = {strlen(exceptions[0]), strlen(exceptions[1]), 0};
+ int i;
+
+ for (i = 0; exceptions[i]; i++) {
+ if (STRCASEEQLEN(fsentry->path, exceptions[i], exceptions_len[i])) {
+ fsentry->valid = true;
+ return;
+ }
+ }
+#endif
+ fsentry->valid = BLI_is_dir(fsentry->path);
+ }
+ else {
+ fsentry->valid = false;
+ }
}
short fsmenu_can_save(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
{
FSMenuEntry *fsm_iter;
- for (fsm_iter = fsmenu_get_category(fsmenu, category); fsm_iter && idx; fsm_iter = fsm_iter->next) {
+ for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && idx; fsm_iter = fsm_iter->next) {
idx--;
}
return fsm_iter ? fsm_iter->save : 0;
}
-void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, FSMenuInsert flag)
+void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, FSMenuInsert flag)
{
FSMenuEntry *fsm_prev;
FSMenuEntry *fsm_iter;
FSMenuEntry *fsm_head;
- fsm_head = fsmenu_get_category(fsmenu, category);
+ fsm_head = ED_fsmenu_get_category(fsmenu, category);
fsm_prev = fsm_head; /* this is odd and not really correct? */
for (fsm_iter = fsm_head; fsm_iter; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) {
@@ -179,7 +270,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const c
if (fsm_iter != fsm_head) {
fsm_prev->next = fsm_iter->next;
fsm_iter->next = fsm_head;
- fsmenu_set_category(fsmenu, category, fsm_iter);
+ ED_fsmenu_set_category(fsmenu, category, fsm_iter);
}
}
return;
@@ -202,10 +293,41 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const c
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. */
+ FSMenuCategory cats[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS};
+ int i = ARRAY_SIZE(cats);
+
+ 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 && tfsm->name[0]) {
+ name = tfsm->name;
+ }
+ break;
+ }
+ }
+ if (tfsm) {
+ break;
+ }
+ }
+ }
+
+ if (name && name[0]) {
+ BLI_strncpy(fsm_iter->name, name, sizeof(fsm_iter->name));
+ }
+ else {
+ fsm_iter->name[0] = '\0';
+ }
+ fsmenu_entry_refresh_valid(fsm_iter);
+
if (fsm_prev) {
if (flag & FS_INSERT_FIRST) {
fsm_iter->next = fsm_head;
- fsmenu_set_category(fsmenu, category, fsm_iter);
+ ED_fsmenu_set_category(fsmenu, category, fsm_iter);
}
else {
fsm_iter->next = fsm_prev->next;
@@ -214,7 +336,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const c
}
else {
fsm_iter->next = fsm_head;
- fsmenu_set_category(fsmenu, category, fsm_iter);
+ ED_fsmenu_set_category(fsmenu, category, fsm_iter);
}
}
@@ -224,7 +346,7 @@ void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx
FSMenuEntry *fsm_iter;
FSMenuEntry *fsm_head;
- fsm_head = fsmenu_get_category(fsmenu, category);
+ fsm_head = ED_fsmenu_get_category(fsmenu, category);
for (fsm_iter = fsm_head; fsm_iter && idx; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next)
idx--;
@@ -241,7 +363,7 @@ void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx
}
else {
fsm_head = fsm_iter->next;
- fsmenu_set_category(fsmenu, category, fsm_head);
+ ED_fsmenu_set_category(fsmenu, category, fsm_head);
}
/* free entry */
MEM_freeN(fsm_iter->path);
@@ -253,20 +375,29 @@ void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx
void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
{
FSMenuEntry *fsm_iter = NULL;
+ char fsm_name[FILE_MAX];
int nwritten = 0;
FILE *fp = BLI_fopen(filename, "w");
if (!fp) return;
-
+
fprintf(fp, "[Bookmarks]\n");
- for (fsm_iter = fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsm_iter; fsm_iter = fsm_iter->next) {
+ for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsm_iter; fsm_iter = fsm_iter->next) {
if (fsm_iter->path && fsm_iter->save) {
+ fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
+ if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
+ fprintf(fp, "!%s\n", fsm_iter->name);
+ }
fprintf(fp, "%s\n", fsm_iter->path);
}
}
fprintf(fp, "[Recent]\n");
- for (fsm_iter = fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT); fsm_iter && (nwritten < FSMENU_RECENT_MAX); fsm_iter = fsm_iter->next, ++nwritten) {
+ for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT); fsm_iter && (nwritten < FSMENU_RECENT_MAX); fsm_iter = fsm_iter->next, ++nwritten) {
if (fsm_iter->path && fsm_iter->save) {
+ fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
+ if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
+ fprintf(fp, "!%s\n", fsm_iter->name);
+ }
fprintf(fp, "%s\n", fsm_iter->path);
}
}
@@ -276,19 +407,31 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
{
char line[FILE_MAXDIR];
+ char name[FILE_MAXFILE];
FSMenuCategory category = FS_CATEGORY_BOOKMARKS;
FILE *fp;
fp = BLI_fopen(filename, "r");
if (!fp) return;
+ name[0] = '\0';
+
while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */
- if (strncmp(line, "[Bookmarks]", 11) == 0) {
+ if (STREQLEN(line, "[Bookmarks]", 11)) {
category = FS_CATEGORY_BOOKMARKS;
}
- else if (strncmp(line, "[Recent]", 8) == 0) {
+ else if (STREQLEN(line, "[Recent]", 8)) {
category = FS_CATEGORY_RECENT;
}
+ else if (line[0] == '!') {
+ int len = strlen(line);
+ if (len > 0) {
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+ BLI_strncpy(name, line + 1, sizeof(name));
+ }
+ }
else {
int len = strlen(line);
if (len > 0) {
@@ -302,9 +445,11 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
if (BLI_exists(line))
#endif
{
- fsmenu_insert_entry(fsmenu, category, line, FS_INSERT_SAVE);
+ fsmenu_insert_entry(fsmenu, category, line, name, FS_INSERT_SAVE);
}
}
+ /* always reset name. */
+ name[0] = '\0';
}
}
fclose(fp);
@@ -316,29 +461,49 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
#ifdef WIN32
/* Add the drive names to the listing */
{
+ wchar_t wline[FILE_MAXDIR];
__int64 tmp;
- char tmps[4];
+ char tmps[4], *name;
int i;
-
+
tmp = GetLogicalDrives();
-
+
for (i = 0; i < 26; i++) {
if ((tmp >> i) & 1) {
tmps[0] = 'A' + i;
tmps[1] = ':';
tmps[2] = '\\';
- tmps[3] = 0;
-
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, FS_INSERT_SORTED);
+ tmps[3] = '\0';
+ name = NULL;
+
+ /* Flee from horrible win querying hover floppy drives! */
+ if (i > 1) {
+ /* Try to get volume label as well... */
+ BLI_strncpy_wchar_from_utf8(wline, tmps, 4);
+ if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) {
+ size_t label_len;
+
+ BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4);
+
+ label_len = MIN2(strlen(line), FILE_MAXDIR - 6);
+ BLI_snprintf(line + label_len, 6, " (%.2s)", tmps);
+
+ name = line;
+ }
+ }
+
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED);
}
}
/* Adding Desktop and My Documents */
if (read_bookmarks) {
- SHGetSpecialFolderPath(0, line, CSIDL_PERSONAL, 0);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
- SHGetSpecialFolderPath(0, line, CSIDL_DESKTOPDIRECTORY, 0);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ 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, 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, FS_INSERT_SORTED);
}
}
#else
@@ -359,38 +524,38 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
FSRefMakePath(&dir, path, FILE_MAX);
- if (strcmp((char *)path, "/home") && strcmp((char *)path, "/net")) {
+ if (!STREQ((char *)path, "/home") && !STREQ((char *)path, "/net")) {
/* /net and /home are meaningless on OSX, home folders are stored in /Users */
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, NULL, FS_INSERT_SORTED);
}
}
/* As 10.4 doesn't provide proper API to retrieve the favorite places,
* assume they are the standard ones
- * TODO : replace hardcoded paths with proper BLI_get_folder calls */
+ * TODO : replace hardcoded paths with proper BKE_appdir_folder_id calls */
home = getenv("HOME");
if (read_bookmarks && home) {
BLI_snprintf(line, sizeof(line), "%s/", home);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
}
BLI_snprintf(line, sizeof(line), "%s/Documents/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
}
BLI_snprintf(line, sizeof(line), "%s/Pictures/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
}
BLI_snprintf(line, sizeof(line), "%s/Music/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
}
BLI_snprintf(line, sizeof(line), "%s/Movies/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
}
}
#else /* OSX 10.6+ */
@@ -410,7 +575,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)defPath, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)defPath, NULL, FS_INSERT_SORTED);
}
CFRelease(volEnum);
@@ -441,9 +606,14 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
- if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
+ if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
continue;
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+
+ /* Exclude "all my files" as it makes no sense in blender fileselector */
+ /* Exclude "airdrop" if wlan not active as it would show "" ) */
+ if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_LAST);
+ }
CFRelease(pathString);
CFRelease(cfURL);
@@ -461,10 +631,10 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
if (read_bookmarks && home) {
BLI_snprintf(line, sizeof(line), "%s/", home);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
}
}
@@ -483,16 +653,16 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
else {
while ((mnt = getmntent(fp))) {
/* not sure if this is right, but seems to give the relevant mnts */
- if (strncmp(mnt->mnt_fsname, "/dev", 4))
+ if (!STREQLEN(mnt->mnt_fsname, "/dev", 4))
continue;
len = strlen(mnt->mnt_dir);
if (len && mnt->mnt_dir[len - 1] != '/') {
BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, NULL, FS_INSERT_SORTED);
}
else {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, FS_INSERT_SORTED);
}
found = 1;
@@ -505,7 +675,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* fallback */
if (!found)
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", FS_INSERT_SORTED);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, FS_INSERT_SORTED);
}
}
#endif
@@ -515,7 +685,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
static void fsmenu_free_category(struct FSMenu *fsmenu, FSMenuCategory category)
{
- FSMenuEntry *fsm_iter = fsmenu_get_category(fsmenu, category);
+ FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category);
while (fsm_iter) {
FSMenuEntry *fsm_next = fsm_iter->next;
@@ -532,15 +702,28 @@ static void fsmenu_free_category(struct FSMenu *fsmenu, FSMenuCategory category)
void fsmenu_refresh_system_category(struct FSMenu *fsmenu)
{
fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM);
- fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM, NULL);
+ ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM, NULL);
fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS);
- fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, NULL);
+ ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, NULL);
/* Add all entries to system category */
fsmenu_read_system(fsmenu, true);
}
+void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu)
+{
+ int categories[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT};
+ int i;
+
+ for (i = sizeof(categories) / sizeof(*categories); i--; ) {
+ FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]);
+ for ( ; fsm_iter; fsm_iter = fsm_iter->next) {
+ fsmenu_entry_refresh_valid(fsm_iter);
+ }
+ }
+}
+
void fsmenu_free(void)
{
if (g_fsmenu) {
@@ -554,3 +737,16 @@ void fsmenu_free(void)
g_fsmenu = NULL;
}
+int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir)
+{
+ FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category);
+ int i;
+
+ for (i = 0; fsm_iter; fsm_iter = fsm_iter->next, i++) {
+ if (BLI_path_cmp(dir, fsm_iter->path) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 01bd4e95afa..81014874fb5 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -37,42 +37,26 @@
/* XXX could become UserPref */
#define FSMENU_RECENT_MAX 10
-typedef enum FSMenuCategory {
- FS_CATEGORY_SYSTEM,
- FS_CATEGORY_SYSTEM_BOOKMARKS,
- FS_CATEGORY_BOOKMARKS,
- FS_CATEGORY_RECENT
-} FSMenuCategory;
-
-typedef enum FSMenuInsert {
- FS_INSERT_SORTED = (1 << 0),
- FS_INSERT_SAVE = (1 << 1),
- FS_INSERT_FIRST = (1 << 2) /* moves the item to the front of the list when its not already there */
-} FSMenuInsert;
+enum FSMenuCategory;
+enum FSMenuInsert;
struct FSMenu;
-
-struct FSMenu *fsmenu_get(void);
-
-/** Returns the number of entries in the Fileselect Menu */
-int fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category);
-
-/** Returns the fsmenu entry at \a index (or NULL if a bad index)
- * or a separator.
- */
-char *fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index);
+struct FSMenuEntry;
/** Inserts a new fsmenu entry with the given \a path.
* Duplicate entries are not added.
* \param flag Options for inserting the entry.
*/
-void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const FSMenuInsert flag);
+void fsmenu_insert_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *path, const char *name, const enum FSMenuInsert flag);
+
+/** Refresh 'valid' status of given menu entry */
+void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry);
/** Return whether the entry was created by the user and can be saved and deleted */
-short fsmenu_can_save(struct FSMenu *fsmenu, FSMenuCategory category, int index);
+short fsmenu_can_save(struct FSMenu *fsmenu, enum FSMenuCategory category, int index);
/** Removes the fsmenu entry at the given \a index. */
-void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index);
+void fsmenu_remove_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, int index);
/** saves the 'bookmarks' to the specified file */
void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename);
@@ -89,5 +73,11 @@ void fsmenu_free(void);
/** Refresh system directory menu */
void fsmenu_refresh_system_category(struct FSMenu *fsmenu);
+/** Refresh 'valid' status of all menu entries */
+void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu);
+
+/** Get active index based on given directory. */
+int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir);
+
#endif
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index d5be04cff20..97c2d75e469 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -39,8 +39,8 @@
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
-#include "BLO_readfile.h"
+#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
@@ -71,7 +71,7 @@ static SpaceLink *file_new(const bContext *UNUSED(C))
{
ARegion *ar;
SpaceFile *sfile;
-
+
sfile = MEM_callocN(sizeof(SpaceFile), "initfile");
sfile->spacetype = SPACE_FILE;
@@ -81,12 +81,18 @@ static SpaceLink *file_new(const bContext *UNUSED(C))
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_TOP;
- /* channel list region */
- ar = MEM_callocN(sizeof(ARegion), "channel area for file");
+ /* Tools region */
+ ar = MEM_callocN(sizeof(ARegion), "tools area for file");
BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_CHANNELS;
+ ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
+ /* Tool props (aka operator) region */
+ ar = MEM_callocN(sizeof(ARegion), "tool props area for file");
+ BLI_addtail(&sfile->regionbase, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
+
/* ui list region */
ar = MEM_callocN(sizeof(ARegion), "ui area for file");
BLI_addtail(&sfile->regionbase, ar);
@@ -111,6 +117,8 @@ static void file_free(SpaceLink *sl)
{
SpaceFile *sfile = (SpaceFile *) sl;
+ BLI_assert(sfile->previews_timer == NULL);
+
if (sfile->files) {
// XXXXX would need to do thumbnails_stop here, but no context available
filelist_freelib(sfile->files);
@@ -149,7 +157,13 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
/* refresh system directory list */
- fsmenu_refresh_system_category(fsmenu_get());
+ fsmenu_refresh_system_category(ED_fsmenu_get());
+
+ /* Update bookmarks 'valid' state.
+ * Done here, because it seems BLI_is_dir() can have huge impact on performances
+ * in some cases, on win systems... See T43684.
+ */
+ fsmenu_refresh_bookmarks_status(ED_fsmenu_get());
if (sfile->layout) sfile->layout->dirty = true;
}
@@ -158,7 +172,12 @@ static void file_exit(wmWindowManager *wm, ScrArea *sa)
{
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
- ED_fileselect_exit(wm, sfile);
+ if (sfile->previews_timer) {
+ WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer);
+ sfile->previews_timer = NULL;
+ }
+
+ ED_fileselect_exit(wm, sa, sfile);
}
static SpaceLink *file_duplicate(SpaceLink *sl)
@@ -187,75 +206,94 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
return (SpaceLink *)sfilen;
}
-static void file_refresh(const bContext *C, ScrArea *UNUSED(sa))
+static void file_refresh(const bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
- if (!sfile->folders_prev)
+ if (!sfile->folders_prev) {
sfile->folders_prev = folderlist_new();
+ }
if (!sfile->files) {
sfile->files = filelist_new(params->type);
- filelist_setdir(sfile->files, params->dir);
- params->active_file = -1; // added this so it opens nicer (ton)
+ params->highlight_file = -1; /* added this so it opens nicer (ton) */
+ }
+ filelist_setdir(sfile->files, params->dir);
+ filelist_setrecursion(sfile->files, params->recursion_level);
+ filelist_setsorting(sfile->files, params->sort);
+ filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0,
+ false, /* TODO hide_parent, should be controllable? */
+ params->flag & FILE_FILTER ? params->filter : 0,
+ params->filter_id,
+ params->filter_glob,
+ params->filter_search);
+
+ /* Update the active indices of bookmarks & co. */
+ sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
+ sfile->system_bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, params->dir);
+ sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir);
+ sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir);
+
+ if (filelist_force_reset(sfile->files)) {
+ filelist_readjob_stop(wm, sa);
+ filelist_clear(sfile->files);
}
- filelist_hidedot(sfile->files, params->flag & FILE_HIDE_DOT);
- filelist_setfilter(sfile->files, params->flag & FILE_FILTER ? params->filter : 0);
- filelist_setfilter_types(sfile->files, params->filter_glob);
if (filelist_empty(sfile->files)) {
- thumbnails_stop(wm, sfile->files);
- filelist_readdir(sfile->files);
- if (params->sort != FILE_SORT_NONE) {
- filelist_sort(sfile->files, params->sort);
- }
- BLI_strncpy(params->dir, filelist_dir(sfile->files), FILE_MAX);
- if (params->display == FILE_IMGDISPLAY) {
- thumbnails_start(sfile->files, C);
+ if (!filelist_pending(sfile->files)) {
+ filelist_readjob_start(sfile->files, C);
}
}
+
+ filelist_sort(sfile->files);
+ filelist_filter(sfile->files);
+
+ if (params->display == FILE_IMGDISPLAY) {
+ filelist_cache_previews_set(sfile->files, true);
+ }
else {
- if (params->sort != FILE_SORT_NONE) {
- thumbnails_stop(wm, sfile->files);
- filelist_sort(sfile->files, params->sort);
- if (params->display == FILE_IMGDISPLAY) {
- thumbnails_start(sfile->files, C);
- }
- }
- else {
- if (params->display == FILE_IMGDISPLAY) {
- if (!thumbnails_running(wm, sfile->files)) {
- thumbnails_start(sfile->files, C);
- }
- }
- else {
- /* stop any running thumbnail jobs if we're not
- * displaying them - speedup for NFS */
- thumbnails_stop(wm, sfile->files);
- }
- filelist_filter(sfile->files);
+ filelist_cache_previews_set(sfile->files, false);
+ if (sfile->previews_timer) {
+ WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer);
+ sfile->previews_timer = NULL;
}
}
-
+
if (params->renamefile[0] != '\0') {
- int idx = filelist_find(sfile->files, params->renamefile);
+ int idx = filelist_file_findpath(sfile->files, params->renamefile);
if (idx >= 0) {
- struct direntry *file = filelist_file(sfile->files, idx);
+ FileDirEntry *file = filelist_file(sfile->files, idx);
if (file) {
- file->selflag |= EDITING_FILE;
+ filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
}
}
BLI_strncpy(sfile->params->renameedit, sfile->params->renamefile, sizeof(sfile->params->renameedit));
- params->renamefile[0] = '\0';
+ /* File listing is now async, do not clear renamefile if matching entry not found
+ * and dirlist is not finished! */
+ if (idx >= 0 || filelist_is_ready(sfile->files)) {
+ params->renamefile[0] = '\0';
+ }
+ }
+
+ if (sfile->layout) {
+ sfile->layout->dirty = true;
}
- if (sfile->layout) sfile->layout->dirty = true;
+ /* Might be called with NULL sa, see file_main_area_draw() below. */
+ if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
+ /* Create TOOLS/TOOL_PROPS regions. */
+ file_tools_region(sa);
+
+ ED_area_initialize(wm, CTX_wm_window(C), sa);
+ ED_area_tag_redraw(sa);
+ }
}
static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
{
- /* SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; */
+ SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -269,6 +307,12 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
break;
+ case ND_SPACE_FILE_PREVIEW:
+ if (sfile->files && filelist_cache_previews_update(sfile->files)) {
+ ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(sa);
+ }
+ break;
}
break;
}
@@ -354,7 +398,7 @@ static void file_main_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_ortho(v2d);
/* on first read, find active file */
- if (params->active_file == -1) {
+ if (params->highlight_file == -1) {
wmEvent *event = CTX_wm_window(C)->eventstate;
file_highlight_set(sfile, ar, event->x, event->y);
}
@@ -374,6 +418,7 @@ static void file_main_area_draw(const bContext *C, ARegion *ar)
static void file_operatortypes(void)
{
WM_operatortype_append(FILE_OT_select);
+ WM_operatortype_append(FILE_OT_select_walk);
WM_operatortype_append(FILE_OT_select_all_toggle);
WM_operatortype_append(FILE_OT_select_border);
WM_operatortype_append(FILE_OT_select_bookmark);
@@ -387,6 +432,8 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_bookmark_toggle);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
+ WM_operatortype_append(FILE_OT_bookmark_cleanup);
+ WM_operatortype_append(FILE_OT_bookmark_move);
WM_operatortype_append(FILE_OT_reset_recent);
WM_operatortype_append(FILE_OT_hidedot);
WM_operatortype_append(FILE_OT_filenum);
@@ -437,6 +484,49 @@ static void file_keymap(struct wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "fill", true);
RNA_boolean_set(kmi->ptr, "open", false);
+
+ /* arrow keys navigation (walk selecting) */
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+
/* front and back mouse folder navigation */
WM_keymap_add_item(keymap, "FILE_OT_previous", BUTTON4MOUSE, KM_CLICK, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0);
@@ -478,7 +568,7 @@ static void file_keymap(struct wmKeyConfig *keyconf)
}
-static void file_channel_area_init(wmWindowManager *wm, ARegion *ar)
+static void file_tools_area_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -490,12 +580,12 @@ static void file_channel_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void file_channel_area_draw(const bContext *C, ARegion *ar)
+static void file_tools_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
-static void file_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void file_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
#if 0
/* context changes */
@@ -621,12 +711,24 @@ void ED_spacetype_file(void)
/* regions: channels (directories) */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
- art->regionid = RGN_TYPE_CHANNELS;
+ art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 240;
+ art->prefsizey = 60;
+ art->keymapflag = ED_KEYMAP_UI;
+ art->listener = file_tools_area_listener;
+ art->init = file_tools_area_init;
+ art->draw = file_tools_area_draw;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: tool properties */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
+ art->regionid = RGN_TYPE_TOOL_PROPS;
+ art->prefsizex = 0;
+ art->prefsizey = 360;
art->keymapflag = ED_KEYMAP_UI;
- art->listener = file_channel_area_listener;
- art->init = file_channel_area_init;
- art->draw = file_channel_area_draw;
+ art->listener = file_tools_area_listener;
+ art->init = file_tools_area_init;
+ art->draw = file_tools_area_draw;
BLI_addhead(&st->regiontypes, art);
file_panels_register(art);
@@ -656,16 +758,16 @@ void ED_file_exit(void)
void ED_file_read_bookmarks(void)
{
- const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL);
+ const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
fsmenu_free();
- fsmenu_read_system(fsmenu_get(), true);
+ fsmenu_read_system(ED_fsmenu_get(), true);
if (cfgdir) {
char name[FILE_MAX];
BLI_make_file_string("/", name, cfgdir, BLENDER_BOOKMARK_FILE);
- fsmenu_read_bookmarks(fsmenu_get(), name);
+ fsmenu_read_bookmarks(ED_fsmenu_get(), name);
}
}
diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt
index d3fb87204fb..40a196fa95b 100644
--- a/source/blender/editors/space_graph/CMakeLists.txt
+++ b/source/blender/editors/space_graph/CMakeLists.txt
@@ -20,13 +20,15 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -46,14 +48,17 @@ set(SRC
)
if(WITH_AUDASPACE)
- list(APPEND INC
- ../../../../intern/audaspace/intern
+ add_definitions(${AUDASPACE_DEFINITIONS})
+
+ list(APPEND INC_SYS
+ ${AUDASPACE_C_INCLUDE_DIRS}
)
- add_definitions(-DWITH_AUDASPACE)
endif()
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_graph "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_graph/SConscript b/source/blender/editors/space_graph/SConscript
index 8ddeb0ccfe8..af17853556e 100644
--- a/source/blender/editors/space_graph/SConscript
+++ b/source/blender/editors/space_graph/SConscript
@@ -31,12 +31,13 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
- '#/intern/audaspace/intern',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -44,6 +45,11 @@ incs = [
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
+
+if env['WITH_BF_AUDASPACE']:
+ defs += env['BF_AUDASPACE_DEF']
+ incs.append(env['BF_AUDASPACE_C_INC'])
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index b59030d3c12..8e471ceca95 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -44,7 +44,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -159,15 +159,34 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
// UNUSED
// block = uiLayoutGetBlock(layout);
- // uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
+ // UI_block_func_handle_set(block, do_graph_region_buttons, NULL);
/* F-Curve pointer */
RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
/* user-friendly 'name' for F-Curve */
- /* TODO: only show the path if this is invalid? */
col = uiLayoutColumn(layout, false);
- icon = getname_anim_fcurve(name, ale->id, fcu);
+ if (ale->type == ANIMTYPE_FCURVE) {
+ /* get user-friendly name for F-Curve */
+ icon = getname_anim_fcurve(name, ale->id, fcu);
+ }
+ else {
+ /* NLA Control Curve, etc. */
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+
+ /* get name */
+ if (acf && acf->name) {
+ acf->name(ale, name);
+ }
+ else {
+ strcpy(name, IFACE_("<invalid>"));
+ icon = ICON_ERROR;
+ }
+
+ /* icon */
+ if (ale->type == ANIMTYPE_NLACURVE)
+ icon = ICON_NLA;
+ }
uiItemL(col, name, icon);
/* RNA-Path Editing - only really should be enabled when things aren't working */
@@ -210,7 +229,7 @@ static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezT
* wants to edit numerically, there is likely to only be 1 vert selected
*/
for (i = 0, b = fcu->bezt; i < fcu->totvert; i++, b++) {
- if (BEZSELECTED(b)) {
+ if (BEZT_ISSEL_ANY(b)) {
/* found
* - 'previous' is either the one before, of the keyframe itself (which is still fine)
* XXX: we can just make this null instead if needed
@@ -315,7 +334,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
return;
block = uiLayoutGetBlock(layout);
- /* uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL); */
+ /* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */
/* only show this info if there are keyframes to edit */
if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
@@ -366,33 +385,33 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
{
uiItemL(col, IFACE_("Key:"), ICON_NONE);
- but = uiDefButR(block, NUM, B_REDR, IFACE_("Frame:"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, IFACE_("Frame:"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "co", 0, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt);
+ UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
- but = uiDefButR(block, NUM, B_REDR, IFACE_("Value:"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, IFACE_("Value:"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "co", 1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt);
- uiButSetUnitType(but, unit);
+ 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);
- but = uiDefButR(block, NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_left", 0, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
+ UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
- but = uiDefButR(block, NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_left", 1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
- uiButSetUnitType(but, unit);
+ UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
+ UI_but_unit_type_set(but, unit);
/* XXX: with label? */
- but = uiDefButR(block, MENU, B_REDR, NULL, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, NULL, 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_left_type", 0, 0, 0, -1, -1, "Type of left handle");
- uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+ UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
}
/* next handle - only if current is Bezier interpolation */
@@ -400,19 +419,19 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
/* NOTE: special update callbacks are needed on the coords here due to T39911 */
uiItemL(col, IFACE_("Right Handle:"), ICON_NONE);
- but = uiDefButR(block, NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_right", 0, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
+ UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
- but = uiDefButR(block, NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_right", 1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
- uiButSetUnitType(but, unit);
+ UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
+ UI_but_unit_type_set(but, unit);
/* XXX: with label? */
- but = uiDefButR(block, MENU, B_REDR, NULL, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, NULL, 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_right_type", 0, 0, 0, -1, -1, "Type of right handle");
- uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+ UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
}
}
else {
@@ -671,22 +690,22 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
/* set event handler for panel */
block = uiLayoutGetBlock(pa->layout); // xxx?
- uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL);
+ UI_block_func_handle_set(block, do_graph_region_driver_buttons, NULL);
/* general actions - management */
col = uiLayoutColumn(pa->layout, false);
block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block, BUT, B_IPO_DEPCHANGE, ICON_FILE_REFRESH, IFACE_("Update Dependencies"),
- 0, 0, 10 * UI_UNIT_X, 22,
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_FILE_REFRESH, IFACE_("Update Dependencies"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0, 0,
TIP_("Force updates of dependencies"));
- uiButSetFunc(but, driver_update_flags_cb, fcu, NULL);
+ UI_but_func_set(but, driver_update_flags_cb, fcu, NULL);
- but = uiDefIconTextBut(block, BUT, B_IPO_DEPCHANGE, ICON_ZOOMOUT, IFACE_("Remove Driver"),
- 0, 0, 10 * UI_UNIT_X, 18,
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMOUT, IFACE_("Remove Driver"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0, 0,
TIP_("Remove this driver"));
- uiButSetNFunc(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
+ UI_but_funcN_set(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
/* driver-level settings - type, expressions, and errors */
RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr);
@@ -763,11 +782,11 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
/* add driver variables */
col = uiLayoutColumn(pa->layout, false);
block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block, BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0, 0,
TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
- uiButSetFunc(but, driver_add_var_cb, driver, NULL);
+ UI_but_func_set(but, driver_add_var_cb, driver, NULL);
/* loop over targets, drawing them */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
@@ -788,11 +807,11 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
/* remove button */
- uiBlockSetEmboss(block, UI_EMBOSSN);
- but = uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ but = uiDefIconBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
- uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_but_func_set(but, driver_delete_var_cb, driver, dvar);
+ UI_block_emboss_set(block, UI_EMBOSS);
/* variable type */
row = uiLayoutRow(box, false);
@@ -864,12 +883,13 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
FModifier *fcm;
uiLayout *col, *row;
uiBlock *block;
+ bool active;
if (!graph_panel_context(C, &ale, &fcu))
return;
block = uiLayoutGetBlock(pa->layout);
- uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL);
+ UI_block_func_handle_set(block, do_graph_region_modifier_buttons, NULL);
/* 'add modifier' button at top of panel */
{
@@ -879,7 +899,7 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
/* this is an operator button which calls a 'add modifier' operator...
* a menu might be nicer but would be tricky as we need some custom filtering
*/
- uiDefButO(block, BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"),
+ uiDefButO(block, UI_BTYPE_BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"),
0.5 * UI_UNIT_X, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, TIP_("Adds a new F-Curve Modifier for the active F-Curve"));
/* copy/paste (as sub-row)*/
@@ -888,9 +908,11 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
}
+ active = !(fcu->flag & FCURVE_MOD_OFF);
/* draw each modifier */
for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
col = uiLayoutColumn(pa->layout, true);
+ uiLayoutSetActive(col, active);
ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
}
@@ -907,7 +929,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
strcpy(pt->idname, "GRAPH_PT_view");
strcpy(pt->label, N_("View Properties"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_view;
pt->flag |= PNL_DEFAULT_CLOSED;
BLI_addtail(&art->paneltypes, pt);
@@ -915,7 +937,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_properties");
strcpy(pt->label, N_("Active F-Curve"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_properties;
pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -923,7 +945,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_key_properties");
strcpy(pt->label, N_("Active Keyframe"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_key_properties;
pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -932,7 +954,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
strcpy(pt->idname, "GRAPH_PT_drivers");
strcpy(pt->label, N_("Drivers"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_drivers;
pt->poll = graph_panel_drivers_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -940,7 +962,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
strcpy(pt->idname, "GRAPH_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_modifiers;
pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt);
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index ed7cfe7da99..91e11ac4b1e 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -33,6 +33,7 @@
#include <float.h>
#include "BLI_blenlib.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -42,6 +43,7 @@
#include "DNA_userdef_types.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_fcurve.h"
@@ -227,7 +229,7 @@ static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2
* Also, need to take into account whether the keyframe was selected
* if a Graph Editor option to only show handles of selected keys is on.
*/
- if (!sel_handle_only || BEZSELECTED(bezt)) {
+ if (!sel_handle_only || BEZT_ISSEL_ANY(bezt)) {
if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
if ((bezt->f1 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/
draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize);
@@ -343,7 +345,7 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
* check that keyframe is selected
*/
if (sipo->flag & SIPO_SELVHANDLESONLY) {
- if (BEZSELECTED(bezt) == 0)
+ if (BEZT_ISSEL_ANY(bezt) == 0)
continue;
}
@@ -475,10 +477,11 @@ static void draw_fcurve_samples(SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
/* helper func - just draw the F-Curve by sampling the visible region (for drawing curves with modifiers) */
static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, View2DGrid *grid)
{
+ SpaceIpo *sipo = (SpaceIpo *)ac->sl;
ChannelDriver *driver;
float samplefreq;
float stime, etime;
- float unitFac;
+ float unitFac, offset;
float dx, dy;
short mapping_flag = ANIM_get_normalization_flags(ac);
int i, n;
@@ -495,14 +498,14 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
fcu->driver = NULL;
/* compute unit correction factor */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
/* Note about sampling frequency:
* Ideally, this is chosen such that we have 1-2 pixels = 1 segment
* which means that our curves can be as smooth as possible. However,
* this does mean that curves may not be fully accurate (i.e. if they have
* sudden spikes which happen at the sampling point, we may have problems).
- * Also, this may introduce lower performance on less densely detailed curves,'
+ * Also, this may introduce lower performance on less densely detailed curves,
* though it is impossible to predict this from the modifiers!
*
* If the automatically determined sampling frequency is likely to cause an infinite
@@ -512,7 +515,25 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
/* grid->dx represents the number of 'frames' between gridlines, but we divide by U.v2d_min_gridsize to get pixels-steps */
/* TODO: perhaps we should have 1.0 frames as upper limit so that curves don't get too distorted? */
samplefreq = dx / (U.v2d_min_gridsize * U.pixelsize);
- if (samplefreq < 0.00001f) samplefreq = 0.00001f;
+
+ if (sipo->flag & SIPO_BEAUTYDRAW_OFF) {
+ /* Low Precision = coarse lower-bound clamping
+ *
+ * Although the "Beauty Draw" flag was originally for AA'd
+ * line drawing, the sampling rate here has a much greater
+ * impact on performance (e.g. for T40372)!
+ *
+ * This one still amounts to 10 sample-frames for each 1-frame interval
+ * which should be quite a decent approximation in many situations.
+ */
+ if (samplefreq < 0.1f)
+ samplefreq = 0.1f;
+ }
+ else {
+ /* "Higher Precision" but slower - especially on larger windows (e.g. T40372) */
+ if (samplefreq < 0.00001f)
+ samplefreq = 0.00001f;
+ }
/* the start/end times are simply the horizontal extents of the 'cur' rect */
@@ -525,12 +546,13 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
* the displayed values appear correctly in the viewport
*/
glBegin(GL_LINE_STRIP);
-
- for (i = 0, n = (etime - stime) / samplefreq + 0.5f; i < n; ++i) {
+
+ n = (etime - stime) / samplefreq + 0.5f;
+ for (i = 0; i <= n; i++) {
float ctime = stime + i * samplefreq;
- glVertex2f(ctime, evaluate_fcurve(fcu, ctime) * unitFac);
+ glVertex2f(ctime, (evaluate_fcurve(fcu, ctime) + offset) * unitFac);
}
-
+
glEnd();
/* restore driver */
@@ -544,13 +566,14 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
FPoint *fpt = prevfpt + 1;
float fac, v[2];
int b = fcu->totvert - 1;
- float unit_scale;
+ float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply unit mapping */
glPushMatrix();
- unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
glBegin(GL_LINE_STRIP);
@@ -616,8 +639,24 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
glPopMatrix();
}
-#if 0
-/* helper func - draw one repeat of an F-Curve */
+/* helper func - check if the F-Curve only contains easily drawable segments
+ * (i.e. no easing equation interpolations)
+ */
+static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu)
+{
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (ELEM(bezt->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN, BEZT_IPO_BEZ) == false) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */
static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d)
{
BezTriple *prevbezt = fcu->bezt;
@@ -627,13 +666,14 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
float fac = 0.0f;
int b = fcu->totvert - 1;
int resol;
- float unit_scale;
+ float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
-
+
/* apply unit mapping */
glPushMatrix();
- unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
glBegin(GL_LINE_STRIP);
@@ -689,17 +729,19 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
v1[1] = prevbezt->vec[1][1];
glVertex2fv(v1);
}
- else {
+ else if (prevbezt->ipo == BEZT_IPO_BEZ) {
/* Bezier-Interpolation: draw curve as series of segments between keyframes
* - resol determines number of points to sample in between keyframes
*/
/* resol depends on distance between points (not just horizontal) OR is a fixed high res */
/* TODO: view scale should factor into this someday too... */
- if (fcu->driver)
+ if (fcu->driver) {
resol = 32;
- else
+ }
+ else {
resol = (int)(5.0f * len_v2v2(bezt->vec[1], prevbezt->vec[1]));
+ }
if (resol < 2) {
/* only draw one */
@@ -773,7 +815,6 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
glEnd();
glPopMatrix();
}
-#endif
/* Debugging -------------------------------- */
@@ -787,7 +828,8 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
ChannelDriver *driver = fcu->driver;
View2D *v2d = &ac->ar->v2d;
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ float offset;
+ float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
/* for now, only show when debugging driver... */
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
@@ -809,11 +851,13 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
* NOTE: we need to scale the y-values to be valid for the units
*/
glBegin(GL_LINES);
+ {
t = v2d->cur.xmin;
- glVertex2f(t, t * unitfac);
+ glVertex2f(t, (t + offset) * unitfac);
t = v2d->cur.xmax;
- glVertex2f(t, t * unitfac);
+ glVertex2f(t, (t + offset) * unitfac);
+ }
glEnd();
/* cleanup line drawing */
@@ -836,6 +880,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
setlinestyle(5);
glBegin(GL_LINES);
+ {
/* x-axis lookup */
co[0] = x;
@@ -855,6 +900,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
co[0] = x;
glVertex2fv(co);
+ }
glEnd();
setlinestyle(0);
@@ -865,7 +911,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glPointSize(7.0);
glBegin(GL_POINTS);
- glVertex2f(x, y);
+ glVertex2f(x, y);
glEnd();
/* inner frame */
@@ -873,7 +919,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glPointSize(3.0);
glBegin(GL_POINTS);
- glVertex2f(x, y);
+ glVertex2f(x, y);
glEnd();
glPointSize(1.0f);
@@ -989,11 +1035,15 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
/* just draw curve based on defined data (i.e. no modifiers) */
- if (fcu->bezt)
- //draw_fcurve_curve_bezts(ac, ale->id, fcu, &ar->v2d);
- draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid); // XXX: better to do an optimised integration here instead, but for now, this works
- else if (fcu->fpt)
+ if (fcu->bezt) {
+ if (fcurve_can_use_simple_bezt_drawing(fcu))
+ draw_fcurve_curve_bezts(ac, ale->id, fcu, &ar->v2d);
+ else
+ draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid);
+ }
+ else if (fcu->fpt) {
draw_fcurve_curve_samples(ac, ale->id, fcu, &ar->v2d);
+ }
}
/* restore settings */
@@ -1020,10 +1070,12 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
glPushMatrix();
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
if (fcu->bezt) {
bool do_handles = draw_fcurve_handles_check(sipo, fcu);
@@ -1090,6 +1142,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
@@ -1101,15 +1155,16 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
+ channel_index++;
}
}
{ /* second pass: widgets */
- uiBlock *block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
y = (float)ACHANNEL_FIRST;
@@ -1135,8 +1190,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
channel_index++;
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
glDisable(GL_BLEND);
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index c8298927f7d..ca5d2db80e7 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -36,7 +36,7 @@
#include <float.h>
#ifdef WITH_AUDASPACE
-# include "AUD_C-API.h"
+# include AUD_SPECIAL_H
#endif
#include "MEM_guardedalloc.h"
@@ -52,7 +52,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -60,8 +60,6 @@
#include "BKE_context.h"
#include "BKE_report.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
#include "UI_view2d.h"
#include "ED_anim_api.h"
@@ -111,7 +109,7 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float txmin, txmax, tymin, tymax;
- float unitFac;
+ float unitFac, offset;
/* get range */
if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
@@ -124,7 +122,9 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
}
/* apply unit corrections */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
+ tymin += offset;
+ tymax += offset;
tymin *= unitFac;
tymax *= unitFac;
@@ -258,6 +258,14 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
}
+static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
+
void GRAPH_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
@@ -296,6 +304,21 @@ void GRAPH_OT_view_selected(wmOperatorType *ot)
"Include handles of keyframes when calculating extents");
}
+void GRAPH_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "GRAPH_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = graphkeys_view_frame_exec;
+ ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ******************** Create Ghost-Curves Operator *********************** */
/* This operator samples the data of the selected F-Curves to F-Points, storing them
* as 'ghost curves' in the active Graph Editor
@@ -329,7 +352,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
ChannelDriver *driver = fcu->driver;
FPoint *fpt;
- float unitFac;
+ float unitFac, offset;
int cfra;
SpaceIpo *sipo = (SpaceIpo *) ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
@@ -338,7 +361,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
fcu->driver = NULL;
/* calculate unit-mapping factor */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* create samples, but store them in a new curve
* - we cannot use fcurve_store_samples() as that will only overwrite the original curve
@@ -351,7 +374,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
fpt->vec[0] = cfrae;
- fpt->vec[1] = fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) * unitFac;
+ fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac;
}
/* set color of ghost curve
@@ -500,12 +523,17 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
else
cfra = (float)CFRA;
- /* if there's an id */
- if (ale->id)
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner)
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
-
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -584,7 +612,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
ListBase anim_data;
short mapping_flag = ANIM_get_normalization_flags(&ac);
-
+ float scale, offset;
/* get frame and value from props */
frame = RNA_float_get(op->ptr, "frame");
val = RNA_float_get(op->ptr, "value");
@@ -594,16 +622,18 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
/* apply inverse unit-mapping to value to get correct value for F-Curves */
- val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE);
-
+ scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
+
+ val = val * scale - offset;
+
/* insert keyframe on the specified frame + value */
insert_vert_fcurve(fcu, frame, val, 0);
-
+
ale->update |= ANIM_UPDATE_DEPS;
-
+
BLI_listbase_clear(&anim_data);
BLI_addtail(&anim_data, ale);
-
+
ANIM_animdata_update(&ac, &anim_data);
}
else {
@@ -699,7 +729,7 @@ static short copy_graph_keys(bAnimContext *ac)
}
static short paste_graph_keys(bAnimContext *ac,
- const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
+ const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
{
ListBase anim_data = {NULL, NULL};
int filter, ok = 0;
@@ -716,7 +746,7 @@ static short paste_graph_keys(bAnimContext *ac,
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* paste keyframes */
- ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode);
+ ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
/* clean up */
ANIM_animdata_freelist(&anim_data);
@@ -767,6 +797,7 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
+ const bool flipped = RNA_boolean_get(op->ptr, "flipped");
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -776,7 +807,7 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
ac.reports = op->reports;
/* paste keyframes - non-zero return means an error occurred while trying to paste */
- if (paste_graph_keys(&ac, offset_mode, merge_mode)) {
+ if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) {
return OPERATOR_CANCELLED;
}
@@ -788,6 +819,8 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
void GRAPH_OT_paste(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Paste Keyframes";
ot->idname = "GRAPH_OT_paste";
@@ -804,6 +837,8 @@ void GRAPH_OT_paste(wmOperatorType *ot)
/* props */
RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
+ prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************** Duplicate Keyframes Operator ************************* */
@@ -848,13 +883,6 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- graphkeys_duplicate_exec(C, op);
-
- return OPERATOR_FINISHED;
-}
-
void GRAPH_OT_duplicate(wmOperatorType *ot)
{
/* identifiers */
@@ -863,7 +891,6 @@ void GRAPH_OT_duplicate(wmOperatorType *ot)
ot->description = "Make a copy of all selected keyframes";
/* api callbacks */
- ot->invoke = graphkeys_duplicate_invoke;
ot->exec = graphkeys_duplicate_exec;
ot->poll = graphop_editable_keyframes_poll;
@@ -955,7 +982,7 @@ void GRAPH_OT_delete(wmOperatorType *ot)
/* ******************** Clean Keyframes Operator ************************* */
-static void clean_graph_keys(bAnimContext *ac, float thresh)
+static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -967,7 +994,7 @@ static void clean_graph_keys(bAnimContext *ac, float thresh)
/* loop through filtered data and clean curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- clean_fcurve((FCurve *)ale->key_data, thresh);
+ clean_fcurve(ac, ale, thresh, clean_chan);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -982,6 +1009,7 @@ static int graphkeys_clean_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
float thresh;
+ bool clean_chan;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -989,9 +1017,9 @@ static int graphkeys_clean_exec(bContext *C, wmOperator *op)
/* get cleaning threshold */
thresh = RNA_float_get(op->ptr, "threshold");
-
+ clean_chan = RNA_boolean_get(op->ptr, "channels");
/* clean keyframes */
- clean_graph_keys(&ac, thresh);
+ clean_graph_keys(&ac, thresh, clean_chan);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1016,6 +1044,7 @@ void GRAPH_OT_clean(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
+ RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
}
/* ******************** Bake F-Curve Operator *********************** */
@@ -1152,6 +1181,11 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
+ if (!BLI_is_file(path)) {
+ BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
+ return OPERATOR_CANCELLED;
+ }
+
scene = ac.scene; /* current scene */
/* store necessary data for the baking steps */
@@ -1241,8 +1275,8 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_float(ot->srna, "low", 0.0f, 0.0, 100000.0, "Lowest frequency",
"Cutoff frequency of a high-pass filter that is applied to the audio data", 0.1, 1000.00);
RNA_def_float(ot->srna, "high", 100000.0, 0.0, 100000.0, "Highest frequency",
@@ -1718,7 +1752,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
* so if the paths or the ID's don't match up, then a curve needs to be added
* to a new group
*/
- if ((euf) && (euf->id == ale->id) && (strcmp(euf->rna_path, fcu->rna_path) == 0)) {
+ if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) {
/* this should be fine to add to the existing group then */
euf->fcurves[fcu->array_index] = fcu;
}
@@ -1874,7 +1908,8 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
short mapping_flag = ANIM_get_normalization_flags(&ac);
KeyframeEditData current_ked;
- float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
memset(&current_ked, 0, sizeof(current_ked));
@@ -1888,7 +1923,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
ked.f1 += current_ked.f1;
ked.i1 += current_ked.i1;
- ked.f2 += current_ked.f2 / unit_scale;
+ ked.f2 += (current_ked.f2 + offset) * unit_scale;
ked.i2 += current_ked.i2;
}
@@ -1981,9 +2016,10 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* normalise cursor value (for normalised F-Curves display) */
if (mode == GRAPHKEYS_SNAP_VALUE) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
- ked.f1 = cursor_value / unit_scale;
+ ked.f1 = (cursor_value / unit_scale) - offset;
}
/* perform snapping */
@@ -2108,9 +2144,10 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* apply unit corrections */
if (mode == GRAPHKEYS_MIRROR_VALUE) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
- ked.f1 = cursor_value * unit_scale;
+ ked.f1 = (cursor_value + offset) * unit_scale;
}
/* perform actual mirroring */
@@ -2240,7 +2277,7 @@ static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(p
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
int index;
/* check if modifier is valid for this context */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 408c78d194e..a478a86a5e2 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -32,11 +32,8 @@
#define __GRAPH_INTERN_H__
struct bContext;
-struct wmWindowManager;
struct bAnimContext;
struct bAnimListElem;
-struct FCurve;
-struct FModifier;
struct SpaceIpo;
struct ScrArea;
struct ARegion;
@@ -62,6 +59,7 @@ void graph_draw_ghost_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, str
void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot);
void GRAPH_OT_select_border(struct wmOperatorType *ot);
void GRAPH_OT_select_lasso(struct wmOperatorType *ot);
+void GRAPH_OT_select_circle(struct wmOperatorType *ot);
void GRAPH_OT_select_column(struct wmOperatorType *ot);
void GRAPH_OT_select_linked(struct wmOperatorType *ot);
void GRAPH_OT_select_more(struct wmOperatorType *ot);
@@ -93,6 +91,7 @@ void get_graph_keyframe_extents(struct bAnimContext *ac, float *xmin, float *xma
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
void GRAPH_OT_view_selected(struct wmOperatorType *ot);
+void GRAPH_OT_view_frame(struct wmOperatorType *ot);
void GRAPH_OT_click_insert(struct wmOperatorType *ot);
void GRAPH_OT_keyframe_insert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 62b6b59df29..8e5c85d2c38 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -34,6 +34,7 @@
#include "DNA_scene_types.h"
+#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
@@ -86,8 +87,9 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
CFRA = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(CFRA);
SUBFRA = 0.f;
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
/* set the cursor value */
sipo->cursorVal = RNA_float_get(op->ptr, "value");
@@ -137,6 +139,7 @@ static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent
/* Modal Operator init */
static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ bScreen *screen = CTX_wm_screen(C);
/* Change to frame that mouse is over before adding modal handler,
* as user could click on a single frame (jump to frame) as well as
* click-dragging over a range (modal scrubbing).
@@ -146,6 +149,9 @@ static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* apply these changes first */
graphview_cursor_apply(C, op);
+ if (screen)
+ screen->scrubbing = true;
+
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -154,9 +160,12 @@ static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* Modal event handling of cursor changing */
static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ bScreen *screen = CTX_wm_screen(C);
/* execute the events */
switch (event->type) {
case ESCKEY:
+ if (screen)
+ screen->scrubbing = false;
return OPERATOR_FINISHED;
case MOUSEMOVE:
@@ -171,8 +180,11 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
/* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
* the modal op) doesn't work for some reason
*/
- if (event->val == KM_RELEASE)
+ if (event->val == KM_RELEASE) {
+ if (screen)
+ screen->scrubbing = false;
return OPERATOR_FINISHED;
+ }
break;
}
@@ -200,6 +212,174 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Value", "", -100.0f, 100.0f);
}
+/* Hide/Reveal ------------------------------------------------------------ */
+
+static int graphview_curves_hide_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ ListBase all_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ const bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* get list of all channels that selection may need to be flushed to
+ * - hierarchy must not affect what we have access to here...
+ */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
+
+ /* filter data
+ * - of the remaining visible curves, we want to hide the ones that are
+ * selected/unselected (depending on "unselected" prop)
+ */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ if (unselected)
+ filter |= ANIMFILTER_UNSEL;
+ else
+ filter |= ANIMFILTER_SEL;
+
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
+ /* TODO: find out why this is the case, and fix that */
+ if (ale->type == ANIMTYPE_OBJECT)
+ continue;
+
+ /* change the hide setting, and unselect it... */
+ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_CLEAR);
+
+ /* now, also flush selection status up/down as appropriate */
+ ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+ BLI_freelistN(&all_data);
+
+ /* unhide selected */
+ if (unselected) {
+ /* turn off requirement for visible */
+ filter = ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_LIST_CHANNELS;
+
+ /* flushing has been done */
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
+ /* TODO: find out why this is the case, and fix that */
+ if (ale->type == ANIMTYPE_OBJECT)
+ continue;
+
+ /* change the hide setting, and unselect it... */
+ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
+ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD);
+
+ /* now, also flush selection status up/down as appropriate */
+ ANIM_flush_setting_anim_channels(&ac, &anim_data, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
+ }
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+
+ /* send notifier that things have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void GRAPH_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Curves";
+ ot->idname = "GRAPH_OT_hide";
+ ot->description = "Hide selected curves from Graph Editor view";
+
+ /* api callbacks */
+ ot->exec = graphview_curves_hide_exec;
+ ot->poll = ED_operator_graphedit_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected curves");
+}
+
+/* ........ */
+
+static int graphview_curves_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bAnimContext ac;
+ ListBase anim_data = {NULL, NULL};
+ ListBase all_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* get list of all channels that selection may need to be flushed to
+ * - hierarchy must not affect what we have access to here...
+ */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
+
+ /* filter data
+ * - just go through all visible channels, ensuring that everything is set to be curve-visible
+ */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
+ /* TODO: find out why this is the case, and fix that */
+ if (ale->type == ANIMTYPE_OBJECT)
+ continue;
+
+ /* select if it is not visible */
+ if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE) == 0)
+ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD);
+
+ /* change the visibility setting */
+ ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
+
+ /* now, also flush selection status up/down as appropriate */
+ ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, true);
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+ BLI_freelistN(&all_data);
+
+ /* send notifier that things have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void GRAPH_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reveal Curves";
+ ot->idname = "GRAPH_OT_reveal";
+ ot->description = "Make previously hidden curves visible again in Graph Editor view";
+
+ /* api callbacks */
+ ot->exec = graphview_curves_reveal_exec;
+ ot->poll = ED_operator_graphedit_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ************************** registration - operator types **********************************/
void graphedit_operatortypes(void)
@@ -211,16 +391,21 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_view_all);
WM_operatortype_append(GRAPH_OT_view_selected);
WM_operatortype_append(GRAPH_OT_properties);
+ WM_operatortype_append(GRAPH_OT_view_frame);
WM_operatortype_append(GRAPH_OT_ghost_curves_create);
WM_operatortype_append(GRAPH_OT_ghost_curves_clear);
+ WM_operatortype_append(GRAPH_OT_hide);
+ WM_operatortype_append(GRAPH_OT_reveal);
+
/* keyframes */
/* selection */
WM_operatortype_append(GRAPH_OT_clickselect);
WM_operatortype_append(GRAPH_OT_select_all_toggle);
WM_operatortype_append(GRAPH_OT_select_border);
WM_operatortype_append(GRAPH_OT_select_lasso);
+ WM_operatortype_append(GRAPH_OT_select_circle);
WM_operatortype_append(GRAPH_OT_select_column);
WM_operatortype_append(GRAPH_OT_select_linked);
WM_operatortype_append(GRAPH_OT_select_more);
@@ -267,6 +452,7 @@ void ED_operatormacros_graph(void)
WM_operatortype_macro_define(ot, "GRAPH_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform");
RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE);
+ RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
}
@@ -359,6 +545,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
+ WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_CFRA);
@@ -387,15 +575,14 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_easing_type", EKEY, KM_PRESS, KM_CTRL, 0);
/* destructive */
- WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_smooth", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_bake", CKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
+ WM_keymap_add_menu(keymap, "GRAPH_MT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "GRAPH_MT_delete", DELKEY, KM_PRESS, 0, 0);
+
WM_keymap_add_item(keymap, "GRAPH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
/* insertkey */
@@ -405,9 +592,13 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* copy/paste */
WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "flipped", true);
#ifdef __APPLE__
WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
+ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "flipped", true);
#endif
/* auto-set range */
@@ -415,7 +606,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
-
+ WM_keymap_add_item(keymap, "GRAPH_OT_view_frame", PAD0, KM_PRESS, 0, 0);
+
/* F-Modifiers */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "only_active", false);
@@ -429,6 +621,22 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_fcurve");
+
+ /* pivot point settings */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
+ RNA_string_set(kmi->ptr, "value", "BOUNDING_BOX_CENTER");
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
+ RNA_string_set(kmi->ptr, "value", "CURSOR");
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
+ RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS");
+
/* special markers hotkeys for anim editors: see note in definition of this function */
ED_marker_keymap_animedit_conflictfree(keymap);
}
@@ -438,6 +646,7 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
void graphedit_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
+ wmKeyMapItem *kmi;
/* keymap for all regions */
keymap = WM_keymap_find(keyconf, "Graph Editor Generic", SPACE_IPO, 0);
@@ -448,7 +657,17 @@ void graphedit_keymap(wmKeyConfig *keyconf)
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
-
+
+ /* hide/reveal selected curves */
+ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_hide", HKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", false);
+
+ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", true);
+
+ WM_keymap_add_item(keymap, "GRAPH_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+
+
/* channels */
/* Channels are not directly handled by the Graph Editor module, but are inherited from the Animation module.
* All the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as these
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 378139accbc..67274100312 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -198,7 +198,7 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
ot->poll = graphop_visible_keyframes_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
@@ -219,7 +219,7 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
*/
static void borderselect_graphkeys(
bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, bool incl_handles,
- struct KeyframeEdit_LassoData *data_lasso)
+ void *data)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -244,10 +244,16 @@ static void borderselect_graphkeys(
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
- if (data_lasso) {
+ if (mode == BEZT_OK_REGION_LASSO) {
+ struct KeyframeEdit_LassoData *data_lasso = data;
data_lasso->rectf_scaled = &scaled_rectf;
ked.data = data_lasso;
}
+ else if (mode == BEZT_OK_REGION_CIRCLE) {
+ struct KeyframeEdit_CircleData *data_circle = data;
+ data_circle->rectf_scaled = &scaled_rectf;
+ ked.data = data;
+ }
else {
ked.data = &scaled_rectf;
}
@@ -266,7 +272,8 @@ static void borderselect_graphkeys(
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
@@ -276,8 +283,8 @@ static void borderselect_graphkeys(
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
- scaled_rectf.ymin = rectf.ymin / unit_scale;
- scaled_rectf.ymax = rectf.ymax / unit_scale;
+ scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
+ scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
@@ -390,7 +397,7 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
ot->poll = graphop_visible_keyframes_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
WM_operator_properties_gesture_border(ot, true);
@@ -485,6 +492,81 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+static int graph_circle_select_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ short selectmode;
+ bool incl_handles;
+ rctf rect_fl;
+ struct KeyframeEdit_CircleData data;
+ float x = RNA_int_get(op->ptr, "x");
+ float y = RNA_int_get(op->ptr, "y");
+ float radius = RNA_int_get(op->ptr, "radius");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data.mval[0] = x;
+ data.mval[1] = y;
+ data.radius_squared = radius * radius;
+ data.rectf_view = &rect_fl;
+
+ if (gesture_mode == GESTURE_MODAL_SELECT)
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ rect_fl.xmin = x - radius;
+ rect_fl.xmax = x + radius;
+ rect_fl.ymin = y - radius;
+ rect_fl.ymax = y + radius;
+
+ if (ac.spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)ac.sl;
+ if (selectmode == SELECT_ADD) {
+ incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
+ (sipo->flag & SIPO_NOHANDLES)) == 0;
+ }
+ else {
+ incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
+ }
+ }
+ else {
+ incl_handles = false;
+ }
+
+ /* apply borderselect action */
+ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_select_circle(wmOperatorType *ot)
+{
+ ot->name = "Circle Select";
+ ot->description = "Select keyframe points using circle selection";
+ ot->idname = "GRAPH_OT_select_circle";
+
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = graph_circle_select_exec;
+ ot->poll = graphop_visible_keyframes_poll;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
/* ******************** Column Select Operator **************************** */
/* This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
@@ -662,7 +744,7 @@ void GRAPH_OT_select_column(wmOperatorType *ot)
ot->poll = graphop_visible_keyframes_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
@@ -720,7 +802,7 @@ void GRAPH_OT_select_linked(wmOperatorType *ot)
ot->poll = graphop_visible_keyframes_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Select More/Less Operators *********************** */
@@ -798,7 +880,7 @@ void GRAPH_OT_select_more(wmOperatorType *ot)
ot->poll = graphop_visible_keyframes_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ----------------- */
@@ -832,7 +914,7 @@ void GRAPH_OT_select_less(wmOperatorType *ot)
ot->poll = graphop_visible_keyframes_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Select Left/Right Operator ************************* */
@@ -1008,6 +1090,8 @@ typedef struct tNearestVertInfo {
short hpoint; /* the handle index that we hit (eHandleIndex) */
short sel; /* whether the handle is selected or not */
int dist; /* distance from mouse to vert */
+
+ eAnim_ChannelType ctype; /* type of animation channel this FCurve comes from */
} tNearestVertInfo;
/* Tags for the type of graph vert that we have */
@@ -1028,15 +1112,15 @@ typedef enum eGraphVertIndex {
static bool fcurve_handle_sel_check(SpaceIpo *sipo, BezTriple *bezt)
{
if (sipo->flag & SIPO_NOHANDLES) return 0;
- if ((sipo->flag & SIPO_SELVHANDLESONLY) && BEZSELECTED(bezt) == 0) return 0;
+ if ((sipo->flag & SIPO_SELVHANDLESONLY) && BEZT_ISSEL_ANY(bezt) == 0) return 0;
return 1;
}
/* check if the given vertex is within bounds or not */
// TODO: should we return if we hit something?
static void nearest_fcurve_vert_store(
- ListBase *matches, View2D *v2d, FCurve *fcu,
- BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale)
+ ListBase *matches, View2D *v2d, FCurve *fcu, eAnim_ChannelType ctype,
+ BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale, float offset)
{
/* Keyframes or Samples? */
if (bezt) {
@@ -1048,7 +1132,7 @@ static void nearest_fcurve_vert_store(
* 'vec' matrix
*/
if (UI_view2d_view_to_region_clip(v2d,
- bezt->vec[hpoint + 1][0], bezt->vec[hpoint + 1][1] * unit_scale,
+ bezt->vec[hpoint + 1][0], (bezt->vec[hpoint + 1][1] + offset) * unit_scale,
&screen_co[0], &screen_co[1]) &&
/* check if distance from mouse cursor to vert in screen space is within tolerance */
((dist = len_v2v2_int(mval, screen_co)) <= GVERTSEL_TOL))
@@ -1059,7 +1143,7 @@ static void nearest_fcurve_vert_store(
/* if there is already a point for the F-Curve, check if this point is closer than that was */
if ((nvi) && (nvi->fcu == fcu)) {
/* replace if we are closer, or if equal and that one wasn't selected but we are... */
- if ((nvi->dist > dist) || ((nvi->sel == 0) && BEZSELECTED(bezt)))
+ if ((nvi->dist > dist) || ((nvi->sel == 0) && BEZT_ISSEL_ANY(bezt)))
replace = 1;
}
/* add new if not replacing... */
@@ -1068,11 +1152,13 @@ static void nearest_fcurve_vert_store(
/* store values */
nvi->fcu = fcu;
+ nvi->ctype = ctype;
+
nvi->bezt = bezt;
nvi->hpoint = hpoint;
nvi->dist = dist;
- nvi->sel = BEZSELECTED(bezt); // XXX... should this use the individual verts instead?
+ nvi->sel = BEZT_ISSEL_ANY(bezt); // XXX... should this use the individual verts instead?
/* add to list of matches if appropriate... */
if (replace == 0)
@@ -1108,30 +1194,31 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
-
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
+
/* apply NLA mapping to all the keyframes */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
-
+
if (fcu->bezt) {
BezTriple *bezt1 = fcu->bezt, *prevbezt = NULL;
int i;
for (i = 0; i < fcu->totvert; i++, prevbezt = bezt1, bezt1++) {
/* keyframe */
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_KEY, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_KEY, mval, unit_scale, offset);
/* handles - only do them if they're visible */
if (fcurve_handle_sel_check(sipo, bezt1) && (fcu->totvert > 1)) {
/* first handle only visible if previous segment had handles */
if ((!prevbezt && (bezt1->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_LEFT, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_LEFT, mval, unit_scale, offset);
}
/* second handle only visible if this segment is bezier */
if (bezt1->ipo == BEZT_IPO_BEZ) {
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval, unit_scale, offset);
}
}
}
@@ -1251,11 +1338,11 @@ static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_m
if (select_mode == SELECT_INVERT) {
/* keyframe - invert select of all */
if (nvi->hpoint == NEAREST_HANDLE_KEY) {
- if (BEZSELECTED(bezt)) {
- BEZ_DESEL(bezt);
+ if (BEZT_ISSEL_ANY(bezt)) {
+ BEZT_DESEL_ALL(bezt);
}
else {
- BEZ_SEL(bezt);
+ BEZT_SEL_ALL(bezt);
}
}
@@ -1272,7 +1359,7 @@ static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_m
else {
/* if the keyframe was clicked on, select all verts of given beztriple */
if (nvi->hpoint == NEAREST_HANDLE_KEY) {
- BEZ_SEL(bezt);
+ BEZT_SEL_ALL(bezt);
}
/* otherwise, select the handle that applied */
else if (nvi->hpoint == NEAREST_HANDLE_LEFT)
@@ -1306,7 +1393,7 @@ static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_m
/* take selection status from item that got hit, to prevent flip/flop on channel
* selection status when shift-selecting (i.e. "SELECT_INVERT") points
*/
- if (BEZSELECTED(bezt))
+ if (BEZT_ISSEL_ANY(bezt))
nvi->fcu->flag |= FCURVE_SELECTED;
else
nvi->fcu->flag &= ~FCURVE_SELECTED;
@@ -1324,7 +1411,7 @@ static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_m
/* needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY) otherwise the active flag won't be set [#26452] */
if (nvi->fcu->flag & FCURVE_SELECTED) {
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
}
/* free temp sample data for filtering */
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index e9c8ae95acd..0e56dc817e4 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -40,7 +40,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BKE_context.h"
@@ -211,13 +210,18 @@ int graphop_active_fcurve_poll(bContext *C)
if (ale == NULL)
return 0;
- /* free temp data... */
- has_fcurve = ((ale->data) && (ale->type == ANIMTYPE_FCURVE));
+ /* do we have a suitable F-Curves?
+ * - For most cases, NLA Control Curves are sufficiently similar to NLA curves to serve this role too.
+ * Under the hood, they are F-Curves too. The only problems which will arise here are if these need to be
+ * in an Action too (but drivers would then also be affected!)
+ */
+ has_fcurve = ((ale->data) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE));
if (has_fcurve) {
FCurve *fcu = (FCurve *)ale->data;
has_fcurve = (fcu->flag & FCURVE_VISIBLE) != 0;
}
+ /* free temp data... */
MEM_freeN(ale);
/* return success */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 6dba706b241..4c7ac532411 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -182,7 +182,7 @@ static void graph_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
{
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
- /* init dopesheet data if non-existant (i.e. for old files) */
+ /* init dopesheet data if non-existent (i.e. for old files) */
if (sipo->ads == NULL) {
sipo->ads = MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
sipo->ads->source = (ID *)(G.main->scene.first); // FIXME: this is a really nasty hack here for now...
@@ -293,7 +293,7 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
- draw_markers_time(C, 0);
+ ED_markers_draw(C, DRAW_MARKERS_MARGIN);
/* preview range */
UI_view2d_view_ortho(v2d);
@@ -384,7 +384,7 @@ static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void graph_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 62ac3c2d985..c60d194b620 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -23,14 +23,16 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
- ../../imbuf
+ ../../blentranslation
../../bmesh
+ ../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
- ../../gpu
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -71,4 +73,6 @@ if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript
index d878a726b55..95d23d177e7 100644
--- a/source/blender/editors/space_image/SConscript
+++ b/source/blender/editors/space_image/SConscript
@@ -31,12 +31,15 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -47,6 +50,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 7e90008d8d2..6b5cc38595b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -38,12 +38,13 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "BKE_scene.h"
#include "RE_pipeline.h"
@@ -64,6 +65,7 @@
#include "image_intern.h"
#define B_NOP -1
+#define MAX_IMAGE_INFO_LEN 128
/* proto */
@@ -81,9 +83,9 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
else {
if (ima->source == IMA_SRC_MOVIE) {
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs);
- if (ima->anim)
+ if (BKE_image_has_anim(ima))
ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(" %d frs"),
- IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN));
}
else {
ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs);
@@ -268,7 +270,7 @@ static void image_panel_preview(ScrArea *sa, short cntrl) // IMAGE_HANDLER_PRE
return;
}
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | UI_PNL_SCALE | cntrl);
uiSetPanelHandler(IMAGE_HANDLER_PREVIEW); // for close and esc
@@ -276,7 +278,7 @@ static void image_panel_preview(ScrArea *sa, short cntrl) // IMAGE_HANDLER_PRE
ofsy = -100 + (sa->winy / 2) / sima->blockscale;
if (uiNewPanel(C, ar, block, "Preview", "Image", ofsx, ofsy, 300, 200) == 0) return;
- uiBlockSetDrawExtraFunc(block, preview_cb);
+ UI_but_func_drawextra_set(block, preview_cb);
}
#endif
@@ -284,31 +286,37 @@ static void image_panel_preview(ScrArea *sa, short cntrl) // IMAGE_HANDLER_PRE
/* ********************* callbacks for standard image buttons *************** */
-static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *render_slot_p)
+static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *image_p)
{
uiBlock *block = uiLayoutGetBlock(layout);
- short *render_slot = render_slot_p;
+ Image *image = image_p;
int slot;
- uiDefBut(block, LABEL, 0, IFACE_("Slot"),
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Slot"),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
slot = IMA_MAX_RENDER_SLOT;
while (slot--) {
- char str[32];
- BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot + 1);
- uiDefButS(block, BUTM, B_NOP, str, 0, 0,
- UI_UNIT_X * 5, UI_UNIT_X, render_slot, (float) slot, 0.0, 0, -1, "");
+ char str[64];
+ if (image->render_slots[slot].name[0] != '\0') {
+ BLI_strncpy(str, image->render_slots[slot].name, sizeof(str));
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot + 1);
+ }
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, str, 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &image->render_slot, (float) slot, 0.0, 0, -1, "");
}
}
static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{
- if (rr->rectf) {
+ RenderView *rv = RE_RenderViewGetById(rr, 0);
+ if (rv->rectf) {
return IFACE_("Composite");
}
- else if (rr->rect32) {
+ else if (rv->rect32) {
return IFACE_("Sequence");
}
else {
@@ -320,21 +328,29 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void
{
void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- RenderResult *rr = rnd_data[0];
+ Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
+ Scene *scene = iuser->scene;
+ RenderResult *rr;
RenderLayer *rl;
RenderLayer rl_fake = {NULL};
const char *fake_name;
int nr;
- uiBlockSetCurLayout(block, layout);
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
+ UI_block_layout_set_current(block, layout);
uiLayoutColumn(layout, false);
- uiDefBut(block, LABEL, 0, IFACE_("Layer"),
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Layer"),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
- nr = BLI_countlist(&rr->layers) - 1;
+ nr = BLI_listbase_count(&rr->layers) - 1;
fake_name = ui_imageuser_layer_fake_name(rr);
if (fake_name) {
@@ -344,7 +360,7 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void
for (rl = rr->layers.last; rl; rl = rl->prev, nr--) {
final:
- uiDefButS(block, BUTM, B_NOP, IFACE_(rl->name), 0, 0,
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, rl->name, 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->layer, (float) nr, 0.0, 0, -1, "");
}
@@ -355,11 +371,13 @@ final:
}
BLI_assert(nr == -1);
+
+ BKE_image_release_renderresult(scene, image);
}
static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
{
- if (rl == NULL || rl->rectf) {
+ if (rl == NULL) {
return IFACE_("Combined");
}
else {
@@ -367,49 +385,129 @@ static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
}
}
-static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *ptrpair_p)
+static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **ptrpair = ptrpair_p;
+ void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- // RenderResult *rr = ptrpair[0];
- ImageUser *iuser = ptrpair[1];
- /* rl==NULL means composite result */
- RenderLayer *rl = ptrpair[2];
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ /* (rpass_index == -1) means composite result */
+ const int rpass_index = GET_INT_FROM_POINTER(rnd_data[2]);
+ Scene *scene = iuser->scene;
+ RenderResult *rr;
+ RenderLayer *rl;
RenderPass rpass_fake = {NULL};
RenderPass *rpass;
const char *fake_name;
int nr;
+ int passflag = 0;
+
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
+ rl = BLI_findlink(&rr->layers, rpass_index);
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
uiLayoutColumn(layout, false);
- uiDefBut(block, LABEL, 0, IFACE_("Pass"),
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Pass"),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
- nr = (rl ? BLI_countlist(&rl->passes) : 0) - 1;
+ nr = 0;
fake_name = ui_imageuser_pass_fake_name(rl);
if (fake_name) {
- BLI_strncpy(rpass_fake.name, fake_name, sizeof(rpass_fake.name));
+ BLI_strncpy(rpass_fake.internal_name, fake_name, sizeof(rpass_fake.internal_name));
nr += 1;
}
/* rendered results don't have a Combined pass */
- for (rpass = rl ? rl->passes.last : NULL; rpass; rpass = rpass->prev, nr--) {
+ /* multiview: the ordering must be ascending, so the left-most pass is always the one picked */
+ for (rpass = rl ? rl->passes.first : NULL; rpass; rpass = rpass->next, nr++) {
+
+ /* just show one pass of each kind */
+ if (passflag & rpass->passtype)
+ continue;
+
+ passflag |= rpass->passtype;
+
final:
- uiDefButS(block, BUTM, B_NOP, IFACE_(rpass->name), 0, 0,
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, (float) nr, 0.0, 0, -1, "");
}
if (fake_name) {
fake_name = NULL;
rpass = &rpass_fake;
+ nr = 0;
goto final;
}
- BLI_assert(nr == -1);
+ BKE_image_release_renderresult(scene, image);
+}
+
+/**************************** view menus *****************************/
+static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
+{
+ void **rnd_data = rnd_pt;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ RenderResult *rr;
+ RenderView *rview;
+ int nr;
+ Scene *scene = iuser->scene;
+
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
+ UI_block_layout_set_current(block, layout);
+ uiLayoutColumn(layout, false);
+
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
+ 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiItemS(layout);
+
+ nr = (rr ? BLI_listbase_count(&rr->views) : 0) - 1;
+ for (rview = rr ? rr->views.last : NULL; rview; rview = rview->prev, nr--) {
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rview->name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
+ }
+
+ BKE_image_release_renderresult(scene, image);
+}
+
+static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
+{
+ void **rnd_data = rnd_pt;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ int nr;
+ ImageView *iv;
+
+ UI_block_layout_set_current(block, layout);
+ uiLayoutColumn(layout, false);
+
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
+ 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiItemS(layout);
+
+ nr = BLI_listbase_count(&image->views) - 1;
+ for (iv = image->views.last; iv; iv = iv->prev, nr--) {
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(iv->name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
+ }
}
/* 5 layer button callbacks... */
@@ -417,16 +515,17 @@ static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
{
ImageUser *iuser = iuser_v;
- BKE_image_multilayer_index(rr_v, iuser);
+ BKE_image_multilayer_index(rr_v, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
+
static void image_multi_inclay_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
- int tot = BLI_countlist(&rr->layers);
+ int tot = BLI_listbase_count(&rr->layers);
- if (rr->rectf || rr->rect32)
+ if (RE_HasFakeLayer(rr))
tot++; /* fake compo/sequencer layer */
if (iuser->layer < tot - 1) {
@@ -449,32 +548,76 @@ static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
- RenderLayer *rl = BLI_findlink(&rr->layers, iuser->layer);
+ RenderLayer *rl;
+ RenderPass *rp;
+ int layer = iuser->layer;
- if (rl) {
- int tot = BLI_countlist(&rl->passes);
+ if (RE_HasFakeLayer(rr))
+ layer -= 1;
- if (rr->rectf || rr->rect32)
- tot++; /* fake compo/sequencer layer */
+ rl = BLI_findlink(&rr->layers, layer);
- if (iuser->pass < tot - 1) {
- iuser->pass++;
- BKE_image_multilayer_index(rr, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ if (rl) {
+ RenderPass *rpass = BLI_findlink(&rl->passes, iuser->pass);
+ int rp_index = iuser->pass + 1;
+
+ if (rpass == NULL)
+ return;
+
+ for (rp = rpass->next; rp; rp = rp->next, rp_index++) {
+ if (rp->passtype != rpass->passtype) {
+ iuser->pass = rp_index;
+ BKE_image_multilayer_index(rr, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ break;
+ }
}
}
}
static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v)
{
+ RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
+ RenderLayer *rl;
+ RenderPass *rp;
+ int layer = iuser->layer;
- if (iuser->pass > 0) {
- iuser->pass--;
- BKE_image_multilayer_index(rr_v, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ if (iuser->pass == 0)
+ return;
+
+ if (RE_HasFakeLayer(rr))
+ layer -= 1;
+
+ rl = BLI_findlink(&rr->layers, layer);
+
+ if (rl) {
+ RenderPass *rpass = BLI_findlink(&rl->passes, iuser->pass);
+ int rp_index = 0;
+
+ if (rpass == NULL)
+ return;
+
+ for (rp = rl->passes.first; rp; rp = rp->next, rp_index++) {
+ if (rp->passtype == rpass->passtype) {
+ iuser->pass = rp_index - 1;
+ BKE_image_multilayer_index(rr, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ break;
+ }
+ }
}
}
+/* 5 view button callbacks... */
+static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v)
+{
+ Image *ima = ima_v;
+ ImageUser *iuser = iuser_v;
+
+ BKE_image_multiview_index(ima, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+}
+
#if 0
static void image_freecache_cb(bContext *C, void *ima_v, void *unused)
{
@@ -492,15 +635,16 @@ static void image_user_change(bContext *C, void *iuser_v, void *unused)
}
#endif
-static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
+static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
{
- static void *rnd_pt[3]; /* XXX, workaround */
+ static void *rnd_pt[4]; /* XXX, workaround */
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
- int wmenu1, wmenu2, wmenu3;
+ int wmenu1, wmenu2, wmenu3, wmenu4;
const char *fake_name;
- const char *display_name;
+ const char *display_name = "";
+ const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO) != 0;
uiLayoutRow(layout, true);
@@ -508,51 +652,94 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, Image
wmenu1 = (2 * w) / 5;
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
+ wmenu4 = (3 * w) / 6;
- rnd_pt[0] = rr;
+ rnd_pt[0] = image;
rnd_pt[1] = iuser;
rnd_pt[2] = NULL;
/* menu buts */
if (render_slot) {
char str[64];
- BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
- but = uiDefMenuBut(block, ui_imageuser_slot_menu, render_slot, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
- uiButSetFunc(but, image_multi_cb, rr, iuser);
- uiButSetMenuFromPulldown(but);
+ if (image->render_slots[*render_slot].name[0] != '\0') {
+ BLI_strncpy(str, image->render_slots[*render_slot].name, sizeof(str));
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
+ }
+ but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
}
if (rr) {
RenderPass *rpass;
+ RenderView *rview;
+ int rpass_index;
/* layer */
fake_name = ui_imageuser_layer_fake_name(rr);
- rl = BLI_findlink(&rr->layers, iuser->layer - (fake_name ? 1 : 0));
- rnd_pt[2] = rl;
-
- display_name = rl ? rl->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name, 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
- uiButSetFunc(but, image_multi_cb, rr, iuser);
- uiButSetMenuFromPulldown(but);
-
+ rpass_index = iuser->layer - (fake_name ? 1 : 0);
+ rl = BLI_findlink(&rr->layers, rpass_index);
+ rnd_pt[2] = SET_INT_IN_POINTER(rpass_index);
+
+ if (RE_layers_have_name(rr)) {
+ display_name = rl ? rl->name : (fake_name ? fake_name : "");
+ but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name,
+ 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
+ }
/* pass */
fake_name = ui_imageuser_pass_fake_name(rl);
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
- display_name = rpass ? rpass->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, display_name, 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
- uiButSetFunc(but, image_multi_cb, rr, iuser);
- uiButSetMenuFromPulldown(but);
+ display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
+ but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
+ 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
+
+ /* view */
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1 &&
+ ((!show_stereo) || (!RE_RenderResult_is_stereo(rr))))
+ {
+ rview = BLI_findlink(&rr->views, iuser->view);
+ display_name = rview ? rview->name : "";
+
+ but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
+ }
+ }
+
+ /* stereo image */
+ else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) ||
+ ((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0)))
+ {
+ ImageView *iv;
+ int nr = 0;
+
+ for (iv = image->views.first; iv; iv = iv->next) {
+ if (nr++ == iuser->view) {
+ display_name = iv->name;
+ break;
+ }
+ }
+
+ but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_func_set(but, image_multiview_cb, image, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
}
}
-static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, short *render_slot)
+static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser,
+ int menus_width, short *render_slot)
{
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row;
uiBut *but;
- const float dpi_fac = UI_DPI_FAC;
row = uiLayoutRow(layout, true);
@@ -564,20 +751,20 @@ static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, RenderResult *rr,
}
/* decrease, increase arrows */
- but = uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Layer"));
- uiButSetFunc(but, image_multi_declay_cb, rr, iuser);
- but = uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Layer"));
- uiButSetFunc(but, image_multi_inclay_cb, rr, iuser);
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Layer"));
+ UI_but_func_set(but, image_multi_declay_cb, rr, iuser);
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Layer"));
+ UI_but_func_set(but, image_multi_inclay_cb, rr, iuser);
- uiblock_layer_pass_buttons(row, rr, iuser, 230 * dpi_fac, render_slot);
+ uiblock_layer_pass_buttons(row, image, rr, iuser, menus_width, render_slot);
/* decrease, increase arrows */
- but = uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Pass"));
- uiButSetFunc(but, image_multi_decpass_cb, rr, iuser);
- but = uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Pass"));
- uiButSetFunc(but, image_multi_incpass_cb, rr, iuser);
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Pass"));
+ UI_but_func_set(but, image_multi_decpass_cb, rr, iuser);
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Pass"));
+ UI_but_func_set(but, image_multi_incpass_cb, rr, iuser);
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
}
// XXX HACK!
@@ -603,10 +790,8 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
RNA_property_update(C, &cb->ptr, cb->prop);
}
-void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact)
+void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact, int multiview)
{
-#define MAX_INFO_LEN 128
-
PropertyRNA *prop;
PointerRNA imaptr;
RNAUpdateCb *cb;
@@ -615,7 +800,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
Scene *scene = CTX_data_scene(C);
uiLayout *row, *split, *col;
uiBlock *block;
- char str[MAX_INFO_LEN];
+ char str[MAX_IMAGE_INFO_LEN];
void *lock;
@@ -652,14 +837,14 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiLayoutSetContextPointer(layout, "edit_image_user", userptr);
if (!compact)
- uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, propname, ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL);
if (ima) {
- uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
+ UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
if (ima->source == IMA_SRC_VIEWER) {
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN);
+ image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN);
BKE_image_release_ibuf(ima, ibuf, lock);
uiItemL(layout, ima->id.name + 2, ICON_NONE);
@@ -670,28 +855,35 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
#if 0
iuser = ntree_get_active_iuser(scene->nodetree);
if (iuser) {
- uiBlockBeginAlign(block);
- uiDefIconTextBut(block, BUT, B_SIMA_RECORD, ICON_REC, "Record", 10, 120, 100, 20, 0, 0, 0, 0, 0, "");
- uiDefIconTextBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, "Play", 110, 120, 100, 20, 0, 0, 0, 0, 0, "");
- but = uiDefBut(block, BUT, B_NOP, "Free Cache", 210, 120, 100, 20, 0, 0, 0, 0, 0, "");
- uiButSetFunc(but, image_freecache_cb, ima, NULL);
+ UI_block_align_begin(block);
+ uiDefIconTextBut(block, UI_BTYPE_BUT, B_SIMA_RECORD, ICON_REC, "Record", 10, 120, 100, 20, 0, 0, 0, 0, 0, "");
+ uiDefIconTextBut(block, UI_BTYPE_BUT, B_SIMA_PLAY, ICON_PLAY, "Play", 110, 120, 100, 20, 0, 0, 0, 0, 0, "");
+ but = uiDefBut(block, UI_BTYPE_BUT, B_NOP, "Free Cache", 210, 120, 100, 20, 0, 0, 0, 0, 0, "");
+ UI_but_func_set(but, image_freecache_cb, ima, NULL);
if (iuser->frames)
BLI_snprintf(str, sizeof(str), "(%d) Frames:", iuser->framenr);
else strcpy(str, "Frames:");
- uiBlockBeginAlign(block);
- uiDefButI(block, NUM, imagechanged, str, 10, 90, 150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Number of images of a movie to use");
- uiDefButI(block, NUM, imagechanged, "StartFr:", 160, 90, 150, 20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Global starting frame of the movie");
+ UI_block_align_begin(block);
+ uiDefButI(block, UI_BTYPE_NUM, imagechanged, str, 10, 90, 150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Number of images of a movie to use");
+ uiDefButI(block, UI_BTYPE_NUM, imagechanged, "StartFr:", 160, 90, 150, 20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Global starting frame of the movie");
}
#endif
}
else if (ima->type == IMA_TYPE_R_RESULT) {
/* browse layer/passes */
RenderResult *rr;
+ const float dpi_fac = UI_DPI_FAC;
+ const int menus_width = 230 * dpi_fac;
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- uiblock_layer_pass_arrow_buttons(layout, rr, iuser, &ima->render_slot);
+ if (rr) {
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
+ else {
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
BKE_image_release_renderresult(scene, ima);
}
}
@@ -700,13 +892,13 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (ima->source != IMA_SRC_GENERATED) {
row = uiLayoutRow(layout, true);
- if (ima->packedfile)
+ if (BKE_image_has_packedfile(ima))
uiItemO(row, "", ICON_PACKAGE, "image.unpack");
else
uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, ima->packedfile == NULL);
+ uiLayoutSetEnabled(row, BKE_image_has_packedfile(ima) == false);
uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@@ -724,14 +916,12 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
/* multilayer? */
if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
- uiblock_layer_pass_arrow_buttons(layout, ima->rr, iuser, NULL);
+ const float dpi_fac = UI_DPI_FAC;
+ uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL);
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN);
- BKE_image_release_ibuf(ima, ibuf, lock);
- uiItemL(layout, str, ICON_NONE);
+ uiTemplateImageInfo(layout, C, ima, iuser);
}
}
@@ -745,7 +935,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
bool has_alpha = true;
if (ibuf) {
- int imtype = BKE_ftype_to_imtype(ibuf->ftype);
+ int imtype = BKE_image_ftype_to_imtype(ibuf->ftype, &ibuf->foptions);
char valid_channels = BKE_imtype_valid_channels(imtype, false);
has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0;
@@ -753,13 +943,28 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
BKE_image_release_ibuf(ima, ibuf, NULL);
}
+ if (multiview) {
+ if ((scene->r.scemode & R_MULTIVIEW) != 0) {
+ uiItemR(layout, &imaptr, "use_multiview", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(&imaptr, "use_multiview")) {
+ uiTemplateImageViews(layout, &imaptr);
+ }
+ }
+ }
+
if (has_alpha) {
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(col, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_alpha"));
+ uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE);
}
- uiItemS(layout);
+ if (ima->source == IMA_SRC_MOVIE) {
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
+ }
split = uiLayoutSplit(layout, 0.0f, false);
@@ -809,16 +1014,18 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE);
uiItemR(split, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ if (ima->gen_type == IMA_GENTYPE_BLANK) {
+ uiItemR(layout, &imaptr, "generated_color", 0, NULL, ICON_NONE);
+ }
}
}
- uiBlockSetNFunc(block, NULL, NULL, NULL);
+ UI_block_funcN_set(block, NULL, NULL, NULL);
}
MEM_freeN(cb);
-
-#undef MAX_INFO_LEN
}
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_management)
@@ -922,35 +1129,143 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
}
}
+void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
+{
+ Stereo3dFormat *stereo3d_format = stereo3d_format_ptr->data;
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
+
+ switch (stereo3d_format->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ {
+ uiItemR(col, stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_INTERLACE:
+ {
+ uiItemR(col, stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
+ uiItemR(col, stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
+ /* fall-through */
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ uiItemR(col, stereo3d_format_ptr, "use_squeezed_frame", 0, NULL, ICON_NONE);
+ break;
+ }
+ }
+}
+
+static void uiTemplateViewsFormat(uiLayout *layout, PointerRNA *ptr, PointerRNA *stereo3d_format_ptr)
+{
+ uiLayout *col, *box;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemL(col, IFACE_("Views Format:"), ICON_NONE);
+ uiItemR(uiLayoutRow(col, false), ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ if (stereo3d_format_ptr) {
+ box = uiLayoutBox(col);
+ uiLayoutSetActive(box, RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D);
+ uiTemplateImageStereo3d(box, stereo3d_format_ptr);
+ }
+}
+
+void uiTemplateImageViews(uiLayout *layout, PointerRNA *imaptr)
+{
+ Image *ima = imaptr->data;
+
+ if (ima->type != IMA_TYPE_MULTILAYER) {
+ PropertyRNA *prop;
+ PointerRNA stereo3d_format_ptr;
+
+ prop = RNA_struct_find_property(imaptr, "stereo_3d_format");
+ stereo3d_format_ptr = RNA_property_pointer_get(imaptr, prop);
+
+ uiTemplateViewsFormat(layout, imaptr, &stereo3d_format_ptr);
+ }
+ else {
+ uiTemplateViewsFormat(layout, imaptr, NULL);
+ }
+}
+
+void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
+{
+ ImageFormatData *imf = imfptr->data;
+
+ if (ptr == NULL)
+ return;
+
+ uiItemR(layout, ptr, "use_multiview", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(ptr, "use_multiview")) {
+ if (imf->imtype != R_IMF_IMTYPE_MULTILAYER) {
+ PropertyRNA *prop;
+ PointerRNA stereo3d_format_ptr;
+
+ prop = RNA_struct_find_property(imfptr, "stereo_3d_format");
+ stereo3d_format_ptr = RNA_property_pointer_get(imfptr, prop);
+
+ uiTemplateViewsFormat(layout, imfptr, &stereo3d_format_ptr);
+ }
+ else {
+ uiTemplateViewsFormat(layout, imfptr, NULL);
+ }
+ }
+}
+
void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
{
Scene *scene = CTX_data_scene(C);
/* render layers and passes */
if (ima && iuser) {
- const float dpi_fac = UI_DPI_FAC;
RenderResult *rr;
+ const float dpi_fac = UI_DPI_FAC;
+ const int menus_width = 160 * dpi_fac;
+ const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT);
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- uiblock_layer_pass_buttons(layout, rr, iuser, 160 * dpi_fac, (ima->type == IMA_TYPE_R_RESULT) ? &ima->render_slot : NULL);
+ if (rr && is_render_result) {
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
+ else {
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width,
+ is_render_result ? &ima->render_slot : NULL);
+ }
BKE_image_release_renderresult(scene, ima);
}
}
-void image_buttons_register(ARegionType *art)
+void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
{
- PanelType *pt;
- const char *category = "Grease Pencil";
+ ImBuf *ibuf;
+ char str[MAX_IMAGE_INFO_LEN];
+ void *lock;
+
+ if (!ima || !iuser)
+ return;
- pt = MEM_callocN(sizeof(PanelType), "spacetype image panel gpencil");
- strcpy(pt->idname, "IMAGE_PT_gpencil");
- strcpy(pt->label, N_("Grease Pencil"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = ED_gpencil_panel_standard_header;
- pt->draw = ED_gpencil_panel_standard;
- BLI_strncpy(pt->category, category, BLI_strlen_utf8(category));
- BLI_addtail(&art->paneltypes, pt);
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
+
+ image_info(CTX_data_scene(C), iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ uiItemL(layout, str, ICON_NONE);
+}
+
+#undef MAX_IMAGE_INFO_LEN
+
+void image_buttons_register(ARegionType *UNUSED(art))
+{
+
}
static int image_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 79c21bab01c..3a178ed0277 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -68,6 +68,7 @@
#include "ED_gpencil.h"
#include "ED_image.h"
#include "ED_mask.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -79,25 +80,36 @@
#include "image_intern.h"
-static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx, float zoomy)
+static void draw_render_info(const bContext *C,
+ Scene *scene,
+ Image *ima,
+ ARegion *ar,
+ float zoomx,
+ float zoomy)
{
RenderResult *rr;
Render *re = RE_GetRender(scene->id.name);
+ RenderData *rd = RE_engine_get_render_data(re);
+ Scene *stats_scene = ED_render_job_get_scene(C);
+ if (stats_scene == NULL) {
+ stats_scene = CTX_data_scene(C);
+ }
- rr = BKE_image_acquire_renderresult(scene, ima);
+ rr = BKE_image_acquire_renderresult(stats_scene, ima);
if (rr && rr->text) {
float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
- ED_region_info_draw(ar, rr->text, 1, fill_color);
+ ED_region_info_draw(ar, rr->text, fill_color, true);
}
- BKE_image_release_renderresult(scene, ima);
+ BKE_image_release_renderresult(stats_scene, ima);
if (re) {
int total_tiles;
+ bool need_free_tiles;
rcti *tiles;
- RE_engine_get_current_tiles(re, &total_tiles, &tiles);
+ tiles = RE_engine_get_current_tiles(re, &total_tiles, &need_free_tiles);
if (total_tiles) {
int i, x, y;
@@ -110,9 +122,9 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx,
glTranslatef(x, y, 0.0f);
glScalef(zoomx, zoomy, 1.0f);
- if (scene->r.mode & R_BORDER) {
- glTranslatef((int)(-scene->r.border.xmin * scene->r.xsch * scene->r.size / 100.0f),
- (int)(-scene->r.border.ymin * scene->r.ysch * scene->r.size / 100.0f),
+ if (rd->mode & R_BORDER) {
+ glTranslatef((int)(-rd->border.xmin * rd->xsch * rd->size / 100.0f),
+ (int)(-rd->border.ymin * rd->ysch * rd->size / 100.0f),
0.0f);
}
@@ -122,7 +134,9 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx,
glaDrawBorderCorners(tile, zoomx, zoomy);
}
- MEM_freeN(tiles);
+ if (need_free_tiles) {
+ MEM_freeN(tiles);
+ }
glPopMatrix();
}
@@ -769,7 +783,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
Image *ima;
ImBuf *ibuf;
float zoomx, zoomy;
- bool show_viewer, show_render, show_paint;
+ bool show_viewer, show_render, show_paint, show_stereo3d, show_multilayer;
void *lock;
/* XXX can we do this in refresh? */
@@ -799,6 +813,8 @@ void draw_image_main(const bContext *C, ARegion *ar)
show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0;
show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0;
show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false));
+ show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO));
+ show_multilayer = ima && BKE_image_is_multilayer(ima);
if (show_viewer) {
/* use locked draw for drawing viewer image buffer since the compositor
@@ -809,17 +825,41 @@ void draw_image_main(const bContext *C, ARegion *ar)
BLI_lock_thread(LOCK_DRAW_IMAGE);
}
+ if (show_stereo3d) {
+ if (show_multilayer)
+ /* update multiindex and pass for the current eye */
+ BKE_image_multilayer_index(ima->rr, &sima->iuser);
+ else
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* draw the image or grid */
- if (ibuf == NULL)
+ if (ibuf == NULL) {
ED_region_grid_draw(ar, zoomx, zoomy);
- else if (sima->flag & SI_DRAW_TILE)
- draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
- else if (ima && (ima->tpageflag & IMA_TILES))
- draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
- else
- draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+ }
+ else {
+
+ if (sima->flag & SI_DRAW_TILE)
+ draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
+ else if (ima && (ima->tpageflag & IMA_TILES))
+ draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
+ else
+ draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+
+ if (sima->flag & SI_DRAW_METADATA) {
+ int x, y;
+ rctf frame;
+
+ BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
+ UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
+
+ ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx, zoomy);
+ }
+ }
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
/* paint helpers */
if (show_paint)
@@ -842,19 +882,22 @@ void draw_image_main(const bContext *C, ARegion *ar)
}
#endif
- ED_space_image_release_buffer(sima, ibuf, lock);
-
if (show_viewer) {
BLI_unlock_thread(LOCK_DRAW_IMAGE);
}
/* render info */
if (ima && show_render)
- draw_render_info(sima->iuser.scene, ima, ar, zoomx, zoomy);
+ draw_render_info(C, sima->iuser.scene, ima, ar, zoomx, zoomy);
}
-static bool show_image_cache(Image *image, Mask *mask)
+bool ED_space_image_show_cache(SpaceImage *sima)
{
+ Image *image = ED_space_image(sima);
+ Mask *mask = NULL;
+ if (sima->mode == SI_MODE_MASK) {
+ mask = ED_space_image_get_mask(sima);
+ }
if (image == NULL && mask == NULL) {
return false;
}
@@ -872,12 +915,12 @@ void draw_image_cache(const bContext *C, ARegion *ar)
float x, cfra = CFRA, sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
Mask *mask = NULL;
- if (sima->mode == SI_MODE_MASK) {
- mask = ED_space_image_get_mask(sima);
+ if (!ED_space_image_show_cache(sima)) {
+ return;
}
- if (!show_image_cache(image, mask)) {
- return;
+ if (sima->mode == SI_MODE_MASK) {
+ mask = ED_space_image_get_mask(sima);
}
glEnable(GL_BLEND);
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 24b1c54dd9f..38c9604d14b 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -35,6 +35,7 @@
#include "BLI_rect.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -103,7 +104,7 @@ void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
}
}
-ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
+ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
{
ImBuf *ibuf;
@@ -113,7 +114,7 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
return BIF_render_spare_imbuf();
else
#endif
- ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, lock_r);
+ ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, r_lock);
if (ibuf) {
if (ibuf->rect || ibuf->rect_float)
@@ -123,7 +124,7 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
}
}
else
- *lock_r = NULL;
+ *r_lock = NULL;
return NULL;
}
@@ -290,6 +291,20 @@ void ED_image_point_pos__reverse(SpaceImage *sima, ARegion *ar, const float co[2
r_co[1] = (co[1] * height * zoomy) + (float)sy;
}
+void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* scope update can be expensive, don't update during paint modes */
+ if (sima->mode == SI_MODE_PAINT)
+ return;
+ if (ob && ((ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0))
+ return;
+
+ scopes_update(&sima->scopes, ibuf, use_view_settings ? &scene->view_settings : NULL, &scene->display_settings);
+}
+
bool ED_space_image_show_render(SpaceImage *sima)
{
return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE));
@@ -303,13 +318,6 @@ bool ED_space_image_show_paint(SpaceImage *sima)
return (sima->mode == SI_MODE_PAINT);
}
-bool ED_space_image_show_texpaint(SpaceImage *sima, Object *ob)
-{
- return (ob && ob->type == OB_MESH &&
- ob->mode == OB_MODE_TEXTURE_PAINT &&
- !(sima->flag & SI_NO_DRAW_TEXPAINT));
-}
-
bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
{
if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima)))
@@ -327,24 +335,6 @@ bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
return false;
}
-bool ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit)
-{
- if (ED_space_image_show_render(sima))
- return false;
-
- if (ED_space_image_show_paint(sima))
- if (obedit && obedit->type == OB_MESH) {
- struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool ret;
-
- ret = EDBM_mtexpoly_check(em);
-
- return ret && !(sima->flag & SI_NO_DRAW_TEXPAINT);
- }
-
- return false;
-}
-
/* matches clip function */
bool ED_space_image_check_show_maskedit(Scene *scene, SpaceImage *sima)
{
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 74a0a18b0c8..6eaad302180 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -38,11 +38,7 @@ struct ARegion;
struct ARegionType;
struct ScrArea;
struct SpaceImage;
-struct Object;
-struct Image;
-struct ImBuf;
struct wmOperatorType;
-struct Scene;
struct bNodeTree;
/* space_image.c */
@@ -92,6 +88,8 @@ void IMAGE_OT_curves_point_set(struct wmOperatorType *ot);
void IMAGE_OT_change_frame(struct wmOperatorType *ot);
void IMAGE_OT_read_renderlayers(struct wmOperatorType *ot);
+void IMAGE_OT_render_border(struct wmOperatorType *ot);
+void IMAGE_OT_clear_render_border(struct wmOperatorType *ot);
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index cd95e67f070..3c5aff4d698 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -30,16 +30,23 @@
#include <stddef.h>
#include <string.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
+#ifndef WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utf8.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_object_types.h"
#include "DNA_node_types.h"
@@ -49,22 +56,27 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "GPU_draw.h"
+#include "GPU_buffers.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_moviecache.h"
+#include "intern/openexr/openexr_multi.h"
#include "RE_pipeline.h"
@@ -73,6 +85,7 @@
#include "RNA_enum_types.h"
#include "ED_image.h"
+#include "ED_mask.h"
#include "ED_paint.h"
#include "ED_render.h"
#include "ED_screen.h"
@@ -89,6 +102,8 @@
#include "PIL_time.h"
+#include "RE_engine.h"
+
#include "image_intern.h"
/******************** view navigation utilities *********************/
@@ -144,10 +159,29 @@ static int image_poll(bContext *C)
static int space_image_buffer_exists_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
- if (sima && sima->spacetype == SPACE_IMAGE)
- if (ED_space_image_has_buffer(sima))
- return 1;
- return 0;
+ if (sima && ED_space_image_has_buffer(sima)) {
+ return true;
+ }
+ return false;
+}
+
+static int image_not_packed_poll(bContext *C)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ /* Do not run 'replace' on packed images, it does not give user expected results at all. */
+ if (sima && sima->image && BLI_listbase_is_empty(&sima->image->packedfiles)) {
+ return true;
+ }
+ return false;
+}
+
+static bool imbuf_format_writeable(const ImBuf *ibuf)
+{
+ ImageFormatData im_format;
+ ImbFormatOptions options_dummy;
+ BKE_imbuf_to_image_format(&im_format, ibuf);
+ return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
}
static int space_image_file_exists_poll(bContext *C)
@@ -171,6 +205,9 @@ static int space_image_file_exists_poll(bContext *C)
else if (!BLI_file_is_writable(name)) {
CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
}
+ else if (!imbuf_format_writeable(ibuf)) {
+ CTX_wm_operator_poll_msg_set(C, "image format is read-only");
+ }
else {
ret = true;
}
@@ -179,26 +216,29 @@ static int space_image_file_exists_poll(bContext *C)
return ret;
}
- return 0;
+ return false;
}
+#if 0 /* UNUSED */
static int space_image_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
- if (sima && sima->spacetype == SPACE_IMAGE && sima->image)
- return 1;
- return 0;
+ if (sima && sima->image) {
+ return true;
+ }
+ return false;
}
+#endif
int space_image_main_area_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
- // XXX ARegion *ar = CTX_wm_region(C);
+ /* XXX ARegion *ar = CTX_wm_region(C); */
- if (sima)
- return 1; // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW);
-
- return 0;
+ if (sima) {
+ return true; /* XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW); */
+ }
+ return false;
}
/* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
@@ -364,7 +404,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
ot->poll = space_image_main_area_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -580,7 +620,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
ot->poll = space_image_main_area_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
@@ -706,6 +746,9 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
ot->exec = image_view_all_exec;
ot->poll = space_image_main_area_poll;
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -737,8 +780,15 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
height = height * aspy;
/* get bounds */
- if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
- return OPERATOR_CANCELLED;
+ if (ED_space_image_show_uvedit(sima, obedit)) {
+ if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
+ return OPERATOR_CANCELLED;
+ }
+ else if (ED_space_image_check_show_maskedit(scene, sima)) {
+ if (!ED_mask_selected_minmax(C, min, max)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
/* adjust offset and zoom */
sima->xof = (int)(((min[0] + max[0]) * 0.5f - 0.5f) * width);
@@ -758,7 +808,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
static int image_view_selected_poll(bContext *C)
{
- return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
+ return (space_image_main_area_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
}
void IMAGE_OT_view_selected(wmOperatorType *ot)
@@ -931,6 +981,7 @@ static void image_filesel(bContext *C, wmOperator *op, const char *path)
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
ImageUser *iuser;
+ ImageFormatData im_format;
} ImageOpenData;
typedef struct ImageFrame {
@@ -941,10 +992,9 @@ typedef struct ImageFrame {
static void image_open_init(bContext *C, wmOperator *op)
{
ImageOpenData *iod;
-
op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
- uiIDContextProperty(C, &iod->pprop.ptr, &iod->pprop.prop);
+ UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
}
static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
@@ -991,6 +1041,7 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p
}
else {
/* different file base name found, is ignored */
+ MEM_freeN(filename);
MEM_freeN(frame);
break;
}
@@ -1021,7 +1072,7 @@ static int image_sequence_get_len(ListBase *frames, int *ofs)
{
ImageFrame *frame;
- BLI_sortlist(frames, image_cmp_frame);
+ BLI_listbase_sort(frames, image_cmp_frame);
frame = frames->first;
if (frame) {
@@ -1043,31 +1094,44 @@ static int image_open_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
- ImageOpenData *iod;
+ ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
char path[FILE_MAX];
int frame_seq_len = 0;
int frame_ofs = 1;
+ bool exists = false;
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
RNA_string_get(op->ptr, "filepath", path);
- if (!IMB_isanim(path) && RNA_struct_property_is_set(op->ptr, "files") &&
- RNA_struct_property_is_set(op->ptr, "directory"))
+ if (RNA_struct_property_is_set(op->ptr, "directory") &&
+ RNA_struct_property_is_set(op->ptr, "files"))
{
- ListBase frames;
-
- BLI_listbase_clear(&frames);
- image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
- frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
- BLI_freelistN(&frames);
+ /* only to pass to imbuf */
+ char path_full[FILE_MAX];
+ BLI_strncpy(path_full, path, sizeof(path_full));
+ BLI_path_abs(path_full, G.main->name);
+
+ if (!IMB_isanim(path_full)) {
+ bool was_relative = BLI_path_is_rel(path);
+ ListBase frames;
+
+ BLI_listbase_clear(&frames);
+ image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
+ frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
+ BLI_freelistN(&frames);
+
+ if (was_relative) {
+ BLI_path_rel(path, G.main->name);
+ }
+ }
}
errno = 0;
- ima = BKE_image_load_exists(path);
+ ima = BKE_image_load_exists_ex(path, &exists);
if (!ima) {
if (op->customdata) MEM_freeN(op->customdata);
@@ -1079,10 +1143,26 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (!op->customdata)
image_open_init(C, op);
+ /* handle multiview images */
+ if (RNA_boolean_get(op->ptr, "use_multiview")) {
+ ImageFormatData *imf = &iod->im_format;
+
+ ima->flag |= IMA_USE_VIEWS;
+ ima->views_format = imf->views_format;
+ *ima->stereo3d_format = imf->stereo3d_format;
+ }
+ else {
+ ima->flag &= ~IMA_USE_VIEWS;
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ BKE_image_free_views(ima);
+ }
+
/* only image path after save, never ibuf */
if (is_relative_path) {
- const char *relbase = ID_BLEND_PATH(bmain, &ima->id);
- BLI_path_rel(ima->name, relbase);
+ if (!exists) {
+ BLI_path_rel(ima->name, bmain->name);
+ }
}
/* hook into UI */
@@ -1121,10 +1201,12 @@ static int image_open_exec(bContext *C, wmOperator *op)
iuser->framenr = 1;
iuser->offset = frame_ofs - 1;
iuser->fie_ima = 2;
+ iuser->scene = scene;
+ BKE_image_init_imageuser(ima, iuser);
}
/* XXX unpackImage frees image buffers */
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
BKE_image_signal(ima, iuser, IMA_SIGNAL_RELOAD);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -1139,7 +1221,8 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
const char *path = U.textudir;
Image *ima = NULL;
-
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
if (sima) {
ima = sima->image;
}
@@ -1155,7 +1238,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
PropertyRNA *prop;
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
PointerRNA oldptr;
@@ -1178,11 +1261,44 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
image_filesel(C, op, path);
return OPERATOR_RUNNING_MODAL;
}
+static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename")
+ );
+}
+
+static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ ImageOpenData *iod = op->customdata;
+ ImageFormatData *imf = &iod->im_format;
+ PointerRNA imf_ptr, ptr;
+
+ /* main draw call */
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, '\0');
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+
+ /* multiview template */
+ if (RNA_boolean_get(op->ptr, "show_multiview"))
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
+}
+
/* called by other space types too */
void IMAGE_OT_open(wmOperatorType *ot)
{
@@ -1195,13 +1311,14 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->exec = image_open_exec;
ot->invoke = image_open_invoke;
ot->cancel = image_open_cancel;
+ ot->ui = image_open_draw;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************** Match movie length operator ********************/
@@ -1226,10 +1343,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
}
- if (!ima || !iuser || !ima->anim)
+ if (!ima || !iuser || !BKE_image_has_anim(ima))
return OPERATOR_CANCELLED;
- iuser->frames = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
+ iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
return OPERATOR_FINISHED;
@@ -1276,9 +1393,9 @@ static int image_replace_exec(bContext *C, wmOperator *op)
sima->image->source = IMA_SRC_FILE;
/* XXX unpackImage frees image buffers */
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- BKE_icon_changed(BKE_icon_getid(&sima->image->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
@@ -1313,14 +1430,14 @@ void IMAGE_OT_replace(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_replace_exec;
ot->invoke = image_replace_invoke;
- ot->poll = space_image_poll;
+ ot->poll = image_not_packed_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************** save image as operator ********************/
@@ -1377,12 +1494,11 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
else {
if (ima->source == IMA_SRC_GENERATED) {
simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
+ simopts->im_format.compress = ibuf->foptions.quality;
}
else {
BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
- simopts->im_format.quality = ibuf->ftype & 0xff;
}
- simopts->im_format.quality = ibuf->ftype & 0xff;
}
simopts->im_format.planes = ibuf->planes;
@@ -1426,6 +1542,10 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
+ /* use the multiview image settings as the default */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
@@ -1461,30 +1581,105 @@ static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
RNA_string_set(op->ptr, "filepath", simopts->filepath);
}
+static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy, const char *relbase, int relative, int do_newpath, const char *filepath)
+{
+ if (ok) {
+ if (!save_copy) {
+ ColorManagedColorspaceSettings old_colorspace_settings;
+
+ if (do_newpath) {
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
+ BLI_strncpy(ima->name, filepath, sizeof(ima->name));
+ }
+
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ /* change type? */
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ ima->type = IMA_TYPE_IMAGE;
+
+ /* workaround to ensure the render result buffer is no longer used
+ * by this image, otherwise can crash when a new render result is
+ * created. */
+ if (ibuf->rect && !(ibuf->mall & IB_rect))
+ imb_freerectImBuf(ibuf);
+ if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
+ imb_freerectfloatImBuf(ibuf);
+ if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
+ IMB_freezbufImBuf(ibuf);
+ if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+
+ /* only image path, never ibuf */
+ if (relative) {
+ BLI_path_rel(ima->name, relbase); /* only after saving */
+ }
+
+ BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings,
+ &ima->colorspace_settings);
+ IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
+ &ima->colorspace_settings))
+ {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ }
+ }
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", filepath);
+ }
+}
+
+static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* This guys might be modified by image buffer write functions,
+ * need to copy them back from color managed image buffer to an
+ * original one, so file type of image is being properly updated.
+ */
+ ibuf->ftype = colormanaged_ibuf->ftype;
+ ibuf->foptions = colormanaged_ibuf->foptions;
+ ibuf->planes = colormanaged_ibuf->planes;
+
+ IMB_freeImBuf(colormanaged_ibuf);
+ }
+}
+
/**
* \return success.
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
+ * \note for multiview the first ``ibuf`` is important to get the settings.
*/
static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
{
Image *ima = ED_space_image(sima);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ Scene *scene;
+ RenderResult *rr = NULL;
bool ok = false;
+ WM_cursor_wait(1);
+
if (ibuf) {
- ImBuf *colormanaged_ibuf;
+ ImBuf *colormanaged_ibuf = NULL;
const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
ImageFormatData *imf = &simopts->im_format;
+ const bool is_multilayer = imf->imtype == R_IMF_IMTYPE_MULTILAYER;
+ bool is_mono;
+
/* old global to ensure a 2nd save goes to same dir */
BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
- WM_cursor_wait(1);
-
if (ima->type == IMA_TYPE_R_RESULT) {
/* enforce user setting for RGB or RGBA, but skip BW */
if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
@@ -1505,83 +1700,194 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
}
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ /* we need renderresult for exr and rendered multiview */
+ scene = CTX_data_scene(C);
+ rr = BKE_image_acquire_renderresult(scene, ima);
+ is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
- if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- Scene *scene = CTX_data_scene(C);
- RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
- if (rr) {
- ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, simopts->im_format.exr_codec);
- }
- else {
+ /* error handling */
+ if (!rr) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
+ goto cleanup;
}
- BKE_image_release_renderresult(scene, ima);
}
else {
- ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, &simopts->im_format, save_copy);
- }
-
- if (ok) {
- if (!save_copy) {
- if (do_newpath) {
- BLI_strncpy(ibuf->name, simopts->filepath, sizeof(ibuf->name));
- BLI_strncpy(ima->name, simopts->filepath, sizeof(ima->name));
+ if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if ((ima->flag & IMA_IS_STEREO) == 0) {
+ BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
+ STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
+ goto cleanup;
}
- ibuf->userflags &= ~IB_BITMAPDIRTY;
-
- /* change type? */
- if (ima->type == IMA_TYPE_R_RESULT) {
- ima->type = IMA_TYPE_IMAGE;
-
- /* workaround to ensure the render result buffer is no longer used
- * by this image, otherwise can crash when a new render result is
- * created. */
- if (ibuf->rect && !(ibuf->mall & IB_rect))
- imb_freerectImBuf(ibuf);
- if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
- imb_freerectfloatImBuf(ibuf);
- if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
- IMB_freezbufImBuf(ibuf);
- if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
- IMB_freezbuffloatImBuf(ibuf);
- }
- if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
- ima->source = IMA_SRC_FILE;
- ima->type = IMA_TYPE_IMAGE;
+ /* it shouldn't ever happen*/
+ if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
+ (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL))
+ {
+ BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
+ STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
+ goto cleanup;
}
+ }
+ BKE_imbuf_stamp_info(rr, ibuf);
+ }
- /* only image path, never ibuf */
- if (relative) {
- BLI_path_rel(ima->name, relbase); /* only after saving */
+ /* fancy multiview OpenEXR */
+ if ((imf->imtype == R_IMF_IMTYPE_MULTILAYER) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, true, NULL);
+ save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ else if ((imf->imtype == R_IMF_IMTYPE_OPENEXR) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
+ /* treat special Openexr case separetely (this is the singlelayer multiview OpenEXR */
+ BKE_imbuf_write_prepare(ibuf, imf);
+ ok = BKE_image_save_openexr_multiview(ima, ibuf, simopts->filepath, (IB_rect | IB_zbuf | IB_zbuffloat | IB_multiview));
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ /* regular mono pipeline */
+ else if (is_mono) {
+ if (is_multilayer) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
+ }
+ else {
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ }
+ save_image_post(op, ibuf, ima, ok, (is_multilayer ? true : save_copy), relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ /* individual multiview images */
+ else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ size_t i;
+ unsigned char planes = ibuf->planes;
+ const size_t totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
+
+ if (!is_multilayer) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+
+ for (i = 0; i < totviews; i++) {
+ char filepath[FILE_MAX];
+ bool ok_view = false;
+ const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name :
+ ((ImageView *) BLI_findlink(&ima->views, i))->name;
+
+ if (is_multilayer) {
+ BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
+ ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, false, view);
+ save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
+ }
+ else {
+ /* copy iuser to get the correct ibuf for this view */
+ ImageUser iuser = sima->iuser;
+ iuser.view = i;
+ iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr)
+ BKE_image_multilayer_index(rr, &iuser);
+ else
+ BKE_image_multiview_index(ima, &iuser);
+
+ ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
+ ibuf->planes = planes;
+
+ BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
+
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &simopts->im_format, save_copy);
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
+ BKE_image_release_ibuf(sima->image, ibuf, lock);
}
+ ok &= ok_view;
+ }
- IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (is_multilayer) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
}
}
- else {
- BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", simopts->filepath);
- }
+ /* stereo (multiview) images */
+ else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
+ save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ else {
+ ImBuf *ibuf_stereo[2] = {NULL};
+ unsigned char planes = ibuf->planes;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ int i;
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
+ /* we need to get the specific per-view buffers */
+ ED_space_image_release_buffer(sima, ibuf, lock);
+
+ for (i = 0; i < 2; i ++) {
+ ImageUser iuser = sima->iuser;
+ iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr) {
+ int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ iuser.view = id;
+ BKE_image_multilayer_index(rr, &iuser);
+ }
+ else {
+ iuser.view = i;
+ BKE_image_multiview_index(ima, &iuser);
+ }
+
+ ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
+
+ if (ibuf == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
+ goto cleanup;
+ }
+
+ ibuf->planes = planes;
+
+ /* color manage the ImBuf leaving it ready for saving */
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true,
+ &imf->view_settings, &imf->display_settings, imf);
- WM_cursor_wait(0);
+ BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
+ IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
- if (colormanaged_ibuf != ibuf) {
- /* This guys might be modified by image buffer write functions,
- * need to copy them back from color managed image buffer to an
- * original one, so file type of image is being properly updated.
- */
- ibuf->ftype = colormanaged_ibuf->ftype;
- ibuf->planes = colormanaged_ibuf->planes;
+ /* duplicate buffer to prevent locker issue when using render result */
+ ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
- IMB_freeImBuf(colormanaged_ibuf);
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ BKE_image_release_ibuf(sima->image, ibuf, lock);
+ }
+
+ ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
+
+ /* save via traditional path */
+ ok = BKE_imbuf_write_as(ibuf, simopts->filepath, imf, save_copy);
+
+ IMB_freeImBuf(ibuf);
+
+ for (i = 0; i < 2; i ++) {
+ IMB_freeImBuf(ibuf_stereo[i]);
+ }
+ }
}
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
+
+ }
+ else {
+cleanup:
+ ED_space_image_release_buffer(sima, ibuf, lock);
}
- ED_space_image_release_buffer(sima, ibuf, lock);
+ if (rr) {
+ BKE_image_release_renderresult(scene, ima);
+ }
+
+ WM_cursor_wait(0);
return ok;
}
@@ -1629,6 +1935,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
Image *ima = ED_space_image(sima);
Scene *scene = CTX_data_scene(C);
SaveImageOptions simopts;
+ PropertyRNA *prop;
const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
if (RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -1650,6 +1957,12 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
+ /* show multiview save options only if image has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+ prop = RNA_struct_find_property(op->ptr, "use_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+
image_filesel(C, op, simopts.filepath);
return OPERATOR_RUNNING_MODAL;
@@ -1676,15 +1989,20 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
ImageFormatData *imf = op->customdata;
- PointerRNA ptr;
+ PointerRNA imf_ptr, ptr;
+ const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
/* image template */
- RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr);
- uiTemplateImageSettings(layout, &ptr, false);
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+ uiTemplateImageSettings(layout, &imf_ptr, false);
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0');
+
+ /* multiview template */
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
static int image_save_as_poll(bContext *C)
@@ -1707,8 +2025,6 @@ static int image_save_as_poll(bContext *C)
void IMAGE_OT_save_as(wmOperatorType *ot)
{
-// PropertyRNA *prop;
-
/* identifiers */
ot->name = "Save As Image";
ot->idname = "IMAGE_OT_save_as";
@@ -1729,8 +2045,8 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image");
RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************** save image operator ********************/
@@ -1877,7 +2193,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* XXX unpackImage frees image buffers */
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
// XXX other users?
BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
@@ -1905,6 +2221,12 @@ void IMAGE_OT_reload(wmOperatorType *ot)
/********************** new image operator *********************/
#define IMA_DEF_NAME N_("Untitled")
+enum {
+ GEN_CONTEXT_NONE = 0,
+ GEN_CONTEXT_PAINT_CANVAS = 1,
+ GEN_CONTEXT_PAINT_STENCIL = 2
+};
+
static int image_new_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima;
@@ -1918,6 +2240,8 @@ static int image_new_exec(bContext *C, wmOperator *op)
char *name = _name;
float color[4];
int width, height, floatbuf, gen_type, alpha;
+ int gen_context;
+ int stereo3d;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -1937,17 +2261,19 @@ static int image_new_exec(bContext *C, wmOperator *op)
gen_type = RNA_enum_get(op->ptr, "generated_type");
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
+ gen_context = RNA_enum_get(op->ptr, "gen_context");
+ stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
if (!alpha)
color[3] = 1.0f;
- ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color);
+ ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
if (!ima)
return OPERATOR_CANCELLED;
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
@@ -1961,6 +2287,40 @@ static int image_new_exec(bContext *C, wmOperator *op)
else if (sima) {
ED_space_image_set(sima, scene, obedit, ima);
}
+ else if (gen_context == GEN_CONTEXT_PAINT_CANVAS) {
+ bScreen *sc;
+ Object *ob = CTX_data_active_object(C);
+
+ GPU_drawobject_free(ob->derivedFinal);
+ if (scene->toolsettings->imapaint.canvas)
+ id_us_min(&scene->toolsettings->imapaint.canvas->id);
+ scene->toolsettings->imapaint.canvas = ima;
+
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin)
+ ED_space_image_set(sima, scene, scene->obedit, ima);
+ }
+ }
+ }
+ }
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+ else if (gen_context == GEN_CONTEXT_PAINT_STENCIL) {
+ Object *ob = CTX_data_active_object(C);
+ if (scene->toolsettings->imapaint.stencil)
+ id_us_min(&scene->toolsettings->imapaint.stencil->id);
+ scene->toolsettings->imapaint.stencil = ima;
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
else {
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
if (tex && tex->type == TEX_IMAGE) {
@@ -1979,7 +2339,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
}
/* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */
-/* XXX Note: the WM_operator_props_dialog_popup() doesn't work for uiIDContextProperty(), image is not being that way */
+/* XXX Note: the WM_operator_props_dialog_popup() doesn't work for UI_context_active_but_prop_get_templateID(), image is not being that way */
static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
/* Better for user feedback. */
@@ -1987,10 +2347,64 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
+static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *split, *col[2];
+ uiLayout *layout = op->layout;
+ PointerRNA ptr;
+#if 0
+ Scene *scene = CTX_data_scene(C);
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+#endif
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ /* copy of WM_operator_props_dialog_popup() layout */
+
+ split = uiLayoutSplit(layout, 0.5f, false);
+ col[0] = uiLayoutColumn(split, false);
+ col[1] = uiLayoutColumn(split, false);
+
+ uiItemL(col[0], IFACE_("Name"), ICON_NONE);
+ uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Width"), ICON_NONE);
+ uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Height"), ICON_NONE);
+ uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Color"), ICON_NONE);
+ uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
+ uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
+
+#if 0
+ if (is_multiview) {
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
+ }
+#endif
+}
+
void IMAGE_OT_new(wmOperatorType *ot)
{
PropertyRNA *prop;
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ static EnumPropertyItem gen_context_items[] = {
+ {GEN_CONTEXT_NONE, "NONE", 0, "None", ""},
+ {GEN_CONTEXT_PAINT_CANVAS, "PAINT_CANVAS", 0, "Paint Canvas", ""},
+ {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
/* identifiers */
ot->name = "New Image";
@@ -2000,6 +2414,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_new_exec;
ot->invoke = image_new_invoke;
+ ot->ui = image_new_draw;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -2017,9 +2432,10 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
- prop = RNA_def_boolean(ot->srna, "texstencil", 0, "Stencil", "Set Image as stencil");
+ prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
RNA_def_property_flag(prop, PROP_HIDDEN);
-
+ prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
#undef IMA_DEF_NAME
@@ -2047,7 +2463,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
const bool b = RNA_boolean_get(op->ptr, "invert_b");
const bool a = RNA_boolean_get(op->ptr, "invert_a");
- int i;
+ size_t i;
if (ibuf == NULL) /* TODO: this should actually never happen, but does for render-results -> cleanup */
return OPERATOR_CANCELLED;
@@ -2058,13 +2474,13 @@ static int image_invert_exec(bContext *C, wmOperator *op)
/* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
* but better do this right in case someone copies this for a tool that uses partial redraw better */
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
float *fp = (float *) ibuf->rect_float;
- for (i = ibuf->x * ibuf->y; i > 0; i--, fp += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
if (r) fp[0] = 1.0f - fp[0];
if (g) fp[1] = 1.0f - fp[1];
if (b) fp[2] = 1.0f - fp[2];
@@ -2078,7 +2494,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
else if (ibuf->rect) {
char *cp = (char *) ibuf->rect;
- for (i = ibuf->x * ibuf->y; i > 0; i--, cp += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
if (r) cp[0] = 255 - cp[0];
if (g) cp[1] = 255 - cp[1];
if (b) cp[2] = 255 - cp[2];
@@ -2144,7 +2560,7 @@ static bool image_pack_test(bContext *C, wmOperator *op)
if (!ima)
return 0;
- if (!as_png && ima->packedfile)
+ if (!as_png && BKE_image_has_packedfile(ima))
return 0;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2173,7 +2589,7 @@ static int image_pack_exec(bContext *C, wmOperator *op)
if (as_png)
BKE_image_memorypack(ima);
else
- ima->packedfile = newPackedFile(op->reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
+ BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -2196,15 +2612,15 @@ static int image_pack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
- pup = uiPupMenuBegin(C, IFACE_("OK"), ICON_QUESTION);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("OK"), ICON_QUESTION);
+ layout = UI_popup_menu_layout(pup);
uiItemBooleanO(layout, IFACE_("Can't pack edited image from disk, pack as internal PNG?"), ICON_NONE,
op->idname, "as_png", 1);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
BKE_image_release_ibuf(ima, ibuf, NULL);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -2245,7 +2661,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
if (!ima) ima = CTX_data_edit_image(C);
}
- if (!ima || !ima->packedfile)
+ if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2257,7 +2673,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
/* XXX unpackImage frees image buffers */
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
unpackImage(op->reports, ima, method);
@@ -2273,7 +2689,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (RNA_struct_property_is_set(op->ptr, "id"))
return image_unpack_exec(C, op);
- if (!ima || !ima->packedfile)
+ if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2284,7 +2700,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (G.fileflags & G_AUTOPACK)
BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
- unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", ima->packedfile);
+ unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : NULL);
return OPERATOR_FINISHED;
}
@@ -2528,8 +2944,9 @@ static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event
ImageSampleInfo *info;
if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] <= 16)
+ if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
return OPERATOR_PASS_THROUGH;
+ }
}
if (!ED_space_image_has_buffer(sima))
@@ -2552,8 +2969,11 @@ static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: // XXX hardcoded
- image_sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ image_sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
image_sample_apply(C, op, event);
break;
@@ -2925,7 +3345,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -2963,8 +3383,10 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
ARegion *ar = CTX_wm_region(C);
if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] > 16)
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (event->mval[1] > 16 || !ED_space_image_show_cache(sima)) {
return OPERATOR_PASS_THROUGH;
+ }
}
RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
@@ -3049,3 +3471,101 @@ void IMAGE_OT_read_renderlayers(wmOperatorType *ot)
/* flags */
ot->flag = 0;
}
+
+/* ********************* Render border operator ****************** */
+
+static int render_border_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ Render *re = RE_GetRender(scene->id.name);
+ RenderData *rd;
+ rctf border;
+
+ if (re == NULL) {
+ /* Shouldn't happen, but better be safe close to the release. */
+ return OPERATOR_CANCELLED;
+ }
+
+ rd = RE_engine_get_render_data(re);
+ if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
+ BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get rectangle from operator */
+ WM_operator_properties_border_to_rctf(op, &border);
+ UI_view2d_region_to_view_rctf(&ar->v2d, &border, &border);
+
+ /* actually set border */
+ CLAMP(border.xmin, 0.0f, 1.0f);
+ CLAMP(border.ymin, 0.0f, 1.0f);
+ CLAMP(border.xmax, 0.0f, 1.0f);
+ CLAMP(border.ymax, 0.0f, 1.0f);
+ scene->r.border = border;
+
+ /* drawing a border surrounding the entire camera view switches off border rendering
+ * or the border covers no pixels */
+ if ((border.xmin <= 0.0f && border.xmax >= 1.0f &&
+ border.ymin <= 0.0f && border.ymax >= 1.0f) ||
+ (border.xmin == border.xmax || border.ymin == border.ymax))
+ {
+ scene->r.mode &= ~R_BORDER;
+ }
+ else {
+ scene->r.mode |= R_BORDER;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ return OPERATOR_FINISHED;
+
+}
+
+void IMAGE_OT_render_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Render Border";
+ ot->description = "Set the boundaries of the border render and enable border render";
+ ot->idname = "IMAGE_OT_render_border";
+
+ /* api callbacks */
+ ot->invoke = WM_border_select_invoke;
+ ot->exec = render_border_exec;
+ ot->modal = WM_border_select_modal;
+ ot->cancel = WM_border_select_cancel;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* rna */
+ WM_operator_properties_border(ot);
+}
+
+/* ********************* Clear render border operator ****************** */
+
+static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ scene->r.mode &= ~R_BORDER;
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
+ return OPERATOR_FINISHED;
+
+}
+
+void IMAGE_OT_clear_render_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Render Border";
+ ot->description = "Clear the boundaries of the border render and disable border render";
+ ot->idname = "IMAGE_OT_clear_render_border";
+
+ /* api callbacks */
+ ot->exec = clear_render_border_exec;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index ab616bf592f..97e3390f142 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -33,6 +33,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_image_types.h"
#include "MEM_guardedalloc.h"
@@ -155,7 +156,8 @@ static SpaceLink *image_new(const bContext *UNUSED(C))
simage->iuser.ok = true;
simage->iuser.fie_ima = 2;
simage->iuser.frames = 100;
-
+ simage->iuser.flag = IMA_SHOW_STEREO;
+
scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
@@ -257,6 +259,8 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_change_frame);
WM_operatortype_append(IMAGE_OT_read_renderlayers);
+ WM_operatortype_append(IMAGE_OT_render_border);
+ WM_operatortype_append(IMAGE_OT_clear_render_border);
}
static void image_keymap(struct wmKeyConfig *keyconf)
@@ -325,9 +329,9 @@ static void image_keymap(struct wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "toggle", true);
/* fast switch to render slots */
- for (i = 0; i < MAX2(IMA_MAX_RENDER_SLOT, 9); i++) {
+ for (i = 0; i < MIN2(IMA_MAX_RENDER_SLOT, 9); i++) {
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_int", ONEKEY + i, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.image.render_slot");
+ RNA_string_set(kmi->ptr, "data_path", "space_data.image.render_slots.active_index");
RNA_int_set(kmi->ptr, "value", i);
}
@@ -343,13 +347,17 @@ static void image_keymap(struct wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
RNA_string_set(kmi->ptr, "value", "CURSOR");
+
+ /* render border */
+ WM_keymap_add_item(keymap, "IMAGE_OT_render_border", BKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "IMAGE_OT_clear_render_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
}
/* dropboxes */
static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
- if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
return 1;
return 0;
}
@@ -674,7 +682,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
float col[3];
-
+
/* XXX not supported yet, disabling for now */
scene->r.scemode &= ~R_COMP_CROP;
@@ -686,7 +694,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
/* put scene context variable in iuser */
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
/* for render result, try to use the currently rendering scene */
- Scene *render_scene = ED_render_job_get_scene(C);
+ Scene *render_scene = ED_render_job_get_current_scene(C);
if (render_scene)
sima->iuser.scene = render_scene;
else
@@ -706,7 +714,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
- draw_uvedit_main(sima, ar, scene, obedit, obact);
+ ED_uvedit_draw_main(sima, ar, scene, obedit, obact);
/* check for mask (delay draw) */
if (ED_space_image_show_uvedit(sima, obedit)) {
@@ -766,12 +774,12 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
NULL, C);
UI_view2d_view_ortho(v2d);
- draw_image_cursor(ar, sima->cursor);
+ ED_image_draw_cursor(ar, sima->cursor);
UI_view2d_view_restore(C);
}
else if (curve) {
UI_view2d_view_ortho(v2d);
- draw_image_cursor(ar, sima->cursor);
+ ED_image_draw_cursor(ar, sima->cursor);
UI_view2d_view_restore(C);
}
@@ -785,18 +793,28 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
#endif
}
-static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->action == NA_EDITED)
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
+ ED_region_tag_redraw(ar);
+ else if (wmn->data & ND_GPENCIL_EDITMODE)
ED_region_tag_redraw(ar);
break;
case NC_IMAGE:
if (wmn->action == NA_PAINTING)
ED_region_tag_redraw(ar);
break;
+ case NC_MATERIAL:
+ if (wmn->data == ND_SHADING_LINKS) {
+ SpaceImage *sima = sa->spacedata.first;
+
+ if (sima->iuser.scene && (sima->iuser.scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE))
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
@@ -816,7 +834,7 @@ static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void image_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -845,6 +863,10 @@ static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
case NC_NODE:
ED_region_tag_redraw(ar);
break;
+ case NC_GPENCIL:
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
+ ED_region_tag_redraw(ar);
+ break;
}
}
@@ -878,14 +900,14 @@ static void image_tools_area_draw(const bContext *C, ARegion *ar)
BKE_histogram_update_sample_line(&sima->sample_line_hist, ibuf, &scene->view_settings, &scene->display_settings);
}
if (sima->image->flag & IMA_VIEW_AS_RENDER)
- scopes_update(&sima->scopes, ibuf, &scene->view_settings, &scene->display_settings);
+ ED_space_image_scopes_update(C, sima, ibuf, true);
else
- scopes_update(&sima->scopes, ibuf, NULL, &scene->display_settings);
+ ED_space_image_scopes_update(C, sima, ibuf, false);
}
}
ED_space_image_release_buffer(sima, ibuf, lock);
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -893,11 +915,12 @@ static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->data == ND_DATA)
+ if (wmn->data == ND_DATA || ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
case NC_BRUSH:
- if (wmn->action == NA_EDITED)
+ /* NA_SELECTED is used on brush changes */
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index 94b40a9f40a..96fe9322b97 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -24,12 +24,15 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../blentranslation
../../imbuf
../../bmesh
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -52,4 +55,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_info "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_info/SConscript b/source/blender/editors/space_info/SConscript
index 2a1419984c6..e17c39f7e38 100644
--- a/source/blender/editors/space_info/SConscript
+++ b/source/blender/editors/space_info/SConscript
@@ -31,13 +31,16 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../blenloader',
+ '../../blentranslation',
'../../bmesh',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -46,6 +49,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 86af89bd6a9..cd424f45842 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -33,7 +33,6 @@
#include <sys/stat.h>
#include <limits.h>
-#include "BLF_api.h"
#include "BLI_utildefines.h"
@@ -45,15 +44,13 @@
#include "BIF_gl.h"
-#include "ED_datafiles.h"
-#include "ED_types.h"
#include "UI_resources.h"
#include "UI_interface.h"
#include "UI_view2d.h"
#include "info_intern.h"
-#include "../space_info/textview.h"
+#include "textview.h"
/* complicates things a bit, so leaving in old simple code */
#define USE_INFO_NEWLINE
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 25fa31407ff..2bcd56a3ced 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_bpath.h"
#include "BKE_context.h"
@@ -134,7 +134,7 @@ static int autopack_toggle_exec(bContext *C, wmOperator *op)
G.fileflags &= ~G_AUTOPACK;
}
else {
- packAll(bmain, op->reports);
+ packAll(bmain, op->reports, true);
G.fileflags |= G_AUTOPACK;
}
@@ -161,7 +161,7 @@ static int pack_all_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- packAll(bmain, op->reports);
+ packAll(bmain, op->reports, true);
G.fileflags |= G_AUTOPACK;
return OPERATOR_FINISHED;
@@ -253,15 +253,15 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
else
BLI_snprintf(title, sizeof(title), IFACE_("Unpack %d Files"), count);
- pup = uiPupMenuBegin(C, title, ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, title, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
uiItemsEnumO(layout, "FILE_OT_unpack_all", "method");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
void FILE_OT_unpack_all(wmOperatorType *ot)
@@ -322,15 +322,15 @@ static int unpack_item_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, IFACE_("Unpack"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Unpack"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
uiItemsFullEnumO(layout, op->type->idname, "method", op->ptr->data, WM_OP_EXEC_REGION_WIN, 0);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
void FILE_OT_unpack_item(wmOperatorType *ot)
@@ -485,7 +485,7 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "find_all", false, "Find All", "Find all files in the search path (not just missing)");
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/********************* report box operator *********************/
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index a0dfb285a1c..dafb71b4480 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -41,7 +41,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_anim.h"
#include "BKE_blender.h"
@@ -56,6 +56,8 @@
#include "ED_info.h"
#include "ED_armature.h"
+#include "GPU_extensions.h"
+
#define MAX_INFO_LEN 512
#define MAX_INFO_NUM_LEN 16
@@ -381,6 +383,7 @@ static void stats_string(Scene *scene)
Object *ob = (scene->basact) ? scene->basact->object : NULL;
uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
+ char gpumemstr[MAX_INFO_MEM_LEN] = "";
char *s;
size_t ofs = 0;
@@ -416,11 +419,22 @@ static void stats_string(Scene *scene)
/* get memory statistics */
- s = memstr;
- ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"),
+ ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem:%.2fM"),
(double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
if (mmap_in_use)
- BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+ BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+
+ if (GPU_mem_stats_supported()) {
+ int gpu_free_mem, gpu_tot_memory;
+
+ GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
+
+ ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem:%.2fM"), (double)((gpu_free_mem)) / 1024.0);
+
+ if (gpu_tot_memory) {
+ BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%.2fM"), (double)((gpu_tot_memory)) / 1024.0);
+ }
+ }
s = stats->infostr;
ofs = 0;
@@ -447,22 +461,23 @@ static void stats_string(Scene *scene)
}
ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s"),
- stats_fmt.totbonesel, stats_fmt.totbone, memstr);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"),
+ stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s"), stats_fmt.totvert,
- stats_fmt.tottri);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert,
+ stats_fmt.tottri, gpumemstr);
}
else {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
- IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s"),
+ IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s%s"),
stats_fmt.totvert, stats_fmt.totface,
stats_fmt.tottri, stats_fmt.totobjsel,
stats_fmt.totobj, stats_fmt.totlampsel,
- stats_fmt.totlamp, memstr);
+ stats_fmt.totlamp, memstr, gpumemstr);
}
if (ob)
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 062fc0cd42e..aeab87e6cb5 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -37,7 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -282,16 +282,13 @@ static void info_header_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi
static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu)
{
struct RecentFile *recent;
- char file[FILE_MAX];
uiLayout *layout = menu->layout;
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- if (G.recent_files.first) {
+ if (!BLI_listbase_is_empty(&G.recent_files)) {
for (recent = G.recent_files.first; (recent); recent = recent->next) {
- BLI_split_file_part(recent->filepath, file, sizeof(file));
- if (BLO_has_bfile_extension(file))
- uiItemStringO(layout, BLI_path_basename(recent->filepath), ICON_FILE_BLEND, "WM_OT_open_mainfile", "filepath", recent->filepath);
- else
- uiItemStringO(layout, BLI_path_basename(recent->filepath), ICON_FILE_BACKUP, "WM_OT_open_mainfile", "filepath", recent->filepath);
+ const char *file = BLI_path_basename(recent->filepath);
+ const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP;
+ uiItemStringO(layout, file, icon, "WM_OT_open_mainfile", "filepath", recent->filepath);
}
}
else {
@@ -306,7 +303,7 @@ static void recent_files_menu_register(void)
mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files");
strcpy(mt->idname, "INFO_MT_file_open_recent");
strcpy(mt->label, N_("Open Recent..."));
- strcpy(mt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = recent_files_menu_draw;
WM_menutype_add(mt);
}
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 33333e4c992..ebce13389c9 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -155,7 +155,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
MEM_freeN(offsets);
return 1;
}
- else if (y_next - cdc->lheight < cdc->ymin) {
+ else if (y_next < cdc->ymin) {
/* have not reached the drawable area so don't break */
cdc->xy[1] = y_next;
diff --git a/source/blender/editors/space_logic/CMakeLists.txt b/source/blender/editors/space_logic/CMakeLists.txt
index af2e8476511..349c003cf56 100644
--- a/source/blender/editors/space_logic/CMakeLists.txt
+++ b/source/blender/editors/space_logic/CMakeLists.txt
@@ -21,13 +21,15 @@
set(INC
../include
../interface
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -47,6 +49,8 @@ if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/space_logic/SConscript b/source/blender/editors/space_logic/SConscript
index ae8e929a684..4b618710d1f 100644
--- a/source/blender/editors/space_logic/SConscript
+++ b/source/blender/editors/space_logic/SConscript
@@ -31,12 +31,14 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../interface',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -45,6 +47,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_GAMEENGINE']:
defs.append('WITH_GAMEENGINE')
diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
index 2c521532484..e0cbc1c9539 100644
--- a/source/blender/editors/space_logic/logic_buttons.c
+++ b/source/blender/editors/space_logic/logic_buttons.c
@@ -34,7 +34,6 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
#include "ED_screen.h"
@@ -124,12 +123,12 @@ static int cut_links_exec(bContext *C, wmOperator *op)
for (block = ar->uiblocks.first; block; block = block->next) {
but = block->buttons.first;
while (but) {
- if (but->type==LINK && but->link) {
+ if (but->type==UI_BTYPE_LINK && but->link) {
for (line = but->link->lines.first; line; line = nline) {
nline = line->next;
if (cut_links_intersect(line, mcoords, i)) {
- ui_delete_linkline(line, but);
+ ui_linkline_remove(line, but);
}
}
}
diff --git a/source/blender/editors/space_logic/logic_intern.h b/source/blender/editors/space_logic/logic_intern.h
index 38b122f64b6..13146621d1b 100644
--- a/source/blender/editors/space_logic/logic_intern.h
+++ b/source/blender/editors/space_logic/logic_intern.h
@@ -35,12 +35,8 @@
/* internal exports only */
struct bContext;
struct ARegion;
-struct ARegionType;
struct ScrArea;
-struct SpaceLogic;
-struct Object;
struct wmOperatorType;
-struct Scene;
/* space_logic.c */
struct ARegion *logic_has_buttons_region(struct ScrArea *sa);
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 62703ba517e..abcb767958f 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -39,6 +39,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_sca.h"
@@ -298,7 +300,7 @@ static int sensor_add_exec(bContext *C, wmOperator *op)
BLI_strncpy(sens->name, sens_name, sizeof(sens->name));
}
- make_unique_prop_names(C, sens->name);
+ BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
ob->scaflag |= OB_SHOWSENS;
WM_event_add_notifier(C, NC_LOGIC, NULL);
@@ -405,7 +407,8 @@ static int controller_add_exec(bContext *C, wmOperator *op)
BLI_strncpy(cont->name, cont_name, sizeof(cont->name));
}
- make_unique_prop_names(C, cont->name);
+ BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
+
/* set the controller state mask from the current object state.
* A controller is always in a single state, so select the lowest bit set
* from the object state */
@@ -523,7 +526,7 @@ static int actuator_add_exec(bContext *C, wmOperator *op)
BLI_strncpy(act->name, act_name, sizeof(act->name));
}
- make_unique_prop_names(C, act->name);
+ BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
ob->scaflag |= OB_SHOWACT;
WM_event_add_notifier(C, NC_LOGIC, NULL);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index dd152022762..ccf8460e9a3 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -48,6 +48,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "BKE_action.h"
#include "BKE_context.h"
@@ -56,7 +57,7 @@
#include "ED_util.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -94,91 +95,6 @@
/* proto */
static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisflag);
-static int vergname(const void *v1, const void *v2)
-{
- char **x1, **x2;
-
- x1 = (char **)v1;
- x2 = (char **)v2;
-
- return BLI_natstrcmp(*x1, *x2);
-}
-
-void make_unique_prop_names(bContext *C, char *str)
-{
- Object *ob;
- bProperty *prop;
- bSensor *sens;
- bController *cont;
- bActuator *act;
- ID **idar;
- short a, obcount, propcount=0, nr;
- const char **names;
-
- /* this function is called by a Button, and gives the current
- * stringpointer as an argument, this is the one that can change
- */
-
- idar= get_selected_and_linked_obs(C, &obcount, BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_CONT_SEL|BUTS_CONT_ACT);
-
- /* for each object, make properties and sca names unique */
-
- /* count total names */
- for (a=0; a<obcount; a++) {
- ob= (Object *)idar[a];
- propcount+= BLI_countlist(&ob->prop);
- propcount+= BLI_countlist(&ob->sensors);
- propcount+= BLI_countlist(&ob->controllers);
- propcount+= BLI_countlist(&ob->actuators);
- }
- if (propcount==0) {
- if (idar) MEM_freeN(idar);
- return;
- }
-
- /* make names array for sorting */
- names= MEM_callocN(propcount*sizeof(void *), "names");
-
- /* count total names */
- nr= 0;
- for (a=0; a<obcount; a++) {
- ob= (Object *)idar[a];
- prop= ob->prop.first;
- while (prop) {
- names[nr++] = prop->name;
- prop= prop->next;
- }
- sens= ob->sensors.first;
- while (sens) {
- names[nr++] = sens->name;
- sens= sens->next;
- }
- cont= ob->controllers.first;
- while (cont) {
- names[nr++] = cont->name;
- cont= cont->next;
- }
- act= ob->actuators.first;
- while (act) {
- names[nr++] = act->name;
- act= act->next;
- }
- }
-
- qsort(names, propcount, sizeof(void *), vergname);
-
- /* now we check for double names, and change them */
-
- for (nr=0; nr<propcount; nr++) {
- if (names[nr]!=str && strcmp( names[nr], str )==0 ) {
- BLI_newname(str, +1);
- }
- }
-
- MEM_freeN(idar);
- MEM_freeN(names);
-}
-
static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
{
Main *bmain= CTX_data_main(C);
@@ -210,7 +126,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
ob->scaflag &= ~OB_ADDSENS;
sens= new_sensor(SENS_ALWAYS);
BLI_addtail(&(ob->sensors), sens);
- make_unique_prop_names(C, sens->name);
+ BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
ob->scaflag |= OB_SHOWSENS;
}
}
@@ -252,7 +168,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
if (ob->scaflag & OB_ADDCONT) {
ob->scaflag &= ~OB_ADDCONT;
cont= new_controller(CONT_LOGIC_AND);
- make_unique_prop_names(C, cont->name);
+ BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
ob->scaflag |= OB_SHOWCONT;
BLI_addtail(&(ob->controllers), cont);
/* set the controller state mask from the current object state.
@@ -328,7 +244,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
if (ob->scaflag & OB_ADDACT) {
ob->scaflag &= ~OB_ADDACT;
act= new_actuator(ACT_OBJECT);
- make_unique_prop_names(C, act->name);
+ BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
BLI_addtail(&(ob->actuators), act);
ob->scaflag |= OB_SHOWACT;
}
@@ -761,17 +677,17 @@ static uiBlock *sensor_menu(bContext *C, ARegion *ar, void *UNUSED(arg))
uiBlock *block;
int yco=0;
- block= uiBeginBlock(C, ar, __func__, UI_EMBOSSP);
- uiBlockSetButmFunc(block, do_sensor_menu, NULL);
+ block= UI_block_begin(C, ar, __func__, UI_EMBOSS_PULLDOWN);
+ UI_block_func_butmenu_set(block, do_sensor_menu, NULL);
- uiDefBut(block, BUTM, 1, IFACE_("Show Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
- uiDefBut(block, BUTM, 1, IFACE_("Hide Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
- uiDefBut(block, SEPRLINE, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, BUTM, 1, IFACE_("Show Sensors"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
- uiDefBut(block, BUTM, 1, IFACE_("Hide Sensors"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, UI_BTYPE_SEPR_LINE, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Sensors"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Sensors"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
- uiBlockSetDirection(block, UI_TOP);
- uiEndBlock(C, block);
+ UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_end(C, block);
return block;
}
@@ -810,17 +726,17 @@ static uiBlock *controller_menu(bContext *C, ARegion *ar, void *UNUSED(arg))
uiBlock *block;
int yco=0;
- block= uiBeginBlock(C, ar, __func__, UI_EMBOSSP);
- uiBlockSetButmFunc(block, do_controller_menu, NULL);
+ block= UI_block_begin(C, ar, __func__, UI_EMBOSS_PULLDOWN);
+ UI_block_func_butmenu_set(block, do_controller_menu, NULL);
- uiDefBut(block, BUTM, 1, IFACE_("Show Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
- uiDefBut(block, BUTM, 1, IFACE_("Hide Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
- uiDefBut(block, SEPRLINE, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, BUTM, 1, IFACE_("Show Controllers"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 2, 2, "");
- uiDefBut(block, BUTM, 1, IFACE_("Hide Controllers"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 3, 3, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, UI_BTYPE_SEPR_LINE, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Controllers"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 2, 2, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Controllers"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 3, 3, "");
- uiBlockSetDirection(block, UI_TOP);
- uiEndBlock(C, block);
+ UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_end(C, block);
return block;
}
@@ -859,17 +775,17 @@ static uiBlock *actuator_menu(bContext *C, ARegion *ar, void *UNUSED(arg))
uiBlock *block;
int xco=0;
- block= uiBeginBlock(C, ar, __func__, UI_EMBOSSP);
- uiBlockSetButmFunc(block, do_actuator_menu, NULL);
+ block= UI_block_begin(C, ar, __func__, UI_EMBOSS_PULLDOWN);
+ UI_block_func_butmenu_set(block, do_actuator_menu, NULL);
- uiDefBut(block, BUTM, 1, IFACE_("Show Objects"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
- uiDefBut(block, BUTM, 1, IFACE_("Hide Objects"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
- uiDefBut(block, SEPRLINE, 0, "", 0, (short)(xco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, BUTM, 1, IFACE_("Show Actuators"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
- uiDefBut(block, BUTM, 1, IFACE_("Hide Actuators"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Objects"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Objects"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, UI_BTYPE_SEPR_LINE, 0, "", 0, (short)(xco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Actuators"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Actuators"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
- uiBlockSetDirection(block, UI_TOP);
- uiEndBlock(C, block);
+ UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_end(C, block);
return block;
}
@@ -892,26 +808,26 @@ static uiBlock *controller_state_mask_menu(bContext *C, ARegion *ar, void *arg_c
short yco = 12, xco = 0, stbit, offset;
- block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ block= UI_block_begin(C, ar, __func__, UI_EMBOSS);
/* use this for a fake extra empy space around the buttons */
- uiDefBut(block, LABEL, 0, "", -5, -5, 200, 34, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", -5, -5, 200, 34, NULL, 0, 0, 0, 0, "");
for (offset=0; offset<15; offset += 5) {
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
for (stbit=0; stbit<5; stbit++) {
- but = uiDefButBitI(block, TOG, (1<<(stbit+offset)), (stbit+offset), "", (short)(xco+12*stbit+13*offset), yco, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
- uiButSetFunc(but, check_controller_state_mask, but, &(cont->state_mask));
+ but = uiDefButBitI(block, UI_BTYPE_TOGGLE, (1<<(stbit+offset)), (stbit+offset), "", (short)(xco+12*stbit+13*offset), yco, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
+ UI_but_func_set(but, check_controller_state_mask, but, &(cont->state_mask));
}
for (stbit=0; stbit<5; stbit++) {
- but = uiDefButBitI(block, TOG, (1<<(stbit+offset+15)), (stbit+offset+15), "", (short)(xco+12*stbit+13*offset), yco-12, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
- uiButSetFunc(but, check_controller_state_mask, but, &(cont->state_mask));
+ but = uiDefButBitI(block, UI_BTYPE_TOGGLE, (1<<(stbit+offset+15)), (stbit+offset+15), "", (short)(xco+12*stbit+13*offset), yco-12, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
+ UI_but_func_set(but, check_controller_state_mask, but, &(cont->state_mask));
}
}
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
- uiBlockSetDirection(block, UI_TOP);
- uiEndBlock(C, block);
+ UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_end(C, block);
return block;
}
@@ -923,7 +839,7 @@ static bool is_sensor_linked(uiBlock *block, bSensor *sens)
for (i=0; i<sens->totlinks; i++) {
cont = sens->links[i];
- if (uiFindInlink(block, cont) != NULL)
+ if (UI_block_links_find_inlink(block, cont) != NULL)
return 1;
}
return 0;
@@ -987,7 +903,7 @@ static void draw_sensor_internal_header(uiLayout *layout, PointerRNA *ptr)
sub = uiLayoutRow(row, false);
uiLayoutSetActive(sub, (RNA_boolean_get(ptr, "use_pulse_true_level") ||
RNA_boolean_get(ptr, "use_pulse_false_level")));
- uiItemR(sub, ptr, "frequency", 0, IFACE_("Freq"), ICON_NONE);
+ uiItemR(sub, ptr, "tick_skip", 0, IFACE_("Skip"), ICON_NONE);
row = uiLayoutRow(split, true);
uiItemR(row, ptr, "use_level", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
@@ -1117,7 +1033,7 @@ static void draw_sensor_keyboard(uiLayout *layout, PointerRNA *ptr)
uiLayout *row, *col;
row = uiLayoutRow(layout, false);
- uiItemL(row, CTX_IFACE_(BLF_I18NCONTEXT_ID_WINDOWMANAGER, "Key:"), ICON_NONE);
+ uiItemL(row, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Key:"), ICON_NONE);
col = uiLayoutColumn(row, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_keys") == false);
uiItemR(col, ptr, "key", UI_ITEM_R_EVENT, "", ICON_NONE);
@@ -2189,12 +2105,15 @@ static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr)
}
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "self_terminated", 0, NULL, ICON_NONE);
+ col = uiLayoutColumn(row, false);
+ uiItemR(col, ptr, "self_terminated", 0, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "mode")==ACT_STEERING_PATHFOLLOWING) {
- uiItemR(row, ptr, "update_period", 0, NULL, ICON_NONE);
- row = uiLayoutRow(layout, false);
+ col = uiLayoutColumn(row, false);
+ uiItemR(col, ptr, "update_period", 0, NULL, ICON_NONE);
}
row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "lock_z_velocity", 1, NULL, ICON_NONE);
+ row = uiLayoutRow(layout, false);
uiItemR(row, ptr, "show_visualization", 0, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "mode") != ACT_STEERING_PATHFOLLOWING) {
uiLayoutSetActive(row, false);
@@ -2353,9 +2272,9 @@ void logic_buttons(bContext *C, ARegion *ar)
idar= get_selected_and_linked_obs(C, &count, slogic->scaflag);
BLI_snprintf(uiblockstr, sizeof(uiblockstr), "buttonswin %p", (void *)ar);
- block= uiBeginBlock(C, ar, uiblockstr, UI_EMBOSS);
- uiBlockSetHandleFunc(block, do_logic_buts, NULL);
- uiBoundsBlock(block, U.widget_unit/2);
+ block= UI_block_begin(C, ar, uiblockstr, UI_EMBOSS);
+ UI_block_func_handle_set(block, do_logic_buts, NULL);
+ UI_block_bounds_set_normal(block, U.widget_unit/2);
/* loop over all objects and set visible/linked flags for the logic bricks */
for (a=0; a<count; a++) {
@@ -2401,7 +2320,7 @@ void logic_buttons(bContext *C, ARegion *ar)
/* ****************** Controllers ****************** */
xco= 21 * U.widget_unit; yco= - U.widget_unit / 2; width= 15 * U.widget_unit;
- layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_GetStyle());
+ layout= UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_style_get());
row = uiLayoutRow(layout, true);
uiDefBlockBut(block, controller_menu, NULL, IFACE_("Controllers"), xco - U.widget_unit / 2, yco, width, UI_UNIT_Y, ""); /* replace this with uiLayout stuff later */
@@ -2431,7 +2350,7 @@ void logic_buttons(bContext *C, ARegion *ar)
uiItemR(split, &settings_ptr, "show_state_panel", UI_ITEM_R_NO_BG, "", ICON_DISCLOSURE_TRI_RIGHT);
row = uiLayoutRow(split, true);
- uiDefButBitS(block, TOG, OB_SHOWCONT, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide controllers"));
+ uiDefButBitS(block, UI_BTYPE_TOGGLE, OB_SHOWCONT, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide controllers"));
RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
uiLayoutSetContextPointer(row, "object", &object_ptr);
@@ -2479,9 +2398,9 @@ void logic_buttons(bContext *C, ARegion *ar)
col = uiLayoutColumn(split, false);
uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_LEFT);
- but = uiDefIconBut(block, INLINK, 0, ICON_INLINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, cont, LINK_CONTROLLER, 0, 0, 0, "");
+ but = uiDefIconBut(block, UI_BTYPE_INLINK, 0, ICON_INLINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, cont, LINK_CONTROLLER, 0, 0, 0, "");
if (!RNA_boolean_get(&ptr, "active")) {
- uiButSetFlag(but, UI_BUT_SCA_LINK_GREY);
+ UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
}
//col = uiLayoutColumn(split, true);
@@ -2502,22 +2421,22 @@ void logic_buttons(bContext *C, ARegion *ar)
col = uiLayoutColumn(subsplit, false);
uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_LEFT);
- but = uiDefIconBut(block, LINK, 0, ICON_LINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ but = uiDefIconBut(block, UI_BTYPE_LINK, 0, ICON_LINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
if (!RNA_boolean_get(&ptr, "active")) {
- uiButSetFlag(but, UI_BUT_SCA_LINK_GREY);
+ UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
}
- uiSetButLink(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR);
+ UI_but_link_set(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR);
}
}
- uiBlockLayoutResolve(block, NULL, &yco); /* stores final height in yco */
+ UI_block_layout_resolve(block, NULL, &yco); /* stores final height in yco */
height = yco;
/* ****************** Sensors ****************** */
xco= U.widget_unit / 2; yco= -U.widget_unit / 2; width= 17 * U.widget_unit;
- layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_GetStyle());
+ layout= UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_style_get());
row = uiLayoutRow(layout, true);
uiDefBlockBut(block, sensor_menu, NULL, IFACE_("Sensors"), xco - U.widget_unit / 2, yco, 15 * U.widget_unit, UI_UNIT_Y, ""); /* replace this with uiLayout stuff later */
@@ -2537,7 +2456,7 @@ void logic_buttons(bContext *C, ARegion *ar)
if ((ob->scavisflag & OB_VIS_SENS) == 0) continue;
row = uiLayoutRow(layout, true);
- uiDefButBitS(block, TOG, OB_SHOWSENS, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide sensors"));
+ uiDefButBitS(block, UI_BTYPE_TOGGLE, OB_SHOWSENS, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide sensors"));
RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
uiLayoutSetContextPointer(row, "object", &object_ptr);
@@ -2575,23 +2494,23 @@ void logic_buttons(bContext *C, ARegion *ar)
/* put link button to the right */
col = uiLayoutColumn(split, false);
uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
- but = uiDefIconBut(block, LINK, 0, ICON_LINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ but = uiDefIconBut(block, UI_BTYPE_LINK, 0, ICON_LINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
if (!RNA_boolean_get(&ptr, "active")) {
- uiButSetFlag(but, UI_BUT_SCA_LINK_GREY);
+ UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
}
/* use old-school uiButtons for links for now */
- uiSetButLink(but, NULL, (void ***)&sens->links, &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER);
+ UI_but_link_set(but, NULL, (void ***)&sens->links, &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER);
}
}
}
- uiBlockLayoutResolve(block, NULL, &yco); /* stores final height in yco */
+ UI_block_layout_resolve(block, NULL, &yco); /* stores final height in yco */
height = MIN2(height, yco);
/* ****************** Actuators ****************** */
xco= 40 * U.widget_unit; yco= -U.widget_unit / 2; width= 17 * U.widget_unit;
- layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_GetStyle());
+ layout= UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_style_get());
row = uiLayoutRow(layout, true);
uiDefBlockBut(block, actuator_menu, NULL, IFACE_("Actuators"), xco - U.widget_unit / 2, yco, 15 * U.widget_unit, UI_UNIT_Y, ""); /* replace this with uiLayout stuff later */
@@ -2613,7 +2532,7 @@ void logic_buttons(bContext *C, ARegion *ar)
}
row = uiLayoutRow(layout, true);
- uiDefButBitS(block, TOG, OB_SHOWACT, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide actuators"));
+ uiDefButBitS(block, UI_BTYPE_TOGGLE, OB_SHOWACT, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide actuators"));
RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
uiLayoutSetContextPointer(row, "object", &object_ptr);
@@ -2644,9 +2563,9 @@ void logic_buttons(bContext *C, ARegion *ar)
/* put inlink button to the left */
col = uiLayoutColumn(split, false);
uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
- but = uiDefIconBut(block, INLINK, 0, ICON_INLINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, act, LINK_ACTUATOR, 0, 0, 0, "");
+ but = uiDefIconBut(block, UI_BTYPE_INLINK, 0, ICON_INLINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, act, LINK_ACTUATOR, 0, 0, 0, "");
if (!RNA_boolean_get(&ptr, "active")) {
- uiButSetFlag(but, UI_BUT_SCA_LINK_GREY);
+ UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
}
col = uiLayoutColumn(split, true);
@@ -2661,7 +2580,7 @@ void logic_buttons(bContext *C, ARegion *ar)
}
}
}
- uiBlockLayoutResolve(block, NULL, &yco); /* stores final height in yco */
+ UI_block_layout_resolve(block, NULL, &yco); /* stores final height in yco */
height = MIN2(height, yco);
UI_view2d_totRect_set(&ar->v2d, 57.5f * U.widget_unit, height - U.widget_unit);
@@ -2669,10 +2588,10 @@ void logic_buttons(bContext *C, ARegion *ar)
/* set the view */
UI_view2d_view_ortho(&ar->v2d);
- uiComposeLinks(block);
+ UI_block_links_compose(block);
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
/* restore view matrix */
UI_view2d_view_restore(C);
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 733cac7794e..34a5fee88eb 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -282,7 +282,7 @@ static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void logic_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
/************************* header region **************************/
diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt
index a74fc3191b7..c8c64a79945 100644
--- a/source/blender/editors/space_nla/CMakeLists.txt
+++ b/source/blender/editors/space_nla/CMakeLists.txt
@@ -20,13 +20,15 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -49,4 +51,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_nla "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_nla/SConscript b/source/blender/editors/space_nla/SConscript
index a00337e0b58..5bfa8d6c4c2 100644
--- a/source/blender/editors/space_nla/SConscript
+++ b/source/blender/editors/space_nla/SConscript
@@ -31,11 +31,13 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
@@ -43,6 +45,7 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 1090106d79f..8eead9b8e44 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -42,7 +42,7 @@
#include "BLI_blenlib.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_nla.h"
#include "BKE_context.h"
@@ -143,6 +143,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSGPENCIL:
{
/* for these channels, we only do AnimData */
if (ale->adt && adt_ptr) {
@@ -158,7 +159,9 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
}
/* AnimData pointer */
- RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+ if (adt_ptr) {
+ RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+ }
/* set found status to -1, since setting to 1 would break the loop
* and potentially skip an active NLA-Track in some cases...
@@ -254,7 +257,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
/* adt = adt_ptr.data; */
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* AnimData Source Properties ----------------------------------- */
@@ -281,7 +284,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
/* Active Action Properties ------------------------------------- */
/* action */
row = uiLayoutRow(layout, true);
- uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/); // XXX: need to make these operators
+ uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, "NLA_OT_action_unlink");
/* extrapolation */
row = uiLayoutRow(layout, true);
@@ -309,7 +312,7 @@ static void nla_panel_track(const bContext *C, Panel *pa)
return;
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* Info - Active NLA-Context:Track ---------------------- */
row = uiLayoutRow(layout, true);
@@ -329,7 +332,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
return;
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* Strip Properties ------------------------------------- */
/* strip type */
@@ -394,7 +397,7 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
return;
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* Strip Properties ------------------------------------- */
/* action pointer */
@@ -434,7 +437,7 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa)
return;
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ 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);
@@ -468,7 +471,7 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
strip = strip_ptr.data;
block = uiLayoutGetBlock(pa->layout);
- uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+ UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* 'add modifier' button at top of panel */
{
@@ -477,7 +480,7 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
// XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
// FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
- uiDefButO(block, BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"), 10, 0, 150, 20,
+ uiDefButO(block, UI_BTYPE_BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"), 10, 0, 150, 20,
TIP_("Adds a new F-Modifier for the active NLA Strip"));
/* copy/paste (as sub-row)*/
@@ -504,7 +507,7 @@ 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->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_animdata;
pt->poll = nla_animdata_panel_poll;
pt->flag = PNL_DEFAULT_CLOSED;
@@ -513,7 +516,7 @@ void nla_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
strcpy(pt->idname, "NLA_PT_track");
strcpy(pt->label, N_("Active Track"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_track;
pt->poll = nla_track_panel_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -521,7 +524,7 @@ void nla_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties");
strcpy(pt->label, N_("Active Strip"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_properties;
pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -529,7 +532,7 @@ 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->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_actclip;
pt->poll = nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -537,7 +540,7 @@ void nla_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation");
strcpy(pt->label, N_("Evaluation"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_evaluation;
pt->poll = nla_strip_eval_panel_poll;
BLI_addtail(&art->paneltypes, pt);
@@ -545,7 +548,7 @@ void nla_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
strcpy(pt->idname, "NLA_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_modifiers;
pt->poll = nla_strip_eval_panel_poll;
BLI_addtail(&art->paneltypes, pt);
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index fbb4d273626..a0ea12b8aa0 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -182,6 +182,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSGPENCIL:
{
/* sanity checking... */
if (ale->adt) {
@@ -290,10 +291,12 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
* the case of users trying to use this to change actions
* - in tweakmode, clicking here gets us out of tweakmode, as changing selection
* while in tweakmode is really evil!
+ * - we disable "solo" flags too, to make it easier to work with stashed actions
+ * with less trouble
*/
if (nlaedit_is_tweakmode_on(ac)) {
/* exit tweakmode immediately */
- nlaedit_disable_tweakmode(ac);
+ nlaedit_disable_tweakmode(ac, true);
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
@@ -503,6 +506,68 @@ void NLA_OT_action_pushdown(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
+/* ******************** Action Unlink ******************************** */
+
+static int nla_action_unlink_poll(bContext *C)
+{
+ if (ED_operator_nla_active(C)) {
+ return nla_panel_context(C, NULL, NULL, NULL);
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int nla_action_unlink_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA adt_ptr;
+ AnimData *adt;
+
+ /* check context and also validity of pointer */
+ if (!nla_panel_context(C, &adt_ptr, NULL, NULL))
+ return OPERATOR_CANCELLED;
+
+ /* get animdata */
+ adt = adt_ptr.data;
+ if (adt == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* do unlinking */
+ if (adt && adt->action) {
+ bool force_delete = RNA_boolean_get(op->ptr, "force_delete");
+ ED_animedit_unlink_action(C, adt_ptr.id.data, adt, adt->action, op->reports, force_delete);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int nla_action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+{
+ /* NOTE: this is hardcoded to match the behaviour for the unlink button (in interface_templates.c) */
+ RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0);
+ return nla_action_unlink_exec(C, op);
+}
+
+void NLA_OT_action_unlink(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Unlink Action";
+ ot->idname = "NLA_OT_action_unlink";
+ ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
+
+ /* callbacks */
+ ot->invoke = nla_action_unlink_invoke;
+ ot->exec = nla_action_unlink_exec;
+ ot->poll = nla_action_unlink_poll;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete",
+ "Clear Fake User and remove copy stashed in this datablock's NLA stack");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
@@ -649,7 +714,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete tracks */
@@ -724,7 +789,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* ensure that object has AnimData... that's all */
- BKE_id_add_animdata(&ob->id);
+ BKE_animdata_add_id(&ob->id);
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index ac8dca6e83a..b0adabe4d1d 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -59,7 +59,6 @@
#include "WM_types.h"
#include "UI_interface.h"
-#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -187,7 +186,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
else {
/* Action Clip (default/normal type of strip) */
- if ((strip->flag & NLASTRIP_FLAG_ACTIVE) && (adt && (adt->flag & ADT_NLA_EDIT_ON))) {
+ if (adt && (adt->flag & ADT_NLA_EDIT_ON) && (adt->actstrip == strip)) {
/* active strip should be drawn green when it is acting as the tweaking strip.
* however, this case should be skipped for when not in EditMode...
*/
@@ -274,7 +273,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
/* main call for drawing a single NLA-strip */
static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
{
- short nonSolo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
+ const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
float color[3];
/* get color of strip */
@@ -283,7 +282,7 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
/* draw extrapolation info first (as backdrop)
* - but this should only be drawn if track has some contribution
*/
- if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (nonSolo == 0)) {
+ if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) {
/* enable transparency... */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
@@ -338,12 +337,12 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
/* draw 'inside' of strip itself */
- if (nonSolo == 0) {
+ if (non_solo == 0) {
/* strip is in normal track */
glColor3fv(color);
- uiSetRoundBox(UI_CNR_ALL); /* all corners rounded */
+ UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
- uiDrawBoxShade(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
+ UI_draw_roundbox_shade_x(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
}
else {
/* strip is in disabled track - make less visible */
@@ -375,11 +374,11 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
}
/* - line style: dotted for muted */
- if (strip->flag & NLASTRIP_FLAG_MUTED)
+ if ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED))
setlinestyle(4);
/* draw outline */
- uiDrawBoxShade(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
+ UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
/* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) {
@@ -423,18 +422,19 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
}
/* add the relevant text to the cache of text-strings to draw in pixelspace */
-static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d, float yminc, float ymaxc)
+static void nla_draw_strip_text(
+ AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d,
+ float xminc, float xmaxc, float yminc, float ymaxc)
{
- short notSolo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
+ const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
char str[256];
size_t str_len;
char col[4];
- float xofs;
rctf rect;
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- str_len = BLI_snprintf(str, sizeof(str), "%d) Temp-Meta", index);
+ str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
}
else {
str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
@@ -449,24 +449,18 @@ static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, i
}
/* text opacity depends on whether if there's a solo'd track, this isn't it */
- if (notSolo == 0)
+ if (non_solo == 0)
col[3] = 255;
else
col[3] = 128;
-
- /* determine the amount of padding required - cannot be constant otherwise looks weird in some cases */
- if ((strip->end - strip->start) <= 5.0f)
- xofs = 0.5f;
- else
- xofs = 1.0f;
-
+
/* set bounding-box for text
* - padding of 2 'units' on either side
*/
// TODO: make this centered?
- rect.xmin = strip->start + xofs;
+ rect.xmin = xminc;
rect.ymin = yminc;
- rect.xmax = strip->end - xofs;
+ rect.xmax = xmaxc;
rect.ymax = ymaxc;
/* add this string to the cache of texts to draw */
@@ -491,11 +485,11 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
* while also preserving some accuracy, since we do use floats
*/
/* start frame */
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->start);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
/* end frame */
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->end);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end);
UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
}
@@ -511,6 +505,8 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
float y = 0.0f;
size_t items;
int height;
+ const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
+ const float text_margin_x = (8 * UI_DPI_FAC) * pixelx;
/* build list of channels to draw */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
@@ -551,11 +547,16 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
/* draw each strip in the track (if visible) */
for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ const float xminc = strip->start + text_margin_x;
+ const float xmaxc = strip->end + text_margin_x;
+
/* draw the visualization of the strip */
nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc);
/* add the text for this strip to the cache */
- nla_draw_strip_text(adt, nlt, strip, index, v2d, yminc, ymaxc);
+ if (xminc < xmaxc) {
+ nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, yminc, ymaxc);
+ }
/* if transforming strips (only real reason for temp-metas currently),
* add to the cache the frame numbers of the strip's extents
@@ -619,7 +620,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
/* *********************************************** */
/* Channel List */
-void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
+void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -651,6 +652,8 @@ void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
/* draw channels */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)(-NLACHANNEL_HEIGHT(snla));
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -662,15 +665,16 @@ void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= NLACHANNEL_STEP(snla);
+ channel_index++;
}
}
{ /* second pass: UI widgets */
- uiBlock *block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
size_t channel_index = 0;
y = (float)(-NLACHANNEL_HEIGHT(snla));
@@ -697,8 +701,8 @@ void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
channel_index++;
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
glDisable(GL_BLEND);
}
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index c787177a62a..f7673d86f94 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -43,7 +43,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_action.h"
#include "BKE_fcurve.h"
@@ -111,6 +111,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+
+ const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
bool ok = false;
/* get editor data */
@@ -133,6 +135,15 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
/* try entering tweakmode if valid */
ok |= BKE_nla_tweakmode_enter(adt);
+
+ /* mark the active track as being "solo"? */
+ if (do_solo && adt->actstrip) {
+ NlaTrack *nlt = BKE_nlatrack_find_tweaked(adt);
+
+ if (nlt && !(nlt->flag & NLATRACK_SOLO)) {
+ BKE_nlatrack_solo_toggle(adt, nlt);
+ }
+ }
}
/* free temp data */
@@ -159,6 +170,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
void NLA_OT_tweakmode_enter(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Enter Tweak Mode";
ot->idname = "NLA_OT_tweakmode_enter";
@@ -170,16 +183,22 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
+ "Enable 'solo' on the NLA Track containing the active strip, "
+ "to edit it without seeing the effects of the NLA stack");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------- */
/* NLA Editor internal API function for exiting tweakmode */
-bool nlaedit_disable_tweakmode(bAnimContext *ac)
+bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter;
+ int filter;
/* get a list of the AnimData blocks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
@@ -195,7 +214,14 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ale->data;
- /* to be sure, just exit tweakmode... */
+ /* clear solo flags */
+ if ((do_solo) & (adt->flag & ADT_NLA_SOLO_TRACK) &&
+ (adt->flag & ADT_NLA_EDIT_ON))
+ {
+ BKE_nlatrack_solo_toggle(adt, NULL);
+ }
+
+ /* to be sure that we're doing everything right, just exit tweakmode... */
BKE_nla_tweakmode_exit(adt);
}
@@ -218,9 +244,11 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
}
/* exit tweakmode operator callback */
-static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
+static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
bool ok = false;
/* get editor data */
@@ -228,7 +256,7 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* perform operation */
- ok = nlaedit_disable_tweakmode(&ac);
+ ok = nlaedit_disable_tweakmode(&ac, do_solo);
/* success? */
if (ok)
@@ -239,6 +267,8 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_tweakmode_exit(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Exit Tweak Mode";
ot->idname = "NLA_OT_tweakmode_exit";
@@ -250,6 +280,12 @@ void NLA_OT_tweakmode_exit(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
+ "Disable 'solo' on any of the NLA Tracks after exiting tweak mode "
+ "to get things back to normal");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* *********************************************** */
@@ -382,7 +418,7 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa
y = (float)NLACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* must be selected... */
if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
@@ -1372,11 +1408,15 @@ static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
/* just flip the mute flag for now */
// TODO: have a pre-pass to check if mute all or unmute all?
strip->flag ^= NLASTRIP_FLAG_MUTED;
+
+ /* tag AnimData to get recalculated */
+ ale->update |= ANIM_UPDATE_DEPS;
}
}
}
- /* free temp data */
+ /* cleanup */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
@@ -1436,7 +1476,9 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
if (BLI_listbase_is_empty(&nlt->strips) == false) {
NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
- if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2)) {
+ if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) &&
+ (BLI_listbase_count_ex(&mstrip->strips, 3) == 2))
+ {
/* remove this temp meta, so that we can see the strips inside */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
}
@@ -2128,9 +2170,13 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
/* remove the meta-strips now that we're done */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+
+ /* tag for recalculating the animation */
+ ale->update |= ANIM_UPDATE_DEPS;
}
- /* free temp data */
+ /* cleanup */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
@@ -2174,12 +2220,12 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w
uiLayout *layout;
int i;
- pup = uiPupMenuBegin(C, IFACE_("Add F-Modifier"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Add F-Modifier"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
/* check if modifier is valid for this context */
if (fmi == NULL)
@@ -2192,9 +2238,9 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w
}
uiItemS(layout);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
@@ -2244,6 +2290,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
if (fcm) {
set_active_fmodifier(&strip->modifiers, fcm);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else {
BKE_reportf(op->reports, RPT_ERROR,
@@ -2254,6 +2301,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
@@ -2319,6 +2367,9 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
}
}
+ /* free temp data */
+ ANIM_animdata_freelist(&anim_data);
+
/* successful or not? */
if (ok == 0) {
BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
@@ -2373,10 +2424,12 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
for (strip = nlt->strips.first; strip; strip = strip->next) {
// TODO: do we want to replace existing modifiers? add user pref for that!
ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
+ ale->update |= ANIM_UPDATE_DEPS;
}
}
/* clean up */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* successful or not? */
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 766ae28da6f..344580c0d15 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -50,7 +50,7 @@ void NLA_OT_properties(wmOperatorType *ot);
/* nla_draw.c */
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar);
-void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar);
+void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar);
/* **************************************** */
/* nla_select.c */
@@ -83,7 +83,7 @@ enum eNlaEdit_Snap_Mode {
/* --- */
-bool nlaedit_disable_tweakmode(bAnimContext *ac);
+bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo);
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
void NLA_OT_tweakmode_exit(wmOperatorType *ot);
@@ -137,6 +137,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac);
void NLA_OT_channels_click(wmOperatorType *ot);
void NLA_OT_action_pushdown(wmOperatorType *ot);
+void NLA_OT_action_unlink(wmOperatorType *ot);
void NLA_OT_tracks_add(wmOperatorType *ot);
void NLA_OT_tracks_delete(wmOperatorType *ot);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 5e1381db696..98da10470f8 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -28,15 +28,11 @@
* \ingroup spnla
*/
-
#include <string.h>
#include <stdio.h>
#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -118,6 +114,7 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_channels_click);
WM_operatortype_append(NLA_OT_action_pushdown);
+ WM_operatortype_append(NLA_OT_action_unlink);
WM_operatortype_append(NLA_OT_tracks_add);
WM_operatortype_append(NLA_OT_tracks_delete);
@@ -309,6 +306,7 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
void nla_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
+ wmKeyMapItem *kmi;
/* keymap for all regions ------------------------------------------- */
keymap = WM_keymap_find(keyconf, "NLA Generic", SPACE_NLA, 0);
@@ -323,6 +321,16 @@ void nla_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0);
+ /* tweakmode for stashed actions
+ * - similar to normal tweakmode, except we mark the tracks as being "solo"
+ * too so that the action can be edited in isolation
+ */
+ kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "isolate_action", true);
+
+ kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "isolate_action", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 134e5dd80a2..9fc7b5d6f8f 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -180,7 +180,7 @@ static void nla_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
{
SpaceNla *snla = (SpaceNla *)sa->spacedata.first;
- /* init dopesheet data if non-existant (i.e. for old files) */
+ /* init dopesheet data if non-existent (i.e. for old files) */
if (snla->ads == NULL) {
snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
snla->ads->source = (ID *)G.main->scene.first; // XXX this is bad, but we need this to be set correct
@@ -236,7 +236,7 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar)
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
- draw_nla_channel_list((bContext *)C, &ac, ar);
+ draw_nla_channel_list(C, &ac, ar);
}
/* reset view matrix */
@@ -305,7 +305,7 @@ static void nla_main_area_draw(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
- draw_markers_time(C, 0);
+ ED_markers_draw(C, DRAW_MARKERS_MARGIN);
/* preview range */
UI_view2d_view_ortho(v2d);
@@ -349,7 +349,7 @@ static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void nla_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void nla_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 6b0460ce5cd..cde818333e4 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../imbuf
../../gpu
../../makesdna
@@ -32,6 +33,7 @@ set(INC
../../windowmanager
../../compositor
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,4 +66,6 @@ if(WITH_COMPOSITOR)
add_definitions(-DWITH_COMPOSITOR)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
index 94756b96035..b559b61cf5a 100644
--- a/source/blender/editors/space_node/SConscript
+++ b/source/blender/editors/space_node/SConscript
@@ -1,3 +1,4 @@
+
#!/usr/bin/env python
#
# ***** BEGIN GPL LICENSE BLOCK *****
@@ -31,11 +32,13 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../compositor',
'../../gpu',
'../../imbuf',
@@ -48,6 +51,8 @@ incs = [
incs = ' '.join(incs)
defs = []
+defs += env['BF_GL_DEFINITIONS']
+
cf = []
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
#cf.append('/WX')
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 0358c1abce2..ab5874682da 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -38,6 +38,7 @@
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_text_types.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -47,14 +48,13 @@
#include "BKE_tracking.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "ED_node.h"
@@ -64,7 +64,6 @@
#include "UI_resources.h"
#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "node_intern.h" /* own include */
@@ -382,7 +381,7 @@ static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree,
static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float aspect)
{
/* XXX font id is crap design */
- const int fontid = UI_GetStyle()->widgetlabel.uifont_id;
+ const int fontid = UI_style_get()->widgetlabel.uifont_id;
NodeFrame *data = (NodeFrame *)node->storage;
rctf *rct = &node->totr;
int color_id = node_get_colorid(node);
@@ -391,6 +390,8 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
float width, ascender;
float x, y;
const int font_size = data->label_size / aspect;
+ const float margin = (float)(NODE_DY / 4);
+ int label_height;
nodeLabel(ntree, node, label, sizeof(label));
@@ -403,14 +404,54 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
width = BLF_width(fontid, label, sizeof(label));
ascender = BLF_ascender(fontid);
+ label_height = ((margin / aspect) + (ascender * aspect));
/* 'x' doesn't need aspect correction */
x = BLI_rctf_cent_x(rct) - (0.5f * width);
- y = rct->ymax - (((NODE_DY / 4) / aspect) + (ascender * aspect));
+ y = rct->ymax - label_height;
BLF_position(fontid, x, y, 0);
BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ /* draw text body */
+ if (node->id) {
+ Text *text = (Text *)node->id;
+ TextLine *line;
+ const int line_height_max = BLF_height_max(fontid);
+ const float line_spacing = (line_height_max * aspect);
+ const float line_width = (BLI_rctf_size_x(rct) - margin) / aspect;
+ int y_min;
+
+ /* 'x' doesn't need aspect correction */
+ x = rct->xmin + margin;
+ y = rct->ymax - (label_height + line_spacing);
+ /* early exit */
+ y_min = y + ((margin * 2) - (y - rct->ymin));
+
+ BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
+ BLF_clipping(
+ fontid,
+ rct->xmin,
+ /* round to avoid clipping half-way through a line */
+ y - (floorf(((y - rct->ymin) - (margin * 2)) / line_spacing) * line_spacing),
+ rct->xmin + line_width,
+ rct->ymax);
+
+ BLF_wordwrap(fontid, line_width);
+
+ for (line = text->lines.first; line; line = line->next) {
+ struct ResultBLF info;
+ BLF_position(fontid, x, y, 0);
+ BLF_draw_ex(fontid, line->line, line->len, &info);
+ y -= line_spacing * info.lines;
+ if (y < y_min) {
+ break;
+ }
+ }
+
+ BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
+ }
+
BLF_disable(fontid, BLF_ASPECT);
}
@@ -424,7 +465,7 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
/* skip if out of view */
if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == false) {
- uiEndBlock(C, node->block);
+ UI_block_end(C, node->block);
node->block = NULL;
return;
}
@@ -441,8 +482,8 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
else
UI_ThemeColor4(TH_NODE_FRAME);
glEnable(GL_BLEND);
- uiSetRoundBox(UI_CNR_ALL);
- uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
glDisable(GL_BLEND);
/* outline active and selected emphasis */
@@ -454,8 +495,8 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
else
UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_LINE_LOOP,
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP,
rct->xmin, rct->ymin,
rct->xmax, rct->ymax, BASIS_RAD);
@@ -468,8 +509,8 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
UI_ThemeClearColor(color_id);
- uiEndBlock(C, node->block);
- uiDrawBlock(C, node->block);
+ UI_block_end(C, node->block);
+ UI_block_draw(C, node->block);
node->block = NULL;
}
@@ -500,6 +541,7 @@ static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA
{
uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE);
uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE);
+ uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE);
}
@@ -546,7 +588,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax)
{
- uiEndBlock(C, node->block);
+ UI_block_end(C, node->block);
node->block = NULL;
return;
}
@@ -556,10 +598,10 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
*/
#if 0
/* body */
- uiSetRoundBox(UI_CNR_ALL);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_ThemeColor4(TH_NODE);
glEnable(GL_BLEND);
- uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
+ UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
glDisable(GL_BLEND);
/* outline active and selected emphasis */
@@ -571,7 +613,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
else
UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
- uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -581,7 +623,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
if (node->label[0] != '\0') {
/* draw title (node label) */
BLI_strncpy(showname, node->label, sizeof(showname));
- uiDefBut(node->block, LABEL, 0, showname,
+ uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname,
(int)(rct->xmin - NODE_DYS), (int)(rct->ymax),
(short)512, (short)NODE_DY,
NULL, 0, 0, 0, 0, NULL);
@@ -594,8 +636,8 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT));
}
- uiEndBlock(C, node->block);
- uiDrawBlock(C, node->block);
+ UI_block_end(C, node->block);
+ UI_block_draw(C, node->block);
node->block = NULL;
}
@@ -605,7 +647,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
static int node_tweak_area_reroute(bNode *node, int x, int y)
{
/* square of tweak radius */
- static const float tweak_radius_sq = 576; /* 24 * 24 */
+ const float tweak_radius_sq = SQUARE(24);
bNodeSocket *sock = node->inputs.first;
float dx = sock->locx - x;
@@ -671,10 +713,12 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
}
- col = uiLayoutColumn(layout, false);
-
- if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER)
+ if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ RNA_boolean_get(ptr, "has_layers"))
+ {
+ col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
+ }
}
static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -781,13 +825,15 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) {
uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE);
}
+ uiItemR(layout, ptr, "extension", 0, "", ICON_NONE);
+
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
*/
@@ -797,7 +843,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
- uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
}
static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -807,10 +853,52 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
+
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+}
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
+static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA imaptr = RNA_pointer_get(ptr, "image");
+ PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
+ Image *ima = imaptr.data;
+
+ uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
+ uiTemplateID(layout, C, ptr, "image", ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+
+ if (!ima)
+ return;
+
+ uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE);
+
+ if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) {
+ uiLayout *row = uiLayoutRow(layout, true);
+ const bool is_packed = BKE_image_has_packedfile(ima);
+
+ if (is_packed)
+ uiItemO(row, "", ICON_PACKAGE, "image.unpack");
+ else
+ uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
+
+ row = uiLayoutRow(row, true);
+ uiLayoutSetEnabled(row, !is_packed);
+ uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
+ uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
+ }
+
+ /* multilayer? */
+ if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
+ uiTemplateImageLayers(layout, C, ima, iuserptr.data);
+ }
+ else if (ima->source != IMA_SRC_GENERATED) {
+ uiTemplateImageInfo(layout, C, ima, iuserptr.data);
+ }
+
+ uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
}
static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -861,8 +949,32 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
}
+static void node_shader_buts_tex_pointdensity(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+ NodeShaderTexPointDensity *shader_point_density = node->storage;
+
+ uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+
+ if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ PointerRNA dataptr;
+ RNA_id_pointer_create((ID *)node->id, &dataptr);
+ uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE);
+ if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ uiItemR(layout, ptr, "color_source", 0, NULL, ICON_NONE);
+ }
+}
+
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "object", 0, NULL, 0);
uiItemR(layout, ptr, "from_dupli", 0, NULL, 0);
}
@@ -1073,6 +1185,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
break;
case SH_NODE_TEX_ENVIRONMENT:
ntype->draw_buttons = node_shader_buts_tex_environment;
+ ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex;
break;
case SH_NODE_TEX_GRADIENT:
ntype->draw_buttons = node_shader_buts_tex_gradient;
@@ -1092,6 +1205,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_VORONOI:
ntype->draw_buttons = node_shader_buts_tex_voronoi;
break;
+ case SH_NODE_TEX_POINTDENSITY:
+ ntype->draw_buttons = node_shader_buts_tex_pointdensity;
+ break;
case SH_NODE_TEX_COORD:
ntype->draw_buttons = node_shader_buts_tex_coord;
break;
@@ -1139,6 +1255,24 @@ static void node_shader_set_butfunc(bNodeType *ntype)
/* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
+static void node_buts_image_views(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr,
+ PointerRNA *imaptr)
+{
+ uiLayout *col;
+
+ if (!imaptr->data)
+ return;
+
+ col = uiLayoutColumn(layout, false);
+
+ if (RNA_boolean_get(ptr, "has_views")) {
+ if (RNA_enum_get(ptr, "view") == 0)
+ uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
+ else
+ uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
+ }
+}
+
static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -1152,6 +1286,8 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
imaptr = RNA_pointer_get(ptr, "image");
node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr);
+
+ node_buts_image_views(layout, C, ptr, &imaptr);
}
static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1161,7 +1297,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1);
}
static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1642,8 +1778,8 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
-
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+
if (multilayer)
uiItemL(layout, IFACE_("Path:"), ICON_NONE);
else
@@ -1652,15 +1788,22 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
uiLayout *row, *col;
int active_index;
- int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
node_composit_buts_file_output(layout, C, ptr);
uiTemplateImageSettings(layout, &imfptr, false);
+ /* disable stereo output for multilayer, too much work for something that no one will use */
+ /* if someone asks for that we can implement it */
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imfptr, NULL);
+
uiItemS(layout);
uiItemO(layout, IFACE_("Add Input"), ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
@@ -1672,13 +1815,13 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
/* using different collection properties if multilayer format is enabled */
if (multilayer) {
uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index",
- 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0);
RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"),
active_index, &active_input_ptr);
}
else {
uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index",
- 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0);
RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"),
active_index, &active_input_ptr);
}
@@ -1722,6 +1865,9 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
uiTemplateImageSettings(col, &imfptr, false);
+
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imfptr, NULL);
}
}
}
@@ -2015,6 +2161,18 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
}
+static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
+{
+ PointerRNA op_ptr;
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1);
+
+ BLI_assert(ot != 0);
+
+ WM_operator_properties_create_ptr(&op_ptr, ot);
+
+ uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+}
+
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row;
@@ -2281,6 +2439,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
+ NodePlaneTrackDeformData *data = node->storage;
uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
@@ -2309,6 +2468,12 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
}
}
+
+ uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ }
}
static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
@@ -2505,6 +2670,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SWITCH:
ntype->draw_buttons = node_composit_buts_switch;
break;
+ case CMP_NODE_SWITCH_VIEW:
+ ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
+ break;
case CMP_NODE_MASK_BOX:
ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
@@ -2657,7 +2825,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA
PointerRNA iuserptr;
RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
- uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
}
static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2877,6 +3045,7 @@ static void node_file_output_socket_draw(bContext *C, uiLayout *layout, PointerR
imfptr = RNA_pointer_get(node_ptr, "format");
imtype = RNA_enum_get(&imfptr, "file_format");
+
if (imtype == R_IMF_IMTYPE_MULTILAYER) {
NodeImageMultiFileSocket *input = sock->storage;
RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotLayer, input, &inputptr);
@@ -2899,9 +3068,9 @@ static void node_file_output_socket_draw(bContext *C, uiLayout *layout, PointerR
RNA_property_enum_name((bContext *)C, &imfptr, imtype_prop,
RNA_property_enum_get(&imfptr, imtype_prop), &imtype_name);
block = uiLayoutGetBlock(row);
- uiBlockSetEmboss(block, UI_EMBOSSP);
+ UI_block_emboss_set(block, UI_EMBOSS_PULLDOWN);
uiItemL(row, imtype_name, ICON_NONE);
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
}
@@ -3055,9 +3224,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
/* somehow the offset has to be calculated inverse */
glaDefine2DArea(&ar->winrct);
- /* ortho at pixel level curarea */
- /* almost #wmOrtho2_region_pixelspace, but no +1 px */
- wmOrtho2_pixelspace(ar->winx, ar->winy);
+ wmOrtho2_region_pixelspace(ar);
x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
y = (ar->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
@@ -3254,7 +3421,7 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa
#define LINK_RESOL 24
#define LINK_ARROW 12 /* position of arrow on the link, LINK_RESOL/2 */
-#define ARROW_SIZE 7
+#define ARROW_SIZE (7 * UI_DPI_FAC)
void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3)
{
@@ -3267,6 +3434,7 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
/* store current linewidth */
float linew;
float arrow[2], arrow1[2], arrow2[2];
+ const float px_fac = UI_DPI_WINDOW_FAC;
glGetFloatv(GL_LINE_WIDTH, &linew);
/* we can reuse the dist variable here to increment the GL curve eval amount*/
@@ -3293,7 +3461,7 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
}
if (do_triple) {
UI_ThemeColorShadeAlpha(th_col3, -80, -120);
- glLineWidth(4.0f);
+ glLineWidth(4.0f * px_fac);
glBegin(GL_LINE_STRIP);
for (i = 0; i <= LINK_RESOL; i++) {
@@ -3314,7 +3482,7 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
* for Intel hardware, this breaks with GL_LINE_STRIP and
* changing color in begin/end blocks.
*/
- glLineWidth(1.5f);
+ glLineWidth(1.5f * px_fac);
if (do_shaded) {
glBegin(GL_LINES);
for (i = 0; i < LINK_RESOL; i++) {
@@ -3444,7 +3612,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
{
bool do_shaded = false;
bool do_triple = false;
- int th_col1 = TH_HEADER, th_col2 = TH_HEADER, th_col3 = TH_WIRE;
+ int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
if (link->fromsock == NULL && link->tosock == NULL)
return;
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 02e6f9b69f3..ab7fa51856a 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -29,8 +29,6 @@
* \ingroup spnode
*/
-#include <errno.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_node_types.h"
@@ -38,7 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_image.h"
@@ -227,7 +225,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
float insert_point[2];
/* always first */
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node_deselect_all(snode);
@@ -304,33 +302,12 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
- Image *ima = NULL;
+ Image *ima;
int type = 0;
- /* check input variables */
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- char path[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", path);
-
- errno = 0;
-
- ima = BKE_image_load_exists(path);
-
- if (!ima) {
- BKE_reportf(op->reports, RPT_ERROR, "Cannot read image '%s': %s",
- path, errno ? strerror(errno) : TIP_("unsupported format"));
- return OPERATOR_CANCELLED;
- }
- }
- else if (RNA_struct_property_is_set(op->ptr, "name")) {
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- ima = (Image *)BKE_libblock_find_name(ID_IM, name);
-
- if (!ima) {
- BKE_reportf(op->reports, RPT_ERROR, "Image '%s' not found", name);
- return OPERATOR_CANCELLED;
- }
+ ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
+ if (!ima) {
+ return OPERATOR_CANCELLED;
}
switch (snode->nodetree->type) {
@@ -347,7 +324,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node = node_add_node(C, NULL, type, snode->cursor[0], snode->cursor[1]);
@@ -357,9 +334,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
}
node->id = (ID *)ima;
-
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+
+ /* When adding new image file via drag-drop we need to load imbuf in order
+ * to get proper image source.
+ */
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+ }
snode_notify(C, snode);
snode_dag_update(C, snode);
@@ -397,8 +379,8 @@ void NODE_OT_add_file(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
}
@@ -426,7 +408,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node = node_add_node(C, NULL, CMP_NODE_MASK, snode->cursor[0], snode->cursor[1]);
@@ -471,8 +453,8 @@ static int new_node_tree_exec(bContext *C, wmOperator *op)
PointerRNA ptr, idptr;
PropertyRNA *prop;
const char *idname;
- char _treename[MAX_ID_NAME - 2];
- char *treename = _treename;
+ char treename_buf[MAX_ID_NAME - 2];
+ const char *treename;
if (RNA_struct_property_is_set(op->ptr, "type")) {
prop = RNA_struct_find_property(op->ptr, "type");
@@ -484,10 +466,11 @@ static int new_node_tree_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if (RNA_struct_property_is_set(op->ptr, "name")) {
- RNA_string_get(op->ptr, "name", treename);
+ RNA_string_get(op->ptr, "name", treename_buf);
+ treename = treename_buf;
}
else {
- treename = (char *)DATA_("NodeTree");
+ treename = DATA_("NodeTree");
}
if (!ntreeTypeFind(idname)) {
@@ -498,7 +481,7 @@ static int new_node_tree_exec(bContext *C, wmOperator *op)
ntree = ntreeAddTree(bmain, treename, idname);
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
/* RNA_property_pointer_set increases the user count,
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 58d94a28226..52b0292b9a3 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -35,7 +35,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -57,6 +57,7 @@
/* ******************* node space & buttons ************** */
+#if 0
/* poll for active nodetree */
static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
{
@@ -64,6 +65,7 @@ static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
return (snode && snode->nodetree);
}
+#endif
static int node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
{
@@ -146,14 +148,14 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
col = uiLayoutColumn(split, true);
uiItemL(col, IFACE_("Inputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input",
- 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0);
opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_IN);
col = uiLayoutColumn(split, true);
uiItemL(col, IFACE_("Outputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output",
- 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0);
opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_OUT);
@@ -184,7 +186,7 @@ void node_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype node panel node sockets");
strcpy(pt->idname, "NODE_PT_sockets");
strcpy(pt->label, N_("Sockets"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = node_sockets_panel;
pt->poll = node_sockets_poll;
pt->flag |= PNL_DEFAULT_CLOSED;
@@ -193,19 +195,10 @@ void node_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype node panel tree interface");
strcpy(pt->idname, "NODE_PT_node_tree_interface");
strcpy(pt->label, N_("Interface"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = node_tree_interface_panel;
pt->poll = node_tree_interface_poll;
BLI_addtail(&art->paneltypes, pt);
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil");
- strcpy(pt->idname, "NODE_PT_gpencil");
- strcpy(pt->label, N_("Grease Pencil"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = ED_gpencil_panel_standard_header;
- pt->draw = ED_gpencil_panel_standard;
- pt->poll = active_nodetree_poll;
- BLI_addtail(&art->paneltypes, pt);
}
static int node_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 7b5ec38f4c6..283457d1fc6 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -41,7 +41,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -66,10 +66,13 @@
#include "RNA_access.h"
#include "node_intern.h" /* own include */
-#include "COM_compositor.h"
+
+#ifdef WITH_COMPOSITOR
+# include "COM_compositor.h"
+#endif
/* XXX interface.h */
-extern void ui_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
+extern void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
float ED_node_grid_size(void)
{
@@ -120,7 +123,14 @@ void ED_node_tag_update_id(ID *id)
bNodeTree *ntree = node_tree_from_ID(id);
if (id == NULL || ntree == NULL)
return;
-
+
+ /* TODO(sergey): With the new dependency graph it
+ * should be just enough to only tag ntree itself,
+ * all the users of this tree will have update
+ * flushed from the tree,
+ */
+ DAG_id_tag_update(&ntree->id, 0);
+
if (ntree->type == NTREE_SHADER) {
DAG_id_tag_update(id, 0);
@@ -160,14 +170,14 @@ void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree)
ntreeTexCheckCyclics(ntree);
}
-static int compare_nodes(bNode *a, bNode *b)
+static bool compare_nodes(const bNode *a, const bNode *b)
{
bNode *parent;
/* These tell if either the node or any of the parent nodes is selected.
* A selected parent means an unselected node is also in foreground!
*/
- int a_select = (a->flag & NODE_SELECT), b_select = (b->flag & NODE_SELECT);
- int a_active = (a->flag & NODE_ACTIVE), b_active = (b->flag & NODE_ACTIVE);
+ bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0;
+ bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0;
/* if one is an ancestor of the other */
/* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
@@ -214,7 +224,7 @@ void ED_node_sort(bNodeTree *ntree)
{
/* merge sort is the algorithm of choice here */
bNode *first_a, *first_b, *node_a, *node_b, *tmp;
- int totnodes = BLI_countlist(&ntree->nodes);
+ int totnodes = BLI_listbase_count(&ntree->nodes);
int k, a, b;
k = 1;
@@ -283,11 +293,11 @@ static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
/* ui block */
BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
- node->block = uiBeginBlock(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
- uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
+ node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
+ UI_block_func_handle_set(node->block, do_node_internal_buttons, node);
/* this cancels events for background nodes */
- uiBlockSetFlag(node->block, UI_BLOCK_CLIP_EVENTS);
+ UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS);
}
}
@@ -298,6 +308,12 @@ void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry)
*ry *= UI_DPI_FAC;
}
+void node_to_updated_rect(struct bNode *node, rctf *r_rect)
+{
+ node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
+ node_to_view(node, node->offsetx + node->width, node->offsety - node->height, &r_rect->xmax, &r_rect->ymin);
+}
+
void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
{
x /= UI_DPI_FAC;
@@ -336,8 +352,9 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
- layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
- locx + NODE_DYS, dy, NODE_WIDTH(node) - NODE_DY, NODE_DY, 0, UI_GetStyle());
+ layout = UI_block_layout(
+ node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
+ locx + NODE_DYS, dy, NODE_WIDTH(node) - NODE_DY, NODE_DY, 0, UI_style_get());
/* context pointers for current node and socket */
uiLayoutSetContextPointer(layout, "node", &nodeptr);
uiLayoutSetContextPointer(layout, "socket", &sockptr);
@@ -348,8 +365,8 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(nsock->name));
- uiBlockEndAlign(node->block);
- uiBlockLayoutResolve(node->block, NULL, &buty);
+ UI_block_align_end(node->block);
+ UI_block_layout_resolve(node->block, NULL, &buty);
/* ensure minimum socket height in case layout is empty */
buty = min_ii(buty, dy - NODE_DY);
@@ -407,14 +424,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
node->butr.ymax = 0;
- layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
- locx + NODE_DYS, dy, node->butr.xmax, 0, 0, UI_GetStyle());
+ layout = UI_block_layout(
+ node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
+ locx + NODE_DYS, dy, node->butr.xmax, 0, 0, UI_style_get());
uiLayoutSetContextPointer(layout, "node", &nodeptr);
node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr);
- uiBlockEndAlign(node->block);
- uiBlockLayoutResolve(node->block, NULL, &buty);
+ UI_block_align_end(node->block);
+ UI_block_layout_resolve(node->block, NULL, &buty);
dy = buty - NODE_DYS / 2;
}
@@ -426,8 +444,9 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
- layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
- locx + NODE_DYS, dy, NODE_WIDTH(node) - NODE_DY, NODE_DY, 0, UI_GetStyle());
+ layout = UI_block_layout(
+ node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
+ locx + NODE_DYS, dy, NODE_WIDTH(node) - NODE_DY, NODE_DY, 0, UI_style_get());
/* context pointers for current node and socket */
uiLayoutSetContextPointer(layout, "node", &nodeptr);
uiLayoutSetContextPointer(layout, "socket", &sockptr);
@@ -436,8 +455,8 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(nsock->name));
- uiBlockEndAlign(node->block);
- uiBlockLayoutResolve(node->block, NULL, &buty);
+ UI_block_align_end(node->block);
+ UI_block_layout_resolve(node->block, NULL, &buty);
/* ensure minimum socket height in case layout is empty */
buty = min_ii(buty, dy - NODE_DY);
@@ -463,11 +482,12 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side.
*/
- uiExplicitBoundsBlock(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(
+ node->block,
+ node->totr.xmin - NODE_SOCKSIZE,
+ node->totr.ymin,
+ node->totr.xmax + NODE_SOCKSIZE,
+ node->totr.ymax);
}
/* based on settings in node, sets drawing rect info. each redraw! */
@@ -524,11 +544,12 @@ static void node_update_hidden(bNode *node)
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side.
*/
- uiExplicitBoundsBlock(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(
+ node->block,
+ node->totr.xmin - NODE_SOCKSIZE,
+ node->totr.ymin,
+ node->totr.xmax + NODE_SOCKSIZE,
+ node->totr.ymax);
}
void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
@@ -739,16 +760,16 @@ void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
{
rctf *rct = &node->totr;
- uiSetRoundBox(UI_CNR_ALL);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
if (node->parent == NULL)
- ui_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
+ ui_draw_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
else {
const float margin = 3.0f;
glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
glEnable(GL_BLEND);
- uiRoundBox(rct->xmin - margin, rct->ymin - margin,
- rct->xmax + margin, rct->ymax + margin, radius + margin);
+ UI_draw_roundbox(rct->xmin - margin, rct->ymin - margin,
+ rct->xmax + margin, rct->ymax + margin, radius + margin);
glDisable(GL_BLEND);
}
}
@@ -771,7 +792,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
/* skip if out of view */
if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == false) {
- uiEndBlock(C, node->block);
+ UI_block_end(C, node->block);
node->block = NULL;
return;
}
@@ -800,8 +821,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
}
#endif
- uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
- uiRoundBox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
+ UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
/* show/hide icons */
iconofs = rct->xmax - 0.35f * U.widget_unit;
@@ -810,27 +831,27 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
if (node->typeinfo->flag & NODE_PREVIEW) {
uiBut *but;
iconofs -= iconbutw;
- uiBlockSetEmboss(node->block, UI_EMBOSSN);
- but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_MATERIAL,
+ UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ but = uiDefIconBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, ICON_MATERIAL,
iconofs, rct->ymax - NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
+ UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
/* XXX this does not work when node is activated and the operator called right afterwards,
* since active ID is not updated yet (needs to process the notifier).
* This can only work as visual indicator!
*/
// if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
-// uiButSetFlag(but, UI_BUT_DISABLED);
- uiBlockSetEmboss(node->block, UI_EMBOSS);
+// UI_but_flag_enable(but, UI_BUT_DISABLED);
+ UI_block_emboss_set(node->block, UI_EMBOSS);
}
/* group edit */
if (node->type == NODE_GROUP) {
uiBut *but;
iconofs -= iconbutw;
- uiBlockSetEmboss(node->block, UI_EMBOSSN);
- but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_NODETREE,
+ UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ but = uiDefIconBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, ICON_NODETREE,
iconofs, rct->ymax - NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
- uiBlockSetEmboss(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
+ UI_block_emboss_set(node->block, UI_EMBOSS);
}
/* title */
@@ -844,15 +865,15 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
uiBut *but;
int but_size = UI_UNIT_X * 0.6f;
/* XXX button uses a custom triangle draw below, so make it invisible without icon */
- uiBlockSetEmboss(node->block, UI_EMBOSSN);
- but = uiDefBut(node->block, TOGBUT, B_REDR, "",
+ UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ but = uiDefBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, "",
rct->xmin + 0.5f * U.widget_unit - but_size / 2, rct->ymax - NODE_DY / 2.0f - but_size / 2,
but_size, but_size, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- uiBlockSetEmboss(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(node->block, UI_EMBOSS);
/* custom draw function for this button */
- UI_DrawTriIcon(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v');
+ UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v');
}
/* this isn't doing anything for the label, so commenting out */
@@ -868,7 +889,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
//if (node->flag & NODE_MUTED)
// BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */
- uiDefBut(node->block, LABEL, 0, showname,
+ uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname,
(int)(rct->xmin + (NODE_MARGIN_X)), (int)(rct->ymax - NODE_DY),
(short)(iconofs - rct->xmin - 18.0f), (short)NODE_DY,
NULL, 0, 0, 0, 0, "");
@@ -881,8 +902,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
else
UI_ThemeColor4(TH_NODE);
glEnable(GL_BLEND);
- uiSetRoundBox(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
- uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD);
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
+ UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD);
glDisable(GL_BLEND);
/* outline active and selected emphasis */
@@ -896,8 +917,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
else
UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -936,8 +957,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
UI_ThemeClearColor(color_id);
- uiEndBlock(C, node->block);
- uiDrawBlock(C, node->block);
+ UI_block_end(C, node->block);
+ UI_block_draw(C, node->block);
node->block = NULL;
}
@@ -969,7 +990,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
(void)ntree;
#endif
- uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
+ UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
@@ -980,7 +1001,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
else
UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
- uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -992,7 +1013,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
glEnable(GL_LINE_SMOOTH);
glColor3fv(node->color);
- uiDrawBox(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -1009,15 +1030,15 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
uiBut *but;
int but_size = UI_UNIT_X * 0.6f;
/* XXX button uses a custom triangle draw below, so make it invisible without icon */
- uiBlockSetEmboss(node->block, UI_EMBOSSN);
- but = uiDefBut(node->block, TOGBUT, B_REDR, "",
+ UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ but = uiDefBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, "",
rct->xmin + 10.0f - but_size / 2, centy - but_size / 2,
but_size, but_size, NULL, 0, 0, 0, 0, "");
- uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- uiBlockSetEmboss(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(node->block, UI_EMBOSS);
/* custom draw function for this button */
- UI_DrawTriIcon(rct->xmin + 10.0f, centy, 'h');
+ UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h');
}
/* disable lines */
@@ -1035,7 +1056,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
//if (node->flag & NODE_MUTED)
// BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */
- uiDefBut(node->block, LABEL, 0, showname,
+ uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname,
(int)(rct->xmin + (NODE_MARGIN_X)), (int)(centy - 10),
(short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f), (short)NODE_DY,
NULL, 0, 0, 0, 0, "");
@@ -1063,8 +1084,8 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
}
- uiEndBlock(C, node->block);
- uiDrawBlock(C, node->block);
+ UI_block_end(C, node->block);
+ UI_block_draw(C, node->block);
node->block = NULL;
}
@@ -1125,6 +1146,9 @@ void node_update_nodetree(const bContext *C, bNodeTree *ntree)
{
bNode *node;
+ /* make sure socket "used" tags are correct, for displaying value buttons */
+ ntreeTagUsedSockets(ntree);
+
/* update nodes front to back, so children sizes get updated before parents */
for (node = ntree->nodes.last; node; node = node->prev) {
node_update(C, ntree, node);
@@ -1243,15 +1267,15 @@ static void draw_group_overlay(const bContext *C, ARegion *ar)
/* shade node groups to separate them visually */
UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
glEnable(GL_BLEND);
- uiSetRoundBox(UI_CNR_NONE);
- uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0);
+ UI_draw_roundbox_corner_set(UI_CNR_NONE);
+ UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0);
glDisable(GL_BLEND);
/* set the block bounds to clip mouse events from underlying nodes */
- block = uiBeginBlock(C, ar, "node tree bounds block", UI_EMBOSS);
- uiExplicitBoundsBlock(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- uiBlockSetFlag(block, UI_BLOCK_CLIP_EVENTS);
- uiEndBlock(C, block);
+ block = UI_block_begin(C, ar, "node tree bounds block", UI_EMBOSS);
+ UI_block_bounds_set_explicit(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ UI_block_flag_enable(block, UI_BLOCK_CLIP_EVENTS);
+ UI_block_end(C, block);
}
void drawnodespace(const bContext *C, ARegion *ar)
@@ -1293,6 +1317,11 @@ void drawnodespace(const bContext *C, ARegion *ar)
path = snode->treepath.last;
+ /* update tree path name (drawn in the bottom left) */
+ if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) {
+ BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name));
+ }
+
/* current View2D center, will be set temporarily for parent node trees */
UI_view2d_center_get(v2d, &center[0], &center[1]);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index ca13d87d632..ffd51bcc44e 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -31,7 +31,6 @@
#include "MEM_guardedalloc.h"
-#include "DNA_action_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -73,8 +72,6 @@
#include "IMB_imbuf_types.h"
#include "node_intern.h" /* own include */
-#include "NOD_common.h"
-#include "NOD_socket.h"
#include "NOD_composite.h"
#include "NOD_shader.h"
#include "NOD_texture.h"
@@ -96,7 +93,6 @@ typedef struct CompoJob {
const short *stop;
short *do_update;
float *progress;
- short need_sync;
int recalc_flags;
} CompoJob;
@@ -165,13 +161,12 @@ static int compo_breakjob(void *cjv)
);
}
-/* called by compo, wmJob sends notifier, old compositor system only */
-static void compo_statsdrawjob(void *cjv, char *UNUSED(str))
+/* called by compo, wmJob sends notifier */
+static void compo_statsdrawjob(void *cjv, const char *UNUSED(str))
{
CompoJob *cj = cjv;
*(cj->do_update) = true;
- cj->need_sync = true;
}
/* called by compo, wmJob sends notifier */
@@ -205,17 +200,8 @@ static void compo_initjob(void *cjv)
}
/* called before redraw notifiers, it moves finished previews over */
-static void compo_updatejob(void *cjv)
+static void compo_updatejob(void *UNUSED(cjv))
{
- CompoJob *cj = cjv;
-
- if (cj->need_sync) {
- /* was used by old compositor system only */
- ntreeLocalSync(cj->localtree, cj->ntree);
-
- cj->need_sync = false;
- }
-
WM_main_add_notifier(NC_SCENE | ND_COMPO_RESULT, NULL);
}
@@ -226,13 +212,13 @@ static void compo_progressjob(void *cjv, float progress)
*(cj->progress) = progress;
}
-
/* only this runs inside thread */
static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
{
CompoJob *cj = cjv;
bNodeTree *ntree = cj->localtree;
Scene *scene = cj->scene;
+ SceneRenderView *srv;
if (scene->use_nodes == false)
return;
@@ -252,7 +238,16 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
// XXX BIF_store_spare();
/* 1 is do_previews */
- ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings);
+
+ if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, "");
+ }
+ else {
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) continue;
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, srv->name);
+ }
+ }
ntree->test_break = NULL;
ntree->stats_draw = NULL;
@@ -342,14 +337,22 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
void snode_notify(bContext *C, SpaceNode *snode)
{
+ ID *id = snode->id;
+
WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL);
- if (ED_node_is_shader(snode))
- WM_event_add_notifier(C, NC_MATERIAL | ND_NODES, snode->id);
+ if (ED_node_is_shader(snode)) {
+ if (GS(id->name) == ID_MA)
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
+ else if (GS(id->name) == ID_LA)
+ WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
+ else if (GS(id->name) == ID_WO)
+ WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
+ }
else if (ED_node_is_compositor(snode))
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, snode->id);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
else if (ED_node_is_texture(snode))
- WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, snode->id);
+ WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
}
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
@@ -561,7 +564,7 @@ void snode_set_context(const bContext *C)
return;
}
- if (snode->nodetree && strcmp(snode->nodetree->idname, snode->tree_idname) != 0) {
+ if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
/* current tree does not match selected type, clear tree path */
ntree = NULL;
id = NULL;
@@ -662,11 +665,16 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
/* if active texture changed, free glsl materials */
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
Material *ma;
+ World *wo;
for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree))
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
+ for (wo = bmain->world.first; wo; wo = wo->id.next)
+ if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree))
+ GPU_material_free(&wo->gpumaterial);
+
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -695,7 +703,7 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
if (node->id == NULL || node->id == (ID *)scene) {
- int num_layers = BLI_countlist(&scene->r.layers);
+ int num_layers = BLI_listbase_count(&scene->r.layers);
scene->r.actlay = node->custom1;
/* Clamp the value, because it might have come from a different
* scene which could have more render layers than new one.
@@ -732,6 +740,34 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
+void ED_node_id_unref(SpaceNode *snode, const ID *id)
+{
+ if (GS(id->name) == ID_SCE) {
+ if (snode->id == id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ bNodeTreePath *path, *path_next;
+ for (path = snode->treepath.first; path; path = path_next) {
+ path_next = path->next;
+ MEM_freeN(path);
+ }
+ BLI_listbase_clear(&snode->treepath);
+
+ snode->id = NULL;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ }
+ }
+ else if (GS(id->name) == ID_OB) {
+ if (snode->from == id) {
+ snode->flag &= ~SNODE_PIN;
+ snode->from = NULL;
+ }
+ }
+}
+
void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
{
/* XXX This does not work due to layout functions relying on node->block,
@@ -1142,7 +1178,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
bNodeLink *link, *newlink, *lastlink;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
lastnode = ntree->nodes.last;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1277,7 +1313,7 @@ static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
Scene *curscene = CTX_data_scene(C), *scene;
bNode *node;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
/* first tag scenes unread */
for (scene = bmain->scene.first; scene; scene = scene->id.next)
@@ -1476,7 +1512,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
if ((snode == NULL) || (snode->edittree == NULL))
return OPERATOR_CANCELLED;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node_flag_toggle_exec(snode, NODE_PREVIEW);
@@ -1540,7 +1576,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
if ((snode == NULL) || (snode->edittree == NULL))
return OPERATOR_CANCELLED;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* Toggle for all selected nodes */
hidden = 0;
@@ -1588,7 +1624,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
for (node = snode->edittree->nodes.first; node; node = node->next) {
/* Only allow muting of nodes having a mute func! */
@@ -1626,7 +1662,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node, *next;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
for (node = snode->edittree->nodes.first; node; node = next) {
next = node->next;
@@ -1661,13 +1697,61 @@ void NODE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ****************** Switch View ******************* */
+
+static int node_switch_view_poll(bContext *C)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if (snode && snode->edittree)
+ return true;
+
+ return false;
+}
+
+static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node, *next;
+
+ for (node = snode->edittree->nodes.first; node; node = next) {
+ next = node->next;
+ if (node->flag & SELECT) {
+ /* call the update function from the Switch View node */
+ node->update = NODE_UPDATE_OPERATOR;
+ }
+ }
+
+ ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_switch_view_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Views";
+ ot->description = "Update views of selected node";
+ ot->idname = "NODE_OT_switch_view_update";
+
+ /* api callbacks */
+ ot->exec = node_switch_view_exec;
+ ot->poll = node_switch_view_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ****************** Delete with reconnect ******************* */
static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node, *next;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
for (node = snode->edittree->nodes.first; node; node = next) {
next = node->next;
@@ -1924,7 +2008,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
bNode *node;
bNodeLink *link, *newlink;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* clear current clipboard */
BKE_node_clipboard_clear();
@@ -2037,7 +2121,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
if (!all_nodes_valid)
return OPERATOR_CANCELLED;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* deselect old nodes */
node_deselect_all(snode);
@@ -2445,7 +2529,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
void *lock;
ImBuf *ibuf;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 96cc7fb4407..b57f95db4e6 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -39,7 +39,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_action.h"
#include "BKE_animsys.h"
@@ -55,7 +55,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -64,7 +63,6 @@
#include "node_intern.h" /* own include */
#include "NOD_common.h"
-#include "NOD_socket.h"
static int node_group_operator_active(bContext *C)
{
@@ -144,7 +142,7 @@ static int node_group_edit_exec(bContext *C, wmOperator *op)
bNode *gnode;
const bool exit = RNA_boolean_get(op->ptr, "exit");
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
gnode = node_group_get_active(C, node_idname);
@@ -352,7 +350,7 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
const char *node_idname = group_node_idname(C);
bNode *gnode;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
gnode = node_group_get_active(C, node_idname);
if (!gnode)
@@ -458,8 +456,8 @@ static int node_group_separate_selected(bNodeTree *ntree, bNodeTree *ngroup, flo
/* add internal links to the ntree */
for (link = ngroup->links.first; link; link = link_next) {
- int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
- int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
+ const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
+ const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
link_next = link->next;
if (make_copy) {
@@ -522,7 +520,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
int type = RNA_enum_get(op->ptr, "type");
float offx, offy;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* are we inside of a group? */
ngroup = snode->edittree;
@@ -562,16 +560,16 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
- uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY);
uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
void NODE_OT_group_separate(wmOperatorType *ot)
@@ -915,7 +913,7 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
bNode *gnode;
Main *bmain = CTX_data_main(C);
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
if (!node_group_make_test_selected(ntree, NULL, ntree_idname, op->reports))
return OPERATOR_CANCELLED;
@@ -966,7 +964,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
bNode *gnode;
Main *bmain = CTX_data_main(C);
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
gnode = node_group_get_active(C, node_idname);
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 9598ff190c0..b08c9b10eeb 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -42,12 +42,9 @@ struct ARegionType;
struct View2D;
struct bContext;
struct wmWindow;
-struct wmWindowManager;
-struct wmEvent;
struct bNode;
struct bNodeSocket;
struct bNodeLink;
-struct Main;
struct wmKeyConfig;
/* temp data to pass on to modal */
@@ -87,6 +84,7 @@ void drawnodespace(const bContext *C, ARegion *ar);
void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]);
/* DPI scaled coords */
void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry);
+void node_to_updated_rect(struct bNode *node, rctf *r_rect);
void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry);
/* node_buttons.c */
@@ -163,13 +161,14 @@ void NODE_OT_links_cut(struct wmOperatorType *ot);
void NODE_OT_links_detach(struct wmOperatorType *ot);
void NODE_OT_parent_set(struct wmOperatorType *ot);
-void NODE_OT_parent_clear(struct wmOperatorType *ot);
void NODE_OT_join(struct wmOperatorType *ot);
void NODE_OT_attach(struct wmOperatorType *ot);
void NODE_OT_detach(struct wmOperatorType *ot);
void NODE_OT_link_viewer(struct wmOperatorType *ot);
+void NODE_OT_insert_offset(wmOperatorType *ot);
+
/* node_edit.c */
void snode_notify(struct bContext *C, struct SpaceNode *snode);
void snode_dag_update(struct bContext *C, struct SpaceNode *snode);
@@ -204,6 +203,8 @@ void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
+void NODE_OT_switch_view_update (struct wmOperatorType *ot);
+
/* Note: clipboard_cut is a simple macro of copy + delete */
void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
@@ -227,7 +228,8 @@ extern const char *node_context_dir[];
#define NODE_DYS (U.widget_unit / 2)
#define NODE_DY U.widget_unit
#define NODE_SOCKDY (0.08f * U.widget_unit)
-#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
+#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
+#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
#define NODE_MARGIN_X (0.75f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
#define NODE_LINK_RESOL 12
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 7dcbeae4627..96f0e69ca71 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -92,6 +92,8 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_link_viewer);
+ WM_operatortype_append(NODE_OT_insert_offset);
+
WM_operatortype_append(NODE_OT_read_renderlayers);
WM_operatortype_append(NODE_OT_read_fullsamplelayers);
WM_operatortype_append(NODE_OT_render_changed);
@@ -111,7 +113,6 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_output_file_move_active_socket);
WM_operatortype_append(NODE_OT_parent_set);
- WM_operatortype_append(NODE_OT_parent_clear);
WM_operatortype_append(NODE_OT_join);
WM_operatortype_append(NODE_OT_attach);
WM_operatortype_append(NODE_OT_detach);
@@ -124,6 +125,8 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_viewer_border);
WM_operatortype_append(NODE_OT_clear_viewer_border);
+ WM_operatortype_append(NODE_OT_switch_view_update);
+
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
WM_operatortype_append(NODE_OT_tree_socket_move);
@@ -146,7 +149,22 @@ void ED_operatormacros_node(void)
mot = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(mot->ptr, "release_confirm", true);
WM_operatortype_macro_define(ot, "NODE_OT_attach");
+ WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
+
+ /* NODE_OT_translate_attach with remove_on_canel set to true */
+ ot = WM_operatortype_append_macro("NODE_OT_translate_attach_remove_on_cancel", "Move and Attach",
+ "Move nodes and attach to frame",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ mot = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(mot->ptr, "release_confirm", true);
+ RNA_boolean_set(mot->ptr, "remove_on_cancel", true);
+ WM_operatortype_macro_define(ot, "NODE_OT_attach");
+ WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
+ /* Note: Currently not in a default keymap or menu due to messy keymaps
+ * and tricky invoke functionality.
+ * Kept around in case users want to make own shortcuts.
+ */
ot = WM_operatortype_append_macro("NODE_OT_detach_translate_attach", "Detach and Move",
"Detach nodes, move and attach to frame",
OPTYPE_UNDO | OPTYPE_REGISTER);
@@ -173,6 +191,7 @@ void ED_operatormacros_node(void)
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "NODE_OT_links_detach");
WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
ot = WM_operatortype_append_macro("NODE_OT_move_detach_links_release", "Detach", "Move a node to detach links",
OPTYPE_UNDO | OPTYPE_REGISTER);
@@ -267,7 +286,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_duplicate_move_keep_inputs", DKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
WM_keymap_add_item(keymap, "NODE_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_parent_clear", PKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_detach", PKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "NODE_OT_join", JKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "NODE_OT_hide_toggle", HKEY, KM_PRESS, 0, 0);
@@ -311,7 +330,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_group_separate", PKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "exit", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "exit", true);
WM_keymap_add_item(keymap, "NODE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 973ce56857c..a9f126a75e2 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -37,6 +37,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_easing.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -45,6 +46,7 @@
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_render.h"
+#include "ED_util.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -53,11 +55,11 @@
#include "WM_types.h"
#include "UI_view2d.h"
+#include "UI_resources.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "node_intern.h" /* own include */
-#include "NOD_common.h"
/* ****************** Add *********************** */
@@ -67,6 +69,17 @@ typedef struct bNodeListItem {
struct bNode *node;
} bNodeListItem;
+typedef struct NodeInsertOfsData {
+ bNodeTree *ntree;
+ bNode *insert; /* inserted node */
+ bNode *prev, *next; /* prev/next node in the chain */
+ bNode *insert_parent;
+
+ wmTimer *anim_timer;
+
+ float offset_x; /* offset to apply to node chain */
+} NodeInsertOfsData;
+
static int sort_nodes_locx(const void *a, const void *b)
{
const bNodeListItem *nli1 = a;
@@ -203,7 +216,7 @@ static void snode_autoconnect(SpaceNode *snode, const bool allow_multiple, const
}
/* sort nodes left to right */
- BLI_sortlist(nodelist, sort_nodes_locx);
+ BLI_listbase_sort(nodelist, sort_nodes_locx);
for (nli = nodelist->first; nli; nli = nli->next) {
bNode *node_fr, *node_to;
@@ -236,7 +249,7 @@ static void snode_autoconnect(SpaceNode *snode, const bool allow_multiple, const
if (!has_selected_inputs) {
/* no selected inputs, connect by finding suitable match */
- int num_inputs = BLI_countlist(&node_to->inputs);
+ int num_inputs = BLI_listbase_count(&node_to->inputs);
for (i = 0; i < num_inputs; i++) {
@@ -368,7 +381,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
if (!node)
return OPERATOR_CANCELLED;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
if (node_link_viewer(C, node) == OPERATOR_CANCELLED)
return OPERATOR_CANCELLED;
@@ -747,7 +760,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
&cursor[0], &cursor[1]);
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
nldrag = node_link_init(snode, cursor, detach);
@@ -803,7 +816,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
const bool replace = RNA_boolean_get(op->ptr, "replace");
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
snode_autoconnect(snode, 1, replace);
@@ -874,7 +887,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
bool found = false;
bNodeLink *link, *next;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
for (link = snode->edittree->links.first; link; link = next) {
next = link->next;
@@ -884,7 +897,8 @@ static int cut_links_exec(bContext *C, wmOperator *op)
if (cut_links_intersect(link, mcoords, i)) {
if (found == false) {
- ED_preview_kill_jobs(C);
+ /* TODO(sergey): Why did we kill jobs twice? */
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
found = true;
}
@@ -941,7 +955,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *ntree = snode->edittree;
bNode *node;
- ED_preview_kill_jobs(C);
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
for (node = ntree->nodes.first; node; node = node->next) {
if (node->flag & SELECT) {
@@ -1011,40 +1025,6 @@ void NODE_OT_parent_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****************** Clear Parent ******************* */
-
-static int node_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->flag & NODE_SELECT) {
- nodeDetachNode(node);
- }
- }
-
- WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void NODE_OT_parent_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Parent";
- ot->description = "Detach selected nodes";
- ot->idname = "NODE_OT_parent_clear";
-
- /* api callbacks */
- ot->exec = node_parent_clear_exec;
- ot->poll = ED_operator_node_editable;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ****************** Join Nodes ******************* */
/* tags for depth-first search */
@@ -1133,25 +1113,33 @@ void NODE_OT_join(wmOperatorType *ot)
/* ****************** Attach ******************* */
-static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static bNode *node_find_frame_to_attach(ARegion *ar, const bNodeTree *ntree, const int mouse_xy[2])
{
- ARegion *ar = CTX_wm_region(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
bNode *frame;
float cursor[2];
-
+
/* convert mouse coordinates to v2d space */
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&ar->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
/* check nodes front to back */
for (frame = ntree->nodes.last; frame; frame = frame->prev) {
/* skip selected, those are the nodes we want to attach */
if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT))
continue;
- if (BLI_rctf_isect_pt(&frame->totr, cursor[0], cursor[1]))
- break;
+ if (BLI_rctf_isect_pt_v(&frame->totr, cursor))
+ return frame;
}
+
+ return NULL;
+}
+
+static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *ntree = snode->edittree;
+ bNode *frame = node_find_frame_to_attach(ar, ntree, event->mval);
+
if (frame) {
bNode *node, *parent;
for (node = ntree->nodes.last; node; node = node->prev) {
@@ -1332,7 +1320,7 @@ void ED_node_link_intersect_test(ScrArea *sa, int test)
bNode *select;
SpaceNode *snode;
bNodeLink *link, *selink = NULL;
- float mcoords[6][2];
+ float dist_best = FLT_MAX;
if (!ed_node_link_conditions(sa, test, &snode, &select)) return;
@@ -1342,34 +1330,40 @@ void ED_node_link_intersect_test(ScrArea *sa, int test)
if (test == 0) return;
- /* okay, there's 1 node, without links, now intersect */
- mcoords[0][0] = select->totr.xmin;
- mcoords[0][1] = select->totr.ymin;
- mcoords[1][0] = select->totr.xmax;
- mcoords[1][1] = select->totr.ymin;
- mcoords[2][0] = select->totr.xmax;
- mcoords[2][1] = select->totr.ymax;
- mcoords[3][0] = select->totr.xmin;
- mcoords[3][1] = select->totr.ymax;
- mcoords[4][0] = select->totr.xmin;
- mcoords[4][1] = select->totr.ymin;
- mcoords[5][0] = select->totr.xmax;
- mcoords[5][1] = select->totr.ymax;
-
- /* we only tag a single link for intersect now */
- /* idea; use header dist when more? */
+ /* find link to select/highlight */
for (link = snode->edittree->links.first; link; link = link->next) {
+ float coord_array[NODE_LINK_RESOL + 1][2];
+
if (nodeLinkIsHidden(link))
continue;
-
- if (cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */
- if (selink)
- break;
- selink = link;
+
+ if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
+ float dist = FLT_MAX;
+ int i;
+
+ /* loop over link coords to find shortest dist to upper left node edge of a intersected line segment */
+ for (i = 0; i < NODE_LINK_RESOL; i++) {
+ /* check if the node rect intersetcts the line from this point to next one */
+ if (BLI_rctf_isect_segment(&select->totr, coord_array[i], coord_array[i + 1])) {
+ /* store the shortest distance to the upper left edge of all intersetctions found so far */
+ const float node_xy[] = {select->totr.xmin, select->totr.ymax};
+
+ /* to be precise coord_array should be clipped by select->totr,
+ * but not done since there's no real noticeable difference */
+ dist = min_ff(dist_squared_to_line_segment_v2(node_xy, coord_array[i], coord_array[i + 1]),
+ dist);
+ }
+ }
+
+ /* we want the link with the shortest distance to node center */
+ if (dist < dist_best) {
+ dist_best = dist;
+ selink = link;
+ }
}
}
- if (link == NULL && selink)
+ if (selink)
selink->flag |= NODE_LINKFLAG_HILITE;
}
@@ -1405,6 +1399,323 @@ static bNodeSocket *socket_best_match(ListBase *sockets)
return NULL;
}
+static bool node_parents_offset_flag_enable_cb(bNode *parent, void *UNUSED(userdata))
+{
+ /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
+ parent->flag |= NODE_TEST;
+
+ return true;
+}
+
+static void node_offset_apply(bNode *node, const float offset_x)
+{
+ /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
+ if ((node->flag & NODE_TEST) == 0) {
+ node->anim_init_locx = node->locx;
+ node->anim_ofsx = (offset_x / UI_DPI_FAC);
+ node->flag |= NODE_TEST;
+ }
+}
+
+static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, const float offset_x)
+{
+ bNode *node;
+
+ node_offset_apply(parent, offset_x);
+
+ /* flag all childs as offset to prevent them from being offset
+ * separately (they've already moved with the parent) */
+ for (node = data->ntree->nodes.first; node; node = node->next) {
+ if (nodeIsChildOf(parent, node)) {
+ /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
+ node->flag |= NODE_TEST;
+ }
+ }
+}
+
+#define NODE_INSOFS_ANIM_DURATION 0.25f
+
+/**
+ * Callback that applies NodeInsertOfsData.offset_x to a node or its parent, similar
+ * to node_link_insert_offset_output_chain_cb below, but with slightly different logic
+ */
+static bool node_link_insert_offset_frame_chain_cb(
+ bNode *fromnode, bNode *tonode,
+ void *userdata,
+ const bool reversed)
+{
+ NodeInsertOfsData *data = userdata;
+ bNode *ofs_node = reversed ? fromnode : tonode;
+
+ if (ofs_node->parent && ofs_node->parent != data->insert_parent) {
+ node_offset_apply(ofs_node->parent, data->offset_x);
+ }
+ else {
+ node_offset_apply(ofs_node, data->offset_x);
+ }
+
+ return true;
+}
+
+/**
+ * Applies NodeInsertOfsData.offset_x to all childs of \a parent
+ */
+static void node_link_insert_offset_frame_chains(
+ const bNodeTree *ntree, const bNode *parent,
+ NodeInsertOfsData *data,
+ const bool reversed)
+{
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (nodeIsChildOf(parent, node)) {
+ nodeChainIter(ntree, node, node_link_insert_offset_frame_chain_cb, data, reversed);
+ }
+ }
+}
+
+/**
+ * Callback that applies NodeInsertOfsData.offset_x to a node or its parent,
+ * considering the logic needed for offseting nodes after link insert
+ */
+static bool node_link_insert_offset_chain_cb(
+ bNode *fromnode, bNode *tonode,
+ void *userdata,
+ const bool reversed)
+{
+ NodeInsertOfsData *data = userdata;
+ bNode *ofs_node = reversed ? fromnode : tonode;
+
+ if (data->insert_parent) {
+ if (ofs_node->parent && (ofs_node->parent->flag & NODE_TEST) == 0) {
+ node_parent_offset_apply(data, ofs_node->parent, data->offset_x);
+ node_link_insert_offset_frame_chains(data->ntree, ofs_node->parent, data, reversed);
+ }
+ else {
+ node_offset_apply(ofs_node, data->offset_x);
+ }
+
+ if (nodeIsChildOf(data->insert_parent, ofs_node) == false) {
+ data->insert_parent = NULL;
+ }
+ }
+ else if (ofs_node->parent) {
+ bNode *node = nodeFindRootParent(ofs_node);
+ node_offset_apply(node, data->offset_x);
+ }
+ else {
+ node_offset_apply(ofs_node, data->offset_x);
+ }
+
+ return true;
+}
+
+static void node_link_insert_offset_ntree(
+ NodeInsertOfsData *iofsd, ARegion *ar,
+ const int mouse_xy[2], const bool right_alignment)
+{
+ bNodeTree *ntree = iofsd->ntree;
+ bNode *insert = iofsd->insert;
+ bNode *prev = iofsd->prev, *next = iofsd->next;
+ bNode *init_parent = insert->parent; /* store old insert->parent for restoring later */
+ rctf totr_insert;
+
+ const float min_margin = U.node_margin * UI_DPI_FAC;
+ const float width = NODE_WIDTH(insert);
+ const bool needs_alignment = (next->totr.xmin - prev->totr.xmax) < (width + (min_margin * 2.0f));
+
+ float margin = width;
+ float dist, addval;
+
+
+ /* NODE_TEST will be used later, so disable for all nodes */
+ ntreeNodeFlagSet(ntree, NODE_TEST, false);
+
+ /* insert->totr isn't updated yet, so totr_insert is used to get the correct worldspace coords */
+ node_to_updated_rect(insert, &totr_insert);
+
+ /* frame attachement was't handled yet so we search the frame that the node will be attached to later */
+ insert->parent = node_find_frame_to_attach(ar, ntree, mouse_xy);
+
+ /* this makes sure nodes are also correctly offset when inserting a node on top of a frame
+ * without actually making it a part of the frame (because mouse isn't intersecting it)
+ * - logic here is similar to node_find_frame_to_attach */
+ if (!insert->parent ||
+ (prev->parent && (prev->parent == next->parent) && (prev->parent != insert->parent)))
+ {
+ bNode *frame;
+ rctf totr_frame;
+
+ /* check nodes front to back */
+ for (frame = ntree->nodes.last; frame; frame = frame->prev) {
+ /* skip selected, those are the nodes we want to attach */
+ if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT))
+ continue;
+
+ /* for some reason frame y coords aren't correct yet */
+ node_to_updated_rect(frame, &totr_frame);
+
+ if (BLI_rctf_isect_x(&totr_frame, totr_insert.xmin) &&
+ BLI_rctf_isect_x(&totr_frame, totr_insert.xmax))
+ {
+ if (BLI_rctf_isect_y(&totr_frame, totr_insert.ymin) ||
+ BLI_rctf_isect_y(&totr_frame, totr_insert.ymax))
+ {
+ /* frame isn't insert->parent actually, but this is needed to make offsetting
+ * nodes work correctly for above checked cases (it is restored later) */
+ insert->parent = frame;
+ break;
+ }
+ }
+ }
+ }
+
+
+ /* *** ensure offset at the left (or right for right_alignment case) of insert_node *** */
+
+ dist = right_alignment ? totr_insert.xmin - prev->totr.xmax : next->totr.xmin - totr_insert.xmax;
+ /* distance between insert_node and prev is smaller than min margin */
+ if (dist < min_margin) {
+ addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
+
+ node_offset_apply(insert, addval);
+
+ totr_insert.xmin += addval;
+ totr_insert.xmax += addval;
+ margin += min_margin;
+ }
+
+ /* *** ensure offset at the right (or left for right_alignment case) of insert_node *** */
+
+ dist = right_alignment ? next->totr.xmin - totr_insert.xmax : totr_insert.xmin - prev->totr.xmax;
+ /* distance between insert_node and next is smaller than min margin */
+ if (dist < min_margin) {
+ addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
+ if (needs_alignment) {
+ bNode *offs_node = right_alignment ? next : prev;
+ if (!offs_node->parent ||
+ offs_node->parent == insert->parent ||
+ nodeIsChildOf(offs_node->parent, insert))
+ {
+ node_offset_apply(offs_node, addval);
+ }
+ else if (!insert->parent && offs_node->parent) {
+ node_offset_apply(nodeFindRootParent(offs_node), addval);
+ }
+ margin = addval;
+ }
+ /* enough room is available, but we want to ensure the min margin at the right */
+ else {
+ /* offset inserted node so that min margin is kept at the right */
+ node_offset_apply(insert, -addval);
+ }
+ }
+
+
+ if (needs_alignment) {
+ iofsd->insert_parent = insert->parent;
+ iofsd->offset_x = margin;
+
+ /* flag all parents of insert as offset to prevent them from being offset */
+ nodeParentsIter(insert, node_parents_offset_flag_enable_cb, NULL);
+ /* iterate over entire chain and apply offsets */
+ nodeChainIter(ntree, right_alignment ? next : prev, node_link_insert_offset_chain_cb, iofsd, !right_alignment);
+ }
+
+ insert->parent = init_parent;
+}
+
+/**
+ * Modal handler for insert offset animation
+ */
+static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ NodeInsertOfsData *iofsd = snode->iofsd;
+ bNode *node;
+ float duration;
+ bool redraw = false;
+
+ if (!snode || event->type != TIMER || iofsd->anim_timer != event->customdata)
+ return OPERATOR_PASS_THROUGH;
+
+ duration = (float)iofsd->anim_timer->duration;
+
+ /* handle animation - do this before possibly aborting due to duration, since
+ * main thread might be so busy that node hasn't reached final position yet */
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if (UNLIKELY(node->anim_ofsx)) {
+ const float endval = node->anim_init_locx + node->anim_ofsx;
+ if (node->locx < endval) {
+ node->locx = BLI_easing_cubic_ease_in_out(duration, node->anim_init_locx, node->anim_ofsx,
+ NODE_INSOFS_ANIM_DURATION);
+ CLAMP_MAX(node->locx, endval);
+ redraw = true;
+ }
+ }
+ }
+ if (redraw) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
+
+ /* end timer + free insert offset data */
+ if (duration > NODE_INSOFS_ANIM_DURATION) {
+ WM_event_remove_timer(CTX_wm_manager(C), NULL, iofsd->anim_timer);
+
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ node->anim_init_locx = node->anim_ofsx = 0.0f;
+ }
+
+ snode->iofsd = NULL;
+ MEM_freeN(iofsd);
+
+ return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+#undef NODE_INSOFS_ANIM_DURATION
+
+static int node_insert_offset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const SpaceNode *snode = CTX_wm_space_node(C);
+ NodeInsertOfsData *iofsd = snode->iofsd;
+
+ if (!iofsd || !iofsd->insert)
+ return OPERATOR_CANCELLED;
+
+ BLI_assert((snode->flag & SNODE_SKIP_INSOFFSET) == 0);
+
+ iofsd->ntree = snode->edittree;
+ iofsd->anim_timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.02);
+
+ node_link_insert_offset_ntree(
+ iofsd, CTX_wm_region(C),
+ event->mval, (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT));
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void NODE_OT_insert_offset(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Insert Offset";
+ ot->description = "Automatically offset nodes on insertion";
+ ot->idname = "NODE_OT_insert_offset";
+
+ /* callbacks */
+ ot->invoke = node_insert_offset_invoke;
+ ot->modal = node_insert_offset_modal;
+ ot->poll = ED_operator_node_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+}
+
/* assumes link with NODE_LINKFLAG_HILITE set */
void ED_node_link_insert(ScrArea *sa)
{
@@ -1435,6 +1746,17 @@ void ED_node_link_insert(ScrArea *sa)
nodeAddLink(snode->edittree, select, best_output, node, sockto);
+ /* set up insert offset data, it needs stuff from here */
+ if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
+ NodeInsertOfsData *iofsd = MEM_callocN(sizeof(NodeInsertOfsData), __func__);
+
+ iofsd->insert = select;
+ iofsd->prev = link->fromnode;
+ iofsd->next = node;
+
+ snode->iofsd = iofsd;
+ }
+
ntreeUpdateTree(G.main, snode->edittree); /* needed for pointers */
snode_update(snode, select);
ED_node_tag_update_id(snode->id);
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index de580f612a0..78302fedd97 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -249,9 +249,9 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
bool changed = false;
const unsigned int delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
- char *sep, *suf_act, *suf_curr;
+ const char *sep, *suf_act, *suf_curr;
- pref_len_act = BLI_str_partition_ex_utf8(node_act->name, delims, &sep, &suf_act, from_right);
+ pref_len_act = BLI_str_partition_ex_utf8(node_act->name, NULL, delims, &sep, &suf_act, from_right);
/* Note: in case we are searching for suffix, and found none, use whole name as suffix. */
if (from_right && !(sep && suf_act)) {
@@ -263,7 +263,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
if (node->flag & SELECT) {
continue;
}
- pref_len_curr = BLI_str_partition_ex_utf8(node->name, delims, &sep, &suf_curr, from_right);
+ pref_len_curr = BLI_str_partition_ex_utf8(node->name, NULL, delims, &sep, &suf_curr, from_right);
/* Same as with active node name! */
if (from_right && !(sep && suf_curr)) {
@@ -972,7 +972,7 @@ static void node_find_cb(const struct bContext *C, void *UNUSED(arg), const char
BLI_snprintf(name, 256, "%s (%s)", node->name, node->label);
else
BLI_strncpy(name, node->name, 256);
- if (false == uiSearchItemAdd(items, name, node, 0))
+ if (false == UI_search_item_add(items, name, node, 0))
break;
}
}
@@ -1006,18 +1006,18 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
uiBut *but;
wmOperator *op = (wmOperator *)arg_op;
- block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
- uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9 * UI_UNIT_X, UI_UNIT_Y, 0, 0, "");
- uiButSetSearchFunc(but, node_find_cb, op->type, node_find_call_cb, NULL);
+ UI_but_func_search_set(but, node_find_cb, op->type, node_find_call_cb, NULL);
/* fake button, it holds space for search items */
- uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
- uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
+ UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
- // uiButActiveOnly(C, ar, block, but); XXX using this here makes Blender hang - investigate
+ // UI_but_active_only(C, ar, block, but); XXX using this here makes Blender hang - investigate
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_OPEN;
event.val = KM_PRESS;
@@ -1031,7 +1031,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
static int node_find_node_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- uiPupBlock(C, node_find_menu, op);
+ UI_popup_block_invoke(C, node_find_menu, op);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 99a481e5d82..f2293754608 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -24,18 +24,18 @@
* \ingroup edinterface
*/
+#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -54,7 +54,6 @@
#include "ED_util.h"
-#include "node_intern.h"
/************************* Node Socket Manipulation **************************/
@@ -216,8 +215,22 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *
}
else if (!node_from) {
node_from = nodeAddStaticNode(C, ntree, type);
- node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
- node_from->locy = node_to->locy;
+ if (node_prev != NULL) {
+ /* If we're replacing existing node, use it's location. */
+ node_from->locx = node_prev->locx;
+ node_from->locy = node_prev->locy;
+ node_from->offsetx = node_prev->offsetx;
+ node_from->offsety = node_prev->offsety;
+ }
+ else {
+ /* Avoid exact intersection of nodes.
+ * TODO(sergey): Still not ideal, but better than nothing.
+ */
+ int index = BLI_findindex(&node_to->inputs, sock_to);
+ BLI_assert(index != -1);
+ node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
+ node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
+ }
node_link_item_apply(node_from, item);
}
@@ -300,7 +313,7 @@ static void ui_node_link_items(NodeLinkArg *arg, int in_out, NodeLinkItem **r_it
for (ngroup = arg->bmain->nodetree.first; ngroup; ngroup = ngroup->id.next) {
ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
- totitems += BLI_countlist(lb);
+ totitems += BLI_listbase_count(lb);
}
if (totitems > 0) {
@@ -454,7 +467,7 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
if (first) {
column = uiLayoutColumn(layout, 0);
- uiBlockSetCurLayout(block, column);
+ UI_block_layout_set_current(block, column);
uiItemL(column, IFACE_(cname), ICON_NODE);
but = block->buttons.last;
@@ -466,7 +479,7 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) {
cur_node_name = items[i].node_name;
/* XXX Do not use uiItemL here, it would add an empty icon as we are in a menu! */
- uiDefBut(block, LABEL, 0, IFACE_(cur_node_name), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_(cur_node_name), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, "");
}
@@ -478,12 +491,12 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
icon = ICON_NONE;
}
- but = uiDefIconTextBut(block, BUT, 0, icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Add node to input"));
argN = MEM_dupallocN(arg);
argN->item = items[i];
- uiButSetNFunc(but, ui_node_link, argN, NULL);
+ UI_but_funcN_set(but, ui_node_link, argN, NULL);
}
if (items)
@@ -511,8 +524,8 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
bNodeSocket *sock = arg->sock;
bNodeTreeType *ntreetype = arg->ntree->typeinfo;
- uiBlockSetFlag(block, UI_BLOCK_NO_FLIP);
- uiBlockSetCurLayout(block, layout);
+ UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
+ UI_block_layout_set_current(block, layout);
split = uiLayoutSplit(layout, 0.0f, false);
arg->bmain = bmain;
@@ -523,20 +536,20 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
column = uiLayoutColumn(split, false);
- uiBlockSetCurLayout(block, column);
+ UI_block_layout_set_current(block, column);
if (sock->link) {
uiItemL(column, IFACE_("Link"), ICON_NONE);
but = block->buttons.last;
but->drawflag = UI_BUT_TEXT_LEFT;
- but = uiDefBut(block, BUT, 0, IFACE_("Remove"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
+ but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Remove"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Remove nodes connected to the input"));
- uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
+ UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
- but = uiDefBut(block, BUT, 0, IFACE_("Disconnect"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
+ but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Disconnect"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Disconnect nodes connected to the input"));
- uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
+ UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
}
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
@@ -553,7 +566,7 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
arg->node = node;
arg->sock = sock;
- uiBlockSetCurLayout(block, layout);
+ UI_block_layout_set_current(block, layout);
if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
char name[UI_MAX_NAME_STR];
@@ -563,7 +576,7 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
else
but = uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
- uiButSetMenuFromPulldown(but);
+ UI_but_type_set_menu_from_pulldown(but);
but->flag |= UI_BUT_NODE_LINK;
but->poin = (char *)but;
@@ -609,7 +622,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
uiLayout *split, *row, *col;
bNode *lnode;
char label[UI_MAX_NAME_STR];
- int indent = (depth > 1) ? 2 * (depth - 1) : 0;
+ int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
int dependency_loop;
if (input->flag & SOCK_UNAVAIL)
@@ -628,7 +641,8 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
/* indented label */
- memset(label, ' ', indent);
+ for (i = 0; i < indent; i++)
+ label[i] = ' ';
label[indent] = '\0';
BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, IFACE_(input->name));
@@ -638,7 +652,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
row = uiLayoutRow(split, true);
if (depth > 0) {
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
if (lnode && (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : ICON_DISCLOSURE_TRI_DOWN;
@@ -650,7 +664,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
bt = block->buttons.last;
bt->rect.xmax = UI_UNIT_X / 2;
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
uiItemL(row, label, ICON_NONE);
diff --git a/source/blender/editors/space_node/node_toolbar.c b/source/blender/editors/space_node/node_toolbar.c
index dd5bad3f8ad..e3e263f2e44 100644
--- a/source/blender/editors/space_node/node_toolbar.c
+++ b/source/blender/editors/space_node/node_toolbar.c
@@ -28,27 +28,18 @@
* \ingroup nodes
*/
-
-#include "MEM_guardedalloc.h"
-
#include "BLI_utildefines.h"
#include "DNA_node_types.h"
#include "BKE_context.h"
-#include "BKE_node.h"
#include "BKE_screen.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "RNA_access.h"
-
#include "ED_screen.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
-
#include "node_intern.h" /* own include */
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 3491ecc86af..8c5d2d82468 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -292,7 +292,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot)
ot->cancel = snode_bg_viewmove_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
static int backimage_zoom_exec(bContext *C, wmOperator *op)
@@ -609,8 +609,11 @@ static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: // XXX hardcoded
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
sample_apply(C, op, event);
break;
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index ccaeae34927..b9b925f1829 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -28,8 +28,6 @@
* \ingroup spnode
*/
-
-
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -152,7 +150,7 @@ void ED_node_tree_pop(SpaceNode *snode)
int ED_node_tree_depth(SpaceNode *snode)
{
- return BLI_countlist(&snode->treepath);
+ return BLI_listbase_count(&snode->treepath);
}
bNodeTree *ED_node_tree_get(SpaceNode *snode, int level)
@@ -205,12 +203,10 @@ void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_lengt
value[0] = '\0';
for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
if (i == 0) {
- BLI_strncpy(value, path->node_name, max_length);
- size = strlen(path->node_name);
+ size = BLI_strncpy_rlen(value, path->node_name, max_length);
}
else {
- BLI_snprintf(value, max_length, "/%s", path->node_name);
- size = strlen(path->node_name) + 1;
+ size = BLI_snprintf_rlen(value, max_length, "/%s", path->node_name);
}
max_length -= size;
if (max_length <= 0)
@@ -515,6 +511,11 @@ static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
ED_area_tag_refresh(sa);
}
break;
+ case NC_GPENCIL:
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
+ ED_area_tag_redraw(sa);
+ }
+ break;
}
}
@@ -597,7 +598,7 @@ static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void node_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
/* add handlers, stuff you only do once or on area/region changes */
@@ -613,7 +614,7 @@ static void node_toolbar_area_init(wmWindowManager *wm, ARegion *ar)
static void node_toolbar_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
@@ -665,12 +666,12 @@ static void node_main_area_draw(const bContext *C, ARegion *ar)
static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_IM)
return 1;
}
else if (drag->type == WM_DRAG_PATH) {
- if (ELEM(drag->icon, 0, ICON_FILE_IMAGE)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */
return 1;
}
return 0;
@@ -679,7 +680,7 @@ static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *
static int node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MSK)
return 1;
}
@@ -688,20 +689,22 @@ static int node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
+ RNA_struct_property_unset(drop->ptr, "filepath");
}
- if (drag->path[0]) {
+ else if (drag->path[0]) {
RNA_string_set(drop->ptr, "filepath", drag->path);
+ RNA_struct_property_unset(drop->ptr, "name");
}
}
@@ -768,6 +771,8 @@ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi
case NC_GPENCIL:
if (wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
+ else if (wmn->data & ND_GPENCIL_EDITMODE)
+ ED_region_tag_redraw(ar);
break;
}
}
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 4db47b75502..289d6e715e1 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -22,12 +22,14 @@ set(INC
../include
../../blenkernel
../../blenlib
- ../../blenfont
+ ../../blentranslation
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -50,4 +52,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_outliner "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_outliner/SConscript b/source/blender/editors/space_outliner/SConscript
index db8041f0235..dce559a21df 100644
--- a/source/blender/editors/space_outliner/SConscript
+++ b/source/blender/editors/space_outliner/SConscript
@@ -28,15 +28,19 @@
Import ('env')
sources = env.Glob('*.c')
+
defs = []
+defs == env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 7eb90953df4..ac9e2e36ded 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -29,7 +29,9 @@
* \ingroup spoutliner
*/
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
@@ -41,11 +43,12 @@
#include "BLI_utildefines.h"
#include "BLI_mempool.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -55,6 +58,7 @@
#include "BKE_object.h"
#include "ED_armature.h"
+#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -168,20 +172,51 @@ static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bon
}
static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag,
- bool state, bool deselect)
+ bool state, bool deselect, const char *rnapropname)
{
Main *bmain = CTX_data_main(C);
Object *ob;
+
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (BKE_object_is_child_recursive(ob_parent, ob)) {
- if (state) {
- ob->restrictflag |= flag;
- if (deselect) {
- ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
+ /* only do if child object is selectable */
+ if ((flag == OB_RESTRICT_SELECT) || (ob->restrictflag & OB_RESTRICT_SELECT) == 0) {
+ if (state) {
+ ob->restrictflag |= flag;
+ if (deselect) {
+ ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
+ }
+ }
+ else {
+ ob->restrictflag &= ~flag;
}
}
- else {
- ob->restrictflag &= ~flag;
+
+ if (rnapropname) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ bAction *action;
+ FCurve *fcu;
+ bool driven, special;
+
+ RNA_id_pointer_create(&ob->id, &ptr);
+ prop = RNA_struct_find_property(&ptr, rnapropname);
+ fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven, &special);
+
+ if (fcu && !driven) {
+ id = ptr.id.data;
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ short flag = ANIM_get_keyframing_flags(scene, 1);
+
+ fcu->flag &= ~FCURVE_SELECTED;
+ insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, fcu->array_index, CFRA, flag);
+ /* Assuming this is not necessary here, since 'ancestor' object button will do it anyway. */
+ /* WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); */
+ }
+ }
}
}
}
@@ -203,7 +238,7 @@ static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW,
- (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true);
+ (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true, "hide");
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -226,7 +261,7 @@ static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT,
- (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true);
+ (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true, NULL);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -239,7 +274,7 @@ static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER,
- (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false);
+ (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false, "hide_render");
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin);
@@ -255,8 +290,7 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
Object *ob = (Object *)poin2;
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
@@ -316,6 +350,11 @@ static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin),
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
+static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), void *UNUSED(poin2))
+{
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
static int group_restrict_flag(Group *gr, int flag)
{
GroupObject *gob;
@@ -407,6 +446,20 @@ static void restrictbutton_gr_restrict_render(bContext *C, void *poin, void *poi
WM_event_add_notifier(C, NC_GROUP, NULL);
}
+static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
+{
+ ID *id = (ID *)poin;
+
+ BLI_assert(id != NULL);
+
+ if (id->flag & LIB_FAKEUSER) {
+ id_us_plus(id);
+ }
+ else {
+ id_us_min(id);
+ }
+}
+
static void namebutton_cb(bContext *C, void *tsep, char *oldname)
{
@@ -417,7 +470,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
TreeStoreElem *tselem = tsep;
if (ts && tselem) {
- TreeElement *te = outliner_find_tse(soops, tselem);
+ TreeElement *te = outliner_find_tree_element(&soops->tree, tselem);
if (tselem->type == 0) {
test_idbutton(tselem->id->name); // library.c, unique name and alpha sort
@@ -514,11 +567,22 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id; // id = object
bActionGroup *grp = te->directdata;
- BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLF_I18NCONTEXT_ID_ACTION, "Group"), '.',
+ BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), '.',
offsetof(bActionGroup, name), sizeof(grp->name));
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
break;
}
+ case TSE_GP_LAYER:
+ {
+ bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock
+ bGPDlayer *gpl = te->directdata;
+
+ // XXX: name needs translation stuff
+ BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.',
+ offsetof(bGPDlayer, info), sizeof(gpl->info));
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd);
+ break;
+ }
case TSE_R_LAYER:
break;
}
@@ -554,29 +618,29 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
ob = (Object *)tselem->id;
RNA_pointer_create((ID *)ob, &RNA_Object, ob, &ptr);
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButR_prop(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&ptr, object_prop_hide, -1, 0, 0, -1, -1,
TIP_("Restrict viewport visibility (Ctrl - Recursive)"));
- uiButSetFunc(bt, restrictbutton_view_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_view_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButR_prop(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&ptr, object_prop_hide_select, -1, 0, 0, -1, -1,
TIP_("Restrict viewport selection (Ctrl - Recursive)"));
- uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_sel_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButR_prop(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&ptr, object_prop_hide_render, -1, 0, 0, -1, -1,
TIP_("Restrict rendering (Ctrl - Recursive)"));
- uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_rend_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
if (tselem->type == 0 && te->idcode == ID_GR) {
@@ -587,130 +651,153 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
if (gr->id.lib)
but_flag |= UI_BUT_DISABLED;
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW);
- bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
+ bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr);
- uiButSetFlag(bt, but_flag);
+ UI_but_func_set(bt, restrictbutton_gr_restrict_view, scene, gr);
+ UI_but_flag_enable(bt, but_flag);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT);
- bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View"));
- uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr);
- uiButSetFlag(bt, but_flag);
+ UI_but_func_set(bt, restrictbutton_gr_restrict_select, scene, gr);
+ UI_but_flag_enable(bt, but_flag);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER);
- bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
- uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr);
- uiButSetFlag(bt, but_flag);
+ UI_but_func_set(bt, restrictbutton_gr_restrict_render, scene, gr);
+ UI_but_flag_enable(bt, but_flag);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
/* scene render layers and passes have toggle-able flags too! */
else if (tselem->type == TSE_R_LAYER) {
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer"));
- uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_R_PASS) {
int *layflag = te->directdata;
int passflag = 1 << tselem->nr;
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, passflag, 0, ICON_CHECKBOX_HLT - 1,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass"));
- uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
layflag++; /* is lay_xor */
if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
{
- bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
+ bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined"));
- uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_MODIFIER) {
ModifierData *md = (ModifierData *)te->directdata;
ob = (Object *)tselem->id;
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(md->mode), 0, 0, 0, 0,
TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
- uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_POSE_CHANNEL) {
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
ob = (Object *)tselem->id;
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow selection in the 3D View"));
- uiButSetFunc(bt, restrictbutton_bone_select_cb, ob->data, bone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_EBONE) {
EditBone *ebone = (EditBone *)te->directdata;
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow selection in the 3D View"));
- uiButSetFunc(bt, restrictbutton_ebone_select_cb, NULL, ebone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
+ else if (tselem->type == TSE_GP_LAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)te->directdata;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_RESTRICT_VIEW_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
+ UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow editing of strokes and keyframes in this layer"));
+ UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ /* TODO: visibility in renders */
+
+ UI_block_emboss_set(block, UI_EMBOSS);
}
}
@@ -718,6 +805,66 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
}
}
+static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb)
+{
+ uiBut *bt;
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for (te = lb->first; te; te = te->next) {
+ tselem = TREESTORE(te);
+ if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
+ if (tselem->type == 0) {
+ ID *id = tselem->id;
+ const char *tip = NULL;
+ int icon = ICON_NONE;
+ char buf[16] = "";
+ int but_flag = UI_BUT_DRAG_LOCK;
+
+ if (id->lib)
+ but_flag |= UI_BUT_DISABLED;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ if (id->flag & LIB_FAKEUSER) {
+ icon = ICON_FILE_TICK;
+ tip = TIP_("Datablock will be retained using a fake user");
+ }
+ else {
+ icon = ICON_X;
+ tip = TIP_("Datablock has no users and will be deleted");
+ }
+ bt = uiDefIconButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &id->flag, 0, 0, 0, 0, tip);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_flag_enable(bt, but_flag);
+
+
+ BLI_str_format_int_grouped(buf, id->us);
+ bt = uiDefBut(block, UI_BTYPE_BUT, 1, buf,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys,
+ UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0,
+ TIP_("Number of users of this datablock"));
+ UI_but_flag_enable(bt, but_flag);
+
+
+ bt = uiDefButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ",
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &id->flag, 0, 0, 0, 0,
+ TIP_("Datablock has a 'fake' user which will keep it in the file "
+ "even if nothing else uses it"));
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_flag_enable(bt, but_flag);
+
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
+ }
+
+ if (TSELEM_OPEN(tselem, soops)) outliner_draw_userbuts(block, ar, soops, &te->subtree);
+ }
+}
+
static void outliner_draw_rnacols(ARegion *ar, int sizex)
{
View2D *v2d = &ar->v2d;
@@ -745,8 +892,6 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
TreeStoreElem *tselem;
PointerRNA *ptr;
PropertyRNA *prop;
-
- uiBlockSetEmboss(block, UI_EMBOSST);
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
@@ -759,7 +904,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
if (RNA_property_type(prop) == PROP_POINTER) {
uiBut *but = uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys,
OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else if (RNA_property_type(prop) == PROP_ENUM) {
uiDefAutoButR(block, ptr, prop, -1, NULL, ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
@@ -783,7 +928,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, scene, ar, soops, sizex, &te->subtree);
}
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te)
@@ -807,12 +952,12 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre
spx = te->xs + 1.8f * UI_UNIT_X;
dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X);
- bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
+ bt = uiDefBut(block, UI_BTYPE_TEXT, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
1.0, (float)len, 0, 0, "");
- uiButSetRenameFunc(bt, namebutton_cb, tselem);
+ UI_but_func_rename_set(bt, namebutton_cb, tselem);
/* returns false if button got removed */
- if (false == uiButActiveOnly(C, ar, block, bt)) {
+ if (false == UI_but_active_only(C, ar, block, bt)) {
tselem->flag &= ~TSE_TEXTBUT;
/* bad! (notifier within draw) without this, we don't get a refesh */
@@ -840,13 +985,46 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
glDisable(GL_BLEND);
}
else {
- uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
+ uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
if (arg->id)
- uiButSetDragID(but, arg->id);
+ UI_but_drag_set_id(but, arg->id);
+ }
+
+}
+
+static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
+{
+ /* restrict column clip - skip it for now... */
+ if (arg->x >= arg->xmax) {
+ /* pass */
}
+ else {
+ PointerRNA ptr;
+ const float eps = 0.001f;
+ const bool is_stroke_visible = (gpl->color[3] > eps);
+ const bool is_fill_visible = (gpl->fill[3] > eps);
+ float w = 0.5f * UI_UNIT_X;
+ float h = 0.85f * UI_UNIT_Y;
+ RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr);
+
+ UI_block_align_begin(arg->block);
+
+ UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
+ &ptr, "color", -1,
+ 0, 0, 0, 0, NULL);
+
+ UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h,
+ &ptr, "fill_color", -1,
+ 0, 0, 0, 0, NULL);
+
+ UI_block_emboss_set(arg->block, UI_EMBOSS_NONE);
+ UI_block_align_end(arg->block);
+ }
}
static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
@@ -946,6 +1124,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
case eModifierType_Smooth:
case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
case eModifierType_SimpleDeform:
UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
@@ -990,6 +1169,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
case eModifierType_LaplacianDeform:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ case eModifierType_DataTransfer:
+ UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
+ case eModifierType_NormalEdit:
+ UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -1042,6 +1225,9 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
else
UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
break;
+ case TSE_GP_LAYER:
+ tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
+ break;
default:
UI_icon_draw(x, y, ICON_DOT); break;
}
@@ -1135,6 +1321,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break;
case ID_LS:
tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
+ case ID_GD:
+ tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
}
}
}
@@ -1176,13 +1364,14 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
if (active != OL_DRAWSEL_NONE) {
float ufac = UI_UNIT_X / 20.0f;
- uiSetRoundBox(UI_CNR_ALL);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
glColor4ub(255, 255, 255, 100);
- uiRoundBox((float) *offsx - 1.0f * ufac,
- (float)ys + 1.0f * ufac,
- (float)*offsx + UI_UNIT_X - 2.0f * ufac,
- (float)ys + UI_UNIT_Y - ufac,
- (float)UI_UNIT_Y / 2.0f - ufac);
+ UI_draw_roundbox(
+ (float) *offsx - 1.0f * ufac,
+ (float)ys + 1.0f * ufac,
+ (float)*offsx + UI_UNIT_X - 2.0f * ufac,
+ (float)ys + UI_UNIT_Y - ufac,
+ (float)UI_UNIT_Y / 2.0f - ufac);
glEnable(GL_BLEND); /* roundbox disables */
}
@@ -1217,8 +1406,9 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i
}
-static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, int startx, int *starty, TreeElement **te_edit)
+static void outliner_draw_tree_element(
+ bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ARegion *ar, SpaceOops *soops,
+ TreeElement *te, int startx, int *starty, TreeElement **te_edit)
{
TreeElement *ten;
TreeStoreElem *tselem;
@@ -1322,12 +1512,13 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
/* active circle */
if (active != OL_DRAWSEL_NONE) {
- uiSetRoundBox(UI_CNR_ALL);
- uiRoundBox((float)startx + UI_UNIT_X,
- (float)*starty + 1.0f * ufac,
- (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
- (float)*starty + UI_UNIT_Y - 1.0f * ufac,
- UI_UNIT_Y / 2.0f - 1.0f * ufac);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox(
+ (float)startx + UI_UNIT_X,
+ (float)*starty + 1.0f * ufac,
+ (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
+ (float)*starty + UI_UNIT_Y - 1.0f * ufac,
+ UI_UNIT_Y / 2.0f - 1.0f * ufac);
glEnable(GL_BLEND); /* roundbox disables it */
te->flag |= TE_ACTIVE; // for lookup in display hierarchies
@@ -1376,9 +1567,9 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
else UI_ThemeColor(TH_TEXT);
- UI_DrawString(startx + offsx, *starty + 5 * ufac, te->name);
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
- offsx += (int)(UI_UNIT_X + UI_GetStringWidth(te->name));
+ offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
/* closed item, we draw the icons, not when it's a scene, or master-server list though */
if (!TSELEM_OPEN(tselem, soops)) {
@@ -1416,13 +1607,15 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
if (TSELEM_OPEN(tselem, soops)) {
*starty -= UI_UNIT_Y;
-
- for (ten = te->subtree.first; ten; ten = ten->next)
- outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+
+ for (ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+ }
}
else {
- for (ten = te->subtree.first; ten; ten = ten->next)
+ for (ten = te->subtree.first; ten; ten = ten->next) {
outliner_set_coord_tree_element(soops, ten, startx, *starty);
+ }
*starty -= UI_UNIT_Y;
}
@@ -1505,6 +1698,7 @@ static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb,
static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar,
SpaceOops *soops, TreeElement **te_edit)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
TreeElement *te;
int starty, startx;
float col[3];
@@ -1535,7 +1729,7 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
for (te = soops->tree.first; te; te = te->next) {
- outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty, te_edit);
+ outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit);
}
}
@@ -1654,7 +1848,7 @@ void draw_outliner(const bContext *C)
/* draw outliner stuff (background, hierarchy lines and names) */
outliner_back(ar);
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
outliner_draw_tree((bContext *)C, block, scene, ar, soops, &te_edit);
if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
@@ -1662,6 +1856,11 @@ void draw_outliner(const bContext *C)
outliner_draw_rnacols(ar, sizex_rna);
outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree);
}
+ else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) {
+ /* draw user toggle columns */
+ outliner_draw_restrictcols(ar);
+ outliner_draw_userbuts(block, ar, soops, &soops->tree);
+ }
else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) {
/* draw restriction columns */
outliner_draw_restrictcols(ar);
@@ -1673,8 +1872,8 @@ void draw_outliner(const bContext *C)
outliner_buttons(C, block, ar, te_edit);
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
/* clear flag that allows quick redraws */
soops->storeflag &= ~SO_TREESTORE_REDRAW;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index ef621407abd..6d420674f3e 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -39,19 +39,24 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_mempool.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_material.h"
+#include "BKE_group.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_keyframing.h"
@@ -73,22 +78,6 @@
/* This is not used anywhere at the moment */
#if 0
-/* return 1 when levels were opened */
-static int outliner_open_back(SpaceOops *soops, TreeElement *te)
-{
- TreeStoreElem *tselem;
- int retval = 0;
-
- for (te = te->parent; te; te = te->parent) {
- tselem = TREESTORE(te);
- if (tselem->flag & TSE_CLOSED) {
- tselem->flag &= ~TSE_CLOSED;
- retval = 1;
- }
- }
- return retval;
-}
-
static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
{
TreeElement *te;
@@ -113,7 +102,9 @@ static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *te
}
#endif
-static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElement *te, const float fmval[2], const int children)
+static TreeElement *outliner_dropzone_element(
+ const SpaceOops *soops, TreeElement *te,
+ const float fmval[2], const bool children)
{
if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
/* name and first icon */
@@ -132,7 +123,7 @@ static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElemen
}
/* Used for drag and drop parenting */
-TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const int children)
+TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children)
{
TreeElement *te;
@@ -229,7 +220,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
else if (tselem->id->lib) {
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
}
- else if (te->idcode == ID_LI && te->parent) {
+ else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
}
else {
@@ -601,6 +592,50 @@ void OUTLINER_OT_selected_toggle(wmOperatorType *ot)
/* Show Active --------------------------------------------------- */
+static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeElement *te, int startx, int *starty)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs = (float)startx;
+ te->ys = (float)(*starty);
+ *starty -= UI_UNIT_Y;
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ TreeElement *ten;
+ for (ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_set_coordinates_element_recursive(soops, ten, startx + UI_UNIT_X, starty);
+ }
+ }
+}
+
+/* to retrieve coordinates with redrawing the entire tree */
+static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
+{
+ TreeElement *te;
+ int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
+
+ for (te = soops->tree.first; te; te = te->next) {
+ outliner_set_coordinates_element_recursive(soops, te, 0, &starty);
+ }
+}
+
+/* return 1 when levels were opened */
+static int outliner_open_back(TreeElement *te)
+{
+ TreeStoreElem *tselem;
+ int retval = 0;
+
+ for (te = te->parent; te; te = te->parent) {
+ tselem = TREESTORE(te);
+ if (tselem->flag & TSE_CLOSED) {
+ tselem->flag &= ~TSE_CLOSED;
+ retval = 1;
+ }
+ }
+ return retval;
+}
+
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceOops *so = CTX_wm_space_outliner(C);
@@ -617,6 +652,11 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
te = outliner_find_id(so, &so->tree, (ID *)OBACT);
if (te) {
+ /* open up tree to active object */
+ if (outliner_open_back(te)) {
+ outliner_set_coordinates(ar, so);
+ }
+
/* make te->ys center of view */
ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
if (ytop > 0) ytop = 0;
@@ -642,7 +682,7 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
/* identifiers */
ot->name = "Show Active";
ot->idname = "OUTLINER_OT_show_active";
- ot->description = "Adjust the view so that the active Object is shown centered";
+ ot->description = "Open up the tree and adjust the view so that the active Object is shown centered";
/* callbacks */
ot->exec = outliner_show_active_exec;
@@ -690,37 +730,6 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
#if 0
-/* recursive helper for function below */
-static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
-{
- TreeStoreElem *tselem = TREESTORE(te);
-
- /* store coord and continue, we need coordinates for elements outside view too */
- te->xs = (float)startx;
- te->ys = (float)(*starty);
- *starty -= UI_UNIT_Y;
-
- if (TSELEM_OPEN(tselem, soops)) {
- TreeElement *ten;
- for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_set_coordinates_element(soops, ten, startx + UI_UNIT_X, starty);
- }
- }
-
-}
-
-/* to retrieve coordinates with redrawing the entire tree */
-static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
-{
- TreeElement *te;
- int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
- int startx = 0;
-
- for (te = soops->tree.first; te; te = te->next) {
- outliner_set_coordinates_element(soops, te, startx, &starty);
- }
-}
-
/* find next element that has this name */
static TreeElement *outliner_find_name(SpaceOops *soops, ListBase *lb, char *name, int flags,
TreeElement *prev, int *prevFound)
@@ -780,7 +789,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
else {
/* pop up panel - no previous, or user didn't want search after previous */
name[0] = '\0';
-// XXX if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
+// XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
// te = outliner_find_name(soops, &soops->tree, name, flags, NULL, &prevFound);
// }
// else return; /* XXX RETURN! XXX */
@@ -1305,7 +1314,7 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add)
// XXX the default settings have yet to evolve
if ((add) && (ks == NULL)) {
ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0);
- scene->active_keyingset = BLI_countlist(&scene->keyingsets);
+ scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
}
return ks;
@@ -1347,7 +1356,7 @@ static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBa
/* TODO: what do we do with group name?
* for now, we don't supply one, and just let this use the KeyingSet name */
BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
- ks->active_path = BLI_countlist(&ks->paths);
+ ks->active_path = BLI_listbase_count(&ks->paths);
break;
}
case KEYINGSET_EDITMODE_REMOVE:
@@ -1453,6 +1462,62 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* ************************************************************** */
+/* ORPHANED DATABLOCKS */
+
+static int ed_operator_outliner_id_orphans_active(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
+ SpaceOops *so = CTX_wm_space_outliner(C);
+ return (so->outlinevis == SO_ID_ORPHANS);
+ }
+ return 0;
+}
+
+/* Purge Orphans Operator --------------------------------------- */
+
+static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+ /* present a prompt to informing users that this change is irreversible */
+ return WM_operator_confirm_message(C, op,
+ "Purging unused datablocks cannot be undone. "
+ "Click here to proceed...");
+}
+
+static int outliner_orphans_purge_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Firstly, ensure that the file has been saved,
+ * so that the latest changes since the last save
+ * are retained...
+ */
+ WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL);
+
+ /* Now, reload the file to get rid of the orphans... */
+ WM_operator_name_call(C, "WM_OT_revert_mainfile", WM_OP_EXEC_DEFAULT, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->idname = "OUTLINER_OT_orphans_purge";
+ ot->name = "Purge All";
+ ot->description = "Clear all orphaned datablocks without any users from the file (cannot be undone)";
+
+ /* callbacks */
+ ot->invoke = outliner_orphans_purge_invoke;
+ ot->exec = outliner_orphans_purge_exec;
+ ot->poll = ed_operator_outliner_id_orphans_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************** */
+/* DRAG AND DROP OPERATORS */
+
/* ******************** Parent Drop Operator *********************** */
static int parent_drop_exec(bContext *C, wmOperator *op)
@@ -1500,7 +1565,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 1);
+ te = outliner_dropzone_find(soops, fmval, true);
if (te) {
RNA_string_set(op->ptr, "parent", te->name);
@@ -1543,8 +1608,8 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* Menu creation */
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
- uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
PointerRNA ptr;
@@ -1615,9 +1680,9 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
}
else {
@@ -1715,7 +1780,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 0);
+ te = outliner_dropzone_find(soops, fmval, false);
if (te) {
Base *base;
@@ -1785,7 +1850,7 @@ static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *even
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 1);
+ te = outliner_dropzone_find(soops, fmval, true);
if (te) {
RNA_string_set(op->ptr, "object", te->name);
@@ -1829,3 +1894,98 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material");
}
+static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Group *group = NULL;
+ Object *ob = NULL;
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ TreeElement *te = NULL;
+ char ob_name[MAX_ID_NAME - 2];
+ float fmval[2];
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ /* Find object hovered over */
+ te = outliner_dropzone_find(soops, fmval, true);
+
+ if (te) {
+ group = (Group *)BKE_libblock_find_name(ID_GR, te->name);
+
+ RNA_string_get(op->ptr, "object", ob_name);
+ ob = (Object *)BKE_libblock_find_name(ID_OB, ob_name);
+
+ if (ELEM(NULL, group, ob)) {
+ return OPERATOR_CANCELLED;
+ }
+ if (BKE_group_object_exists(group, ob)) {
+ return OPERATOR_FINISHED;
+ }
+
+ if (BKE_group_object_cyclic_check(bmain, ob, group)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_group_object_add(group, ob, scene, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_group_link(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Link Object to Group";
+ ot->description = "Link Object to Group in Outliner";
+ ot->idname = "OUTLINER_OT_group_link";
+
+ /* api callbacks */
+ ot->invoke = group_link_invoke;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ /* properties */
+ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
+}
+
+/******** Utils to clear any ref to freed ID... **********/
+
+void ED_outliner_id_unref(SpaceOops *so, const ID *id)
+{
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == id) {
+ so->search_tse.id = NULL;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == id) {
+ tselem->id = NULL;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 317d33dd3e2..c89a1bb1b9f 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -36,12 +36,10 @@
/* internal exports only */
-struct wmWindowManager;
struct wmOperatorType;
struct TreeStoreElem;
struct bContext;
struct Scene;
-struct ARegion;
struct ID;
struct Object;
@@ -59,52 +57,17 @@ typedef struct TreeElement {
PointerRNA rnaptr; // RNA Pointer
} TreeElement;
+#define TREESTORE_ID_TYPE(_id) \
+ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
+ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF)) /* Only in 'blendfile' mode ... :/ */
+
/* TreeElement->flag */
#define TE_ACTIVE 1
#define TE_ICONROW 2
#define TE_LAZY_CLOSED 4
#define TE_FREE_NAME 8
-/* TreeStoreElem types */
-#define TSE_NLA 1
-#define TSE_NLA_ACTION 2
-#define TSE_DEFGROUP_BASE 3
-#define TSE_DEFGROUP 4
-#define TSE_BONE 5
-#define TSE_EBONE 6
-#define TSE_CONSTRAINT_BASE 7
-#define TSE_CONSTRAINT 8
-#define TSE_MODIFIER_BASE 9
-#define TSE_MODIFIER 10
-#define TSE_LINKED_OB 11
-// #define TSE_SCRIPT_BASE 12 // UNUSED
-#define TSE_POSE_BASE 13
-#define TSE_POSE_CHANNEL 14
-#define TSE_ANIM_DATA 15
-#define TSE_DRIVER_BASE 16
-#define TSE_DRIVER 17
-
-#define TSE_PROXY 18
-#define TSE_R_LAYER_BASE 19
-#define TSE_R_LAYER 20
-#define TSE_R_PASS 21
-#define TSE_LINKED_MAT 22
-/* NOTE, is used for light group */
-#define TSE_LINKED_LAMP 23
-#define TSE_POSEGRP_BASE 24
-#define TSE_POSEGRP 25
-#define TSE_SEQUENCE 26
-#define TSE_SEQ_STRIP 27
-#define TSE_SEQUENCE_DUP 28
-#define TSE_LINKED_PSYS 29
-#define TSE_RNA_STRUCT 30
-#define TSE_RNA_PROPERTY 31
-#define TSE_RNA_ARRAY_ELEM 32
-#define TSE_NLA_TRACK 33
-#define TSE_KEYMAP 34
-#define TSE_KEYMAP_ITEM 35
-#define TSE_ID_BASE 36
-
/* button events */
#define OL_NAMEBUTTON 1
@@ -166,6 +129,7 @@ void outliner_free_tree(ListBase *lb);
void outliner_cleanup_tree(struct SpaceOops *soops);
TreeElement *outliner_find_tse(struct SpaceOops *soops, TreeStoreElem *tse);
+TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem);
TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, struct ID *id);
struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
@@ -205,7 +169,7 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree
void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const int children);
+TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
/* ...................................................... */
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
@@ -233,21 +197,26 @@ void OUTLINER_OT_keyingset_remove_selected(struct wmOperatorType *ot);
void OUTLINER_OT_drivers_add_selected(struct wmOperatorType *ot);
void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot);
+void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
+
void OUTLINER_OT_parent_drop(struct wmOperatorType *ot);
void OUTLINER_OT_parent_clear(struct wmOperatorType *ot);
void OUTLINER_OT_scene_drop(struct wmOperatorType *ot);
void OUTLINER_OT_material_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_group_link(struct wmOperatorType *ot);
/* outliner_tools.c ---------------------------------------------- */
void OUTLINER_OT_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
-
+void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot);
/* ---------------------------------------------------------------- */
/* outliner_ops.c */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index d735b5e75cf..839d44df25d 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -30,7 +30,6 @@
#include "DNA_space_types.h"
-#include "BLI_utildefines.h"
#include "RNA_access.h"
@@ -49,12 +48,15 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
WM_operatortype_append(OUTLINER_OT_operation);
+ WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_group_operation);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
WM_operatortype_append(OUTLINER_OT_action_set);
+ WM_operatortype_append(OUTLINER_OT_constraint_operation);
+ WM_operatortype_append(OUTLINER_OT_modifier_operation);
WM_operatortype_append(OUTLINER_OT_show_one_level);
WM_operatortype_append(OUTLINER_OT_show_active);
@@ -73,11 +75,14 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_drivers_add_selected);
WM_operatortype_append(OUTLINER_OT_drivers_delete_selected);
+
+ WM_operatortype_append(OUTLINER_OT_orphans_purge);
WM_operatortype_append(OUTLINER_OT_parent_drop);
WM_operatortype_append(OUTLINER_OT_parent_clear);
WM_operatortype_append(OUTLINER_OT_scene_drop);
WM_operatortype_append(OUTLINER_OT_material_drop);
+ WM_operatortype_append(OUTLINER_OT_group_link);
}
void outliner_keymap(wmKeyConfig *keyconf)
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 6f5bf712d55..e52c68b57e9 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -290,6 +290,10 @@ static eOLDrawState tree_element_active_material(
}
}
if (set != OL_SETSEL_NONE) {
+ /* Tagging object for update seems a bit stupid here, but looks like we have to do it
+ * for render views to update. See T42973.
+ * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
+ DAG_id_tag_update((ID *)ob, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
}
return OL_DRAWSEL_NONE;
@@ -550,10 +554,12 @@ static eOLDrawState tree_element_active_bone(
Object *ob = OBACT;
if (ob) {
if (set != OL_SETSEL_EXTEND) {
- bPoseChannel *pchannel;
/* single select forces all other bones to get unselected */
- for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next)
- pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ Bone *bone;
+ for (bone = arm->bonebase.first; bone != NULL; bone = bone->next) {
+ bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ do_outliner_bone_select_recursive(arm, bone, false);
+ }
}
}
@@ -614,7 +620,7 @@ static eOLDrawState tree_element_active_ebone(
if (set != OL_SETSEL_NONE) {
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
- ED_armature_deselect_all(scene->obedit, 0); // deselect
+ ED_armature_deselect_all(scene->obedit);
tree_element_active_ebone__sel(C, scene, arm, ebone, true);
status = OL_DRAWSEL_NORMAL;
}
@@ -771,7 +777,7 @@ static eOLDrawState tree_element_active_sequence_dup(
continue;
}
-// if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+// if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
// XXX select_single_seq(p, 0);
p = p->next;
}
@@ -869,6 +875,9 @@ eOLDrawState tree_element_type_active(
return tree_element_active_sequence_dup(scene, te, tselem, set);
case TSE_KEYMAP_ITEM:
return tree_element_active_keymap_item(C, te, tselem, set);
+ case TSE_GP_LAYER:
+ //return tree_element_active_gplayer(C, scene, te, tselem, set);
+ break;
}
return OL_DRAWSEL_NONE;
@@ -911,7 +920,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP)
tree_element_set_active_object(C, scene, soops, te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive && tselem->type == 0 );
+ recursive && tselem->type == 0);
if (tselem->type == 0) { // the lib blocks
/* editmode? */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index d09ed1a100e..50171d7f032 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -33,6 +33,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_linestyle_types.h"
@@ -43,12 +44,15 @@
#include "DNA_sequence_types.h"
#include "DNA_world_types.h"
#include "DNA_object_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_constraint.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_group.h"
@@ -69,6 +73,7 @@
#include "UI_interface.h"
#include "UI_view2d.h"
+#include "UI_resources.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -258,7 +263,90 @@ static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *
}
}
-/* */
+/* ******************************************** */
+typedef enum eOutliner_PropSceneOps {
+ OL_SCENE_OP_DELETE = 1
+} eOutliner_PropSceneOps;
+
+static EnumPropertyItem prop_scene_op_types[] = {
+ {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static bool outliner_do_scene_operation(
+ bContext *C, eOutliner_PropSceneOps event, ListBase *lb,
+ bool (*operation_cb)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ bool success = false;
+
+ for (te = lb->first; te; te = te->next) {
+ tselem = TREESTORE(te);
+ if (tselem->flag & TSE_SELECTED) {
+ if (operation_cb(C, event, te, tselem)) {
+ success = true;
+ }
+ }
+ }
+
+ return success;
+}
+
+static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNUSED(te), TreeStoreElem *tselem)
+{
+ Scene *scene = (Scene *)tselem->id;
+
+ if (event == OL_SCENE_OP_DELETE) {
+ if (ED_screen_delete_scene(C, scene)) {
+ WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
+ }
+ else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type");
+
+ if (outliner_do_scene_operation(C, event, &soops->tree, scene_cb) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (event == OL_SCENE_OP_DELETE) {
+ outliner_cleanup_tree(soops);
+ ED_undo_push(C, "Delete Scene(s)");
+ }
+ else {
+ BLI_assert(0);
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_scene_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Scene Operation";
+ ot->idname = "OUTLINER_OT_scene_operation";
+ ot->description = "Context menu for scene operations";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_scene_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
+}
+/* ******************************************** */
static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
@@ -422,8 +510,7 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
{
Group *group = (Group *)tselem->id;
- Object *ob = ED_object_add_type(C, OB_EMPTY, scene->cursor, NULL, false, scene->layact);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -462,7 +549,7 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_free_animdata(tselem->id);
+ BKE_animdata_free(tselem->id);
}
@@ -499,19 +586,39 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te
/* --------------------------------- */
+typedef enum eOutliner_PropDataOps {
+ OL_DOP_SELECT = 1,
+ OL_DOP_DESELECT,
+ OL_DOP_HIDE,
+ OL_DOP_UNHIDE,
+ OL_DOP_SELECT_LINKED,
+} eOutliner_PropDataOps;
+
+typedef enum eOutliner_PropConstraintOps {
+ OL_CONSTRAINTOP_ENABLE = 1,
+ OL_CONSTRAINTOP_DISABLE,
+ OL_CONSTRAINTOP_DELETE
+} eOutliner_PropConstraintOps;
+
+typedef enum eOutliner_PropModifierOps {
+ OL_MODIFIER_OP_TOGVIS = 1,
+ OL_MODIFIER_OP_TOGREN,
+ OL_MODIFIER_OP_DELETE
+} eOutliner_PropModifierOps;
+
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
pchan->bone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
pchan->bone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
pchan->bone->flag |= BONE_HIDDEN_P;
pchan->bone->flag &= ~BONE_SELECTED;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
pchan->bone->flag &= ~BONE_HIDDEN_P;
}
@@ -519,15 +626,15 @@ static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), v
{
Bone *bone = (Bone *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
bone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
bone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
bone->flag |= BONE_HIDDEN_P;
bone->flag &= ~BONE_SELECTED;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
bone->flag &= ~BONE_HIDDEN_P;
}
@@ -535,22 +642,22 @@ static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem),
{
EditBone *ebone = (EditBone *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
ebone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
ebone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
ebone->flag |= BONE_HIDDEN_A;
ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
ebone->flag &= ~BONE_HIDDEN_A;
}
static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr)
{
Sequence *seq = (Sequence *)te->directdata;
- if (event == 1) {
+ if (event == OL_DOP_SELECT) {
Scene *scene = (Scene *)scene_ptr;
Editing *ed = BKE_sequencer_editing_get(scene, false);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -561,9 +668,23 @@ static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void
(void)tselem;
}
+static void gp_layer_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
+{
+ bGPDlayer *gpl = (bGPDlayer *)te->directdata;
+
+ if (event == OL_DOP_SELECT)
+ gpl->flag |= GP_LAYER_SELECT;
+ else if (event == OL_DOP_DESELECT)
+ gpl->flag &= ~GP_LAYER_SELECT;
+ else if (event == OL_DOP_HIDE)
+ gpl->flag |= GP_LAYER_HIDE;
+ else if (event == OL_DOP_UNHIDE)
+ gpl->flag &= ~GP_LAYER_HIDE;
+}
+
static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- if (event == 5) {
+ if (event == OL_DOP_SELECT_LINKED) {
if (RNA_struct_is_ID(te->rnaptr.type)) {
bContext *C = (bContext *) C_v;
ID *id = te->rnaptr.data;
@@ -573,6 +694,68 @@ static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNU
}
}
+static void constraint_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
+{
+ bContext *C = C_v;
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ bConstraint *constraint = (bConstraint *)te->directdata;
+ Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
+
+ if (event == OL_CONSTRAINTOP_ENABLE) {
+ constraint->flag &= ~CONSTRAINT_OFF;
+ ED_object_constraint_update(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
+ }
+ else if (event == OL_CONSTRAINTOP_DISABLE) {
+ constraint->flag = CONSTRAINT_OFF;
+ ED_object_constraint_update(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
+ }
+ else if (event == OL_CONSTRAINTOP_DELETE) {
+ ListBase *lb = NULL;
+
+ if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
+ lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
+ }
+ else {
+ lb = &ob->constraints;
+ }
+
+ if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
+ /* there's no active constraint now, so make sure this is the case */
+ BKE_constraints_active_set(&ob->constraints, NULL);
+ ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
+ te->store_elem->flag &= ~TSE_SELECTED;
+ }
+ }
+}
+
+static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
+{
+ bContext *C = (bContext *)Carg;
+ Main *bmain = CTX_data_main(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ModifierData *md = (ModifierData *)te->directdata;
+ Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
+
+ if (event == OL_MODIFIER_OP_TOGVIS) {
+ md->mode ^= eModifierMode_Realtime;
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
+ else if (event == OL_MODIFIER_OP_TOGREN) {
+ md->mode ^= eModifierMode_Render;
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
+ else if (event == OL_MODIFIER_OP_DELETE) {
+ ED_object_modifier_remove(NULL, bmain, ob, md);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
+ te->store_elem->flag &= ~TSE_SELECTED;
+ }
+}
+
static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *),
void *arg)
@@ -593,14 +776,60 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
+static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+{
+ Base *child_base, *base_next;
+ Object *parent;
+
+ if (!base) {
+ return NULL;
+ }
+
+ for (child_base = scene->base.first; child_base; child_base = base_next) {
+ base_next = child_base->next;
+ for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
+ if (parent) {
+ base_next = outline_delete_hierarchy(C, scene, child_base);
+ }
+ }
+
+ base_next = base->next;
+ ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ return base_next;
+}
+
+static void object_delete_hierarchy_cb(
+ bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+{
+ Base *base = (Base *)te->directdata;
+ Object *obedit = scene->obedit;
+
+ if (!base) {
+ base = BKE_scene_base_find(scene, (Object *)tselem->id);
+ }
+ if (base) {
+ /* Check also library later. */
+ for (; obedit && (obedit != base->object); obedit = obedit->parent);
+ if (obedit == base->object) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ }
+
+ outline_delete_hierarchy(C, scene, base);
+ te->directdata = NULL;
+ tselem->id = NULL;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+}
+
/* **************************************** */
enum {
- OL_OP_ENDMARKER = 0,
- OL_OP_SELECT,
+ OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
+ OL_OP_DELETE_HIERARCHY,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -613,11 +842,12 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
+ {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
- {OL_OP_ENDMARKER, NULL, 0, NULL, NULL}
+ {0, NULL, 0, NULL, NULL}
};
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
@@ -672,6 +902,16 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_DELETE_HIERARCHY) {
+ outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb);
+
+ /* XXX: See OL_OP_DELETE comment above. */
+ outliner_cleanup_tree(soops);
+
+ DAG_relations_tag_update(bmain);
+ str = "Delete Object Hierarchy";
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ }
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
@@ -725,15 +965,26 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
/* **************************************** */
+typedef enum eOutliner_PropGroupOps {
+ OL_GROUPOP_UNLINK = 1,
+ OL_GROUPOP_LOCAL,
+ OL_GROUPOP_LINK,
+ OL_GROUPOP_INSTANCE,
+ OL_GROUPOP_TOGVIS,
+ OL_GROUPOP_TOGSEL,
+ OL_GROUPOP_TOGREN,
+ OL_GROUPOP_RENAME,
+} eOutliner_PropGroupOps;
+
static EnumPropertyItem prop_group_op_types[] = {
- {0, "UNLINK", 0, "Unlink Group", ""},
- {1, "LOCAL", 0, "Make Local Group", ""},
- {2, "LINK", 0, "Link Group Objects to Scene", ""},
- {3, "INSTANCE", 0, "Instance Groups in Scene", ""},
- {4, "TOGVIS", 0, "Toggle Visible Group", ""},
- {5, "TOGSEL", 0, "Toggle Selectable", ""},
- {6, "TOGREN", 0, "Toggle Renderable", ""},
- {7, "RENAME", 0, "Rename", ""},
+ {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
+ {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
+ {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
+ {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
+ {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
+ {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
+ {OL_GROUPOP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
+ {OL_GROUPOP_RENAME, "RENAME", 0, "Rename", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -750,28 +1001,42 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
switch (event) {
- case 0: outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb); break;
- case 1: outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb); break;
- case 2: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb); break;
- case 3: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb); break;
- case 4: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb); break;
- case 5: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb); break;
- case 6: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb); break;
- case 7: outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb); break;
+ case OL_GROUPOP_UNLINK:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb);
+ break;
+ case OL_GROUPOP_LOCAL:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
+ break;
+ case OL_GROUPOP_LINK:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb);
+ break;
+ case OL_GROUPOP_INSTANCE:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb);
+ break;
+ case OL_GROUPOP_TOGVIS:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb);
+ break;
+ case OL_GROUPOP_TOGSEL:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb);
+ break;
+ case OL_GROUPOP_TOGREN:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb);
+ break;
+ case OL_GROUPOP_RENAME:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ break;
default:
BLI_assert(0);
- return OPERATOR_CANCELLED;
}
-
if (event == 3) { /* instance */
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(CTX_data_main(C));
}
-
- ED_undo_push(C, prop_group_op_types[event].name);
+
+ ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1195,12 +1460,105 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
/* **************************************** */
+static EnumPropertyItem prop_constraint_op_types[] = {
+ {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_RESTRICT_VIEW_OFF, "Enable", ""},
+ {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_RESTRICT_VIEW_ON, "Disable", ""},
+ {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+ eOutliner_PropConstraintOps event;
+
+ event = RNA_enum_get(op->ptr, "type");
+ set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, constraint_cb, C);
+
+ if (event == OL_CONSTRAINTOP_DELETE) {
+ outliner_cleanup_tree(soops);
+ }
+
+ ED_undo_push(C, "Constraint operation");
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Constraint Operation";
+ ot->idname = "OUTLINER_OT_constraint_operation";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_constraint_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
+}
+
+/* ******************** */
+
+static EnumPropertyItem prop_modifier_op_types[] = {
+ {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""},
+ {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle render use", ""},
+ {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+ eOutliner_PropModifierOps event;
+
+ event = RNA_enum_get(op->ptr, "type");
+ set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, modifier_cb, C);
+
+ if (event == OL_MODIFIER_OP_DELETE) {
+ outliner_cleanup_tree(soops);
+ }
+
+ ED_undo_push(C, "Modifier operation");
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Modifier Operation";
+ ot->idname = "OUTLINER_OT_modifier_operation";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_modifier_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
+}
+
+/* ******************** */
+
+// XXX: select linked is for RNA structs only
static EnumPropertyItem prop_data_op_types[] = {
- {1, "SELECT", 0, "Select", ""},
- {2, "DESELECT", 0, "Deselect", ""},
- {3, "HIDE", 0, "Hide", ""},
- {4, "UNHIDE", 0, "Unhide", ""},
- {5, "SELECT_LINKED", 0, "Select Linked", ""},
+ {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
+ {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
+ {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
+ {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
+ {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1208,7 +1566,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
- int event;
+ eOutliner_PropDataOps event;
/* check for invalid states */
if (soops == NULL)
@@ -1217,47 +1575,53 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
- if (event <= 0)
- return OPERATOR_CANCELLED;
-
switch (datalevel) {
case TSE_POSE_CHANNEL:
{
outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
ED_undo_push(C, "PoseChannel operation");
- }
+
break;
-
+ }
case TSE_BONE:
{
outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
ED_undo_push(C, "Bone operation");
- }
+
break;
-
+ }
case TSE_EBONE:
{
outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
ED_undo_push(C, "EditBone operation");
- }
+
break;
-
+ }
case TSE_SEQUENCE:
{
Scene *scene = CTX_data_scene(C);
outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb, scene);
+
+ break;
}
+ case TSE_GP_LAYER:
+ {
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, gp_layer_cb, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ ED_undo_push(C, "Grease Pencil Layer operation");
+
break;
-
+ }
case TSE_RNA_STRUCT:
- if (event == 5) {
+ if (event == OL_DOP_SELECT_LINKED) {
outliner_do_data_operation(soops, datalevel, event, &soops->tree, data_select_linked_cb, C);
}
+
break;
-
+
default:
BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
break;
@@ -1312,8 +1676,12 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
if (scenelevel) {
- //if (objectlevel || datalevel || idlevel) error("Mixed selection");
- //else pupmenu("Scene Operations%t|Delete");
+ if (objectlevel || datalevel || idlevel) {
+ BKE_report(reports, RPT_WARNING, "Mixed selection");
+ }
+ else {
+ WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
}
else if (objectlevel) {
WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
@@ -1342,6 +1710,15 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
/*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
}
+ else if (datalevel == TSE_ID_BASE) {
+ /* do nothing... there are no ops needed here yet */
+ }
+ else if (datalevel == TSE_CONSTRAINT) {
+ WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
+ else if (datalevel == TSE_MODIFIER) {
+ WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
else {
WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
@@ -1364,9 +1741,14 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
+ uiBut *but = UI_context_active_but_get(C);
TreeElement *te;
float fmval[2];
+ if (but) {
+ UI_but_tooltip_timer_remove(C, but);
+ }
+
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 5801dd126e3..aaca61ed5cf 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -57,7 +58,7 @@
#include "BLI_mempool.h"
#include "BLI_fnmatch.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
@@ -65,7 +66,7 @@
#include "BKE_modifier.h"
#include "BKE_sequencer.h"
#include "BKE_idcode.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_armature.h"
#include "ED_screen.h"
@@ -103,6 +104,8 @@ static void outliner_storage_cleanup(SpaceOops *soops)
/* cleanup only after reading file or undo step, and always for
* RNA datablocks view in order to save memory */
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
+ soops->storeflag &= ~SO_TREESTORE_CLEANUP;
+
BLI_mempool_iternew(ts, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
if (tselem->id == NULL) unused++;
@@ -113,7 +116,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
BLI_mempool_destroy(ts);
soops->treestore = NULL;
if (soops->treehash) {
- BKE_treehash_free(soops->treehash);
+ BKE_outliner_treehash_free(soops->treehash);
soops->treehash = NULL;
}
}
@@ -132,7 +135,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
soops->treestore = new_ts;
if (soops->treehash) {
/* update hash table to fix broken pointers */
- BKE_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
}
}
}
@@ -150,12 +153,12 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
}
if (soops->treehash == NULL) {
- soops->treehash = BKE_treehash_create_from_treestore(soops->treestore);
+ soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
}
/* find any unused tree element in treestore and mark it as used
* (note that there may be multiple unused elements in case of linked objects) */
- tselem = BKE_treehash_lookup_unused(soops->treehash, type, nr, id);
+ tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
if (tselem) {
te->store_elem = tselem;
tselem->used = 1;
@@ -170,7 +173,7 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
tselem->used = 0;
tselem->flag = TSE_CLOSED;
te->store_elem = tselem;
- BKE_treehash_add_element(soops->treehash, tselem);
+ BKE_outliner_treehash_add_element(soops->treehash, tselem);
}
/* ********************************************************* */
@@ -196,7 +199,7 @@ void outliner_cleanup_tree(SpaceOops *soops)
}
/* Find specific item from the treestore */
-static TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
+TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
{
TreeElement *te, *tes;
for (te = lb->first; te; te = te->next) {
@@ -215,7 +218,7 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
if (tse->id == NULL) return NULL;
/* check if 'tse' is in treestore */
- tselem = BKE_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
+ tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
if (tselem)
return outliner_find_tree_element(&soops->tree, tselem);
@@ -430,11 +433,13 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
// TODO: move this to the front?
if (outliner_animdata_test(sce->adt))
outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
+
+ outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
outliner_add_element(soops, lb, sce->world, te, 0, 0);
#ifdef WITH_FREESTYLE
- if (STREQ(sce->r.engine, "BLENDER_RENDER") && (sce->r.mode & R_EDGE_FRS))
+ if (STREQ(sce->r.engine, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS))
outliner_add_line_styles(soops, lb, sce, te);
#endif
}
@@ -451,6 +456,8 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
if (ob->proxy && ob->id.lib == NULL)
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
+
+ outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
@@ -764,16 +771,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
- ebone->temp = ten;
+ ebone->temp.p = ten;
}
/* make hierarchy */
- ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp : NULL;
+ ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
while (ten) {
TreeElement *nten = ten->next, *par;
ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp;
+ par = ebone->parent->temp.p;
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -809,6 +816,22 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
}
break;
}
+ case ID_GD:
+ {
+ bGPdata *gpd = (bGPdata *)id;
+ bGPDlayer *gpl;
+ int a = 0;
+
+ if (outliner_animdata_test(gpd->adt))
+ outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
+
+ // TODO: base element for layers?
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a);
+ a++;
+ }
+ break;
+ }
}
}
@@ -825,6 +848,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
id = ((PointerRNA *)idv)->id.data;
if (!id) id = ((PointerRNA *)idv)->data;
}
+ else if (type == TSE_GP_LAYER) {
+ /* idv is the layer its self */
+ id = TREESTORE(parent)->id;
+ }
/* One exception */
if (type == TSE_ID_BASE) {
@@ -834,6 +861,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
return NULL;
}
+ if (type == 0) {
+ /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
+ BLI_assert(TREESTORE_ID_TYPE(id));
+ }
+
te = MEM_callocN(sizeof(TreeElement), "tree elem");
/* add to the visual tree */
BLI_addtail(lb, te);
@@ -856,6 +888,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if (type == TSE_ANIM_DATA) {
/* pass */
}
+ else if (type == TSE_GP_LAYER) {
+ /* pass */
+ }
else if (type == TSE_ID_BASE) {
/* pass */
}
@@ -938,6 +973,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
}
}
+ else if (type == TSE_GP_LAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)idv;
+
+ te->name = gpl->info;
+ te->directdata = gpl;
+ }
else if (type == TSE_SEQUENCE) {
Sequence *seq = (Sequence *) idv;
Sequence *p;
@@ -951,7 +992,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->directdata = seq;
te->name = seq->name + 2;
- if (seq->type < SEQ_TYPE_EFFECT) {
+ if (!(seq->type & SEQ_TYPE_EFFECT)) {
/*
* This work like the sequence.
* If the sequence have a name (not default name)
@@ -1102,7 +1143,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
int a = 0;
for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
- const char *key = WM_key_event_string(kmi->type);
+ const char *key = WM_key_event_string(kmi->type, false);
if (key[0]) {
wmOperatorType *ot = NULL;
@@ -1160,7 +1201,7 @@ static int need_add_seq_dup(Sequence *seq)
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
return(2);
p = p->prev;
}
@@ -1172,7 +1213,7 @@ static int need_add_seq_dup(Sequence *seq)
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
return(0);
p = p->next;
}
@@ -1191,12 +1232,90 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
/* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
p = p->next;
}
}
+
+/* ----------------------------------------------- */
+
+
+static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
+{
+ TreeElement *ten;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, tot;
+
+ tot = set_listbasepointers(mainvar, lbarray);
+ for (a = 0; a < tot; a++) {
+ if (lbarray[a]->first) {
+ ID *id = lbarray[a]->first;
+
+ /* check if there's data in current lib */
+ for (; id; id = id->next)
+ if (id->lib == lib)
+ break;
+
+ if (id) {
+ ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+
+ ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
+ if (ten->name == NULL)
+ ten->name = "UNKNOWN";
+
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (id->lib == lib)
+ outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ }
+ }
+ }
+ }
+
+}
+
+static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
+{
+ TreeElement *ten;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, tot;
+
+ tot = set_listbasepointers(mainvar, lbarray);
+ for (a = 0; a < tot; a++) {
+ if (lbarray[a]->first) {
+ ID *id = lbarray[a]->first;
+
+ /* check if there are any datablocks of this type which are orphans */
+ for (; id; id = id->next) {
+ if (ID_REAL_USERS(id) <= 0)
+ break;
+ }
+
+ if (id) {
+ /* header for this type of datablock */
+ /* TODO's:
+ * - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead?
+ * - Ensure that this uses nice icons for the datablock type involved instead of the dot?
+ */
+ ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+
+ ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
+ if (ten->name == NULL)
+ ten->name = "UNKNOWN";
+
+ /* add the orphaned datablocks - these will not be added with any subtrees attached */
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (ID_REAL_USERS(id) <= 0)
+ outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ }
+ }
+ }
+ }
+}
+
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
@@ -1311,7 +1430,10 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
TreeElement *te;
TreeStoreElem *tselem;
int totelem = 0;
-
+
+ if (soops->flag & SO_SKIP_SORT_ALPHA)
+ return;
+
te = lb->last;
if (te == NULL) return;
tselem = TREESTORE(te);
@@ -1371,59 +1493,42 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
/* Filtering ----------------------------------------------- */
-static int outliner_filter_has_name(TreeElement *te, const char *name, int flags)
+static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
{
-#if 0
- int found = 0;
-
- /* determine if match */
- if (flags & SO_FIND_CASE_SENSITIVE) {
- if (flags & SO_FIND_COMPLETE)
- found = strcmp(te->name, name) == 0;
- else
- found = strstr(te->name, name) != NULL;
- }
- else {
- if (flags & SO_FIND_COMPLETE)
- found = BLI_strcasecmp(te->name, name) == 0;
- else
- found = BLI_strcasestr(te->name, name) != NULL;
- }
-#else
-
int fn_flag = 0;
- int found = 0;
-
+
if ((flags & SO_FIND_CASE_SENSITIVE) == 0)
fn_flag |= FNM_CASEFOLD;
- if (flags & SO_FIND_COMPLETE) {
- found = fnmatch(name, te->name, fn_flag) == 0;
- }
- else {
- char fn_name[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
- BLI_snprintf(fn_name, sizeof(fn_name), "*%s*", name);
- found = fnmatch(fn_name, te->name, fn_flag) == 0;
- }
- return found;
-#endif
+ return fnmatch(name, te->name, fn_flag) == 0;
}
static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
{
TreeElement *te, *ten;
TreeStoreElem *tselem;
-
+ char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
+ char *search_string;
+
/* although we don't have any search string, we return true
* since the entire tree is ok then...
*/
if (soops->search_string[0] == 0)
return 1;
+ if (soops->search_flags & SO_FIND_COMPLETE) {
+ search_string = soops->search_string;
+ }
+ else {
+ /* Implicitly add heading/trailing wildcards if needed. */
+ BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
+ search_string = search_buff;
+ }
+
for (te = lb->first; te; te = ten) {
ten = te->next;
- if (0 == outliner_filter_has_name(te, soops->search_string, soops->search_flags)) {
+ if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
/* item isn't something we're looking for, but...
* - if the subtree is expanded, check if there are any matches that can be easily found
* so that searching for "cu" in the default scene will still match the Cube
@@ -1458,42 +1563,6 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
return (BLI_listbase_is_empty(lb) == false);
}
-static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
-{
- TreeElement *ten;
- ListBase *lbarray[MAX_LIBARRAY];
- int a, tot;
-
- tot = set_listbasepointers(mainvar, lbarray);
- for (a = 0; a < tot; a++) {
- if (lbarray[a]->first) {
- ID *id = lbarray[a]->first;
-
- /* check if there's data in current lib */
- for (; id; id = id->next)
- if (id->lib == lib)
- break;
-
- if (id) {
-
- ten = outliner_add_element(soops, &te->subtree, (void *)lbarray[a], NULL, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
-
- ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
- if (ten->name == NULL)
- ten->name = "UNKNOWN";
-
- for (id = lbarray[a]->first; id; id = id->next) {
- if (id->lib == lib)
- outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
- }
- }
- }
- }
-
-}
-
-
/* ======================================================= */
/* Main Tree Building API */
@@ -1515,6 +1584,11 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
else
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
+ if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
+ soops->storeflag &= ~SO_TREESTORE_REBUILD;
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ }
+
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
return;
@@ -1553,10 +1627,19 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
tselem = TREESTORE(ten);
lib = (Library *)tselem->id;
if (lib && lib->parent) {
- BLI_remlink(&soops->tree, ten);
par = (TreeElement *)lib->parent->id.newid;
- BLI_addtail(&par->subtree, ten);
- ten->parent = par;
+ if (tselem->id->flag & LIB_INDIRECT) {
+ /* Only remove from 'first level' if lib is not also directly used. */
+ BLI_remlink(&soops->tree, ten);
+ BLI_addtail(&par->subtree, ten);
+ ten->parent = par;
+ }
+ else {
+ /* Else, make a new copy of the libtree for our parent. */
+ TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0);
+ outliner_add_library_contents(mainvar, soops, dupten, lib);
+ dupten->parent = par;
+ }
}
ten = nten;
}
@@ -1688,6 +1771,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
tselem->flag &= ~TSE_CLOSED;
}
}
+ else if (soops->outlinevis == SO_ID_ORPHANS) {
+ outliner_add_orphaned_datablocks(mainvar, soops);
+ }
else {
ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
if (ten) ten->directdata = BASACT;
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 504d9628d98..7b1ec174a6b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -41,7 +41,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -98,10 +98,10 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 1);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
if (te && te->idcode == ID_OB && TREESTORE(te)->type == 0) {
Scene *scene;
@@ -129,7 +129,7 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "child", id->name + 2);
}
@@ -148,10 +148,10 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
}
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
if (((Object *)id)->parent) {
- if ((te = outliner_dropzone_find(soops, fmval, 1))) {
+ if ((te = outliner_dropzone_find(soops, fmval, true))) {
TreeStoreElem *tselem = TREESTORE(te);
switch (te->idcode) {
@@ -171,7 +171,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "dragged_obj", id->name + 2);
/* Set to simple parent clear type. Avoid menus for drag and drop if possible.
@@ -188,10 +188,10 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 0);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, false);
return (te && te->idcode == ID_SCE && TREESTORE(te)->type == 0);
}
}
@@ -200,7 +200,7 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev
static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "object", id->name + 2);
}
@@ -213,10 +213,10 @@ static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MA) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 1);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
return (te && te->idcode == ID_OB && TREESTORE(te)->type == 0);
}
}
@@ -225,11 +225,35 @@ static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent
static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "material", id->name + 2);
}
+static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ float fmval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ if (drag->type == WM_DRAG_ID) {
+ ID *id = drag->poin;
+ if (GS(id->name) == ID_OB) {
+ /* Ensure item under cursor is valid drop target */
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
+ return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0);
+ }
+ }
+ return 0;
+}
+
+static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop)
+{
+ ID *id = drag->poin;
+ RNA_string_set(drop->ptr, "object", id->name + 2);
+}
+
/* region dropbox definition */
static void outliner_dropboxes(void)
{
@@ -239,6 +263,7 @@ static void outliner_dropboxes(void)
WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy);
WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy);
WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy);
+ WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy);
}
static void outliner_main_area_draw(const bContext *C, ARegion *ar)
@@ -362,6 +387,10 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
break;
}
break;
+ case NC_GPENCIL:
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
+ ED_region_tag_redraw(ar);
+ break;
}
}
@@ -435,7 +464,7 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(soutliner->treestore);
}
if (soutliner->treehash) {
- BKE_treehash_free(soutliner->treehash);
+ BKE_outliner_treehash_free(soutliner->treehash);
}
}
diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt
index 26c4183f7df..2eb31576c57 100644
--- a/source/blender/editors/space_script/CMakeLists.txt
+++ b/source/blender/editors/space_script/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -47,4 +49,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_script "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_script/SConscript b/source/blender/editors/space_script/SConscript
index acb0bf9f20b..c03a61ec197 100644
--- a/source/blender/editors/space_script/SConscript
+++ b/source/blender/editors/space_script/SConscript
@@ -31,10 +31,12 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -43,6 +45,7 @@ incs = [
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
defs.append('WITH_PYTHON')
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 9077d0cf8ed..d265ae62db6 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -32,7 +32,6 @@
#include <string.h>
#include <stdio.h>
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -131,7 +130,7 @@ static int script_reload_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
#else
- (void)C, (void)op; /* unused */
+ UNUSED_VARS(C, op);
return OPERATOR_CANCELLED;
#endif
}
diff --git a/source/blender/editors/space_script/script_ops.c b/source/blender/editors/space_script/script_ops.c
index 045df87d8db..41c07596a3b 100644
--- a/source/blender/editors/space_script/script_ops.c
+++ b/source/blender/editors/space_script/script_ops.c
@@ -32,19 +32,7 @@
#include <stdlib.h>
#include <math.h>
-
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-
-#include "BKE_context.h"
-
-#include "RNA_access.h"
-
#include "WM_api.h"
-#include "WM_types.h"
#include "script_intern.h"
@@ -63,4 +51,3 @@ void script_keymap(wmKeyConfig *UNUSED(keyconf))
{
/* Script space is deprecated, and doesn't need a keymap */
}
-
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index fd2cd268a27..759dcd3d0a4 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -35,7 +35,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
-#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -53,7 +52,6 @@
#include "UI_view2d.h"
#ifdef WITH_PYTHON
-#include "BPY_extern.h"
#endif
#include "script_intern.h" // own include
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index db5729a5762..778ccf902d1 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -20,14 +20,16 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -41,6 +43,7 @@ set(SRC
sequencer_edit.c
sequencer_modifier.c
sequencer_ops.c
+ sequencer_preview.c
sequencer_scopes.c
sequencer_select.c
sequencer_view.c
@@ -50,14 +53,17 @@ set(SRC
)
if(WITH_AUDASPACE)
- list(APPEND INC
- ../../../../intern/audaspace/intern
+ add_definitions(${AUDASPACE_DEFINITIONS})
+
+ list(APPEND INC_SYS
+ ${AUDASPACE_C_INCLUDE_DIRS}
)
- add_definitions(-DWITH_AUDASPACE)
endif()
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_sequencer "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_sequencer/SConscript b/source/blender/editors/space_sequencer/SConscript
index 5aae30244a7..9c654d7a1e5 100644
--- a/source/blender/editors/space_sequencer/SConscript
+++ b/source/blender/editors/space_sequencer/SConscript
@@ -31,12 +31,13 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
- '#/intern/audaspace/intern',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -44,6 +45,11 @@ incs = [
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
+
+if env['WITH_BF_AUDASPACE']:
+ defs += env['BF_AUDASPACE_DEF']
+ incs.append(env['BF_AUDASPACE_C_INC'])
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 345988c1d5c..ce03c24e2ab 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <math.h>
#include <string.h>
+#include <ctype.h>
#include "MEM_guardedalloc.h"
@@ -40,7 +41,6 @@
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
-#include "BLF_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -61,17 +61,21 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
-#include "UI_view2d.h"
+#include "UI_interface.h"
#include "BKE_sound.h"
#ifdef WITH_AUDASPACE
-# include "AUD_C-API.h"
+# include AUD_SEQUENCE_H
#endif
/* own include */
#include "sequencer_intern.h"
+typedef struct SequencerAddData {
+ ImageFormatData im_format;
+} SequencerAddData;
+
/* Generic functions, reused by add strip operators */
/* avoid passing multiple args and be more verbose */
@@ -224,6 +228,19 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, wmOperator *op)
}
RNA_PROP_END;
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_multiview")) && RNA_property_boolean_get(op->ptr, prop)) {
+ if (op->customdata) {
+ SequencerAddData *sad = op->customdata;
+ ImageFormatData *imf = &sad->im_format;
+
+ seq_load->views_format = imf->views_format;
+ seq_load->flag |= SEQ_USE_VIEWS;
+
+ /* operator custom data is always released after the SeqLoadInfo, no need to handle the memory here */
+ seq_load->stereo3d_format = &imf->stereo3d_format;
+ }
+ }
}
/**
@@ -289,7 +306,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
- seq->scene_sound = sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
BKE_sequencer_sort(scene);
@@ -575,6 +592,9 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_CANCELLED;
}
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+
BKE_sequencer_sort(scene);
BKE_sequencer_update_muting(ed);
@@ -583,15 +603,40 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_FINISHED;
}
+/* add sequencer operators */
+static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
+{
+ op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
+}
+
+static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
+
+static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename")
+ );
+}
+
/* add movie operator */
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip);
}
-
static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ PropertyRNA *prop;
+ Scene *scene = CTX_data_scene(C);
+
/* This is for drag and drop */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -601,13 +646,37 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const w
}
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
-
+
+ sequencer_add_init(C, op);
+
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
//return sequencer_add_movie_strip_exec(C, op);
}
+static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ SequencerAddData *sad = op->customdata;
+ ImageFormatData *imf = &sad->im_format;
+ PointerRNA imf_ptr, ptr;
+
+ /* main draw call */
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, '\0');
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+
+ /* multiview template */
+ if (RNA_boolean_get(op->ptr, "show_multiview"))
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
+}
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
{
@@ -620,14 +689,16 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_movie_strip_invoke;
ot->exec = sequencer_add_movie_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie");
}
@@ -675,17 +746,80 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
}
+int sequencer_image_seq_get_minmax_frame(wmOperator *op, int sfra, int *r_minframe, int *r_numdigits)
+{
+ int minframe = INT32_MAX, maxframe = INT32_MIN;
+ int numdigits = 0;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename;
+ int frame;
+ /* just get the first filename */
+ filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+
+ if (filename) {
+ if (BLI_path_frame_get(filename, &frame, &numdigits)) {
+ minframe = min_ii(minframe, frame);
+ maxframe = max_ii(maxframe, frame);
+ }
+
+ MEM_freeN(filename);
+ }
+ }
+ RNA_END;
+
+ if (minframe == INT32_MAX) {
+ minframe = sfra;
+ maxframe = minframe + 1;
+ }
+
+ *r_minframe = minframe;
+ *r_numdigits = numdigits;
+
+ return maxframe - minframe + 1;
+}
+
+void sequencer_image_seq_reserve_frames(wmOperator *op, StripElem *se, int len, int minframe, int numdigits)
+{
+ int i;
+ char *filename = NULL;
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ /* just get the first filename */
+ filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ break;
+ }
+ RNA_END;
+
+ if (filename) {
+ char ext[PATH_MAX];
+ char filename_stripped[PATH_MAX];
+ /* strip the frame from filename and substitute with # */
+ BLI_path_frame_strip(filename, true, ext);
+
+ for (i = 0; i < len; i++, se++) {
+ BLI_strncpy(filename_stripped, filename, sizeof(filename_stripped));
+ BLI_path_frame(filename_stripped, minframe + i, numdigits);
+ BLI_snprintf(se->name, sizeof(se->name), "%s%s", filename_stripped, ext);
+ }
+
+ MEM_freeN(filename);
+ }
+}
+
+
/* add image operator */
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
+ int minframe, numdigits;
/* cant use the generic function for this */
-
Scene *scene = CTX_data_scene(C); /* only for sound */
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
@@ -693,11 +827,17 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
Strip *strip;
StripElem *se;
+ const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
seq_load_operator_info(&seq_load, op);
/* images are unique in how they handle this - 1 per strip elem */
- seq_load.len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ if (use_placeholders) {
+ seq_load.len = sequencer_image_seq_get_minmax_frame(op, seq_load.start_frame, &minframe, &numdigits);
+ }
+ else {
+ seq_load.len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ }
if (seq_load.len == 0)
return OPERATOR_CANCELLED;
@@ -705,20 +845,24 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
if (seq_load.flag & SEQ_LOAD_REPLACE_SEL)
ED_sequencer_deselect_all(scene);
-
/* main adding function */
seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load);
strip = seq->strip;
se = strip->stripdata;
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
- BLI_strncpy(se->name, filename, sizeof(se->name));
- MEM_freeN(filename);
- se++;
+ if (use_placeholders) {
+ sequencer_image_seq_reserve_frames(op, se, seq_load.len, minframe, numdigits);
+ }
+ else {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ BLI_strncpy(se->name, filename, sizeof(se->name));
+ MEM_freeN(filename);
+ se++;
+ }
+ RNA_END;
}
- RNA_END;
if (seq_load.len == 1) {
if (seq_load.start_frame < seq_load.end_frame) {
@@ -737,6 +881,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_overlap(C, op, seq);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -744,6 +891,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ PropertyRNA *prop;
+ Scene *scene = CTX_data_scene(C);
+
/* drag drop has set the names */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
@@ -752,6 +902,12 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const w
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
+ sequencer_add_init(C, op);
+
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -768,15 +924,19 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_image_strip_invoke;
ot->exec = sequencer_add_image_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+
+ RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
}
@@ -850,6 +1010,9 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
seq->blend_mode = SEQ_TYPE_CROSS;
}
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+ }
/* an unset channel is a special case where we automatically go above
* the other strips. */
@@ -920,8 +1083,9 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
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);
+ 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);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index d75eeca2c67..86d3fcbe1ac 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -34,7 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -46,12 +46,12 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "UI_interface.h"
#include "sequencer_intern.h"
/* **************************** buttons ********************************* */
+#if 0
static int sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt))
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
@@ -59,19 +59,22 @@ static int sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNUS
/* don't show the gpencil if we are not showing the image */
return ED_space_sequencer_check_show_imbuf(sseq);
}
+#endif
-void sequencer_buttons_register(ARegionType *art)
+void sequencer_buttons_register(ARegionType *UNUSED(art))
{
+#if 0
PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype sequencer panel gpencil");
strcpy(pt->idname, "SEQUENCER_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw_header = ED_gpencil_panel_standard_header;
pt->draw = ED_gpencil_panel_standard;
pt->poll = sequencer_grease_pencil_panel_poll;
BLI_addtail(&art->paneltypes, pt);
+#endif
}
/* **************** operator to open/close properties view ************* */
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index dab51f752b4..afa59876647 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_threads.h"
#include "IMB_imbuf_types.h"
@@ -49,6 +50,7 @@
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -61,6 +63,7 @@
#include "ED_markers.h"
#include "ED_mask.h"
#include "ED_sequencer.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
#include "UI_interface.h"
@@ -69,6 +72,8 @@
#include "WM_api.h"
+#include "MEM_guardedalloc.h"
+
/* own include */
#include "sequencer_intern.h"
@@ -82,9 +87,13 @@
/* Note, Don't use SEQ_BEGIN/SEQ_END while drawing!
* it messes up transform, - Campbell */
-static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2);
+#undef SEQ_BEGIN
+#undef SEQP_BEGIN
+#undef SEQ_END
+
+static Sequence *special_seq_update = NULL;
-static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[3])
+void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
{
unsigned char blendcol[3];
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
@@ -175,14 +184,14 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[
}
}
-static void drawseqwave(Scene *scene, Sequence *seq, float x1, float y1, float x2, float y2, float stepsize)
+static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequence *seq, float x1, float y1, float x2, float y2, float stepsize)
{
/*
* x1 is the starting x value to draw the wave,
* x2 the end x value, same for y1 and y2
* stepsize is width of a pixel.
*/
- if (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM) {
+ if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) {
int i, j, pos;
int length = floor((x2 - x1) / stepsize) + 1;
float ymid = (y1 + y2) / 2;
@@ -190,19 +199,37 @@ static void drawseqwave(Scene *scene, Sequence *seq, float x1, float y1, float x
float samplestep;
float startsample, endsample;
float value;
-
+ bSound *sound = seq->sound;
+
SoundWaveform *waveform;
-
- if (!seq->sound->waveform)
- sound_read_waveform(seq->sound);
-
- if (!seq->sound->waveform)
- return; /* zero length sound */
-
+
+ if (!sound->spinlock) {
+ sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
+ BLI_spin_init(sound->spinlock);
+ }
+
+ BLI_spin_lock(sound->spinlock);
+ if (!seq->sound->waveform) {
+ if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) {
+ /* prevent sounds from reloading */
+ seq->sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
+ sequencer_preview_add_sound(C, seq);
+ }
+ else {
+ BLI_spin_unlock(sound->spinlock);
+ }
+ return; /* nothing to draw */
+ }
+ BLI_spin_unlock(sound->spinlock);
+
waveform = seq->sound->waveform;
- if (!waveform)
+ if (waveform->length == 0) {
+ /* BKE_sound_read_waveform() set an empty SoundWaveform data in case it cannot generate a valid one...
+ * See T45726. */
return;
+ }
startsample = floor((seq->startofs + seq->anim_startofs) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND);
endsample = ceil((seq->startofs + seq->anim_startofs + seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND);
@@ -299,7 +326,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE))
drawmeta_stipple(1);
- get_seq_color3ubv(scene, seq, col);
+ color3ubv_from_seq(scene, seq, col);
glColor4ubv(col);
@@ -332,7 +359,10 @@ static float draw_seq_handle_size_get_clamped(Sequence *seq, const float pixelx)
{
const float minhandle = pixelx * SEQ_HANDLE_SIZE_MIN;
const float maxhandle = pixelx * SEQ_HANDLE_SIZE_MAX;
- return CLAMPIS(seq->handsize, minhandle, maxhandle);
+ float size = CLAMPIS(seq->handsize, minhandle, maxhandle);
+
+ /* ensure we're not greater than half width */
+ return min_ff(size, ((float)(seq->enddisp - seq->startdisp) / 2.0f) / pixelx);
}
/* draw a handle, for each end of a sequence strip */
@@ -371,7 +401,7 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
}
/* draw! */
- if (seq->type < SEQ_TYPE_EFFECT ||
+ if (!(seq->type & SEQ_TYPE_EFFECT) ||
BKE_sequence_effect_get_num_inputs(seq->type) == 0)
{
glEnable(GL_BLEND);
@@ -402,12 +432,12 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
size_t numstr_len;
if (direction == SEQ_LEFTHANDLE) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", seq->startdisp);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp);
x1 = rx1;
y1 -= 0.45f;
}
else {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
x1 = x2 - handsize_clamped * 0.75f;
y1 = y2 + 0.05f;
}
@@ -415,112 +445,6 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
}
}
-static void draw_seq_extensions(Scene *scene, ARegion *ar, Sequence *seq)
-{
- float x1, x2, y1, y2, pixely, a;
- unsigned char col[3], blendcol[3];
- View2D *v2d = &ar->v2d;
-
- if (seq->type >= SEQ_TYPE_EFFECT) return;
-
- x1 = seq->startdisp;
- x2 = seq->enddisp;
-
- y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
- y2 = seq->machine + SEQ_STRIP_OFSTOP;
-
- pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
-
- if (pixely <= 0) return; /* can happen when the view is split/resized */
-
- blendcol[0] = blendcol[1] = blendcol[2] = 120;
-
- if (seq->startofs) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- get_seq_color3ubv(scene, seq, col);
-
- if (seq->flag & SELECT) {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
- glColor4ub(col[0], col[1], col[2], 170);
- }
- else {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
- glColor4ub(col[0], col[1], col[2], 110);
- }
-
- glRectf((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1);
-
- if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
- else glColor4ub(col[0], col[1], col[2], 160);
-
- fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline
-
- glDisable(GL_BLEND);
- }
- if (seq->endofs) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- get_seq_color3ubv(scene, seq, col);
-
- if (seq->flag & SELECT) {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
- glColor4ub(col[0], col[1], col[2], 170);
- }
- else {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
- glColor4ub(col[0], col[1], col[2], 110);
- }
-
- glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
-
- if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
- else glColor4ub(col[0], col[1], col[2], 160);
-
- fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline
-
- glDisable(GL_BLEND);
- }
- if (seq->startstill) {
- get_seq_color3ubv(scene, seq, col);
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
- glColor3ubv((GLubyte *)col);
-
- draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2);
-
- /* feint pinstripes, helps see exactly which is extended and which isn't,
- * especially when the extension is very small */
- if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24);
- else UI_GetColorPtrShade3ubv(col, col, -16);
-
- glColor3ubv((GLubyte *)col);
-
- for (a = y1; a < y2; a += pixely * 2.0f) {
- fdrawline(x1, a, (float)(seq->start), a);
- }
- }
- if (seq->endstill) {
- get_seq_color3ubv(scene, seq, col);
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
- glColor3ubv((GLubyte *)col);
-
- draw_shadedstrip(seq, col, (float)(seq->start + seq->len), y1, x2, y2);
-
- /* feint pinstripes, helps see exactly which is extended and which isn't,
- * especially when the extension is very small */
- if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, 24);
- else UI_GetColorPtrShade3ubv(col, col, -16);
-
- glColor3ubv((GLubyte *)col);
-
- for (a = y1; a < y2; a += pixely * 2.0f) {
- fdrawline((float)(seq->start + seq->len), a, x2, a);
- }
- }
-}
-
/* draw info text on a sequence strip */
static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float y1, float y2, const unsigned char background_col[3])
{
@@ -554,7 +478,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
}
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
- if (seq->clip && strcmp(name, seq->clip->id.name + 2) != 0) {
+ if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->clip->id.name + 2, seq->len);
}
@@ -564,7 +488,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
}
}
else if (seq->type == SEQ_TYPE_MASK) {
- if (seq->mask && strcmp(name, seq->mask->id.name + 2) != 0) {
+ if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->mask->id.name + 2, seq->len);
}
@@ -581,6 +505,11 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
str_len = BLI_snprintf(str, sizeof(str), "%s: %s%s | %d",
name, seq->strip->dir, seq->strip->stripdata->name, seq->len);
}
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ TextVars *textdata = seq->effectdata;
+ str_len = BLI_snprintf(str, sizeof(str), "%s | %d",
+ textdata->text, seq->startdisp);
+ }
else if (seq->type & SEQ_TYPE_EFFECT) {
str_len = BLI_snprintf(str, sizeof(str), "%s | %d",
name, seq->len);
@@ -627,7 +556,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
}
/* draws a shaded strip, made from gradient + flat color + gradient */
-static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2)
+void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2)
{
float ymid1, ymid2;
@@ -684,12 +613,117 @@ static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, floa
}
}
+void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq)
+{
+ float x1, x2, y1, y2, pixely, a;
+ unsigned char col[3], blendcol[3];
+ View2D *v2d = &ar->v2d;
+
+ x1 = seq->startdisp;
+ x2 = seq->enddisp;
+
+ y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
+ y2 = seq->machine + SEQ_STRIP_OFSTOP;
+
+ pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
+
+ if (pixely <= 0) return; /* can happen when the view is split/resized */
+
+ blendcol[0] = blendcol[1] = blendcol[2] = 120;
+
+ if (seq->startofs) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ color3ubv_from_seq(scene, seq, col);
+
+ if (seq->flag & SELECT) {
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
+ glColor4ub(col[0], col[1], col[2], 170);
+ }
+ else {
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
+ glColor4ub(col[0], col[1], col[2], 110);
+ }
+
+ glRectf((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1);
+
+ if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
+ else glColor4ub(col[0], col[1], col[2], 160);
+
+ fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline
+
+ glDisable(GL_BLEND);
+ }
+ if (seq->endofs) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ color3ubv_from_seq(scene, seq, col);
+
+ if (seq->flag & SELECT) {
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
+ glColor4ub(col[0], col[1], col[2], 170);
+ }
+ else {
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
+ glColor4ub(col[0], col[1], col[2], 110);
+ }
+
+ glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+
+ if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
+ else glColor4ub(col[0], col[1], col[2], 160);
+
+ fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline
+
+ glDisable(GL_BLEND);
+ }
+ if (seq->startstill) {
+ color3ubv_from_seq(scene, seq, col);
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
+ glColor3ubv((GLubyte *)col);
+
+ draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2);
+
+ /* feint pinstripes, helps see exactly which is extended and which isn't,
+ * especially when the extension is very small */
+ if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24);
+ else UI_GetColorPtrShade3ubv(col, col, -16);
+
+ glColor3ubv((GLubyte *)col);
+
+ for (a = y1; a < y2; a += pixely * 2.0f) {
+ fdrawline(x1, a, (float)(seq->start), a);
+ }
+ }
+ if (seq->endstill) {
+ color3ubv_from_seq(scene, seq, col);
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
+ glColor3ubv((GLubyte *)col);
+
+ draw_shadedstrip(seq, col, (float)(seq->start + seq->len), y1, x2, y2);
+
+ /* feint pinstripes, helps see exactly which is extended and which isn't,
+ * especially when the extension is very small */
+ if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, 24);
+ else UI_GetColorPtrShade3ubv(col, col, -16);
+
+ glColor3ubv((GLubyte *)col);
+
+ for (a = y1; a < y2; a += pixely * 2.0f) {
+ fdrawline((float)(seq->start + seq->len), a, x2, a);
+ }
+ }
+}
+
+
/*
* Draw a sequence strip, bounds check already made
* ARegion is currently only used to get the windows width in pixels
* so wave file sample drawing precision is zoom adjusted
*/
-static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline_tint, float pixelx)
+static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, ARegion *ar, Sequence *seq, int outline_tint, float pixelx)
{
View2D *v2d = &ar->v2d;
float x1, x2, y1, y2;
@@ -707,8 +741,8 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline
/* get the correct color per strip type*/
- //get_seq_color3ubv(scene, seq, col);
- get_seq_color3ubv(scene, seq, background_col);
+ //color3ubv_from_seq(scene, seq, col);
+ color3ubv_from_seq(scene, seq, background_col);
/* draw the main strip body */
if (is_single_image) { /* single image */
@@ -719,11 +753,13 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline
else { /* normal operation */
draw_shadedstrip(seq, background_col, x1, y1, x2, y2);
}
-
- /* draw additional info and controls */
- if (!is_single_image)
- draw_seq_extensions(scene, ar, seq);
-
+
+ if (!is_single_image) {
+ if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) {
+ draw_sequence_extensions(scene, ar, seq);
+ }
+ }
+
draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE);
draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE);
@@ -733,7 +769,9 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline
/* draw sound wave */
if (seq->type == SEQ_TYPE_SOUND_RAM) {
- drawseqwave(scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx);
+ if (!(sseq->flag & SEQ_NO_WAVEFORMS)) {
+ drawseqwave(C, sseq, scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx);
+ }
}
/* draw lock */
@@ -766,7 +804,7 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline
glDisable(GL_POLYGON_STIPPLE);
}
- get_seq_color3ubv(scene, seq, col);
+ color3ubv_from_seq(scene, seq, col);
if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT)) {
if (seq->flag & SEQ_OVERLAP) {
col[0] = 255; col[1] = col[2] = 40;
@@ -784,7 +822,7 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline
glLineStipple(1, 0x8888);
}
- uiDrawBoxShade(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
+ UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
if (seq->flag & SEQ_MUTE) {
glDisable(GL_LINE_STIPPLE);
@@ -810,22 +848,32 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, Sequence *seq, int outline
}
}
-static Sequence *special_seq_update = NULL;
+void sequencer_special_update_set(Sequence *seq)
+{
+ special_seq_update = seq;
+}
-static void UNUSED_FUNCTION(set_special_seq_update) (int val)
+Sequence *ED_sequencer_special_preview_get(void)
{
-// int x;
+ return special_seq_update;
+}
- /* if mouse over a sequence && LEFTMOUSE */
- if (val) {
-// XXX special_seq_update = find_nearest_seq(&x);
- }
- else {
- special_seq_update = NULL;
- }
+void ED_sequencer_special_preview_set(bContext *C, const int mval[2])
+{
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ int hand;
+ Sequence *seq;
+ seq = find_nearest_seq(scene, &ar->v2d, &hand, mval);
+ sequencer_special_update_set(seq);
+}
+
+void ED_sequencer_special_preview_clear(void)
+{
+ sequencer_special_update_set(NULL);
}
-ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs)
+ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname)
{
SeqRenderData context;
ImBuf *ibuf;
@@ -835,9 +883,6 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
short is_break = G.is_break;
render_size = sseq->render_size;
- if (render_size == 99) {
- render_size = 100;
- }
if (render_size == 0) {
render_size = scene->r.size;
}
@@ -852,7 +897,11 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
rectx = (render_size * (float)scene->r.xsch) / 100.0f + 0.5f;
recty = (render_size * (float)scene->r.ysch) / 100.0f + 0.5f;
- context = BKE_sequencer_new_render_data(bmain->eval_ctx, bmain, scene, rectx, recty, proxy_size);
+ BKE_sequencer_new_render_data(
+ bmain->eval_ctx, bmain, scene,
+ rectx, recty, proxy_size,
+ &context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
/* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Esc pressed somewhere in the past
@@ -917,16 +966,110 @@ static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scop
return scope;
}
-void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay)
+static void sequencer_display_size(Scene *scene, SpaceSeq *sseq, float r_viewrect[2])
+{
+ float render_size, proxy_size;
+
+ if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
+ render_size = (float)scene->r.size / 100.0f;
+ proxy_size = 1.0f;
+ }
+ else {
+ render_size = (float)sseq->render_size / 100.0f;
+ proxy_size = render_size;
+ }
+
+ r_viewrect[0] = (render_size * (float)scene->r.xsch);
+ r_viewrect[1] = (render_size * (float)scene->r.ysch);
+
+ /* rectx = viewrectx + 0.5f; */ /* UNUSED */
+ /* recty = viewrecty + 0.5f; */ /* UNUSED */
+
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ r_viewrect[0] *= scene->r.xasp / scene->r.yasp;
+ r_viewrect[0] /= proxy_size;
+ r_viewrect[1] /= proxy_size;
+ }
+}
+
+static void sequencer_draw_gpencil(const bContext *C)
+{
+ /* draw grease-pencil (image aligned) */
+ ED_gpencil_draw_2dimage(C);
+
+ /* ortho at pixel level */
+ UI_view2d_view_restore(C);
+
+ /* draw grease-pencil (screen aligned) */
+ ED_gpencil_draw_view2d(C, 0);
+}
+
+/* draws content borders plus safety borders if needed */
+static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene)
+{
+ float x1 = v2d->tot.xmin;
+ float y1 = v2d->tot.ymin;
+ float x2 = v2d->tot.xmax;
+ float y2 = v2d->tot.ymax;
+
+ /* border */
+ setlinestyle(3);
+
+ UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x1 - 0.5f, y1 - 0.5f);
+ glVertex2f(x1 - 0.5f, y2 + 0.5f);
+ glVertex2f(x2 + 0.5f, y2 + 0.5f);
+ glVertex2f(x2 + 0.5f, y1 - 0.5f);
+ glEnd();
+
+ /* safety border */
+ if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title,
+ scene->safe_areas.action);
+
+ if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title_center,
+ scene->safe_areas.action_center);
+ }
+ }
+
+ setlinestyle(0);
+}
+
+/* draws checkerboard background for transparent content */
+static void sequencer_draw_background(const SpaceSeq *sseq, View2D *v2d, const float viewrect[2])
+{
+ /* setting up the view */
+ UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
+ UI_view2d_curRect_validate(v2d);
+ UI_view2d_view_ortho(v2d);
+
+ /* only draw alpha for main buffer */
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ if (sseq->flag & SEQ_USE_ALPHA) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ }
+ }
+}
+
+void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_backdrop)
{
struct Main *bmain = CTX_data_main(C);
struct ImBuf *ibuf = NULL;
struct ImBuf *scope = NULL;
struct View2D *v2d = &ar->v2d;
/* int rectx, recty; */ /* UNUSED */
- float viewrectx, viewrecty;
- float render_size = 0.0;
- float proxy_size = 100.0;
+ float viewrect[2];
float col[3];
GLuint texid;
GLuint last_texid;
@@ -935,6 +1078,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
const bool is_imbuf = ED_space_sequencer_check_show_imbuf(sseq);
int format, type;
bool glsl_used = false;
+ const bool draw_gpencil = ((sseq->flag & SEQ_SHOW_GPENCIL) && sseq->gpd);
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ bool draw_metadata = false;
if (G.is_rendering == false && (scene->r.seq_flag & R_SEQ_GL_PREV) == 0) {
/* stop all running jobs, except screen one. currently previews frustrate Render
@@ -950,48 +1096,44 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
}
- render_size = sseq->render_size;
- if (render_size == 0) {
- render_size = scene->r.size;
- }
- else {
- proxy_size = render_size;
- }
- if (render_size < 0) {
- return;
- }
-
- viewrectx = (render_size * (float)scene->r.xsch) / 100.0f;
- viewrecty = (render_size * (float)scene->r.ysch) / 100.0f;
-
- /* rectx = viewrectx + 0.5f; */ /* UNUSED */
- /* recty = viewrecty + 0.5f; */ /* UNUSED */
-
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
- viewrectx *= scene->r.xasp / scene->r.yasp;
- viewrectx /= proxy_size / 100.0f;
- viewrecty /= proxy_size / 100.0f;
- }
-
- if (!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) {
+ if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) {
UI_GetThemeColor3fv(TH_SEQ_PREVIEW, col);
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
}
+ /* without this colors can flicker from previous opengl state */
+ glColor4ub(255, 255, 255, 255);
+
/* only initialize the preview if a render is in progress */
if (G.is_rendering)
return;
- ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs);
-
- if (ibuf == NULL)
+ if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_NONE) {
return;
+ }
- if (ibuf->rect == NULL && ibuf->rect_float == NULL)
+ /* for now we only support Left/Right */
+ ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
+
+ if ((ibuf == NULL) ||
+ (ibuf->rect == NULL && ibuf->rect_float == NULL))
+ {
+ /* gpencil can also be drawn without a valid imbuf */
+ if (draw_gpencil && is_imbuf) {
+ sequencer_display_size(scene, sseq, viewrect);
+
+ sequencer_draw_background(sseq, v2d, viewrect);
+ sequencer_draw_borders(sseq, v2d, scene);
+
+ sequencer_draw_gpencil(C);
+ }
return;
+ }
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0) {
+ sequencer_display_size(scene, sseq, viewrect);
+
+ if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) {
SequencerScopes *scopes = &sseq->scopes;
sequencer_check_scopes(scopes, ibuf);
@@ -1037,32 +1179,21 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
/* future files may have new scopes we don't catch above */
if (scope) {
scopes->reference_ibuf = ibuf;
- viewrectx = scope->x;
- viewrecty = scope->y;
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ /* scopes drawn in image preview use viewrect from orig ibuf - currently that's only zebra */
+ }
+ else {
+ viewrect[0] = scope->x;
+ viewrect[1] = scope->y;
+ }
}
else {
scopes->reference_ibuf = NULL;
}
}
- /* without this colors can flicker from previous opengl state */
- glColor4ub(255, 255, 255, 255);
-
- UI_view2d_totRect_set(v2d, viewrectx + 0.5f, viewrecty + 0.5f);
- UI_view2d_curRect_validate(v2d);
-
- /* setting up the view - actual drawing starts here */
- UI_view2d_view_ortho(v2d);
-
- /* only draw alpha for main buffer */
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
- if (sseq->flag & SEQ_USE_ALPHA) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
- glColor4f(1.0, 1.0, 1.0, 1.0);
- }
+ if (!draw_backdrop) {
+ sequencer_draw_background(sseq, v2d, viewrect);
}
if (scope) {
@@ -1154,6 +1285,14 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, format, type, display_buffer);
+ if (draw_backdrop) {
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ }
glBegin(GL_QUADS);
if (draw_overlay) {
@@ -1176,13 +1315,37 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin);
}
}
+ else if (draw_backdrop) {
+ float aspect;
+ float image_aspect = viewrect[0] / viewrect[1];
+ float imagex, imagey;
+
+ aspect = BLI_rcti_size_x(&ar->winrct) / (float)BLI_rcti_size_y(&ar->winrct);
+
+ if (aspect >= image_aspect) {
+ imagex = image_aspect / aspect;
+ imagey = 1.0f;
+ }
+ else {
+ imagex = 1.0f;
+ imagey = aspect / image_aspect;
+ }
+
+ glTexCoord2f(0.0f, 0.0f); glVertex2f(-imagex, -imagey);
+ glTexCoord2f(0.0f, 1.0f); glVertex2f(-imagex, imagey);
+ glTexCoord2f(1.0f, 1.0f); glVertex2f(imagex, imagey);
+ glTexCoord2f(1.0f, 0.0f); glVertex2f(imagex, -imagey);
+ }
else {
+ draw_metadata = ((sseq->flag & SEQ_SHOW_METADATA) != 0);
+
glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin);
glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax);
glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax);
glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin);
}
glEnd();
+
glBindTexture(GL_TEXTURE_2D, last_texid);
glDisable(GL_TEXTURE_2D);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA)
@@ -1192,67 +1355,34 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if (glsl_used)
IMB_colormanagement_finish_glsl_draw();
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
-
- float x1 = v2d->tot.xmin;
- float y1 = v2d->tot.ymin;
- float x2 = v2d->tot.xmax;
- float y2 = v2d->tot.ymax;
-
- /* border */
- setlinestyle(3);
-
- UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(x1 - 0.5f, y1 - 0.5f);
- glVertex2f(x1 - 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y1 - 0.5f);
- glEnd();
-
- /* safety border */
- if ((sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) {
- float fac = 0.1;
-
- float a = fac * (x2 - x1);
- x1 += a;
- x2 -= a;
-
- a = fac * (y2 - y1);
- y1 += a;
- y2 -= a;
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- uiSetRoundBox(UI_CNR_ALL);
- uiDrawBox(GL_LINE_LOOP, x1, y1, x2, y2, 12.0);
+ if (cache_handle)
+ IMB_display_buffer_release(cache_handle);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if (!scope)
+ IMB_freeImBuf(ibuf);
- }
+ if (draw_metadata) {
+ ED_region_image_metadata_draw(0.0, 0.0, ibuf, v2d->tot, 1.0, 1.0);
+ }
- setlinestyle(0);
+ if (draw_backdrop) {
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ return;
}
-
- if (sseq->flag & SEQ_SHOW_GPENCIL) {
- if (is_imbuf) {
- /* draw grease-pencil (image aligned) */
- ED_gpencil_draw_2dimage(C);
- }
+
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ sequencer_draw_borders(sseq, v2d, scene);
}
- if (!scope)
- IMB_freeImBuf(ibuf);
-
- /* ortho at pixel level */
- UI_view2d_view_restore(C);
-
- if (sseq->flag & SEQ_SHOW_GPENCIL) {
- if (is_imbuf) {
- /* draw grease-pencil (screen aligned) */
- ED_gpencil_draw_view2d(C, 0);
- }
+ if (draw_gpencil && is_imbuf) {
+ sequencer_draw_gpencil(C);
+ }
+ else {
+ /* ortho at pixel level */
+ UI_view2d_view_restore(C);
}
@@ -1280,9 +1410,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
NULL, C);
}
}
-
- if (cache_handle)
- IMB_display_buffer_release(cache_handle);
}
#if 0
@@ -1359,6 +1486,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = &ar->v2d;
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
Sequence *last_seq = BKE_sequencer_active_get(scene);
int sel = 0, j;
float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
@@ -1379,7 +1507,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
else if (seq->machine > v2d->cur.ymax) continue;
/* strip passed all tests unscathed... so draw it now */
- draw_seq_strip(scene, ar, seq, outline_tint, pixelx);
+ draw_seq_strip(C, sseq, scene, ar, seq, outline_tint, pixelx);
}
/* draw selected next time round */
@@ -1388,20 +1516,33 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
/* draw the last selected last (i.e. 'active' in other parts of Blender), removes some overlapping error */
if (last_seq)
- draw_seq_strip(scene, ar, last_seq, 120, pixelx);
+ draw_seq_strip(C, sseq, scene, ar, last_seq, 120, pixelx);
+
+ /* draw highlight when previewing a single strip */
+ if (special_seq_update) {
+ const Sequence *seq = special_seq_update;
+ glEnable(GL_BLEND);
+ glColor4ub(255, 255, 255, 48);
+ glRectf(seq->startdisp, seq->machine + SEQ_STRIP_OFSBOTTOM, seq->enddisp, seq->machine + SEQ_STRIP_OFSTOP);
+ glDisable(GL_BLEND);
+ }
}
static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
-{
+{
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
+ const int frame_sta = PSFRA;
+ const int frame_end = PEFRA + 1;
+
glEnable(GL_BLEND);
/* draw darkened area outside of active timeline
* frame range used is preview range or scene range */
UI_ThemeColorShadeAlpha(TH_BACK, -25, -100);
- if (PSFRA < PEFRA + 1) {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- glRectf((float)(PEFRA + 1), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ if (frame_sta < frame_end) {
+ glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax);
+ glRectf((float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
@@ -1409,9 +1550,21 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
UI_ThemeColorShade(TH_BACK, -60);
/* thin lines where the actual frames are */
- fdrawline((float)PSFRA, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- fdrawline((float)(PEFRA + 1), v2d->cur.ymin, (float)(PEFRA + 1), v2d->cur.ymax);
-
+ fdrawline(frame_sta, v2d->cur.ymin, frame_sta, v2d->cur.ymax);
+ fdrawline(frame_end, v2d->cur.ymin, frame_end, v2d->cur.ymax);
+
+ if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
+ MetaStack *ms = ed->metastack.last;
+
+ glColor4ub(255, 255, 255, 8);
+ glRectf(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+
+ UI_ThemeColorShade(TH_BACK, -40);
+
+ fdrawline(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax);
+ fdrawline(ms->disp_range[1], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+ }
+
glDisable(GL_BLEND);
}
@@ -1450,6 +1603,11 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
// NOTE: the gridlines are currently spaced every 25 frames, which is only fine for 25 fps, but maybe not for 30...
UI_view2d_constant_grid_draw(v2d);
+ if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true);
+ UI_view2d_view_ortho(v2d);
+ }
+
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
seq_draw_sfra_efra(scene, v2d);
@@ -1471,7 +1629,7 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
- draw_markers_time(C, DRAW_MARKERS_LINES);
+ ED_markers_draw(C, DRAW_MARKERS_LINES | DRAW_MARKERS_MARGIN);
/* preview range */
UI_view2d_view_ortho(v2d);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 9c43d22ae2f..3cc0276104e 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -35,10 +35,13 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
+#include "BLI_timecode.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_scene_types.h"
@@ -49,7 +52,6 @@
#include "BKE_report.h"
#include "BKE_sound.h"
-#include "IMB_imbuf.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -59,11 +61,15 @@
/* for menu/popup icons etc etc*/
+#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_sequencer.h"
+#include "ED_space_api.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
+
/* own include */
#include "sequencer_intern.h"
@@ -87,6 +93,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
{SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
{SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
+ {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -145,11 +152,12 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
struct SeqIndexBuildContext *context = link->data;
BKE_sequencer_proxy_rebuild(context, stop, do_update, progress);
- }
-
- if (*stop) {
- pj->stop = 1;
- fprintf(stderr, "Canceling proxy rebuild on users request...\n");
+
+ if (*stop) {
+ pj->stop = 1;
+ fprintf(stderr, "Canceling proxy rebuild on users request...\n");
+ break;
+ }
}
}
@@ -175,9 +183,12 @@ static void seq_proxy_build_job(const bContext *C)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
ScrArea *sa = CTX_wm_area(C);
- struct SeqIndexBuildContext *context;
- LinkData *link;
Sequence *seq;
+ GSet *file_list;
+
+ if (ed == NULL) {
+ return;
+ }
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies",
WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PROXY);
@@ -195,16 +206,17 @@ static void seq_proxy_build_job(const bContext *C)
WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
}
+ file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
SEQP_BEGIN (ed, seq)
{
if ((seq->flag & SELECT)) {
- context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq);
- link = BLI_genericNodeN(context);
- BLI_addtail(&pj->queue, link);
+ BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list, &pj->queue);
}
}
SEQ_END
+ BLI_gset_free(file_list, MEM_freeN);
+
if (!WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
@@ -385,7 +397,7 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
displen = (float)abs(seq->startdisp - seq->enddisp);
if (displen / pixelx > 16) { /* don't even try to grab the handles of small strips */
- /* Set the max value to handle to 1/3 of the total len when its less then 28.
+ /* Set the max value to handle to 1/3 of the total len when its less than 28.
* This is important because otherwise selecting handles happens even when you click in the middle */
if ((displen / 3) < 30 * pixelx) {
@@ -494,6 +506,13 @@ bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF));
}
+bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq)
+{
+ return (ELEM(sseq->view, SEQ_VIEW_SEQUENCE, SEQ_VIEW_SEQUENCE_PREVIEW) &&
+ ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF));
+}
+
+
int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3, const char **error_str)
{
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -884,6 +903,7 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, false);
bool done = false;
+ TimeMarker *marker;
/* all strips >= cfra are shifted */
@@ -897,6 +917,14 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
}
}
+ if (!scene->toolsettings->lock_markers) {
+ for (marker = scene->markers.first; marker; marker = marker->next) {
+ if (marker->frame >= cfra) {
+ marker->frame += delta;
+ }
+ }
+ }
+
return done;
}
@@ -968,20 +996,20 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene)
return;
BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
-// XXX if (0 == sbutton(from, 0, sizeof(from)-1, "From: "))
+// XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
// return;
BLI_strncpy(to, from, sizeof(to));
-// XXX if (0 == sbutton(to, 0, sizeof(to)-1, "To: "))
+// XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
// return;
- if (strcmp(to, from) == 0)
+ if (STREQ(to, from))
return;
SEQP_BEGIN (ed, seq)
{
if (seq->flag & SELECT) {
- if (strncmp(seq->strip->dir, from, strlen(from)) == 0) {
+ if (STREQLEN(seq->strip->dir, from, strlen(from))) {
printf("found %s\n", seq->strip->dir);
/* strip off the beginning */
@@ -1019,7 +1047,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
break;
}
}
-
+
for ( ; cfra < efra; cfra++) {
/* first == 0 means there's still no strip to remove a gap for */
if (first == false) {
@@ -1129,7 +1157,7 @@ int sequencer_strip_has_path_poll(bContext *C)
return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq)));
}
-int sequencer_view_poll(bContext *C)
+int sequencer_view_preview_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
Editing *ed = BKE_sequencer_editing_get(CTX_data_scene(C), false);
@@ -1139,6 +1167,15 @@ int sequencer_view_poll(bContext *C)
return 0;
}
+int sequencer_view_strips_poll(bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq && ED_space_sequencer_check_show_strip(sseq))
+ return 1;
+
+ return 0;
+}
+
/* snap operator*/
static int sequencer_snap_exec(bContext *C, wmOperator *op)
{
@@ -1231,6 +1268,450 @@ void SEQUENCER_OT_snap(struct wmOperatorType *ot)
RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be snapped", INT_MIN, INT_MAX);
}
+typedef struct SlipData {
+ int init_mouse[2];
+ float init_mouseloc[2];
+ TransSeq *ts;
+ Sequence **seq_array;
+ bool *trim;
+ int num_seq;
+ bool slow;
+ int slow_offset; /* offset at the point where offset was turned on */
+ void *draw_handle;
+ NumInput num_input;
+} SlipData;
+
+static void transseq_backup(TransSeq *ts, Sequence *seq)
+{
+ ts->start = seq->start;
+ ts->machine = seq->machine;
+ ts->startstill = seq->startstill;
+ ts->endstill = seq->endstill;
+ ts->startdisp = seq->startdisp;
+ ts->enddisp = seq->enddisp;
+ ts->startofs = seq->startofs;
+ ts->endofs = seq->endofs;
+ ts->anim_startofs = seq->anim_startofs;
+ ts->anim_endofs = seq->anim_endofs;
+ ts->len = seq->len;
+}
+
+
+static void transseq_restore(TransSeq *ts, Sequence *seq)
+{
+ seq->start = ts->start;
+ seq->machine = ts->machine;
+ seq->startstill = ts->startstill;
+ seq->endstill = ts->endstill;
+ seq->startdisp = ts->startdisp;
+ seq->enddisp = ts->enddisp;
+ seq->startofs = ts->startofs;
+ seq->endofs = ts->endofs;
+ seq->anim_startofs = ts->anim_startofs;
+ seq->anim_endofs = ts->anim_endofs;
+ seq->len = ts->len;
+}
+
+static void draw_slip_extensions(const bContext *C, ARegion *ar, void *data)
+{
+ Scene *scene = CTX_data_scene(C);
+ SlipData *td = data;
+ int i;
+
+ for (i = 0; i < td->num_seq; i++) {
+ Sequence *seq = td->seq_array[i];
+
+ if ((seq->type != SEQ_TYPE_META) && td->trim[i]) {
+ draw_sequence_extensions(scene, ar, seq);
+ }
+ }
+}
+
+static int slip_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim)
+{
+ Sequence *seq;
+ int num_items = 0;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (!do_trim || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
+ seq_array[offset + num_items] = seq;
+ trim[offset + num_items] = do_trim;
+ num_items++;
+
+ if (seq->type == SEQ_TYPE_META) {
+ /* trim the sub-sequences */
+ num_items += slip_add_sequences_rec(&seq->seqbase, seq_array, trim, num_items + offset, false);
+ }
+ else if (seq->type & SEQ_TYPE_EFFECT) {
+ trim[offset + num_items] = false;
+ }
+ }
+ }
+
+ return num_items;
+}
+
+static int slip_count_sequences_rec(ListBase *seqbasep, bool first_level)
+{
+ Sequence *seq;
+ int trimmed_sequences = 0;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (!first_level || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
+ trimmed_sequences++;
+
+ if (seq->type == SEQ_TYPE_META) {
+ /* trim the sub-sequences */
+ trimmed_sequences += slip_count_sequences_rec(&seq->seqbase, false);
+ }
+ }
+ }
+
+ return trimmed_sequences;
+}
+
+static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SlipData *data;
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ ARegion *ar = CTX_wm_region(C);
+ float mouseloc[2];
+ int num_seq, i;
+ View2D *v2d = UI_view2d_fromcontext(C);
+
+ /* first recursively cound the trimmed elements */
+ num_seq = slip_count_sequences_rec(ed->seqbasep, true);
+
+ if (num_seq == 0)
+ return OPERATOR_CANCELLED;
+
+ data = op->customdata = MEM_mallocN(sizeof(SlipData), "trimdata");
+ data->ts = MEM_mallocN(num_seq * sizeof(TransSeq), "trimdata_transform");
+ data->seq_array = MEM_mallocN(num_seq * sizeof(Sequence *), "trimdata_sequences");
+ data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
+ data->num_seq = num_seq;
+
+ initNumInput(&data->num_input);
+ data->num_input.idx_max = 0;
+ data->num_input.val_flag[0] |= NUM_NO_FRACTION;
+ data->num_input.unit_sys = USER_UNIT_NONE;
+ data->num_input.unit_type[0] = 0;
+
+
+ slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+
+ for (i = 0; i < num_seq; i++) {
+ transseq_backup(data->ts + i, data->seq_array[i]);
+ }
+
+ data->draw_handle = ED_region_draw_cb_activate(ar->type, draw_slip_extensions, data, REGION_DRAW_POST_VIEW);
+
+ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
+
+ copy_v2_v2_int(data->init_mouse, event->mval);
+ copy_v2_v2(data->init_mouseloc, mouseloc);
+
+ data->slow = false;
+
+ WM_event_add_modal_handler(C, op);
+
+ /* notify so we draw extensions immediately */
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
+{
+
+ /* only data types supported for now */
+ if (offset != 0) {
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ int i;
+
+ /* we iterate in reverse so metastrips are iterated after their children */
+ for (i = data->num_seq - 1; i >= 0; i--) {
+ Sequence *seq = data->seq_array[i];
+ int endframe;
+ /* we have the offset, do the terrible math */
+
+ /* first, do the offset */
+ seq->start = data->ts[i].start + offset;
+
+ if (data->trim[i]) {
+ /* find the endframe */
+ endframe = seq->start + seq->len;
+
+ /* now compute the terrible offsets */
+ if (endframe > seq->enddisp) {
+ seq->endstill = 0;
+ seq->endofs = endframe - seq->enddisp;
+ }
+ else if (endframe <= seq->enddisp) {
+ seq->endstill = seq->enddisp - endframe;
+ seq->endofs = 0;
+ }
+
+ if (seq->start > seq->startdisp) {
+ seq->startstill = seq->start - seq->startdisp;
+ seq->startofs = 0;
+ }
+ else if (seq->start <= seq->startdisp) {
+ seq->startstill = 0;
+ seq->startofs = seq->startdisp - seq->start;
+ }
+ }
+ else {
+ /* if no real trim, don't change the data, rather transform the strips themselves */
+ seq->startdisp = data->ts[i].startdisp + offset;
+ seq->enddisp = data->ts[i].enddisp + offset;
+ }
+
+ /* effects are only added if we they are in a metastrip. In this case, dependent strips will just be transformed and we can skip calculating for effects
+ * This way we can avoid an extra loop just for effects*/
+ if (!(seq->type & SEQ_TYPE_EFFECT))
+ BKE_sequence_calc(scene, seq);
+ }
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+
+ return true;
+ }
+
+ return false;
+}
+
+static int sequencer_slip_exec(bContext *C, wmOperator *op)
+{
+ SlipData *data;
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ int num_seq, i;
+ int offset = RNA_int_get(op->ptr, "offset");
+ bool success = false;
+
+ /* first recursively cound the trimmed elements */
+ num_seq = slip_count_sequences_rec(ed->seqbasep, true);
+
+ if (num_seq == 0)
+ return OPERATOR_CANCELLED;
+
+ data = op->customdata = MEM_mallocN(sizeof(SlipData), "trimdata");
+ data->ts = MEM_mallocN(num_seq * sizeof(TransSeq), "trimdata_transform");
+ data->seq_array = MEM_mallocN(num_seq * sizeof(Sequence *), "trimdata_sequences");
+ data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
+ data->num_seq = num_seq;
+
+ slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+
+ for (i = 0; i < num_seq; i++) {
+ transseq_backup(data->ts + i, data->seq_array[i]);
+ }
+
+ success = sequencer_slip_recursively(scene, data, offset);
+
+ MEM_freeN(data->seq_array);
+ MEM_freeN(data->trim);
+ MEM_freeN(data->ts);
+ MEM_freeN(data);
+
+ if (success) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+
+static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
+{
+#define HEADER_LENGTH 40
+ char msg[HEADER_LENGTH];
+
+ if (sa) {
+ if (hasNumInput(&data->num_input)) {
+ char num_str[NUM_STR_REP_LEN];
+ outputNumInput(&data->num_input, num_str, &scene->unit);
+ BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str);
+ }
+ else {
+ BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset);
+ }
+ }
+
+ ED_area_headerprint(sa, msg);
+
+#undef HEADER_LENGTH
+}
+
+static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = CTX_data_scene(C);
+ SlipData *data = (SlipData *)op->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ const bool has_numInput = hasNumInput(&data->num_input);
+ bool handled = true;
+
+ /* Modal numinput active, try to handle numeric inputs first... */
+ if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &data->num_input, event)) {
+ float offset;
+ applyNumInput(&data->num_input, &offset);
+
+ sequencer_slip_update_header(scene, sa, data, (int)offset);
+
+ RNA_int_set(op->ptr, "offset", offset);
+
+ if (sequencer_slip_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ {
+ if (!has_numInput) {
+ float mouseloc[2];
+ int offset;
+ int mouse_x;
+ View2D *v2d = UI_view2d_fromcontext(C);
+
+ if (data->slow) {
+ mouse_x = event->mval[0] - data->slow_offset;
+ mouse_x *= 0.1f;
+ mouse_x += data->slow_offset;
+ }
+ else {
+ mouse_x = event->mval[0];
+ }
+
+
+ /* choose the side based on which side of the playhead the mouse is on */
+ UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
+ offset = mouseloc[0] - data->init_mouseloc[0];
+
+ sequencer_slip_update_header(scene, sa, data, offset);
+
+ RNA_int_set(op->ptr, "offset", offset);
+
+ if (sequencer_slip_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
+ }
+ break;
+ }
+
+ case LEFTMOUSE:
+ case RETKEY:
+ case SPACEKEY:
+ {
+ ED_region_draw_cb_exit(ar->type, data->draw_handle);
+ MEM_freeN(data->seq_array);
+ MEM_freeN(data->trim);
+ MEM_freeN(data->ts);
+ MEM_freeN(data);
+ op->customdata = NULL;
+ if (sa) {
+ ED_area_headerprint(sa, NULL);
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY:
+ case RIGHTMOUSE:
+ {
+ int i;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ for (i = 0; i < data->num_seq; i++) {
+ transseq_restore(data->ts + i, data->seq_array[i]);
+ }
+
+ for (i = 0; i < data->num_seq; i++) {
+ Sequence *seq = data->seq_array[i];
+ BKE_sequence_reload_new_file(scene, seq, false);
+ BKE_sequence_calc(scene, seq);
+ }
+
+ ED_region_draw_cb_exit(ar->type, data->draw_handle);
+
+ MEM_freeN(data->seq_array);
+ MEM_freeN(data->ts);
+ MEM_freeN(data->trim);
+ MEM_freeN(data);
+ op->customdata = NULL;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+
+ if (sa) {
+ ED_area_headerprint(sa, NULL);
+ }
+
+ return OPERATOR_CANCELLED;
+ }
+
+ case RIGHTSHIFTKEY:
+ case LEFTSHIFTKEY:
+ if (!has_numInput) {
+ if (event->val == KM_PRESS) {
+ data->slow = true;
+ data->slow_offset = event->mval[0];
+ }
+ else if (event->val == KM_RELEASE) {
+ data->slow = false;
+ }
+ }
+ break;
+
+ default:
+ handled = false;
+ break;
+ }
+
+ /* Modal numinput inactive, try to handle numeric inputs last... */
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) {
+ float offset;
+ applyNumInput(&data->num_input, &offset);
+
+ sequencer_slip_update_header(scene, sa, data, (int)offset);
+
+ RNA_int_set(op->ptr, "offset", offset);
+
+ if (sequencer_slip_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SEQUENCER_OT_slip(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Trim Strips";
+ ot->idname = "SEQUENCER_OT_slip";
+ ot->description = "Trim the contents of the active strip";
+
+ /* api callbacks */
+ ot->invoke = sequencer_slip_invoke;
+ ot->modal = sequencer_slip_modal;
+ ot->exec = sequencer_slip_exec;
+ ot->poll = sequencer_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "offset", 0, INT32_MIN, INT32_MAX, "Offset", "Offset to the data of the strip",
+ INT32_MIN, INT32_MAX);
+}
+
/* mute operator */
static int sequencer_mute_exec(bContext *C, wmOperator *op)
{
@@ -1269,7 +1750,7 @@ void SEQUENCER_OT_mute(struct wmOperatorType *ot)
/* identifiers */
ot->name = "Mute Strips";
ot->idname = "SEQUENCER_OT_mute";
- ot->description = "Mute selected strips";
+ ot->description = "Mute (un)selected strips";
/* api callbacks */
ot->exec = sequencer_mute_exec;
@@ -1320,7 +1801,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
/* identifiers */
ot->name = "Un-Mute Strips";
ot->idname = "SEQUENCER_OT_unmute";
- ot->description = "Un-Mute unselected rather than selected strips";
+ ot->description = "Unmute (un)selected strips";
/* api callbacks */
ot->exec = sequencer_unmute_exec;
@@ -1329,7 +1810,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "UnMute unselected rather than selected strips");
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unmute unselected rather than selected strips");
}
@@ -1446,6 +1927,14 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot)
}
/* reload operator */
+static int sequencer_refresh_all_poll(bContext *C)
+{
+ if (G.is_rendering) {
+ return 0;
+ }
+ return sequencer_edit_poll(C);
+}
+
static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1467,7 +1956,7 @@ void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = sequencer_refresh_all_exec;
- ot->poll = sequencer_edit_poll;
+ ot->poll = sequencer_refresh_all_poll;
}
static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
@@ -1993,6 +2482,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
BLI_addtail(&ed->metastack, ms);
ms->parseq = last_seq;
ms->oldbasep = ed->seqbasep;
+ copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
ed->seqbasep = &last_seq->seqbase;
@@ -2012,12 +2502,25 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
ed->seqbasep = ms->oldbasep;
+ /* for old files, update from meta */
+ if (ms->disp_range[0] == ms->disp_range[1]) {
+ copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
+ }
+
/* recalc all: the meta can have effects connected to it */
for (seq = ed->seqbasep->first; seq; seq = seq->next)
BKE_sequence_calc(scene, seq);
+ /* 2.73+, keeping endpoings is important!
+ * moving them around means you can't usefully use metas in a complex edit */
+#if 1
+ BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]);
+ BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]);
+ BKE_sequence_calc(scene, ms->parseq);
+#else
if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq))
BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene);
+#endif
BKE_sequencer_active_set(scene, ms->parseq);
@@ -2059,8 +2562,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
Sequence *seq, *seqm, *next, *last_seq = BKE_sequencer_active_get(scene);
int channel_max = 1;
- if (BKE_sequence_base_isolated_sel_check(ed->seqbasep, false) == false) {
- BKE_report(op->reports, RPT_ERROR, "Please select more than one or all related strips");
+ if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
+ BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
return OPERATOR_CANCELLED;
}
@@ -2439,88 +2942,13 @@ void SEQUENCER_OT_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-
-static int find_next_prev_edit(Scene *scene, int cfra,
- const short side,
- const bool do_skip_mute, const bool do_center)
-{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq, *best_seq = NULL, *frame_seq = NULL;
-
- int dist, best_dist;
- best_dist = MAXFRAME * 2;
-
- if (ed == NULL) return cfra;
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- int seq_frame;
-
- if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
- continue;
- }
-
- if (do_center) {
- seq_frame = (seq->startdisp + seq->enddisp) / 2;
- }
- else {
- seq_frame = seq->startdisp;
- }
-
- dist = MAXFRAME * 2;
-
- switch (side) {
- case SEQ_SIDE_LEFT:
- if (seq_frame < cfra) {
- dist = cfra - seq_frame;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if (seq_frame > cfra) {
- dist = seq_frame - cfra;
- }
- else if (seq_frame == cfra) {
- frame_seq = seq;
- }
- break;
- }
-
- if (dist < best_dist) {
- best_dist = dist;
- best_seq = seq;
- }
- }
-
- /* if no sequence to the right is found and the
- * frame is on the start of the last sequence,
- * move to the end of the last sequence */
- if (frame_seq) {
- if (do_center) {
- cfra = (frame_seq->startdisp + frame_seq->enddisp) / 2;
- }
- else {
- cfra = frame_seq->enddisp;
- }
- }
-
- if (best_seq) {
- if (do_center) {
- cfra = (best_seq->startdisp + best_seq->enddisp) / 2;
- }
- else {
- cfra = best_seq->startdisp;
- }
- }
-
- return cfra;
-}
-
static bool strip_jump_internal(Scene *scene,
const short side,
const bool do_skip_mute, const bool do_center)
{
bool changed = false;
int cfra = CFRA;
- int nfra = find_next_prev_edit(scene, cfra, side, do_skip_mute, do_center);
+ int nfra = BKE_sequencer_find_next_prev_edit(scene, cfra, side, do_skip_mute, do_center, false);
if (nfra != cfra) {
CFRA = nfra;
@@ -2753,7 +3181,7 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
else if (seq->scene_sound) {
- sound_remove_scene_sound(scene, seq->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq->scene_sound);
seq->scene_sound = NULL;
}
}
@@ -2767,7 +3195,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
BKE_sequencer_free_clipboard();
- if (BKE_sequence_base_isolated_sel_check(ed->seqbasep, true) == false) {
+ if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
return OPERATOR_CANCELLED;
}
@@ -2804,9 +3232,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
}
/* duplicate pointers */
- for (seq = seqbase_clipboard.first; seq; seq = seq->next) {
- BKE_sequence_clipboard_pointers_store(seq);
- }
+ BKE_sequencer_base_clipboard_pointers_store(&seqbase_clipboard);
}
return OPERATOR_FINISHED;
@@ -2850,9 +3276,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
- BKE_sequence_clipboard_pointers_restore(iseq, bmain);
- }
+ BKE_sequencer_base_clipboard_pointers_restore(&nseqbase, bmain);
for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
BKE_sequence_sound_init(scene, iseq);
@@ -2914,10 +3338,10 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
}
if (seq_act->scene_sound)
- sound_remove_scene_sound(scene, seq_act->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq_act->scene_sound);
if (seq_other->scene_sound)
- sound_remove_scene_sound(scene, seq_other->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq_other->scene_sound);
seq_act->scene_sound = NULL;
seq_other->scene_sound = NULL;
@@ -2925,8 +3349,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
BKE_sequence_calc(scene, seq_act);
BKE_sequence_calc(scene, seq_other);
- if (seq_act->sound) sound_add_scene_sound_defaults(scene, seq_act);
- if (seq_other->sound) sound_add_scene_sound_defaults(scene, seq_other);
+ if (seq_act->sound) BKE_sound_add_scene_sound_defaults(scene, seq_act);
+ if (seq_other->sound) BKE_sound_add_scene_sound_defaults(scene, seq_other);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2997,7 +3421,7 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
ot->invoke = WM_border_select_invoke;
ot->exec = view_ghost_border_exec;
ot->modal = WM_border_select_modal;
- ot->poll = sequencer_view_poll;
+ ot->poll = sequencer_view_preview_poll;
ot->cancel = WM_border_select_cancel;
/* flags */
@@ -3008,13 +3432,54 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
}
/* rebuild_proxy operator */
-static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
+
+static int sequencer_rebuild_proxy_invoke(bContext *C, wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
{
seq_proxy_build_job(C);
return OPERATOR_FINISHED;
}
+static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ GSet *file_list;
+
+ if (ed == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+
+ SEQP_BEGIN(ed, seq)
+ {
+ if ((seq->flag & SELECT)) {
+ ListBase queue = {NULL, NULL};
+ LinkData *link;
+ short stop = 0, do_update;
+ float progress;
+
+ BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list, &queue);
+
+ for (link = queue.first; link; link = link->next) {
+ struct SeqIndexBuildContext *context = link->data;
+ BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
+ BKE_sequencer_proxy_rebuild_finish(context, 0);
+ }
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+ }
+ }
+ SEQ_END
+
+ BLI_gset_free(file_list, MEM_freeN);
+
+ return OPERATOR_FINISHED;
+}
+
void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
{
/* identifiers */
@@ -3023,13 +3488,98 @@ void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
ot->description = "Rebuild all selected proxies and timecode indices using the job system";
/* api callbacks */
+ ot->invoke = sequencer_rebuild_proxy_invoke;
ot->exec = sequencer_rebuild_proxy_exec;
- ot->poll = ED_operator_sequencer_active;
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+static int sequencer_enable_proxies_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
+}
+
+static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25");
+ bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
+ bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
+ bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
+ bool override = RNA_boolean_get(op->ptr, "override");
+ bool turnon = true;
+
+ if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
+ turnon = false;
+ }
+
+ SEQP_BEGIN(ed, seq)
+ {
+ if ((seq->flag & SELECT)) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MULTICAM)) {
+ BKE_sequencer_proxy_set(seq, turnon);
+ if (seq->strip->proxy == NULL) {
+ continue;
+ }
+
+ if (proxy_25)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_25;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_25;
+
+ if (proxy_50)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_50;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_50;
+
+ if (proxy_75)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_75;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_75;
+
+ if (proxy_100)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_100;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
+
+ if (!override)
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+ else
+ seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
+ }
+ }
+ }
+ SEQ_END
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Selected Strip Proxies";
+ ot->idname = "SEQUENCER_OT_enable_proxies";
+ ot->description = "Enable selected proxies on all selected Movie strips";
+
+ /* api callbacks */
+ ot->invoke = sequencer_enable_proxies_invoke;
+ ot->exec = sequencer_enable_proxies_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+
+ RNA_def_boolean(ot->srna, "proxy_25", false, "25%", "");
+ RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
+ RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
+ RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
+ RNA_def_boolean(ot->srna, "override", false, "Override", "");
+}
+
/* change ops */
static EnumPropertyItem prop_change_effect_input_types[] = {
@@ -3164,12 +3714,21 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq = BKE_sequencer_active_get(scene);
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
+ const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
+ int minframe, numdigits;
if (seq->type == SEQ_TYPE_IMAGE) {
char directory[FILE_MAX];
- const int len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ int len;
StripElem *se;
+ /* need to find min/max frame for placeholders */
+ if (use_placeholders) {
+ len = sequencer_image_seq_get_minmax_frame(op, seq->sfra, &minframe, &numdigits);
+ }
+ else {
+ len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ }
if (len == 0)
return OPERATOR_CANCELLED;
@@ -3187,14 +3746,19 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
}
seq->strip->stripdata = se = MEM_callocN(len * sizeof(StripElem), "stripelem");
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
- BLI_strncpy(se->name, filename, sizeof(se->name));
- MEM_freeN(filename);
- se++;
+ if (use_placeholders) {
+ sequencer_image_seq_reserve_frames(op, se, len, minframe, numdigits);
+ }
+ else {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ BLI_strncpy(se->name, filename, sizeof(se->name));
+ MEM_freeN(filename);
+ se++;
+ }
+ RNA_END;
}
- RNA_END;
/* reset these else we wont see all the images */
seq->anim_startofs = seq->anim_endofs = 0;
@@ -3266,8 +3830,117 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY);
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
}
+static int sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+
+ if (G.main->name[0] == 0)
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ else
+ BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+
+ BLI_replace_extension(filepath, sizeof(filepath), ".srt");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Sequence *seq = BKE_sequencer_active_get(scene);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ int iter = 0;
+ FILE *file;
+ char filepath[FILE_MAX];
+
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+ BLI_ensure_extension(filepath, sizeof(filepath), ".srt");
+
+ /* Avoid File write exceptions */
+ if (!BLI_exists(filepath)) {
+ BLI_make_existing_file(filepath);
+ if (!BLI_file_touch(filepath)) {
+ BKE_report(op->reports, RPT_ERROR, "Can't create subtitle file");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if (!BLI_file_is_writable(filepath)) {
+ BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* time to open and write! */
+ file = BLI_fopen(filepath, "w");
+
+ SEQ_BEGIN(ed, seq)
+ {
+ if (seq->type == SEQ_TYPE_TEXT) {
+ TextVars *data = seq->effectdata;
+ char timecode_str[32];
+ double sec;
+ int frac;
+ int len;
+ fprintf(file, "%d\n", iter++);
+ sec = FRA2TIME(seq->startdisp);
+ frac = 1000 * (sec - floor(sec));
+ sec = floor(sec);
+ BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), 1, sec, FPS, USER_TIMECODE_SMPTE_FULL);
+ len = strlen(timecode_str);
+ timecode_str[len - 3] = 0;
+ fprintf(file, "%s,%d", timecode_str, frac);
+ sec = FRA2TIME(seq->enddisp);
+ BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), 1, sec, FPS, USER_TIMECODE_SMPTE_FULL);
+ len = strlen(timecode_str);
+ timecode_str[len - 3] = 0;
+ fprintf(file, " --> %s,%d\n", timecode_str, frac);
+ fprintf(file, "%s\n\n", data->text);
+ }
+ }
+ SEQ_END
+
+ fclose(file);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sequencer_strip_is_text_poll(bContext *C)
+{
+ Editing *ed;
+ Sequence *seq;
+ return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (seq->type == SEQ_TYPE_TEXT));
+}
+
+void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Export Subtitles";
+ ot->idname = "SEQUENCER_OT_export_subtitles";
+ ot->description = "Export .srt file containing text strips";
+
+ /* api callbacks */
+ ot->exec = sequencer_export_subtitles_exec;
+ ot->invoke = sequencer_export_subtitles_invoke;
+ ot->poll = sequencer_strip_is_text_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index df266b0f546..3e228fd0b31 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -45,6 +45,8 @@ struct ARegion;
struct ARegionType;
struct Scene;
struct Main;
+struct wmOperator;
+struct StripElem;
/* space_sequencer.c */
struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa);
@@ -52,12 +54,17 @@ struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa);
/* sequencer_draw.c */
void draw_timeline_seq(const struct bContext *C, struct ARegion *ar);
-void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegion *ar, struct SpaceSeq *sseq, int cfra, int offset, bool draw_overlay);
+void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegion *ar, struct SpaceSeq *sseq, int cfra, int offset, bool draw_overlay, bool draw_backdrop);
+void color3ubv_from_seq(struct Scene *curscene, struct Sequence *seq, unsigned char col[3]);
+void draw_shadedstrip(struct Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2);
+void draw_sequence_extensions(struct Scene *scene, struct ARegion *ar, struct Sequence *seq);
+
+void sequencer_special_update_set(Sequence *seq);
/* UNUSED */
// void seq_reset_imageofs(struct SpaceSeq *sseq);
-struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs);
+struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname);
/* sequencer_edit.c */
struct View2D;
@@ -73,7 +80,8 @@ int sequencer_edit_poll(struct bContext *C);
/* UNUSED */
//int sequencer_strip_poll(struct bContext *C);
int sequencer_strip_has_path_poll(struct bContext *C);
-int sequencer_view_poll(struct bContext *C);
+int sequencer_view_preview_poll(struct bContext *C);
+int sequencer_view_strips_poll(struct bContext *C);
/* externs */
extern EnumPropertyItem sequencer_prop_effect_types[];
@@ -84,6 +92,7 @@ struct wmOperatorType;
struct wmKeyConfig;
void SEQUENCER_OT_cut(struct wmOperatorType *ot);
+void SEQUENCER_OT_slip(struct wmOperatorType *ot);
void SEQUENCER_OT_mute(struct wmOperatorType *ot);
void SEQUENCER_OT_unmute(struct wmOperatorType *ot);
void SEQUENCER_OT_lock(struct wmOperatorType *ot);
@@ -123,6 +132,9 @@ void SEQUENCER_OT_copy(struct wmOperatorType *ot);
void SEQUENCER_OT_paste(struct wmOperatorType *ot);
void SEQUENCER_OT_rebuild_proxy(struct wmOperatorType *ot);
+void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot);
+
+void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot);
/* preview specific operators */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);
@@ -149,13 +161,6 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot);
-/* RNA enums, just to be more readable */
-enum {
- SEQ_SIDE_NONE = 0,
- SEQ_SIDE_LEFT,
- SEQ_SIDE_RIGHT,
- SEQ_SIDE_BOTH
-};
enum {
SEQ_CUT_SOFT,
SEQ_CUT_HARD
@@ -194,9 +199,17 @@ void SEQUENCER_OT_properties(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_add(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_remove(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_move(struct wmOperatorType *ot);
+void SEQUENCER_OT_strip_modifier_copy(struct wmOperatorType *ot);
/* sequencer_view.c */
void SEQUENCER_OT_sample(struct wmOperatorType *ot);
+/* sequencer_preview.c */
+void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq);
+
+/* sequencer_add */
+int sequencer_image_seq_get_minmax_frame(struct wmOperator *op, int sfra, int *r_minframe, int *r_numdigits);
+void sequencer_image_seq_reserve_frames(struct wmOperator *op, struct StripElem *se, int len, int minframe, int numdigits);
+
#endif /* __SEQUENCER_INTERN_H__ */
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index ff40bf1e638..fad317fdd4e 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -29,24 +29,14 @@
* \ingroup spseq
*/
-#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
-#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_scene_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_userdef_types.h"
#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_sequencer.h"
-#include "BKE_movieclip.h"
-#include "BKE_mask.h"
-#include "BKE_report.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -54,8 +44,6 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
/* own include */
#include "sequencer_intern.h"
@@ -219,3 +207,58 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
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", "");
}
+
+static int strip_modifier_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = scene->ed;
+ Sequence *seq = BKE_sequencer_active_get(scene);
+ Sequence *seq_iter;
+
+ if (!seq || !seq->modifiers.first)
+ return OPERATOR_CANCELLED;
+
+ SEQP_BEGIN(ed, seq_iter)
+ {
+ if (seq_iter->flag & SELECT) {
+ if (seq_iter == seq)
+ continue;
+
+ if (seq_iter->modifiers.first) {
+ SequenceModifierData *smd_tmp, *smd = seq_iter->modifiers.first;
+
+ while (smd) {
+ smd_tmp = smd->next;
+ BLI_remlink(&seq_iter->modifiers, smd);
+ BKE_sequence_modifier_free(smd);
+ smd = smd_tmp;
+ }
+ BLI_listbase_clear(&seq_iter->modifiers);
+ }
+
+ BKE_sequence_modifier_list_copy(seq_iter, seq);
+ }
+ }
+ SEQ_END
+
+ BKE_sequence_invalidate_cache(scene, seq);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_strip_modifier_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy to Selected Strips";
+ ot->idname = "SEQUENCER_OT_strip_modifier_copy";
+ ot->description = "Copy modifiers of the active strip to all selected strips";
+
+ /* api callbacks */
+ ot->exec = strip_modifier_copy_exec;
+ ot->poll = strip_modifier_active_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index c5e47c3aa3e..3d08e0c5ed8 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -40,6 +40,8 @@
#include "ED_markers.h"
#include "ED_transform.h" /* transform keymap */
+#include "BKE_sequencer.h"
+
#include "sequencer_intern.h"
@@ -50,6 +52,7 @@ void sequencer_operatortypes(void)
{
/* sequencer_edit.c */
WM_operatortype_append(SEQUENCER_OT_cut);
+ WM_operatortype_append(SEQUENCER_OT_slip);
WM_operatortype_append(SEQUENCER_OT_mute);
WM_operatortype_append(SEQUENCER_OT_unmute);
WM_operatortype_append(SEQUENCER_OT_lock);
@@ -74,6 +77,8 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_swap_data);
WM_operatortype_append(SEQUENCER_OT_rendersize);
+ WM_operatortype_append(SEQUENCER_OT_export_subtitles);
+
WM_operatortype_append(SEQUENCER_OT_copy);
WM_operatortype_append(SEQUENCER_OT_paste);
@@ -85,6 +90,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_view_ghost_border);
WM_operatortype_append(SEQUENCER_OT_rebuild_proxy);
+ WM_operatortype_append(SEQUENCER_OT_enable_proxies);
WM_operatortype_append(SEQUENCER_OT_change_effect_input);
WM_operatortype_append(SEQUENCER_OT_change_effect_type);
WM_operatortype_append(SEQUENCER_OT_change_path);
@@ -117,6 +123,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_strip_modifier_add);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_remove);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_move);
+ WM_operatortype_append(SEQUENCER_OT_strip_modifier_copy);
/* sequencer_view.h */
WM_operatortype_append(SEQUENCER_OT_sample);
@@ -316,6 +323,8 @@ void sequencer_keymap(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "SEQUENCER_MT_change", CKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "SEQUENCER_OT_slip", SKEY, KM_PRESS, 0, 0);
+
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_int", OKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "scene.sequence_editor.overlay_frame");
RNA_int_set(kmi->ptr, "value", 0);
@@ -359,5 +368,5 @@ void ED_operatormacros_sequencer(void)
"Duplicate selected strips and move them", OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
- WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_seq_slide");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c
new file mode 100644
index 00000000000..3f908dc7096
--- /dev/null
+++ b/source/blender/editors/space_sequencer/sequencer_preview.c
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2003-2009, Antony Riakiotakis
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_sequencer/sequencer_preview.c
+ * \ingroup spseq
+ */
+
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+
+#include "BKE_sound.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "sequencer_intern.h"
+
+typedef struct PreviewJob {
+ ListBase previews;
+ ThreadMutex *mutex;
+ Scene *scene;
+ int total;
+ int processed;
+} PreviewJob;
+
+typedef struct PreviewJobAudio {
+ struct PreviewJobAudio *next, *prev;
+ bSound *sound;
+ int lr; /* sample left or right */
+ int startframe;
+ bool waveform; /* reload sound or waveform */
+} PreviewJobAudio;
+
+static void free_preview_job(void *data)
+{
+ PreviewJob *pj = (PreviewJob *)data;
+
+ BLI_mutex_free(pj->mutex);
+ BLI_freelistN(&pj->previews);
+ MEM_freeN(pj);
+}
+
+/* only this runs inside thread */
+static void preview_startjob(void *data, short *stop, short *do_update, float *progress)
+{
+ PreviewJob *pj = data;
+ PreviewJobAudio *previewjb;
+
+ BLI_mutex_lock(pj->mutex);
+ previewjb = pj->previews.first;
+ BLI_mutex_unlock(pj->mutex);
+
+ while (previewjb) {
+ PreviewJobAudio *preview_next;
+ bSound *sound = previewjb->sound;
+
+ BKE_sound_read_waveform(sound, stop);
+
+ if (*stop || G.is_break) {
+ BLI_mutex_lock(pj->mutex);
+ previewjb = previewjb->next;
+ BLI_mutex_unlock(pj->mutex);
+ while (previewjb) {
+ sound = previewjb->sound;
+
+ /* make sure we cleanup the loading flag! */
+ BLI_spin_lock(sound->spinlock);
+ sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
+
+ BLI_mutex_lock(pj->mutex);
+ previewjb = previewjb->next;
+ BLI_mutex_unlock(pj->mutex);
+ }
+
+ BLI_mutex_lock(pj->mutex);
+ BLI_freelistN(&pj->previews);
+ pj->total = 0;
+ pj->processed = 0;
+ BLI_mutex_unlock(pj->mutex);
+ break;
+ }
+
+ BLI_mutex_lock(pj->mutex);
+ preview_next = previewjb->next;
+ BLI_freelinkN(&pj->previews, previewjb);
+ previewjb = preview_next;
+ pj->processed++;
+ *progress = (pj->total > 0) ? (float)pj->processed / (float)pj->total : 1.0f;
+ *do_update = true;
+ BLI_mutex_unlock(pj->mutex);
+ }
+}
+
+static void preview_endjob(void *data)
+{
+ PreviewJob *pj = data;
+
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
+}
+
+
+void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
+{
+ /* first, get the preview job, if it exists */
+ wmJob *wm_job;
+ PreviewJob *pj;
+ ScrArea *sa = CTX_wm_area(C);
+ PreviewJobAudio *audiojob = MEM_callocN(sizeof(PreviewJobAudio), "preview_audio");
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Strip Previews",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PREVIEW);
+
+ pj = WM_jobs_customdata_get(wm_job);
+
+ if (!pj) {
+ pj = MEM_callocN(sizeof(PreviewJob), "preview rebuild job");
+
+ pj->mutex = BLI_mutex_alloc();
+ pj->scene = CTX_data_scene(C);
+
+ WM_jobs_customdata_set(wm_job, pj, free_preview_job);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
+ WM_jobs_callbacks(wm_job, preview_startjob, NULL, NULL, preview_endjob);
+ }
+
+ /* attempt to lock mutex of job here */
+
+ audiojob->sound = seq->sound;
+
+ BLI_mutex_lock(pj->mutex);
+ BLI_addtail(&pj->previews, audiojob);
+ pj->total++;
+ BLI_mutex_unlock(pj->mutex);
+
+ if (!WM_jobs_is_running(wm_job)) {
+ G.is_break = false;
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+
+ ED_area_tag_redraw(sa);
+}
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 9b3b9f23036..c197aabedfd 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -29,9 +29,9 @@
#include <math.h>
#include <string.h>
-#include "BLI_math_color.h"
#include "BLI_utildefines.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -55,7 +55,7 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
static void scope_put_pixel(unsigned char *table, unsigned char *pos)
{
- char newval = table[*pos];
+ unsigned char newval = table[*pos];
pos[0] = pos[1] = pos[2] = newval;
pos[3] = 255;
}
@@ -148,8 +148,8 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- unsigned char *src = (unsigned char *) ibuf->rect;
- unsigned char *tgt = (unsigned char *) rval->rect;
+ const unsigned char *src = (unsigned char *)ibuf->rect;
+ unsigned char *tgt = (unsigned char *)rval->rect;
int w = ibuf->x + 3;
int h = 515;
float waveform_gamma = 0.2;
@@ -166,8 +166,8 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
unsigned char *last_p = NULL;
for (x = 0; x < ibuf->x; x++) {
- unsigned char *rgb = src + 4 * (ibuf->x * y + x);
- float v = (float)rgb_to_luma_byte(rgb) / 255.0f;
+ const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
+ float v = (float)IMB_colormanagement_get_luminance_byte(rgb) / 255.0f;
unsigned char *p = tgt;
p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1);
@@ -189,7 +189,7 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- float *src = ibuf->rect_float;
+ const float *src = ibuf->rect_float;
unsigned char *tgt = (unsigned char *) rval->rect;
int w = ibuf->x + 3;
int h = 515;
@@ -207,7 +207,7 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
for (x = 0; x < ibuf->x; x++) {
const float *rgb = src + 4 * (ibuf->x * y + x);
- float v = rgb_to_luma(rgb);
+ float v = IMB_colormanagement_get_luminance(rgb);
unsigned char *p = tgt;
CLAMP(v, 0.0f, 1.0f);
@@ -245,8 +245,8 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- unsigned char *src = (unsigned char *) ibuf->rect;
- unsigned char *tgt = (unsigned char *) rval->rect;
+ const unsigned char *src = (const unsigned char *)ibuf->rect;
+ unsigned char *tgt = (unsigned char *)rval->rect;
int w = ibuf->x + 3;
int sw = ibuf->x / 3;
int h = 515;
@@ -264,7 +264,7 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf)
for (x = 0; x < ibuf->x; x++) {
int c;
- unsigned char *rgb = src + 4 * (ibuf->x * y + x);
+ const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
for (c = 0; c < 3; c++) {
unsigned char *p = tgt;
p += 4 * (w * ((rgb[c] * (h - 3)) / 255 + 1) + c * sw + x / 3 + 1);
@@ -290,8 +290,8 @@ static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- float *src = ibuf->rect_float;
- unsigned char *tgt = (unsigned char *) rval->rect;
+ const float *src = ibuf->rect_float;
+ unsigned char *tgt = (unsigned char *)rval->rect;
int w = ibuf->x + 3;
int sw = ibuf->x / 3;
int h = 515;
@@ -455,7 +455,7 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
int x, y;
unsigned int nr, ng, nb;
- unsigned char *src = (unsigned char *) ibuf->rect;
+ const unsigned char *src = (unsigned char *)ibuf->rect;
unsigned int bins[3][HIS_STEPS];
@@ -468,7 +468,7 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
memset(cur_bins, 0, sizeof(cur_bins));
for (x = 0; x < ibuf->x; x++) {
- unsigned char *pixel = src + (y * ibuf->x + x) * 4;
+ const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
cur_bins[0][pixel[0]]++;
cur_bins[1][pixel[1]]++;
@@ -532,7 +532,7 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
int nr, ng, nb, x, y;
- float *src = ibuf->rect_float;
+ const float *src = ibuf->rect_float;
unsigned int bins[3][HIS_STEPS];
@@ -635,7 +635,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect);
int x, y;
- char *src = (char *) ibuf->rect;
+ const char *src = (const char *) ibuf->rect;
char *tgt = (char *) rval->rect;
float rgb[3], yuv[3];
int w = 515;
@@ -647,19 +647,19 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
wtable[x] = (unsigned char) (pow(((float) x + 1) / 256, scope_gamma) * 255);
}
- for (x = 0; x <= 255; x++) {
- vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
- vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
- vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
- vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
- vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
- vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ for (x = 0; x < 256; x++) {
+ vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
for (x = 0; x < ibuf->x; x++) {
const char *src1 = src + 4 * (ibuf->x * y + x);
- const char *p;
+ char *p;
rgb[0] = (float)src1[0] / 255.0f;
rgb[1] = (float)src1[1] / 255.0f;
@@ -681,7 +681,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect);
int x, y;
- float *src = ibuf->rect_float;
+ const float *src = ibuf->rect_float;
char *tgt = (char *) rval->rect;
float rgb[3], yuv[3];
int w = 515;
@@ -694,12 +694,12 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
}
for (x = 0; x <= 255; x++) {
- vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
- vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
- vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
- vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
- vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
- vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 933daf4adee..3dff2442f45 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -66,17 +66,23 @@ static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRIN
neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
if (neighbor) {
+ /* Only select neighbor handle if matching handle from test seq is also selected, or if neighbor
+ * was not selected at all up till now.
+ * Otherwise, we get odd mismatch when shift-alt-rmb selecting neighbor strips... */
+ if (!(neighbor->flag & SELECT) || (test->flag & SEQ_LEFTSEL)) {
+ neighbor->flag |= SEQ_RIGHTSEL;
+ }
neighbor->flag |= SELECT;
recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_RIGHTSEL;
}
neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
if (neighbor) {
+ if (!(neighbor->flag & SELECT) || (test->flag & SEQ_RIGHTSEL)) { /* See comment above. */
+ neighbor->flag |= SEQ_LEFTSEL;
+ }
neighbor->flag |= SELECT;
recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_LEFTSEL;
}
- test->flag |= SELECT;
}
/* used for mouse selection and for SEQUENCER_OT_select_active_side() */
@@ -357,40 +363,33 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
case SEQ_SELECT_LR_MOUSE:
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
break;
-
case SEQ_SELECT_LR_LEFT:
- x = CFRA - 1;
+ x = CFRA - 1.0f;
break;
case SEQ_SELECT_LR_RIGHT:
- x = CFRA + 1;
+ default:
+ x = CFRA;
break;
}
SEQP_BEGIN (ed, seq)
{
- if (x < CFRA) {
- if (seq->enddisp < CFRA) {
- seq->flag |= SELECT;
- recurs_sel_seq(seq);
- }
- }
- else {
- if (seq->startdisp > CFRA) {
- seq->flag |= SELECT;
- recurs_sel_seq(seq);
- }
+ if (((x < CFRA) && (seq->enddisp <= CFRA)) ||
+ ((x >= CFRA) && (seq->startdisp >= CFRA)))
+ {
+ seq->flag |= SELECT;
+ recurs_sel_seq(seq);
}
}
SEQ_END
-
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
TimeMarker *tmarker;
for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
- if (((x < CFRA) && tmarker->frame < CFRA) ||
- ((x >= CFRA) && tmarker->frame >= CFRA))
+ if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
+ ((x >= CFRA) && (tmarker->frame >= CFRA)))
{
tmarker->flag |= SELECT;
}
@@ -423,83 +422,94 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
- if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
- switch (hand) {
- case SEQ_SIDE_NONE:
- if (linked_handle == 0)
- seq->flag &= ~SEQ_ALLSEL;
- break;
- case SEQ_SIDE_LEFT:
- seq->flag ^= SEQ_LEFTSEL;
- break;
- case SEQ_SIDE_RIGHT:
- seq->flag ^= SEQ_RIGHTSEL;
- break;
+ /* On Alt selection, select the strip and bordering handles */
+ if (linked_handle) {
+ if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
+ /* First click selects the strip and its adjacent handles (if valid).
+ * Second click selects the strip, both of its handles and its adjacent handles (if valid).
+ */
+ const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ }
+ seq->flag &= ~SEQ_ALLSEL;
+ seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
+ select_surrounding_handles(scene, seq);
+ }
+ else if (seq->flag & SELECT) {
+ /* First click selects adjacent handles on that side.
+ * Second click selects all strips in that direction.
+ * If there are no adjacent strips, it just selects all in that direction.
+ */
+ sel_side = hand;
+ neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
+ if (neighbor) {
+ switch (sel_side) {
+ case SEQ_SIDE_LEFT:
+ if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
+ if (extend == 0) ED_sequencer_deselect_all(scene);
+ seq->flag |= SELECT;
+
+ select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
+ }
+ else {
+ if (extend == 0) ED_sequencer_deselect_all(scene);
+ seq->flag |= SELECT;
+
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
+ if (extend == 0) ED_sequencer_deselect_all(scene);
+ seq->flag |= SELECT;
+
+ select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
+ }
+ else {
+ if (extend == 0) ED_sequencer_deselect_all(scene);
+ seq->flag |= SELECT;
+
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ break;
+ }
+ }
+ else {
+ if (extend == 0) ED_sequencer_deselect_all(scene);
+ select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ }
}
}
else {
- seq->flag |= SELECT;
- if (hand == SEQ_SIDE_LEFT) seq->flag |= SEQ_LEFTSEL;
- if (hand == SEQ_SIDE_RIGHT) seq->flag |= SEQ_RIGHTSEL;
- }
-
- /* On Alt selection, select the strip and bordering handles */
- if (linked_handle && !ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
- if (extend == 0) ED_sequencer_deselect_all(scene);
- seq->flag |= SELECT;
- select_surrounding_handles(scene, seq);
- }
- else if (linked_handle && ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT) && (seq->flag & SELECT)) {
- /*
- * First click selects adjacent handles on that side.
- * Second click selects all strips in that direction.
- * If there are no adjacent strips, it just selects all in that direction.
- */
- sel_side = hand;
- neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
- if (neighbor) {
- switch (sel_side) {
+ if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
+ switch (hand) {
+ case SEQ_SIDE_NONE:
+ if (linked_handle == 0)
+ seq->flag &= ~SEQ_ALLSEL;
+ break;
case SEQ_SIDE_LEFT:
- if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
- if (extend == 0) ED_sequencer_deselect_all(scene);
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) ED_sequencer_deselect_all(scene);
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_RIGHTSEL;
- seq->flag |= SEQ_LEFTSEL;
- }
+ seq->flag ^= SEQ_LEFTSEL;
break;
case SEQ_SIDE_RIGHT:
- if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
- if (extend == 0) ED_sequencer_deselect_all(scene);
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) ED_sequencer_deselect_all(scene);
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_LEFTSEL;
- seq->flag |= SEQ_RIGHTSEL;
- }
+ seq->flag ^= SEQ_RIGHTSEL;
break;
}
}
else {
- if (extend == 0) ED_sequencer_deselect_all(scene);
- select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ seq->flag |= SELECT;
+ if (hand == SEQ_SIDE_LEFT) seq->flag |= SEQ_LEFTSEL;
+ if (hand == SEQ_SIDE_RIGHT) seq->flag |= SEQ_RIGHTSEL;
}
}
+
recurs_sel_seq(seq);
if (linked_time) {
@@ -591,21 +601,35 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if ((int)(seq->flag & SELECT) == sel) {
- if ((linked == 0 && seq->tmp) == 0) {
- /* only get unselected nabours */
+ if ((seq->flag & SELECT) == sel) {
+ if (linked || (seq->tmp == NULL)) {
+ /* only get unselected neighbors */
neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
if (neighbor) {
- if (sel) { neighbor->flag |= SELECT; recurs_sel_seq(neighbor); }
- else neighbor->flag &= ~SELECT;
- if (linked == 0) neighbor->tmp = (Sequence *)1;
+ if (sel) {
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ }
+ else {
+ neighbor->flag &= ~SELECT;
+ }
+ if (!linked) {
+ neighbor->tmp = (Sequence *)1;
+ }
changed = true;
}
neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
if (neighbor) {
- if (sel) { neighbor->flag |= SELECT; recurs_sel_seq(neighbor); }
- else neighbor->flag &= ~SELECT;
- if (linked == 0) neighbor->tmp = (void *)1;
+ if (sel) {
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ }
+ else {
+ neighbor->flag &= ~SELECT;
+ }
+ if (!linked) {
+ neighbor->tmp = (Sequence *)1;
+ }
changed = true;
}
}
@@ -622,7 +646,7 @@ static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- if (!select_more_less_seq__internal(scene, 0, 0))
+ if (!select_more_less_seq__internal(scene, true, false))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
@@ -653,7 +677,7 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- if (!select_more_less_seq__internal(scene, 1, 0))
+ if (!select_more_less_seq__internal(scene, false, false))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
@@ -999,7 +1023,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
if (SEQ_HAS_PATH(actseq) && dir) {
SEQP_BEGIN (ed, seq)
{
- if (SEQ_HAS_PATH(seq) && seq->strip && strcmp(seq->strip->dir, dir) == 0) {
+ if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1047,15 +1071,15 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
{
Sequence *seq;
bool changed = false;
- bool effects[SEQ_TYPE_EFFECT_MAX + 1];
+ bool effects[SEQ_TYPE_MAX + 1];
int i;
- for (i = 0; i <= SEQ_TYPE_EFFECT_MAX; i++)
+ for (i = 0; i <= SEQ_TYPE_MAX; i++)
effects[i] = false;
SEQP_BEGIN (ed, seq)
{
- if (ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 7fdbc9cc7de..4d6ea865b40 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -94,7 +94,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *) CTX_wm_space_data(C);
ARegion *ar = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;
@@ -201,8 +201,11 @@ static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: /* XXX hardcoded */
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
sample_apply(C, op, event);
break;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index c0cfaed7867..5b3061bd513 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -144,9 +144,9 @@ static SpaceLink *sequencer_new(const bContext *C)
ar->alignment = RGN_ALIGN_TOP;
ar->flag |= RGN_FLAG_HIDDEN;
/* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
- ar->v2d.keepzoom = V2D_KEEPASPECT | V2D_KEEPZOOM;
- ar->v2d.minzoom = 0.00001f;
- ar->v2d.maxzoom = 100000.0f;
+ ar->v2d.keepzoom = V2D_KEEPASPECT | V2D_KEEPZOOM | V2D_LIMITZOOM;
+ ar->v2d.minzoom = 0.001f;
+ ar->v2d.maxzoom = 1000.0f;
ar->v2d.tot.xmin = -960.0f; /* 1920 width centered */
ar->v2d.tot.ymin = -540.0f; /* 1080 height centered */
ar->v2d.tot.xmax = 960.0f;
@@ -328,7 +328,7 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
SpaceSeq *sseqn = MEM_dupallocN(sl);
/* clear or remove stuff from old */
-// XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd);
+// XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd, false);
memset(&sseqn->scopes, 0, sizeof(sseqn->scopes));
@@ -352,6 +352,10 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn
if (wmn->data == ND_SPACE_SEQUENCER)
sequencer_scopes_tag_refresh(sa);
break;
+ case NC_GPENCIL:
+ if (wmn->data & ND_GPENCIL_EDITMODE)
+ ED_area_tag_redraw(sa);
+ break;
}
}
@@ -500,6 +504,13 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
break;
}
break;
+ case NC_ANIMATION:
+ switch (wmn->data) {
+ case ND_KEYFRAME:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
case NC_SPACE:
if (wmn->data == ND_SPACE_SEQUENCER)
ED_region_tag_redraw(ar);
@@ -553,13 +564,16 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
SpaceSeq *sseq = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- int show_split = scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW && sseq->mainb == SEQ_DRAW_IMG_IMBUF;
+ const bool show_split = (
+ scene->ed &&
+ (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
+ (sseq->mainb == SEQ_DRAW_IMG_IMBUF));
/* XXX temp fix for wrong setting in sseq->mainb */
if (sseq->mainb == SEQ_DRAW_SEQUENCE) sseq->mainb = SEQ_DRAW_IMG_IMBUF;
if (!show_split || sseq->overlay_type != SEQ_DRAW_OVERLAY_REFERENCE)
- draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false);
+ draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, false);
if (show_split && sseq->overlay_type != SEQ_DRAW_OVERLAY_CURRENT) {
int over_cfra;
@@ -570,10 +584,10 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
over_cfra = scene->r.cfra + scene->ed->over_ofs;
if (over_cfra != scene->r.cfra || sseq->overlay_type != SEQ_DRAW_OVERLAY_RECT)
- draw_image_seq(C, scene, ar, sseq, scene->r.cfra, over_cfra - scene->r.cfra, true);
+ draw_image_seq(C, scene, ar, sseq, scene->r.cfra, over_cfra - scene->r.cfra, true, false);
}
- if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_playing(wm)) {
+ if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
rcti rect;
ED_region_visible_rect(ar, &rect);
ED_scene_draw_fps(scene, &rect);
@@ -585,7 +599,7 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->action == NA_EDITED) {
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
ED_region_tag_redraw(ar);
}
break;
@@ -595,6 +609,16 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
case ND_MARKERS:
case ND_SEQUENCER:
case ND_RENDER_OPTIONS:
+ case ND_DRAW_RENDER_VIEWPORT:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
+ case NC_ANIMATION:
+ switch (wmn->data) {
+ case ND_KEYFRAME:
+ /* Otherwise, often prevents seing immediately effects of keyframe editing... */
+ BKE_sequencer_cache_cleanup();
ED_region_tag_redraw(ar);
break;
}
@@ -633,7 +657,7 @@ static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void sequencer_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void sequencer_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -641,7 +665,7 @@ static void sequencer_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->data == ND_DATA) {
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
ED_region_tag_redraw(ar);
}
break;
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index bfeeb93372a..de85ddc40ab 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -23,10 +23,13 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -48,6 +51,8 @@ set(SRC
text_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_PYTHON)
list(APPEND INC
../../python
diff --git a/source/blender/editors/space_text/SConscript b/source/blender/editors/space_text/SConscript
index 3f617f95c58..d11671fe743 100644
--- a/source/blender/editors/space_text/SConscript
+++ b/source/blender/editors/space_text/SConscript
@@ -28,14 +28,20 @@
Import ('env')
sources = env.Glob('*.c')
+
defs = []
+defs += env['BF_GL_DEFINITIONS']
+
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 1e710b88cad..ff53d306e69 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -135,7 +135,7 @@ static void text_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
break;
case ND_CURSOR:
if (st->text && st->text == wmn->reference)
- text_scroll_to_cursor(st, sa);
+ text_scroll_to_cursor__area(st, sa, true);
ED_area_tag_redraw(sa);
break;
@@ -156,7 +156,7 @@ static void text_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
break;
case NA_SELECTED:
if (st->text && st->text == wmn->reference)
- text_scroll_to_cursor(st, sa);
+ text_scroll_to_cursor__area(st, sa, true);
break;
}
@@ -541,7 +541,7 @@ static void text_properties_area_draw(const bContext *C, ARegion *ar)
{
SpaceText *st = CTX_wm_space_text(C);
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
/* this flag trick is make sure buttons have been added already */
if (st->flags & ST_FIND_ACTIVATE) {
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 99e1606c9bd..1637ae14892 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -183,7 +183,7 @@ static GHash *text_autocomplete_build(Text *text)
const int choice_len = i_end - i_start;
if ((choice_len > seek_len) &&
- (seek_len == 0 || strncmp(seek, str_sub, seek_len) == 0) &&
+ (seek_len == 0 || STREQLEN(seek, str_sub, seek_len)) &&
(seek != str_sub))
{
// printf("Adding: %s\n", s);
@@ -207,18 +207,16 @@ static GHash *text_autocomplete_build(Text *text)
}
{
- GHashIterator *iter = BLI_ghashIterator_new(gh);
+ GHashIterator gh_iter;
/* get the formatter for highlighting */
TextFormatType *tft;
tft = ED_text_format_get(text);
- for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
- const char *s = BLI_ghashIterator_getValue(iter);
+ GHASH_ITER (gh_iter, gh) {
+ const char *s = BLI_ghashIterator_getValue(&gh_iter);
texttool_suggest_add(s, tft->format_identifier(s));
}
- BLI_ghashIterator_free(iter);
-
}
}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index af827d6dc5a..462b619f497 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -28,8 +28,6 @@
* \ingroup sptext
*/
-
-
#include "MEM_guardedalloc.h"
#include "BLF_api.h"
@@ -44,6 +42,9 @@
#include "BKE_context.h"
#include "BKE_suggestions.h"
#include "BKE_text.h"
+#include "BKE_screen.h"
+
+#include "ED_text.h"
#include "BIF_gl.h"
@@ -381,7 +382,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
int a, fstart, fpos; /* utf8 chars */
int mi, ma, mstart, mend; /* mem */
char fmt_prev = 0xff;
-
+ /* don't draw lines below this */
+ const int clip_min_y = -(int)(st->lheight_dpi - 1);
+
flatten_string(st, &fs, str);
str = fs.buf;
max = w / st->cwidth;
@@ -424,7 +427,8 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
mend = txt_utf8_forward_columns(str + mend, max, &padding) - str;
end = (wrap += max - padding);
- if (y <= 0) break;
+ if (y <= clip_min_y)
+ break;
}
else if (str[mi] == ' ' || str[mi] == '-') {
wrap = i + 1; mend = mi + 1;
@@ -432,7 +436,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
}
/* Draw the remaining text */
- for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
+ for (a = fstart, ma = mstart; str[ma] && y > clip_min_y; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (use_syntax) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
@@ -519,7 +523,7 @@ static void text_drawcache_init(SpaceText *st)
DrawCache *drawcache = MEM_callocN(sizeof(DrawCache), "text draw cache");
drawcache->winx = -1;
- drawcache->nlines = BLI_countlist(&st->text->lines);
+ drawcache->nlines = BLI_listbase_count(&st->text->lines);
drawcache->text_id[0] = '\0';
st->drawcache = drawcache;
@@ -545,7 +549,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
full_update |= drawcache->tabnumber != st->tabnumber; /* word-wrapping option was toggled */
full_update |= drawcache->lheight != st->lheight_dpi; /* word-wrapping option was toggled */
full_update |= drawcache->cwidth != st->cwidth; /* word-wrapping option was toggled */
- full_update |= strncmp(drawcache->text_id, txt->id.name, MAX_ID_NAME); /* text datablock was changed */
+ full_update |= !STREQLEN(drawcache->text_id, txt->id.name, MAX_ID_NAME); /* text datablock was changed */
if (st->wordwrap) {
/* update line heights */
@@ -560,7 +564,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
int lineno = 0, size, lines_count;
int *fp = drawcache->line_height, *new_tail, *old_tail;
- nlines = BLI_countlist(&txt->lines);
+ nlines = BLI_listbase_count(&txt->lines);
size = sizeof(int) * nlines;
if (fp) fp = MEM_reallocN(fp, size);
@@ -605,7 +609,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
}
if (full_update || drawcache->update_flag) {
- nlines = BLI_countlist(&txt->lines);
+ nlines = BLI_listbase_count(&txt->lines);
if (st->showlinenrs)
st->linenrs_tot = (int)floor(log10((float)nlines)) + 1;
@@ -892,15 +896,15 @@ static void draw_textscroll(SpaceText *st, rcti *scroll, rcti *back)
UI_ThemeColor(TH_BACK);
glRecti(back->xmin, back->ymin, back->xmax, back->ymax);
- uiWidgetScrollDraw(&wcol, scroll, &st->txtbar, (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0);
+ UI_draw_widget_scroll(&wcol, scroll, &st->txtbar, (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0);
- uiSetRoundBox(UI_CNR_ALL);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll));
UI_GetThemeColor3ubv(TH_HILITE, col);
col[3] = 48;
glColor4ubv(col);
glEnable(GL_BLEND);
- uiRoundBox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad);
+ UI_draw_roundbox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad);
glDisable(GL_BLEND);
}
@@ -1034,7 +1038,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
x = MAX2(0, ar->winx - boxw);
/* not needed but stands out nicer */
- uiDrawBoxShadow(220, x, y - boxh, x + boxw, y);
+ UI_draw_box_shadow(220, x, y - boxh, x + boxw, y);
UI_ThemeColor(TH_SHADE1);
glRecti(x - 1, y + 1, x + boxw + 1, y - boxh - 1);
@@ -1323,6 +1327,8 @@ void draw_text_main(SpaceText *st, ARegion *ar)
int i, x, y, winx, linecount = 0, lineno = 0;
int wraplinecount = 0, wrap_skip = 0;
int margin_column_x;
+ /* don't draw lines below this */
+ const int clip_min_y = -(int)(st->lheight_dpi - 1);
/* if no text, nothing to do */
if (!text)
@@ -1330,7 +1336,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
/* dpi controlled line height and font size */
st->lheight_dpi = (U.widget_unit * st->lheight) / 20;
- st->viewlines = (st->lheight_dpi) ? (int)ar->winy / (st->lheight_dpi + TXT_LINE_SPACING) : 0;
+ st->viewlines = (st->lheight_dpi) ? (int)(ar->winy - clip_min_y) / (st->lheight_dpi + TXT_LINE_SPACING) : 0;
text_update_drawcache(st, ar);
@@ -1394,7 +1400,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
/* draw the text */
UI_ThemeColor(TH_TEXT);
- for (i = 0; y > 0 && i < st->viewlines && tmp; i++, tmp = tmp->next) {
+ for (i = 0; y > clip_min_y && i < st->viewlines && tmp; i++, tmp = tmp->next) {
if (st->showsyntax && !tmp->format)
tft->format_line(st, tmp, false);
@@ -1441,7 +1447,6 @@ void draw_text_main(SpaceText *st, ARegion *ar)
/* draw other stuff */
draw_brackets(st, ar);
- glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0f); /* XXX scroll requires exact pixel space */
draw_textscroll(st, &scroll, &back);
draw_documentation(st, ar);
draw_suggestion_list(st, ar);
@@ -1461,22 +1466,15 @@ void text_update_character_width(SpaceText *st)
/* Moves the view to the cursor location,
* also used to make sure the view isn't outside the file */
-void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
+void text_scroll_to_cursor(SpaceText *st, ARegion *ar, const bool center)
{
Text *text;
- ARegion *ar = NULL;
- int i, x, winx = 0;
+ int i, x, winx = ar->winx;
if (ELEM(NULL, st, st->text, st->text->curl)) return;
text = st->text;
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- winx = ar->winx;
- break;
- }
-
text_update_character_width(st);
i = txt_get_span(text->lines.first, text->sell);
@@ -1486,8 +1484,19 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
i += offl;
}
- if (st->top + st->viewlines <= i || st->top > i)
- st->top = i - st->viewlines / 2;
+ if (center) {
+ if (st->top + st->viewlines <= i || st->top > i) {
+ st->top = i - st->viewlines / 2;
+ }
+ }
+ else {
+ if (st->top + st->viewlines <= i) {
+ st->top = i - (st->viewlines - 1);
+ }
+ else if (st->top > i) {
+ st->top = i;
+ }
+ }
if (st->wordwrap) {
st->left = 0;
@@ -1496,8 +1505,19 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
x = st->cwidth * (text_get_char_pos(st, text->sell->line, text->selc) - st->left);
winx -= TXT_OFFSET + (st->showlinenrs ? TEXTXLOC : 0) + TXT_SCROLL_WIDTH;
- if (x <= 0 || x > winx)
- st->left += (x - winx / 2) / st->cwidth;
+ if (center) {
+ if (x <= 0 || x > winx) {
+ st->left += (x - winx / 2) / st->cwidth;
+ }
+ }
+ else {
+ if (x <= 0) {
+ st->left += ((x + 1) / st->cwidth) - 1;
+ }
+ else if (x > winx) {
+ st->left += ((x - (winx + 1)) / st->cwidth) + 1;
+ }
+ }
}
if (st->top < 0) st->top = 0;
@@ -1507,10 +1527,58 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
st->scroll_accum[1] = 0.0f;
}
+/* takes an area instead of a region, use for listeners */
+void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
+{
+ ARegion *ar;
+
+ if (ELEM(NULL, st, st->text, st->text->curl)) return;
+
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+
+ if (ar) {
+ text_scroll_to_cursor(st, ar, center);
+ }
+}
+
void text_update_cursor_moved(bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
SpaceText *st = CTX_wm_space_text(C);
- text_scroll_to_cursor(st, sa);
+ text_scroll_to_cursor__area(st, sa, true);
+}
+
+/**
+ * Takes a cursor (row, character) and returns x,y pixel coords.
+ */
+bool ED_text_region_location_from_cursor(SpaceText *st, ARegion *ar, const int cursor_co[2], int r_pixel_co[2])
+{
+ TextLine *line = NULL;
+
+ if (!st->text) {
+ goto error;
+ }
+
+ line = BLI_findlink(&st->text->lines, cursor_co[0]);
+ if (!line || (cursor_co[1] < 0) || (cursor_co[1] > line->len)) {
+ goto error;
+ }
+ else {
+ int offl, offc;
+ int linenr_offset = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
+ /* handle tabs as well! */
+ int char_pos = text_get_char_pos(st, line->line, cursor_co[1]);
+
+ wrap_offset(st, ar, line, cursor_co[1], &offl, &offc);
+ r_pixel_co[0] = (char_pos + offc - st->left) * st->cwidth + linenr_offset;
+ r_pixel_co[1] = (cursor_co[0] + offl - st->top) * (st->lheight_dpi + TXT_LINE_SPACING);
+ r_pixel_co[1] = (ar->winy - (r_pixel_co[1] + TXT_OFFSET)) - st->lheight_dpi;
+ }
+ return true;
+
+
+error:
+ r_pixel_co[0] = r_pixel_co[1] = -1;
+ return false;
}
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index b1d57f5a75e..91665f1a598 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -34,7 +34,6 @@
#include "BLI_blenlib.h"
-#include "BLF_translation.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -142,7 +141,7 @@ void TEXT_OT_start_find(wmOperatorType *ot)
uiPopupMenu *pup;
if (text) {
- pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
+ pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE);
if (txt_has_sel(text)) {
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy");
@@ -153,13 +152,13 @@ void TEXT_OT_start_find(wmOperatorType *ot)
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save_as");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_run_script");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
else {
- pup = uiPupMenuBegin(C, IFACE_("File"), ICON_NONE);
+ pup = UI_popup_menu_begin(C, IFACE_("File"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
}
@@ -168,11 +167,11 @@ void TEXT_OT_start_find(wmOperatorType *ot)
uiPopupMenu *pup;
- pup = uiPupMenuBegin(C, IFACE_("Edit"), ICON_NONE);
+ pup = UI_popup_menu_begin(C, IFACE_("Edit"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
{
@@ -181,19 +180,19 @@ void TEXT_OT_start_find(wmOperatorType *ot)
uiPopupMenu *pup;
if (text) {
- pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
+ pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save_as");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_run_script");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
else {
- pup = uiPupMenuBegin(C, IFACE_("File"), ICON_NONE);
+ pup = UI_popup_menu_begin(C, IFACE_("File"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
}
@@ -202,15 +201,15 @@ void TEXT_OT_start_find(wmOperatorType *ot)
uiPopupMenu *pup;
- pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
- uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Top of File"),
+ pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Top of File"),
0, "type", FILE_TOP);
- uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Bottom of File"),
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Bottom of File"),
0, "type", FILE_BOTTOM);
- uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Page Up"), 0, "type", PREV_PAGE);
- uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Page Down"),
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Page Up"), 0, "type", PREV_PAGE);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Page Down"),
0, "type", NEXT_PAGE);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
#endif
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index d4cd029dac0..7ae2617f375 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -34,15 +34,12 @@
/* internal exports only */
struct ARegion;
-struct ARegionType;
struct bContext;
-struct ReportList;
struct ScrArea;
struct SpaceText;
struct Text;
struct TextLine;
struct wmOperatorType;
-struct wmWindowManager;
/* text_draw.c */
void draw_text_main(struct SpaceText *st, struct ARegion *ar);
@@ -50,7 +47,8 @@ void draw_text_main(struct SpaceText *st, struct ARegion *ar);
void text_update_line_edited(struct TextLine *line);
void text_update_edited(struct Text *text);
void text_update_character_width(struct SpaceText *st);
-void text_scroll_to_cursor(struct SpaceText *st, struct ScrArea *sa);
+void text_scroll_to_cursor(struct SpaceText *st, struct ARegion *ar, const bool center);
+void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *sa, const bool center);
void text_update_cursor_moved(struct bContext *C);
#define TXT_OFFSET ((int)(0.5f * U.widget_unit))
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 852edaac7dc..a2fae2d5667 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -39,7 +39,7 @@
#include "BLI_blenlib.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "PIL_time.h"
@@ -171,7 +171,7 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op))
text = BKE_text_add(bmain, "Text");
/* hook into UI */
- uiIDContextProperty(C, &ptr, &prop);
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
RNA_id_pointer_create(&text->id, &idptr);
@@ -214,7 +214,7 @@ static void text_open_init(bContext *C, wmOperator *op)
PropertyPointerRNA *pprop;
op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
- uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
+ UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
}
static void text_open_cancel(bContext *UNUSED(C), wmOperator *op)
@@ -300,8 +300,8 @@ void TEXT_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE | PYSCRIPTFILE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); //XXX TODO, relative_path
RNA_def_boolean(ot->srna, "internal", 0, "Make internal", "Make text file internal after loading");
}
@@ -577,8 +577,8 @@ void TEXT_OT_save_as(wmOperatorType *ot)
ot->poll = text_edit_poll;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE | PYSCRIPTFILE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); //XXX TODO, relative_path
}
/******************* run script operator *********************/
@@ -714,88 +714,6 @@ void TEXT_OT_refresh_pyconstraints(wmOperatorType *ot)
/******************* paste operator *********************/
-static char *txt_copy_selected(Text *text)
-{
- TextLine *tmp, *linef, *linel;
- char *buf = NULL;
- int charf, charl, length = 0;
-
- if (!text) return NULL;
- if (!text->curl) return NULL;
- if (!text->sell) return NULL;
-
- if (!txt_has_sel(text)) return NULL;
-
- if (text->curl == text->sell) {
- linef = linel = text->curl;
-
- if (text->curc < text->selc) {
- charf = text->curc;
- charl = text->selc;
- }
- else {
- charf = text->selc;
- charl = text->curc;
- }
- }
- else if (txt_get_span(text->curl, text->sell) < 0) {
- linef = text->sell;
- linel = text->curl;
-
- charf = text->selc;
- charl = text->curc;
- }
- else {
- linef = text->curl;
- linel = text->sell;
-
- charf = text->curc;
- charl = text->selc;
- }
-
- if (linef == linel) {
- length = charl - charf;
-
- buf = MEM_callocN(length + 1, "cut buffera");
-
- BLI_strncpy(buf, linef->line + charf, length + 1);
- }
- else {
- length += linef->len - charf;
- length += charl;
- length++; /* For the '\n' */
-
- tmp = linef->next;
- while (tmp && tmp != linel) {
- length += tmp->len + 1;
- tmp = tmp->next;
- }
-
- buf = MEM_callocN(length + 1, "cut bufferb");
-
- strncpy(buf, linef->line + charf, linef->len - charf);
- length = linef->len - charf;
-
- buf[length++] = '\n';
-
- tmp = linef->next;
- while (tmp && tmp != linel) {
- strncpy(buf + length, tmp->line, tmp->len);
- length += tmp->len;
-
- buf[length++] = '\n';
-
- tmp = tmp->next;
- }
- strncpy(buf + length, linel->line, charl);
- length += charl;
-
- buf[length] = 0;
- }
-
- return buf;
-}
-
static int text_paste_exec(bContext *C, wmOperator *op)
{
const bool selection = RNA_boolean_get(op->ptr, "selection");
@@ -876,7 +794,10 @@ static void txt_copy_clipboard(Text *text)
{
char *buf;
- buf = txt_copy_selected(text);
+ if (!txt_has_sel(text))
+ return;
+
+ buf = txt_sel_to_buf(text);
if (buf) {
WM_clipboard_text_set(buf, 0);
@@ -2000,7 +1921,7 @@ void TEXT_OT_jump(wmOperatorType *ot)
/* properties */
prop = RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000);
- RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
}
/******************* delete operator **********************/
@@ -2312,7 +2233,7 @@ void TEXT_OT_scroll(wmOperatorType *ot)
ot->poll = text_scroll_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_INTERNAL;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_INTERNAL;
/* properties */
RNA_def_int(ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
@@ -2415,6 +2336,7 @@ typedef struct SetSelection {
int selecting;
int selc, sell;
short old[2];
+ wmTimer *timer; /* needed for scrolling when mouse at region bounds */
} SetSelection;
static int flatten_width(SpaceText *st, const char *str)
@@ -2615,10 +2537,14 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, con
y -= txt_get_span(text->lines.first, *linep) - st->top;
if (y > 0) {
- while (y-- != 0) if ((*linep)->next) *linep = (*linep)->next;
+ while (y-- != 0) {
+ if ((*linep)->next) *linep = (*linep)->next;
+ }
}
else if (y < 0) {
- while (y++ != 0) if ((*linep)->prev) *linep = (*linep)->prev;
+ while (y++ != 0) {
+ if ((*linep)->prev) *linep = (*linep)->prev;
+ }
}
@@ -2629,6 +2555,29 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, con
if (!sel) txt_pop_sel(text);
}
+static void text_cursor_timer_ensure(bContext *C, SetSelection *ssel)
+{
+ if (ssel->timer == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
+ ssel->timer = WM_event_add_timer(wm, win, TIMER, 0.02f);
+ }
+}
+
+static void text_cursor_timer_remove(bContext *C, SetSelection *ssel)
+{
+ if (ssel->timer) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
+ WM_event_remove_timer(wm, win, ssel->timer);
+ }
+ ssel->timer = NULL;
+}
+
+
+
static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
@@ -2636,32 +2585,34 @@ static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *ev
SetSelection *ssel = op->customdata;
if (event->mval[1] < 0 || event->mval[1] > ar->winy) {
- int d = (ssel->old[1] - event->mval[1]) * st->pix_per_line;
- if (d) txt_screen_skip(st, ar, d);
-
- text_cursor_set_to_pos(st, ar, event->mval[0], event->mval[1] < 0 ? 0 : ar->winy, 1);
+ text_cursor_timer_ensure(C, ssel);
- text_update_cursor_moved(C);
- WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
+ if (event->type == TIMER) {
+ text_cursor_set_to_pos(st, ar, event->mval[0], event->mval[1], 1);
+ text_scroll_to_cursor(st, ar, false);
+ WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
+ }
}
else if (!st->wordwrap && (event->mval[0] < 0 || event->mval[0] > ar->winx)) {
- if (event->mval[0] > ar->winx) st->left++;
- else if (event->mval[0] < 0 && st->left > 0) st->left--;
-
- text_cursor_set_to_pos(st, ar, event->mval[0], event->mval[1], 1);
+ text_cursor_timer_ensure(C, ssel);
- text_update_cursor_moved(C);
- WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
- // XXX PIL_sleep_ms(10);
+ if (event->type == TIMER) {
+ text_cursor_set_to_pos(st, ar, CLAMPIS(event->mval[0], 0, ar->winx), event->mval[1], 1);
+ text_scroll_to_cursor(st, ar, false);
+ WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
+ }
}
else {
- text_cursor_set_to_pos(st, ar, event->mval[0], event->mval[1], 1);
+ text_cursor_timer_remove(C, ssel);
- text_update_cursor_moved(C);
- WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
+ if (event->type != TIMER) {
+ text_cursor_set_to_pos(st, ar, event->mval[0], event->mval[1], 1);
+ text_scroll_to_cursor(st, ar, false);
+ WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
- ssel->old[0] = event->mval[0];
- ssel->old[1] = event->mval[1];
+ ssel->old[0] = event->mval[0];
+ ssel->old[1] = event->mval[1];
+ }
}
}
@@ -2681,6 +2632,7 @@ static void text_cursor_set_exit(bContext *C, wmOperator *op)
text_update_cursor_moved(C);
WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, st->text);
+ text_cursor_timer_remove(C, ssel);
MEM_freeN(ssel);
}
@@ -2717,6 +2669,7 @@ static int text_set_selection_modal(bContext *C, wmOperator *op, const wmEvent *
case RIGHTMOUSE:
text_cursor_set_exit(C, op);
return OPERATOR_FINISHED;
+ case TIMER:
case MOUSEMOVE:
text_cursor_set_apply(C, op, event);
break;
@@ -2970,7 +2923,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
if (mode != TEXT_FIND && txt_has_sel(text)) {
tmp = txt_sel_to_buf(text);
- if (flags & ST_MATCH_CASE) found = strcmp(st->findstr, tmp) == 0;
+ if (flags & ST_MATCH_CASE) found = STREQ(st->findstr, tmp);
else found = BLI_strcasecmp(st->findstr, tmp) == 0;
if (found) {
@@ -3144,36 +3097,36 @@ static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEve
case 1:
if (text->flags & TXT_ISDIRTY) {
/* modified locally and externally, ahhh. offer more possibilites. */
- pup = uiPupMenuBegin(C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemEnumO_ptr(layout, op->type, IFACE_("Reload from disk (ignore local changes)"),
0, "resolution", RESOLVE_RELOAD);
uiItemEnumO_ptr(layout, op->type, IFACE_("Save to disk (ignore outside changes)"),
0, "resolution", RESOLVE_SAVE);
uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal (separate copy)"),
0, "resolution", RESOLVE_MAKE_INTERNAL);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
else {
- pup = uiPupMenuBegin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemEnumO_ptr(layout, op->type, IFACE_("Reload from disk"), 0, "resolution", RESOLVE_RELOAD);
uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal (separate copy)"),
0, "resolution", RESOLVE_MAKE_INTERNAL);
uiItemEnumO_ptr(layout, op->type, IFACE_("Ignore"), 0, "resolution", RESOLVE_IGNORE);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
break;
case 2:
- pup = uiPupMenuBegin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal"), 0, "resolution", RESOLVE_MAKE_INTERNAL);
uiItemEnumO_ptr(layout, op->type, IFACE_("Recreate file"), 0, "resolution", RESOLVE_SAVE);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
break;
}
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
void TEXT_OT_resolve_conflict(wmOperatorType *ot)
diff --git a/source/blender/editors/space_time/CMakeLists.txt b/source/blender/editors/space_time/CMakeLists.txt
index b42ae3ab725..90af405eaa8 100644
--- a/source/blender/editors/space_time/CMakeLists.txt
+++ b/source/blender/editors/space_time/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -39,4 +41,6 @@ set(SRC
time_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_time "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_time/SConscript b/source/blender/editors/space_time/SConscript
index bf1b918f4f1..86437b9c258 100644
--- a/source/blender/editors/space_time/SConscript
+++ b/source/blender/editors/space_time/SConscript
@@ -31,15 +31,18 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
env.BlenderLib('bf_editors_space_time', sources, incs, defs, libtype=['core'], priority=[65])
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 88c57d45b79..9ecea7462ff 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -57,6 +58,7 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
#include "ED_space_api.h"
#include "ED_markers.h"
@@ -89,13 +91,12 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax);
}
-#define CACHE_DRAW_HEIGHT 3.0f
-
static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
{
PTCacheID *pid;
ListBase pidlist;
SpaceTimeCache *stc = stime->caches.first;
+ const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
float yoffs = 0.f;
if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
@@ -171,7 +172,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
glPushMatrix();
glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0);
- glScalef(1.0, CACHE_DRAW_HEIGHT, 0.0);
+ glScalef(1.0, cache_draw_height, 0.0);
switch (pid->type) {
case PTCACHE_TYPE_SOFTBODY:
@@ -229,7 +230,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
glPopMatrix();
- yoffs += CACHE_DRAW_HEIGHT;
+ yoffs += cache_draw_height;
stc = stc->next;
}
@@ -295,13 +296,19 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
DLRBT_Tree keys;
ActKeyColumn *ak;
+ float fac1 = (GS(id->name) == ID_GD) ? 0.8f : 0.6f; /* draw GPencil keys taller, to help distinguish them */
+ float fac2 = 1.0f - fac1;
+
+ float ymin = v2d->tot.ymin;
+ float ymax = v2d->tot.ymax * fac1 + ymin * fac2;
+
/* init binarytree-list for getting keyframes */
BLI_dlrbTree_init(&keys);
/* init dopesheet settings */
if (onlysel)
ads.filterflag |= ADS_FILTER_ONLYSEL;
-
+
/* populate tree with keyframe nodes */
switch (GS(id->name)) {
case ID_SCE:
@@ -310,6 +317,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
case ID_OB:
ob_to_keylist(&ads, (Object *)id, &keys, NULL);
break;
+ case ID_GD:
+ gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
+ break;
}
/* build linked-list for searching */
@@ -325,8 +335,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
(ak) && (ak->cfra <= v2d->cur.xmax);
ak = ak->next)
{
- glVertex2f(ak->cfra, v2d->tot.ymin);
- glVertex2f(ak->cfra, v2d->tot.ymax);
+ glVertex2f(ak->cfra, ymin);
+ glVertex2f(ak->cfra, ymax);
}
glEnd(); // GL_LINES
@@ -339,16 +349,23 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
View2D *v2d = &ar->v2d;
bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
+ /* draw grease pencil keyframes (if available) */
+ if (gpd) {
+ UI_ThemeColor(TH_TIME_GP_KEYFRAME);
+ time_draw_idblock_keyframes(v2d, (ID *)gpd, onlysel);
+ }
+
/* draw scene keyframes first
* - don't try to do this when only drawing active/selected data keyframes,
* since this can become quite slow
*/
if (onlysel == 0) {
/* set draw color */
- glColor3ub(0xDD, 0xA7, 0x00);
+ UI_ThemeColorShade(TH_TIME_KEYFRAME, -50);
time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel);
}
@@ -357,7 +374,7 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
* OR the onlysel flag was set, which means that only active object's keyframes should
* be considered
*/
- glColor3ub(0xDD, 0xD7, 0x00);
+ UI_ThemeColor(TH_TIME_KEYFRAME);
if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) {
/* draw keyframes for active object only */
@@ -520,7 +537,7 @@ static void time_main_area_draw(const bContext *C, ARegion *ar)
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
- draw_markers_time(C, 0);
+ ED_markers_draw(C, 0);
/* caches */
time_draw_cache(stime, obact, scene);
diff --git a/source/blender/editors/space_time/time_intern.h b/source/blender/editors/space_time/time_intern.h
index ce52cbbd65e..ced36b2ac2d 100644
--- a/source/blender/editors/space_time/time_intern.h
+++ b/source/blender/editors/space_time/time_intern.h
@@ -34,7 +34,6 @@
/* internal exports only */
-struct wmWindowManager;
/* time_ops.c */
void time_operatortypes(void);
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 0bd094b6a33..b5a6821d147 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -47,9 +47,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "UI_view2d.h"
-#include "userpref_intern.h" // own include
/* ******************** default callbacks for userpref space ***************** */
@@ -115,7 +113,7 @@ static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar)
static void userpref_main_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void userpref_operatortypes(void)
diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c
index 8dd6c3c0271..0783eacc65c 100644
--- a/source/blender/editors/space_userpref/userpref_ops.c
+++ b/source/blender/editors/space_userpref/userpref_ops.c
@@ -32,5 +32,4 @@
#include <string.h>
#include <stdio.h>
-#include "userpref_intern.h"
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 97c328dbac2..059b384a9e2 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../gpu
../../imbuf
@@ -30,7 +31,9 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../depsgraph
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
../../../../intern/smoke/extern
)
@@ -43,6 +46,7 @@ set(SRC
drawarmature.c
drawmesh.c
drawobject.c
+ drawsimdebug.c
drawvolume.c
space_view3d.c
view3d_buttons.c
@@ -76,7 +80,7 @@ if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
@@ -86,4 +90,8 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index e6658ab3c49..7fdccce1c0e 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -28,17 +28,21 @@
Import ('env')
sources = env.Glob('*.c')
-defs = [ 'GLEW_STATIC' ]
+
+defs = []
+defs += env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/smoke/extern',
'#/source/gameengine/BlenderRoutines',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../imbuf',
@@ -46,6 +50,7 @@ incs = [
'../../makesrna',
'../../render/extern/include',
'../../windowmanager',
+ '../../depsgraph',
]
if env['WITH_BF_PYTHON']:
@@ -63,4 +68,7 @@ if env['WITH_BF_INTERNATIONAL']:
if env['WITH_BF_FREESTYLE']:
defs.append('WITH_FREESTYLE')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
env.BlenderLib ( 'bf_editors_space_view3d', sources, incs, defines = defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index 17f90fc54e3..d753ad68fcc 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -51,10 +51,8 @@
#include "BIF_gl.h"
-#include "ED_armature.h"
#include "ED_keyframes_draw.h"
-#include "BLF_api.h"
#include "UI_resources.h"
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index dfa373f111f..f7698b0e9f3 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -61,7 +61,6 @@
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
-#include "BLF_api.h"
#include "UI_resources.h"
@@ -1548,7 +1547,7 @@ static void draw_pose_dofs(Object *ob)
glPushMatrix();
copy_v3_v3(posetrans, pchan->pose_mat[3]);
- glTranslatef(posetrans[0], posetrans[1], posetrans[2]);
+ glTranslate3fv(posetrans);
if (pchan->parent) {
copy_m4_m4(mat, pchan->parent->pose_mat);
@@ -1620,7 +1619,7 @@ static void draw_pose_dofs(Object *ob)
for (a = -16; a <= 16; a++) {
/* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
float fac = ((float)a) / 16.0f * 0.5f;
- phi = (float)(0.5 * M_PI) + fac * (pchan->limitmax[0] - pchan->limitmin[0]);
+ phi = (float)M_PI_2 + fac * (pchan->limitmax[0] - pchan->limitmin[0]);
i = (a == -16) ? 2 : 3;
corner[i][0] = 0.0f;
@@ -1779,7 +1778,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
draw_custom_bone(scene, v3d, rv3d, pchan->custom,
- OB_SOLID, arm->flag, flag, index, bone->length);
+ OB_SOLID, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
}
}
else {
@@ -1870,7 +1869,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
flag |= BONE_DRAW_ACTIVE;
draw_custom_bone(scene, v3d, rv3d, pchan->custom,
- OB_WIRE, arm->flag, flag, index, bone->length);
+ OB_WIRE, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
glPopMatrix();
}
@@ -2088,6 +2087,10 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
}
+
+ if (index != -1) {
+ GPU_select_load_id(-1);
+ }
}
/* in editmode, we don't store the bone matrix... */
@@ -2363,7 +2366,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
bArmature *arm = ob->data;
bPose *posen, *poseo;
float start, end, stepsize, range, colfac;
- int cfrao, flago, ipoflago;
+ int cfrao, flago;
start = (float)arm->ghostsf;
end = (float)arm->ghostef;
@@ -2378,8 +2381,6 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
cfrao = CFRA;
flago = arm->flag;
arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES);
- ipoflago = ob->ipoflag;
- ob->ipoflag |= OB_DISABLE_PATH;
/* copy the pose */
poseo = ob->pose;
@@ -2392,7 +2393,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
/* draw from first frame of range to last */
- for (CFRA = (int)start; CFRA < end; CFRA += (int)stepsize) {
+ for (CFRA = (int)start; CFRA <= end; CFRA += (int)stepsize) {
colfac = (end - (float)CFRA) / range;
UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)));
@@ -2415,7 +2416,6 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
ob->pose = poseo;
arm->flag = flago;
ob->mode |= OB_MODE_POSE;
- ob->ipoflag = ipoflago;
}
/* draw ghosts on keyframes in action within range
@@ -2459,8 +2459,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *
cfrao = CFRA;
flago = arm->flag;
arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES);
- ob->ipoflag |= OB_DISABLE_PATH;
-
+
/* copy the pose */
poseo = ob->pose;
BKE_pose_copy_data(&posen, ob->pose, 1);
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index fb97a6ac9f4..d806dfa015a 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -60,7 +60,6 @@
#include "UI_resources.h"
-#include "GPU_buffers.h"
#include "GPU_extensions.h"
#include "GPU_draw.h"
#include "GPU_material.h"
@@ -80,15 +79,15 @@ typedef struct drawMeshFaceSelect_userData {
typedef struct drawEMTFMapped_userData {
BMEditMesh *em;
bool has_mcol;
- bool has_mtface;
- MFace *mf;
- MTFace *tf;
+ int cd_poly_tex_offset;
+ const MPoly *mpoly;
+ const MTexPoly *mtexpoly;
} drawEMTFMapped_userData;
typedef struct drawTFace_userData {
- Mesh *me;
- MFace *mf;
- MTFace *tf;
+ const Mesh *me;
+ const MPoly *mpoly;
+ const MTexPoly *mtexpoly;
} drawTFace_userData;
/**************************** Face Select Mode *******************************/
@@ -97,7 +96,7 @@ typedef struct drawTFace_userData {
BLI_INLINE int edge_vis_index(const int index) { return index * 2; }
BLI_INLINE int edge_sel_index(const int index) { return index * 2 + 1; }
-static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me)
+static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me, bool draw_select_edges)
{
BLI_bitmap *bitmap_edge_flags = BLI_BITMAP_NEW(me->totedge * 2, __func__);
MPoly *mp;
@@ -113,8 +112,17 @@ static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me)
ml = me->mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++) {
- BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e));
- if (select_set) BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e));
+ if ((draw_select_edges == false) &&
+ (select_set && BLI_BITMAP_TEST(bitmap_edge_flags, edge_sel_index(ml->e))))
+ {
+ BLI_BITMAP_DISABLE(bitmap_edge_flags, edge_vis_index(ml->e));
+ }
+ else {
+ BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e));
+ if (select_set) {
+ BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e));
+ }
+ }
}
}
}
@@ -129,21 +137,26 @@ static DMDrawOption draw_mesh_face_select__setHiddenOpts(void *userData, int ind
Mesh *me = data->me;
if (me->drawflag & ME_DRAWEDGES) {
- if ((me->drawflag & ME_HIDDENEDGES) || (BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))))
+ if ((BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))))
return DM_DRAW_OPTION_NORMAL;
else
return DM_DRAW_OPTION_SKIP;
}
- else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)))
+ else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) &&
+ BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index)))
+ {
return DM_DRAW_OPTION_NORMAL;
- else
+ }
+ else {
return DM_DRAW_OPTION_SKIP;
+ }
}
static DMDrawOption draw_mesh_face_select__setSelectOpts(void *userData, int index)
{
drawMeshFaceSelect_userData *data = userData;
- return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP;
+ return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) &&
+ BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP;
}
/* draws unselected */
@@ -158,12 +171,12 @@ static DMDrawOption draw_mesh_face_select__drawFaceOptsInv(void *userData, int i
return DM_DRAW_OPTION_SKIP;
}
-void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm)
+void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool draw_select_edges)
{
drawMeshFaceSelect_userData data;
data.me = me;
- data.edge_flags = get_tface_mesh_marked_edge_info(me);
+ data.edge_flags = get_tface_mesh_marked_edge_info(me, draw_select_edges);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
@@ -181,7 +194,7 @@ void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* dull unselected faces so as not to get in the way of seeing color */
glColor4ub(96, 96, 96, 64);
- dm->drawMappedFaces(dm, draw_mesh_face_select__drawFaceOptsInv, NULL, NULL, (void *)me, 0);
+ dm->drawMappedFaces(dm, draw_mesh_face_select__drawFaceOptsInv, NULL, NULL, (void *)me, DM_DRAW_SKIP_HIDDEN);
glDisable(GL_BLEND);
}
@@ -223,11 +236,11 @@ static struct TextureDrawState {
bool texpaint_material; /* use material slots for texture painting */
} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, {0, 0, 0, 0}, false, false};
-static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw)
+static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material *ma, struct TextureDrawState gtexdraw)
{
static Material *c_ma;
static int c_textured;
- static MTFace c_texface;
+ static MTexPoly c_texface;
static int c_backculled;
static bool c_badtex;
static int c_lit;
@@ -251,7 +264,7 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
if (clearcache) {
c_textured = c_lit = c_backculled = -1;
- memset(&c_texface, 0, sizeof(MTFace));
+ memset(&c_texface, 0, sizeof(c_texface));
c_badtex = false;
c_has_texface = -1;
c_ma = NULL;
@@ -279,10 +292,10 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
if (!ma && BKE_image_has_alpha(texface->tpage))
alphablend = GPU_BLEND_ALPHA;
}
- else if (texpaint && ma) {
+ else if (texpaint) {
if (gtexdraw.texpaint_material)
- ima = ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
- else
+ ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ else
ima = gtexdraw.canvas;
}
else
@@ -315,6 +328,14 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
glActiveTexture(GL_TEXTURE0);
}
@@ -513,7 +534,7 @@ static void draw_textured_end(void)
glPopMatrix();
}
-static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, const bool has_mcol, int matnr)
+static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool has_mcol, int matnr)
{
Material *ma = give_current_material(Gtexdraw.ob, matnr + 1);
bool invalidtexture = false;
@@ -521,9 +542,9 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, const bool has_mc
if (ma && (ma->game.flag & GEMAT_INVISIBLE))
return DM_DRAW_OPTION_SKIP;
- invalidtexture = set_draw_settings_cached(0, tface, ma, Gtexdraw);
+ invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw);
- if (tface && invalidtexture) {
+ if (mtexpoly && invalidtexture) {
glColor3ub(0xFF, 0x00, 0xFF);
return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
}
@@ -532,7 +553,7 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, const bool has_mc
return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
}
else if (!has_mcol) {
- if (tface) {
+ if (mtexpoly) {
glColor3f(1.0, 1.0, 1.0);
}
else {
@@ -554,162 +575,173 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, const bool has_mc
}
}
-static DMDrawOption draw_mcol__set_draw_legacy(MTFace *UNUSED(tface), const bool has_mcol, int UNUSED(matnr))
-{
- if (has_mcol)
- return DM_DRAW_OPTION_NORMAL;
- else
- return DM_DRAW_OPTION_NO_MCOL;
-}
-
-static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mcol), int matnr)
+static DMDrawOption draw_tface__set_draw(MTexPoly *mtexpoly, const bool UNUSED(has_mcol), int matnr)
{
Material *ma = give_current_material(Gtexdraw.ob, matnr + 1);
- if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return 0;
+ if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP;
- if (tface || Gtexdraw.is_texpaint)
- set_draw_settings_cached(0, tface, ma, Gtexdraw);
+ if (mtexpoly || Gtexdraw.is_texpaint)
+ set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw);
/* always use color from mcol, as set in update_tface_color_layer */
return DM_DRAW_OPTION_NORMAL;
}
-static void update_tface_color_layer(DerivedMesh *dm)
+static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
{
- MTFace *tface = DM_get_tessface_data_layer(dm, CD_MTFACE);
- MFace *mface = dm->getTessFaceArray(dm);
- MCol *finalCol;
+ const MPoly *mp = dm->getPolyArray(dm);
+ const int mpoly_num = dm->getNumPolys(dm);
+ MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
+ MLoopCol *finalCol;
int i, j;
- MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
- if (!mcol)
- mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
+ MLoopCol *mloopcol = NULL;
+
+ /* cache material values to avoid a lot of lookups */
+ Material *ma = NULL;
+ short mat_nr_prev = -1;
+ enum {
+ COPY_CALC,
+ COPY_ORIG,
+ COPY_PREV,
+ } copy_mode = COPY_CALC;
+
+ if (use_mcol) {
+ mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol)
+ mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL);
+ }
- if (CustomData_has_layer(&dm->faceData, CD_TEXTURE_MCOL)) {
- finalCol = CustomData_get_layer(&dm->faceData, CD_TEXTURE_MCOL);
+ if (CustomData_has_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL)) {
+ finalCol = CustomData_get_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL);
}
else {
- finalCol = MEM_mallocN(sizeof(MCol) * 4 * dm->getNumTessFaces(dm), "add_tface_color_layer");
-
- CustomData_add_layer(&dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numTessFaceData);
+ finalCol = MEM_mallocN(sizeof(MLoopCol) * dm->numLoopData, "add_tface_color_layer");
+ CustomData_add_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL, CD_ASSIGN, finalCol, dm->numLoopData);
}
- for (i = 0; i < dm->getNumTessFaces(dm); i++) {
- Material *ma = give_current_material(Gtexdraw.ob, mface[i].mat_nr + 1);
-
- if (ma && (ma->game.flag & GEMAT_INVISIBLE)) {
- if (mcol)
- memcpy(&finalCol[i * 4], &mcol[i * 4], sizeof(MCol) * 4);
- else
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].b = 255;
- finalCol[i * 4 + j].g = 255;
- finalCol[i * 4 + j].r = 255;
- }
+ for (i = mpoly_num; i--; mp++) {
+ const short mat_nr = mp->mat_nr;
+
+ if (UNLIKELY(mat_nr_prev != mat_nr)) {
+ ma = give_current_material(Gtexdraw.ob, mat_nr + 1);
+ copy_mode = COPY_CALC;
+ mat_nr_prev = mat_nr;
+ }
+
+ /* avoid lookups */
+ if (copy_mode == COPY_ORIG) {
+ memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop);
}
- else if (tface && set_draw_settings_cached(0, tface, ma, Gtexdraw)) {
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].b = 255;
- finalCol[i * 4 + j].g = 0;
- finalCol[i * 4 + j].r = 255;
+ else if (copy_mode == COPY_PREV) {
+ int loop_index = mp->loopstart;
+ const MLoopCol *lcol_prev = &finalCol[(mp - 1)->loopstart];
+ for (j = 0; j < mp->totloop; j++, loop_index++) {
+ finalCol[loop_index] = *lcol_prev;
}
}
+
+ /* (copy_mode == COPY_CALC) */
+ else if (ma && (ma->game.flag & GEMAT_INVISIBLE)) {
+ if (mloopcol) {
+ memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop);
+ copy_mode = COPY_ORIG;
+ }
+ else {
+ memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop);
+ copy_mode = COPY_PREV;
+ }
+ }
+ else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw)) {
+ int loop_index = mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, loop_index++) {
+ finalCol[loop_index].r = 255;
+ finalCol[loop_index].g = 0;
+ finalCol[loop_index].b = 255;
+ }
+ copy_mode = COPY_PREV;
+ }
else if (ma && (ma->shade_flag & MA_OBCOLOR)) {
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].b = Gtexdraw.obcol[0];
- finalCol[i * 4 + j].g = Gtexdraw.obcol[1];
- finalCol[i * 4 + j].r = Gtexdraw.obcol[2];
+ int loop_index = mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, loop_index++) {
+ copy_v3_v3_char(&finalCol[loop_index].r, (char *)Gtexdraw.obcol);
}
+ copy_mode = COPY_PREV;
}
- else if (!mcol) {
- if (tface) {
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].b = 255;
- finalCol[i * 4 + j].g = 255;
- finalCol[i * 4 + j].r = 255;
- }
+ else {
+ if (mloopcol) {
+ memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop);
+ copy_mode = COPY_ORIG;
+ }
+ else if (mtexpoly) {
+ memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop);
+ copy_mode = COPY_PREV;
}
else {
float col[3];
if (ma) {
+ int loop_index = mp->loopstart;
+ MLoopCol lcol;
+
if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
else copy_v3_v3(col, &ma->r);
+ rgb_float_to_uchar((unsigned char *)&lcol.r, col);
+ lcol.a = 255;
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].b = FTOCHAR(col[0]);
- finalCol[i * 4 + j].g = FTOCHAR(col[1]);
- finalCol[i * 4 + j].r = FTOCHAR(col[2]);
+ for (j = 0; j < mp->totloop; j++, loop_index++) {
+ finalCol[loop_index] = lcol;
}
}
- else
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].b = 255;
- finalCol[i * 4 + j].g = 255;
- finalCol[i * 4 + j].r = 255;
- }
- }
- }
- else {
- for (j = 0; j < 4; j++) {
- finalCol[i * 4 + j].r = mcol[i * 4 + j].r;
- finalCol[i * 4 + j].g = mcol[i * 4 + j].g;
- finalCol[i * 4 + j].b = mcol[i * 4 + j].b;
+ else {
+ memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop);
+ }
+ copy_mode = COPY_PREV;
}
}
}
}
-static DMDrawOption draw_tface_mapped__set_draw(void *userData, int index)
+static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr))
{
- Mesh *me = ((drawTFace_userData *)userData)->me;
+ const Mesh *me = ((drawTFace_userData *)userData)->me;
/* array checked for NULL before calling */
- MPoly *mpoly = &me->mpoly[index];
+ MPoly *mpoly = &me->mpoly[origindex];
- BLI_assert(index >= 0 && index < me->totpoly);
+ BLI_assert(origindex >= 0 && origindex < me->totpoly);
if (mpoly->flag & ME_HIDE) {
return DM_DRAW_OPTION_SKIP;
}
else {
- MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[index] : NULL;
- MTFace mtf = {{{0}}};
+ MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[origindex] : NULL;
int matnr = mpoly->mat_nr;
-
- if (tpoly) {
- ME_MTEXFACE_CPY(&mtf, tpoly);
- }
-
- return draw_tface__set_draw(&mtf, (me->mloopcol != NULL), matnr);
+
+ return draw_tface__set_draw(tpoly, (me->mloopcol != NULL), matnr);
}
}
-static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int index)
+static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int origindex, int mat_nr)
{
drawEMTFMapped_userData *data = userData;
BMEditMesh *em = data->em;
BMFace *efa;
- if (UNLIKELY(index >= em->bm->totface))
+ if (UNLIKELY(origindex >= em->bm->totface))
return DM_DRAW_OPTION_NORMAL;
- efa = BM_face_at_index(em->bm, index);
+ efa = BM_face_at_index(em->bm, origindex);
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
return DM_DRAW_OPTION_SKIP;
}
else {
- MTFace mtf = {{{0}}};
- int matnr = efa->mat_nr;
+ MTexPoly *mtexpoly = (data->cd_poly_tex_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(efa, data->cd_poly_tex_offset) : NULL;
+ int matnr = (mat_nr != -1) ? mat_nr : efa->mat_nr;
- if (data->has_mtface) {
- MTexPoly *tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- ME_MTEXFACE_CPY(&mtf, tpoly);
- }
-
- return draw_tface__set_draw_legacy(data->has_mtface ? &mtf : NULL,
- data->has_mcol, matnr);
+ return draw_tface__set_draw_legacy(mtexpoly, data->has_mcol, matnr);
}
}
@@ -741,7 +773,6 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
/* fake values to pass to GPU_render_text() */
MCol tmp_mcol[4] = {{0}};
MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL;
- MTFace tmp_tf = {{{0}}};
/* don't draw without tfaces */
if (!mtpoly || !mloopuv)
@@ -758,7 +789,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) {
short matnr = mp->mat_nr;
- int mf_smooth = mp->flag & ME_SMOOTH;
+ const bool mf_smooth = (mp->flag & ME_SMOOTH) != 0;
Material *mat = (me->mat) ? me->mat[matnr] : NULL;
int mode = mat ? mat->game.flag : GEMAT_INVISIBLE;
@@ -766,14 +797,14 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
if (!(mode & GEMAT_INVISIBLE) && (mode & GEMAT_TEXT) && mp->totloop >= 3) {
/* get the polygon as a tri/quad */
int mp_vi[4];
- float v1[3], v2[3], v3[3], v4[3];
+ float v_quad_data[4][3];
+ const float *v_quad[4];
+ const float *uv_quad[4];
char string[MAX_PROPSTRING];
int characters, i, glattrib = -1, badtex = 0;
/* TEXFACE */
- ME_MTEXFACE_CPY(&tmp_tf, mtpoly);
-
if (glsl) {
GPU_enable_material(matnr + 1, &gattribs);
@@ -785,7 +816,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
}
}
else {
- badtex = set_draw_settings_cached(0, &tmp_tf, mat, Gtexdraw);
+ badtex = set_draw_settings_cached(0, mtpoly, mat, Gtexdraw);
if (badtex) {
continue;
}
@@ -798,13 +829,17 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
/* UV */
luv = &mloopuv[mp->loopstart];
- copy_v2_v2(tmp_tf.uv[0], luv->uv); luv++;
- copy_v2_v2(tmp_tf.uv[1], luv->uv); luv++;
- copy_v2_v2(tmp_tf.uv[2], luv->uv); luv++;
+ uv_quad[0] = luv->uv; luv++;
+ uv_quad[1] = luv->uv; luv++;
+ uv_quad[2] = luv->uv; luv++;
if (mp->totloop >= 4) {
- copy_v2_v2(tmp_tf.uv[3], luv->uv);
+ uv_quad[3] = luv->uv;
+ }
+ else {
+ uv_quad[3] = NULL;
}
+
/* COLOR */
if (mloopcol) {
unsigned int totloop_clamp = min_ii(4, mp->totloop);
@@ -817,13 +852,22 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
}
/* LOCATION */
- ddm->getVertCo(ddm, mp_vi[0], v1);
- ddm->getVertCo(ddm, mp_vi[1], v2);
- ddm->getVertCo(ddm, mp_vi[2], v3);
+ ddm->getVertCo(ddm, mp_vi[0], v_quad_data[0]);
+ ddm->getVertCo(ddm, mp_vi[1], v_quad_data[1]);
+ ddm->getVertCo(ddm, mp_vi[2], v_quad_data[2]);
if (mp->totloop >= 4) {
- ddm->getVertCo(ddm, mp_vi[3], v4);
+ ddm->getVertCo(ddm, mp_vi[3], v_quad_data[3]);
}
+ v_quad[0] = v_quad_data[0];
+ v_quad[1] = v_quad_data[1];
+ v_quad[2] = v_quad_data[2];
+ if (mp->totloop >= 4) {
+ v_quad[3] = v_quad_data[2];
+ }
+ else {
+ v_quad[3] = NULL;
+ }
/* The BM_FONT handling is in the gpu module, shared with the
@@ -838,13 +882,16 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
if (!mf_smooth) {
float nor[3];
- normal_tri_v3(nor, v1, v2, v3);
+ normal_tri_v3(nor, v_quad[0], v_quad[1], v_quad[2]);
glNormal3fv(nor);
}
- GPU_render_text(&tmp_tf, mode, string, characters,
- (unsigned int *)tmp_mcol_pt, v1, v2, v3, (mp->totloop >= 4 ? v4 : NULL), glattrib);
+ GPU_render_text(
+ mtpoly, mode, string, characters,
+ (unsigned int *)tmp_mcol_pt,
+ v_quad, uv_quad,
+ glattrib);
}
}
@@ -855,10 +902,10 @@ static int compareDrawOptions(void *userData, int cur_index, int next_index)
{
drawTFace_userData *data = userData;
- if (data->mf && data->mf[cur_index].mat_nr != data->mf[next_index].mat_nr)
+ if (data->mpoly && data->mpoly[cur_index].mat_nr != data->mpoly[next_index].mat_nr)
return 0;
- if (data->tf && data->tf[cur_index].tpage != data->tf[next_index].tpage)
+ if (data->mtexpoly && data->mtexpoly[cur_index].tpage != data->mtexpoly[next_index].tpage)
return 0;
return 1;
@@ -869,10 +916,10 @@ static int compareDrawOptionsEm(void *userData, int cur_index, int next_index)
{
drawEMTFMapped_userData *data = userData;
- if (data->mf && data->mf[cur_index].mat_nr != data->mf[next_index].mat_nr)
+ if (data->mpoly && data->mpoly[cur_index].mat_nr != data->mpoly[next_index].mat_nr)
return 0;
- if (data->tf && data->tf[cur_index].tpage != data->tf[next_index].tpage)
+ if (data->mtexpoly && data->mtexpoly[cur_index].tpage != data->mtexpoly[next_index].tpage)
return 0;
return 1;
@@ -902,43 +949,36 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
data.em = me->edit_btmesh;
data.has_mcol = CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_MLOOPCOL);
- data.has_mtface = CustomData_has_layer(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY);
- data.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
- data.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+ data.cd_poly_tex_offset = CustomData_get_offset(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY);
+
+ data.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
+ data.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0);
}
else if (draw_flags & DRAW_FACE_SELECT) {
if (ob->mode & OB_MODE_WEIGHT_PAINT)
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions_facemask, GPU_enable_material, NULL, me,
- DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH);
+ DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN);
else {
drawTFace_userData userData;
- userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
- userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+ userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
+ userData.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
userData.me = me;
dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag);
}
}
- else {
- if (GPU_buffer_legacy(dm)) {
- if (draw_flags & DRAW_MODIFIERS_PREVIEW)
- dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL, uvflag);
- else
- dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL, uvflag);
- }
- else {
- drawTFace_userData userData;
-
- update_tface_color_layer(dm);
-
- userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
- userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
- userData.me = NULL;
-
- dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag);
- }
+ else {
+ drawTFace_userData userData;
+
+ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
+
+ userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
+ userData.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
+ userData.me = NULL;
+
+ dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag);
}
/* draw game engine text hack */
@@ -948,8 +988,10 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
draw_textured_end();
/* draw edges and selected faces over textured mesh */
- if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT))
- draw_mesh_face_select(rv3d, me, dm);
+ if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) {
+ bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0;
+ draw_mesh_face_select(rv3d, me, dm, draw_select_edges);
+ }
/* reset from negative scale correction */
glFrontFace(GL_CCW);
@@ -1096,7 +1138,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Mesh *me = ob->data;
TexMatCallback data = {scene, ob, me, dm};
bool (*set_face_cb)(void *, int);
- int glsl, picking = (G.f & G_PICKSEL);
+ bool glsl, picking = (G.f & G_PICKSEL) != 0;
/* face hiding callback depending on mode */
if (ob == scene->obedit)
@@ -1145,8 +1187,10 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
glMatrixMode(GL_MODELVIEW);
/* faceselect mode drawing over textured mesh */
- if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT))
- draw_mesh_face_select(rv3d, ob->data, dm);
+ if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) {
+ bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0;
+ draw_mesh_face_select(rv3d, ob->data, dm, draw_select_edges);
+ }
}
/* Vertex Paint and Weight Paint */
@@ -1176,12 +1220,14 @@ static void draw_mesh_paint_light_end(void)
void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light,
void *facemask_cb, void *user_data)
{
+ DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_enable_material : NULL;
+
if (use_light) {
draw_mesh_paint_light_begin();
}
- dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, GPU_enable_material, NULL, user_data,
- DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH);
+ dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data,
+ DM_DRAW_USE_COLORS);
if (use_light) {
draw_mesh_paint_light_end();
@@ -1192,18 +1238,18 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light,
void *facemask_cb, void *user_data,
const Mesh *me)
{
+ DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_enable_material : NULL;
+
if (use_light) {
draw_mesh_paint_light_begin();
}
if (me->mloopcol) {
- dm->drawMappedFaces(dm, facemask_cb, GPU_enable_material, NULL, user_data,
- DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH);
+ dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, DM_DRAW_USE_COLORS);
}
else {
glColor3f(1.0f, 1.0f, 1.0f);
- dm->drawMappedFaces(dm, facemask_cb, GPU_enable_material, NULL, user_data,
- DM_DRAW_ALWAYS_SMOOTH);
+ dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, 0);
}
if (use_light) {
@@ -1271,7 +1317,8 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
/* draw face selection on top */
if (draw_flags & DRAW_FACE_SELECT) {
- draw_mesh_face_select(rv3d, me, dm);
+ bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0;
+ draw_mesh_face_select(rv3d, me, dm, draw_select_edges);
}
else if ((use_light == false) || (ob->dtx & OB_DRAWWIRE)) {
const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) || !(ob->mode & OB_MODE_WEIGHT_PAINT);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 2f0f6d59b8c..4e9818deb72 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -52,6 +52,7 @@
#include "BKE_anim.h" /* for the where_on_path function */
#include "BKE_armature.h"
#include "BKE_camera.h"
+#include "BKE_colortools.h"
#include "BKE_constraint.h" /* for the get_constraint_target function */
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
@@ -73,6 +74,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_subsurf.h"
#include "BKE_unit.h"
#include "BKE_tracking.h"
@@ -175,7 +177,6 @@ typedef struct drawDMFacesSel_userData {
BMesh *bm;
BMFace *efa_act;
- const int *orig_index_mf_to_mpoly;
const int *orig_index_mp_to_orig;
} drawDMFacesSel_userData;
@@ -213,6 +214,7 @@ static void drawcube_size(float size);
static void drawcircle_size(float size);
static void draw_empty_sphere(float size);
static void draw_empty_cone(float size);
+static void draw_box(float vec[8][3], bool solid);
static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
{
@@ -299,11 +301,12 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
return true;
- if (BKE_scene_use_new_shading_nodes(scene))
+ if (v3d->drawtype == OB_TEXTURE)
+ return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
+ else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
+ return true;
+ else
return false;
-
- return ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
- (v3d->drawtype == OB_MATERIAL)) && (dt > OB_SOLID);
}
static bool check_alpha_pass(Base *base)
@@ -402,13 +405,13 @@ static const float cosval[CIRCLE_RESOL] = {
static void draw_xyz_wire(const float c[3], float size, int axis)
{
- float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
+ float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
float dim = size * 0.1f;
float dx[3], dy[3], dz[3];
- dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
- dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
- dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
+ dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
+ dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
+ dz[0] = 0.0f; dz[1] = 0.0f; dz[2] = dim;
switch (axis) {
case 0: /* x axis */
@@ -424,7 +427,7 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v2);
/* top left to bottom right */
- mul_v3_fl(dy, 2.f);
+ mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
sub_v3_v3(v2, dy);
@@ -447,7 +450,7 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v2);
/* top left to center */
- mul_v3_fl(dy, 2.f);
+ mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
copy_v3_v3(v2, c);
@@ -465,12 +468,12 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v1);
- mul_v3_fl(dx, 2.f);
+ mul_v3_fl(dx, 2.0f);
add_v3_v3(v1, dx);
glVertex3fv(v1);
- mul_v3_fl(dz, 2.f);
+ mul_v3_fl(dz, 2.0f);
sub_v3_v3(v1, dx);
sub_v3_v3(v1, dz);
@@ -483,7 +486,6 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glEnd();
break;
}
-
}
void drawaxes(float size, char drawtype)
@@ -597,10 +599,10 @@ void drawaxes(float size, char drawtype)
}
-/* Function to draw an Image on a empty Object */
+/* Function to draw an Image on an empty Object */
static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
{
- Image *ima = (Image *)ob->data;
+ Image *ima = ob->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
float scale, ofs_x, ofs_y, sca_x, sca_y;
@@ -640,16 +642,13 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
sca_y = 1.0f;
}
- /* Calculate the scale center based on objects origin */
+ /* Calculate the scale center based on object's origin */
ofs_x = ob->ima_ofs[0] * ima_x;
ofs_y = ob->ima_ofs[1] * ima_y;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- /* Make sure we are drawing at the origin */
- glTranslatef(0.0f, 0.0f, 0.0f);
-
/* Calculate Image scale */
scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
@@ -732,7 +731,7 @@ void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4])
}
/* circle for object centers, special_color is for library or ob users */
-static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
+static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color)
{
const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
float verts[CIRCLE_RESOL][3];
@@ -740,6 +739,8 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
/* using gldepthfunc guarantees that it does write z values,
* but not checks for it, so centers remain visible independent order of drawing */
if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
+ /* write to near buffer always */
+ glDepthRange(0.0, 0.0);
glEnable(GL_BLEND);
if (special_color) {
@@ -769,6 +770,7 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
/* finish up */
glDisableClientState(GL_VERTEX_ARRAY);
+ glDepthRange(0.0, 1.0);
glDisable(GL_BLEND);
if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
@@ -940,7 +942,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
/* ******************** primitive drawing ******************* */
-/* draws a cube on given the scaling of the cube, assuming that
+/* draws a cube given the scaling of the cube, assuming that
* all required matrices have been set (used for drawing empties)
*/
static void drawcube_size(float size)
@@ -974,7 +976,7 @@ static void drawcube_size(const float size[3])
{
glPushMatrix();
- glScalef(size[0], size[1], size[2]);
+ glScale3fv(size);
glBegin(GL_LINE_STRIP);
@@ -1022,8 +1024,6 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4])
glPointSize(1.0);
}
-
-
static void spotvolume(float lvec[3], float vvec[3], const float inp)
{
/* camera is at 0,0,0 */
@@ -1032,8 +1032,8 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp)
normalize_v3(lvec);
normalize_v3(vvec); /* is this the correct vector ? */
- cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
- cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
+ cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */
+ cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */
/* vectors are exactly aligned, use the X axis, this is arbitrary */
if (normalize_v3(plane) == 0.0f)
@@ -1146,6 +1146,52 @@ static void draw_transp_spot_volume(Lamp *la, float x, float z)
glCullFace(GL_BACK);
}
+#ifdef WITH_GAMEENGINE
+static void draw_transp_sun_volume(Lamp *la)
+{
+ float box[8][3];
+
+ /* construct box */
+ box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
+ box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
+ box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
+ box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
+ box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
+ box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
+
+ /* draw edges */
+ draw_box(box, false);
+
+ /* draw faces */
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glDepthMask(0);
+
+ /* draw backside darkening */
+ glCullFace(GL_FRONT);
+
+ glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
+ glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+
+ draw_box(box, true);
+
+ /* draw front side lighting */
+ glCullFace(GL_BACK);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+ glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
+
+ draw_box(box, true);
+
+ /* restore state */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+ glDepthMask(1);
+ glDisable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+}
+#endif
+
static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
{
@@ -1158,7 +1204,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
unsigned char curcol[4];
unsigned char col[4];
- /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
+ /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
/* the moment of view3d_draw_transp() call */
const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
const bool drawcone = ((dt > OB_WIRE) &&
@@ -1168,7 +1214,22 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
!(base->flag & OB_FROMDUPLI) &&
!is_view);
- if (drawcone && !v3d->transp) {
+#ifdef WITH_GAMEENGINE
+ const bool drawshadowbox = (
+ (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
+ (dt > OB_WIRE) &&
+ !(G.f & G_PICKSEL) &&
+ (la->type == LA_SUN) &&
+ ((la->mode & LA_SHAD_BUF) ||
+ (la->mode & LA_SHAD_RAY)) &&
+ (la->mode & LA_SHOW_SHADOW_BOX) &&
+ !(base->flag & OB_FROMDUPLI) &&
+ !is_view);
+#else
+ const bool drawshadowbox = false;
+#endif
+
+ if ((drawcone || drawshadowbox) && !v3d->transp) {
/* in this case we need to draw delayed */
ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
return;
@@ -1254,7 +1315,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
/* center */
- glTranslatef(vec[0], vec[1], vec[2]);
+ glTranslate3fv(vec);
setlinestyle(3);
@@ -1307,7 +1368,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
x *= y;
/* draw the circle/square at the end of the cone */
- glTranslatef(0.0, 0.0, x);
+ glTranslatef(0.0, 0.0, x);
if (la->mode & LA_SQUARE) {
float tvec[3];
float z_abs = fabsf(z);
@@ -1331,7 +1392,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
/* draw the circle/square representing spotbl */
if (la->type == LA_SPOT) {
- float spotblcirc = fabsf(z) * (1.0f - powf(la->spotblend, 2));
+ float spotblcirc = fabsf(z) * (1.0f - pow2f(la->spotblend));
/* hide line if it is zero size or overlaps with outer border,
* previously it adjusted to always to show it but that seems
* confusing because it doesn't show the actual blend size */
@@ -1413,6 +1474,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
dir = -dir;
}
}
+
+#ifdef WITH_GAMEENGINE
+ if (drawshadowbox) {
+ draw_transp_sun_volume(la);
+ }
+#endif
+
}
else if (la->type == LA_AREA) {
setlinestyle(3);
@@ -1496,10 +1564,10 @@ static void draw_limit_line(float sta, float end, const short dflag, unsigned in
static void draw_focus_cross(float dist, float size)
{
glBegin(GL_LINES);
- glVertex3f(-size, 0.f, -dist);
- glVertex3f(size, 0.f, -dist);
- glVertex3f(0.f, -size, -dist);
- glVertex3f(0.f, size, -dist);
+ glVertex3f(-size, 0.0f, -dist);
+ glVertex3f(size, 0.0f, -dist);
+ glVertex3f(0.0f, -size, -dist);
+ glVertex3f(0.0f, size, -dist);
glEnd();
}
@@ -1552,8 +1620,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
/* we're compensating camera size for bundles size,
- * to make it so bundles are always displayed with the same size
- */
+ * to make it so bundles are always displayed with the same size */
copy_v3_v3(camera_size, base->object->size);
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
mul_v3_fl(camera_size, tracking_object->scale);
@@ -1592,7 +1659,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
GPU_select_load_id(base->selcol + (tracknr << 16));
glPushMatrix();
- glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+ glTranslate3fv(track->bundle_pos);
glScalef(v3d->bundle_size / 0.05f / camera_size[0],
v3d->bundle_size / 0.05f / camera_size[1],
v3d->bundle_size / 0.05f / camera_size[2]);
@@ -1621,7 +1688,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
glColor3ubv(ob_wire_col);
}
- glLineWidth(2.f);
+ glLineWidth(2.0f);
glDisable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -1629,7 +1696,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LIGHTING);
- glLineWidth(1.f);
+ glLineWidth(1.0f);
}
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1743,6 +1810,238 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d,
GPU_select_load_id(base->selcol);
}
+static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
+{
+ glBegin(mode);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(far_plane[0]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(near_plane[1]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(near_plane[1]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(far_plane[2]);
+ glVertex3fv(near_plane[2]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(near_plane[2]);
+ glVertex3fv(near_plane[1]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(far_plane[2]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(far_plane[0]);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(near_plane[3]);
+ glVertex3fv(far_plane[3]);
+ glEnd();
+}
+
+/* camera frame */
+static void drawcamera_frame(float vec[4][3], const GLenum mode)
+{
+ glBegin(mode);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[2]);
+ glVertex3fv(vec[3]);
+ glEnd();
+}
+
+/* center point to camera frame */
+static void drawcamera_framelines(float vec[4][3], float origin[3])
+{
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[1]);
+ glVertex3fv(origin);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]);
+ glVertex3fv(origin);
+ glVertex3fv(vec[2]);
+ glEnd();
+}
+
+static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
+{
+ return (ob == v3d->camera) &&
+ (scene->r.scemode & R_MULTIVIEW) != 0 &&
+ (v3d->stereo3d_flag);
+}
+
+static void drawcamera_stereo3d(
+ Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
+ float vec[4][3], float drawsize, const float scale[3])
+{
+ int i, j;
+ float obmat[4][4];
+ float vec_lr[2][4][3];
+ const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
+ float origin[2][3] = {{0}};
+ float tvec[3];
+ const Camera *cam_lr[2];
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
+
+ zero_v3(tvec);
+
+ glPushMatrix();
+
+ for (i = 0; i < 2; i++) {
+ ob = BKE_camera_multiview_render(scene, ob, names[i]);
+ cam_lr[i] = ob->data;
+
+ glLoadMatrixf(rv3d->viewmat);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
+ glMultMatrixf(obmat);
+
+ copy_m3_m3(vec_lr[i], vec);
+ copy_v3_v3(vec_lr[i][3], vec[3]);
+
+ if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ const float shift_x =
+ ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
+ (drawsize * scale[0] * fac));
+
+ for (j = 0; j < 4; j++) {
+ vec_lr[i][j][0] += shift_x;
+ }
+ }
+
+ if (is_stereo3d_cameras) {
+ /* camera frame */
+ drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
+
+ /* center point to camera frame */
+ drawcamera_framelines(vec_lr[i], tvec);
+ }
+
+ /* connecting line */
+ mul_m4_v3(obmat, origin[i]);
+
+ /* convergence plane */
+ if (is_stereo3d_plane || is_stereo3d_volume) {
+ for (j = 0; j < 4; j++) {
+ mul_m4_v3(obmat, vec_lr[i][j]);
+ }
+ }
+ }
+
+
+ /* the remaining drawing takes place in the view space */
+ glLoadMatrixf(rv3d->viewmat);
+
+ if (is_stereo3d_cameras) {
+ /* draw connecting lines */
+ glPushAttrib(GL_ENABLE_BIT);
+
+ glLineStipple(2, 0xAAAA);
+ glEnable(GL_LINE_STIPPLE);
+
+ glBegin(GL_LINES);
+ glVertex3fv(origin[0]);
+ glVertex3fv(origin[1]);
+ glEnd();
+ glPopAttrib();
+ }
+
+ /* draw convergence plane*/
+ if (is_stereo3d_plane) {
+ float axis_center[3], screen_center[3];
+ float world_plane[4][3];
+ float local_plane[4][3];
+ float offset;
+
+ mid_v3_v3v3(axis_center, origin[0], origin[1]);
+
+ for (i = 0; i < 4; i++) {
+ mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
+ sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
+ }
+
+ mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
+ offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
+
+ for (i = 0; i < 4; i++) {
+ mul_v3_fl(local_plane[i], offset);
+ add_v3_v3(local_plane[i], axis_center);
+ }
+
+ glColor3f(0.0f, 0.0f, 0.0f);
+
+ /* camera frame */
+ drawcamera_frame(local_plane, GL_LINE_LOOP);
+
+ if (v3d->stereo3d_convergence_alpha > 0.0f) {
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+
+ glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
+
+ drawcamera_frame(local_plane, GL_QUADS);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ }
+
+ /* draw convergence plane*/
+ if (is_stereo3d_volume) {
+ float screen_center[3];
+ float near_plane[4][3], far_plane[4][3];
+ float offset;
+ int j;
+
+ for (i = 0; i < 2; i++) {
+ mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
+
+ offset = len_v3v3(screen_center, origin[i]);
+
+ for (j = 0; j < 4; j++) {
+ sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
+ mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
+ add_v3_v3(near_plane[j], origin[i]);
+
+ sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
+ mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
+ add_v3_v3(far_plane[j], origin[i]);
+ }
+
+ /* camera frame */
+ glColor3f(0.0f, 0.0f, 0.0f);
+
+ drawcamera_frame(near_plane, GL_LINE_LOOP);
+ drawcamera_frame(far_plane, GL_LINE_LOOP);
+ drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
+
+ if (v3d->stereo3d_volume_alpha > 0.0f) {
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+
+ if (i == 0)
+ glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
+ else
+ glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
+
+ drawcamera_frame(near_plane, GL_QUADS);
+ drawcamera_frame(far_plane, GL_QUADS);
+ drawcamera_volume(near_plane, far_plane, GL_QUADS);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ }
+ }
+
+ glPopMatrix();
+}
+
/* flag similar to draw_object() */
static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const short dflag, const unsigned char ob_wire_col[4])
@@ -1754,9 +2053,20 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
float vec[4][3], asp[2], shift[2], scale[3];
int i;
float drawsize;
- const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
+ const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
+ const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_cameras = (ob == scene->camera) &&
+ is_multiview &&
+ is_stereo3d_view &&
+ (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
+ const bool is_selection_camera_stereo = (G.f & G_PICKSEL) &&
+ is_view && is_multiview &&
+ is_stereo3d_view;
+
/* draw data for movie clip set as active for scene */
if (clip) {
draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
@@ -1782,9 +2092,17 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
cam = ob->data;
- scale[0] = 1.0f / len_v3(ob->obmat[0]);
- scale[1] = 1.0f / len_v3(ob->obmat[1]);
- scale[2] = 1.0f / len_v3(ob->obmat[2]);
+ /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */
+ if (is_selection_camera_stereo) {
+ scale[0] = 1.0f;
+ scale[1] = 1.0f;
+ scale[2] = 1.0f;
+ }
+ else {
+ scale[0] = 1.0f / len_v3(ob->obmat[0]);
+ scale[1] = 1.0f / len_v3(ob->obmat[1]);
+ scale[2] = 1.0f / len_v3(ob->obmat[2]);
+ }
BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
asp, shift, &drawsize, vec);
@@ -1793,12 +2111,24 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glDisable(GL_CULL_FACE);
/* camera frame */
- glBegin(GL_LINE_LOOP);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[1]);
- glVertex3fv(vec[2]);
- glVertex3fv(vec[3]);
- glEnd();
+ if (!is_stereo3d_cameras) {
+ /* make sure selection uses the same matrix for camera as the one used while viewing */
+ if (is_selection_camera_stereo) {
+ float obmat[4][4];
+ bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+
+ glPushMatrix();
+ glLoadMatrixf(rv3d->viewmat);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
+ glMultMatrixf(obmat);
+
+ drawcamera_frame(vec, GL_LINE_LOOP);
+ glPopMatrix();
+ }
+ else {
+ drawcamera_frame(vec, GL_LINE_LOOP);
+ }
+ }
if (is_view)
return;
@@ -1806,20 +2136,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
zero_v3(tvec);
/* center point to camera frame */
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[1]);
- glVertex3fv(tvec);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[3]);
- glVertex3fv(tvec);
- glVertex3fv(vec[2]);
- glEnd();
-
+ if (!is_stereo3d_cameras)
+ drawcamera_framelines(vec, tvec);
/* arrow on top */
tvec[2] = vec[1][2]; /* copy the depth */
-
/* draw an outline arrow for inactive cameras and filled
* for active cameras. We actually draw both outline+filled
* for active cameras so the wire can be seen side-on */
@@ -1869,14 +2191,17 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glPopMatrix();
}
}
+
+ /* stereo cameras drawing */
+ if (is_stereo3d) {
+ drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
+ }
}
/* flag similar to draw_object() */
static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
Object *UNUSED(ob), int UNUSED(flag))
{
- //Speaker *spk = ob->data;
-
float vec[3];
int i, j;
@@ -1948,8 +2273,8 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
}
}
- glPointSize(1.0);
bglEnd();
+ glPointSize(1.0);
}
static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
@@ -1987,9 +2312,9 @@ static void ensure_curve_cache(Scene *scene, Object *object)
* here, we also need to check whether display list is
* empty or not.
*
- * The trick below tries to optimie calls to displist
+ * The trick below tries to optimize calls to displist
* creation for cases curve is empty. Meaning, if the curve
- * is empty (without splies) bevel list would also be empty.
+ * is empty (without splines) bevel list would also be empty.
* And the thing is, render thread always leaves bevel list
* in a proper state. So if bevel list is here and display
* list is not we need to make display list.
@@ -2153,8 +2478,7 @@ static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
invert_m3_m3(data->imat, obmat);
/* transposed inverted matrix */
- copy_m3_m3(data->tmat, data->imat);
- transpose_m3(data->tmat);
+ transpose_m3_m3(data->tmat, data->imat);
}
}
@@ -2268,8 +2592,7 @@ static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
- /* skin nodes: draw a red circle around the root
- * node(s) */
+ /* skin nodes: draw a red circle around the root node(s) */
if (data->cd_vskin_offset != -1) {
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
if (vs->flag & MVERT_SKIN_ROOT) {
@@ -2335,7 +2658,6 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
{
BMEdge *eed;
- //unsigned char **cols = userData, *col;
drawDMEdgesSel_userData *data = userData;
unsigned char *col;
@@ -2352,7 +2674,7 @@ static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
else {
col = data->baseCol;
}
- /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
+ /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
if (col[3] == 0)
return DM_DRAW_OPTION_SKIP;
@@ -2497,7 +2819,7 @@ static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const c
data.bm = em->bm;
data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
- data.defgroup_tot = BLI_countlist(&ob->defbase);
+ data.defgroup_tot = BLI_listbase_count(&ob->defbase);
data.vgroup_index = ob->actdef - 1;
data.weight_user = weight_user;
UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
@@ -2692,12 +3014,9 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
unsigned char *col, *next_col;
- if (!data->orig_index_mf_to_mpoly)
- return 0;
-
- i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, index);
+ i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[index] : index;
efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
- i = DM_origindex_mface_mpoly(data->orig_index_mf_to_mpoly, data->orig_index_mp_to_orig, next_index);
+ i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[next_index] : next_index;
next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
if (ELEM(NULL, efa, next_efa))
@@ -2743,13 +3062,9 @@ static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *ba
#endif
data.efa_act = efa_act;
/* double lookup */
- data.orig_index_mf_to_mpoly = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
- if ((data.orig_index_mf_to_mpoly && data.orig_index_mp_to_orig) == false) {
- data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
- }
- dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
+ dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, NULL, draw_dm_faces_sel__compareDrawOptions, &data, DM_DRAW_SKIP_HIDDEN);
}
static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
@@ -2842,11 +3157,6 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
}
}
-static int draw_dm_override_material_color(int UNUSED(nr), void *UNUSED(attribs))
-{
- return 1;
-}
-
/* Second section of routines: Combine first sets to form fancy
* drawing routines (for example rendering twice to get overlays).
*
@@ -2953,21 +3263,23 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
if (!sel_only) wireCol[3] = 255;
}
- if (ts->selectmode == SCE_SELECT_FACE) {
- draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
- }
- else if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
+ if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
if (cageDM->drawMappedEdgesInterp &&
((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT)))
{
- glShadeModel(GL_SMOOTH);
if (draw_dm_edges_weight_check(me, v3d)) {
+ glShadeModel(GL_SMOOTH);
draw_dm_edges_weight_interp(em, cageDM, ts->weightuser);
+ glShadeModel(GL_FLAT);
+ }
+ else if (ts->selectmode == SCE_SELECT_FACE) {
+ draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else {
+ glShadeModel(GL_SMOOTH);
draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
+ glShadeModel(GL_FLAT);
}
- glShadeModel(GL_FLAT);
}
else {
draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
@@ -3040,7 +3352,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
}
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- /* draw selected edges, or edges next to selected verts while draging */
+ /* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
(do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
@@ -3078,7 +3390,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
unit->system, B_UNIT_LENGTH, do_split, false);
}
else {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
}
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
@@ -3097,17 +3409,15 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
}
- // invert_m4_m4(ob->imat, ob->obmat); // this is already called
-
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
- /* draw selected edges, or edges next to selected verts while draging */
+ /* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
(do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
- /* special case, this is useful to show when vertes connected to this edge via a
- * face are being transformed */
+ /* special case, this is useful to show when verts connected to
+ * this edge via a face are being transformed */
BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
@@ -3157,7 +3467,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
angle = angle_normalized_v3v3(no_a, no_b);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3182,7 +3492,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
3, unit->system, B_UNIT_AREA, do_split, false); \
} \
else { \
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area); \
} \
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); \
} (void)0
@@ -3256,7 +3566,12 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
bool is_first = true;
BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (is_face_sel || (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) {
+ if (is_face_sel ||
+ (do_moving &&
+ (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT))))
+ {
float angle;
float v2_local[3];
@@ -3300,7 +3615,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
angle = angle_v3v3v3(v1, v2, v3);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
view3d_cached_text_draw_add(fvec, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3331,7 +3646,7 @@ static void draw_em_indices(BMEditMesh *em)
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
view3d_cached_text_draw_add(v->co, numstr, numstr_len, 0, txt_flag, col);
}
i++;
@@ -3343,7 +3658,7 @@ static void draw_em_indices(BMEditMesh *em)
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
mid_v3_v3v3(pos, e->v1->co, e->v2->co);
view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3357,7 +3672,7 @@ static void draw_em_indices(BMEditMesh *em)
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
BM_face_calc_center_mean(f, pos);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
}
i++;
@@ -3375,7 +3690,6 @@ static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
efa = BM_face_at_index(em->bm, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_enable_material(efa->mat_nr + 1, NULL);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -3414,7 +3728,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
if (em->bm->selected.last) {
BMEditSelection *ese = em->bm->selected.last;
- /* face is handeled above */
+ /* face is handled above */
#if 0
if (ese->type == BM_FACE) {
efa_act = (BMFace *)ese->data;
@@ -3450,7 +3764,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
/* use the cageDM since it always overlaps the editmesh faces */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
cageDM->drawMappedFaces(cageDM, draw_em_fancy__setFaceOpts,
- GPU_enable_material, NULL, me->edit_btmesh, 0);
+ GPU_enable_material, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
else if (check_object_draw_texture(scene, v3d, dt)) {
@@ -3474,7 +3788,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, 0);
+ finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN);
glFrontFace(GL_CCW);
glDisable(GL_LIGHTING);
@@ -3529,11 +3843,14 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
else if (efa_act) {
/* even if draw faces is off it would be nice to draw the stipple face
- * Make all other faces zero alpha except for the active
- * */
- /* col4 is only used by WITH_FREESTYLE, but keeping it here spares some #ifdef's... */
- unsigned char col1[4], col2[4], col3[4], col4[4];
- col1[3] = col2[3] = col4[3] = 0; /* don't draw */
+ * Make all other faces zero alpha except for the active */
+ unsigned char col1[4], col2[4], col3[4];
+#ifdef WITH_FREESTYLE
+ unsigned char col4[4];
+ col4[3] = 0; /* don't draw */
+#endif
+ col1[3] = col2[3] = 0; /* don't draw */
+
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
glEnable(GL_BLEND);
@@ -3547,7 +3864,6 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
glDisable(GL_BLEND);
glDepthMask(1); /* restore write in zbuffer */
-
}
/* here starts all fancy draw-extra over */
@@ -3672,6 +3988,12 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
}
}
+static bool object_is_halo(Scene *scene, Object *ob)
+{
+ const Material *ma = give_current_material(ob, 1);
+ return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
+}
+
static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
@@ -3681,10 +4003,8 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
Object *ob = base->object;
#endif
Mesh *me = ob->data;
- Material *ma = give_current_material(ob, 1);
- const bool hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
- int /* totvert,*/ totedge, totface;
+ bool /* no_verts,*/ no_edges, no_faces;
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
const bool is_obact = (ob == OBACT);
int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
@@ -3696,7 +4016,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* Check to draw dynamic paint colors (or weights from WeightVG modifiers).
* Note: Last "preview-active" modifier in stack will win! */
- if (DM_get_tessface_data_layer(dm, CD_PREVIEW_MCOL) && modifiers_isPreview(ob))
+ if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob))
draw_flags |= DRAW_MODIFIERS_PREVIEW;
/* Unwanted combination */
@@ -3707,10 +4027,16 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_wire = OBDRAW_WIRE_ON_DEPTH; /* draw wire after solid using zoffset and depth buffer adjusment */
}
- /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
- totedge = dm->getNumEdges(dm);
- totface = dm->getNumTessFaces(dm);
-
+ /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */
+ if (dm->type == DM_TYPE_CCGDM) {
+ no_edges = !subsurf_has_edges(dm);
+ no_faces = !subsurf_has_faces(dm);
+ }
+ else {
+ no_edges = (dm->getNumEdges(dm) == 0);
+ no_faces = (dm->getNumPolys(dm) == 0);
+ }
+
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
@@ -3718,13 +4044,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
draw_bounding_volume(ob, ob->boundtype);
}
- else if (hasHaloMat || (totface == 0 && totedge == 0)) {
+ else if ((no_faces && no_edges) ||
+ ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
+ {
glPointSize(1.5);
dm->drawVerts(dm);
glPointSize(1.0);
}
- else if (dt == OB_WIRE || totface == 0) {
- draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
+ else if ((dt == OB_WIRE) || no_faces) {
+ draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
}
else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
check_object_draw_texture(scene, v3d, dt))
@@ -3766,14 +4094,16 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
else
dm->drawFacesGLSL(dm, GPU_enable_material);
-// if (BKE_bproperty_object_get(ob, "Text"))
-// XXX draw_mesh_text(ob, 1);
+#if 0 /* XXX */
+ if (BKE_bproperty_object_get(ob, "Text"))
+ draw_mesh_text(ob, 1);
+#endif
GPU_disable_material();
glFrontFace(GL_CCW);
if (draw_flags & DRAW_FACE_SELECT)
- draw_mesh_face_select(rv3d, me, dm);
+ draw_mesh_face_select(rv3d, me, dm, false);
}
else {
draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
@@ -3820,7 +4150,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
- dm->drawMappedFaces(dm, NULL, draw_dm_override_material_color, NULL, NULL, DM_DRAW_USE_COLORS);
+ dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
@@ -3885,7 +4215,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */
- /* when overriding with render only, don't bother */
+ /* when overriding with render only, don't bother */
(((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0))
{
/* When using wireframe object draw in particle edit mode
@@ -3915,7 +4245,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
}
- dm->drawEdges(dm, (dt == OB_WIRE || totface == 0), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
+ dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
glDepthMask(1);
@@ -3924,7 +4254,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
if (is_obact && BKE_paint_select_vert_test(ob)) {
- const int use_depth = (v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
@@ -3939,7 +4269,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
dm->release(dm);
}
-/* returns 1 if nothing was drawn, for detecting to draw an object center */
+/* returns true if nothing was drawn, for detecting to draw an object center */
static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
@@ -3979,11 +4309,14 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
if (obedit != ob)
finalDM = cageDM = editbmesh_get_derived_base(ob, em);
else
- cageDM = editbmesh_get_derived_cage_and_final(scene, ob, em, &finalDM,
- scene->customdata_mask);
+ cageDM = editbmesh_get_derived_cage_and_final(
+ scene, ob, em, scene->customdata_mask,
+ &finalDM);
DM_update_materials(finalDM, ob);
- DM_update_materials(cageDM, ob);
+ if (cageDM != finalDM) {
+ DM_update_materials(cageDM, ob);
+ }
if (dt > OB_WIRE) {
const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
@@ -4295,7 +4628,7 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- if (dt > OB_WIRE && dm->getNumTessFaces(dm)) {
+ if (dt > OB_WIRE && dm->getNumPolys(dm)) {
int glsl = draw_glsl_material(scene, ob, v3d, dt);
GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
@@ -4319,7 +4652,7 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/**
* Only called by #drawDispList
- * \return 1 when nothing was drawn
+ * \return true when nothing was drawn
*/
static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
@@ -4328,19 +4661,8 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
ListBase *lb = NULL;
DispList *dl;
Curve *cu;
- const short render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE);
- const short solid = (dt > OB_WIRE);
-
- if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
- return false;
- }
-
- if (ob->type == OB_MBALL) {
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- }
- else {
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CCW : GL_CW);
- }
+ const bool render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
+ const bool solid = (dt > OB_WIRE);
switch (ob->type) {
case OB_FONT:
@@ -4469,7 +4791,28 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
ensure_curve_cache(scene, base->object);
#endif
- retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
+ retval = false;
+ }
+ else {
+ Object *ob = base->object;
+ GLenum mode;
+
+ if (ob->type == OB_MBALL) {
+ mode = (ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW;
+ }
+ else {
+ mode = (ob->transflag & OB_NEG_SCALE) ? GL_CCW : GL_CW;
+ }
+
+ glFrontFace(mode);
+
+ retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+
+ if (mode != GL_CCW) {
+ glFrontFace(GL_CCW);
+ }
+ }
if (v3d->flag2 & V3D_BACKFACE_CULLING) {
glDisable(GL_CULL_FACE);
@@ -4581,7 +4924,7 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
vec[2] = 2.0f * pixsize;
- vec[0] = vec[1] = 0.0;
+ vec[0] = vec[1] = 0.0f;
mul_qt_v3(state->rot, vec);
if (draw_as == PART_DRAW_AXIS) {
copy_v3_v3(vec2, state->co);
@@ -4664,7 +5007,7 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
if (psys->parent)
mul_m4_v3(psys->parent->obmat, state->co);
- /* create actiual particle data */
+ /* create actual particle data */
if (draw_as == PART_DRAW_BB) {
bb->offset[0] = part->bb_offset[0];
bb->offset[1] = part->bb_offset[1];
@@ -4689,16 +5032,17 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
}
-/* unified drawing of all new particle systems draw types except dupli ob & group */
-/* mostly tries to use vertex arrays for speed */
-
-/* 1. check that everything is ok & updated */
-/* 2. start initializing things */
-/* 3. initialize according to draw type */
-/* 4. allocate drawing data arrays */
-/* 5. start filling the arrays */
-/* 6. draw the arrays */
-/* 7. clean up */
+/* unified drawing of all new particle systems draw types except dupli ob & group
+ * mostly tries to use vertex arrays for speed
+ *
+ * 1. check that everything is ok & updated
+ * 2. start initializing things
+ * 3. initialize according to draw type
+ * 4. allocate drawing data arrays
+ * 5. start filling the arrays
+ * 6. draw the arrays
+ * 7. clean up
+ */
static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Base *base, ParticleSystem *psys,
const char ob_dt, const short dflag)
@@ -4743,6 +5087,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (draw_as == PART_DRAW_NOT)
return;
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+
/* 2. */
sim.scene = scene;
sim.ob = ob;
@@ -4888,7 +5238,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
int create_ndata = 0;
if (!pdd)
- pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticlDrawData");
+ pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData");
if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
tot_vec_size *= part->trail_count;
@@ -4991,7 +5341,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
BLI_assert(0);
break;
}
- CLAMP(intensity, 0.f, 1.f);
+ CLAMP(intensity, 0.0f, 1.0f);
weight_to_rgb(ma_col, intensity);
}
}
@@ -5050,8 +5400,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
if (drawn) {
- /* additional things to draw for each particle */
- /* (velocity, size and number) */
+ /* additional things to draw for each particle
+ * (velocity, size and number) */
if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) {
copy_v3_v3(pdd->ved, state.co);
pdd->ved += 3;
@@ -5079,21 +5429,21 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (part->draw & PART_DRAW_NUM) {
if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
}
else {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%d", a);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a);
}
}
else {
if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%.2f", pa_health);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health);
}
}
if (numstr[0]) {
- /* in path drawing state.co is the end point */
- /* use worldspace beause object matrix is already applied */
+ /* in path drawing state.co is the end point
+ * use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, state.co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
@@ -5110,7 +5460,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (draw_as == PART_DRAW_PATH) {
ParticleCacheKey **cache, *path;
- float /* *cd2=NULL, */ /* UNUSED */ *cdata2 = NULL;
+ float *cdata2 = NULL;
/* setup gl flags */
if (1) { //ob_dt > OB_WIRE) {
@@ -5144,7 +5494,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
cache = psys->pathcache;
for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
path = cache[a];
- if (path->steps > 0) {
+ if (path->segments > 0) {
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
if (1) { //ob_dt > OB_WIRE) {
@@ -5156,7 +5506,138 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
}
- glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+ glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
+ }
+ }
+
+ if (part->type == PART_HAIR) {
+ if (part->draw & PART_DRAW_GUIDE_HAIRS) {
+ DerivedMesh *hair_dm = psys->hair_out_dm;
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
+ if (pa->totkey > 1) {
+ HairKey *hkey = pa->hair;
+
+ glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co);
+
+#if 0 /* XXX use proper theme color here */
+ UI_ThemeColor(TH_NORMAL);
+#else
+ glColor3f(0.58f, 0.67f, 1.0f);
+#endif
+
+ glDrawArrays(GL_LINE_STRIP, 0, pa->totkey);
+ }
+ }
+
+ if (hair_dm) {
+ MVert *mvert = hair_dm->getVertArray(hair_dm);
+ int i;
+
+ glColor3f(0.9f, 0.4f, 0.4f);
+
+ glBegin(GL_LINES);
+ for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
+ for (i = 1; i < pa->totkey; ++i) {
+ float v1[3], v2[3];
+
+ copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co);
+ copy_v3_v3(v2, mvert[pa->hair_index + i].co);
+
+ mul_m4_v3(ob->obmat, v1);
+ mul_m4_v3(ob->obmat, v2);
+
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ }
+ }
+ glEnd();
+ }
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if ((dflag & DRAW_CONSTCOLOR) == 0)
+ if (part->draw_col == PART_DRAW_COL_MAT)
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+
+ if (part->draw & PART_DRAW_HAIR_GRID) {
+ ClothModifierData *clmd = psys->clmd;
+ if (clmd) {
+ float *a = clmd->hair_grid_min;
+ float *b = clmd->hair_grid_max;
+ int *res = clmd->hair_grid_res;
+ int i;
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ if (select)
+ UI_ThemeColor(TH_ACTIVE);
+ else
+ UI_ThemeColor(TH_WIRE);
+ glBegin(GL_LINES);
+ glVertex3f(a[0], a[1], a[2]); glVertex3f(b[0], a[1], a[2]);
+ glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], b[1], a[2]);
+ glVertex3f(b[0], b[1], a[2]); glVertex3f(a[0], b[1], a[2]);
+ glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], a[1], a[2]);
+
+ glVertex3f(a[0], a[1], b[2]); glVertex3f(b[0], a[1], b[2]);
+ glVertex3f(b[0], a[1], b[2]); glVertex3f(b[0], b[1], b[2]);
+ glVertex3f(b[0], b[1], b[2]); glVertex3f(a[0], b[1], b[2]);
+ glVertex3f(a[0], b[1], b[2]); glVertex3f(a[0], a[1], b[2]);
+
+ glVertex3f(a[0], a[1], a[2]); glVertex3f(a[0], a[1], b[2]);
+ glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], a[1], b[2]);
+ glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], b[1], b[2]);
+ glVertex3f(b[0], b[1], a[2]); glVertex3f(b[0], b[1], b[2]);
+ glEnd();
+
+ if (select)
+ UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100);
+ else
+ UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100);
+ glEnable(GL_BLEND);
+ glBegin(GL_LINES);
+ for (i = 1; i < res[0] - 1; ++i) {
+ float f = interpf(b[0], a[0], (float)i / (float)(res[0] - 1));
+ glVertex3f(f, a[1], a[2]); glVertex3f(f, b[1], a[2]);
+ glVertex3f(f, b[1], a[2]); glVertex3f(f, b[1], b[2]);
+ glVertex3f(f, b[1], b[2]); glVertex3f(f, a[1], b[2]);
+ glVertex3f(f, a[1], b[2]); glVertex3f(f, a[1], a[2]);
+ }
+ for (i = 1; i < res[1] - 1; ++i) {
+ float f = interpf(b[1], a[1], (float)i / (float)(res[1] - 1));
+ glVertex3f(a[0], f, a[2]); glVertex3f(b[0], f, a[2]);
+ glVertex3f(b[0], f, a[2]); glVertex3f(b[0], f, b[2]);
+ glVertex3f(b[0], f, b[2]); glVertex3f(a[0], f, b[2]);
+ glVertex3f(a[0], f, b[2]); glVertex3f(a[0], f, a[2]);
+ }
+ for (i = 1; i < res[2] - 1; ++i) {
+ float f = interpf(b[2], a[2], (float)i / (float)(res[2] - 1));
+ glVertex3f(a[0], a[1], f); glVertex3f(b[0], a[1], f);
+ glVertex3f(b[0], a[1], f); glVertex3f(b[0], b[1], f);
+ glVertex3f(b[0], b[1], f); glVertex3f(a[0], b[1], f);
+ glVertex3f(a[0], b[1], f); glVertex3f(a[0], a[1], f);
+ }
+ glEnd();
+ glDisable(GL_BLEND);
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if ((dflag & DRAW_CONSTCOLOR) == 0)
+ if (part->draw_col == PART_DRAW_COL_MAT)
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
}
}
@@ -5175,10 +5656,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
}
- glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+ glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
}
-
/* restore & clean up */
if (1) { //ob_dt > OB_WIRE) {
if (part->draw_col == PART_DRAW_COL_MAT)
@@ -5186,9 +5666,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDisable(GL_COLOR_MATERIAL);
}
- if (cdata2)
+ if (cdata2) {
MEM_freeN(cdata2);
- /* cd2 = */ /* UNUSED */ cdata2 = NULL;
+ cdata2 = NULL;
+ }
glLineWidth(1.0f);
@@ -5197,8 +5678,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
float vec_txt[3];
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%i", a);
- /* use worldspace beause object matrix is already applied */
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a);
+ /* use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
@@ -5326,8 +5807,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
PTCacheEditPoint *point;
PTCacheEditKey *key;
ParticleEditSettings *pset = PE_settings(scene);
- int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0;
- int steps = 1;
+ int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0;
+ int totkeys = 1;
float sel_col[3];
float nosel_col[3];
float *pathcol = NULL, *pcol;
@@ -5346,10 +5827,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
UI_GetThemeColor3fv(TH_VERTEX, nosel_col);
/* draw paths */
- steps = (*edit->pathcache)->steps + 1;
+ totkeys = (*edit->pathcache)->segments + 1;
glEnable(GL_BLEND);
- pathcol = MEM_callocN(steps * 4 * sizeof(float), "particle path color data");
+ pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
@@ -5369,7 +5850,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
if (point->flag & PEP_HIDE) {
- for (k = 0, pcol = pathcol; k < steps; k++, pcol += 4) {
+ for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) {
copy_v3_v3(pcol, path->col);
pcol[3] = 0.25f;
}
@@ -5377,7 +5858,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
}
else if (timed) {
- for (k = 0, pcol = pathcol, pkey = path; k < steps; k++, pkey++, pcol += 4) {
+ for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) {
copy_v3_v3(pcol, pkey->col);
pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames;
}
@@ -5387,7 +5868,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
else
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
- glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+ glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
}
if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
@@ -5466,7 +5947,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glColor3fv(nosel_col);
/* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
glBegin(GL_POINTS);
- glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co);
+ glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co);
glEnd();
}
}
@@ -5482,9 +5963,9 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glLineWidth(1.0f);
- glPointSize(1.0);
+ glPointSize(1.0f);
}
-//static void ob_draw_RE_motion(float com[3],float rotscale[3][3],float tw,float th)
+
static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size)
{
float tr[3][3];
@@ -5771,8 +6252,8 @@ static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const
if (bezt->hide == 0) {
if (sel == 1 && bezt == vert) {
UI_ThemeColor(TH_ACTIVE_VERT);
- bglVertex3fv(bezt->vec[1]);
+ if (bezt->f2 & SELECT) bglVertex3fv(bezt->vec[1]);
if (!hide_handles) {
if (bezt->f1 & SELECT) bglVertex3fv(bezt->vec[0]);
if (bezt->f3 & SELECT) bglVertex3fv(bezt->vec[2]);
@@ -5888,7 +6369,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
Nurb *nu;
BPoint *bp, *bp1;
int a, b, ofs, index;
- Curve *cu = (Curve *)ob->data;
+ Curve *cu = ob->data;
index = 0;
nu = nurb;
@@ -6248,7 +6729,7 @@ static void draw_empty_sphere(float size)
static GLuint displist = 0;
if (displist == 0) {
- GLUquadricObj *qobj;
+ GLUquadricObj *qobj;
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
@@ -6279,16 +6760,13 @@ static void draw_empty_sphere(float size)
/* draw a cone for use as an empty drawtype */
static void draw_empty_cone(float size)
{
- float cent = 0;
- float radius;
+ const float radius = size;
+
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
-
glPushMatrix();
- radius = size;
- glTranslatef(cent, cent, cent);
glScalef(radius, size * 2.0f, radius);
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
@@ -6301,7 +6779,7 @@ static void draw_empty_cone(float size)
static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start)
{
float vec[3], vx[3], vy[3];
- const float tot_inv = (1.0f / (float)CIRCLE_RESOL);
+ const float tot_inv = 1.0f / (float)CIRCLE_RESOL;
int a;
bool inverse = false;
float x, y, fac;
@@ -6365,8 +6843,7 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
}
/* draws a circle on x-z plane given the scaling of the circle, assuming that
- * all required matrices have been set (used for drawing empties)
- */
+ * all required matrices have been set (used for drawing empties) */
static void drawcircle_size(float size)
{
float x, y;
@@ -6374,7 +6851,7 @@ static void drawcircle_size(float size)
glBegin(GL_LINE_LOOP);
- /* coordinates are: cos(degrees * 11.25) = x, sin(degrees*11.25) = y, 0.0f = z */
+ /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */
for (degrees = 0; degrees < CIRCLE_RESOL; degrees++) {
x = cosval[degrees];
y = sinval[degrees];
@@ -6518,31 +6995,23 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
PartDeflect *pd = ob->pd;
float imat[4][4], tmat[4][4];
float vec[3] = {0.0, 0.0, 0.0};
- float size;
-
/* scale size of circle etc with the empty drawsize */
- if (ob->type == OB_EMPTY) size = ob->empty_drawsize;
- else size = 1.0;
+ const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f;
/* calculus here, is reused in PFIELD_FORCE */
invert_m4_m4(imat, rv3d->viewmatob);
-// normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
-// normalize_v3(imat[1]);
+#if 0
+ normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
+ normalize_v3(imat[1]);
+#endif
if (pd->forcefield == PFIELD_WIND) {
- float force_val;
+ float force_val = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
}
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- force_val = pd->f_strength;
- }
-
unit_m4(tmat);
force_val *= 0.1f;
drawcircball(GL_LINE_LOOP, vec, size, tmat);
@@ -6556,14 +7025,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
}
else if (pd->forcefield == PFIELD_FORCE) {
- float ffall_val;
-
- //if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra);
- //else
- {
- ffall_val = pd->f_power;
- }
+ float ffall_val = pd->f_power;
if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
drawcircball(GL_LINE_LOOP, vec, size, imat);
@@ -6573,20 +7035,9 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
drawcircball(GL_LINE_LOOP, vec, size * 2.0f, imat);
}
else if (pd->forcefield == PFIELD_VORTEX) {
- float /*ffall_val,*/ force_val;
+ float force_val = pd->f_strength;
unit_m4(tmat);
- //if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra);
- //else
- // ffall_val = pd->f_power;
-
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- force_val = pd->f_strength;
- }
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f);
@@ -6604,25 +7055,19 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) {
Curve *cu = ob->data;
if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
- float mindist, guidevec1[4], guidevec2[3];
-
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- mindist = pd->f_strength;
- }
+ float guidevec1[4], guidevec2[3];
+ float mindist = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
}
- /*path end*/
+ /* path end */
setlinestyle(3);
where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL, NULL);
drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
- /*path beginning*/
+ /* path beginning */
setlinestyle(0);
where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL, NULL);
drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
@@ -6693,19 +7138,31 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
setlinestyle(0);
}
-static void draw_box(float vec[8][3])
+static void draw_box(float vec[8][3], bool solid)
{
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
- glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
- glVertex3fv(vec[7]); glVertex3fv(vec[4]);
- glEnd();
+ if (!solid) {
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[4]);
+ glEnd();
- glBegin(GL_LINES);
- glVertex3fv(vec[1]); glVertex3fv(vec[5]);
- glVertex3fv(vec[2]); glVertex3fv(vec[6]);
- glVertex3fv(vec[3]); glVertex3fv(vec[7]);
- glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]);
+ glVertex3fv(vec[2]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]);
+ glEnd();
+ }
+ else {
+ glBegin(GL_QUADS);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[6]); glVertex3fv(vec[5]); glVertex3fv(vec[4]);
+ glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[1]); glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[2]); glVertex3fv(vec[6]); glVertex3fv(vec[7]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]); glVertex3fv(vec[4]); glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]); glVertex3fv(vec[6]); glVertex3fv(vec[2]);
+ glEnd();
+ }
}
static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
@@ -6727,7 +7184,7 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
glPushMatrix();
if (type == OB_BOUND_SPHERE) {
float scale = MAX3(size[0], size[1], size[2]);
- glTranslatef(cent[0], cent[1], cent[2]);
+ glTranslate3fv(cent);
glScalef(scale, scale, scale);
gluSphere(qobj, 1.0, 8, 5);
}
@@ -6776,6 +7233,9 @@ static void draw_bounding_volume(Object *ob, char type)
else if (ob->type == OB_ARMATURE) {
bb = BKE_armature_boundbox_get(ob);
}
+ else if (ob->type == OB_LATTICE) {
+ bb = BKE_lattice_boundbox_get(ob);
+ }
else {
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
bb = &bb_local;
@@ -6799,7 +7259,7 @@ static void draw_bounding_volume(Object *ob, char type)
vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
- draw_box(vec);
+ draw_box(vec, false);
}
else {
draw_bb_quadric(bb, type, true);
@@ -6807,7 +7267,7 @@ static void draw_bounding_volume(Object *ob, char type)
}
else {
if (type == OB_BOUND_BOX)
- draw_box(bb->vec);
+ draw_box(bb->vec, false);
else
draw_bb_quadric(bb, type, false);
}
@@ -6843,7 +7303,7 @@ static void drawtexspace(Object *ob)
setlinestyle(2);
- draw_box(vec);
+ draw_box(vec, false);
setlinestyle(0);
}
@@ -6859,17 +7319,20 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glDepthMask(0);
if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
- DerivedMesh *dm = ob->derivedFinal;
+ DerivedMesh *dm;
bool has_faces = false;
- if (dm)
- DM_update_materials(dm, ob);
#ifdef SEQUENCER_DAG_WORKAROUND
ensure_curve_cache(scene, ob);
#endif
+ dm = ob->derivedFinal;
if (dm) {
- has_faces = dm->getNumTessFaces(dm) > 0;
+ DM_update_materials(dm, ob);
+ }
+
+ if (dm) {
+ has_faces = (dm->getNumPolys(dm) != 0);
}
else {
has_faces = BKE_displist_has_faces(&ob->curve_cache->disp);
@@ -7027,7 +7490,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
else {
if (ob->flag & OB_FROMGROUP) {
if (base->flag & (SELECT + BA_WAS_SEL)) {
- /* uses darker active color for non-active + selected*/
+ /* uses darker active color for non-active + selected */
theme_id = TH_GROUP_ACTIVE;
if (scene->basact != base) {
@@ -7081,8 +7544,11 @@ static void draw_object_matcap_check(View3D *v3d, Object *ob)
v3d->defmaterial->preview = NULL;
}
/* first time users */
- if (v3d->matcap_icon == 0)
+ if (v3d->matcap_icon < ICON_MATCAP_01 ||
+ v3d->matcap_icon > ICON_MATCAP_24)
+ {
v3d->matcap_icon = ICON_MATCAP_01;
+ }
if (v3d->defmaterial->preview == NULL)
v3d->defmaterial->preview = UI_icon_to_preview(v3d->matcap_icon);
@@ -7114,7 +7580,7 @@ static void draw_rigidbody_shape(Object *ob)
vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
- draw_box(vec);
+ draw_box(vec, false);
break;
case RB_SHAPE_SPHERE:
draw_bb_quadric(bb, OB_BOUND_SPHERE, true);
@@ -7151,7 +7617,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
const bool is_picking = (G.f & G_PICKSEL) != 0;
const bool has_particles = (ob->particlesystem.first != NULL);
- bool particle_skip_object = false; /* Draw particles but not their emitter object. */
+ bool skip_object = false; /* Draw particles but not their emitter object. */
+ SmokeModifierData *smd = NULL;
if (ob != scene->obedit) {
if (ob->restrictflag & OB_RESTRICT_VIEW)
@@ -7175,17 +7642,37 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->mode == OB_MODE_OBJECT) {
ParticleSystem *psys;
- particle_skip_object = render_override;
+ skip_object = render_override;
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
/* Once we have found a psys which renders its emitter object, we are done. */
if (psys->part->draw & PART_DRAW_EMITTER) {
- particle_skip_object = false;
+ skip_object = false;
break;
}
}
}
}
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
+ smd = (SmokeModifierData *)md;
+
+ if (smd->domain) {
+ if (!v3d->transp && (dflag & DRAW_PICKING) == 0) {
+ if (!v3d->xray && !(ob->dtx & OB_DRAWXRAY)) {
+ /* object has already been drawn so skip drawing it */
+ ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
+ return;
+ }
+ else if (v3d->xray) {
+ /* object has already been drawn so skip drawing it */
+ ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag);
+ return;
+ }
+ }
+ }
+ }
+
+
/* xray delay? */
if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
/* don't do xray in particle mode, need the z-buffer */
@@ -7257,7 +7744,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) {
if (ob->type == OB_MESH) {
if (dt < OB_SOLID) {
- zbufoff = 1;
+ zbufoff = true;
dt = OB_SOLID;
}
@@ -7284,13 +7771,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (dt >= OB_BOUNDBOX) {
dtx = ob->dtx;
if (ob->mode & OB_MODE_EDIT) {
- // the only 2 extra drawtypes alowed in editmode
+ /* the only 2 extra drawtypes alowed in editmode */
dtx = dtx & (OB_DRAWWIRE | OB_TEXSPACE);
}
-
}
- if (!particle_skip_object) {
+ if (!skip_object) {
/* draw outline for selected objects, mesh does itself */
if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) {
if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) {
@@ -7345,9 +7831,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
-
-//XXX old animsys if (cu->path)
-// curve_draw_speed(scene, ob);
}
break;
case OB_MBALL:
@@ -7512,12 +7995,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* draw code for smoke */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
-
- // draw collision objects
- if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
+ if (smd) {
#if 0
+ /* draw collision objects */
+ if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
SmokeCollSettings *scs = smd->coll;
if (scs->points) {
size_t i;
@@ -7544,30 +8025,30 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
if (col) cpack(col);
-
}
-#endif
}
+#endif
/* only draw domains */
if (smd->domain) {
SmokeDomainSettings *sds = smd->domain;
- float p0[3], p1[3], viewnormal[3];
- BoundBox bb;
+ float viewnormal[3];
glLoadMatrixf(rv3d->viewmat);
glMultMatrixf(ob->obmat);
/* draw adaptive domain bounds */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) {
+ float p0[3], p1[3];
+ BoundBox bb;
/* draw domain max bounds */
VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec);
+ draw_box(bb.vec, false);
- /* draw base resolution bounds */
#if 0
+ /* draw base resolution bounds */
BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
draw_box(bb.vec);
#endif
@@ -7575,16 +8056,16 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* don't show smoke before simulation starts, this could be made an option in the future */
if (smd->domain->fluid && CFRA >= smd->domain->point_cache[0]->startframe) {
+ float p0[3], p1[3];
- // get view vector
- copy_v3_v3(viewnormal, rv3d->viewinv[2]);
+ /* get view vector */
invert_m4_m4(ob->imat, ob->obmat);
- mul_mat3_m4_v3(ob->imat, viewnormal);
+ mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]);
normalize_v3(viewnormal);
/* set dynamic boundaries to draw the volume
- * also scale cube to global space to equalize volume slicing on all axises
- * (its scaled back before drawing) */
+ * also scale cube to global space to equalize volume slicing on all axes
+ * (it's scaled back before drawing) */
p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
@@ -7668,7 +8149,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
view3d_cached_text_draw_add(zero, ob->id.name + 2, strlen(ob->id.name + 2), 10, 0, ob_wire_col);
}
}
- /*if (dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/
if ((dtx & OB_DRAWWIRE) && dt >= OB_SOLID) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
draw_wire_extra(scene, rv3d, ob, ob_wire_col);
@@ -7679,10 +8159,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if ((dt <= OB_SOLID) && !render_override) {
if (((ob->gameflag & OB_DYNAMIC) &&
- !ELEM(ob->collision_boundtype, OB_BOUND_TRIANGLE_MESH, OB_BOUND_CONVEX_HULL)) ||
+ ((ob->gameflag & OB_BOUNDS) == 0)) ||
((ob->gameflag & OB_BOUNDS) &&
- (ob->boundtype == OB_BOUND_SPHERE)))
+ (ob->collision_boundtype == OB_BOUND_SPHERE)))
{
float imat[4][4], vec[3] = {0.0f, 0.0f, 0.0f};
@@ -7723,7 +8203,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (render_override) {
/* don't draw */
}
- else if ((scene->basact) == base)
+ else if (is_obact)
do_draw_center = ACTIVE;
else if (base->flag & SELECT)
do_draw_center = SELECT;
@@ -7784,7 +8264,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
/* special case for object solver and follow track constraints because they don't fill
* constraint targets properly (design limitation -- scene is needed for their target
- * but it can't be accessed from get_targets callvack) */
+ * but it can't be accessed from get_targets callback) */
Object *camob = NULL;
@@ -7809,7 +8289,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
else {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
ListBase targets = {NULL, NULL};
@@ -7975,7 +8455,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
cpack(0);
if (use_faceselect) {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, em->bm, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, NULL, NULL, em->bm, DM_DRAW_SKIP_HIDDEN | DM_DRAW_SELECT_USE_EDITMODE);
if (check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
@@ -7987,7 +8467,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
}
else {
- dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, GPU_enable_material, NULL, em->bm, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, NULL, NULL, em->bm, DM_DRAW_SKIP_SELECT | DM_DRAW_SKIP_HIDDEN | DM_DRAW_SELECT_USE_EDITMODE);
}
}
@@ -8031,7 +8511,7 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
DM_update_materials(dm, ob);
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, DM_DRAW_SKIP_HIDDEN);
bbs_obmode_mesh_verts(ob, dm, 1);
bm_vertoffs = me->totvert + 1;
@@ -8041,16 +8521,16 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
- Mesh *me = (Mesh *)ob->data;
+ Mesh *me = ob->data;
glColor3ub(0, 0, 0);
DM_update_materials(dm, ob);
if ((me->editflag & ME_EDIT_PAINT_FACE_SEL))
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, GPU_enable_material, NULL, me, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN);
else
- dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, GPU_enable_material, NULL, me, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, NULL, NULL, me, 0);
dm->release(dm);
}
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
new file mode 100644
index 00000000000..46320ba6763
--- /dev/null
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -0,0 +1,166 @@
+/*
+ * ***** 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 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/drawsimdebug.c
+ * \ingroup spview3d
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BKE_effect.h"
+
+#include "view3d_intern.h"
+
+#include "BIF_gl.h"
+
+
+static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
+{
+ GHashIterator iter;
+
+ /**** dots ****/
+
+ glPointSize(3.0f);
+ glBegin(GL_POINTS);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_DOT)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ }
+ glEnd();
+ glPointSize(1.0f);
+
+ /**** circles ****/
+
+ {
+ float circle[16][2] = {
+ {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683},
+ {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880},
+ {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684},
+ {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} };
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ float radius = elem->v2[0];
+ float co[3];
+ int i;
+
+ if (elem->type != SIM_DEBUG_ELEM_CIRCLE)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < 16; ++i) {
+ co[0] = radius * circle[i][0];
+ co[1] = radius * circle[i][1];
+ co[2] = 0.0f;
+ mul_mat3_m4_v3(imat, co);
+ add_v3_v3(co, elem->v1);
+
+ glVertex3f(co[0], co[1], co[2]);
+ }
+ glEnd();
+ }
+ }
+
+ /**** lines ****/
+
+ glBegin(GL_LINES);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_LINE)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]);
+ }
+ glEnd();
+
+ /**** vectors ****/
+
+ glPointSize(2.0f);
+ glBegin(GL_POINTS);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_VECTOR)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ }
+ glEnd();
+ glPointSize(1.0f);
+
+ glBegin(GL_LINES);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ float t[3];
+ if (elem->type != SIM_DEBUG_ELEM_VECTOR)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ add_v3_v3v3(t, elem->v1, elem->v2);
+ glVertex3f(t[0], t[1], t[2]);
+ }
+ glEnd();
+}
+
+void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ /*Object *ob = base->object;*/
+ float imat[4][4];
+
+ if (!_sim_debug_data)
+ return;
+
+ invert_m4_m4(imat, rv3d->viewmatob);
+
+// glDepthMask(GL_FALSE);
+// glEnable(GL_BLEND);
+
+ glPushMatrix();
+
+ glLoadMatrixf(rv3d->viewmat);
+ draw_sim_debug_elements(_sim_debug_data, imat);
+
+ glPopMatrix();
+
+// glDepthMask(GL_TRUE);
+// glDisable(GL_BLEND);
+}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 59798f97d93..d6691f431dd 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -27,8 +27,6 @@
* \ingroup spview3d
*/
-
-
#include <string.h>
#include <math.h>
@@ -38,7 +36,6 @@
#include "DNA_screen_types.h"
#include "DNA_smoke_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_property_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -51,10 +48,6 @@
#include "GPU_extensions.h"
-#include "ED_mesh.h"
-
-#include "BLF_api.h"
-
#include "view3d_intern.h" // own include
struct GPUTexture;
@@ -112,7 +105,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
float cor[3] = {1.0f, 1.0f, 1.0f};
int gl_depth = 0, gl_blend = 0;
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
+ const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0;
/* draw slices of smoke is adapted from c++ code authored
* by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
@@ -142,76 +135,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
unsigned char *spec_data;
float *spec_pixels;
GPUTexture *tex_spec;
-
- /* Fragment program to calculate the view3d of smoke */
- /* using 4 textures, density, shadow, flame and flame spectrum */
- const char *shader_basic =
- "!!ARBfp1.0\n"
- "PARAM dx = program.local[0];\n"
- "PARAM darkness = program.local[1];\n"
- "PARAM render = program.local[2];\n"
- "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
- "TEMP temp, shadow, flame, spec, value;\n"
- "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
- "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
- "TEX spec, flame.r, texture[3], 1D;\n"
- /* calculate shading factor from density */
- "MUL value.r, temp.a, darkness.a;\n"
- "MUL value.r, value.r, dx.r;\n"
- "MUL value.r, value.r, f.r;\n"
- "EX2 temp, -value.r;\n"
- /* alpha */
- "SUB temp.a, 1.0, temp.r;\n"
- /* shade colors */
- "MUL temp.r, temp.r, shadow.r;\n"
- "MUL temp.g, temp.g, shadow.r;\n"
- "MUL temp.b, temp.b, shadow.r;\n"
- "MUL temp.r, temp.r, darkness.r;\n"
- "MUL temp.g, temp.g, darkness.g;\n"
- "MUL temp.b, temp.b, darkness.b;\n"
- /* for now this just replace smoke shading if rendering fire */
- "CMP result.color, render.r, temp, spec;\n"
- "END\n";
-
- /* color shader */
- const char *shader_color =
- "!!ARBfp1.0\n"
- "PARAM dx = program.local[0];\n"
- "PARAM darkness = program.local[1];\n"
- "PARAM render = program.local[2];\n"
- "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
- "TEMP temp, shadow, flame, spec, value;\n"
- "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
- "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
- "TEX spec, flame.r, texture[3], 1D;\n"
- /* unpremultiply volume texture */
- "RCP value.r, temp.a;\n"
- "MUL temp.r, temp.r, value.r;\n"
- "MUL temp.g, temp.g, value.r;\n"
- "MUL temp.b, temp.b, value.r;\n"
- /* calculate shading factor from density */
- "MUL value.r, temp.a, darkness.a;\n"
- "MUL value.r, value.r, dx.r;\n"
- "MUL value.r, value.r, f.r;\n"
- "EX2 value.r, -value.r;\n"
- /* alpha */
- "SUB temp.a, 1.0, value.r;\n"
- /* shade colors */
- "MUL temp.r, temp.r, shadow.r;\n"
- "MUL temp.g, temp.g, shadow.r;\n"
- "MUL temp.b, temp.b, shadow.r;\n"
- "MUL temp.r, temp.r, value.r;\n"
- "MUL temp.g, temp.g, value.r;\n"
- "MUL temp.b, temp.b, value.r;\n"
- /* for now this just replace smoke shading if rendering fire */
- "CMP result.color, render.r, temp, spec;\n"
- "END\n";
-
- GLuint prog;
-
-
+ GPUProgram *smoke_program;
+ int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE;
float size[3];
if (!tex) {
@@ -328,8 +253,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
+ glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
/* find cube vertex that is closest to the viewer */
@@ -356,24 +280,17 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
// printf("i: %d\n", i);
// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
- if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) {
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
- glGenProgramsARB(1, &prog);
-
- glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
- /* set shader */
- if (sds->active_fields & SM_ACTIVE_COLORS)
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
- else
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);
+ smoke_program = GPU_shader_get_builtin_program(progtype);
+ if (smoke_program) {
+ GPU_program_bind(smoke_program);
/* cell spacing */
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
+ GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0);
/* custom parameter for smoke style (higher = thicker) */
if (sds->active_fields & SM_ACTIVE_COLORS)
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
+ GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0);
else
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
+ GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
}
else
printf("Your gfx card does not support 3D View smoke drawing.\n");
@@ -453,7 +370,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
+ GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
@@ -473,7 +390,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
+ GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
@@ -506,10 +423,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
free(spec_data);
free(spec_pixels);
- if (GLEW_ARB_fragment_program) {
- glDisable(GL_FRAGMENT_PROGRAM_ARB);
- glDeleteProgramsARB(1, &prog);
- }
+ if (smoke_program)
+ GPU_program_unbind(smoke_program);
MEM_freeN(points);
@@ -521,8 +436,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
if (gl_depth) {
glEnable(GL_DEPTH_TEST);
}
-
- glDepthMask(GL_TRUE);
}
#ifdef SMOKE_DEBUG_VELOCITY
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 8b76ec3a56d..7869522e8fb 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -56,6 +56,7 @@
#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "GPU_compositing.h"
#include "BIF_gl.h"
@@ -73,6 +74,8 @@
# include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
/* ******************** manage regions ********************* */
@@ -265,7 +268,7 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d)
}
#endif
-static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
+void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
@@ -296,7 +299,7 @@ void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa)
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiondata)
- view3d_stop_render_preview(wm, ar);
+ ED_view3d_stop_render_preview(wm, ar);
}
}
else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) {
@@ -343,7 +346,13 @@ static SpaceLink *view3d_new(const bContext *C)
v3d->bundle_size = 0.2f;
v3d->bundle_drawtype = OB_PLAINAXES;
-
+
+ /* stereo */
+ v3d->stereo3d_camera = STEREO_3D_ID;
+ v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
+ v3d->stereo3d_convergence_alpha = 0.15f;
+ v3d->stereo3d_volume_alpha = 0.05f;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for view3d");
@@ -414,10 +423,15 @@ static void view3d_free(SpaceLink *sl)
/* matcap material, its preview rect gets freed via icons */
if (vd->defmaterial) {
if (vd->defmaterial->gpumaterial.first)
- GPU_material_free(vd->defmaterial);
+ GPU_material_free(&vd->defmaterial->gpumaterial);
BKE_previewimg_free(&vd->defmaterial->preview);
MEM_freeN(vd->defmaterial);
}
+
+ if (vd->fx_settings.ssao)
+ MEM_freeN(vd->fx_settings.ssao);
+ if (vd->fx_settings.dof)
+ MEM_freeN(vd->fx_settings.dof);
}
@@ -434,9 +448,7 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
BGpic *bgpic;
/* clear or remove stuff from old */
-
-// XXX BIF_view3d_previewrender_free(v3do);
-
+
if (v3dn->localvd) {
v3dn->localvd = NULL;
v3dn->properties_storage = NULL;
@@ -461,7 +473,11 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
}
v3dn->properties_storage = NULL;
-
+ if (v3dn->fx_settings.dof)
+ v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof);
+ if (v3dn->fx_settings.ssao)
+ v3dn->fx_settings.ssao = MEM_dupallocN(v3do->fx_settings.ssao);
+
return (SpaceLink *)v3dn;
}
@@ -555,18 +571,23 @@ static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
- view3d_stop_render_preview(wm, ar);
+ ED_view3d_stop_render_preview(wm, ar);
if (rv3d->gpuoffscreen) {
GPU_offscreen_free(rv3d->gpuoffscreen);
rv3d->gpuoffscreen = NULL;
}
+
+ if (rv3d->compositor) {
+ GPU_fx_compositor_destroy(rv3d->compositor);
+ rv3d->compositor = NULL;
+ }
}
static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB)
return 1;
}
@@ -576,7 +597,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_GR)
return 1;
}
@@ -586,7 +607,7 @@ static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEve
static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MA)
return 1;
}
@@ -596,12 +617,12 @@ static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_IM)
return 1;
}
else if (drag->type == WM_DRAG_PATH) {
- if (ELEM(drag->icon, 0, ICON_FILE_IMAGE)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */
return 1;
}
return 0;
@@ -643,14 +664,14 @@ static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
drop->opcontext = WM_OP_EXEC_DEFAULT;
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -658,19 +679,23 @@ static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
- if (id)
+ if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
- if (drag->path[0])
+ RNA_struct_property_unset(drop->ptr, "filepath");
+ }
+ else if (drag->path[0]) {
RNA_string_set(drop->ptr, "filepath", drag->path);
+ RNA_struct_property_unset(drop->ptr, "image");
+ }
}
@@ -698,10 +723,6 @@ static void view3d_main_area_free(ARegion *ar)
if (rv3d->localvd) MEM_freeN(rv3d->localvd);
if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
- if (rv3d->ri) {
- // XXX BIF_view3d_previewrender_free(rv3d);
- }
-
if (rv3d->render_engine)
RE_engine_free(rv3d->render_engine);
@@ -715,6 +736,9 @@ static void view3d_main_area_free(ARegion *ar)
if (rv3d->gpuoffscreen) {
GPU_offscreen_free(rv3d->gpuoffscreen);
}
+ if (rv3d->compositor) {
+ GPU_fx_compositor_destroy(rv3d->compositor);
+ }
MEM_freeN(rv3d);
ar->regiondata = NULL;
@@ -735,10 +759,10 @@ static void *view3d_main_area_duplicate(void *poin)
new->depths = NULL;
new->gpuoffscreen = NULL;
- new->ri = NULL;
new->render_engine = NULL;
new->sms = NULL;
new->smooth_timer = NULL;
+ new->compositor = NULL;
return new;
}
@@ -820,6 +844,16 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
case ND_WORLD:
/* handled by space_view3d_listener() for v3d access */
break;
+ case ND_DRAW_RENDER_VIEWPORT:
+ {
+ if (v3d->camera && (scene == wmn->reference)) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ break;
+ }
}
if (wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
@@ -859,25 +893,50 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
}
break;
+ case NC_CAMERA:
+ switch (wmn->data) {
+ case ND_DRAW_RENDER_VIEWPORT:
+ {
+ if (v3d->camera && (v3d->camera->data == wmn->reference)) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ break;
+ }
+ }
+ break;
case NC_GROUP:
/* all group ops for now */
ED_region_tag_redraw(ar);
break;
case NC_BRUSH:
- if (wmn->action == NA_EDITED)
- ED_region_tag_redraw_overlay(ar);
+ switch (wmn->action) {
+ case NA_EDITED:
+ ED_region_tag_redraw_overlay(ar);
+ break;
+ case NA_SELECTED:
+ /* used on brush changes - needed because 3d cursor
+ * has to be drawn if clone brush is selected */
+ ED_region_tag_redraw(ar);
+ break;
+ }
break;
case NC_MATERIAL:
switch (wmn->data) {
case ND_SHADING:
case ND_NODES:
{
+#ifdef WITH_LEGACY_DEPSGRAPH
Object *ob = OBACT;
if ((v3d->drawtype == OB_MATERIAL) ||
(ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
(scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))))
+ BKE_scene_use_new_shading_nodes(scene))) ||
+ !DEG_depsgraph_use_legacy())
+#endif
{
ED_region_tag_redraw(ar);
}
@@ -900,7 +959,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_LIGHTING:
if ((v3d->drawtype == OB_MATERIAL) ||
- (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)))
+ (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@@ -957,8 +1017,9 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
case NC_GPENCIL:
- if (wmn->action == NA_EDITED)
+ if (wmn->data == ND_DATA || ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
ED_region_tag_redraw(ar);
+ }
break;
}
}
@@ -1014,6 +1075,10 @@ static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
if (wmn->data == ND_SPACE_VIEW3D)
ED_region_tag_redraw(ar);
break;
+ case NC_GPENCIL:
+ if (wmn->data & ND_GPENCIL_EDITMODE)
+ ED_region_tag_redraw(ar);
+ break;
}
}
@@ -1030,7 +1095,7 @@ static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void view3d_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, NULL, -1);
+ ED_region_panels(C, ar, NULL, -1, true);
}
static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -1099,7 +1164,8 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
ED_region_tag_redraw(ar);
break;
case NC_BRUSH:
- if (wmn->action == NA_EDITED)
+ /* NA_SELECTED is used on brush changes */
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
case NC_SPACE:
@@ -1111,7 +1177,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
ED_region_tag_redraw(ar);
break;
case NC_GPENCIL:
- if (wmn->data == ND_DATA || wmn->action == NA_EDITED)
+ if ((wmn->data & (ND_DATA | ND_GPENCIL_EDITMODE)) || (wmn->action == NA_EDITED))
ED_region_tag_redraw(ar);
break;
case NC_IMAGE:
@@ -1135,7 +1201,7 @@ static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar)
static void view3d_tools_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, 1, CTX_data_mode_string(C), -1);
+ ED_region_panels(C, ar, CTX_data_mode_string(C), -1, true);
}
static void view3d_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -1175,7 +1241,8 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot
case NC_WORLD:
switch (wmn->data) {
case ND_WORLD_DRAW:
- if (v3d->flag2 & V3D_RENDER_OVERRIDE)
+ case ND_WORLD:
+ if (v3d->flag3 & V3D_SHOW_WORLD)
ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
break;
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index cf589cdd946..d5fd18a77db 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -45,7 +45,7 @@
#include "MEM_guardedalloc.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -60,6 +60,7 @@
#include "BKE_editmesh.h"
#include "BKE_deform.h"
#include "BKE_object.h"
+#include "BKE_object_deform.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -67,8 +68,6 @@
#include "RNA_access.h"
#include "ED_armature.h"
-#include "ED_gpencil.h"
-#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -82,7 +81,7 @@
#define B_REDR 2
#define B_OBJECTPANELMEDIAN 1008
-#define NBR_TRANSFORM_PROPERTIES 7
+#define NBR_TRANSFORM_PROPERTIES 8
/* temporary struct for storing transform properties */
typedef struct {
@@ -124,38 +123,84 @@ static float compute_scale_factor(const float ve_median, const float median)
}
}
+/* Apply helpers.
+ * Note: In case we only have one element, copy directly the value instead of applying the diff or scale factor.
+ * Avoids some glitches when going e.g. from 3 to 0.0001 (see T37327).
+ */
+static void apply_raw_diff(float *val, const int tot, const float ve_median, const float median)
+{
+ *val = (tot == 1) ? ve_median : (*val + median);
+}
+
+static void apply_raw_diff_v3(float val[3], const int tot, const float ve_median[3], const float median[3])
+{
+ if (tot == 1) {
+ copy_v3_v3(val, ve_median);
+ }
+ else {
+ add_v3_v3(val, median);
+ }
+}
+
+static void apply_scale_factor(float *val, const int tot, const float ve_median, const float median, const float sca)
+{
+ if (tot == 1 || ve_median == median) {
+ *val = ve_median;
+ }
+ else {
+ *val *= sca;
+ }
+}
+
+static void apply_scale_factor_clamp(float *val, const int tot, const float ve_median, const float sca)
+{
+ if (tot == 1) {
+ *val = ve_median;
+ CLAMP(*val, 0.0f, 1.0f);
+ }
+ else if (ELEM(sca, 0.0f, 1.0f)) {
+ *val = sca;
+ }
+ else {
+ *val = (sca > 0.0f) ? (*val * sca) : (1.0f + ((1.0f - *val) * sca));
+ CLAMP(*val, 0.0f, 1.0f);
+ }
+}
+
/* is used for both read and write... */
static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim)
{
/* Get rid of those ugly magic numbers, even in a single func they become confusing! */
/* Location, common to all. */
-/* XXX Those two *must* remain contiguous (used as array)! */
-#define LOC_X 0
-#define LOC_Y 1
-#define LOC_Z 2
+/* Next three *must* remain contiguous (used as array)! */
+#define LOC_X 0
+#define LOC_Y 1
+#define LOC_Z 2
/* Meshes... */
-#define M_CREASE 3
-#define M_WEIGHT 4
-/* XXX Those two *must* remain contiguous (used as array)! */
-#define M_SKIN_X 5
-#define M_SKIN_Y 6
+#define M_BV_WEIGHT 3
+/* Next two *must* remain contiguous (used as array)! */
+#define M_SKIN_X 4
+#define M_SKIN_Y 5
+#define M_BE_WEIGHT 6
+#define M_CREASE 7
/* Curves... */
-#define C_BWEIGHT 3
-#define C_WEIGHT 4
-#define C_RADIUS 5
-#define C_TILT 6
+#define C_BWEIGHT 3
+#define C_WEIGHT 4
+#define C_RADIUS 5
+#define C_TILT 6
/*Lattice... */
-#define L_WEIGHT 4
+#define L_WEIGHT 4
uiBlock *block = (layout) ? uiLayoutAbsoluteBlock(layout) : NULL;
TransformProperties *tfp;
float median[NBR_TRANSFORM_PROPERTIES], ve_median[NBR_TRANSFORM_PROPERTIES];
- int tot, totedgedata, totcurvedata, totlattdata, totskinradius, totcurvebweight;
+ int tot, totedgedata, totcurvedata, totlattdata, totcurvebweight;
bool has_meshdata = false;
+ bool has_skinradius = false;
PointerRNA data_ptr;
- fill_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
- tot = totedgedata = totcurvedata = totlattdata = totskinradius = totcurvebweight = 0;
+ copy_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
+ tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
/* make sure we got storage */
if (v3d->properties_storage == NULL)
@@ -170,37 +215,37 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMEdge *eed;
BMIter iter;
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ has_skinradius = (cd_vert_skin_offset != -1);
+
if (bm->totvertsel) {
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
tot++;
add_v3_v3(&median[LOC_X], eve->co);
- /* TODO cd_vert_bweight_offset */
- (void)cd_vert_bweight_offset;
+ if (cd_vert_bweight_offset != -1) {
+ median[M_BV_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
+ }
- if (cd_vert_skin_offset != -1) {
+ if (has_skinradius) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
add_v2_v2(&median[M_SKIN_X], vs->radius); /* Third val not used currently. */
- totskinradius++;
}
}
}
}
- if ((cd_edge_bweight_offset != -1) ||
- (cd_edge_crease_offset != -1))
- {
+ if ((cd_edge_bweight_offset != -1) || (cd_edge_crease_offset != -1)) {
if (bm->totedgesel) {
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
if (cd_edge_bweight_offset != -1) {
- median[M_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
+ median[M_BE_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
}
if (cd_edge_crease_offset != -1) {
@@ -216,7 +261,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
totedgedata = bm->totedgesel;
}
- has_meshdata = (totedgedata || totskinradius);
+ has_meshdata = (tot || totedgedata);
}
else if (ob->type == OB_CURVE || ob->type == OB_SURF) {
Curve *cu = ob->data;
@@ -314,7 +359,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (tot == 0) {
- uiDefBut(block, LABEL, 0, IFACE_("Nothing selected"), 0, 130, 200, 20, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Nothing selected"), 0, 130, 200, 20, NULL, 0, 0, 0, 0, "");
return;
}
@@ -326,22 +371,27 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (has_meshdata) {
if (totedgedata) {
median[M_CREASE] /= (float)totedgedata;
- median[M_WEIGHT] /= (float)totedgedata;
+ median[M_BE_WEIGHT] /= (float)totedgedata;
}
- if (totskinradius) {
- median[M_SKIN_X] /= (float)totskinradius;
- median[M_SKIN_Y] /= (float)totskinradius;
+ if (tot) {
+ median[M_BV_WEIGHT] /= (float)tot;
+ if (has_skinradius) {
+ median[M_SKIN_X] /= (float)tot;
+ median[M_SKIN_Y] /= (float)tot;
+ }
}
}
else if (totcurvedata) {
+ if (totcurvebweight) {
+ median[C_BWEIGHT] /= (float)totcurvebweight;
+ }
median[C_WEIGHT] /= (float)totcurvedata;
median[C_RADIUS] /= (float)totcurvedata;
median[C_TILT] /= (float)totcurvedata;
- if (totcurvebweight)
- median[C_BWEIGHT] /= (float)totcurvebweight;
}
- else if (totlattdata)
+ else if (totlattdata) {
median[L_WEIGHT] /= (float)totlattdata;
+ }
if (block) { /* buttons */
uiBut *but;
@@ -353,7 +403,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
memcpy(tfp->ve_median, median, sizeof(tfp->ve_median));
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
if (tot == 1) {
if (totcurvedata) /* Curve */
c = IFACE_("Control Point:");
@@ -362,98 +412,111 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
else
c = IFACE_("Median:");
- uiDefBut(block, LABEL, 0, c, 0, yi -= buth, 200, buth, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, UI_BTYPE_LABEL, 0, c, 0, yi -= buth, 200, buth, NULL, 0, 0, 0, 0, "");
- uiBlockBeginAlign(block);
+ UI_block_align_begin(block);
/* Should be no need to translate these. */
- but = uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("X:"), 0, yi -= buth, 200, buth,
+ but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("X:"), 0, yi -= buth, 200, buth,
&(tfp->ve_median[LOC_X]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
- uiButSetUnitType(but, PROP_UNIT_LENGTH);
- but = uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("Y:"), 0, yi -= buth, 200, buth,
+ UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
+ but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Y:"), 0, yi -= buth, 200, buth,
&(tfp->ve_median[LOC_Y]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
- uiButSetUnitType(but, PROP_UNIT_LENGTH);
- but = uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("Z:"), 0, yi -= buth, 200, buth,
+ UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
+ but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Z:"), 0, yi -= buth, 200, buth,
&(tfp->ve_median[LOC_Z]), -lim, lim, 10, RNA_TRANSLATION_PREC_DEFAULT, "");
- uiButSetUnitType(but, PROP_UNIT_LENGTH);
+ UI_but_unit_type_set(but, PROP_UNIT_LENGTH);
if (totcurvebweight == tot) {
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("W:"), 0, yi -= buth, 200, buth,
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("W:"), 0, yi -= buth, 200, buth,
&(tfp->ve_median[C_BWEIGHT]), 0.01, 100.0, 1, 3, "");
}
- uiBlockBeginAlign(block);
- uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, IFACE_("Global"),
+ UI_block_align_begin(block);
+ uiDefButBitS(block, UI_BTYPE_TOGGLE, V3D_GLOBAL_STATS, B_REDR, IFACE_("Global"),
0, yi -= buth + but_margin, 100, buth,
&v3d->flag, 0, 0, 0, 0, TIP_("Displays global values"));
- uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, IFACE_("Local"),
+ uiDefButBitS(block, UI_BTYPE_TOGGLE_N, V3D_GLOBAL_STATS, B_REDR, IFACE_("Local"),
100, yi, 100, buth,
&v3d->flag, 0, 0, 0, 0, TIP_("Displays local values"));
- uiBlockEndAlign(block);
+ UI_block_align_end(block);
/* Meshes... */
if (has_meshdata) {
- if (totedgedata) {
- /* customdata layer added on demand */
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
- 0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier"));
+ if (tot) {
+ uiDefBut(block, UI_BTYPE_LABEL, 0, tot == 1 ? IFACE_("Vertex Data:") : IFACE_("Vertices Data:"),
+ 0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
/* customdata layer added on demand */
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
+ tot == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[M_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Weight used by Bevel modifier"));
+ &(tfp->ve_median[M_BV_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Vertex weight used by Bevel modifier"));
}
- if (totskinradius) {
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totskinradius == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
+ if (has_skinradius) {
+ UI_block_align_begin(block);
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
+ tot == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[M_SKIN_X]), 0.0, 100.0, 1, 3, TIP_("X radius used by Skin modifier"));
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totskinradius == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
+ tot == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[M_SKIN_Y]), 0.0, 100.0, 1, 3, TIP_("Y radius used by Skin modifier"));
+ UI_block_align_end(block);
+ }
+ if (totedgedata) {
+ uiDefBut(block, UI_BTYPE_LABEL, 0, totedgedata == 1 ? IFACE_("Edge Data:") : IFACE_("Edges Data:"),
+ 0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
+ /* customdata layer added on demand */
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
+ totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
+ 0, yi -= buth + but_margin, 200, buth,
+ &(tfp->ve_median[M_BE_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Edge weight used by Bevel modifier"));
+ /* customdata layer added on demand */
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
+ totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
+ 0, yi -= buth + but_margin, 200, buth,
+ &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier"));
}
}
/* Curve... */
else if (totcurvedata == 1) {
- uiDefButR(block, NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
+ uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
&data_ptr, "weight_softbody", 0, 0.0, 1.0, 1, 3, NULL);
- uiDefButR(block, NUM, 0, IFACE_("Radius:"), 0, yi -= buth + but_margin, 200, buth,
+ uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Radius:"), 0, yi -= buth + but_margin, 200, buth,
&data_ptr, "radius", 0, 0.0, 100.0, 1, 3, NULL);
- uiDefButR(block, NUM, 0, IFACE_("Tilt:"), 0, yi -= buth + but_margin, 200, buth,
+ uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Tilt:"), 0, yi -= buth + but_margin, 200, buth,
&data_ptr, "tilt", 0, -tilt_limit, tilt_limit, 1, 3, NULL);
}
else if (totcurvedata > 1) {
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal"));
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"),
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points"));
- but = uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Tilt:"),
+ but = uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Tilt:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[C_TILT]), -tilt_limit, tilt_limit, 1, 3,
TIP_("Tilt of curve control points"));
- uiButSetUnitType(but, PROP_UNIT_ROTATION);
+ UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
}
/* Lattice... */
else if (totlattdata == 1) {
- uiDefButR(block, NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
+ uiDefButR(block, UI_BTYPE_NUM, 0, IFACE_("Weight:"), 0, yi -= buth + but_margin, 200, buth,
&data_ptr, "weight_softbody", 0, 0.0, 1.0, 1, 3, NULL);
}
else if (totlattdata > 1) {
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
+ uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal"));
}
- uiBlockEndAlign(block);
-
+ UI_block_align_end(block);
}
else { /* apply */
int i;
+ bool apply_vcos;
memcpy(ve_median, tfp->ve_median, sizeof(tfp->ve_median));
@@ -466,155 +529,130 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
while (i--)
median[i] = ve_median[i] - median[i];
- if (ob->type == OB_MESH) {
+ /* Note with a single element selected, we always do. */
+ apply_vcos = (tot == 1) || (len_squared_v3(&median[LOC_X]) != 0.0f);
+
+ if ((ob->type == OB_MESH) &&
+ (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y] ||
+ median[M_BE_WEIGHT] || median[M_CREASE]))
+ {
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
BMesh *bm = em->bm;
BMIter iter;
+ BMVert *eve;
+ BMEdge *eed;
- if (tot == 1 || len_v3(&median[LOC_X]) != 0.0f) {
- BMVert *eve;
+ int cd_vert_bweight_offset = -1;
+ int cd_vert_skin_offset = -1;
+ int cd_edge_bweight_offset = -1;
+ int cd_edge_crease_offset = -1;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- if (tot == 1) {
- /* In case we only have one element selected, copy directly the value instead of applying
- * the diff. Avoids some glitches when going e.g. from 3 to 0.0001 (see [#37327]).
- */
- copy_v3_v3(eve->co, &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(eve->co, &median[LOC_X]);
- }
- }
- }
+ float scale_bv_weight = 1.0f;
+ float scale_skin_x = 1.0f;
+ float scale_skin_y = 1.0f;
+ float scale_be_weight = 1.0f;
+ float scale_crease = 1.0f;
- EDBM_mesh_normals_update(em);
- }
+ /* Vertices */
- if (median[M_CREASE] != 0.0f) {
- const int cd_edge_crease_offset = (BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE),
- CustomData_get_offset(&bm->edata, CD_CREASE));
- const float sca = compute_scale_factor(ve_median[M_CREASE], median[M_CREASE]);
- BMEdge *eed;
+ if (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y]) {
+ if (median[M_BV_WEIGHT]) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
+ cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ BLI_assert(cd_vert_bweight_offset != -1);
- if (ELEM(sca, 0.0f, 1.0f)) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- BM_ELEM_CD_SET_FLOAT(eed, cd_edge_crease_offset, sca);
- }
- }
- }
- else if (sca > 0.0f) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- *crease *= sca;
- CLAMP(*crease, 0.0f, 1.0f);
- }
- }
+ scale_bv_weight = compute_scale_factor(ve_median[M_BV_WEIGHT], median[M_BV_WEIGHT]);
}
- else {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- *crease = 1.0f + ((1.0f - *crease) * sca);
- CLAMP(*crease, 0.0f, 1.0f);
- }
- }
- }
- }
-
- if (median[M_WEIGHT] != 0.0f) {
- const int cd_edge_bweight_offset = (BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT),
- CustomData_get_offset(&bm->edata, CD_BWEIGHT));
- const float sca = compute_scale_factor(ve_median[M_WEIGHT], median[M_WEIGHT]);
- BMEdge *eed;
- BLI_assert(cd_edge_bweight_offset != -1);
+ if (median[M_SKIN_X]) {
+ cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+ BLI_assert(cd_vert_skin_offset != -1);
- if (ELEM(sca, 0.0f, 1.0f)) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
- *bweight = sca;
- }
+ if (ve_median[M_SKIN_X] != median[M_SKIN_X]) {
+ scale_skin_x = ve_median[M_SKIN_X] / (ve_median[M_SKIN_X] - median[M_SKIN_X]);
}
}
- else if (sca > 0.0f) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
- *bweight *= sca;
- CLAMP(*bweight, 0.0f, 1.0f);
- }
+ if (median[M_SKIN_Y]) {
+ if (cd_vert_skin_offset == -1) {
+ cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+ BLI_assert(cd_vert_skin_offset != -1);
}
- }
- else {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
- *bweight = 1.0f + ((1.0f - *bweight) * sca);
- CLAMP(*bweight, 0.0f, 1.0f);
- }
+
+ if (ve_median[M_SKIN_Y] != median[M_SKIN_Y]) {
+ scale_skin_y = ve_median[M_SKIN_Y] / (ve_median[M_SKIN_Y] - median[M_SKIN_Y]);
}
}
- }
- if (median[M_SKIN_X] != 0.0f) {
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
- /* That one is not clamped to [0.0, 1.0]. */
- float sca = ve_median[M_SKIN_X];
- BMVert *eve;
-
- BLI_assert(cd_vert_skin_offset != -1);
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (apply_vcos) {
+ apply_raw_diff_v3(eve->co, tot, &ve_median[LOC_X], &median[LOC_X]);
+ }
- if (ve_median[M_SKIN_X] - median[M_SKIN_X] == 0.0f) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[0] = sca;
+ if (cd_vert_bweight_offset != -1) {
+ float *bweight = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset);
+ apply_scale_factor_clamp(bweight, tot, ve_median[M_BV_WEIGHT], scale_bv_weight);
}
- }
- }
- else {
- sca /= (ve_median[M_SKIN_X] - median[M_SKIN_X]);
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+
+ if (cd_vert_skin_offset != -1) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[0] *= sca;
+
+ /* That one is not clamped to [0.0, 1.0]. */
+ if (median[M_SKIN_X] != 0.0f) {
+ apply_scale_factor(&vs->radius[0], tot, ve_median[M_SKIN_X], median[M_SKIN_X],
+ scale_skin_x);
+ }
+ if (median[M_SKIN_Y] != 0.0f) {
+ apply_scale_factor(&vs->radius[1], tot, ve_median[M_SKIN_Y], median[M_SKIN_Y],
+ scale_skin_y);
+ }
}
}
}
}
- if (median[M_SKIN_Y] != 0.0f) {
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
- /* That one is not clamped to [0.0, 1.0]. */
- float sca = ve_median[M_SKIN_Y];
- BMVert *eve;
- BLI_assert(cd_vert_skin_offset != -1);
+ if (apply_vcos) {
+ EDBM_mesh_normals_update(em);
+ }
- if (ve_median[M_SKIN_Y] - median[M_SKIN_Y] == 0.0f) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[1] = sca;
- }
- }
+ /* Edges */
+
+ if (median[M_BE_WEIGHT] || median[M_CREASE]) {
+ if (median[M_BE_WEIGHT]) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+ cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+ BLI_assert(cd_edge_bweight_offset != -1);
+
+ scale_be_weight = compute_scale_factor(ve_median[M_BE_WEIGHT], median[M_BE_WEIGHT]);
}
- else {
- sca /= (ve_median[M_SKIN_Y] - median[M_SKIN_Y]);
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[1] *= sca;
+
+ if (median[M_CREASE]) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
+ cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ BLI_assert(cd_edge_crease_offset != -1);
+
+ scale_crease = compute_scale_factor(ve_median[M_CREASE], median[M_CREASE]);
+ }
+
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ if (median[M_BE_WEIGHT] != 0.0f) {
+ float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
+ apply_scale_factor_clamp(bweight, tot, ve_median[M_BE_WEIGHT], scale_be_weight);
+ }
+
+ if (median[M_CREASE] != 0.0f) {
+ float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
+ apply_scale_factor_clamp(crease, tot, ve_median[M_CREASE], scale_crease);
}
}
}
}
}
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF) &&
+ (apply_vcos || median[C_BWEIGHT] || median[C_WEIGHT] || median[C_RADIUS] || median[C_TILT]))
+ {
Curve *cu = ob->data;
Nurb *nu;
BPoint *bp;
@@ -628,44 +666,31 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (nu->type == CU_BEZIER) {
for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
if (bezt->f2 & SELECT) {
- /* Here we always have to use the diff... :/
- * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see [#37327]),
- * unless we use doubles.
- */
- add_v3_v3(bezt->vec[0], &median[LOC_X]);
- add_v3_v3(bezt->vec[1], &median[LOC_X]);
- add_v3_v3(bezt->vec[2], &median[LOC_X]);
-
- if (median[C_WEIGHT] != 0.0f) {
- if (ELEM(scale_w, 0.0f, 1.0f)) {
- bezt->weight = scale_w;
- }
- else {
- bezt->weight = scale_w > 0.0f ? bezt->weight * scale_w :
- 1.0f + ((1.0f - bezt->weight) * scale_w);
- CLAMP(bezt->weight, 0.0f, 1.0f);
- }
+ if (apply_vcos) {
+ /* Here we always have to use the diff... :/
+ * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see T37327),
+ * unless we use doubles.
+ */
+ add_v3_v3(bezt->vec[0], &median[LOC_X]);
+ add_v3_v3(bezt->vec[1], &median[LOC_X]);
+ add_v3_v3(bezt->vec[2], &median[LOC_X]);
+ }
+ if (median[C_WEIGHT]) {
+ apply_scale_factor_clamp(&bezt->weight, tot, ve_median[C_WEIGHT], scale_w);
+ }
+ if (median[C_RADIUS]) {
+ apply_raw_diff(&bezt->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
+ }
+ if (median[C_TILT]) {
+ apply_raw_diff(&bezt->alfa, tot, ve_median[C_TILT], median[C_TILT]);
}
-
- bezt->radius += median[C_RADIUS];
- bezt->alfa += median[C_TILT];
}
- else {
+ else if (apply_vcos) { /* Handles can only have their coordinates changed here. */
if (bezt->f1 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bezt->vec[0], &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(bezt->vec[0], &median[LOC_X]);
- }
+ apply_raw_diff_v3(bezt->vec[0], tot, &ve_median[LOC_X], &median[LOC_X]);
}
if (bezt->f3 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bezt->vec[2], &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(bezt->vec[2], &median[LOC_X]);
- }
+ apply_raw_diff_v3(bezt->vec[2], tot, &ve_median[LOC_X], &median[LOC_X]);
}
}
}
@@ -673,28 +698,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
else {
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a--; bp++) {
if (bp->f1 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bp->vec, &ve_median[LOC_X]);
- bp->vec[3] = ve_median[C_BWEIGHT];
- bp->radius = ve_median[C_RADIUS];
- bp->alfa = ve_median[C_TILT];
+ if (apply_vcos) {
+ apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
}
- else {
- add_v3_v3(bp->vec, &median[LOC_X]);
- bp->vec[3] += median[C_BWEIGHT];
- bp->radius += median[C_RADIUS];
- bp->alfa += median[C_TILT];
+ if (median[C_BWEIGHT]) {
+ apply_raw_diff(&bp->vec[3], tot, ve_median[C_BWEIGHT], median[C_BWEIGHT]);
}
-
- if (median[C_WEIGHT] != 0.0f) {
- if (ELEM(scale_w, 0.0f, 1.0f)) {
- bp->weight = scale_w;
- }
- else {
- bp->weight = scale_w > 0.0f ? bp->weight * scale_w :
- 1.0f + ((1.0f - bp->weight) * scale_w);
- CLAMP(bp->weight, 0.0f, 1.0f);
- }
+ if (median[C_WEIGHT]) {
+ apply_scale_factor_clamp(&bp->weight, tot, ve_median[C_WEIGHT], scale_w);
+ }
+ if (median[C_RADIUS]) {
+ apply_raw_diff(&bp->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
+ }
+ if (median[C_TILT]) {
+ apply_raw_diff(&bp->alfa, tot, ve_median[C_TILT], median[C_TILT]);
}
}
}
@@ -705,7 +722,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
nu = nu->next;
}
}
- else if (ob->type == OB_LATTICE) {
+ else if ((ob->type == OB_LATTICE) && (apply_vcos || median[L_WEIGHT])) {
Lattice *lt = ob->data;
BPoint *bp;
int a;
@@ -715,22 +732,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
bp = lt->editlatt->latt->def;
while (a--) {
if (bp->f1 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bp->vec, &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(bp->vec, &median[LOC_X]);
+ if (apply_vcos) {
+ apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
}
-
- if (median[L_WEIGHT] != 0.0f) {
- if (ELEM(scale_w, 0.0f, 1.0f)) {
- bp->weight = scale_w;
- }
- else {
- bp->weight = scale_w > 0.0f ? bp->weight * scale_w :
- 1.0f + ((1.0f - bp->weight) * scale_w);
- CLAMP(bp->weight, 0.0f, 1.0f);
- }
+ if (median[L_WEIGHT]) {
+ apply_scale_factor_clamp(&bp->weight, tot, ve_median[L_WEIGHT], scale_w);
}
}
bp++;
@@ -746,10 +752,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
#undef LOC_Y
#undef LOC_Z
/* Meshes (and lattice)... */
-#undef M_CREASE
-#undef M_WEIGHT
+#undef M_BV_WEIGHT
#undef M_SKIN_X
#undef M_SKIN_Y
+#undef M_BE_WEIGHT
+#undef M_CREASE
/* Curves... */
#undef C_BWEIGHT
#undef C_WEIGHT
@@ -826,7 +833,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
int yco = 0;
int lock_count = 0;
- uiBlockSetHandleFunc(block, do_view3d_vgroup_buttons, NULL);
+ UI_block_func_handle_set(block, do_view3d_vgroup_buttons, NULL);
bcol = uiLayoutColumn(pa->layout, true);
row = uiLayoutRow(bcol, true); /* The filter button row */
@@ -836,9 +843,9 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
col = uiLayoutColumn(bcol, true);
- vgroup_validmap = ED_vgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
+ vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
for (i = 0, dg = ob->defbase.first; dg; i++, dg = dg->next) {
- bool locked = dg->flag & DG_LOCK_WEIGHT;
+ bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0;
if (vgroup_validmap[i]) {
MDeformWeight *dw = defvert_find_index(dv, i);
if (dw) {
@@ -850,13 +857,13 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
/* The Weight Group Name */
ot = ot_weight_set_active;
- but = uiDefButO_ptr(block, BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
+ but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
- but_ptr = uiButGetOperatorPtrRNA(but);
+ but_ptr = UI_but_operator_ptr_get(but);
RNA_int_set(but_ptr, "weight_group", i);
- uiButSetDrawFlag(but, UI_BUT_TEXT_RIGHT);
+ UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
if (ob->actdef != i + 1) {
- uiButSetFlag(but, UI_BUT_INACTIVE);
+ UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
xco += x;
@@ -865,10 +872,10 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
/* The weight group value */
/* To be reworked still */
- but = uiDefButF(block, NUM, B_VGRP_PNL_EDIT_SINGLE + i, "",
+ but = uiDefButF(block, UI_BTYPE_NUM, B_VGRP_PNL_EDIT_SINGLE + i, "",
xco, yco, (x = UI_UNIT_X * 4), UI_UNIT_Y,
&dw->weight, 0.0, 1.0, 1, 3, "");
- uiButSetDrawFlag(but, UI_BUT_TEXT_LEFT);
+ UI_but_drawflag_enable(but, UI_BUT_TEXT_LEFT);
if (locked) {
lock_count++;
}
@@ -903,19 +910,19 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
row = uiLayoutRow(col, true);
ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", 1);
- but = uiDefButO_ptr(block, BUT, ot, WM_OP_EXEC_DEFAULT, "Normalize",
+ but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, "Normalize",
0, yco, UI_UNIT_X * 5, UI_UNIT_Y,
TIP_("Normalize weights of active vertex (if affected groups are unlocked)"));
if (lock_count) {
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
ot = WM_operatortype_find("OBJECT_OT_vertex_weight_copy", 1);
- but = uiDefButO_ptr(block, BUT, ot, WM_OP_EXEC_DEFAULT, "Copy",
+ but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, "Copy",
UI_UNIT_X * 5, yco, UI_UNIT_X * 5, UI_UNIT_Y,
TIP_("Copy active vertex to other selected vertices (if affected groups are unlocked)"));
if (lock_count) {
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
@@ -985,9 +992,8 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
if (ptr->type == &RNA_Object) {
Object *ob = ptr->data;
- /* dimensions and material support just happen to be the same checks
- * later we may want to add dimensions for lattice, armature etc too */
- if (OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
+ /* dimensions and editmode just happen to be the same checks */
+ if (OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
uiItemR(layout, ptr, "dimensions", 0, NULL, ICON_NONE);
}
}
@@ -1137,7 +1143,7 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
uiLayout *col;
block = uiLayoutGetBlock(pa->layout);
- uiBlockSetHandleFunc(block, do_view3d_region_buttons, NULL);
+ UI_block_func_handle_set(block, do_view3d_region_buttons, NULL);
col = uiLayoutColumn(pa->layout, false);
@@ -1172,23 +1178,15 @@ void view3d_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object");
strcpy(pt->idname, "VIEW3D_PT_transform");
strcpy(pt->label, N_("Transform")); /* XXX C panels not available through RNA (bpy.types)! */
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_transform;
pt->poll = view3d_panel_transform_poll;
BLI_addtail(&art->paneltypes, pt);
- pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel gpencil");
- strcpy(pt->idname, "VIEW3D_PT_gpencil");
- strcpy(pt->label, N_("Grease Pencil")); /* XXX C panels are not available through RNA (bpy.types)! */
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = ED_gpencil_panel_standard_header;
- pt->draw = ED_gpencil_panel_standard;
- BLI_addtail(&art->paneltypes, pt);
-
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
strcpy(pt->idname, "VIEW3D_PT_vgroup");
strcpy(pt->label, N_("Vertex Weights")); /* XXX C panels are not available through RNA (bpy.types)! */
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_vgroup;
pt->poll = view3d_panel_vgroup_poll;
BLI_addtail(&art->paneltypes, pt);
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index ee0f3da18b4..f717f1c0a43 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -51,14 +51,12 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_object.h"
#include "BKE_depsgraph.h" /* for object updating */
-#include "ED_keyframing.h"
#include "ED_screen.h"
#include "view3d_intern.h" /* own include */
@@ -135,7 +133,7 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
/**
- * Creates a #View3DControl handle and sets up
+ * Creates a #View3DCameraControl handle and sets up
* the view for first-person style navigation.
*/
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
@@ -266,6 +264,8 @@ void ED_view3d_cameracontrol_update(
BKE_object_apply_mat4(v3d->camera, view_mat, true, true);
+ DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+
copy_v3_v3(v3d->camera->size, size_back);
id_key = &v3d->camera->id;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 2629d9f33d0..d9ad481ab33 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -42,6 +42,7 @@
#include "DNA_lamp_types.h"
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
+#include "DNA_brush_types.h"
#include "MEM_guardedalloc.h"
@@ -49,11 +50,13 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_endian_switch.h"
+#include "BLI_threads.h"
#include "BKE_anim.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_main.h"
@@ -77,7 +80,7 @@
#include "WM_api.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "ED_armature.h"
#include "ED_keyframing.h"
@@ -94,9 +97,15 @@
#include "GPU_draw.h"
#include "GPU_material.h"
#include "GPU_extensions.h"
+#include "GPU_compositing.h"
#include "view3d_intern.h" /* own include */
+/* prototypes */
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
+static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname);
+
/* handy utility for drawing shapes in the viewport for arbitrary code.
* could add lines and points too */
// #define DEBUG_DRAW
@@ -162,15 +171,15 @@ static void view3d_draw_clipping(RegionView3D *rv3d)
/* fill in zero alpha for rendering & re-projection [#31530] */
unsigned char col[4];
- UI_GetThemeColorShade3ubv(TH_BACK, -8, col);
- col[3] = 0;
+ UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col);
glColor4ubv(col);
+ glEnable(GL_BLEND);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, bb->vec);
glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index);
glDisableClientState(GL_VERTEX_ARRAY);
-
+ glDisable(GL_BLEND);
}
}
@@ -205,7 +214,7 @@ void ED_view3d_clipping_enable(void)
}
}
-static bool view3d_clipping_test(const float co[3], float clip[6][4])
+static bool view3d_clipping_test(const float co[3], const float clip[6][4])
{
if (plane_point_side_v3(clip[0], co) > 0.0f)
if (plane_point_side_v3(clip[1], co) > 0.0f)
@@ -218,7 +227,7 @@ static bool view3d_clipping_test(const float co[3], float clip[6][4])
/* for 'local' ED_view3d_clipping_local must run first
* then all comparisons can be done in localspace */
-bool ED_view3d_clipping_test(RegionView3D *rv3d, const float co[3], const bool is_local)
+bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
{
return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
}
@@ -294,7 +303,7 @@ static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **
dx = fabs(x - (wx) * fx / fw);
if (dx == 0) dx = fabs(y - (wy) * fy / fw);
- glDepthMask(0); /* disable write in zbuffer */
+ glDepthMask(GL_FALSE); /* disable write in zbuffer */
/* check zoom out */
UI_ThemeColor(TH_GRID);
@@ -433,7 +442,7 @@ static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **
fdrawline(x, 0.0, x, (float)ar->winy);
- glDepthMask(1); /* enable write in zbuffer */
+ glDepthMask(GL_TRUE); /* enable write in zbuffer */
}
#undef GRID_MIN_PX
@@ -463,7 +472,7 @@ float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
}
-static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
+static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
{
float grid, grid_scale;
unsigned char col_grid[3];
@@ -475,8 +484,8 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
grid = gridlines * grid_scale;
- if (v3d->zbuf && scene->obedit)
- glDepthMask(0); /* for zbuffer-select */
+ if (!write_depth)
+ glDepthMask(GL_FALSE);
UI_GetThemeColor3ubv(TH_GRID, col_grid);
@@ -545,7 +554,7 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
}
}
- if (v3d->zbuf && scene->obedit) glDepthMask(1);
+ glDepthMask(GL_TRUE);
}
@@ -586,20 +595,26 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
float ydisp = 0.0; /* vertical displacement to allow obj info text */
int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
float vec[3];
- char axis_text[2] = "x";
float dx, dy;
- int i;
-
+
+ int axis_order[3] = {0, 1, 2};
+ int axis_i;
+
startx += rect->xmin;
starty += rect->ymin;
-
+
+ axis_sort_v3(rv3d->viewinv[2], axis_order);
+
/* thickness of lines is proportional to k */
glLineWidth(2);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- for (i = 0; i < 3; i++) {
+ for (axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
+ const char axis_text[2] = {'x' + i, '\0'};
+
zero_v3(vec);
vec[i] = 1.0f;
mul_qt_v3(rv3d->viewquat, vec);
@@ -616,8 +631,6 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1);
}
- axis_text[0]++;
-
/* BLF_draw_default disables blending */
glEnable(GL_BLEND);
}
@@ -645,7 +658,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glEnable(GL_POINT_SMOOTH);
glDepthMask(0); /* don't overwrite zbuf */
- if (rv3d->rot_angle != 0.f) {
+ if (rv3d->rot_angle != 0.0f) {
/* -- draw rotation axis -- */
float scaled_axis[3];
const float scale = rv3d->dist;
@@ -653,19 +666,21 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glBegin(GL_LINE_STRIP);
- color[3] = 0.f; /* more transparent toward the ends */
+ color[3] = 0.0f; /* more transparent toward the ends */
glColor4fv(color);
add_v3_v3v3(end, o, scaled_axis);
glVertex3fv(end);
- // color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
- // ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2
+#if 0
+ color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
+ /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
+#endif
color[3] = 0.5f; /* more opaque toward the center */
glColor4fv(color);
glVertex3fv(o);
- color[3] = 0.f;
+ color[3] = 0.0f;
glColor4fv(color);
sub_v3_v3v3(end, o, scaled_axis);
glVertex3fv(end);
@@ -676,14 +691,14 @@ static void draw_rotation_guide(RegionView3D *rv3d)
#define ROT_AXIS_DETAIL 13
const float s = 0.05f * scale;
- const float step = 2.f * (float)(M_PI / ROT_AXIS_DETAIL);
+ const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
float angle;
int i;
float q[4]; /* rotate ring so it's perpendicular to axis */
const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
if (!upright) {
- const float up[3] = {0.f, 0.f, 1.f};
+ const float up[3] = {0.0f, 0.0f, 1.0f};
float vis_angle, vis_axis[3];
cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
@@ -694,7 +709,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
color[3] = 0.25f; /* somewhat faint */
glColor4fv(color);
glBegin(GL_LINE_LOOP);
- for (i = 0, angle = 0.f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
+ for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
if (!upright) {
@@ -720,12 +735,12 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glVertex3fv(o);
glEnd();
- /* find screen coordinates for rotation center, then draw pretty icon */
#if 0
+ /* find screen coordinates for rotation center, then draw pretty icon */
mul_m4_v3(rv3d->persinv, rot_center);
UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
-#endif
/* ^^ just playing around, does not work */
+#endif
glDisable(GL_BLEND);
glDisable(GL_POINT_SMOOTH);
@@ -787,7 +802,16 @@ static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
Camera *cam;
cam = v3d->camera->data;
- name = (cam->type != CAM_ORTHO) ? IFACE_("Camera Persp") : IFACE_("Camera Ortho");
+ if (cam->type == CAM_PERSP) {
+ name = IFACE_("Camera Persp");
+ }
+ else if (cam->type == CAM_ORTHO) {
+ name = IFACE_("Camera Ortho");
+ }
+ else {
+ BLI_assert(cam->type == CAM_PANO);
+ name = IFACE_("Camera Pano");
+ }
}
else {
name = IFACE_("Object as Camera");
@@ -935,8 +959,9 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
}
-static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *r_viewborder, const bool no_shift, const bool no_zoom)
+static void view3d_camera_border(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ rctf *r_viewborder, const bool no_shift, const bool no_zoom)
{
CameraParams params;
rctf rect_view, rect_camera;
@@ -969,7 +994,9 @@ static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionV
r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
}
-void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float r_size[2])
+void ED_view3d_calc_camera_border_size(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ float r_size[2])
{
rctf viewborder;
@@ -978,8 +1005,9 @@ void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, R
r_size[1] = BLI_rctf_size_y(&viewborder);
}
-void ED_view3d_calc_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *r_viewborder, const bool no_shift)
+void ED_view3d_calc_camera_border(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ rctf *r_viewborder, const bool no_shift)
{
view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
}
@@ -1057,14 +1085,13 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons
static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
{
- float hmargin, vmargin;
float x1, x2, y1, y2;
float x1i, x2i, y1i, y2i;
rctf viewborder;
Camera *ca = NULL;
RegionView3D *rv3d = ar->regiondata;
-
+
if (v3d->camera == NULL)
return;
if (v3d->camera->type == OB_CAMERA)
@@ -1091,6 +1118,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* passepartout, specified in camera edit buttons */
if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
+ const float winx = (ar->winx + 1);
+ const float winy = (ar->winy + 1);
+
if (ca->passepartalpha == 1.0f) {
glColor3f(0, 0, 0);
}
@@ -1100,11 +1130,11 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
glColor4f(0, 0, 0, ca->passepartalpha);
}
if (x1i > 0.0f)
- glRectf(0.0, (float)ar->winy, x1i, 0.0);
- if (x2i < (float)ar->winx)
- glRectf(x2i, (float)ar->winy, (float)ar->winx, 0.0);
- if (y2i < (float)ar->winy)
- glRectf(x1i, (float)ar->winy, x2i, y2i);
+ glRectf(0.0, winy, x1i, 0.0);
+ if (x2i < winx)
+ glRectf(x2i, winy, winx, 0.0);
+ if (y2i < winy)
+ glRectf(x1i, winy, x2i, y2i);
if (y2i > 0.0f)
glRectf(x1i, y1i, x2i, 0.0);
@@ -1143,10 +1173,10 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
if (scene->r.mode & R_BORDER) {
float x3, y3, x4, y4;
- x3 = x1 + scene->r.border.xmin * (x2 - x1);
- y3 = y1 + scene->r.border.ymin * (y2 - y1);
- x4 = x1 + scene->r.border.xmax * (x2 - x1);
- y4 = y1 + scene->r.border.ymax * (y2 - y1);
+ x3 = x1i + 1 + roundf(scene->r.border.xmin * (x2 - x1));
+ y3 = y1i + 1 + roundf(scene->r.border.ymin * (y2 - y1));
+ x4 = x1i + 1 + roundf(scene->r.border.xmax * (x2 - x1));
+ y4 = y1i + 1 + roundf(scene->r.border.ymax * (y2 - y1));
cpack(0x4040FF);
glRecti(x3, y3, x4, y4);
@@ -1213,17 +1243,20 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
drawviewborder_triangle(x1, x2, y1, y2, 1, 'B');
}
- if (ca->flag & CAM_SHOWTITLESAFE) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
-
- hmargin = 0.1f * (x2 - x1);
- vmargin = 0.05f * (y2 - y1);
- uiDrawBox(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f);
+ if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title,
+ scene->safe_areas.action);
- hmargin = 0.035f * (x2 - x1);
- vmargin = 0.035f * (y2 - y1);
- uiDrawBox(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f);
+ if (ca->flag & CAM_SHOW_SAFE_CENTER) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title_center,
+ scene->safe_areas.action_center);
+ }
}
+
if (ca->flag & CAM_SHOWSENSOR) {
/* determine sensor fit, and get sensor x/y, for auto fit we
* assume and square sensor and only use sensor_x */
@@ -1257,7 +1290,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* draw */
UI_ThemeColorShade(TH_VIEW_OVERLAY, 100);
- uiDrawBox(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f);
+ UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f);
}
}
@@ -1267,8 +1300,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* camera name - draw in highlighted text color */
if (ca && (ca->flag & CAM_SHOWNAME)) {
UI_ThemeColor(TH_TEXT_HI);
- BLF_draw_default(x1i, y1i - 15, 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
- UI_ThemeColor(TH_WIRE);
+ BLF_draw_default(
+ x1i, y1i - (0.7f * U.widget_unit), 0.0f,
+ v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
}
}
@@ -1294,12 +1328,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
/* do nothing */
}
else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
- v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
+ V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
- else if (scene->obedit && v3d->drawtype > OB_WIRE &&
- (v3d->flag & V3D_ZBUF_SELECT))
+ else if (scene->obedit &&
+ V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
@@ -1355,11 +1389,11 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
}
if (rv3d->gpuoffscreen)
- GPU_offscreen_bind(rv3d->gpuoffscreen);
+ GPU_offscreen_bind(rv3d->gpuoffscreen, true);
else
glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
- glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
if (v3d->zbuf) {
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -1378,7 +1412,7 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
draw_object_backbufsel(scene, v3d, rv3d, base->object);
if (rv3d->gpuoffscreen)
- GPU_offscreen_unbind(rv3d->gpuoffscreen);
+ GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
else
ar->swap = 0; /* mark invalid backbuf for wm draw */
@@ -1404,10 +1438,10 @@ void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int form
RegionView3D *rv3d = ar->regiondata;
if (rv3d->gpuoffscreen) {
- GPU_offscreen_bind(rv3d->gpuoffscreen);
+ GPU_offscreen_bind(rv3d->gpuoffscreen, true);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(x, y, w, h, format, type, data);
- GPU_offscreen_unbind(rv3d->gpuoffscreen);
+ GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
}
else {
glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
@@ -1421,14 +1455,23 @@ static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h,
glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
}
-void view3d_validate_backbuf(ViewContext *vc)
+void ED_view3d_backbuf_validate(ViewContext *vc)
{
if (vc->v3d->flag & V3D_INVALID_BACKBUF)
backdrawview3d(vc->scene, vc->ar, vc->v3d);
}
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
+int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
+{
+ return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
+}
+
/* samples a single pixel (copied from vpaint) */
-unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
+unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
{
unsigned int col;
@@ -1436,7 +1479,7 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
return 0;
}
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
glReadBuffer(GL_BACK);
@@ -1449,81 +1492,79 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
}
/* reads full rect, converts indices */
-ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
+ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax)
{
- unsigned int *dr, *rd;
- struct ImBuf *ibuf, *ibuf1;
- int a;
- short xminc, yminc, xmaxc, ymaxc, xs, ys;
-
+ struct ImBuf *ibuf_clip;
/* clip */
- if (xmin < 0) xminc = 0; else xminc = xmin;
- if (xmax >= vc->ar->winx) xmaxc = vc->ar->winx - 1; else xmaxc = xmax;
- if (xminc > xmaxc) return NULL;
+ const rcti clip = {
+ max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1),
+ max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)};
+ const int size_clip[2] = {
+ BLI_rcti_size_x(&clip) + 1,
+ BLI_rcti_size_y(&clip) + 1};
+
+ if (UNLIKELY((clip.xmin > clip.xmax) ||
+ (clip.ymin > clip.ymax)))
+ {
+ return NULL;
+ }
- if (ymin < 0) yminc = 0; else yminc = ymin;
- if (ymax >= vc->ar->winy) ymaxc = vc->ar->winy - 1; else ymaxc = ymax;
- if (yminc > ymaxc) return NULL;
-
- ibuf = IMB_allocImBuf((xmaxc - xminc + 1), (ymaxc - yminc + 1), 32, IB_rect);
+ ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect);
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
- view3d_opengl_read_pixels(vc->ar,
- xminc, yminc,
- (xmaxc - xminc + 1),
- (ymaxc - yminc + 1),
- GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect);
glReadBuffer(GL_BACK);
- if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
-
- a = (xmaxc - xminc + 1) * (ymaxc - yminc + 1);
- dr = ibuf->rect;
- while (a--) {
- if (*dr) *dr = WM_framebuffer_to_index(*dr);
- dr++;
+ if (ENDIAN_ORDER == B_ENDIAN) {
+ IMB_convert_rgba_to_abgr(ibuf_clip);
}
+
+ WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
- /* put clipped result back, if needed */
- if (xminc == xmin && xmaxc == xmax && yminc == ymin && ymaxc == ymax)
- return ibuf;
-
- ibuf1 = IMB_allocImBuf( (xmax - xmin + 1), (ymax - ymin + 1), 32, IB_rect);
- rd = ibuf->rect;
- dr = ibuf1->rect;
+ if ((clip.xmin == xmin) &&
+ (clip.xmax == xmax) &&
+ (clip.ymin == ymin) &&
+ (clip.ymax == ymax))
+ {
+ return ibuf_clip;
+ }
+ else {
+ /* put clipped result into a non-clipped buffer */
+ struct ImBuf *ibuf_full;
+ const int size[2] = {
+ (xmax - xmin + 1),
+ (ymax - ymin + 1)};
- for (ys = ymin; ys <= ymax; ys++) {
- for (xs = xmin; xs <= xmax; xs++, dr++) {
- if (xs >= xminc && xs <= xmaxc && ys >= yminc && ys <= ymaxc) {
- *dr = *rd;
- rd++;
- }
- }
+ ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
+
+ IMB_rectcpy(
+ ibuf_full, ibuf_clip,
+ clip.xmin - xmin, clip.ymin - ymin,
+ 0, 0,
+ size_clip[0], size_clip[1]);
+ IMB_freeImBuf(ibuf_clip);
+ return ibuf_full;
}
- IMB_freeImBuf(ibuf);
- return ibuf1;
}
/* smart function to sample a rect spiralling outside, nice for backbuf selection */
-unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *r_dist, short strict,
- void *handle, bool (*indextest)(void *handle, unsigned int index))
+unsigned int ED_view3d_backbuf_sample_rect(
+ ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist)
{
struct ImBuf *buf;
- unsigned int *bufmin, *bufmax, *tbuf;
+ const unsigned int *bufmin, *bufmax, *tbuf;
int minx, miny;
int a, b, rc, nr, amount, dirvec[4][2];
- int distance = 0;
unsigned int index = 0;
- bool indexok = false;
amount = (size - 1) / 2;
minx = mval[0] - (amount + 1);
miny = mval[1] - (amount + 1);
- buf = view3d_read_backbuf(vc, minx, miny, minx + size - 1, miny + size - 1);
+ buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
if (!buf) return 0;
rc = 0;
@@ -1541,21 +1582,19 @@ unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int
for (nr = 1; nr <= size; nr++) {
for (a = 0; a < 2; a++) {
- for (b = 0; b < nr; b++, distance++) {
- if (*tbuf && *tbuf >= min && *tbuf < max) { /* we got a hit */
- if (strict) {
- indexok = indextest(handle, *tbuf - min + 1);
- if (indexok) {
- *r_dist = sqrtf((float)distance);
- index = *tbuf - min + 1;
- goto exit;
- }
- }
- else {
- *r_dist = sqrtf((float)distance); /* XXX, this distance is wrong - */
- index = *tbuf - min + 1; /* messy yah, but indices start at 1 */
- goto exit;
- }
+ for (b = 0; b < nr; b++) {
+ if (*tbuf && *tbuf >= min && *tbuf < max) {
+ /* we got a hit */
+
+ /* get x,y pixel coords from the offset
+ * (manhatten distance in keeping with other screen-based selection) */
+ *r_dist = (float)(
+ abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
+ abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
+
+ /* indices start at 1 here */
+ index = (*tbuf - min) + 1;
+ goto exit;
}
tbuf += (dirvec[rc][0] + dirvec[rc][1]);
@@ -1577,6 +1616,26 @@ exit:
/* ************************************************************* */
+static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
+{
+ if ((ima->flag & IMA_IS_STEREO)) {
+ iuser->flag |= IMA_SHOW_STEREO;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ iuser->multiview_eye = STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ iuser->multiview_eye = v3d->stereo3d_camera;
+ }
+
+ BKE_image_multiview_index(ima, iuser);
+ }
+ else {
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+}
+
static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
const bool do_foreground, const bool do_camera_frame)
{
@@ -1585,6 +1644,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ bgpic->iuser.scene = scene; /* Needed for render results. */
if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
continue;
@@ -1595,12 +1655,14 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
{
float image_aspect[2];
float fac, asp, zoomx, zoomy;
- float x1, y1, x2, y2;
+ float x1, y1, x2, y2, centx, centy;
ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
+ void *lock;
+ rctf clip_rect;
- Image *ima;
- MovieClip *clip;
+ Image *ima = NULL;
+ MovieClip *clip = NULL;
/* disable individual images */
if ((bgpic->flag & V3D_BGPIC_DISABLED))
@@ -1617,16 +1679,15 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ibuf = NULL; /* frame is out of range, dont show */
}
else {
- ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, NULL);
+ view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
+ ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
releaseibuf = ibuf;
}
image_aspect[0] = ima->aspx;
- image_aspect[1] = ima->aspx;
+ image_aspect[1] = ima->aspy;
}
else if (bgpic->source == V3D_BGPIC_MOVIE) {
- clip = NULL;
-
/* TODO: skip drawing when out of frame range (as image sequences do above) */
if (bgpic->flag & V3D_BGPIC_CAMERACLIP) {
@@ -1664,7 +1725,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, NULL);
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
continue;
}
@@ -1702,6 +1763,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
y2 += yof_scale;
}
+ centx = (x1 + x2) / 2.0f;
+ centy = (y1 + y2) / 2.0f;
+
/* aspect correction */
if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) {
/* apply aspect from clip */
@@ -1719,16 +1783,14 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) {
/* fit X */
const float div = asp_src / asp_dst;
- const float cent = (x1 + x2) / 2.0f;
- x1 = ((x1 - cent) * div) + cent;
- x2 = ((x2 - cent) * div) + cent;
+ x1 = ((x1 - centx) * div) + centx;
+ x2 = ((x2 - centx) * div) + centx;
}
else {
/* fit Y */
const float div = asp_dst / asp_src;
- const float cent = (y1 + y2) / 2.0f;
- y1 = ((y1 - cent) * div) + cent;
- y2 = ((y2 - cent) * div) + cent;
+ y1 = ((y1 - centy) * div) + centy;
+ y2 = ((y2 - centy) * div) + centy;
}
}
}
@@ -1755,15 +1817,22 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size);
x2 = sco[0] + fac * (bgpic->xof + bgpic->size);
y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size);
+
+ centx = (x1 + x2) / 2.0f;
+ centy = (y1 + y2) / 2.0f;
}
/* complete clip? */
+ BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
+ if (bgpic->rotation) {
+ BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
+ }
- if (x2 < 0 || y2 < 0 || x1 > ar->winx || y1 > ar->winy) {
+ if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, NULL);
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
continue;
}
@@ -1805,6 +1874,17 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
glPushMatrix();
ED_region_pixelspace(ar);
+ glTranslatef(centx, centy, 0.0);
+ glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
+
+ if (bgpic->flag & V3D_BGPIC_FLIP_X) {
+ zoomx *= -1.0f;
+ x1 = x2;
+ }
+ if (bgpic->flag & V3D_BGPIC_FLIP_Y) {
+ zoomy *= -1.0f;
+ y1 = y2;
+ }
glPixelZoom(zoomx, zoomy);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend);
@@ -1812,7 +1892,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
* glaDrawPixelsSafe in some cases, which will end up in missing
* alpha transparency for the background image (sergey)
*/
- glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
+ glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
glPixelZoom(1.0, 1.0);
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
@@ -1830,7 +1910,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, NULL);
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
}
}
}
@@ -1883,7 +1963,7 @@ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
{
View3DAfter *v3da, *next;
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
v3d->transp = true;
for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) {
@@ -1894,17 +1974,19 @@ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
}
v3d->transp = false;
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
}
/* clears zbuffer and draws it over */
-static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, const bool clear)
+static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
{
View3DAfter *v3da, *next;
- if (clear && v3d->zbuf)
+ if (*clear && v3d->zbuf) {
glClear(GL_DEPTH_BUFFER_BIT);
+ *clear = false;
+ }
v3d->xray = true;
for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
@@ -1928,6 +2010,8 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const
v3d->xray = true;
v3d->transp = true;
+ glDepthMask(GL_FALSE);
+
for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) {
next = v3da->next;
draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
@@ -1938,6 +2022,7 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const
v3d->transp = false;
v3d->xray = false;
+ glDepthMask(GL_TRUE);
}
/* *********************** */
@@ -2000,9 +2085,9 @@ static void draw_dupli_objects_color(
tbase.flag = OB_FROMDUPLI | base->flag;
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
- // BLI_sortlist(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
+ // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
- apply_data = duplilist_apply(base->object, lb);
+ apply_data = duplilist_apply(base->object, scene, lb);
dob = dupli_step(lb->first);
if (dob) dob_next = dupli_step(dob->next);
@@ -2068,14 +2153,14 @@ static void draw_dupli_objects_color(
* so for now it should be ok to - campbell */
if ( /* if this is the last no need to make a displist */
- (dob_next == NULL || dob_next->ob != dob->ob) ||
- /* lamp drawing messes with matrices, could be handled smarter... but this works */
- (dob->ob->type == OB_LAMP) ||
- (dob->type == OB_DUPLIGROUP && dob->animated) ||
- !bb_tmp ||
- draw_glsl_material(scene, dob->ob, v3d, dt) ||
- check_object_draw_texture(scene, v3d, dt) ||
- (base->object == OBACT && v3d->flag2 & V3D_SOLID_MATCAP))
+ (dob_next == NULL || dob_next->ob != dob->ob) ||
+ /* lamp drawing messes with matrices, could be handled smarter... but this works */
+ (dob->ob->type == OB_LAMP) ||
+ (dob->type == OB_DUPLIGROUP && dob->animated) ||
+ !bb_tmp ||
+ draw_glsl_material(scene, dob->ob, v3d, dt) ||
+ check_object_draw_texture(scene, v3d, dt) ||
+ (v3d->flag2 & V3D_SOLID_MATCAP) != 0)
{
// printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2);
use_displist = false;
@@ -2106,7 +2191,9 @@ static void draw_dupli_objects_color(
}
else {
copy_m4_m4(dob->ob->obmat, dob->mat);
+ GPU_begin_dupli_object(dob);
draw_object(scene, ar, v3d, &tbase, dflag_dupli);
+ GPU_end_dupli_object();
}
}
@@ -2310,7 +2397,9 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_set(rv3d);
}
-
+ /* get surface depth without bias */
+ rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
+
v3d->zbuf = true;
glEnable(GL_DEPTH_TEST);
@@ -2395,8 +2484,10 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
glDepthMask(mask_orig);
}
- if (rv3d->rflag & RV3D_CLIPPING)
+ if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_disable();
+ }
+ rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
v3d->zbuf = zbuf;
if (!v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -2411,8 +2502,10 @@ typedef struct View3DShadow {
GPULamp *lamp;
} View3DShadow;
-static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object *par,
- float obmat[4][4], ListBase *shadows, SceneRenderLayer *srl)
+static void gpu_render_lamp_update(Scene *scene, View3D *v3d,
+ Object *ob, Object *par,
+ float obmat[4][4], unsigned int lay,
+ ListBase *shadows, SceneRenderLayer *srl)
{
GPULamp *lamp;
Lamp *la = (Lamp *)ob->data;
@@ -2422,10 +2515,10 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object
lamp = GPU_lamp_from_blender(scene, ob, par);
if (lamp) {
- GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat);
+ GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat);
GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy);
- layers = ob->lay & v3d->lay;
+ layers = lay & v3d->lay;
if (srl)
layers &= srl->lay;
@@ -2437,13 +2530,14 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object
}
}
-static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
+static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
{
ListBase shadows;
View3DShadow *shadow;
Scene *sce_iter;
Base *base;
Object *ob;
+ World *world = scene->world;
SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL;
BLI_listbase_clear(&shadows);
@@ -2453,7 +2547,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
ob = base->object;
if (ob->type == OB_LAMP)
- gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, &shadows, srl);
+ gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl);
if (ob->transflag & OB_DUPLI) {
DupliObject *dob;
@@ -2461,7 +2555,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
for (dob = lb->first; dob; dob = dob->next)
if (dob->ob->type == OB_LAMP)
- gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, &shadows, srl);
+ gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl);
free_object_duplilist(lb);
}
@@ -2481,7 +2575,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
v3d->drawtype = OB_SOLID;
v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp);
- v3d->flag2 &= ~V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP;
+ v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP);
v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW;
GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat);
@@ -2496,7 +2590,10 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
/* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */
- ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, false, false);
+ ED_view3d_draw_offscreen(
+ scene, v3d, &ar, winsize, winsize, viewmat, winmat,
+ false, false, true,
+ NULL, NULL, NULL, NULL);
GPU_lamp_shadow_buffer_unbind(shadow->lamp);
v3d->drawtype = drawtype;
@@ -2505,18 +2602,26 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
}
BLI_freelistN(&shadows);
+
+ /* update world values */
+ if (world) {
+ GPU_mist_update_enable(world->mode & WO_MIST);
+ GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
+ GPU_horizon_update_color(&world->horr);
+ GPU_ambient_update_color(&world->ambr);
+ }
}
/* *********************** customdata **************** */
-CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
+CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
{
CustomDataMask mask = 0;
if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) ||
((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
{
- mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
+ mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
if (BKE_scene_use_new_shading_nodes(scene)) {
if (v3d->drawtype == OB_MATERIAL)
@@ -2524,8 +2629,10 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
}
else {
if ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
- (v3d->drawtype == OB_MATERIAL))
+ (v3d->drawtype == OB_MATERIAL))
+ {
mask |= CD_MASK_ORCO;
+ }
}
}
@@ -2533,16 +2640,16 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
}
/* goes over all modes and view3d settings */
-CustomDataMask ED_view3d_screen_datamask(bScreen *screen)
+CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
{
- Scene *scene = screen->scene;
+ const Scene *scene = screen->scene;
CustomDataMask mask = CD_MASK_BAREMESH;
- ScrArea *sa;
+ const ScrArea *sa;
/* check if we need tfaces & mcols due to view mode */
for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_VIEW3D) {
- mask |= ED_view3d_datamask(scene, (View3D *)sa->spacedata.first);
+ mask |= ED_view3d_datamask(scene, sa->spacedata.first);
}
}
@@ -2552,6 +2659,7 @@ CustomDataMask ED_view3d_screen_datamask(bScreen *screen)
void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
{
RegionView3D *rv3d = ar->regiondata;
+ rctf cameraborder;
/* setup window matrices */
if (winmat)
@@ -2569,7 +2677,23 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
invert_m4_m4(rv3d->persinv, rv3d->persmat);
invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
+
+ /* calculate GLSL view dependent values */
+ /* store window coordinates scaling/offset */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
+ rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
+ rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
+
+ rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
+ rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
+ }
+ else {
+ rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
+ rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
+ }
+
/* calculate pixelsize factor once, is used for lamps and obcenters */
{
/* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])'
@@ -2592,8 +2716,6 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
}
}
-
-
/**
* Shared by #ED_view3d_draw_offscreen and #view3d_main_area_draw_objects
*
@@ -2604,11 +2726,17 @@ static void view3d_draw_objects(
const bContext *C,
Scene *scene, View3D *v3d, ARegion *ar,
const char **grid_unit,
- const bool do_bgpic, const bool draw_offscreen)
+ const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
{
RegionView3D *rv3d = ar->regiondata;
Base *base;
const bool do_camera_frame = !draw_offscreen;
+ const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0;
+ const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO);
+ /* only draw grids after in solid modes, else it hovers over mesh wires */
+ const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx;
+ bool do_composite_xray = false;
+ bool xrayclear = true;
if (!draw_offscreen) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
@@ -2639,28 +2767,24 @@ static void view3d_draw_objects(
glEnable(GL_DEPTH_TEST);
}
- if (!draw_offscreen) {
+ /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override
+ * objects if done last */
+ if (draw_grids) {
/* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */
- rv3d->gridview = v3d->grid;
- if (scene->unit.system) {
- rv3d->gridview /= scene->unit.scale_length;
- }
+ rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit);
- if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
- if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- drawfloor(scene, v3d, grid_unit);
- }
+ if (!draw_floor) {
+ ED_region_pixelspace(ar);
+ *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */
+ drawgrid(&scene->unit, ar, v3d, grid_unit);
+ /* XXX make function? replaces persp(1) */
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(rv3d->winmat);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(rv3d->viewmat);
}
- else {
- if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- ED_region_pixelspace(ar);
- drawgrid(&scene->unit, ar, v3d, grid_unit);
- /* XXX make function? replaces persp(1) */
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(rv3d->winmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(rv3d->viewmat);
- }
+ else if (!draw_grids_after) {
+ drawfloor(scene, v3d, grid_unit, true);
}
}
@@ -2736,6 +2860,11 @@ static void view3d_draw_objects(
}
}
+ /* perspective floor goes last to use scene depth and avoid writing to depth buffer */
+ if (draw_grids_after) {
+ drawfloor(scene, v3d, grid_unit, false);
+ }
+
/* must be before xray draw which clears the depth buffer */
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* must be before xray draw which clears the depth buffer */
@@ -2746,8 +2875,19 @@ static void view3d_draw_objects(
/* transp and X-ray afterdraw stuff */
if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d);
- if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, true);
- if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, true);
+
+ /* always do that here to cleanup depth buffers if none needed */
+ if (fx) {
+ do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first);
+ GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray);
+ }
+
+ if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear);
+ if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear);
+
+ if (fx && do_composite_xray) {
+ GPU_fx_compositor_XRay_resolve(fx);
+ }
if (!draw_offscreen) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
@@ -2793,18 +2933,240 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
{
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows(scene, v3d);
+ gpu_update_lamps_shadows_world(scene, v3d);
+}
+
+/*
+ * Function to clear the view
+ */
+static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
+{
+ if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
+ bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes;
+
+ if (glsl) {
+ RegionView3D *rv3d = ar->regiondata;
+ GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
+ bool material_not_bound;
+
+ /* calculate full shader for background */
+ GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
+
+ material_not_bound = !GPU_material_bound(gpumat);
+
+ if (material_not_bound) {
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_TRIANGLE_STRIP);
+ glVertex3f(-1.0, -1.0, 1.0);
+ glVertex3f(1.0, -1.0, 1.0);
+ glVertex3f(-1.0, 1.0, 1.0);
+ glVertex3f(1.0, 1.0, 1.0);
+ glEnd();
+ glShadeModel(GL_FLAT);
+
+ if (material_not_bound) {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
+ GPU_material_unbind(gpumat);
+
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_DEPTH_TEST);
+ }
+ else if (scene->world->skytype & WO_SKYBLEND) { /* blend sky */
+ int x, y;
+ float col_hor[3];
+ float col_zen[3];
+
+#define VIEWGRAD_RES_X 16
+#define VIEWGRAD_RES_Y 16
+
+ GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
+ static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
+ static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
+ static bool buf_calculated = false;
+
+ IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
+ &scene->display_settings);
+ IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings,
+ &scene->display_settings);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* calculate buffers the first time only */
+ if (!buf_calculated) {
+ for (x = 0; x < VIEWGRAD_RES_X; x++) {
+ for (y = 0; y < VIEWGRAD_RES_Y; y++) {
+ const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
+ const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
+
+ /* -1..1 range */
+ grid_pos[x][y][0] = (xf - 0.5f) * 2.0f;
+ grid_pos[x][y][1] = (yf - 0.5f) * 2.0f;
+ grid_pos[x][y][2] = 1.0;
+ }
+ }
+
+ for (x = 0; x < VIEWGRAD_RES_X - 1; x++) {
+ for (y = 0; y < VIEWGRAD_RES_Y - 1; y++) {
+ indices[x][y][0] = x * VIEWGRAD_RES_X + y;
+ indices[x][y][1] = x * VIEWGRAD_RES_X + y + 1;
+ indices[x][y][2] = (x + 1) * VIEWGRAD_RES_X + y + 1;
+ indices[x][y][3] = (x + 1) * VIEWGRAD_RES_X + y;
+ }
+ }
+
+ buf_calculated = true;
+ }
+
+ for (x = 0; x < VIEWGRAD_RES_X; x++) {
+ for (y = 0; y < VIEWGRAD_RES_Y; y++) {
+ const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
+ const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
+ const float mval[2] = {xf * (float)ar->winx, yf * ar->winy};
+ const float z_up[3] = {0.0f, 0.0f, 1.0f};
+ float out[3];
+ GLubyte *col_ub = grid_col[x][y];
+
+ float col_fac;
+ float col_fl[3];
+
+ ED_view3d_win_to_vector(ar, mval, out);
+
+ if (scene->world->skytype & WO_SKYPAPER) {
+ if (scene->world->skytype & WO_SKYREAL) {
+ col_fac = fabsf(((float)y / (float)VIEWGRAD_RES_Y) - 0.5f) * 2.0f;
+ }
+ else {
+ col_fac = (float)y / (float)VIEWGRAD_RES_Y;
+ }
+ }
+ else {
+ if (scene->world->skytype & WO_SKYREAL) {
+ col_fac = fabsf((angle_normalized_v3v3(z_up, out) / (float)M_PI) - 0.5f) * 2.0f;
+ }
+ else {
+ col_fac = 1.0f - (angle_normalized_v3v3(z_up, out) / (float)M_PI);
+ }
+ }
+
+ interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac);
+
+ rgb_float_to_uchar(col_ub, col_fl);
+ col_ub[3] = 255;
+ }
+ }
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, grid_pos);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col);
+
+ glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_DEPTH_TEST);
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glShadeModel(GL_FLAT);
+
+#undef VIEWGRAD_RES_X
+#undef VIEWGRAD_RES_Y
+ }
+ else { /* solid sky */
+ float col_hor[3];
+ IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
+ &scene->display_settings);
+
+ glClearColor(col_hor[0], col_hor[1], col_hor[2], 1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+ }
+ else {
+ if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_QUADS);
+ UI_ThemeColor(TH_LOW_GRAD);
+ glVertex3f(-1.0, -1.0, 1.0);
+ glVertex3f(1.0, -1.0, 1.0);
+ UI_ThemeColor(TH_HIGH_GRAD);
+ glVertex3f(1.0, 1.0, 1.0);
+ glVertex3f(-1.0, 1.0, 1.0);
+ glEnd();
+ glShadeModel(GL_FLAT);
+
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_DEPTH_TEST);
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+ else {
+ UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+ }
}
/* ED_view3d_draw_offscreen_init should be called before this to initialize
* stuff like shadow buffers
*/
-void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
- float viewmat[4][4], float winmat[4][4],
- bool do_bgpic, bool do_sky)
-{
+void ED_view3d_draw_offscreen(
+ Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
+ float viewmat[4][4], float winmat[4][4],
+ bool do_bgpic, bool do_sky, bool is_persp,
+ GPUOffScreen *ofs,
+ GPUFX *fx, GPUFXSettings *fx_settings,
+ const char *viewname)
+{
+ struct bThemeState theme_state;
int bwinx, bwiny;
rcti brect;
+ bool do_compositing = false;
+ RegionView3D *rv3d = ar->regiondata;
glPushMatrix();
@@ -2820,7 +3182,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
ar->winrct.xmax = winx;
ar->winrct.ymax = winy;
- /* set theme */
+ UI_Theme_Store(&theme_state);
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
/* set flags */
@@ -2832,26 +3194,45 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
GPU_free_images_anim();
}
+ /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */
+ if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
+ view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
+ else
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+
+ /* framebuffer fx needed, we need to draw offscreen first */
+ if (v3d->fx_settings.fx_flag && fx) {
+ GPUSSAOSettings *ssao = NULL;
+
+ if (v3d->drawtype < OB_SOLID) {
+ ssao = v3d->fx_settings.ssao;
+ v3d->fx_settings.ssao = NULL;
+ }
+
+ do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings);
+
+ if (ssao)
+ v3d->fx_settings.ssao = ssao;
+ }
+
/* clear opengl buffers */
if (do_sky) {
- float sky_color[3];
-
- ED_view3d_offscreen_sky_color_get(scene, sky_color);
- glClearColor(sky_color[0], sky_color[1], sky_color[2], 1.0f);
+ view3d_main_area_clear(scene, v3d, ar);
}
else {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-
- /* setup view matrices */
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
-
-
/* main drawing call */
- view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true);
+ view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL);
+
+ /* post process */
+ if (do_compositing) {
+ if (!winmat)
+ is_persp = rv3d->is_persp;
+ GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs);
+ }
if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
/* draw grease-pencil stuff */
@@ -2874,30 +3255,23 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
glPopMatrix();
- /* XXX, without this the sequencer flickers with opengl draw enabled, need to find out why - campbell */
- glColor4ub(255, 255, 255, 255);
+ UI_Theme_Restore(&theme_state);
G.f &= ~G_RENDER_OGL;
}
-/* get a color used for offscreen sky, returns color in sRGB space */
-void ED_view3d_offscreen_sky_color_get(Scene *scene, float sky_color[3])
-{
- if (scene->world)
- linearrgb_to_srgb_v3_v3(sky_color, &scene->world->horr);
- else
- UI_GetThemeColor3fv(TH_BACK, sky_color);
-}
-
/* utility func for ED_view3d_draw_offscreen */
ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, char err_out[256])
+ bool draw_background, int alpha_mode, const char *viewname, char err_out[256])
{
RegionView3D *rv3d = ar->regiondata;
ImBuf *ibuf;
GPUOffScreen *ofs;
- bool draw_sky = (alpha_mode == R_ADDSKY);
-
+ bool draw_sky = (alpha_mode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD);
+
+ if (UNLIKELY(v3d == NULL))
+ return NULL;
+
/* state changes make normal drawing go weird otherwise */
glPushAttrib(GL_LIGHTING_BIT);
@@ -2910,24 +3284,35 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
ED_view3d_draw_offscreen_init(scene, v3d);
- GPU_offscreen_bind(ofs);
+ GPU_offscreen_bind(ofs, true);
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
CameraParams params;
+ GPUFXSettings fx_settings = {NULL};
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
BKE_camera_params_init(&params);
/* fallback for non camera objects */
params.clipsta = v3d->near;
params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
- ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background, draw_sky);
+ BKE_camera_to_gpu_dof(camera, &fx_settings);
+
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, params.winmat,
+ draw_background, draw_sky, !params.is_ortho,
+ ofs, NULL, &fx_settings, viewname);
}
else {
- ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background, draw_sky);
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, NULL,
+ draw_background, draw_sky, true,
+ ofs, NULL, NULL, viewname);
}
/* read in pixels & stamp */
@@ -2939,20 +3324,21 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
/* unbind */
- GPU_offscreen_unbind(ofs);
+ GPU_offscreen_unbind(ofs, true);
GPU_offscreen_free(ofs);
glPopAttrib();
if (ibuf->rect_float && ibuf->rect)
IMB_rect_from_float(ibuf);
-
+
return ibuf;
}
/* creates own 3d views, used by the sequencer */
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool draw_background, int alpha_mode, char err_out[256])
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode,
+ const char *viewname, char err_out[256])
{
View3D v3d = {NULL};
ARegion ar = {NULL};
@@ -2967,6 +3353,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
v3d.lay = scene->lay;
v3d.drawtype = drawtype;
v3d.flag2 = V3D_RENDER_OVERRIDE;
+
+ if (use_gpencil)
+ v3d.flag2 |= V3D_SHOW_GPENCIL;
if (use_solid_tex)
v3d.flag2 |= V3D_SOLID_TEX;
@@ -2979,9 +3368,11 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
{
CameraParams params;
+ Object *camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, v3d.camera);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -2995,7 +3386,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
- draw_background, alpha_mode, err_out);
+ draw_background, alpha_mode, viewname, err_out);
// seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
}
@@ -3197,181 +3588,107 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A
fill_color[3] = 1.0f;
}
- ED_region_info_draw(ar, rv3d->render_engine->text, 1, fill_color);
+ ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true);
}
-/*
- * Function to clear the view
- */
-static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
+static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
- /* clear background */
- if (scene->world && (v3d->flag2 & V3D_RENDER_OVERRIDE)) { /* clear with solid color */
- if (scene->world->skytype & WO_SKYBLEND) { /* blend sky */
- int x, y;
- float col_hor[3];
- float col_zen[3];
-
-#define VIEWGRAD_RES_X 16
-#define VIEWGRAD_RES_Y 16
-
- GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
- static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
- static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
- static bool buf_calculated = false;
-
- IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
- &scene->display_settings);
- IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings,
- &scene->display_settings);
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glShadeModel(GL_SMOOTH);
-
- /* calculate buffers the first time only */
- if (!buf_calculated) {
- for (x = 0; x < VIEWGRAD_RES_X; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y; y++) {
- const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
- const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
-
- /* -1..1 range */
- grid_pos[x][y][0] = (xf - 0.5f) * 2.0f;
- grid_pos[x][y][1] = (yf - 0.5f) * 2.0f;
- grid_pos[x][y][2] = 1.0;
- }
- }
+ wmWindow *win = CTX_wm_window(C);
- for (x = 0; x < VIEWGRAD_RES_X - 1; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y - 1; y++) {
- indices[x][y][0] = x * VIEWGRAD_RES_X + y;
- indices[x][y][1] = x * VIEWGRAD_RES_X + y + 1;
- indices[x][y][2] = (x + 1) * VIEWGRAD_RES_X + y + 1;
- indices[x][y][3] = (x + 1) * VIEWGRAD_RES_X + y;
- }
- }
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return false;
- buf_calculated = true;
- }
+ if (WM_stereo3d_enabled(win, true) == false)
+ return false;
- for (x = 0; x < VIEWGRAD_RES_X; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y; y++) {
- const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
- const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
- const float mval[2] = {xf * (float)ar->winx, yf * ar->winy};
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
- float out[3];
- GLubyte *col_ub = grid_col[x][y];
+ if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB)
+ return false;
- float col_fac;
- float col_fl[3];
+ if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) {
+ if (v3d->stereo3d_camera == STEREO_MONO_ID)
+ return false;
- ED_view3d_win_to_vector(ar, mval, out);
+ return BKE_scene_multiview_is_stereo3d(&scene->r);
+ }
- if (scene->world->skytype & WO_SKYPAPER) {
- if (scene->world->skytype & WO_SKYREAL) {
- col_fac = fabsf(((float)y / (float)VIEWGRAD_RES_Y) - 0.5f) * 2.0f;
- }
- else {
- col_fac = (float)y / (float)VIEWGRAD_RES_Y;
- }
- }
- else {
- if (scene->world->skytype & WO_SKYREAL) {
- col_fac = fabsf((angle_normalized_v3v3(z_up, out) / (float)M_PI) - 0.5f) * 2.0f;
- }
- else {
- col_fac = 1.0f - (angle_normalized_v3v3(z_up, out) / (float)M_PI);
- }
- }
+ return true;
+}
- interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac);
+/* setup the view and win matrices for the multiview cameras
+ *
+ * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
+ * we have no winmatrix (i.e., projection matrix) defined at that time.
+ * Since the camera and the camera shift are needed for the winmat calculation
+ * we do a small hack to replace it temporarily so we don't need to change the
+ * view3d)main_area_setup_view() code to account for that.
+ */
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
+{
+ bool is_left;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ const char *viewname;
- rgb_float_to_uchar(col_ub, col_fl);
- col_ub[3] = 0;
- }
- }
+ /* show only left or right camera */
+ if (v3d->stereo3d_camera != STEREO_3D_ID)
+ v3d->multiview_eye = v3d->stereo3d_camera;
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
+ is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+ viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, grid_pos);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col);
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ Camera *data;
+ float viewmat[4][4];
+ float shiftx;
- glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices);
+ data = (Camera *)v3d->camera->data;
+ shiftx = data->shiftx;
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
+ BLI_lock_thread(LOCK_VIEW3D);
+ data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ data->shiftx = shiftx;
+ BLI_unlock_thread(LOCK_VIEW3D);
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *view_ob = v3d->camera;
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
- glShadeModel(GL_FLAT);
+ BLI_lock_thread(LOCK_VIEW3D);
+ v3d->camera = camera;
-#undef VIEWGRAD_RES_X
-#undef VIEWGRAD_RES_Y
- }
- else { /* solid sky */
- float col_hor[3];
- IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
- &scene->display_settings);
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
- glClearColor(col_hor[0], col_hor[1], col_hor[2], 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
+ v3d->camera = view_ob;
+ BLI_unlock_thread(LOCK_VIEW3D);
}
- else {
- if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
- glShadeModel(GL_SMOOTH);
- glBegin(GL_QUADS);
- UI_ThemeColor(TH_LOW_GRAD);
- glVertex3f(-1.0, -1.0, 1.0);
- glVertex3f(1.0, -1.0, 1.0);
- UI_ThemeColor(TH_HIGH_GRAD);
- glVertex3f(1.0, 1.0, 1.0);
- glVertex3f(-1.0, 1.0, 1.0);
- glEnd();
- glShadeModel(GL_FLAT);
+}
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
+static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname)
+{
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ float viewmat[4][4];
+ const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- else {
- UI_ThemeClearColor(TH_HIGH_GRAD);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
}
}
-
#ifdef WITH_GAMEENGINE
static void update_lods(Scene *scene, float camera_pos[3])
{
@@ -3386,29 +3703,34 @@ static void update_lods(Scene *scene, float camera_pos[3])
}
#endif
-
static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3D *v3d,
ARegion *ar, const char **grid_unit)
{
RegionView3D *rv3d = ar->regiondata;
unsigned int lay_used = v3d->lay_used;
-
+
+ /* post processing */
+ bool do_compositing = false;
+
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows(scene, v3d);
-
+ gpu_update_lamps_shadows_world(scene, v3d);
+
/* reset default OpenGL lights if needed (i.e. after preferences have been altered) */
if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) {
rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE;
GPU_default_lights();
}
- /* setup view matrices */
- view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
+ /* setup the view matrix */
+ if (view3d_stereo3d_active(C, scene, v3d, rv3d))
+ view3d_stereo3d_setup(scene, v3d, ar);
+ else
+ view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
rv3d->rflag &= ~RV3D_IS_GAME_ENGINE;
#ifdef WITH_GAMEENGINE
- if (STREQ(scene->r.engine, "BLENDER_GAME")) {
+ if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) {
rv3d->rflag |= RV3D_IS_GAME_ENGINE;
/* Make sure LoDs are up to date */
@@ -3416,6 +3738,23 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
}
#endif
+ /* framebuffer fx needed, we need to draw offscreen first */
+ if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) {
+ GPUFXSettings fx_settings;
+ BKE_screen_gpu_fx_validate(&v3d->fx_settings);
+ fx_settings = v3d->fx_settings;
+ if (!rv3d->compositor)
+ rv3d->compositor = GPU_fx_compositor_create();
+
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera)
+ BKE_camera_to_gpu_dof(v3d->camera, &fx_settings);
+ else {
+ fx_settings.dof = NULL;
+ }
+
+ do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings);
+ }
+
/* clear the background */
view3d_main_area_clear(scene, v3d, ar);
@@ -3425,7 +3764,12 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
}
/* main drawing call */
- view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false);
+ view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL);
+
+ /* post process */
+ if (do_compositing) {
+ GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL);
+ }
/* Disable back anti-aliasing */
if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
@@ -3449,6 +3793,36 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
}
+static bool is_cursor_visible(Scene *scene)
+{
+ Object *ob = OBACT;
+
+ /* don't draw cursor in paint modes, but with a few exceptions */
+ if (ob && ob->mode & OB_MODE_ALL_PAINT) {
+ /* exception: object is in weight paint and has deforming armature in pose mode */
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ if (BKE_object_pose_armature_get(ob) != NULL) {
+ return true;
+ }
+ }
+ /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
+ else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ const Paint *p = BKE_paint_get_active(scene);
+
+ if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
+ if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
+ return true;
+ }
+ }
+ }
+
+ /* no exception met? then don't draw cursor! */
+ return false;
+ }
+
+ return true;
+}
+
static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
ARegion *ar, View3D *v3d,
const char *grid_unit, bool render_border)
@@ -3482,7 +3856,10 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
Object *ob;
- drawcursor(scene, ar, v3d);
+ /* 3d cursor */
+ if (is_cursor_visible(scene)) {
+ drawcursor(scene, ar, v3d);
+ }
if (U.uiflag & USER_SHOW_ROTVIEWICON)
draw_view_axis(rv3d, &rect);
@@ -3502,7 +3879,7 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
wmWindowManager *wm = CTX_wm_manager(C);
- if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_playing(wm)) {
+ if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
ED_scene_draw_fps(scene, &rect);
}
else if (U.uiflag & USER_SHOW_VIEWPORTNAME) {
@@ -3540,9 +3917,13 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
/* draw viewport using opengl */
if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) {
view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit);
+
#ifdef DEBUG_DRAW
bl_debug_draw();
#endif
+ if (G.debug & G_DEBUG_SIMDATA)
+ draw_sim_debug_data(scene, v3d, ar);
+
ED_region_pixelspace(ar);
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index cff6761d628..2295986faf0 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -28,7 +28,6 @@
* \ingroup spview3d
*/
-
#include <string.h>
#include <stdio.h>
#include <math.h>
@@ -38,7 +37,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_camera_types.h"
#include "MEM_guardedalloc.h"
@@ -46,10 +44,10 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_font.h"
-#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -76,7 +74,6 @@
#include "ED_transform.h"
#include "ED_mesh.h"
#include "ED_view3d.h"
-#include "ED_sculpt.h"
#include "UI_resources.h"
@@ -84,7 +81,7 @@
#include "view3d_intern.h" /* own include */
-bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d)
+bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
}
@@ -104,7 +101,10 @@ static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
/* ********************** view3d_edit: view manipulations ********************* */
-bool ED_view3d_camera_lock_check(View3D *v3d, RegionView3D *rv3d)
+/**
+ * \return true when the view-port is locked to its camera.
+ */
+bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) &&
(v3d->camera->id.lib == NULL) &&
@@ -112,6 +112,10 @@ bool ED_view3d_camera_lock_check(View3D *v3d, RegionView3D *rv3d)
(rv3d->persp == RV3D_CAMOB));
}
+/**
+ * Apply the camera object transformation to the view-port.
+ * (needed so we can use regular view-port manipulation operators, that sync back to the camera).
+ */
void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
@@ -128,7 +132,11 @@ void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
ED_view3d_camera_lock_init_ex(v3d, rv3d, true);
}
-/* return true if the camera is moved */
+/**
+ * Apply the view-port transformation back to the camera object.
+ *
+ * \return true if the camera is moved.
+ */
bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
@@ -190,6 +198,7 @@ bool ED_view3d_camera_autokey(
struct bContext *C, const bool do_rotate, const bool do_translate)
{
if (autokeyframe_cfra_can_key(scene, id_key)) {
+ const float cfra = (float)CFRA;
ListBase dsources = {NULL, NULL};
/* add data-source override for the camera object */
@@ -201,12 +210,12 @@ bool ED_view3d_camera_autokey(
* TODO: need to check in future that frame changed before doing this
*/
if (do_rotate) {
- struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
}
if (do_translate) {
- struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
}
/* free temp data */
@@ -520,6 +529,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
typedef struct ViewOpsData {
/* context pointers (assigned by viewops_data_alloc) */
+ Scene *scene;
ScrArea *sa;
ARegion *ar;
View3D *v3d;
@@ -592,6 +602,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
/* store data */
op->customdata = vod;
+ vod->scene = CTX_data_scene(C);
vod->sa = CTX_wm_area(C);
vod->ar = CTX_wm_region(C);
vod->v3d = vod->sa->spacedata.first;
@@ -621,14 +632,17 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
Scene *scene = CTX_data_scene(C);
Object *ob = OBACT;
- if (ob && (ob->mode & OB_MODE_ALL_PAINT) && (BKE_object_pose_armature_get(ob) == NULL)) {
+ if (ob && (ob->mode & OB_MODE_ALL_PAINT) &&
+ /* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
+ ((ob->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob)) == 0)
+ {
/* in case of sculpting use last average stroke position as a rotation
* center, in other cases it's not clear what rotation center shall be
* so just rotate around object origin
*/
- if (ob->mode & OB_MODE_SCULPT) {
+ if (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT)) {
float stroke[3];
- ED_sculpt_stroke_get_average(ob, stroke);
+ BKE_paint_stroke_get_average(scene, ob, stroke);
copy_v3_v3(lastofs, stroke);
}
else {
@@ -1035,7 +1049,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
* - of rotation is linearly proportional
* - to the distance that the mouse is
* - dragged. */
- phi = si * (float)(M_PI / 2.0);
+ phi = si * (float)M_PI_2;
q1[0] = cosf(phi);
mul_v3_fl(q1 + 1, sinf(phi));
@@ -1119,6 +1133,8 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
+ bool use_autokey = false;
+ int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
if (event->type == MOUSEMOVE) {
@@ -1153,17 +1169,25 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event_code == VIEW_APPLY) {
viewrotate_apply(vod, event->x, event->y);
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ use_autokey = true;
+ }
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
ED_view3d_depth_tag_update(vod->rv3d);
+ use_autokey = true;
+ ret = OPERATOR_FINISHED;
+ }
- viewops_data_free(C, op);
+ if (use_autokey) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
+ }
- return OPERATOR_FINISHED;
+ if (ret & OPERATOR_FINISHED) {
+ viewops_data_free(C, op);
}
- return OPERATOR_RUNNING_MODAL;
+ return ret;
}
/**
@@ -1221,26 +1245,31 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(vod->ar);
}
- if (event->type == MOUSEPAN) {
+ if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
/* Rotate direction we keep always same */
- if (U.uiflag2 & USER_TRACKPAD_NATURAL)
- viewrotate_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
- else
- viewrotate_apply(vod, event->prevx, event->prevy);
-
- ED_view3d_depth_tag_update(vod->rv3d);
-
- viewops_data_free(C, op);
-
- return OPERATOR_FINISHED;
- }
- else if (event->type == MOUSEROTATE) {
- /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
- viewrotate_apply(vod, event->prevx, event->y);
+ int x, y;
+
+ if (event->type == MOUSEPAN) {
+ if (U.uiflag2 & USER_TRACKPAD_NATURAL) {
+ x = 2 * event->x - event->prevx;
+ y = 2 * event->y - event->prevy;
+ }
+ else {
+ x = event->prevx;
+ y = event->prevy;
+ }
+ }
+ else {
+ /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
+ x = event->prevx;
+ y = event->y;
+ }
+
+ viewrotate_apply(vod, x, y);
ED_view3d_depth_tag_update(vod->rv3d);
-
+
viewops_data_free(C, op);
-
+
return OPERATOR_FINISHED;
}
else {
@@ -1298,7 +1327,7 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->cancel = viewrotate_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
/** \name NDOF Utility Functions
@@ -1912,7 +1941,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
vod->rv3d->ofs_lock[1] -= ((vod->oldy - y) * 2.0f) / (float)vod->ar->winy;
}
else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) {
- const float zoomfac = BKE_screen_view3d_zoom_to_fac((float)vod->rv3d->camzoom) * 2.0f;
+ const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
vod->rv3d->camdx += (vod->oldx - x) / (vod->ar->winx * zoomfac);
vod->rv3d->camdy += (vod->oldy - y) / (vod->ar->winy * zoomfac);
CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
@@ -1946,6 +1975,8 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
+ bool use_autokey = false;
+ int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
if (event->type == MOUSEMOVE) {
@@ -1972,17 +2003,25 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event_code == VIEW_APPLY) {
viewmove_apply(vod, event->x, event->y);
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ use_autokey = true;
+ }
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
+ use_autokey = true;
+ ret = OPERATOR_FINISHED;
+ }
- viewops_data_free(C, op);
+ if (use_autokey) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
+ }
- return OPERATOR_FINISHED;
+ if (ret & OPERATOR_FINISHED) {
+ viewops_data_free(C, op);
}
- return OPERATOR_RUNNING_MODAL;
+ return ret;
}
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -2031,7 +2070,7 @@ void VIEW3D_OT_move(wmOperatorType *ot)
ot->cancel = viewmove_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
/* ************************ viewzoom ******************************** */
@@ -2071,16 +2110,63 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
}
-static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
+static void view_zoom_mouseloc_camera(
+ Scene *scene, View3D *v3d,
+ ARegion *ar, float dfac, int mx, int my)
{
RegionView3D *rv3d = ar->regiondata;
+ const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
+ const float zoomfac_new = CLAMPIS(zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR);
+ const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new);
+
+
+ if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
+ float zoomfac_px;
+ rctf camera_frame_old;
+ rctf camera_frame_new;
+
+ const float pt_src[2] = {mx, my};
+ float pt_dst[2];
+ float delta_px[2];
+
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false);
+ BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin);
+
+ rv3d->camzoom = camzoom_new;
+ CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
+
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false);
+ BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin);
+
+ BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
+ sub_v2_v2v2(delta_px, pt_dst, pt_src);
+
+ /* translate the camera offset using pixel space delta
+ * mapped back to the camera (same logic as panning in camera view) */
+ zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
+
+ rv3d->camdx += delta_px[0] / (ar->winx * zoomfac_px);
+ rv3d->camdy += delta_px[1] / (ar->winy * zoomfac_px);
+ CLAMP(rv3d->camdx, -1.0f, 1.0f);
+ CLAMP(rv3d->camdy, -1.0f, 1.0f);
+ }
+ else {
+ rv3d->camzoom = camzoom_new;
+ CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
+ }
+}
+
+static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ const float dist_new = rv3d->dist * dfac;
if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
float dvec[3];
float tvec[3];
float tpos[3];
float mval_f[2];
- float new_dist;
+
float zfac;
negate_v3_v3(tpos, rv3d->ofs);
@@ -2097,105 +2183,133 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
negate_v3(tvec);
/* Offset to target position and dolly */
- new_dist = rv3d->dist * dfac;
-
copy_v3_v3(rv3d->ofs, tvec);
- rv3d->dist = new_dist;
+ rv3d->dist = dist_new;
/* Calculate final offset */
madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
}
else {
- rv3d->dist *= dfac;
+ rv3d->dist = dist_new;
}
}
-
-static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzoom, const short zoom_invert)
+static float viewzoom_scale_value(
+ const rcti *winrct,
+ const short viewzoom,
+ const bool zoom_invert, const bool zoom_invert_force,
+ const int xy[2], const int xy_orig[2],
+ const float val, const float val_orig,
+ double *r_timer_lastdraw)
{
- float zfac = 1.0;
- bool use_cam_zoom;
- float dist_range[2];
-
- use_cam_zoom = (vod->rv3d->persp == RV3D_CAMOB) && !(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d));
-
- ED_view3d_dist_range_get(vod->v3d, dist_range);
-
- if (use_cam_zoom) {
- float delta;
- delta = (xy[0] - vod->origx + xy[1] - vod->origy) / 10.0f;
- vod->rv3d->camzoom = vod->camzoom_prev + (zoom_invert ? -delta : delta);
-
- CLAMP(vod->rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
- }
+ float zfac;
if (viewzoom == USER_ZOOM_CONT) {
double time = PIL_check_seconds_timer();
- float time_step = (float)(time - vod->timer_lastdraw);
+ float time_step = (float)(time - *r_timer_lastdraw);
float fac;
if (U.uiflag & USER_ZOOM_HORIZ) {
- fac = (float)(vod->origx - xy[0]);
+ fac = (float)(xy_orig[0] - xy[0]);
}
else {
- fac = (float)(vod->origy - xy[1]);
+ fac = (float)(xy_orig[1] - xy[1]);
}
- if (zoom_invert) {
+ if (zoom_invert != zoom_invert_force) {
fac = -fac;
}
/* oldstyle zoom */
zfac = 1.0f + ((fac / 20.0f) * time_step);
- vod->timer_lastdraw = time;
+ *r_timer_lastdraw = time;
}
else if (viewzoom == USER_ZOOM_SCALE) {
/* method which zooms based on how far you move the mouse */
const int ctr[2] = {
- BLI_rcti_cent_x(&vod->ar->winrct),
- BLI_rcti_cent_y(&vod->ar->winrct),
+ BLI_rcti_cent_x(winrct),
+ BLI_rcti_cent_y(winrct),
};
- const float len_new = 5 + len_v2v2_int(ctr, xy);
- const float len_old = 5 + len_v2v2_int(ctr, &vod->origx);
- zfac = vod->dist_prev * ((len_old + 5) / (len_new + 5)) / vod->rv3d->dist;
+ float len_new = 5 + len_v2v2_int(ctr, xy);
+ float len_old = 5 + len_v2v2_int(ctr, xy_orig);
+
+ /* intentionally ignore 'zoom_invert' for scale */
+ if (zoom_invert_force) {
+ SWAP(float, len_new, len_old);
+ }
+
+ zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val;
}
else { /* USER_ZOOM_DOLLY */
- float len1, len2;
-
+ float len_new = 5;
+ float len_old = 5;
+
if (U.uiflag & USER_ZOOM_HORIZ) {
- len1 = (vod->ar->winrct.xmax - xy[0]) + 5;
- len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
+ len_new += (winrct->xmax - xy[0]);
+ len_old += (winrct->xmax - xy_orig[0]);
}
else {
- len1 = (vod->ar->winrct.ymax - xy[1]) + 5;
- len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
+ len_new += (winrct->ymax - xy[1]);
+ len_old += (winrct->ymax - xy_orig[1]);
}
- if (zoom_invert) {
- SWAP(float, len1, len2);
- }
-
- if (use_cam_zoom) {
- /* zfac is ignored in this case, see below */
-#if 0
- zfac = vod->camzoom_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->camzoom;
-#endif
- }
- else {
- zfac = vod->dist_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->dist;
+
+ if (zoom_invert != zoom_invert_force) {
+ SWAP(float, len_new, len_old);
}
+
+ zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val;
}
- if (!use_cam_zoom) {
- if (zfac != 1.0f) {
- const float zfac_min = dist_range[0] / vod->rv3d->dist;
- const float zfac_max = dist_range[1] / vod->rv3d->dist;
- CLAMP(zfac, zfac_min, zfac_max);
- if (zfac != 1.0f) {
- view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
- }
- }
+ return zfac;
+}
+
+static void viewzoom_apply_camera(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ float zfac;
+ float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f;
+ float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
+
+ zfac = viewzoom_scale_value(
+ &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx,
+ zoomfac, zoomfac_prev,
+ &vod->timer_lastdraw);
+
+ if (zfac != 1.0f && zfac != 0.0f) {
+ /* calculate inverted, then invert again (needed because of camera zoom scaling) */
+ zfac = 1.0f / zfac;
+ view_zoom_mouseloc_camera(
+ vod->scene, vod->v3d,
+ vod->ar, zfac, vod->oldx, vod->oldy);
+ }
+
+ ED_region_tag_redraw(vod->ar);
+}
+
+static void viewzoom_apply_3d(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ float zfac;
+ float dist_range[2];
+
+ ED_view3d_dist_range_get(vod->v3d, dist_range);
+
+ zfac = viewzoom_scale_value(
+ &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx,
+ vod->rv3d->dist, vod->dist_prev,
+ &vod->timer_lastdraw);
+
+ if (zfac != 1.0f) {
+ const float zfac_min = dist_range[0] / vod->rv3d->dist;
+ const float zfac_max = dist_range[1] / vod->rv3d->dist;
+ CLAMP(zfac, zfac_min, zfac_max);
+
+ view_zoom_mouseloc_3d(
+ vod->ar, zfac, vod->oldx, vod->oldy);
}
/* these limits were in old code too */
@@ -2209,11 +2323,26 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo
ED_region_tag_redraw(vod->ar);
}
+static void viewzoom_apply(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ if ((vod->rv3d->persp == RV3D_CAMOB) &&
+ (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0)
+ {
+ viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert);
+ }
+ else {
+ viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert);
+ }
+}
static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
+ bool use_autokey = false;
+ int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
if (event->type == TIMER && event->customdata == vod->timer) {
@@ -2244,20 +2373,30 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event_code == VIEW_APPLY) {
viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ use_autokey = true;
+ }
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
- viewops_data_free(C, op);
+ use_autokey = true;
+ ret = OPERATOR_FINISHED;
+ }
- return OPERATOR_FINISHED;
+ if (use_autokey) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
+ }
+
+ if (ret & OPERATOR_FINISHED) {
+ viewops_data_free(C, op);
}
- return OPERATOR_RUNNING_MODAL;
+ return ret;
}
static int viewzoom_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
ScrArea *sa;
@@ -2290,22 +2429,26 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_view3d_dist_range_get(v3d, dist_range);
if (delta < 0) {
+ const float step = 1.2f;
/* this min and max is also in viewmove() */
if (use_cam_zoom) {
- rv3d->camzoom -= 10.0f;
- if (rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom = RV3D_CAMZOOM_MIN;
+ view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
}
- else if (rv3d->dist < dist_range[1]) {
- view_zoom_mouseloc(ar, 1.2f, mx, my);
+ else {
+ if (rv3d->dist < dist_range[1]) {
+ view_zoom_mouseloc_3d(ar, step, mx, my);
+ }
}
}
else {
+ const float step = 1.0f / 1.2f;
if (use_cam_zoom) {
- rv3d->camzoom += 10.0f;
- if (rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom = RV3D_CAMZOOM_MAX;
+ view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
}
- else if (rv3d->dist > dist_range[0]) {
- view_zoom_mouseloc(ar, 0.83333f, mx, my);
+ else {
+ if (rv3d->dist > dist_range[0]) {
+ view_zoom_mouseloc_3d(ar, step, mx, my);
+ }
}
}
@@ -2315,6 +2458,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_view3d_depth_tag_update(rv3d);
ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_region_tag_redraw(ar);
@@ -2389,8 +2533,10 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0);
}
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
+
ED_view3d_depth_tag_update(vod->rv3d);
-
+
viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -2432,7 +2578,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
ot->cancel = viewzoom_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
@@ -2486,6 +2632,8 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
+ bool use_autokey = false;
+ int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
if (event->type == MOUSEMOVE) {
@@ -2512,16 +2660,25 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event_code == VIEW_APPLY) {
viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0);
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ use_autokey = true;
+ }
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
- viewops_data_free(C, op);
+ use_autokey = true;
+ ret = OPERATOR_FINISHED;
+ }
- return OPERATOR_FINISHED;
+ if (use_autokey) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
}
- return OPERATOR_RUNNING_MODAL;
+ if (ret & OPERATOR_FINISHED) {
+ viewops_data_free(C, op);
+ }
+
+ return ret;
}
static int viewdolly_exec(bContext *C, wmOperator *op)
@@ -2675,7 +2832,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
ot->cancel = viewdolly_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
@@ -2698,29 +2855,15 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
size = max_fff(afm[0], afm[1], afm[2]);
if (ok_dist) {
- /* fix up zoom distance if needed */
+ char persp;
if (rv3d->is_persp) {
- float lens, sensor_size;
- /* offset the view based on the lens */
if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) {
- CameraParams params;
- BKE_camera_params_init(&params);
- params.clipsta = v3d->near;
- params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
-
- lens = params.lens;
- sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+ persp = RV3D_CAMOB;
}
else {
- lens = v3d->lens;
- sensor_size = DEFAULT_SENSOR_WIDTH;
+ persp = RV3D_PERSP;
}
- size = ED_view3d_radius_to_persp_dist(focallength_to_fov(lens, sensor_size), size / 2.0f) * VIEW3D_MARGIN;
-
- /* do not zoom closer than the near clipping plane */
- size = max_ff(size, v3d->near * 1.5f);
}
else { /* ortho */
if (size < 0.0001f) {
@@ -2729,7 +2872,15 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
}
else {
/* adjust zoom so it looks nicer */
- size = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
+ persp = RV3D_ORTHO;
+ }
+ }
+
+ if (ok_dist) {
+ new_dist = ED_view3d_radius_to_dist(v3d, ar, persp, true, (size / 2) * VIEW3D_MARGIN);
+ if (rv3d->is_persp) {
+ /* don't zoom closer than the near clipping plane */
+ new_dist = max_ff(new_dist, v3d->near * 1.5f);
}
}
}
@@ -2737,15 +2888,6 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
mid_v3_v3v3(new_ofs, min, max);
negate_v3(new_ofs);
- new_dist = size;
-
- /* correction for window aspect ratio */
- if (ar->winy > 2 && ar->winx > 2) {
- size = (float)ar->winx / (float)ar->winy;
- if (size < 1.0f) size = 1.0f / size;
- new_dist *= size;
- }
-
if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) {
rv3d->persp = RV3D_PERSP;
ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL,
@@ -2901,24 +3043,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok = ED_view3d_minmax_verts(obedit, min, max); /* only selected */
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- if (ob->pose) {
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- float vec[3];
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_SELECTED) {
- if (pchan->bone->layer & arm->layer) {
- bPoseChannel *pchan_tx = pchan->custom_tx ? pchan->custom_tx : pchan;
- ok = 1;
- mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
- minmax_v3v3_v3(min, max, vec);
- mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
- minmax_v3v3_v3(min, max, vec);
- }
- }
- }
- }
+ ok = BKE_pose_minmax(ob, min, max, true, true);
}
else if (BKE_paint_select_face_test(ob)) {
ok = paintface_minmax(ob, min, max);
@@ -2926,8 +3051,10 @@ static int viewselected_exec(bContext *C, wmOperator *op)
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
ok = PE_minmax(scene, min, max);
}
- else if (ob && (ob->mode & OB_MODE_SCULPT)) {
- ok = ED_sculpt_minmax(C, min, max);
+ else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) {
+ BKE_paint_stroke_get_average(scene, ob, min);
+ copy_v3_v3(max, min);
+ ok = true;
ok_dist = 0; /* don't zoom */
}
else {
@@ -3322,7 +3449,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
/* rna */
WM_operator_properties_border(ot);
- prop = RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only");
+ prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only",
+ "Set render border for camera view and final render only");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
@@ -3423,7 +3551,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* find the closest Z pixel */
depth_close = view3d_depth_near(&depth_temp);
- MEM_freeN(depth_temp.depths);
+ MEM_SAFE_FREE(depth_temp.depths);
}
cent[0] = (((double)rect.xmin) + ((double)rect.xmax)) / 2;
@@ -3624,6 +3752,8 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
{
RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */
float quat[4];
+ const short orig_persp = rv3d->persp;
+
normalize_qt_qt(quat, quat_);
@@ -3639,7 +3769,7 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
float twmat[3][3];
/* same as transform manipulator when normal is set */
- ED_getTransformOrientationMatrix(C, twmat, true);
+ ED_getTransformOrientationMatrix(C, twmat, V3D_ACTIVE);
mat3_to_quat(obact_quat, twmat);
invert_qt(obact_quat);
@@ -3650,22 +3780,6 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
}
if (align_active == false) {
- /* normal operation */
- if (rv3d->viewlock & RV3D_LOCKED) {
- /* only pass on if */
-
- /* nice confusing if-block */
- if (!((rv3d->view == RV3D_VIEW_FRONT && view == RV3D_VIEW_BACK) ||
- (rv3d->view == RV3D_VIEW_BACK && view == RV3D_VIEW_FRONT) ||
- (rv3d->view == RV3D_VIEW_RIGHT && view == RV3D_VIEW_LEFT) ||
- (rv3d->view == RV3D_VIEW_LEFT && view == RV3D_VIEW_RIGHT) ||
- (rv3d->view == RV3D_VIEW_BOTTOM && view == RV3D_VIEW_TOP) ||
- (rv3d->view == RV3D_VIEW_TOP && view == RV3D_VIEW_BOTTOM)))
- {
- return;
- }
- }
-
rv3d->view = view;
}
@@ -3682,16 +3796,31 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
}
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ /* to camera */
ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL,
rv3d->ofs, quat, NULL, NULL,
smooth_viewtx);
}
+ else if (orig_persp == RV3D_CAMOB && v3d->camera) {
+ /* from camera */
+ float ofs[3], dist;
+
+ copy_v3_v3(ofs, rv3d->ofs);
+ dist = rv3d->dist;
+
+ /* so we animate _from_ the camera location */
+ ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, &rv3d->dist, NULL);
+
+ ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
+ ofs, quat, &dist, NULL,
+ smooth_viewtx);
+ }
else {
+ /* no camera involved */
ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
NULL, quat, NULL, NULL,
smooth_viewtx);
}
-
}
static int viewnumpad_exec(bContext *C, wmOperator *op)
@@ -3712,10 +3841,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
viewnum = RNA_enum_get(op->ptr, "type");
align_active = RNA_boolean_get(op->ptr, "align_active");
- /* set this to zero, gets handled in axis_set_view */
- if (rv3d->viewlock & RV3D_LOCKED)
- align_active = false;
-
/* Use this to test if we started out with a camera */
if (rv3d->persp == RV3D_CAMOB) {
@@ -3841,23 +3966,37 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
ARegion *ar;
RegionView3D *rv3d;
int orbitdir;
+ char view_opposite;
+ PropertyRNA *prop_angle = RNA_struct_find_property(op->ptr, "angle");
+ float angle = RNA_property_is_set(op->ptr, prop_angle) ?
+ RNA_property_float_get(op->ptr, prop_angle) : DEG2RADF(U.pad_rot_angle);
/* no NULL check is needed, poll checks */
- ED_view3d_context_user_region(C, &v3d, &ar);
+ v3d = CTX_wm_view3d(C);
+ ar = CTX_wm_region(C);
rv3d = ar->regiondata;
+ /* support for switching to the opposite view (even when in locked views) */
+ view_opposite = (fabsf(angle) == (float)M_PI) ? ED_view3d_axis_view_opposite(rv3d->view) : RV3D_VIEW_USER;
orbitdir = RNA_enum_get(op->ptr, "type");
- if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
+ if ((rv3d->viewlock & RV3D_LOCKED) && (view_opposite == RV3D_VIEW_USER)) {
+ /* no NULL check is needed, poll checks */
+ ED_view3d_context_user_region(C, &v3d, &ar);
+ rv3d = ar->regiondata;
+ }
+
+ if ((rv3d->viewlock & RV3D_LOCKED) == 0 || (view_opposite != RV3D_VIEW_USER)) {
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- float angle = DEG2RADF((float)U.pad_rot_angle);
float quat_mul[4];
float quat_new[4];
float ofs_new[3];
float *ofs_new_pt = NULL;
- view3d_ensure_persp(v3d, ar);
+ if (view_opposite == RV3D_VIEW_USER) {
+ view3d_ensure_persp(v3d, ar);
+ }
if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
const float zvec[3] = {0.0f, 0.0f, 1.0f};
@@ -3880,7 +4019,15 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
}
mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul);
- rv3d->view = RV3D_VIEW_USER;
+
+ if (view_opposite != RV3D_VIEW_USER) {
+ rv3d->view = view_opposite;
+ /* avoid float in-precision, just get a new orientation */
+ ED_view3d_quat_from_axis_view(view_opposite, quat_new);
+ }
+ else {
+ rv3d->view = RV3D_VIEW_USER;
+ }
if (U.uiflag & USER_ORBIT_SELECTION) {
float dyn_ofs[3];
@@ -3911,6 +4058,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_view_orbit(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Orbit";
ot->description = "Orbit the view";
@@ -3924,7 +4073,11 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot)
ot->flag = 0;
/* properties */
+ prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
+
}
@@ -3970,6 +4123,8 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
+ bool use_autokey = false;
+ int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
if (event->type == MOUSEMOVE) {
@@ -3996,18 +4151,35 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event_code == VIEW_APPLY) {
viewroll_apply(vod, event->x, event->y);
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ use_autokey = true;
+ }
}
else if (event_code == VIEW_CONFIRM) {
- ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false);
ED_view3d_depth_tag_update(vod->rv3d);
- viewops_data_free(C, op);
+ use_autokey = true;
+ ret = OPERATOR_FINISHED;
+ }
- return OPERATOR_FINISHED;
+ if (use_autokey) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false);
+ }
+
+ if (ret & OPERATOR_FINISHED) {
+ viewops_data_free(C, op);
}
- return OPERATOR_RUNNING_MODAL;
+ return ret;
}
+static EnumPropertyItem prop_view_roll_items[] = {
+ {0, "ROLLANGLE", 0, "Roll Angle", "Roll the view using an angle value"},
+ {V3D_VIEW_STEPLEFT, "ROLLLEFT", 0, "Roll Left", "Roll the view around to the Left"},
+ {V3D_VIEW_STEPRIGHT, "ROLLTRIGHT", 0, "Roll Right", "Roll the view around to the Right"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
static int viewroll_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
@@ -4025,12 +4197,17 @@ static int viewroll_exec(bContext *C, wmOperator *op)
rv3d = ar->regiondata;
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
- const float angle = RNA_float_get(op->ptr, "angle");
+ int type = RNA_enum_get(op->ptr, "type");
+ float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle);
float mousevec[3];
float quat_new[4];
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ if (type == V3D_VIEW_STEPLEFT) {
+ angle = -angle;
+ }
+
normalize_v3_v3(mousevec, rv3d->viewinv[2]);
negate_v3(mousevec);
view_roll_angle(ar, quat_new, rv3d->viewquat, mousevec, angle);
@@ -4052,7 +4229,9 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
- if (RNA_struct_property_is_set(op->ptr, "angle")) {
+ bool use_angle = RNA_enum_get(op->ptr, "type") != 0;
+
+ if (use_angle || RNA_struct_property_is_set(op->ptr, "angle")) {
viewroll_exec(C, op);
}
else {
@@ -4090,6 +4269,8 @@ static void viewroll_cancel(bContext *C, wmOperator *op)
void VIEW3D_OT_view_roll(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Roll";
ot->description = "Roll the view";
@@ -4106,7 +4287,10 @@ void VIEW3D_OT_view_roll(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- ot->prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
+ ot->prop = prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "type", prop_view_roll_items, 0, "Roll Angle Source", "How roll angle is calculated");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
static EnumPropertyItem prop_view_pan_items[] = {
@@ -4259,32 +4443,16 @@ static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op))
static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
View3D *v3d = CTX_wm_view3d(C);
- Image *ima = NULL;
+ Image *ima;
BGpic *bgpic;
- char name[MAX_ID_NAME - 2];
-
- /* check input variables */
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- char path[FILE_MAX];
-
- RNA_string_get(op->ptr, "filepath", path);
- ima = BKE_image_load_exists(path);
- }
- else if (RNA_struct_property_is_set(op->ptr, "name")) {
- RNA_string_get(op->ptr, "name", name);
- ima = (Image *)BKE_libblock_find_name(ID_IM, name);
- }
+ ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
+ /* may be NULL, continue anyway */
+
bgpic = background_image_add(C);
-
- if (ima) {
- bgpic->ima = ima;
-
- id_us_plus(&ima->id);
-
- if (!(v3d->flag & V3D_DISPBGPICS))
- v3d->flag |= V3D_DISPBGPICS;
- }
+ bgpic->ima = ima;
+
+ v3d->flag |= V3D_DISPBGPICS;
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
@@ -4310,7 +4478,8 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
- RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file");
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
@@ -4360,16 +4529,6 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* ********************* set clipping operator ****************** */
-static void calc_clipping_plane(float clip[6][4], const BoundBox *clipbb)
-{
- int val;
-
- for (val = 0; val < 4; val++) {
- normal_tri_v3(clip[val], clipbb->vec[val], clipbb->vec[val == 3 ? 0 : val + 1], clipbb->vec[val + 4]);
- clip[val][3] = -dot_v3v3(clip[val], clipbb->vec[val]);
- }
-}
-
static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float mat[4][4])
{
BoundBox clipbb_local;
@@ -4382,7 +4541,7 @@ static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float
mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
}
- calc_clipping_plane(clip_local, &clipbb_local);
+ ED_view3d_clipping_calc_from_boundbox(clip_local, &clipbb_local, is_negative_m4(mat));
}
void ED_view3d_clipping_local(RegionView3D *rv3d, float mat[4][4])
@@ -4463,7 +4622,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ RegionView3D *rv3d = ar->regiondata;
bool flip;
bool depth_used = false;
@@ -4498,11 +4657,30 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- float *fp = ED_view3d_cursor3d_get(scene, v3d);
- ED_view3d_cursor3d_position(C, fp, mval);
+ float *fp_curr = ED_view3d_cursor3d_get(scene, v3d);
+ float fp_prev[3];
+
+ copy_v3_v3(fp_prev, fp_curr);
+
+ ED_view3d_cursor3d_position(C, fp_curr, mval);
- if (v3d && v3d->localvd)
+ /* offset the cursor lock to avoid jumping to new offset */
+ if (v3d->ob_centre_cursor) {
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ float co_curr[2], co_prev[2];
+
+ if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+ (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+ {
+ rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f);
+ rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f);
+ }
+ }
+
+ if (v3d->localvd)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
else
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
@@ -4512,7 +4690,7 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
{
ED_view3d_cursor3d_update(C, event->mval);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void VIEW3D_OT_cursor3d(wmOperatorType *ot)
@@ -4526,7 +4704,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* api callbacks */
ot->invoke = view3d_cursor3d_invoke;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = ED_operator_region_view3d_active;
/* flags */
// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -4640,28 +4818,43 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
view3d_update_depths_rect(ar, &depth_temp, &rect);
depth_close = view3d_depth_near(&depth_temp);
- if (depth_temp.depths) MEM_freeN(depth_temp.depths);
+ MEM_SAFE_FREE(depth_temp.depths);
return depth_close;
}
-/* XXX todo Zooms in on a border drawn by the user */
-bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d,
- const int mval[2], float mouse_worldloc[3],
- const bool alphaoverride, const float fallback_depth_pt[3])
+/**
+ * Get the world-space 3d location from a screen-space 2d point.
+ *
+ * \param mval: Input screen-space pixel location.
+ * \param mouse_worldloc: Output world-space loction.
+ * \param fallback_depth_pt: Use this points depth when no depth can be found.
+ */
+bool ED_view3d_autodist(
+ Scene *scene, ARegion *ar, View3D *v3d,
+ const int mval[2], float mouse_worldloc[3],
+ const bool alphaoverride, const float fallback_depth_pt[3])
{
bglMats mats; /* ZBuffer depth vars */
float depth_close;
double cent[2], p[3];
+ int margin_arr[] = {0, 2, 4};
+ int i;
+ bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
bgl_get_mats(&mats);
ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
- depth_close = view_autodist_depth_margin(ar, mval, 4);
+ /* Attempt with low margin's first */
+ i = 0;
+ do {
+ depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
+ depth_ok = (depth_close != FLT_MAX);
+ } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
- if (depth_close != FLT_MAX) {
- cent[0] = (double)mval[0];
- cent[1] = (double)mval[1];
+ if (depth_ok) {
+ cent[0] = (double)mval[0] + 0.5;
+ cent[1] = (double)mval[1] + 0.5;
if (gluUnProject(cent[0], cent[1], depth_close,
mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
@@ -4712,8 +4905,8 @@ bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_world
if (depth == FLT_MAX)
return false;
- cent[0] = (double)mval[0];
- cent[1] = (double)mval[1];
+ cent[0] = (double)mval[0] + 0.5;
+ cent[1] = (double)mval[1] + 0.5;
bgl_get_mats(&mats);
@@ -4932,8 +5125,9 @@ BGpic *ED_view3D_background_image_new(View3D *v3d)
{
BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image");
- bgpic->size = 5.0;
- bgpic->blend = 0.5;
+ bgpic->rotation = 0.0f;
+ bgpic->size = 5.0f;
+ bgpic->blend = 0.5f;
bgpic->iuser.fie_ima = 2;
bgpic->iuser.ok = 1;
bgpic->view = 0; /* 0 for all */
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index da77c4f75f7..e6910cf9303 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -39,7 +39,7 @@
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BIF_gl.h"
@@ -51,6 +51,7 @@
#include "PIL_time.h" /* smoothview */
+#include "UI_interface.h"
#include "UI_resources.h"
#include "view3d_intern.h" /* own include */
@@ -283,26 +284,37 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar),
glEnd();
}
-static void fly_update_header(bContext *C, FlyInfo *fly)
+static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly)
{
-#define HEADER_LENGTH 256
- char header[HEADER_LENGTH];
-
- BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB/Return: confirm, "
- "RMB/Esc: cancel, "
- "MMB: pan, "
- "WASDQE: direction, "
- "Alt: slow, "
- "Ctrl: free look, "
- "X: Upright x axis (%s), "
- "Z: Upright z axis (%s), "
- "(+/- | Wheel): speed"),
-
- WM_bool_as_string(fly->xlock != FLY_AXISLOCK_STATE_OFF),
- WM_bool_as_string(fly->zlock != FLY_AXISLOCK_STATE_OFF));
+ char header[UI_MAX_DRAW_STR];
+ char buf[UI_MAX_DRAW_STR];
+
+ char *p = buf;
+ int available_len = sizeof(buf);
+
+#define WM_MODALKEY(_id) \
+ WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
+
+ BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, "
+ "%s: pan enable, "
+ "%s|%s|%s|%s|%s|%s: direction, "
+ "%s: slow, %s: free look, "
+ "%s: Upright x axis (%s), "
+ "%s: Upright z axis (%s), "
+ "%s: increase speed, %s: decrease speed"),
+ WM_MODALKEY(FLY_MODAL_CONFIRM), WM_MODALKEY(FLY_MODAL_CANCEL),
+ WM_MODALKEY(FLY_MODAL_PAN_ENABLE),
+ WM_MODALKEY(FLY_MODAL_DIR_FORWARD), WM_MODALKEY(FLY_MODAL_DIR_LEFT),
+ WM_MODALKEY(FLY_MODAL_DIR_BACKWARD), WM_MODALKEY(FLY_MODAL_DIR_RIGHT),
+ WM_MODALKEY(FLY_MODAL_DIR_UP), WM_MODALKEY(FLY_MODAL_DIR_DOWN),
+ WM_MODALKEY(FLY_MODAL_PRECISION_ENABLE), WM_MODALKEY(FLY_MODAL_FREELOOK_ENABLE),
+ WM_MODALKEY(FLY_MODAL_AXIS_LOCK_X), WM_bool_as_string(fly->xlock != FLY_AXISLOCK_STATE_OFF),
+ WM_MODALKEY(FLY_MODAL_AXIS_LOCK_Z), WM_bool_as_string(fly->zlock != FLY_AXISLOCK_STATE_OFF),
+ WM_MODALKEY(FLY_MODAL_ACCELERATE), WM_MODALKEY(FLY_MODAL_DECELERATE));
+
+#undef WM_MODALKEY
ED_area_headerprint(CTX_wm_area(C), header);
-#undef HEADER_LENGTH
}
/* FlyInfo->state */
@@ -410,7 +422,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
/* center the mouse, probably the UI mafia are against this but without its quite annoying */
WM_cursor_warp(win, fly->ar->winrct.xmin + fly->center_mval[0], fly->ar->winrct.ymin + fly->center_mval[1]);
- fly_update_header(C, fly);
+ fly_update_header(C, op, fly);
return 1;
}
@@ -449,7 +461,7 @@ static int flyEnd(bContext *C, FlyInfo *fly)
return OPERATOR_CANCELLED;
}
-static void flyEvent(bContext *C, FlyInfo *fly, const wmEvent *event)
+static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *event)
{
if (event->type == TIMER && event->customdata == fly->timer) {
fly->redraw = 1;
@@ -657,7 +669,7 @@ static void flyEvent(bContext *C, FlyInfo *fly, const wmEvent *event)
fly->xlock = FLY_AXISLOCK_STATE_ACTIVE;
fly->xlock_momentum = 0.0;
}
- fly_update_header(C, fly);
+ fly_update_header(C, op, fly);
break;
case FLY_MODAL_AXIS_LOCK_Z:
if (fly->zlock != FLY_AXISLOCK_STATE_OFF)
@@ -666,7 +678,7 @@ static void flyEvent(bContext *C, FlyInfo *fly, const wmEvent *event)
fly->zlock = FLY_AXISLOCK_STATE_ACTIVE;
fly->zlock_momentum = 0.0;
}
- fly_update_header(C, fly);
+ fly_update_header(C, op, fly);
break;
case FLY_MODAL_PRECISION_ENABLE:
@@ -806,7 +818,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
/* Rotate about the relative up vec */
- axis_angle_to_quat(tmp_quat, upvec, (float)moffset[1] * time_redraw * -FLY_ROTATE_FAC);
+ axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -FLY_ROTATE_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF)
@@ -836,7 +848,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
}
/* Rotate about the relative up vec */
- axis_angle_to_quat(tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC);
+ axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * FLY_ROTATE_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF)
@@ -982,7 +994,7 @@ static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- flyEvent(C, fly, event);
+ flyEvent(C, op, fly, event);
WM_event_add_modal_handler(C, op);
@@ -1008,7 +1020,7 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
fly->redraw = 0;
- flyEvent(C, fly, event);
+ flyEvent(C, op, fly, event);
if (fly->ndof) { /* 3D mouse overrules [2D mouse + timer] */
if (event->type == NDOF_MOTION) {
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index a88724a1cdd..42895a7530b 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -32,21 +32,16 @@
#include <stdio.h>
#include <stdlib.h>
-#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_main.h"
-#include "BKE_modifier.h"
-#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_editmesh.h"
@@ -110,8 +105,8 @@ static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d)
if (scene->obedit && (scene->obedit->lay & v3d->lay) == 0) {
int bit;
for (bit = 0; bit < 32; bit++) {
- if (scene->obedit->lay & (1 << bit)) {
- v3d->lay |= 1 << bit;
+ if (scene->obedit->lay & (1u << bit)) {
+ v3d->lay |= (1u << bit);
break;
}
}
@@ -166,8 +161,8 @@ static int view3d_layers_exec(bContext *C, wmOperator *op)
v3d->layact = 1 << nr;
else if ((v3d->lay & v3d->layact) == 0) {
for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
}
@@ -262,7 +257,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
Object *obedit = CTX_data_edit_object(C);
uiBlock *block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_view3d_header_buttons, NULL);
+ UI_block_func_handle_set(block, do_view3d_header_buttons, NULL);
if (obedit && (obedit->type == OB_MESH)) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -270,13 +265,13 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
- uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL,
+ uiDefIconButBitS(block, UI_BTYPE_TOGGLE, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
TIP_("Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection"));
- uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL,
+ uiDefIconButBitS(block, UI_BTYPE_TOGGLE, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click expands/contracts selection"));
- uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL,
+ uiDefIconButBitS(block, UI_BTYPE_TOGGLE, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
}
@@ -302,10 +297,10 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
RNA_pointer_create(&scene->id, &RNA_Scene, scene, &sceneptr);
block = uiLayoutGetBlock(layout);
- uiBlockSetHandleFunc(block, do_view3d_header_buttons, NULL);
+ UI_block_func_handle_set(block, do_view3d_header_buttons, NULL);
/* other buttons: */
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
/* mode */
if (ob) {
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 84ac4f7d02d..95c0ef92680 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -41,16 +41,15 @@ struct BoundBox;
struct DerivedMesh;
struct Object;
struct SmokeDomainSettings;
-struct ViewContext;
struct bAnimVizSettings;
struct bContext;
struct bMotionPath;
struct bPoseChannel;
-struct bScreen;
struct Mesh;
struct wmNDOFMotionData;
struct wmOperatorType;
struct wmWindowManager;
+struct wmKeyConfig;
/* drawing flags: */
enum {
@@ -163,7 +162,9 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* drawmesh.c */
void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
struct Object *ob, struct DerivedMesh *dm, const int draw_flags);
-void draw_mesh_face_select(struct RegionView3D *rv3d, struct Mesh *me, struct DerivedMesh *dm);
+void draw_mesh_face_select(
+ struct RegionView3D *rv3d, struct Mesh *me, struct DerivedMesh *dm,
+ bool draw_select_edges);
void draw_mesh_paint_weight_faces(struct DerivedMesh *dm, const bool do_light,
void *facemask_cb, void *user_data);
void draw_mesh_paint_vcolor_faces(struct DerivedMesh *dm, const bool use_light,
@@ -175,6 +176,9 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, struct DerivedMesh *dm,
void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
struct Object *ob, struct DerivedMesh *dm, const int draw_flags);
+/* drawsimdebug.c */
+void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar);
+
/* view3d_draw.c */
void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
@@ -201,7 +205,7 @@ void VIEW3D_OT_localview(struct wmOperatorType *ot);
void VIEW3D_OT_game_start(struct wmOperatorType *ot);
-bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb);
void ED_view3d_smooth_view_ex(
@@ -218,8 +222,8 @@ void ED_view3d_smooth_view(
const float *ofs, const float *quat, const float *dist, const float *lens,
const int smooth_viewtx);
-void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect);
-void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d);
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
+void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 7e101fea138..8c668b2b8e0 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -42,6 +42,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_appdir.h"
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -77,7 +78,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- BLI_make_file_string("/", str, BLI_temp_dir_base(), "copybuffer.blend");
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(str, op->reports);
BKE_report(op->reports, RPT_INFO, "Copied selected objects to buffer");
@@ -102,7 +103,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
- BLI_make_file_string("/", str, BLI_temp_dir_base(), "copybuffer.blend");
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
if (BKE_copybuffer_paste(C, str, op->reports)) {
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -296,8 +297,11 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD6, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / -12);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / 12);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD9, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "type", V3D_VIEW_STEPRIGHT);
+ RNA_float_set(kmi->ptr, "angle", (float)M_PI);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
@@ -309,8 +313,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPUP);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPDOWN);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / -12);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / 12);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
/* active aligned, replaces '*' key in 2.4x */
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT, 0);
@@ -343,8 +347,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "use_all_regions", false);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", M_PI / -2);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI / 2);
+ RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", -M_PI_2);
+ RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI_2);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 75c1d9dcd22..ba0626c58ea 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -497,7 +497,7 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f;
if (rv3d->persp == RV3D_CAMOB) {
/* ortho camera needs offset applied */
- const float zoomfac = BKE_screen_view3d_zoom_to_fac((float)rv3d->camzoom) * 4.0f;
+ const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 4.0f;
dx += rv3d->camdx * zoomfac;
dy += rv3d->camdy * zoomfac;
}
@@ -605,6 +605,14 @@ void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pm
mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
}
+void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obmat[4][4], float pmat[4][4])
+{
+ float vmat[4][4];
+
+ mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, obmat);
+ mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
+}
+
/**
* Uses window coordinates (x,y) and depth component z to find a point in
* modelspace */
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 9d0a70ea9d0..98b1e846c70 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -70,7 +70,7 @@
* \param r_co hit location.
* \param r_no hit normal (optional).
* \param co_ss Screenspace coordinate.
- * \param use_depth Snap to the closest element, use when using more then one snap type.
+ * \param use_depth Snap to the closest element, use when using more than one snap type.
* \param use_obedit Use editmode cage.
* \param use_vert Snap to verts.
* \param use_edge Snap to edges.
@@ -122,12 +122,10 @@ static bool ED_view3d_snap_ray(bContext *C, float r_co[3],
bool ret;
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
struct Object *obedit = CTX_data_edit_object(C);
/* try snap edge, then face if it fails */
- ret = snapObjectsRayEx(scene, NULL, v3d, ar, obedit, SCE_SNAP_MODE_FACE,
+ ret = snapObjectsRayEx(scene, NULL, NULL, NULL, obedit, SCE_SNAP_MODE_FACE,
NULL, NULL,
ray_start, ray_normal, &ray_dist,
NULL, &dist_px, r_co, r_no_dummy, SNAP_ALL);
@@ -190,8 +188,8 @@ typedef struct RulerInfo {
/* wm state */
wmWindow *win;
ScrArea *sa;
- ARegion *ar;
void *draw_handle_pixel;
+ ARegion *ar; /* re-assigned every modal update */
} RulerInfo;
/* -------------------------------------------------------------------- */
@@ -438,7 +436,7 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
UnitSettings *unit = &scene->unit;
RulerItem *ruler_item;
RulerInfo *ruler_info = arg;
- RegionView3D *rv3d = ruler_info->ar->regiondata;
+ RegionView3D *rv3d = ar->regiondata;
// ARegion *ar = ruler_info->ar;
const float cap_size = 4.0f;
const float bg_margin = 4.0f * U.pixelsize;
@@ -552,10 +550,11 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
/* draw text (bg) */
glColor4ubv(color_back);
- uiSetRoundBox(UI_CNR_ALL);
- uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin,
- pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
- bg_radius);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox(
+ pos[0] - bg_margin, pos[1] - bg_margin,
+ pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
+ bg_radius);
/* draw text */
glColor3ubv(color_text);
BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
@@ -641,8 +640,8 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
/* draw text (bg) */
glColor4ubv(color_back);
- uiSetRoundBox(UI_CNR_ALL);
- uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin,
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox(pos[0] - bg_margin, pos[1] - bg_margin,
pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
bg_radius);
/* draw text */
@@ -801,12 +800,13 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
ruler_info->win = win;
ruler_info->sa = sa;
- ruler_info->ar = ar;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
ruler_info, REGION_DRAW_POST_PIXEL);
view3d_ruler_header_update(sa);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
WM_cursor_modal_set(win, BC_CROSSCURSOR);
WM_event_add_modal_handler(C, op);
@@ -827,16 +827,18 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool do_draw = false;
int exit_code = OPERATOR_RUNNING_MODAL;
RulerInfo *ruler_info = op->customdata;
- ScrArea *sa = ruler_info->sa;
- ARegion *ar = ruler_info->ar;
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
- /* its possible to change spaces while running the operator [#34894] */
- if (UNLIKELY(ar != CTX_wm_region(C))) {
+ /* its possible to change spaces while running the operator [#34894] */
+ if (UNLIKELY(sa != ruler_info->sa)) {
exit_code = OPERATOR_FINISHED;
goto exit;
}
+ ruler_info->ar = ar;
+
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
@@ -1022,6 +1024,13 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
if (do_draw) {
view3d_ruler_header_update(sa);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index ad716d1a98f..69e354d87c7 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -93,7 +93,6 @@
#include "ED_mball.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "view3d_intern.h" /* own include */
@@ -726,7 +725,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv,
}
static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
Mesh *me = ob->data;
rcti rect;
@@ -1143,7 +1142,7 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int
const char *name = ob->id.name + 2;
BLI_strncpy(object_mouse_select_menu_data[i].idname, name, MAX_ID_NAME - 2);
- object_mouse_select_menu_data[i].icon = uiIconFromID(&ob->id);
+ object_mouse_select_menu_data[i].icon = UI_icon_from_id(&ob->id);
}
{
@@ -1181,20 +1180,23 @@ static short selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const short
static short selectbuffer_ret_hits_9(unsigned int *buffer, const short hits15, const short hits9)
{
const int offs = 4 * hits15;
- memcpy(buffer, buffer + offs, 4 * hits9);
+ memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int));
return hits9;
}
static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, const short hits9, const short hits5)
{
const int offs = 4 * hits15 + 4 * hits9;
- memcpy(buffer, buffer + offs, 4 * hits5);
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
return hits5;
}
/* we want a select buffer with bones, if there are... */
/* so check three selection levels and compare */
-static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate)
+static short mixed_bones_object_selectbuffer(
+ ViewContext *vc, unsigned int *buffer, const int mval[2],
+ bool use_cycle, bool enumerate,
+ bool *r_do_nearest)
{
rcti rect;
int offs;
@@ -1205,16 +1207,24 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
View3D *v3d = vc->v3d;
/* define if we use solid nearest select or not */
- if (v3d->drawtype > OB_WIRE) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
- do_nearest = false;
+ if (use_cycle) {
+ if (v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+ }
+ else {
+ if (v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
}
}
- copy_v2_v2_int(last_mval, mval);
- if (p_do_nearest)
- *p_do_nearest = do_nearest;
+ if (r_do_nearest) {
+ *r_do_nearest = do_nearest;
+ }
do_nearest = do_nearest && !enumerate;
@@ -1346,7 +1356,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
ViewContext vc;
Base *basact = NULL;
- unsigned int buffer[4 * MAXPICKBUF];
+ unsigned int buffer[MAXPICKBUF];
int hits;
bool do_nearest;
@@ -1354,7 +1364,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
view3d_set_viewcontext(C, &vc);
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1444,12 +1454,12 @@ static bool mouse_select(bContext *C, const int mval[2],
}
}
else {
- unsigned int buffer[4 * MAXPICKBUF];
+ unsigned int buffer[MAXPICKBUF];
bool do_nearest;
/* if objects have posemode set, the bones are in the same selection buffer */
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
@@ -1642,39 +1652,48 @@ static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, con
}
static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me;
MVert *mvert;
struct ImBuf *ibuf;
unsigned int *rt;
int a, index;
char *selar;
- int sx = BLI_rcti_size_x(rect) + 1;
- int sy = BLI_rcti_size_y(rect) + 1;
+ const int size[2] = {
+ BLI_rcti_size_x(rect) + 1,
+ BLI_rcti_size_y(rect) + 1};
me = vc->obact->data;
- if (me == NULL || me->totvert == 0 || sx * sy <= 0)
+ if ((me == NULL) || (me->totvert == 0) || (size[0] * size[1] <= 0)) {
return OPERATOR_CANCELLED;
-
+ }
if (extend == false && select)
paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false);
if (use_zbuf) {
selar = MEM_callocN(me->totvert + 1, "selar");
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
- ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
+ ibuf = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
rt = ibuf->rect;
- glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+ glReadPixels(
+ rect->xmin + vc->ar->winrct.xmin,
+ rect->ymin + vc->ar->winrct.ymin,
+ size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ if (ENDIAN_ORDER == B_ENDIAN) {
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+ WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
- a = sx * sy;
+ a = size[0] * size[1];
while (a--) {
if (*rt) {
- index = WM_framebuffer_to_index(*rt);
- if (index <= me->totvert) selar[index] = 1;
+ index = *rt;
+ if (index <= me->totvert) {
+ selar[index] = 1;
+ }
}
rt++;
}
@@ -1877,7 +1896,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
MetaElem *ml;
int a;
- unsigned int buffer[4 * MAXPICKBUF];
+ unsigned int buffer[MAXPICKBUF];
short hits;
hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
@@ -1911,7 +1930,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
EditBone *ebone;
int a;
- unsigned int buffer[4 * MAXPICKBUF];
+ unsigned int buffer[MAXPICKBUF];
short hits;
hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
@@ -1972,7 +1991,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
ED_armature_sync_selection(arm->edbo);
- return OPERATOR_CANCELLED;
+ return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend)
@@ -2007,8 +2026,8 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
}
/* selection buffer now has bones potentially too, so we add MAXPICKBUF */
- vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
- hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect, false);
+ vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer");
+ hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, false);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
@@ -2186,7 +2205,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
static bool mouse_weight_paint_vertex_select(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
- const int use_zbuf = (v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me = obact->data; /* already checked for NULL */
unsigned int index = 0;
@@ -2454,7 +2473,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv,
}
static void paint_vertsel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
Mesh *me = ob->data;
bool bbsel;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 8e6deeddc39..8bb84d00c83 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -31,20 +31,19 @@
#include "DNA_armature_types.h"
-#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_lattice.h"
+#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_object.h"
-#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -53,6 +52,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "ED_object.h"
#include "ED_transverts.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
@@ -60,6 +60,7 @@
#include "view3d_intern.h"
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]);
+static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
/* *********************** operators ******************** */
@@ -205,8 +206,9 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Object *obact = CTX_data_active_object(C);
View3D *v3d = CTX_wm_view3d(C);
TransVertStore tvs = {NULL};
TransVert *tv;
@@ -221,7 +223,14 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
cursor_global = ED_view3d_cursor3d_get(scene, v3d);
if (use_offset) {
- snap_curs_to_sel_ex(C, center_global);
+ if ((v3d && v3d->around == V3D_ACTIVE) &&
+ snap_calc_active_center(C, true, center_global))
+ {
+ /* pass */
+ }
+ else {
+ snap_curs_to_sel_ex(C, center_global);
+ }
sub_v3_v3v3(offset_global, cursor_global, center_global);
}
@@ -260,59 +269,98 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
ED_transverts_update_obedit(&tvs, obedit);
ED_transverts_free(&tvs);
}
- else {
+ else if (obact && (obact->mode & OB_MODE_POSE)) {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
- {
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan;
- bArmature *arm = ob->data;
- float cursor_local[3];
-
- invert_m4_m4(ob->imat, ob->obmat);
- mul_v3_m4v3(cursor_local, ob->imat, cursor_global);
+ bPoseChannel *pchan;
+ bArmature *arm = obact->data;
+ float cursor_local[3];
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_SELECTED) {
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if ((pchan->bone->flag & BONE_CONNECTED) == 0) {
- /* Get position in pchan (pose) space. */
- float cursor_pose[3];
+ invert_m4_m4(obact->imat, obact->obmat);
+ mul_v3_m4v3(cursor_local, obact->imat, cursor_global);
- if (use_offset) {
- mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]);
- add_v3_v3(cursor_pose, offset_global);
+ for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_SELECTED) &&
+ (PBONE_VISIBLE(arm, pchan->bone)) &&
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
+ (pchan->bone->flag & BONE_CONNECTED) == 0)
+ {
+ pchan->bone->flag |= BONE_TRANSFORM;
+ }
+ else {
+ pchan->bone->flag &= ~BONE_TRANSFORM;
+ }
+ }
- mul_m4_v3(ob->imat, cursor_pose);
- BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
- }
- else {
- BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose);
- }
+ for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) &&
+ /* check that our parents not transformed (if we have one) */
+ ((pchan->bone->parent &&
+ BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0))
+ {
+ /* Get position in pchan (pose) space. */
+ float cursor_pose[3];
- /* copy new position */
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
- pchan->loc[0] = cursor_pose[0];
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
- pchan->loc[1] = cursor_pose[1];
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
- pchan->loc[2] = cursor_pose[2];
+ if (use_offset) {
+ mul_v3_m4v3(cursor_pose, obact->obmat, pchan->pose_mat[3]);
+ add_v3_v3(cursor_pose, offset_global);
- /* auto-keyframing */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
- }
- /* if the bone has a parent and is connected to the parent,
- * don't do anything - will break chain unless we do auto-ik.
- */
- }
- }
+ mul_m4_v3(obact->imat, cursor_pose);
+ BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
}
- ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ else {
+ BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose);
+ }
+
+ /* copy new position */
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
+ pchan->loc[0] = cursor_pose[0];
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
+ pchan->loc[1] = cursor_pose[1];
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
+ pchan->loc[2] = cursor_pose[2];
+
+ /* auto-keyframing */
+ ED_autokeyframe_pchan(C, scene, obact, pchan, ks);
}
- else {
+ }
+
+ for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone->flag &= ~BONE_TRANSFORM;
+ }
+
+ obact->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
+
+ DAG_id_tag_update(&obact->id, OB_RECALC_DATA);
+ }
+ else {
+ struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
+ Main *bmain = CTX_data_main(C);
+
+ ListBase ctx_data_list;
+ CollectionPointerLink *ctx_ob;
+ Object *ob;
+
+ CTX_data_selected_editable_objects(C, &ctx_data_list);
+
+ /* reset flags */
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ ob->flag &= ~OB_DONE;
+ }
+
+ /* tag objects we're transforming */
+ for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ ob = ctx_ob->ptr.data;
+ ob->flag |= OB_DONE;
+ }
+
+ for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ ob = ctx_ob->ptr.data;
+
+ if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) {
+
float cursor_parent[3]; /* parent-relative */
if (use_offset) {
@@ -323,11 +371,11 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
}
sub_v3_v3(cursor_parent, ob->obmat[3]);
-
+
if (ob->parent) {
float originmat[3][3];
BKE_object_where_is_calc_ex(scene, NULL, ob, originmat);
-
+
invert_m3_m3(imat, originmat);
mul_m3_v3(imat, cursor_parent);
}
@@ -344,7 +392,8 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
- CTX_DATA_END;
+
+ BLI_freelistN(&ctx_data_list);
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -592,45 +641,60 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
/* ********************************************** */
-static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
+/* this could be exported to be a generic function
+ * see: calculateCenterActive */
+
+static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3])
{
Object *obedit = CTX_data_edit_object(C);
- Object *obact = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- float *curs;
-
- curs = ED_view3d_cursor3d_get(scene, v3d);
if (obedit) {
- if (obedit->type == OB_MESH) {
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* check active */
- BMEditSelection ese;
-
- if (BM_select_history_active_get(em->bm, &ese)) {
- BM_editselection_center(&ese, curs);
- }
-
- mul_m4_v3(obedit->obmat, curs);
+ if (ED_object_editmode_calc_active_center(obedit, select_only, r_center)) {
+ mul_m4_v3(obedit->obmat, r_center);
+ return true;
}
- else if (obedit->type == OB_LATTICE) {
- BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
+ }
+ else {
+ Object *ob = CTX_data_active_object(C);
- if (actbp) {
- copy_v3_v3(curs, actbp->vec);
- mul_m4_v3(obedit->obmat, curs);
+ if (ob) {
+ if (ob->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ if (pchan) {
+ if (!select_only || (pchan->bone->flag & BONE_SELECTED)) {
+ copy_v3_v3(r_center, pchan->pose_head);
+ mul_m4_v3(ob->obmat, r_center);
+ return true;
+ }
+ }
+ }
+ else {
+ if (!select_only || (ob->flag & SELECT)) {
+ copy_v3_v3(r_center, ob->obmat[3]);
+ return true;
+ }
}
}
}
+
+ return false;
+}
+
+static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ float *curs;
+
+ curs = ED_view3d_cursor3d_get(scene, v3d);
+
+ if (snap_calc_active_center(C, false, curs)) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ return OPERATOR_FINISHED;
+ }
else {
- if (obact) {
- copy_v3_v3(curs, obact->obmat[3]);
- }
+ return OPERATOR_CANCELLED;
}
-
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
- return OPERATOR_FINISHED;
}
void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index 3f7f12d2020..065c336d001 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -39,12 +39,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -118,7 +117,7 @@ static void view3d_panel_operator_redo(const bContext *C, Panel *pa)
uiLayoutSetEnabled(pa->layout, false);
/* note, blockfunc is a default but->func, use Handle func to allow button callbacks too */
- uiBlockSetHandleFunc(block, ED_undo_operator_repeat_cb_evt, op);
+ UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
view3d_panel_operator_redo_operator(C, pa, op);
}
@@ -151,20 +150,19 @@ static void operator_call_cb(struct bContext *C, void *arg_listbase, void *arg2)
static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
{
- GHashIterator *iter = WM_operatortype_iter();
+ GHashIterator iter;
- for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
if (BLI_strcasestr(ot->name, str)) {
if (WM_operator_poll((bContext *)C, ot)) {
- if (false == uiSearchItemAdd(items, ot->name, ot, 0))
+ if (false == UI_search_item_add(items, ot->name, ot, 0))
break;
}
}
}
- BLI_ghashIterator_free(iter);
}
@@ -180,18 +178,18 @@ static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase)
/* clear initial search string, then all items show */
search[0] = 0;
- block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
- uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_SEARCH_MENU);
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
/* fake button, it holds space for search items */
- uiDefBut(block, LABEL, 0, "", 10, 15, uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, 19, 0, 0, "");
- uiButSetSearchFunc(but, operator_search_cb, arg_listbase, operator_call_cb, NULL);
+ UI_but_func_search_set(but, operator_search_cb, arg_listbase, operator_call_cb, NULL);
- uiBoundsBlock(block, 6);
- uiBlockSetDirection(block, UI_DOWN);
- uiEndBlock(C, block);
+ UI_block_bounds_set_normal(block, 6);
+ UI_block_direction_set(block, UI_DIR_DOWN);
+ UI_block_end(C, block);
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_OPEN;
@@ -218,7 +216,7 @@ static void view3d_panel_tool_shelf(const bContext *C, Panel *pa)
CustomTool *ct;
for (ct = st->toolshelf.first; ct; ct = ct->next) {
- if (0 == strncmp(context, ct->context, OP_MAX_TYPENAME)) {
+ if (STREQLEN(context, ct->context, OP_MAX_TYPENAME)) {
col = uiLayoutColumn(pa->layout, true);
uiItemFullO(col, ct->opname, NULL, ICON_NONE, NULL, WM_OP_INVOKE_REGION_WIN, 0);
}
@@ -236,7 +234,7 @@ void view3d_toolshelf_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel tools");
strcpy(pt->idname, "VIEW3D_PT_tool_shelf");
strcpy(pt->label, N_("Tool Shelf"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_tool_shelf;
BLI_addtail(&art->paneltypes, pt);
}
@@ -248,7 +246,7 @@ void view3d_tool_props_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel last operator");
strcpy(pt->idname, "VIEW3D_PT_last_operator");
strcpy(pt->label, N_("Operator"));
- strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw_header = view3d_panel_operator_redo_header;
pt->draw = view3d_panel_operator_redo;
BLI_addtail(&art->paneltypes, pt);
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 7d3f7ce282e..0f05f4e52dd 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -37,9 +37,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BLI_callbacks.h"
#include "BKE_anim.h"
#include "BKE_action.h"
@@ -51,11 +49,11 @@
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_draw.h"
#include "GPU_select.h"
#include "WM_api.h"
@@ -64,14 +62,16 @@
#include "ED_screen.h"
#include "ED_armature.h"
-#include "RE_engine.h"
#ifdef WITH_GAMEENGINE
-#include "BL_System.h"
+# include "BLI_listbase.h"
+# include "BLI_callbacks.h"
+
+# include "GPU_draw.h"
+
+# include "BL_System.h"
#endif
-#include "RNA_access.h"
-#include "RNA_define.h"
#include "view3d_intern.h" /* own include */
@@ -137,6 +137,9 @@ struct SmoothView3DStore {
struct SmoothView3DState org; /* original */
bool to_camera;
+
+ /* When smooth-view is enabled, store the 'rv3d->view' here,
+ * assign back when the view motion is completed. */
char org_view;
double time_allowed;
@@ -180,12 +183,12 @@ void ED_view3d_smooth_view_ex(
/* if smoothview runs multiple times... */
if (rv3d->sms == NULL) {
view3d_smooth_view_state_backup(&sms.org, v3d, rv3d);
- sms.org_view = rv3d->view;
}
else {
sms.org = rv3d->sms->org;
- sms.org_view = rv3d->sms->org_view;
}
+ sms.org_view = rv3d->view;
+
/* sms.to_camera = false; */ /* initizlized to zero anyway */
/* note on camera locking, this is a little confusing but works ok.
@@ -356,6 +359,7 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d);
ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
@@ -382,6 +386,10 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv;
ED_view3d_camera_lock_sync(v3d, rv3d);
+ if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
+ }
+
}
if (rv3d->viewlock & RV3D_BOXVIEW)
@@ -492,26 +500,22 @@ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
Object *camera_ob = v3d ? v3d->camera : scene->camera;
float r_co[3]; /* the new location to apply */
+ float r_scale; /* only for ortho cameras */
if (camera_ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active camera");
return OPERATOR_CANCELLED;
}
- else if (camera_ob->type != OB_CAMERA) {
- BKE_report(op->reports, RPT_ERROR, "Object not a camera");
- return OPERATOR_CANCELLED;
- }
- else if (((Camera *)camera_ob->data)->type == R_ORTHO) {
- BKE_report(op->reports, RPT_ERROR, "Orthographic cameras not supported");
- return OPERATOR_CANCELLED;
- }
/* this function does all the important stuff */
- if (BKE_camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co)) {
-
+ if (BKE_camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co, &r_scale)) {
ObjectTfmProtectedChannels obtfm;
float obmat_new[4][4];
+ if ((camera_ob->type == OB_CAMERA) && (((Camera *)camera_ob->data)->type == CAM_ORTHO)) {
+ ((Camera *)camera_ob->data)->ortho_scale = r_scale;
+ }
+
copy_m4_m4(obmat_new, camera_ob->obmat);
copy_v3_v3(obmat_new[3], r_co);
@@ -609,6 +613,20 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
/* ********************************** */
+void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
+{
+ int val;
+
+ for (val = 0; val < 4; val++) {
+ normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
+ if (UNLIKELY(is_flip)) {
+ negate_v3(clip[val]);
+ }
+
+ clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
+ }
+}
+
void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect)
{
float modelview[4][4];
@@ -644,16 +662,7 @@ void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, co
((float *)modelview)[a] = mats->modelview[a];
flip_sign = is_negative_m4(modelview);
- /* then plane equations */
- for (val = 0; val < 4; val++) {
-
- normal_tri_v3(planes[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
-
- if (flip_sign)
- negate_v3(planes[val]);
-
- planes[val][3] = -dot_v3v3(planes[val], bb->vec[val]);
- }
+ ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
}
static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
@@ -683,7 +692,7 @@ static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
return false;
}
-bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
{
/* return 1: draw */
@@ -692,7 +701,7 @@ bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float ob
if (bb == NULL) return true;
if (bb->flag & BOUNDBOX_DISABLED) return true;
- mul_m4_m4m4(persmatob, rv3d->persmat, obmat);
+ mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
return view3d_boundbox_clip_m4(bb, persmatob);
}
@@ -705,7 +714,7 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
}
-float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
+float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y)
{
ViewDepths *vd = vc->rv3d->depths;
@@ -724,16 +733,19 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d)
rv3d->depths->damaged = true;
}
-void ED_view3d_dist_range_get(struct View3D *v3d,
- float r_dist_range[2])
+void ED_view3d_dist_range_get(
+ const View3D *v3d,
+ float r_dist_range[2])
{
r_dist_range[0] = v3d->grid * 0.001f;
r_dist_range[1] = v3d->far * 10.0f;
}
/* copies logic of get_view3d_viewplane(), keep in sync */
-bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend,
- const bool use_ortho_factor)
+bool ED_view3d_clip_range_get(
+ const View3D *v3d, const RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend,
+ const bool use_ortho_factor)
{
CameraParams params;
@@ -753,8 +765,9 @@ bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta,
}
/* also exposed in previewrender.c */
-bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
- rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
+bool ED_view3d_viewplane_get(
+ const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
+ rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
{
CameraParams params;
@@ -775,7 +788,13 @@ bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy
*/
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
{
- float viewdist = rv3d->dist;
+ float viewdist;
+
+ if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
+ return;
+ }
+
+ viewdist = rv3d->dist;
/* special exception for ortho camera (viewdist isnt used for perspective cameras) */
if (dist != 0.0f) {
@@ -792,7 +811,7 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
/**
* \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect)
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
@@ -891,13 +910,28 @@ char ED_view3d_lock_view_from_index(int index)
}
+char ED_view3d_axis_view_opposite(char view)
+{
+ switch (view) {
+ case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK;
+ case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT;
+ case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT;
+ case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT;
+ case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM;
+ case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP;
+ }
+
+ return RV3D_VIEW_USER;
+}
+
+
bool ED_view3d_lock(RegionView3D *rv3d)
{
return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
}
/* don't set windows active in here, is used by renderwin too */
-void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
+void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d)
{
if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */
if (v3d->camera) {
@@ -936,7 +970,7 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
}
else if (v3d->ob_centre_cursor) {
float vec[3];
- copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, v3d));
+ copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d));
translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
use_lock_ofs = true;
}
@@ -1047,7 +1081,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
- rctf rect, selrect;
+ rctf rect;
short hits;
const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
const bool do_passes = do_nearest && GPU_select_query_check_active();
@@ -1064,8 +1098,6 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
else {
BLI_rctf_rcti_copy(&rect, input);
}
-
- selrect = rect;
view3d_winmatrix_set(ar, v3d, &rect);
mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
@@ -1079,9 +1111,9 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
ED_view3d_clipping_set(vc->rv3d);
if (do_passes)
- GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
else
- GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_ALL, 0);
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0);
view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
@@ -1089,7 +1121,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
/* second pass, to get the closest object to camera */
if (do_passes) {
- GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
@@ -1196,7 +1228,7 @@ static bool view3d_localview_init(
View3D *v3d = sa->spacedata.first;
Base *base;
float min[3], max[3], box[3], mid[3];
- float size = 0.0f, size_persp = 0.0f, size_ortho = 0.0f;
+ float size = 0.0f;
unsigned int locallay;
bool ok = false;
@@ -1234,13 +1266,6 @@ static bool view3d_localview_init(
sub_v3_v3v3(box, max, min);
size = max_fff(box[0], box[1], box[2]);
-
- /* do not zoom closer than the near clipping plane */
- size = max_ff(size, v3d->near * 1.5f);
-
- /* perspective size (we always switch out of camera view so no need to use its lens size) */
- size_persp = ED_view3d_radius_to_persp_dist(focallength_to_fov(v3d->lens, DEFAULT_SENSOR_WIDTH), size / 2.0f) * VIEW3D_MARGIN;
- size_ortho = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
}
if (ok == true) {
@@ -1257,6 +1282,7 @@ static bool view3d_localview_init(
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
+ bool ok_dist = true;
/* new view values */
Object *camera_old = NULL;
@@ -1272,25 +1298,24 @@ static bool view3d_localview_init(
camera_old = v3d->camera;
}
- /* perspective should be a bit farther away to look nice */
- if (rv3d->persp != RV3D_ORTHO) {
- dist_new = size_persp;
- }
- else {
- dist_new = size_ortho;
+ if (rv3d->persp == RV3D_ORTHO) {
+ if (size < 0.0001f) {
+ ok_dist = false;
+ }
}
- /* correction for window aspect ratio */
- if (ar->winy > 2 && ar->winx > 2) {
- float asp = (float)ar->winx / (float)ar->winy;
- if (asp < 1.0f) asp = 1.0f / asp;
- dist_new *= asp;
+ if (ok_dist) {
+ dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+ if (rv3d->persp == RV3D_PERSP) {
+ /* don't zoom closer than the near clipping plane */
+ dist_new = max_ff(dist_new, v3d->near * 1.5f);
+ }
}
ED_view3d_smooth_view_ex(
wm, win, sa,
v3d, ar, camera_old, NULL,
- ofs_new, NULL, &dist_new, NULL,
+ ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL,
smooth_viewtx);
}
}
@@ -1545,18 +1570,21 @@ static void game_set_commmandline_options(GameData *gm)
static int game_engine_poll(bContext *C)
{
+ bScreen *screen;
/* we need a context and area to launch BGE
* it's a temporary solution to avoid crash at load time
* if we try to auto run the BGE. Ideally we want the
* context to be set as soon as we load the file. */
if (CTX_wm_window(C) == NULL) return 0;
- if (CTX_wm_screen(C) == NULL) return 0;
- if (CTX_wm_area(C) == NULL) return 0;
+ if ((screen = CTX_wm_screen(C)) == NULL) return 0;
if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)
return 0;
+ if (!BKE_scene_uses_blender_game(screen->scene))
+ return 0;
+
return 1;
}
@@ -1567,20 +1595,18 @@ bool ED_view3d_context_activate(bContext *C)
ARegion *ar;
/* sa can be NULL when called from python */
- if (sa == NULL || sa->spacetype != SPACE_VIEW3D)
- for (sa = sc->areabase.first; sa; sa = sa->next)
- if (sa->spacetype == SPACE_VIEW3D)
- break;
+ if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
+ sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
+ }
- if (!sa)
+ if (sa == NULL) {
return false;
+ }
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_WINDOW)
- break;
-
- if (!ar)
+ ar = BKE_area_find_region_active_win(sa);
+ if (ar == NULL) {
return false;
+ }
/* bad context switch .. */
CTX_wm_area_set(C, sa);
@@ -1693,21 +1719,116 @@ void VIEW3D_OT_game_start(wmOperatorType *ot)
/* ************************************** */
-float ED_view3d_pixel_size(RegionView3D *rv3d, const float co[3])
+float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
{
- return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
+ return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
}
-float ED_view3d_radius_to_persp_dist(const float angle, const float radius)
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
{
- return (radius / 2.0f) * fabsf(1.0f / cosf((((float)M_PI) - angle) / 2.0f));
+ return radius * (1.0f / tanf(angle / 2.0f));
}
-float ED_view3d_radius_to_ortho_dist(const float lens, const float radius)
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
{
return radius / (DEFAULT_SENSOR_WIDTH / lens);
}
+/**
+ * Return a new RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param ar Can be NULL if \a use_aspect is false.
+ * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect Increase the distance to account for non 1:1 view aspect.
+ * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
+float ED_view3d_radius_to_dist(
+ const View3D *v3d, const ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius)
+{
+ float dist;
+
+ BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
+ BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
+
+ if (persp == RV3D_ORTHO) {
+ dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
+ }
+ else {
+ float lens, sensor_size, zoom;
+ float angle;
+
+ if (persp == RV3D_CAMOB) {
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ params.clipsta = v3d->near;
+ params.clipend = v3d->far;
+ BKE_camera_params_from_object(&params, v3d->camera);
+
+ lens = params.lens;
+ sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+
+ /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
+ zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
+ }
+ else {
+ lens = v3d->lens;
+ sensor_size = DEFAULT_SENSOR_WIDTH;
+ zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ }
+
+ angle = focallength_to_fov(lens, sensor_size);
+
+ /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
+ angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
+
+ dist = ED_view3d_radius_to_dist_persp(angle, radius);
+ }
+
+ if (use_aspect) {
+ const RegionView3D *rv3d = ar->regiondata;
+
+ float winx, winy;
+
+ if (persp == RV3D_CAMOB) {
+ /* camera frame x/y in pixels */
+ winx = ar->winx / rv3d->viewcamtexcofac[0];
+ winy = ar->winy / rv3d->viewcamtexcofac[1];
+ }
+ else {
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ if (winx && winy) {
+ float aspect = winx / winy;
+ if (aspect < 1.0f) {
+ aspect = 1.0f / aspect;
+ }
+ dist *= aspect;
+ }
+ }
+
+ return dist;
+}
+
/* view matrix properties utilities */
/* unused */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index c54948b23c6..0bda6e37fd1 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -26,8 +26,6 @@
/* defines VIEW3D_OT_navigate - walk modal operator */
-//#define NDOF_WALK_DEBUG
-//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -40,10 +38,8 @@
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "BIF_gl.h"
@@ -56,10 +52,19 @@
#include "PIL_time.h" /* smoothview */
+#include "UI_interface.h"
#include "UI_resources.h"
#include "view3d_intern.h" /* own include */
+//#define NDOF_WALK_DEBUG
+//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+
+#define USE_TABLET_SUPPORT
+
+/* ensure the target position is one we can reach, see: T45771 */
+#define USE_PIXELSIZE_NATIVE_SUPPORT
+
/* prototypes */
static float getVelocityZeroTime(const float gravity, const float velocity);
@@ -152,6 +157,8 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"},
{WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump Stop", "Stop pushing jump"},
+ {WALK_MODAL_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+
{0, NULL, 0, NULL, NULL}};
wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Walk Modal");
@@ -220,8 +227,7 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
}
-typedef struct WalkTeleport
-{
+typedef struct WalkTeleport {
eWalkTeleportState state;
float duration; /* from user preferences */
float origin[3];
@@ -277,6 +283,14 @@ typedef struct WalkInfo {
/* mouse reverse */
bool is_reversed;
+#ifdef USE_TABLET_SUPPORT
+ /* check if we had a cursor event before */
+ bool is_cursor_first;
+
+ /* tablet devices (we can't relocate the cursor) */
+ bool is_cursor_absolute;
+#endif
+
/* gravity system */
eWalkGravityState gravity_state;
float gravity;
@@ -335,27 +349,42 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a
glEnd();
}
-static void walk_update_header(bContext *C, WalkInfo *walk)
+static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk)
{
- bool gravity = walk->navigation_mode == WALK_MODE_GRAVITY ||
- (walk->teleport.state == WALK_TELEPORT_STATE_ON &&
- walk->teleport.navigation_mode == WALK_MODE_GRAVITY);
-
-#define HEADER_LENGTH 256
- char header[HEADER_LENGTH];
-
- BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB/Return: confirm, Esc/RMB: cancel, "
- "Tab: gravity (%s), "
- "WASD: move around, "
- "Shift: fast, Alt: slow, "
- "QE: up and down, MMB/Space: teleport, V: jump, "
- "Pad +/Wheel Up: increase speed, Pad -/Wheel Down: decrease speed"),
- WM_bool_as_string(gravity));
+ const bool gravity = (walk->navigation_mode == WALK_MODE_GRAVITY) ||
+ ((walk->teleport.state == WALK_TELEPORT_STATE_ON) &&
+ (walk->teleport.navigation_mode == WALK_MODE_GRAVITY));
+ char header[UI_MAX_DRAW_STR];
+ char buf[UI_MAX_DRAW_STR];
+
+ char *p = buf;
+ int available_len = sizeof(buf);
+
+#define WM_MODALKEY(_id) \
+ WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
+
+ BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, "
+ "%s: gravity (%s), "
+ "%s|%s|%s|%s: move around, "
+ "%s: fast, %s: slow, "
+ "%s|%s: up and down, "
+ "%s: teleport, %s: jump, "
+ "%s: increase speed, %s: decrease speed"),
+ WM_MODALKEY(WALK_MODAL_CONFIRM), WM_MODALKEY(WALK_MODAL_CANCEL),
+ WM_MODALKEY(WALK_MODAL_TOGGLE), WM_bool_as_string(gravity),
+ WM_MODALKEY(WALK_MODAL_DIR_FORWARD), WM_MODALKEY(WALK_MODAL_DIR_LEFT),
+ WM_MODALKEY(WALK_MODAL_DIR_BACKWARD), WM_MODALKEY(WALK_MODAL_DIR_RIGHT),
+ WM_MODALKEY(WALK_MODAL_FAST_ENABLE), WM_MODALKEY(WALK_MODAL_SLOW_ENABLE),
+ WM_MODALKEY(WALK_MODAL_DIR_UP), WM_MODALKEY(WALK_MODAL_DIR_DOWN),
+ WM_MODALKEY(WALK_MODAL_TELEPORT), WM_MODALKEY(WALK_MODAL_JUMP),
+ WM_MODALKEY(WALK_MODAL_ACCELERATE), WM_MODALKEY(WALK_MODAL_DECELERATE));
+
+#undef WM_MODALKEY
+
ED_area_headerprint(CTX_wm_area(C), header);
-#undef HEADER_LENGTH
}
-static void walk_navigation_mode_set(bContext *C, WalkInfo *walk, eWalkMethod mode)
+static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk, eWalkMethod mode)
{
if (mode == WALK_MODE_FREE) {
walk->navigation_mode = WALK_MODE_FREE;
@@ -366,7 +395,7 @@ static void walk_navigation_mode_set(bContext *C, WalkInfo *walk, eWalkMethod mo
walk->gravity_state = WALK_GRAVITY_STATE_START;
}
- walk_update_header(C, walk);
+ walk_update_header(C, op, walk);
}
/**
@@ -493,16 +522,16 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->speed = 0.0f;
walk->is_fast = false;
walk->is_slow = false;
- walk->grid = 1.f / walk->scene->unit.scale_length;
+ walk->grid = (walk->scene->unit.system == USER_UNIT_NONE) ? 1.f : 1.f / walk->scene->unit.scale_length;
/* user preference settings */
walk->teleport.duration = U.walk_navigation.teleport_time;
walk->mouse_speed = U.walk_navigation.mouse_speed;
if ((U.walk_navigation.flag & USER_WALK_GRAVITY))
- walk_navigation_mode_set(C, walk, WALK_MODE_GRAVITY);
+ walk_navigation_mode_set(C, op, walk, WALK_MODE_GRAVITY);
else
- walk_navigation_mode_set(C, walk, WALK_MODE_FREE);
+ walk_navigation_mode_set(C, op, walk, WALK_MODE_FREE);
walk->view_height = U.walk_navigation.view_height;
walk->jump_height = U.walk_navigation.jump_height;
@@ -520,6 +549,12 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
+#ifdef USE_TABLET_SUPPORT
+ walk->is_cursor_first = true;
+
+ walk->is_cursor_absolute = false;
+#endif
+
walk->active_directions = 0;
#ifdef NDOF_WALK_DRAW_TOOMUCH
@@ -546,6 +581,16 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->center_mval[0] = walk->ar->winx * 0.5f;
walk->center_mval[1] = walk->ar->winy * 0.5f;
+#ifdef USE_PIXELSIZE_NATIVE_SUPPORT
+ walk->center_mval[0] += walk->ar->winrct.xmin;
+ walk->center_mval[1] += walk->ar->winrct.ymin;
+
+ WM_cursor_compatible_xy(win, &walk->center_mval[0], &walk->center_mval[1]);
+
+ walk->center_mval[0] -= walk->ar->winrct.xmin;
+ walk->center_mval[1] -= walk->ar->winrct.ymin;
+#endif
+
copy_v2_v2_int(walk->prev_mval, walk->center_mval);
WM_cursor_warp(win,
@@ -587,10 +632,16 @@ static int walkEnd(bContext *C, WalkInfo *walk)
/* restore the cursor */
WM_cursor_modal_restore(win);
- /* center the mouse */
- WM_cursor_warp(win,
- walk->ar->winrct.xmin + walk->center_mval[0],
- walk->ar->winrct.ymin + walk->center_mval[1]);
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_absolute == false)
+#endif
+ {
+ /* center the mouse */
+ WM_cursor_warp(
+ win,
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+ }
if (walk->state == WALK_CONFIRM) {
MEM_freeN(walk);
@@ -611,13 +662,42 @@ static bool wm_event_is_last_mousemove(const wmEvent *event)
return true;
}
-static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const wmEvent *event)
+static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent *event)
{
if (event->type == TIMER && event->customdata == walk->timer) {
walk->redraw = true;
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_first) {
+ /* wait until we get the 'warp' event */
+ if ((walk->center_mval[0] == event->mval[0]) &&
+ (walk->center_mval[1] == event->mval[1]))
+ {
+ walk->is_cursor_first = false;
+ }
+ else {
+ /* note, its possible the system isn't giving us the warp event
+ * ideally we shouldn't have to worry about this, see: T45361 */
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_warp(win,
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+ }
+ return;
+ }
+
+ if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) {
+ walk->is_cursor_absolute = true;
+ copy_v2_v2_int(walk->prev_mval, event->mval);
+ copy_v2_v2_int(walk->center_mval, event->mval);
+ /* without this we can't turn 180d */
+ CLAMP_MIN(walk->mouse_speed, 4.0f);
+ }
+#endif /* USE_TABLET_SUPPORT */
+
+
walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
walk->moffset[1] += event->mval[1] - walk->prev_mval[1];
@@ -628,6 +708,12 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
{
walk->redraw = true;
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_absolute) {
+ /* pass */
+ }
+ else
+#endif
if (wm_event_is_last_mousemove(event)) {
wmWindow *win = CTX_wm_window(C);
@@ -820,7 +906,7 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
teleport->duration = U.walk_navigation.teleport_time;
teleport->navigation_mode = walk->navigation_mode;
- walk_navigation_mode_set(C, walk, WALK_MODE_FREE);
+ walk_navigation_mode_set(C, op, walk, WALK_MODE_FREE);
copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
@@ -843,10 +929,10 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
case WALK_MODAL_TOGGLE:
if (walk->navigation_mode == WALK_MODE_GRAVITY) {
- walk_navigation_mode_set(C, walk, WALK_MODE_FREE);
+ walk_navigation_mode_set(C, op, walk, WALK_MODE_FREE);
}
else { /* WALK_MODE_FREE */
- walk_navigation_mode_set(C, walk, WALK_MODE_GRAVITY);
+ walk_navigation_mode_set(C, op, walk, WALK_MODE_GRAVITY);
}
break;
}
@@ -869,7 +955,7 @@ static float getVelocityZeroTime(const float gravity, const float velocity)
return velocity / gravity;
}
-static int walkApply(bContext *C, WalkInfo *walk)
+static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
{
#define WALK_ROTATE_FAC 2.2f /* more is faster */
#define WALK_TOP_LIMIT DEG2RADF(85.0f)
@@ -1182,7 +1268,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
if (t >= 1.0f) {
t = 1.0f;
walk->teleport.state = WALK_TELEPORT_STATE_OFF;
- walk_navigation_mode_set(C, walk, walk->teleport.navigation_mode);
+ walk_navigation_mode_set(C, op, walk, walk->teleport.navigation_mode);
}
mul_v3_v3fl(new_loc, walk->teleport.direction, t);
@@ -1299,7 +1385,7 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event->type == TIMER && event->customdata == walk->timer) {
- walkApply(C, walk);
+ walkApply(C, op, walk);
}
do_draw |= walk->redraw;
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 3ad5d94efd6..42aa6a0a3a3 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
../../gpu
../../ikplugin
@@ -30,6 +31,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -54,4 +56,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index 4f47062e3a3..0f34ce546de 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -31,22 +31,28 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
+ '../../gpu',
'../../ikplugin',
'../../makesdna',
'../../makesrna',
- '../../gpu',
'../../windowmanager',
]
defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 008022a9859..2b295b85da0 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -44,20 +44,24 @@
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h" /* PET modes */
+#include "BLI_alloca.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
+#include "BLI_memarena.h"
#include "BKE_nla.h"
+#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
#include "BKE_particle.h"
#include "BKE_unit.h"
#include "BKE_mask.h"
+#include "BKE_report.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -82,7 +86,7 @@
#include "RNA_access.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "transform.h"
@@ -92,14 +96,17 @@
#define MAX_INFO_LEN 256
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
-static int doEdgeSlide(TransInfo *t, float perc);
-static int doVertSlide(TransInfo *t, float perc);
+static void doEdgeSlide(TransInfo *t, float perc);
+static void doVertSlide(TransInfo *t, float perc);
-static void drawEdgeSlide(const struct bContext *C, TransInfo *t);
-static void drawVertSlide(const struct bContext *C, TransInfo *t);
+static void drawEdgeSlide(TransInfo *t);
+static void drawVertSlide(TransInfo *t);
static void len_v3_ensure(float v[3], const float length);
static void postInputRotation(TransInfo *t, float values[3]);
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around);
+static void initSnapSpatial(TransInfo *t, float r_snap[3]);
+
/* Transform Callbacks */
static void initBend(TransInfo *t);
@@ -137,6 +144,9 @@ static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]);
static void initMaskShrinkFatten(TransInfo *t);
static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]);
+static void initGPShrinkFatten(TransInfo *t);
+static void applyGPShrinkFatten(TransInfo *t, const int mval[2]);
+
static void initTrackball(TransInfo *t);
static void applyTrackball(TransInfo *t, const int mval[2]);
@@ -158,6 +168,7 @@ static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
static void initBoneRoll(TransInfo *t);
static void applyBoneRoll(TransInfo *t, const int mval[2]);
+static void initEdgeSlide_ex(TransInfo *t, bool use_double_side);
static void initEdgeSlide(TransInfo *t);
static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
static void applyEdgeSlide(TransInfo *t, const int mval[2]);
@@ -199,6 +210,12 @@ static bool transdata_check_local_center(TransInfo *t, short around)
);
}
+bool transdata_check_local_islands(TransInfo *t, short around)
+{
+ return ((around == V3D_LOCAL) && (
+ (t->obedit && ELEM(t->obedit->type, OB_MESH))));
+}
+
/* ************************** SPACE DEPENDANT CODE **************************** */
void setTransformViewMatrices(TransInfo *t)
@@ -223,6 +240,38 @@ void setTransformViewMatrices(TransInfo *t)
calculateCenter2D(t);
}
+void setTransformViewAspect(TransInfo *t, float r_aspect[3])
+{
+ copy_v3_fl(r_aspect, 1.0f);
+
+ if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->sa->spacedata.first;
+
+ if (t->options & CTX_MASK) {
+ ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
+ }
+ else if (t->options & CTX_PAINT_CURVE) {
+ /* pass */
+ }
+ else {
+ ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]);
+ }
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ SpaceClip *sclip = t->sa->spacedata.first;
+
+ if (t->options & CTX_MOVIECLIP) {
+ ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
+ }
+ else {
+ ED_space_clip_get_aspect(sclip, &r_aspect[0], &r_aspect[1]);
+ }
+ }
+ else if (t->spacetype == SPACE_IPO) {
+ /* depemds on context of usage */
+ }
+}
+
static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
{
float divx, divy;
@@ -270,30 +319,25 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
r_vec[0] = dx;
r_vec[1] = dy;
}
- else { const float mval_f[2] = {(float)dx, (float)dy};
+ else {
+ const float mval_f[2] = {(float)dx, (float)dy};
ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
}
}
else if (t->spacetype == SPACE_IMAGE) {
- float aspx, aspy;
-
if (t->options & CTX_MASK) {
convertViewVec2D_mask(t->view, r_vec, dx, dy);
- ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
else if (t->options & CTX_PAINT_CURVE) {
r_vec[0] = dx;
r_vec[1] = dy;
-
- aspx = aspy = 1.0;
}
else {
convertViewVec2D(t->view, r_vec, dx, dy);
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
- r_vec[0] *= aspx;
- r_vec[1] *= aspy;
+ r_vec[0] *= t->aspect[0];
+ r_vec[1] *= t->aspect[1];
}
else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
convertViewVec2D(t->view, r_vec, dx, dy);
@@ -302,8 +346,6 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
}
else if (t->spacetype == SPACE_CLIP) {
- float aspx, aspy;
-
if (t->options & CTX_MASK) {
convertViewVec2D_mask(t->view, r_vec, dx, dy);
}
@@ -311,21 +353,8 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
convertViewVec2D(t->view, r_vec, dx, dy);
}
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
- }
- else if (t->options & CTX_MASK) {
- /* TODO - NOT WORKING, this isnt so bad since its only display aspect */
- ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
- }
- else {
- /* should never happen, quiet warnings */
- BLI_assert(0);
- aspx = aspy = 1.0f;
- }
-
- r_vec[0] *= aspx;
- r_vec[1] *= aspy;
+ r_vec[0] *= t->aspect[0];
+ r_vec[1] *= t->aspect[1];
}
else {
printf("%s: called in an invalid context\n", __func__);
@@ -347,15 +376,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
SpaceImage *sima = t->sa->spacedata.first;
if (t->options & CTX_MASK) {
- float aspx, aspy;
float v[2];
- ED_space_image_get_aspect(sima, &aspx, &aspy);
-
- copy_v2_v2(v, vec);
-
- v[0] = v[0] / aspx;
- v[1] = v[1] / aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
@@ -369,11 +393,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
adr[1] = vec[1];
}
else {
- float aspx, aspy, v[2];
+ float v[2];
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
- v[0] = vec[0] / aspx;
- v[1] = vec[1] / aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
}
@@ -418,15 +441,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
MovieClip *clip = ED_space_clip_get_clip(sc);
if (clip) {
- float aspx, aspy;
float v[2];
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
-
- copy_v2_v2(v, vec);
-
- v[0] = v[0] / aspx;
- v[1] = v[1] / aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
@@ -441,13 +459,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
}
}
else if (t->options & CTX_MOVIECLIP) {
- float v[2], aspx, aspy;
-
- copy_v2_v2(v, vec);
- ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
+ float v[2];
- v[0] /= aspx;
- v[1] /= aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
}
@@ -503,7 +518,6 @@ void applyAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) {
SpaceImage *sima = t->sa->spacedata.first;
- float aspx, aspy;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -513,28 +527,13 @@ void applyAspectRatio(TransInfo *t, float vec[2])
vec[1] *= height;
}
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- vec[0] /= aspx;
- vec[1] /= aspy;
+ vec[0] /= t->aspect[0];
+ vec[1] /= t->aspect[1];
}
else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- SpaceClip *sc = t->sa->spacedata.first;
- float aspx, aspy;
-
-
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
-
- vec[0] /= aspx;
- vec[1] /= aspy;
- }
- else if (t->options & CTX_MASK) {
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
-
- vec[0] /= aspx;
- vec[1] /= aspy;
- }
+ vec[0] /= t->aspect[0];
+ vec[1] /= t->aspect[1];
}
}
}
@@ -543,7 +542,6 @@ void removeAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
SpaceImage *sima = t->sa->spacedata.first;
- float aspx, aspy;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -553,31 +551,23 @@ void removeAspectRatio(TransInfo *t, float vec[2])
vec[1] /= height;
}
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- vec[0] *= aspx;
- vec[1] *= aspy;
+ vec[0] *= t->aspect[0];
+ vec[1] *= t->aspect[1];
}
else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- SpaceClip *sc = t->sa->spacedata.first;
- float aspx = 1.0f, aspy = 1.0f;
-
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
- }
- else if (t->options & CTX_MASK) {
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
- }
-
- vec[0] *= aspx;
- vec[1] *= aspy;
+ vec[0] *= t->aspect[0];
+ vec[1] *= t->aspect[1];
}
}
}
static void viewRedrawForce(const bContext *C, TransInfo *t)
{
- if (t->spacetype == SPACE_VIEW3D) {
+ if (t->options & CTX_GPENCIL_STROKES) {
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ }
+ else if (t->spacetype == SPACE_VIEW3D) {
if (t->options & CTX_PAINT_CURVE) {
wmWindow *window = CTX_wm_window(C);
WM_paint_cursor_tag_redraw(window, t->ar);
@@ -660,8 +650,11 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
/* redraw UV editor */
- if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+ if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) &&
+ (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+ {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
/* XXX temp, first hack to get auto-render in compositor work (ton) */
WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
@@ -710,7 +703,6 @@ static void view_editmove(unsigned short UNUSED(event))
switch (event) {
case WHEELUPMOUSE:
-
if (G.qual & LR_SHIFTKEY) {
if (G.qual & LR_ALTKEY) {
G.qual &= ~LR_SHIFTKEY;
@@ -776,35 +768,40 @@ static void view_editmove(unsigned short UNUSED(event))
/* ************************************************* */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-#define TFM_MODAL_CANCEL 1
-#define TFM_MODAL_CONFIRM 2
-#define TFM_MODAL_TRANSLATE 3
-#define TFM_MODAL_ROTATE 4
-#define TFM_MODAL_RESIZE 5
-#define TFM_MODAL_SNAP_INV_ON 6
-#define TFM_MODAL_SNAP_INV_OFF 7
-#define TFM_MODAL_SNAP_TOGGLE 8
-#define TFM_MODAL_AXIS_X 9
-#define TFM_MODAL_AXIS_Y 10
-#define TFM_MODAL_AXIS_Z 11
-#define TFM_MODAL_PLANE_X 12
-#define TFM_MODAL_PLANE_Y 13
-#define TFM_MODAL_PLANE_Z 14
-#define TFM_MODAL_CONS_OFF 15
-#define TFM_MODAL_ADD_SNAP 16
-#define TFM_MODAL_REMOVE_SNAP 17
-/* 18 and 19 used by numinput, defined in transform.h
- * */
-#define TFM_MODAL_PROPSIZE_UP 20
-#define TFM_MODAL_PROPSIZE_DOWN 21
-#define TFM_MODAL_AUTOIK_LEN_INC 22
-#define TFM_MODAL_AUTOIK_LEN_DEC 23
-
-#define TFM_MODAL_EDGESLIDE_UP 24
-#define TFM_MODAL_EDGESLIDE_DOWN 25
+enum {
+ TFM_MODAL_CANCEL = 1,
+ TFM_MODAL_CONFIRM = 2,
+ TFM_MODAL_TRANSLATE = 3,
+ TFM_MODAL_ROTATE = 4,
+ TFM_MODAL_RESIZE = 5,
+ TFM_MODAL_SNAP_INV_ON = 6,
+ TFM_MODAL_SNAP_INV_OFF = 7,
+ TFM_MODAL_SNAP_TOGGLE = 8,
+ TFM_MODAL_AXIS_X = 9,
+ TFM_MODAL_AXIS_Y = 10,
+ TFM_MODAL_AXIS_Z = 11,
+ TFM_MODAL_PLANE_X = 12,
+ TFM_MODAL_PLANE_Y = 13,
+ TFM_MODAL_PLANE_Z = 14,
+ TFM_MODAL_CONS_OFF = 15,
+ TFM_MODAL_ADD_SNAP = 16,
+ TFM_MODAL_REMOVE_SNAP = 17,
+
+/* 18 and 19 used by numinput, defined in transform.h */
+
+ TFM_MODAL_PROPSIZE_UP = 20,
+ TFM_MODAL_PROPSIZE_DOWN = 21,
+ TFM_MODAL_AUTOIK_LEN_INC = 22,
+ TFM_MODAL_AUTOIK_LEN_DEC = 23,
+
+ TFM_MODAL_EDGESLIDE_UP = 24,
+ TFM_MODAL_EDGESLIDE_DOWN = 25,
/* for analog input, like trackpad */
-#define TFM_MODAL_PROPSIZE 26
+ TFM_MODAL_PROPSIZE = 26,
+/* node editor insert offset (aka auto-offset) direction toggle */
+ TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27,
+};
/* called in transform_ops.c, on each regeneration of keymaps */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
@@ -836,6 +833,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
{TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
{TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
+ {TFM_MODAL_INSERTOFS_TOGGLE_DIR, "INSERTOFS_TOGGLE_DIR", 0, "Toggle Direction for Node Auto-offset", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -849,8 +847,8 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE);
WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE);
@@ -869,8 +867,12 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+ WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
+ WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+ WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
+ WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
@@ -880,7 +882,10 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
-
+
+ /* node editor only */
+ WM_modalkeymap_add_item(keymap, TKEY, KM_PRESS, 0, 0, TFM_MODAL_INSERTOFS_TOGGLE_DIR);
+
return keymap;
}
@@ -888,7 +893,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
{
if (!(t->flag & T_NO_CONSTRAINT)) {
int constraint_axis, constraint_plane;
- int edit_2d = (t->flag & T_2D_EDIT);
+ const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
char axis;
@@ -958,6 +963,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
{
char cmode = constraintModeToChar(t);
bool handled = false;
+ const int modifiers_prev = t->modifiers;
t->redraw |= handleMouseInput(t, &t->mouse, event);
@@ -1001,9 +1007,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_TRANSLATE:
/* only switch when... */
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- restoreTransObjects(t);
initTranslation(t);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1018,9 +1024,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
else {
if (t->obedit && t->obedit->type == OB_MESH) {
if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- restoreTransObjects(t);
/* first try edge slide */
initEdgeSlide(t);
@@ -1032,8 +1038,8 @@ int transformEvent(TransInfo *t, const wmEvent *event)
/* vert slide can fail on unconnected vertices (rare but possible) */
if (t->state == TRANS_CANCEL) {
t->state = TRANS_STARTING;
- resetTransRestrictions(t);
restoreTransObjects(t);
+ resetTransRestrictions(t);
initTranslation(t);
}
initSnapping(t, NULL); // need to reinit after mode change
@@ -1057,15 +1063,14 @@ int transformEvent(TransInfo *t, const wmEvent *event)
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
if (t->mode == TFM_ROTATION) {
- restoreTransObjects(t);
initTrackball(t);
}
else {
- restoreTransObjects(t);
initRotation(t);
}
initSnapping(t, NULL); // need to reinit after mode change
@@ -1083,9 +1088,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
stopConstraint(t);
}
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- restoreTransObjects(t);
initResize(t);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1123,47 +1128,22 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
break;
case TFM_MODAL_AXIS_X:
- if ((t->flag & T_NO_CONSTRAINT) == 0) {
- if (cmode == 'X') {
- stopConstraint(t);
- }
- else {
- if (t->flag & T_2D_EDIT) {
- setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), IFACE_("along X"));
- }
- else {
- setUserConstraint(t, t->current_orientation, (CON_AXIS0), IFACE_("along %s X"));
- }
- }
+ if (!(t->flag & T_NO_CONSTRAINT)) {
+ transform_event_xyz_constraint(t, XKEY, cmode);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Y:
if ((t->flag & T_NO_CONSTRAINT) == 0) {
- if (cmode == 'Y') {
- stopConstraint(t);
- }
- else {
- if (t->flag & T_2D_EDIT) {
- setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), IFACE_("along Y"));
- }
- else {
- setUserConstraint(t, t->current_orientation, (CON_AXIS1), IFACE_("along %s Y"));
- }
- }
+ transform_event_xyz_constraint(t, YKEY, cmode);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Z:
- if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- if (cmode == 'Z') {
- stopConstraint(t);
- }
- else {
- setUserConstraint(t, t->current_orientation, (CON_AXIS2), IFACE_("along %s Z"));
- }
+ if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
+ transform_event_xyz_constraint(t, ZKEY, cmode);
t->redraw |= TREDRAW_HARD;
handled = true;
}
@@ -1235,7 +1215,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
- t->prop_size *= 1.1f;
+ t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
calculatePropRatio(t);
@@ -1245,17 +1225,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
- t->prop_size *= 0.90909090f;
+ t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
- case TFM_MODAL_EDGESLIDE_UP:
- case TFM_MODAL_EDGESLIDE_DOWN:
- t->redraw |= TREDRAW_HARD;
- handled = true;
- break;
case TFM_MODAL_AUTOIK_LEN_INC:
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, 1);
@@ -1270,6 +1245,28 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
+ case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
+ if (t->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+
+ BLI_assert(t->sa->spacetype == t->spacetype);
+
+ if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) {
+ snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT;
+ }
+ else if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_LEFT) {
+ snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_RIGHT;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ t->redraw |= TREDRAW_SOFT;
+ }
+ break;
+ /* Those two are only handled in transform's own handler, see T44634! */
+ case TFM_MODAL_EDGESLIDE_UP:
+ case TFM_MODAL_EDGESLIDE_DOWN:
default:
break;
}
@@ -1340,9 +1337,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case GKEY:
/* only switch when... */
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- restoreTransObjects(t);
initTranslation(t);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1352,9 +1349,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case SKEY:
/* only switch when... */
if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- restoreTransObjects(t);
initResize(t);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1365,15 +1362,14 @@ int transformEvent(TransInfo *t, const wmEvent *event)
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
+ restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
if (t->mode == TFM_ROTATION) {
- restoreTransObjects(t);
initTrackball(t);
}
else {
- restoreTransObjects(t);
initRotation(t);
}
initSnapping(t, NULL); // need to reinit after mode change
@@ -1418,7 +1414,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case PADPLUSKEY:
if (event->alt && t->flag & T_PROP_EDIT) {
- t->prop_size *= 1.1f;
+ t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
calculatePropRatio(t);
@@ -1439,7 +1435,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case PADMINUS:
if (event->alt && t->flag & T_PROP_EDIT) {
- t->prop_size *= 0.90909090f;
+ t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
t->redraw = TREDRAW_HARD;
handled = true;
@@ -1509,6 +1505,13 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
}
+ /* if we change snap options, get the unsnapped values back */
+ if ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) !=
+ (modifiers_prev & (MOD_SNAP | MOD_SNAP_INVERT)))
+ {
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+ }
+
/* Per transform event, if present */
if (t->handleEvent &&
(!handled ||
@@ -1569,7 +1572,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
if (cent3d) {
// Copy center from constraint center. Transform center can be local
- copy_v3_v3(cent3d, t->con.center);
+ copy_v3_v3(cent3d, t->center_global);
}
}
@@ -1716,7 +1719,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
glVertex2fv(cent);
glEnd();
- glTranslatef(mval[0], mval[1], 0);
+ glTranslate2fv((const float *)mval);
glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1);
setlinestyle(0);
@@ -1728,7 +1731,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
case HLP_HARROW:
UI_ThemeColor(TH_VIEW_OVERLAY);
- glTranslatef(mval[0], mval[1], 0);
+ glTranslate2fv((const float *)mval);
glLineWidth(3.0);
drawArrow(RIGHT, 5, 10, 5);
@@ -1738,7 +1741,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
case HLP_VARROW:
UI_ThemeColor(TH_VIEW_OVERLAY);
- glTranslatef(mval[0], mval[1], 0);
+ glTranslate2fv((const float *)mval);
glLineWidth(3.0);
drawArrow(UP, 5, 10, 5);
@@ -1789,7 +1792,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
unsigned char col[3], col2[3];
UI_GetThemeColor3ubv(TH_GRID, col);
- glTranslatef(mval[0], mval[1], 0);
+ glTranslate2fv((const float *)mval);
glLineWidth(3.0);
@@ -1822,8 +1825,8 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
drawSnapping(C, t);
/* edge slide, vert slide */
- drawEdgeSlide(C, t);
- drawVertSlide(C, t);
+ drawEdgeSlide(t);
+ drawVertSlide(t);
}
/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
@@ -1932,7 +1935,11 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
!RNA_property_is_set(op->ptr, prop))
{
- if (t->obedit)
+ if (t->spacetype == SPACE_IPO)
+ ts->proportional_fcurve = proportional;
+ else if (t->spacetype == SPACE_ACTION)
+ ts->proportional_action = proportional;
+ else if (t->obedit)
ts->proportional = proportional;
else if (t->options & CTX_MASK)
ts->proportional_mask = (proportional != PROP_EDIT_OFF);
@@ -1972,8 +1979,8 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if (RNA_struct_find_property(op->ptr, "proportional")) {
- RNA_enum_set(op->ptr, "proportional", proportional);
+ if ((prop = RNA_struct_find_property(op->ptr, "proportional"))) {
+ RNA_property_enum_set(op->ptr, prop, proportional);
RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
RNA_float_set(op->ptr, "proportional_size", t->prop_size);
}
@@ -1983,7 +1990,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
- RNA_property_boolean_set(op->ptr, prop, t->flag & T_MIRROR);
+ RNA_property_boolean_set(op->ptr, prop, (t->flag & T_MIRROR) != 0);
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
@@ -2011,6 +2018,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
}
+
+ {
+ const char *prop_id = NULL;
+ if (t->mode == TFM_SHRINKFATTEN) {
+ prop_id = "use_even_offset";
+ }
+
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
+
+ RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0);
+ }
+ }
}
/* note: caller needs to free 't' on a 0 return */
@@ -2030,6 +2049,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
options |= CTX_TEXTURE;
}
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "gpencil_strokes")) && RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ options |= CTX_GPENCIL_STROKES;
+ }
+ }
t->options = options;
@@ -2050,36 +2075,41 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->launch_event = LEFTMOUSE;
}
+ unit_m3(t->spacemtx);
+
initTransInfo(C, t, op, event);
+ initTransformOrientation(C, t);
if (t->spacetype == SPACE_VIEW3D) {
- //calc_manipulator_stats(curarea);
- initTransformOrientation(C, t);
-
t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_IMAGE) {
- unit_m3(t->spacemtx);
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
//t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_CLIP) {
- unit_m3(t->spacemtx);
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_NODE) {
- unit_m3(t->spacemtx);
/*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
}
- else
- unit_m3(t->spacemtx);
+ else if (t->spacetype == SPACE_IPO) {
+ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ }
createTransData(C, t); // make TransData structs from selection
@@ -2118,6 +2148,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initSnapping(t, op); // Initialize snapping data AFTER mode flags
+ initSnapSpatial(t, t->snap_spatial);
+
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
/* EVIL2: we gave as argument also texture space context bit... was cleared */
/* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
@@ -2162,6 +2194,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
case TFM_MASK_SHRINKFATTEN:
initMaskShrinkFatten(t);
break;
+ case TFM_GPENCIL_SHRINKFATTEN:
+ initGPShrinkFatten(t);
+ break;
case TFM_TRACKBALL:
initTrackball(t);
break;
@@ -2174,18 +2209,28 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
case TFM_BONESIZE:
{ /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
bArmature *arm = t->poseobj->data;
- if (arm->drawtype == ARM_ENVELOPE)
+ if (arm->drawtype == ARM_ENVELOPE) {
initBoneEnvelope(t);
- else
+ t->mode = TFM_BONE_ENVELOPE_DIST;
+ }
+ else {
initBoneSize(t);
+ }
break;
}
case TFM_BONE_ENVELOPE:
initBoneEnvelope(t);
break;
+ case TFM_BONE_ENVELOPE_DIST:
+ initBoneEnvelope(t);
+ t->mode = TFM_BONE_ENVELOPE_DIST;
+ break;
case TFM_EDGE_SLIDE:
- initEdgeSlide(t);
+ {
+ const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
+ initEdgeSlide_ex(t, use_double_side);
break;
+ }
case TFM_VERT_SLIDE:
initVertSlide(t);
break;
@@ -2244,7 +2289,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
return 0;
}
-
/* overwrite initial values if operator supplied a non-null vector */
if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
@@ -2340,8 +2384,12 @@ int transformEnd(bContext *C, TransInfo *t)
/* handle restoring objects */
if (t->state == TRANS_CANCEL) {
/* exception, edge slide transformed UVs too */
- if (t->mode == TFM_EDGE_SLIDE)
+ if (t->mode == TFM_EDGE_SLIDE) {
doEdgeSlide(t, 0.0f);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ doVertSlide(t, 0.0f);
+ }
exit_code = OPERATOR_CANCELLED;
restoreTransObjects(t); // calls recalcData()
@@ -2498,8 +2546,8 @@ static void protectedQuaternionBits(short protectflag, float quat[4], const floa
static void constraintTransLim(TransInfo *t, TransData *td)
{
if (td->con) {
- bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
- bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
+ const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
+ const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
bConstraintOb cob = {NULL};
bConstraint *con;
@@ -2514,7 +2562,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
/* Evaluate valid constraints */
for (con = td->con; con; con = con->next) {
- bConstraintTypeInfo *cti = NULL;
+ const bConstraintTypeInfo *cti = NULL;
ListBase targets = {NULL, NULL};
/* only consider constraint if enabled */
@@ -2601,7 +2649,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
{
if (td->con) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
bConstraintOb cob;
bConstraint *con;
bool do_limit = false;
@@ -2668,7 +2716,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
static void constraintSizeLim(TransInfo *t, TransData *td)
{
if (td->con && td->ext) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
bConstraintOb cob = {NULL};
bConstraint *con;
float size_sign[3], size_abs[3];
@@ -2792,10 +2840,11 @@ static void initBend(TransInfo *t)
t->num.unit_type[0] = B_UNIT_ROTATION;
t->num.unit_type[1] = B_UNIT_LENGTH;
- t->flag |= T_NO_CONSTRAINT;
+ t->flag |= T_NO_CONSTRAINT | T_FREE_CUSTOMDATA;
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
+ calculateCenterGlobal(t);
t->val = 0.0f;
@@ -2870,6 +2919,8 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
values.scale = values.scale / data->warp_init_dist;
}
+ copy_v2_v2(t->values, values.vector);
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN * 2];
@@ -2887,8 +2938,6 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
WM_bool_as_string(is_clamp));
}
- copy_v2_v2(t->values, values.vector);
-
values.angle *= -1.0f;
values.scale *= data->warp_init_dist;
@@ -2943,6 +2992,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3(vec, pivot);
mul_m3_v3(td->smtx, vec);
+
+ /* rotation */
+ if ((t->flag & T_POINTS) == 0) {
+ ElementRotation(t, td, mat, V3D_LOCAL);
+ }
+
+ /* location */
copy_v3_v3(td->loc, vec);
}
@@ -3038,6 +3094,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &value);
+ t->values[0] = value;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -3051,8 +3109,6 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
}
- t->values[0] = value;
-
unit_m3(smat);
// Custom data signals shear direction
@@ -3138,7 +3194,7 @@ static void initResize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
+static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -3183,38 +3239,23 @@ static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
}
}
-/* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */
-#define TX_FLIP_EPS 0.00001f
-BLI_INLINE int tx_sign(const float a)
-{
- return (a < -TX_FLIP_EPS ? 1 : a > TX_FLIP_EPS ? 2 : 3);
-}
-BLI_INLINE int tx_vec_sign_flip(const float a[3], const float b[3])
-{
- return ((tx_sign(a[0]) & tx_sign(b[0])) == 0 ||
- (tx_sign(a[1]) & tx_sign(b[1])) == 0 ||
- (tx_sign(a[2]) & tx_sign(b[2])) == 0);
-}
-
-/* smat is reference matrix, only scaled */
+/**
+ * \a smat is reference matrix only.
+ *
+ * \note this is a tricky area, before making changes see: T29633, T42444
+ */
static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
{
- float vec[3];
-
- copy_v3_v3(vec, mat[0]);
- size[0] = normalize_v3(vec);
- copy_v3_v3(vec, mat[1]);
- size[1] = normalize_v3(vec);
- copy_v3_v3(vec, mat[2]);
- size[2] = normalize_v3(vec);
-
+ float rmat[3][3];
+
+ mat3_to_rot_size(rmat, size, mat);
+
/* first tried with dotproduct... but the sign flip is crucial */
- if (tx_vec_sign_flip(mat[0], smat[0]) ) size[0] = -size[0];
- if (tx_vec_sign_flip(mat[1], smat[1]) ) size[1] = -size[1];
- if (tx_vec_sign_flip(mat[2], smat[2]) ) size[2] = -size[2];
+ if (dot_v3v3(rmat[0], smat[0]) < 0.0f) size[0] = -size[0];
+ if (dot_v3v3(rmat[1], smat[1]) < 0.0f) size[1] = -size[1];
+ if (dot_v3v3(rmat[2], smat[2]) < 0.0f) size[2] = -size[2];
}
-
static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
{
float tmat[3][3], smat[3][3], center[3];
@@ -3330,7 +3371,7 @@ static void applyResize(TransInfo *t, const int mval[2])
ratio = t->values[0];
}
- size[0] = size[1] = size[2] = ratio;
+ copy_v3_fl(size, ratio);
snapGridIncrement(t, size);
@@ -3436,12 +3477,10 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td;
float size[3], mat[3][3];
- float ratio;
int i;
char str[MAX_INFO_LEN];
- ratio = t->values[0];
- size[0] = size[1] = size[2] = ratio;
+ copy_v3_fl(size, t->values[0]);
snapGridIncrement(t, size);
@@ -3546,10 +3585,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
- if (ratio < 0)
- ratio = 0.0f;
- else if (ratio > 1)
- ratio = 1.0f;
+ CLAMP(ratio, 0.0f, 1.0f);
t->values[0] = ratio;
@@ -3918,6 +3954,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
final = angle_wrap_rad(final);
}
+ t->values[0] = final;
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -3934,8 +3972,6 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
- t->values[0] = final;
-
applyRotationValue(t, final, t->axis);
recalcData(t);
@@ -4007,7 +4043,9 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
char str[MAX_INFO_LEN];
size_t ofs = 0;
float axis1[3], axis2[3];
+#if 0 /* UNUSED */
float mat[3][3], totmat[3][3], smat[3][3];
+#endif
float phi[2];
copy_v3_v3(axis1, t->persinv[0]);
@@ -4015,13 +4053,14 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
normalize_v3(axis1);
normalize_v3(axis2);
- phi[0] = t->values[0];
- phi[1] = t->values[1];
+ copy_v2_v2(phi, t->values);
snapGridIncrement(t, phi);
applyNumInput(&t->num, phi);
+ copy_v2_v2(t->values, phi);
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN * 2];
@@ -4039,6 +4078,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
+#if 0 /* UNUSED */
axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
@@ -4046,6 +4086,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
// TRANSFORM_FIX_ME
//copy_m3_m3(t->mat, mat); // used in manipulator
+#endif
applyTrackballValue(t, axis1, axis2, phi);
@@ -4059,6 +4100,38 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
/* -------------------------------------------------------------------- */
/* Transform (Translation) */
+static void initSnapSpatial(TransInfo *t, float r_snap[3])
+{
+ if (t->spacetype == SPACE_VIEW3D) {
+ RegionView3D *rv3d = t->ar->regiondata;
+
+ if (rv3d) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = rv3d->gridview * 1.0f;
+ r_snap[2] = r_snap[1] * 0.1f;
+ }
+ }
+ else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.125f;
+ r_snap[2] = 0.0625f;
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = ED_node_grid_size();
+ r_snap[2] = ED_node_grid_size();
+ }
+ else if (t->spacetype == SPACE_IPO) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 1.0;
+ r_snap[2] = 0.1f;
+ }
+ else {
+ r_snap[0] = 0.0f;
+ r_snap[1] = r_snap[2] = 1.0f;
+ }
+}
+
/** \name Transform Translation
* \{ */
@@ -4066,6 +4139,9 @@ static void initTranslation(TransInfo *t)
{
if (t->spacetype == SPACE_ACTION) {
/* this space uses time translate */
+ BKE_report(t->reports, RPT_ERROR,
+ "Use 'Time_Translate' transform mode instead of 'Translation' mode "
+ "for translating keyframes in Dope Sheet Editor");
t->state = TRANS_CANCEL;
}
@@ -4078,29 +4154,7 @@ static void initTranslation(TransInfo *t)
t->num.flag = 0;
t->num.idx_max = t->idx_max;
- if (t->spacetype == SPACE_VIEW3D) {
- RegionView3D *rv3d = t->ar->regiondata;
-
- if (rv3d) {
- t->snap[0] = 0.0f;
- t->snap[1] = rv3d->gridview * 1.0f;
- t->snap[2] = t->snap[1] * 0.1f;
- }
- }
- else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
- t->snap[0] = 0.0f;
- t->snap[1] = 0.125f;
- t->snap[2] = 0.0625f;
- }
- else if (t->spacetype == SPACE_NODE) {
- t->snap[0] = 0.0f;
- t->snap[1] = ED_node_grid_size() * NODE_GRID_STEPS;
- t->snap[2] = ED_node_grid_size();
- }
- else {
- t->snap[0] = 0.0f;
- t->snap[1] = t->snap[2] = 1.0f;
- }
+ copy_v3_v3(t->snap, t->snap_spatial);
copy_v3_fl(t->num.val_inc, t->snap[1]);
t->num.unit_sys = t->scene->unit.system;
@@ -4118,7 +4172,7 @@ static void initTranslation(TransInfo *t)
}
}
-static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
+static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
{
size_t ofs = 0;
char tvec[NUM_STR_REP_LEN * 3];
@@ -4209,9 +4263,26 @@ static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]
if (t->flag & T_PROP_EDIT_ALL) {
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
+
+ if (t->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+
+ if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
+ const char *str_old = BLI_strdup(str);
+ const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? "right" : "left";
+ char str_km[MAX_INFO_LEN];
+
+ WM_modalkeymap_items_to_string(t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, sizeof(str_km), str_km);
+
+ ofs += BLI_snprintf(str, MAX_INFO_LEN, "Auto-offset set to %s - press %s to toggle direction | %s",
+ str_dir, str_km, str_old);
+
+ MEM_freeN((void *)str_old);
+ }
+ }
}
-static void applyTranslationValue(TransInfo *t, float vec[3])
+static void applyTranslationValue(TransInfo *t, const float vec[3])
{
TransData *td = t->data;
float tvec[3];
@@ -4223,29 +4294,21 @@ static void applyTranslationValue(TransInfo *t, float vec[3])
if (td->flag & TD_SKIP)
continue;
-
+
/* handle snapping rotation before doing the translation */
if (usingSnappingNormal(t)) {
if (validSnappingNormal(t)) {
const float *original_normal;
- float axis[3];
- float quat[4];
float mat[3][3];
- float angle;
/* In pose mode, we want to align normals with Y axis of bones... */
if (t->flag & T_POSE)
original_normal = td->axismtx[1];
else
original_normal = td->axismtx[2];
-
- cross_v3_v3v3(axis, original_normal, t->tsnap.snapNormal);
- angle = saacos(dot_v3v3(original_normal, t->tsnap.snapNormal));
-
- axis_angle_to_quat(quat, axis, angle);
-
- quat_to_mat3(mat, quat);
-
+
+ rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
+
ElementRotation(t, td, mat, V3D_LOCAL);
}
else {
@@ -4371,6 +4434,8 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &distance);
+ t->values[0] = -distance;
+
/* header print for NumInput */
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
@@ -4391,16 +4456,13 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
}
}
BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"),
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
/* done with header string */
-
- t->values[0] = -distance;
-
for (i = 0; i < t->total; i++, td++) {
float tdistance; /* temp dist */
if (td->flag & TD_NOACTION)
@@ -4467,6 +4529,8 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4544,6 +4608,8 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4622,6 +4688,8 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4677,6 +4745,85 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
/* -------------------------------------------------------------------- */
+/* Transform (GPencil Shrink/Fatten) */
+
+/** \name Transform GPencil Strokes Shrink/Fatten
+ * \{ */
+
+static void initGPShrinkFatten(TransInfo *t)
+{
+ t->mode = TFM_GPENCIL_SHRINKFATTEN;
+ t->transform = applyGPShrinkFatten;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+
+static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+{
+ TransData *td = t->data;
+ float ratio;
+ int i;
+ char str[MAX_INFO_LEN];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ t->values[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
+ }
+ else {
+ BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio);
+ }
+
+ for (i = 0; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (td->flag & TD_SKIP)
+ continue;
+
+ if (td->val) {
+ *td->val = td->ival * ratio;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) *td->val = 0.001f;
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_headerprint(t->sa, str);
+}
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
/* Transform (Push/Pull) */
/** \name Transform Push/Pull
@@ -4715,6 +4862,8 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &distance);
+ t->values[0] = distance;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4728,8 +4877,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
}
- t->values[0] = distance;
-
if (t->con.applyRot && t->con.mode & CON_APPLY) {
t->con.applyRot(t, NULL, axis, NULL);
}
@@ -4802,12 +4949,14 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
weight = t->values[0];
- if (weight > 1.0f) weight = 1.0f;
+ CLAMP_MAX(weight, 1.0f);
snapGridIncrement(t, &weight);
applyNumInput(&t->num, &weight);
+ t->values[0] = weight;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4880,12 +5029,14 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
crease = t->values[0];
- if (crease > 1.0f) crease = 1.0f;
+ CLAMP_MAX(crease, 1.0f);
snapGridIncrement(t, &crease);
applyNumInput(&t->num, &crease);
+ t->values[0] = crease;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4956,7 +5107,7 @@ static void initBoneSize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerBoneSize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
+static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
@@ -5019,7 +5170,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
ratio = t->values[0];
}
- size[0] = size[1] = size[2] = ratio;
+ copy_v3_fl(size, ratio);
snapGridIncrement(t, size);
@@ -5027,6 +5178,8 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
constraintNumInput(t, size);
}
+ copy_v3_v3(t->values, size);
+
size_to_mat3(mat, size);
if (t->con.applySize) {
@@ -5093,6 +5246,8 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -5126,6 +5281,312 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
}
/** \} */
+/* -------------------------------------------------------------------- */
+/* Original Data Store */
+
+/** \name Orig-Data Store Utility Functions
+ * \{ */
+
+static void slide_origdata_init_flag(
+ TransInfo *t, SlideOrigData *sod)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+
+ if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
+ /* don't do this at all for non-basis shape keys, too easy to
+ * accidentally break uv maps or vertex colors then */
+ (bm->shapenr <= 1) &&
+ CustomData_has_math(&bm->ldata))
+ {
+ sod->use_origfaces = true;
+ }
+ else {
+ sod->use_origfaces = false;
+ }
+}
+
+static void slide_origdata_init_data(
+ TransInfo *t, SlideOrigData *sod)
+{
+ if (sod->use_origfaces) {
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+
+ sod->origfaces = BLI_ghash_ptr_new(__func__);
+ sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
+ /* we need to have matching customdata */
+ BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
+ }
+}
+
+static void slide_origdata_create_data_vert(
+ BMesh *bm, SlideOrigData *sod,
+ TransDataGenericSlideVert *sv)
+{
+ BMIter liter;
+ int j, l_num;
+ float *loop_weights;
+
+ /* copy face data */
+ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
+ BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
+ l_num = liter.count;
+ loop_weights = BLI_array_alloca(loop_weights, l_num);
+ for (j = 0; j < l_num; j++) {
+ BMLoop *l = BM_iter_step(&liter);
+ BMLoop *l_prev, *l_next;
+ void **val_p;
+ if (!BLI_ghash_ensure_p(sod->origfaces, l->f, &val_p)) {
+ BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, l->f, true, true);
+ *val_p = f_copy;
+ }
+
+ if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
+ (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON)))
+ {
+ loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+
+ }
+
+ /* store cd_loop_groups */
+ if (l_num != 0) {
+ sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, sod->layer_math_map_num * sizeof(void *));
+ for (j = 0; j < sod->layer_math_map_num; j++) {
+ const int layer_nr = sod->layer_math_map[j];
+ sv->cd_loop_groups[j] = BM_vert_loop_groups_data_layer_create(bm, sv->v, layer_nr, loop_weights, sod->arena);
+ }
+ }
+ else {
+ sv->cd_loop_groups = NULL;
+ }
+
+ BLI_ghash_insert(sod->origverts, sv->v, sv);
+}
+
+static void slide_origdata_create_data(
+ TransInfo *t, SlideOrigData *sod,
+ TransDataGenericSlideVert *sv_array, unsigned int v_stride, unsigned int v_num)
+{
+ if (sod->use_origfaces) {
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+ unsigned int i;
+ TransDataGenericSlideVert *sv;
+
+ int layer_index_dst;
+ int j;
+
+ /* over alloc, only 'math' layers are indexed */
+ sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
+ layer_index_dst = 0;
+ for (j = 0; j < bm->ldata.totlayer; j++) {
+ if (CustomData_layer_has_math(&bm->ldata, j)) {
+ sod->layer_math_map[layer_index_dst++] = j;
+ }
+ }
+ BLI_assert(layer_index_dst != 0);
+ sod->layer_math_map_num = layer_index_dst;
+
+ sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num);
+
+ for (i = 0, sv = sv_array; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
+ slide_origdata_create_data_vert(bm, sod, sv);
+ }
+
+ if (t->flag & T_MIRROR) {
+ TransData *td = t->data;
+ TransDataGenericSlideVert *sv_mirror;
+
+ sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * t->total, __func__);
+ sod->totsv_mirror = t->total;
+
+ sv_mirror = sod->sv_mirror;
+
+ for (i = 0; i < t->total; i++, td++) {
+ BMVert *eve = td->extra;
+ if (eve) {
+ sv_mirror->v = eve;
+ copy_v3_v3(sv_mirror->co_orig_3d, eve->co);
+
+ slide_origdata_create_data_vert(bm, sod, sv_mirror);
+ sv_mirror++;
+ }
+ else {
+ sod->totsv_mirror--;
+ }
+ }
+
+ if (sod->totsv_mirror == 0) {
+ MEM_freeN(sod->sv_mirror);
+ sod->sv_mirror = NULL;
+ }
+ }
+ }
+}
+
+/**
+ * If we're sliding the vert, return its original location, if not, the current location is good.
+ */
+static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v)
+{
+ TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v);
+ return sv ? sv->co_orig_3d : v->co;
+}
+
+static void slide_origdata_interp_data_vert(
+ SlideOrigData *sod, BMesh *bm, bool is_final,
+ TransDataGenericSlideVert *sv)
+{
+ BMIter liter;
+ int j, l_num;
+ float *loop_weights;
+ const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
+ const float *v_proj_axis = sv->v->no;
+ /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
+ float v_proj[3][3];
+
+ if (do_loop_weight) {
+ project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
+ }
+
+ // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
+ BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
+ l_num = liter.count;
+ loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
+ for (j = 0; j < l_num; j++) {
+ BMFace *f_copy; /* the copy of 'f' */
+ BMLoop *l = BM_iter_step(&liter);
+
+ f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
+
+ /* only loop data, no vertex data since that contains shape keys,
+ * and we do not want to mess up other shape keys */
+ BM_loop_interp_from_face(bm, l, f_copy, false, is_final);
+
+ /* make sure face-attributes are correct (e.g. MTexPoly) */
+ BM_elem_attrs_copy(sod->bm_origfaces, bm, f_copy, l->f);
+
+ /* weight the loop */
+ if (do_loop_weight) {
+ const float eps = 1.0e-8f;
+ const BMLoop *l_prev = l->prev;
+ const BMLoop *l_next = l->next;
+ const float *co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
+ const float *co_next = slide_origdata_orig_vert_co(sod, l_next->v);
+ bool co_prev_ok;
+ bool co_next_ok;
+
+
+ /* In the unlikely case that we're next to a zero length edge - walk around the to the next.
+ * Since we only need to check if the vertex is in this corner,
+ * its not important _which_ loop - as long as its not overlapping 'sv->co_orig_3d', see: T45096. */
+ project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
+ ((l_prev = l_prev->prev) != l->next)))
+ {
+ co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
+ project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ }
+ project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
+ ((l_next = l_next->next) != l->prev)))
+ {
+ co_next = slide_origdata_orig_vert_co(sod, l_next->v);
+ project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ }
+
+ if (co_prev_ok && co_next_ok) {
+ const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, UNPACK3(v_proj), v_proj_axis);
+
+ loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
+ if (UNLIKELY(!isfinite(loop_weights[j]))) {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ }
+
+ if (do_loop_weight) {
+ for (j = 0; j < sod->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
+ }
+ }
+ else {
+ for (j = 0; j < sod->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
+ }
+ }
+}
+
+static void slide_origdata_interp_data(
+ TransInfo *t, SlideOrigData *sod,
+ TransDataGenericSlideVert *sv, unsigned int v_stride, unsigned int v_num,
+ bool is_final)
+{
+ if (sod->use_origfaces) {
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+ unsigned int i;
+
+ for (i = 0; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
+
+ if (sv->cd_loop_groups) {
+ slide_origdata_interp_data_vert(sod, bm, is_final, sv);
+ }
+ }
+
+ if (sod->sv_mirror) {
+ sv = sod->sv_mirror;
+ for (i = 0; i < v_num; i++, sv++) {
+ if (sv->cd_loop_groups) {
+ slide_origdata_interp_data_vert(sod, bm, is_final, sv);
+ }
+ }
+ }
+ }
+}
+
+static void slide_origdata_free_date(
+ SlideOrigData *sod)
+{
+ if (sod->use_origfaces) {
+ if (sod->bm_origfaces) {
+ BM_mesh_free(sod->bm_origfaces);
+ sod->bm_origfaces = NULL;
+ }
+
+ if (sod->origfaces) {
+ BLI_ghash_free(sod->origfaces, NULL, NULL);
+ sod->origfaces = NULL;
+ }
+
+ if (sod->origverts) {
+ BLI_ghash_free(sod->origverts, NULL, NULL);
+ sod->origverts = NULL;
+ }
+
+ if (sod->arena) {
+ BLI_memarena_free(sod->arena);
+ sod->arena = NULL;
+ }
+
+ MEM_SAFE_FREE(sod->layer_math_map);
+
+ MEM_SAFE_FREE(sod->sv_mirror);
+ }
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/* Transform (Edge Slide) */
@@ -5133,6 +5594,19 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
/** \name Transform Edge Slide
* \{ */
+static void calcEdgeSlideCustomPoints(struct TransInfo *t)
+{
+ EdgeSlideData *sld = t->customData;
+
+ setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediatly so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+}
+
+
static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
{
BMIter iter;
@@ -5148,7 +5622,7 @@ static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
}
/* interpoaltes along a line made up of 2 segments (used for edge slide) */
-static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float t)
+static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
{
float t_mid, t_delta;
@@ -5156,17 +5630,28 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[
t_mid = line_point_factor_v3(v2, v1, v3);
t_delta = t - t_mid;
- if (fabsf(t_delta) < FLT_EPSILON) {
- copy_v3_v3(p, v2);
- }
- else if (t_delta < 0.0f) {
- interp_v3_v3v3(p, v1, v2, t / t_mid);
+ if (t_delta < 0.0f) {
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v2);
+ }
+ else {
+ interp_v3_v3v3(p, v1, v2, t / t_mid);
+ }
}
else {
- interp_v3_v3v3(p, v2, v3, (t - t_mid) / (1.0f - t_mid));
+ t = t - t_mid;
+ t_mid = 1.0f - t_mid;
+
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v3);
+ }
+ else {
+ interp_v3_v3v3(p, v2, v3, t / t_mid);
+ }
}
}
+
static void len_v3_ensure(float v[3], const float length)
{
normalize_v3(v);
@@ -5311,7 +5796,171 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
return NULL;
}
-static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2])
+/**
+ * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
+ */
+static void calcEdgeSlide_mval_range(
+ TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
+ const float mval[2], const bool use_btree_disp, const bool use_calc_direction)
+{
+ TransDataEdgeSlideVert *sv_array = sld->sv;
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+ ARegion *ar = t->ar;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
+ float projectMat[4][4];
+ BMBVHTree *btree;
+
+ /* only for use_calc_direction */
+ float (*loop_dir)[3] = NULL, *loop_maxdist = NULL;
+
+ float mval_start[2], mval_end[2];
+ float mval_dir[3], dist_best_sq;
+ BMIter iter;
+ BMEdge *e;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ }
+
+ if (!rv3d) {
+ /* ok, let's try to survive this */
+ unit_m4(projectMat);
+ }
+ else {
+ ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+ }
+
+ if (use_btree_disp) {
+ btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
+ }
+ else {
+ btree = NULL;
+ }
+
+ /* find mouse vectors, the global one, and one per loop in case we have
+ * multiple loops selected, in case they are oriented different */
+ zero_v3(mval_dir);
+ dist_best_sq = -1.0f;
+
+ if (use_calc_direction) {
+ loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
+ loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
+ copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ int i;
+
+ /* search cross edges for visible edge to the mouse cursor,
+ * then use the shared vertex to calculate screen vector*/
+ for (i = 0; i < 2; i++) {
+ BMIter iter_other;
+ BMEdge *e_other;
+
+ BMVert *v = i ? e->v1 : e->v2;
+ BM_ITER_ELEM (e_other, &iter_other, v, BM_EDGES_OF_VERT) {
+ /* screen-space coords */
+ float sco_a[3], sco_b[3];
+ float dist_sq;
+ int j, l_nr;
+
+ if (BM_elem_flag_test(e_other, BM_ELEM_SELECT))
+ continue;
+
+ /* This test is only relevant if object is not wire-drawn! See [#32068]. */
+ if (use_btree_disp && !BMBVH_EdgeVisible(btree, e_other, ar, v3d, t->obedit)) {
+ continue;
+ }
+
+ BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
+ j = sv_table[BM_elem_index_get(v)];
+
+ if (sv_array[j].v_side[1]) {
+ ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[1]->co, sco_b, projectMat);
+ }
+ else {
+ add_v3_v3v3(sco_b, v->co, sv_array[j].dir_side[1]);
+ ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
+ }
+
+ if (sv_array[j].v_side[0]) {
+ ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[0]->co, sco_a, projectMat);
+ }
+ else {
+ add_v3_v3v3(sco_a, v->co, sv_array[j].dir_side[0]);
+ ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
+ }
+
+ /* global direction */
+ dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
+ if ((dist_best_sq == -1.0f) ||
+ /* intentionally use 2d size on 3d vector */
+ (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
+ {
+ dist_best_sq = dist_sq;
+ sub_v3_v3v3(mval_dir, sco_b, sco_a);
+ }
+
+ if (use_calc_direction) {
+ /* per loop direction */
+ l_nr = sv_array[j].loop_nr;
+ if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
+ loop_maxdist[l_nr] = dist_sq;
+ sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (use_calc_direction) {
+ int i;
+ sv_array = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv_array++) {
+ /* switch a/b if loop direction is different from global direction */
+ int l_nr = sv_array->loop_nr;
+ if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
+ swap_v3_v3(sv_array->dir_side[0], sv_array->dir_side[1]);
+ SWAP(BMVert *, sv_array->v_side[0], sv_array->v_side[1]);
+ }
+ }
+
+ MEM_freeN(loop_dir);
+ MEM_freeN(loop_maxdist);
+ }
+
+ /* possible all of the edge loops are pointing directly at the view */
+ if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
+ mval_dir[0] = 0.0f;
+ mval_dir[1] = 100.0f;
+ }
+
+ /* zero out start */
+ zero_v2(mval_start);
+
+ /* dir holds a vector along edge loop */
+ copy_v2_v2(mval_end, mval_dir);
+ mul_v2_fl(mval_end, 0.5f);
+
+ sld->mval_start[0] = t->mval[0] + mval_start[0];
+ sld->mval_start[1] = t->mval[1] + mval_start[1];
+
+ sld->mval_end[0] = t->mval[0] + mval_end[0];
+ sld->mval_end[1] = t->mval[1] + mval_end[1];
+
+ if (btree) {
+ BKE_bmbvh_free(btree);
+ }
+}
+
+static void calcEdgeSlide_non_proportional(
+ TransInfo *t, EdgeSlideData *sld, const float mval[2])
{
TransDataEdgeSlideVert *sv = sld->sv;
@@ -5341,7 +5990,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
for (i = 0; i < sld->totsv; i++, sv++) {
/* Set length */
- sv->edge_len = len_v3v3(sv->dir_a, sv->dir_b);
+ sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]);
ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
dist_sq = len_squared_v2v2(mval, v_proj);
@@ -5356,7 +6005,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
}
}
-static bool createEdgeSlideVerts(TransInfo *t)
+static bool createEdgeSlideVerts_double_side(TransInfo *t)
{
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
@@ -5365,48 +6014,20 @@ static bool createEdgeSlideVerts(TransInfo *t)
BMVert *v;
TransDataEdgeSlideVert *sv_array;
int sv_tot;
- BMBVHTree *btree;
int *sv_table; /* BMVert -> sv_array index */
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
+ int numsel, i, j, loop_nr;
+ bool use_btree_disp = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
- ARegion *ar = t->ar;
- float projectMat[4][4];
- float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- float mval_start[2], mval_end[2];
- float mval_dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
- int numsel, i, j, loop_nr, l_nr;
- int use_btree_disp;
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = t->ar ? t->ar->regiondata : NULL;
- }
- if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
- /* don't do this at all for non-basis shape keys, too easy to
- * accidentally break uv maps or vertex colors then */
- (bm->shapenr <= 1))
- {
- sld->use_origfaces = true;
- }
- else {
- sld->use_origfaces = false;
- }
+ slide_origdata_init_flag(t, &sld->orig_data);
sld->is_proportional = true;
sld->curr_sv_index = 0;
sld->flipped_vtx = false;
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
- }
-
/*ensure valid selection*/
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
@@ -5578,14 +6199,14 @@ static bool createEdgeSlideVerts(TransInfo *t)
if (l_a || l_a_prev) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v);
- sv->v_a = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_a, vec_a);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[0], vec_a);
}
if (l_b || l_b_prev) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v);
- sv->v_b = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_b, vec_b);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[1], vec_b);
}
v_prev = v;
@@ -5604,23 +6225,23 @@ static bool createEdgeSlideVerts(TransInfo *t)
if (l_a) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
- sv->v_a = BM_edge_other_vert(l_tmp->e, v);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_a);
+ get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]);
}
else {
- sub_v3_v3v3(sv->dir_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
}
}
if (l_b) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
- sv->v_b = BM_edge_other_vert(l_tmp->e, v);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_b);
+ get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]);
}
else {
- sub_v3_v3v3(sv->dir_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co);
}
}
@@ -5691,160 +6312,228 @@ static bool createEdgeSlideVerts(TransInfo *t)
#undef EDGESLIDE_VERT_IS_INNER
}
- /* use for visibility checks */
- use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
-
- if (use_btree_disp) {
- btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
- }
- else {
- btree = NULL;
- }
-
-
/* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
sld->sv = sv_array;
sld->totsv = sv_tot;
-
- /* find mouse vectors, the global one, and one per loop in case we have
- * multiple loops selected, in case they are oriented different */
- zero_v3(mval_dir);
- maxdist = -1.0f;
- loop_dir = MEM_callocN(sizeof(float) * 3 * loop_nr, "sv loop_dir");
- loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
- fill_vn_fl(loop_maxdist, loop_nr, -1.0f);
+ /* use for visibility checks */
+ if (t->spacetype == SPACE_VIEW3D) {
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ }
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- BMIter iter2;
- BMEdge *e2;
- float d;
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, true);
- /* search cross edges for visible edge to the mouse cursor,
- * then use the shared vertex to calculate screen vector*/
- for (i = 0; i < 2; i++) {
- v = i ? e->v1 : e->v2;
- BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) {
- /* screen-space coords */
- float sco_a[3], sco_b[3];
+ /* create copies of faces for customdata projection */
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+ slide_origdata_init_data(t, &sld->orig_data);
+ slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
- if (BM_elem_flag_test(e2, BM_ELEM_SELECT))
- continue;
+ if (rv3d) {
+ calcEdgeSlide_non_proportional(t, sld, mval);
+ }
- /* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) {
- continue;
- }
+ sld->em = em;
+
+ sld->perc = 0.0f;
+
+ t->customData = sld;
+
+ MEM_freeN(sv_table);
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- j = sv_table[BM_elem_index_get(v)];
+ return true;
+}
- if (sv_array[j].v_b) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_b->co, sco_b, projectMat);
- }
- else {
- add_v3_v3v3(sco_b, v->co, sv_array[j].dir_b);
- ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
- }
-
- if (sv_array[j].v_a) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_a->co, sco_a, projectMat);
- }
- else {
- add_v3_v3v3(sco_a, v->co, sv_array[j].dir_a);
- ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
- }
-
- /* global direction */
- d = dist_to_line_segment_v2(mval, sco_b, sco_a);
- if ((maxdist == -1.0f) ||
- /* intentionally use 2d size on 3d vector */
- (d < maxdist && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
- {
- maxdist = d;
- sub_v3_v3v3(mval_dir, sco_b, sco_a);
- }
+/**
+ * A simple version of #createEdgeSlideVerts_double_side
+ * Which assumes the longest unselected.
+ */
+static bool createEdgeSlideVerts_single_side(TransInfo *t)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *e;
+ BMVert *v;
+ TransDataEdgeSlideVert *sv_array;
+ int sv_tot;
+ int *sv_table; /* BMVert -> sv_array index */
+ EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
+ int i, j, loop_nr;
+ bool use_btree_disp = false;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ }
+
+ slide_origdata_init_flag(t, &sld->orig_data);
+
+ sld->is_proportional = true;
+ sld->curr_sv_index = 0;
+ /* heppans to be best for single-sided */
+ sld->flipped_vtx = true;
- /* per loop direction */
- l_nr = sv_array[j].loop_nr;
- if (loop_maxdist[l_nr] == -1.0f || d < loop_maxdist[l_nr]) {
- loop_maxdist[l_nr] = d;
- sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
+ /* ensure valid selection */
+ j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float len_sq_max = -1.0f;
+ BMIter iter2;
+ BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > len_sq_max) {
+ len_sq_max = len_sq;
+ v->e = e;
}
}
}
+
+ if (len_sq_max != -1.0f) {
+ j++;
+ }
}
+ BM_elem_index_set(v, i); /* set_inline */
}
+ bm->elem_index_dirty &= ~BM_VERT;
- /* possible all of the edge loops are pointing directly at the view */
- if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
- mval_dir[0] = 0.0f;
- mval_dir[1] = 100.0f;
+ if (!j) {
+ return false;
}
- bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- if (sld->use_origfaces) {
- sld->origfaces = BLI_ghash_ptr_new(__func__);
- sld->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
- /* we need to have matching customdata */
- BM_mesh_copy_init_customdata(sld->bm_origfaces, bm, NULL);
+ sv_tot = j;
+ BLI_assert(sv_tot != 0);
+ /* over alloc */
+ sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
+
+ /* same loop for all loops, weak but we dont connect loops in this case */
+ loop_nr = 1;
+
+ sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
+
+ j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ sv_table[i] = -1;
+ if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
+ if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
+ TransDataEdgeSlideVert *sv;
+ sv = &sv_array[j];
+ sv->v = v;
+ copy_v3_v3(sv->v_co_orig, v->co);
+ sv->v_side[0] = BM_edge_other_vert(v->e, v);
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
+ sv->loop_nr = 0;
+ sv_table[i] = j;
+ j += 1;
+ }
+ }
}
- /*create copies of faces for customdata projection*/
- sv_array = sld->sv;
- for (i = 0; i < sld->totsv; i++, sv_array++) {
- BMIter fiter;
- BMFace *f;
-
+ /* check for wire vertices,
+ * interpolate the directions of wire verts between non-wire verts */
+ if (sv_tot != bm->totvert) {
+ const int sv_tot_nowire = sv_tot;
+ TransDataEdgeSlideVert *sv_iter = sv_array;
+ int i;
+ for (i = 0; i < sv_tot_nowire; i++, sv_iter++) {
+ BMIter eiter;
+ BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
+ /* walk over wire */
+ TransDataEdgeSlideVert *sv_end = NULL;
+ BMEdge *e_step = e;
+ BMVert *v = sv_iter->v;
+
+ j = sv_tot;
+
+ while (1) {
+ BMVert *v_other = BM_edge_other_vert(e_step, v);
+ int endpoint = (
+ (sv_table[BM_elem_index_get(v_other)] != -1) +
+ (BM_vert_is_edge_pair(v_other) == false));
+
+ if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(v_other, BM_ELEM_SELECT)) &&
+ (endpoint == 0))
+ {
+ /* scan down the list */
+ TransDataEdgeSlideVert *sv;
+ BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1);
+ sv_table[BM_elem_index_get(v_other)] = j;
+ sv = &sv_array[j];
+ sv->v = v_other;
+ copy_v3_v3(sv->v_co_orig, v_other->co);
+ copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]);
+ j++;
+
+ /* advance! */
+ v = v_other;
+ e_step = BM_DISK_EDGE_NEXT(e_step, v_other);
+ }
+ else {
+ if ((endpoint == 2) && (sv_tot != j)) {
+ BLI_assert(BM_elem_index_get(v_other) != -1);
+ sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]];
+ }
+ break;
+ }
+ }
- if (sld->use_origfaces) {
- BM_ITER_ELEM (f, &fiter, sv_array->v, BM_FACES_OF_VERT) {
- if (!BLI_ghash_haskey(sld->origfaces, f)) {
- BMFace *f_copy = BM_face_copy(sld->bm_origfaces, bm, f, true, true);
- BLI_ghash_insert(sld->origfaces, f, f_copy);
+ if (sv_end) {
+ int sv_tot_prev = sv_tot;
+ const float *co_src = sv_iter->v->co;
+ const float *co_dst = sv_end->v->co;
+ const float *dir_src = sv_iter->dir_side[0];
+ const float *dir_dst = sv_end->dir_side[0];
+ sv_tot = j;
+
+ while (j-- != sv_tot_prev) {
+ float factor;
+ factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst);
+ interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor);
+ }
}
}
}
+ }
- /* switch a/b if loop direction is different from global direction */
- l_nr = sv_array->loop_nr;
- if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
- swap_v3_v3(sv_array->dir_a, sv_array->dir_b);
- SWAP(BMVert *, sv_array->v_a, sv_array->v_b);
- }
+ /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+
+ sld->sv = sv_array;
+ sld->totsv = sv_tot;
+
+ /* use for visibility checks */
+ if (t->spacetype == SPACE_VIEW3D) {
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
- if (rv3d)
- calcNonProportionalEdgeSlide(t, sld, mval);
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, false);
- sld->em = em;
+ /* create copies of faces for customdata projection */
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+ slide_origdata_init_data(t, &sld->orig_data);
+ slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
- /*zero out start*/
- zero_v2(mval_start);
+ if (rv3d) {
+ calcEdgeSlide_non_proportional(t, sld, mval);
+ }
- /*dir holds a vector along edge loop*/
- copy_v2_v2(mval_end, mval_dir);
- mul_v2_fl(mval_end, 0.5f);
-
- sld->mval_start[0] = t->mval[0] + mval_start[0];
- sld->mval_start[1] = t->mval[1] + mval_start[1];
+ sld->em = em;
- sld->mval_end[0] = t->mval[0] + mval_end[0];
- sld->mval_end[1] = t->mval[1] + mval_end[1];
-
sld->perc = 0.0f;
-
+
t->customData = sld;
-
+
MEM_freeN(sv_table);
- if (btree) {
- BKE_bmbvh_free(btree);
- }
- MEM_freeN(loop_dir);
- MEM_freeN(loop_maxdist);
return true;
}
@@ -5852,172 +6541,27 @@ static bool createEdgeSlideVerts(TransInfo *t)
void projectEdgeSlideData(TransInfo *t, bool is_final)
{
EdgeSlideData *sld = t->customData;
- TransDataEdgeSlideVert *sv;
- BMEditMesh *em = sld->em;
- int i;
+ SlideOrigData *sod = &sld->orig_data;
- if (sld->use_origfaces == false) {
+ if (sod->use_origfaces == false) {
return;
}
- for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
- BMIter fiter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) {
- BMFace *f_copy; /* the copy of 'f' */
- BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
-
- f_copy = BLI_ghash_lookup(sld->origfaces, l->f);
-
- /* project onto copied projection face */
- f_copy_flip = f_copy;
-
- if (BM_elem_flag_test(l->e, BM_ELEM_SELECT) || BM_elem_flag_test(l->prev->e, BM_ELEM_SELECT)) {
- /* the loop is attached of the selected edges that are sliding */
- BMLoop *l_ed_sel = l;
-
- if (!BM_elem_flag_test(l->e, BM_ELEM_SELECT))
- l_ed_sel = l_ed_sel->prev;
-
- if (sld->perc < 0.0f) {
- if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->v_b)) {
- f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
- }
- }
- else if (sld->perc > 0.0f) {
- if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->v_a)) {
- f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
- }
- }
-
- BLI_assert(f_copy_flip != NULL);
- if (!f_copy_flip) {
- continue; /* shouldn't happen, but protection */
- }
- }
- else {
- /* the loop is attached to only one vertex and not a selected edge,
- * this means we have to find a selected edges face going in the right direction
- * to copy from else we get bad distortion see: [#31080] */
- BMIter eiter;
- BMEdge *e_sel;
-
- BLI_assert(l->v == sv->v);
- BM_ITER_ELEM (e_sel, &eiter, sv->v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e_sel, BM_ELEM_SELECT)) {
- break;
- }
- }
-
- if (e_sel) {
- /* warning if the UV's are not contiguous, this will copy from the _wrong_ UVs
- * in fact whenever the face being copied is not 'f_copy' this can happen,
- * we could be a lot smarter about this but would need to deal with every UV channel or
- * add a way to mask out lauers when calling #BM_loop_interp_from_face() */
-
- /*
- * + +----------------+
- * \ | |
- * (this) l_adj| |
- * \ | |
- * \| e_sel |
- * +----------+----------------+ <- the edge we are sliding.
- * /|sv->v |
- * / | |
- * (or) l_adj| |
- * / | |
- * + +----------------+
- * (above)
- * 'other connected loops', attached to sv->v slide faces.
- *
- * NOTE: The faces connected to the edge may not have contiguous UV's
- * so step around the loops to find l_adj.
- * However if the 'other loops' are not cotiguous it will still give problems.
- *
- * A full solution to this would have to store
- * per-customdata-layer map of which loops are contiguous
- * and take this into account when interpolating.
- *
- * NOTE: If l_adj's edge isnt manifold then use then
- * interpolate the loop from its own face.
- * Can happen when 'other connected loops' are disconnected from the face-fan.
- */
-
- BMLoop *l_adj = NULL;
- if (sld->perc < 0.0f) {
- if (BM_vert_in_face(e_sel->l->f, sv->v_b)) {
- l_adj = e_sel->l;
- }
- else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_b)) {
- l_adj = e_sel->l->radial_next;
- }
- }
- else if (sld->perc > 0.0f) {
- if (BM_vert_in_face(e_sel->l->f, sv->v_a)) {
- l_adj = e_sel->l;
- }
- else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_a)) {
- l_adj = e_sel->l->radial_next;
- }
- }
-
- /* step across to the face */
- if (l_adj) {
- l_adj = BM_loop_other_edge_loop(l_adj, sv->v);
- if (!BM_edge_is_boundary(l_adj->e)) {
- l_adj = l_adj->radial_next;
- }
- else {
- /* disconnected face-fan, fallback to self */
- l_adj = l;
- }
-
- f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_adj->f);
- }
- }
- }
-
- /* only loop data, no vertex data since that contains shape keys,
- * and we do not want to mess up other shape keys */
- BM_loop_interp_from_face(em->bm, l, f_copy_flip, false, false);
-
- if (is_final) {
- BM_loop_interp_multires(em->bm, l, f_copy_flip);
- if (f_copy != f_copy_flip) {
- BM_loop_interp_multires(em->bm, l, f_copy);
- }
- }
-
- /* make sure face-attributes are correct (e.g. MTexPoly) */
- BM_elem_attrs_copy(sld->bm_origfaces, em->bm, f_copy, l->f);
- }
- }
+ slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
}
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
{
- if (sld->use_origfaces) {
- if (sld->bm_origfaces) {
- BM_mesh_free(sld->bm_origfaces);
- sld->bm_origfaces = NULL;
- }
-
- if (sld->origfaces) {
- BLI_ghash_free(sld->origfaces, NULL, NULL);
- sld->origfaces = NULL;
- }
- }
+ slide_origdata_free_date(&sld->orig_data);
}
-
void freeEdgeSlideVerts(TransInfo *t)
{
EdgeSlideData *sld = t->customData;
if (!sld)
return;
-
+
freeEdgeSlideTempFaces(sld);
bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
@@ -6026,19 +6570,25 @@ void freeEdgeSlideVerts(TransInfo *t)
MEM_freeN(sld);
t->customData = NULL;
-
- recalcData(t);
}
-static void initEdgeSlide(TransInfo *t)
+static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
{
EdgeSlideData *sld;
+ bool ok;
t->mode = TFM_EDGE_SLIDE;
t->transform = applyEdgeSlide;
t->handleEvent = handleEventEdgeSlide;
- if (!createEdgeSlideVerts(t)) {
+ if (use_double_side) {
+ ok = createEdgeSlideVerts_double_side(t);
+ }
+ else {
+ ok = createEdgeSlideVerts_single_side(t);
+ }
+
+ if (!ok) {
t->state = TRANS_CANCEL;
return;
}
@@ -6051,7 +6601,7 @@ static void initEdgeSlide(TransInfo *t)
t->customFree = freeEdgeSlideVerts;
/* set custom point first if you want value to be initialized by init */
- setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+ calcEdgeSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
t->idx_max = 0;
@@ -6067,6 +6617,11 @@ static void initEdgeSlide(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+static void initEdgeSlide(TransInfo *t)
+{
+ initEdgeSlide_ex(t, true);
+}
+
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_EDGE_SLIDE) {
@@ -6077,35 +6632,40 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
case EKEY:
if (event->val == KM_PRESS) {
sld->is_proportional = !sld->is_proportional;
+ calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
case FKEY:
- {
if (event->val == KM_PRESS) {
if (sld->is_proportional == false) {
sld->flipped_vtx = !sld->flipped_vtx;
}
+ calcEdgeSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case CKEY:
+ /* use like a modifier key */
+ if (event->val == KM_PRESS) {
+ t->flag ^= T_ALT_TRANSFORM;
+ calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
- }
case EVT_MODAL_MAP:
- {
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
- {
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
- break;
- }
+ return TREDRAW_HARD;
case TFM_MODAL_EDGESLIDE_UP:
- {
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
- break;
- }
+ return TREDRAW_HARD;
}
break;
- }
+ case MOUSEMOVE:
+ calcEdgeSlideCustomPoints(t);
+ break;
default:
break;
}
@@ -6114,23 +6674,16 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_NOTHING;
}
-static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
+static void drawEdgeSlide(TransInfo *t)
{
- if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = (EdgeSlideData *)t->customData;
+ if ((t->mode == TFM_EDGE_SLIDE) && t->customData) {
+ EdgeSlideData *sld = t->customData;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
/* Non-Prop mode */
- if (sld && sld->is_proportional == false) {
- View3D *v3d = CTX_wm_view3d(C);
- float co_a[3], co_b[3], co_mark[3];
- TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float fac = (sld->perc + 1.0f) / 2.0f;
- const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
- const float guide_size = ctrl_size - 0.5f;
+ if ((sld->is_proportional == false) || (is_clamp == false)) {
+ View3D *v3d = t->view;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
- const int alpha_shade = -30;
-
- add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_a);
- add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_b);
if (v3d && v3d->zbuf)
glDisable(GL_DEPTH_TEST);
@@ -6143,42 +6696,88 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
glMultMatrixf(t->obedit->obmat);
- glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
- if (curr_sv->v_a) {
- glVertex3fv(curr_sv->v_a->co);
- glVertex3fv(curr_sv->v_co_orig);
- }
- if (curr_sv->v_b) {
- glVertex3fv(curr_sv->v_b->co);
- glVertex3fv(curr_sv->v_co_orig);
- }
- bglEnd();
+ if (sld->is_proportional == false) {
+ float co_a[3], co_b[3], co_mark[3];
+ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+ const float fac = (sld->perc + 1.0f) / 2.0f;
+ const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
+ const float guide_size = ctrl_size - 0.5f;
+ const int alpha_shade = -30;
+
+ add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
+ add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
+
+ glLineWidth(line_size);
+ UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ glBegin(GL_LINES);
+ if (curr_sv->v_side[0]) {
+ glVertex3fv(curr_sv->v_side[0]->co);
+ glVertex3fv(curr_sv->v_co_orig);
+ }
+ if (curr_sv->v_side[1]) {
+ glVertex3fv(curr_sv->v_side[1]->co);
+ glVertex3fv(curr_sv->v_co_orig);
+ }
+ glEnd();
+ UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
+ glPointSize(ctrl_size);
+ bglBegin(GL_POINTS);
+ if (sld->flipped_vtx) {
+ if (curr_sv->v_side[1]) bglVertex3fv(curr_sv->v_side[1]->co);
+ }
+ else {
+ if (curr_sv->v_side[0]) bglVertex3fv(curr_sv->v_side[0]->co);
+ }
+ bglEnd();
- UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
- glPointSize(ctrl_size);
- bglBegin(GL_POINTS);
- if (sld->flipped_vtx) {
- if (curr_sv->v_b) bglVertex3fv(curr_sv->v_b->co);
+ UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
+ glPointSize(guide_size);
+ bglBegin(GL_POINTS);
+#if 0
+ interp_v3_v3v3(co_mark, co_b, co_a, fac);
+ bglVertex3fv(co_mark);
+#endif
+ interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
+ bglVertex3fv(co_mark);
+ bglEnd();
}
else {
- if (curr_sv->v_a) bglVertex3fv(curr_sv->v_a->co);
- }
- bglEnd();
+ if (is_clamp == false) {
+ const int side_index = sld->curr_side_unclamp;
+ TransDataEdgeSlideVert *sv;
+ int i;
+ const int alpha_shade = -160;
+
+ glLineWidth(line_size);
+ UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ glBegin(GL_LINES);
+
+ sv = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float a[3], b[3];
+
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(a, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(a, sv->dir_side[!side_index]);
+ }
- UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
- glPointSize(guide_size);
- bglBegin(GL_POINTS);
-#if 0
- interp_v3_v3v3(co_mark, co_b, co_a, fac);
- bglVertex3fv(co_mark);
-#endif
- interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
- bglVertex3fv(co_mark);
- bglEnd();
+ mul_v3_fl(a, 100.0f);
+ negate_v3_v3(b, a);
+ add_v3_v3(a, sv->v_co_orig);
+ add_v3_v3(b, sv->v_co_orig);
+ glVertex3fv(a);
+ glVertex3fv(b);
+ }
+ glEnd();
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
glPopMatrix();
glPopAttrib();
@@ -6191,7 +6790,7 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
}
}
-static int doEdgeSlide(TransInfo *t, float perc)
+static void doEdgeSlide(TransInfo *t, float perc)
{
EdgeSlideData *sld = t->customData;
TransDataEdgeSlideVert *svlist = sld->sv, *sv;
@@ -6201,17 +6800,30 @@ static int doEdgeSlide(TransInfo *t, float perc)
sv = svlist;
if (sld->is_proportional == true) {
- for (i = 0; i < sld->totsv; i++, sv++) {
- float vec[3];
- if (perc > 0.0f) {
- copy_v3_v3(vec, sv->dir_a);
- mul_v3_fl(vec, perc);
- add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ if (is_clamp) {
+ const int side_index = (perc < 0.0f);
+ const float perc_final = fabsf(perc);
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
}
- else {
- copy_v3_v3(vec, sv->dir_b);
- mul_v3_fl(vec, -perc);
- add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
+
+ sld->curr_side_unclamp = side_index;
+ }
+ else {
+ const int side_index = sld->curr_side_unclamp;
+ const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float dir_flip[3];
+ float perc_final = perc_init;
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(dir_flip, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
+ perc_final *= -1;
+ }
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
}
}
}
@@ -6221,7 +6833,7 @@ static int doEdgeSlide(TransInfo *t, float perc)
* a/b verts, this could be changed/improved so the distance is still met but the verts are moved along
* their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
*
- * \note len_v3v3(curr_sv->dir_a, curr_sv->dir_b)
+ * \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])
* is the same as the distance between the original vert locations, same goes for the lines below.
*/
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
@@ -6234,8 +6846,8 @@ static int doEdgeSlide(TransInfo *t, float perc)
if (sv->edge_len > FLT_EPSILON) {
const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
- add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_a);
- add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_b);
+ add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
+ add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
if (sld->flipped_vtx) {
interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
@@ -6246,55 +6858,48 @@ static int doEdgeSlide(TransInfo *t, float perc)
}
}
}
-
- projectEdgeSlideData(t, 0);
-
- return 1;
}
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
char str[MAX_INFO_LEN];
+ size_t ofs = 0;
float final;
EdgeSlideData *sld = t->customData;
bool flipped = sld->flipped_vtx;
bool is_proportional = sld->is_proportional;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
final = t->values[0];
snapGridIncrement(t, &final);
/* only do this so out of range values are not displayed */
- CLAMP(final, -1.0f, 1.0f);
+ if (is_constrained) {
+ CLAMP(final, -1.0f, 1.0f);
+ }
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
+ /* header string */
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
-
outputNumInput(&(t->num), c, &t->scene->unit);
-
- if (is_proportional) {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"),
- &c[0], WM_bool_as_string(!is_proportional));
- }
- else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
- &c[0], WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
- }
- }
- else if (is_proportional) {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s"),
- final, WM_bool_as_string(!is_proportional));
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
- final, WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
}
-
- CLAMP(final, -1.0f, 1.0f);
-
- t->values[0] = final;
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional));
+ if (!is_proportional) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ }
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ /* done with header string */
/* do stuff here */
doEdgeSlide(t, final);
@@ -6316,10 +6921,20 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
{
VertSlideData *sld = t->customData;
TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
- const float *co_orig = sv->co_orig_2d;
- const float *co_curr = sv->co_link_orig_2d[sv->co_link_curr];
- const int mval_start[2] = {co_orig[0], co_orig[1]};
- const int mval_end[2] = {co_curr[0], co_curr[1]};
+
+ const float *co_orig_3d = sv->co_orig_3d;
+ const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr];
+
+ float co_curr_2d[2], co_orig_2d[2];
+
+ int mval_ofs[2], mval_start[2], mval_end[2];
+
+ ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat);
+ ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat);
+
+ ARRAY_SET_ITEMS(mval_ofs, t->imval[0] - co_orig_2d[0], t->imval[1] - co_orig_2d[1]);
+ ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
+ ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
if (sld->flipped_vtx && sld->is_proportional == false) {
setCustomPoints(t, &t->mouse, mval_start, mval_end);
@@ -6327,6 +6942,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
else {
setCustomPoints(t, &t->mouse, mval_end, mval_start);
}
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediatly so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
}
/**
@@ -6344,28 +6964,39 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
int i;
for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
- dist_sq = len_squared_v2v2(mval_fl, sv->co_orig_2d);
+ float co_2d[2];
+
+ ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat);
+
+ dist_sq = len_squared_v2v2(mval_fl, co_2d);
if (dist_sq < dist_min_sq) {
dist_min_sq = dist_sq;
sld->curr_sv_index = i;
}
}
}
+
/**
* Run while moving the mouse to slide along the edge matching the mouse direction
*/
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
{
VertSlideData *sld = t->customData;
- float mval_fl[2] = {UNPACK2(mval)};
+ float imval_fl[2] = {UNPACK2(t->imval)};
+ float mval_fl[2] = {UNPACK2(mval)};
- float dir[2];
+ float dir[3];
TransDataVertSlideVert *sv;
int i;
- /* first get the direction of the original vertex */
- sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl);
- normalize_v2(dir);
+ /* note: we could save a matrix-multiply for each vertex
+ * by finding the closest edge in local-space.
+ * However this skews the outcome with non-uniform-scale. */
+
+ /* first get the direction of the original mouse position */
+ sub_v2_v2v2(dir, imval_fl, mval_fl);
+ ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac);
+ normalize_v3(dir);
for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
if (sv->co_link_tot > 1) {
@@ -6374,11 +7005,15 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
int j;
for (j = 0; j < sv->co_link_tot; j++) {
- float tdir[2];
+ float tdir[3];
float dir_dot;
- sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]);
- normalize_v2(tdir);
- dir_dot = dot_v2v2(dir, tdir);
+
+ sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
+ mul_mat3_m4_v3(t->obedit->obmat, tdir);
+ project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
+
+ normalize_v3(tdir);
+ dir_dot = dot_v3v3(dir, tdir);
if (dir_dot > dir_dot_best) {
dir_dot_best = dir_dot;
co_link_curr_best = j;
@@ -6402,30 +7037,14 @@ static bool createVertSlideVerts(TransInfo *t)
BMVert *v;
TransDataVertSlideVert *sv_array;
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
-// View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
- ARegion *ar = t->ar;
- float projectMat[4][4];
int j;
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
-// v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = ar ? ar->regiondata : NULL;
- }
+ slide_origdata_init_flag(t, &sld->orig_data);
sld->is_proportional = true;
sld->curr_sv_index = 0;
sld->flipped_vtx = false;
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
- }
-
j = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
bool ok = false;
@@ -6469,7 +7088,6 @@ static bool createVertSlideVerts(TransInfo *t)
}
sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, __func__);
- sv_array[j].co_link_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * k, __func__);
sv_array[j].co_link_tot = k;
k = 0;
@@ -6477,31 +7095,9 @@ static bool createVertSlideVerts(TransInfo *t)
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMVert *v_other = BM_edge_other_vert(e, v);
copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
- if (ar) {
- ED_view3d_project_float_v2_m4(ar,
- sv_array[j].co_link_orig_3d[k],
- sv_array[j].co_link_orig_2d[k],
- projectMat);
- }
- else {
- copy_v2_v2(sv_array[j].co_link_orig_2d[k],
- sv_array[j].co_link_orig_3d[k]);
- }
k++;
}
}
-
- if (ar) {
- ED_view3d_project_float_v2_m4(ar,
- sv_array[j].co_orig_3d,
- sv_array[j].co_orig_2d,
- projectMat);
- }
- else {
- copy_v2_v2(sv_array[j].co_orig_2d,
- sv_array[j].co_orig_3d);
- }
-
j++;
}
}
@@ -6509,13 +7105,29 @@ static bool createVertSlideVerts(TransInfo *t)
sld->sv = sv_array;
sld->totsv = j;
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+ slide_origdata_init_data(t, &sld->orig_data);
+ slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+
sld->em = em;
sld->perc = 0.0f;
t->customData = sld;
- if (rv3d) {
+ /* most likely will be set below */
+ unit_m4(sld->proj_mat);
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* view vars */
+ RegionView3D *rv3d = NULL;
+ ARegion *ar = t->ar;
+
+ rv3d = ar ? ar->regiondata : NULL;
+ if (rv3d) {
+ ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat);
+ }
+
calcVertSlideMouseActiveVert(t, t->mval);
calcVertSlideMouseActiveEdges(t, t->mval);
}
@@ -6523,6 +7135,23 @@ static bool createVertSlideVerts(TransInfo *t)
return true;
}
+void projectVertSlideData(TransInfo *t, bool is_final)
+{
+ VertSlideData *sld = t->customData;
+ SlideOrigData *sod = &sld->orig_data;
+
+ if (sod->use_origfaces == false) {
+ return;
+ }
+
+ slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+}
+
+void freeVertSlideTempFaces(VertSlideData *sld)
+{
+ slide_origdata_free_date(&sld->orig_data);
+}
+
void freeVertSlideVerts(TransInfo *t)
{
VertSlideData *sld = t->customData;
@@ -6530,12 +7159,14 @@ void freeVertSlideVerts(TransInfo *t)
if (!sld)
return;
+ freeVertSlideTempFaces(sld);
+
+ bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
if (sld->totsv > 0) {
TransDataVertSlideVert *sv = sld->sv;
int i = 0;
for (i = 0; i < sld->totsv; i++, sv++) {
- MEM_freeN(sv->co_link_orig_2d);
MEM_freeN(sv->co_link_orig_3d);
}
}
@@ -6544,8 +7175,6 @@ void freeVertSlideVerts(TransInfo *t)
MEM_freeN(sld);
t->customData = NULL;
-
- recalcData(t);
}
static void initVertSlide(TransInfo *t)
@@ -6602,16 +7231,13 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
}
break;
case FKEY:
- {
if (event->val == KM_PRESS) {
sld->flipped_vtx = !sld->flipped_vtx;
calcVertSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
- }
case CKEY:
- {
/* use like a modifier key */
if (event->val == KM_PRESS) {
t->flag ^= T_ALT_TRANSFORM;
@@ -6619,27 +7245,21 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_HARD;
}
break;
- }
#if 0
case EVT_MODAL_MAP:
- {
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
- {
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
break;
- }
case TFM_MODAL_EDGESLIDE_UP:
- {
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
break;
- }
}
- }
+ break;
#endif
case MOUSEMOVE:
{
- /* don't recalculat the best edge */
+ /* don't recalculate the best edge */
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
if (is_clamp) {
calcVertSlideMouseActiveEdges(t, event->mval);
@@ -6655,19 +7275,20 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_NOTHING;
}
-static void drawVertSlide(const struct bContext *C, TransInfo *t)
+static void drawVertSlide(TransInfo *t)
{
- if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = (VertSlideData *)t->customData;
+ if ((t->mode == TFM_VERT_SLIDE) && t->customData) {
+ VertSlideData *sld = t->customData;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
/* Non-Prop mode */
- if (sld) {
- View3D *v3d = CTX_wm_view3d(C);
+ {
+ View3D *v3d = t->view;
TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
TransDataVertSlideVert *sv;
const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
const int alpha_shade = -160;
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
int i;
if (v3d && v3d->zbuf)
@@ -6715,18 +7336,51 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t)
curr_sv->co_orig_3d);
bglEnd();
+ glDisable(GL_BLEND);
+
+ /* direction from active vertex! */
+ if ((t->mval[0] != t->imval[0]) ||
+ (t->mval[1] != t->imval[1]))
+ {
+ float zfac;
+ float mval_ofs[2];
+ float co_orig_3d[3];
+ float co_dest_3d[3];
+
+ mval_ofs[0] = t->mval[0] - t->imval[0];
+ mval_ofs[1] = t->mval[1] - t->imval[1];
+
+ mul_v3_m4v3(co_orig_3d, t->obedit->obmat, curr_sv->co_orig_3d);
+ zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL);
+
+ ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
+
+ invert_m4_m4(t->obedit->imat, t->obedit->obmat);
+ mul_mat3_m4_v3(t->obedit->imat, co_dest_3d);
+
+ add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
+
+ glLineWidth(1);
+ setlinestyle(1);
+
+ cpack(0xffffff);
+ glBegin(GL_LINES);
+ glVertex3fv(curr_sv->co_orig_3d);
+ glVertex3fv(co_dest_3d);
+
+ glEnd();
+ }
+
glPopMatrix();
glPopAttrib();
- glDisable(GL_BLEND);
-
if (v3d && v3d->zbuf)
glEnable(GL_DEPTH_TEST);
}
}
}
-static int doVertSlide(TransInfo *t, float perc)
+static void doVertSlide(TransInfo *t, float perc)
{
VertSlideData *sld = t->customData;
TransDataVertSlideVert *svlist = sld->sv, *sv;
@@ -6765,8 +7419,6 @@ static int doVertSlide(TransInfo *t, float perc)
}
}
}
-
- return 1;
}
static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
@@ -6791,6 +7443,8 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
/* header string */
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
@@ -6859,6 +7513,8 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -7131,7 +7787,7 @@ static void initSeqSlide(TransInfo *t)
t->num.idx_max = t->idx_max;
t->snap[0] = 0.0f;
- t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
+ t->snap[1] = floorf(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
t->snap[2] = 10.0f;
copy_v3_fl(t->num.val_inc, t->snap[1]);
@@ -7141,7 +7797,7 @@ static void initSeqSlide(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
}
-static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN])
+static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -7158,7 +7814,7 @@ static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN])
if (t->keymap) {
wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs);
+ ofs += WM_keymap_item_to_string(kmi, false, MAX_INFO_LEN - ofs, str + ofs);
}
}
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"),
@@ -7171,27 +7827,22 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
int i;
for (i = 0; i < t->total; i++, td++) {
- float tvec[2];
-
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
- copy_v2_v2(tvec, val);
-
- mul_v2_fl(tvec, td->factor);
-
- td->loc[0] = td->iloc[0] + tvec[0];
- td->loc[1] = td->iloc[1] + tvec[1];
+ madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
}
}
-static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
+static void applySeqSlide(TransInfo *t, const int mval[2])
{
char str[MAX_INFO_LEN];
+ snapSequenceBounds(t, mval);
+
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
@@ -7199,12 +7850,12 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
copy_v3_v3(t->values, tvec);
}
else {
- snapGridIncrement(t, t->values);
+ // snapGridIncrement(t, t->values);
applyNumInput(&t->num, t->values);
}
- t->values[0] = floor(t->values[0] + 0.5f);
- t->values[1] = floor(t->values[1] + 0.5f);
+ t->values[0] = floorf(t->values[0] + 0.5f);
+ t->values[1] = floorf(t->values[1] + 0.5f);
headerSeqSlide(t, t->values, str);
applySeqSlideValue(t, t->values);
@@ -7370,6 +8021,7 @@ static void initTimeTranslate(TransInfo *t)
static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
+ int ofs = 0;
/* if numeric input is active, use results from that, otherwise apply snapping to result */
if (hasNumInput(&t->num)) {
@@ -7405,10 +8057,14 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+ ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ }
}
-static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
+static void applyTimeTranslateValue(TransInfo *t)
{
TransData *td = t->data;
TransData2D *td2d = t->data2d;
@@ -7438,11 +8094,11 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
}
else if (autosnap == SACTSNAP_STEP) {
- deltax = (float)(floor(deltax + 0.5f));
+ deltax = floorf(deltax + 0.5f);
}
val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
- val += deltax;
+ val += deltax * td->factor;
*(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
}
else {
@@ -7452,7 +8108,7 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
}
else if (autosnap == SACTSNAP_STEP) {
- val = (float)(floor(val + 0.5f));
+ val = floorf(val + 0.5f);
}
*(td->val) = td->ival + val;
@@ -7466,15 +8122,17 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
static void applyTimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
- float cval[2], sval[2];
char str[MAX_INFO_LEN];
/* calculate translation amount from mouse movement - in 'time-grid space' */
- UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
+ if (t->flag & T_MODAL) {
+ float cval[2], sval[2];
+ UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
+ UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
- /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
- t->values[0] = cval[0] - sval[0];
+ /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+ t->values[0] = cval[0] - sval[0];
+ }
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -7482,7 +8140,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
t->values[0] = t->vec[0];
headerTimeTranslate(t, str);
- applyTimeTranslateValue(t, sval[0]);
+ applyTimeTranslateValue(t);
recalcData(t);
@@ -7532,7 +8190,7 @@ static void initTimeSlide(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeSlide(TransInfo *t, float sval, char str[MAX_INFO_LEN])
+static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -7615,7 +8273,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
/* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */
// XXX Need to be able to repeat this
- t->values[0] = cval[0];
+ /* t->values[0] = cval[0]; */ /* UNUSED (reset again later). */
/* handle numeric-input stuff */
t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx);
@@ -7716,7 +8374,7 @@ static void applyTimeScaleValue(TransInfo *t)
fac = (float)(floor((double)fac / secf + 0.5) * secf);
}
else if (autosnap == SACTSNAP_STEP) {
- fac = (float)(floor(fac + 0.5f));
+ fac = floorf(fac + 0.5f);
}
/* check if any need to apply nla-mapping */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 012f9185d8b..aab065675fe 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -39,9 +39,6 @@
#include "DNA_listBase.h"
-#include "BLI_smallhash.h"
-#include "BKE_editmesh.h"
-
/* ************************** Types ***************************** */
struct TransInfo;
@@ -84,6 +81,7 @@ typedef struct TransSnap {
bool project;
bool snap_self;
bool peel;
+ bool snap_spatial_grid;
short status;
float snapPoint[3]; /* snapping from this point */
float snapTarget[3]; /* to this point */
@@ -107,8 +105,6 @@ typedef struct TransCon {
float mtx[3][3]; /* Matrix of the Constraint space */
float imtx[3][3]; /* Inverse Matrix of the Constraint space */
float pmtx[3][3]; /* Projection Constraint Matrix (same as imtx with some axis == 0) */
- float center[3]; /* transformation center to define where to draw the view widget
- * ALWAYS in global space. Unlike the transformation center */
int imval[2]; /* initial mouse value for visual calculation */
/* the one in TransInfo is not garanty to stay the same (Rotates change it) */
int mode; /* Mode flags of the Constraint */
@@ -173,6 +169,13 @@ typedef struct TransDataSeq {
} TransDataSeq;
+typedef struct TransSeq {
+ TransDataSeq *tdseq;
+ int min;
+ int max;
+ bool snap_left;
+} TransSeq;
+
/* for NLA transform (stored in td->extra pointer) */
typedef struct TransDataNla {
ID *id; /* ID-block NLA-data is attached to */
@@ -193,31 +196,59 @@ typedef struct TransDataNla {
struct LinkNode;
struct GHash;
+/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
+typedef struct TransDataGenericSlideVert {
+ struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
+ float co_orig_3d[3];
+} TransDataGenericSlideVert;
+
typedef struct TransDataEdgeSlideVert {
- struct BMVert *v_a, *v_b;
+ /* TransDataGenericSlideVert */
struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
float v_co_orig[3];
+ /* end generic */
float edge_len;
+ struct BMVert *v_side[2];
+
/* add origvert.co to get the original locations */
- float dir_a[3], dir_b[3];
+ float dir_side[2][3];
int loop_nr;
} TransDataEdgeSlideVert;
+
+/* store original data so we can correct UV's and similar when sliding */
+typedef struct SlideOrigData {
+ /* flag that is set when origfaces is initialized */
+ bool use_origfaces;
+ struct GHash *origverts; /* map {BMVert: TransDataGenericSlideVert} */
+ struct GHash *origfaces;
+ struct BMesh *bm_origfaces;
+
+ struct MemArena *arena;
+ /* number of math BMLoop layers */
+ int layer_math_map_num;
+ /* array size of 'layer_math_map_num'
+ * maps TransDataVertSlideVert.cd_group index to absolute CustomData layer index */
+ int *layer_math_map;
+
+ /* array of slide vert data especially for mirror verts */
+ TransDataGenericSlideVert *sv_mirror;
+ int totsv_mirror;
+} SlideOrigData;
+
typedef struct EdgeSlideData {
TransDataEdgeSlideVert *sv;
int totsv;
-
- struct GHash *origfaces;
int mval_start[2], mval_end[2];
struct BMEditMesh *em;
- /* flag that is set when origfaces is initialized */
- bool use_origfaces;
- struct BMesh *bm_origfaces;
+ SlideOrigData orig_data;
float perc;
@@ -225,15 +256,20 @@ typedef struct EdgeSlideData {
bool flipped_vtx;
int curr_sv_index;
+
+ /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
+ int curr_side_unclamp;
} EdgeSlideData;
typedef struct TransDataVertSlideVert {
- BMVert *v;
+ /* TransDataGenericSlideVert */
+ struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
float co_orig_3d[3];
- float co_orig_2d[2];
+ /* end generic */
+
float (*co_link_orig_3d)[3];
- float (*co_link_orig_2d)[2];
int co_link_tot;
int co_link_curr;
} TransDataVertSlideVert;
@@ -244,12 +280,17 @@ typedef struct VertSlideData {
struct BMEditMesh *em;
+ SlideOrigData orig_data;
+
float perc;
bool is_proportional;
bool flipped_vtx;
int curr_sv_index;
+
+ /* result of ED_view3d_ob_project_mat_get */
+ float proj_mat[4][4];
} VertSlideData;
typedef struct BoneInitData {
@@ -319,12 +360,16 @@ typedef struct TransInfo {
eRedrawFlag redraw; /* redraw flag */
float prop_size; /* proportional circle radius */
char proptext[20]; /* proportional falloff text */
- float center[3]; /* center of transformation */
+ float aspect[3]; /* spaces using non 1:1 aspect, (uv's, f-curve, movie-clip... etc)
+ * use for conversion and snapping. */
+ float center[3]; /* center of transformation (in local-space) */
+ float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
int imval[2]; /* initial mouse position */
short event_type; /* event->type used to invoke transform */
short idx_max; /* maximum index on the input vector */
float snap[3]; /* Snapping Gears */
+ float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */
char frame_side; /* Mouse side of the cfra, 'L', 'R' or 'B' */
float viewmat[4][4]; /* copy from G.vd, prevents feedback, */
@@ -504,6 +549,7 @@ void transformApply(struct bContext *C, TransInfo *t);
int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
+void setTransformViewAspect(TransInfo *t, float r_aspect[3]);
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy);
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
@@ -537,7 +583,6 @@ void restoreBones(TransInfo *t);
/*********************** exported from transform_manipulator.c ********** */
bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */
-int calc_manipulator_stats(const struct bContext *C);
/*********************** TransData Creation and General Handling *********** */
void createTransData(struct bContext *C, TransInfo *t);
@@ -546,6 +591,7 @@ void special_aftertrans_update(struct bContext *C, TransInfo *t);
int special_transform_moving(TransInfo *t);
void transform_autoik_update(TransInfo *t, short mode);
+bool transdata_check_local_islands(TransInfo *t, short around);
int count_set_pose_transflags(int *out_mode, short around, struct Object *ob);
@@ -589,6 +635,8 @@ typedef enum {
void snapGridIncrement(TransInfo *t, float *val);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action);
+void snapSequenceBounds(TransInfo *t, const int mval[2]);
+
bool activeSnap(TransInfo *t);
bool validSnap(TransInfo *t);
@@ -651,6 +699,7 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
+void calculateCenterGlobal(TransInfo *t);
void calculateCenter(TransInfo *t);
@@ -666,6 +715,8 @@ void calculatePropRatio(TransInfo *t);
void getViewVector(TransInfo *t, float coord[3], float vec[3]);
+void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
+
/*********************** Transform Orientations ******************************/
void initTransformOrientation(struct bContext *C, TransInfo *t);
@@ -676,7 +727,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3],
const char *name, const bool overwrite);
-bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r_name[64]);
+bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r_name[64], int index);
#define ORIENTATION_NONE 0
#define ORIENTATION_NORMAL 1
@@ -684,13 +735,16 @@ bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r
#define ORIENTATION_EDGE 3
#define ORIENTATION_FACE 4
-int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3], const bool activeOnly);
+int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around);
+int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
void freeEdgeSlideVerts(TransInfo *t);
void projectEdgeSlideData(TransInfo *t, bool is_final);
+void freeVertSlideTempFaces(VertSlideData *sld);
void freeVertSlideVerts(TransInfo *t);
+void projectVertSlideData(TransInfo *t, bool is_final);
/* TODO. transform_queries.c */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index d8f17315c01..895c8a81044 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -46,13 +46,14 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
#include "ED_image.h"
#include "ED_view3d.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "UI_resources.h"
@@ -202,13 +203,13 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
return;
}
- copy_v3_v3(t_con_center, t->con.center);
+ copy_v3_v3(t_con_center, t->center_global);
/* checks for center being too close to the view center */
viewAxisCorrectCenter(t, t_con_center);
angle = fabsf(angle_v3v3(axis, t->viewinv[2]));
- if (angle > (float)M_PI / 2.0f) {
+ if (angle > (float)M_PI_2) {
angle = (float)M_PI - angle;
}
angle = RAD2DEGF(angle);
@@ -276,7 +277,7 @@ static void planeProjection(TransInfo *t, const float in[3], float out[3])
{
float vec[3], factor, norm[3];
- add_v3_v3v3(vec, in, t->con.center);
+ add_v3_v3v3(vec, in, t->center_global);
getViewVector(t, vec, norm);
sub_v3_v3v3(vec, out, in);
@@ -309,7 +310,7 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3
mul_m3_v3(t->con.pmtx, out);
// With snap, a projection is alright, no need to correct for view alignment
- if (!(t->tsnap.mode != SCE_SNAP_MODE_INCREMENT && activeSnap(t))) {
+ if (!(!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t))) {
if (getConstraintSpaceDimension(t) == 2) {
if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
planeProjection(t, in, out);
@@ -687,11 +688,11 @@ void drawConstraint(TransInfo *t)
int depth_test_enabled;
convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
- add_v3_v3(vec, tc->center);
+ add_v3_v3(vec, t->center_global);
- drawLine(t, tc->center, tc->mtx[0], 'X', 0);
- drawLine(t, tc->center, tc->mtx[1], 'Y', 0);
- drawLine(t, tc->center, tc->mtx[2], 'Z', 0);
+ drawLine(t, t->center_global, tc->mtx[0], 'X', 0);
+ drawLine(t, t->center_global, tc->mtx[1], 'Y', 0);
+ drawLine(t, t->center_global, tc->mtx[2], 'Z', 0);
glColor3ubv((GLubyte *)col2);
@@ -701,7 +702,7 @@ void drawConstraint(TransInfo *t)
setlinestyle(1);
glBegin(GL_LINE_STRIP);
- glVertex3fv(tc->center);
+ glVertex3fv(t->center_global);
glVertex3fv(vec);
glEnd();
setlinestyle(0);
@@ -711,13 +712,13 @@ void drawConstraint(TransInfo *t)
}
if (tc->mode & CON_AXIS0) {
- drawLine(t, tc->center, tc->mtx[0], 'X', DRAWLIGHT);
+ drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT);
}
if (tc->mode & CON_AXIS1) {
- drawLine(t, tc->center, tc->mtx[1], 'Y', DRAWLIGHT);
+ drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT);
}
if (tc->mode & CON_AXIS2) {
- drawLine(t, tc->center, tc->mtx[2], 'Z', DRAWLIGHT);
+ drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT);
}
}
}
@@ -728,7 +729,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
if (t->flag & T_PROP_EDIT) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float tmat[4][4], imat[4][4];
- float center[3];
int depth_test_enabled;
UI_ThemeColor(TH_GRID);
@@ -744,25 +744,21 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
glPushMatrix();
- copy_v3_v3(center, t->center);
-
- if ((t->spacetype == SPACE_VIEW3D) && t->obedit) {
- mul_m4_v3(t->obedit->obmat, center); /* because t->center is in local space */
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* pass */
}
else if (t->spacetype == SPACE_IMAGE) {
- float aspx, aspy;
-
- if (t->options & CTX_MASK) {
- /* untested - mask aspect is TODO */
- ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- aspx = aspy = 1.0;
- }
- else {
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
- }
- glScalef(1.0f / aspx, 1.0f / aspy, 1.0);
+ glScalef(1.0f / t->aspect[0], 1.0f / t->aspect[1], 1.0f);
+ }
+ else if (ELEM(t->spacetype, SPACE_IPO, 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);
+ glScalef(1.0f, (ysize / xsize) * (xmask / ymask), 1.0f);
}
depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
@@ -770,7 +766,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
glDisable(GL_DEPTH_TEST);
set_inverted_drawing(1);
- drawcircball(GL_LINE_LOOP, center, t->prop_size, imat);
+ drawcircball(GL_LINE_LOOP, t->center_global, t->prop_size, imat);
set_inverted_drawing(0);
if (depth_test_enabled)
@@ -859,21 +855,15 @@ void getConstraintMatrix(TransInfo *t)
unit_m3(t->con.pmtx);
if (!(t->con.mode & CON_AXIS0)) {
- t->con.pmtx[0][0] =
- t->con.pmtx[0][1] =
- t->con.pmtx[0][2] = 0.0f;
+ zero_v3(t->con.pmtx[0]);
}
if (!(t->con.mode & CON_AXIS1)) {
- t->con.pmtx[1][0] =
- t->con.pmtx[1][1] =
- t->con.pmtx[1][2] = 0.0f;
+ zero_v3(t->con.pmtx[1]);
}
if (!(t->con.mode & CON_AXIS2)) {
- t->con.pmtx[2][0] =
- t->con.pmtx[2][1] =
- t->con.pmtx[2][2] = 0.0f;
+ zero_v3(t->con.pmtx[2]);
}
mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
@@ -961,7 +951,7 @@ static void setNearestAxis3d(TransInfo *t)
mul_v3_fl(axis, zfac);
/* now we can project to get window coordinate */
- add_v3_v3(axis, t->con.center);
+ add_v3_v3(axis, t->center_global);
projectFloatView(t, axis, axis_2d);
sub_v2_v2v2(axis, axis_2d, t->center2d);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index b7098085ac2..c12418f1a0f 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <math.h>
+#include <limits.h>
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
@@ -54,11 +55,11 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_smallhash.h"
#include "BLI_listbase.h"
#include "BLI_linklist_stack.h"
#include "BLI_string.h"
#include "BLI_bitmap.h"
+#include "BLI_rect.h"
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
@@ -90,7 +91,6 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
-#include "BKE_lattice.h"
#include "BIK_api.h"
@@ -107,6 +107,7 @@
#include "ED_uvedit.h"
#include "ED_clip.h"
#include "ED_mask.h"
+#include "ED_gpencil.h"
#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
#include "WM_types.h"
@@ -218,6 +219,9 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
float _proj_vec[3];
const float *proj_vec = NULL;
+ /* support for face-islands */
+ const bool use_island = transdata_check_local_islands(t, t->around);
+
if (t->flag & T_PROP_PROJECTED) {
if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = t->ar->regiondata;
@@ -239,7 +243,12 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_SELECTED) {
- sub_v3_v3v3(vec, tob->center, td->center);
+ if (use_island) {
+ sub_v3_v3v3(vec, tob->iloc, td->iloc);
+ }
+ else {
+ sub_v3_v3v3(vec, tob->center, td->center);
+ }
mul_m3_v3(tob->mtx, vec);
if (proj_vec) {
@@ -249,8 +258,12 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
dist_sq = len_squared_v3(vec);
- if ((tob->rdist == -1.0f) || (dist_sq < (tob->rdist * tob->rdist))) {
+ if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
tob->rdist = sqrtf(dist_sq);
+ if (use_island) {
+ copy_v3_v3(tob->center, td->center);
+ copy_m3_m3(tob->axismtx, td->axismtx);
+ }
}
}
else {
@@ -329,20 +342,20 @@ static void createTransEdge(TransInfo *t)
BMIter iter;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
int cd_edge_float_offset;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
}
if (countsel == 0)
return;
- if (propmode) {
+ if (is_prop_edit) {
t->total = count;
}
else {
@@ -368,7 +381,7 @@ static void createTransEdge(TransInfo *t)
BLI_assert(cd_edge_float_offset != -1);
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || propmode)) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
float *fl_ptr;
/* need to set center for center calculations */
mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
@@ -616,10 +629,10 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
mul_m3_m3m3(td->axismtx, omat, pmat);
normalize_m3(td->axismtx);
- if (t->mode == TFM_BONESIZE) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
bArmature *arm = t->poseobj->data;
- if (arm->drawtype == ARM_ENVELOPE) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
td->val = &bone->dist;
td->ival = bone->dist;
@@ -706,7 +719,7 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
/* make sure no bone can be transformed when a parent is transformed */
/* since pchans are depsgraph sorted, the parents are in beginning of list */
- if (mode != TFM_BONESIZE) {
+ if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
if (bone->flag & BONE_TRANSFORM)
@@ -1056,11 +1069,13 @@ static void createTransPose(TransInfo *t, Object *ob)
void restoreBones(TransInfo *t)
{
+ bArmature *arm = t->obedit->data;
BoneInitData *bid = t->customData;
EditBone *ebo;
while (bid->bone) {
ebo = bid->bone;
+
ebo->dist = bid->dist;
ebo->rad_tail = bid->rad_tail;
ebo->roll = bid->roll;
@@ -1068,7 +1083,26 @@ void restoreBones(TransInfo *t)
ebo->zwidth = bid->zwidth;
copy_v3_v3(ebo->head, bid->head);
copy_v3_v3(ebo->tail, bid->tail);
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *ebo_child;
+
+ /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
+ for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
+ if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
+ copy_v3_v3(ebo_child->head, ebo->tail);
+ ebo_child->rad_head = ebo->rad_tail;
+ }
+ }
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ EditBone *parent = ebo->parent;
+ copy_v3_v3(parent->tail, ebo->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+
bid++;
}
}
@@ -1092,7 +1126,7 @@ static void createTransArmatureVerts(TransInfo *t)
oldtot = t->total;
if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (t->mode == TFM_BONESIZE) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED)
t->total++;
}
@@ -1170,9 +1204,9 @@ static void createTransArmatureVerts(TransInfo *t)
}
}
- else if (t->mode == TFM_BONESIZE) {
+ else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED) {
- if (arm->drawtype == ARM_ENVELOPE) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
td->val = &ebo->dist;
td->ival = ebo->dist;
@@ -1218,7 +1252,13 @@ static void createTransArmatureVerts(TransInfo *t)
else {
if (ebo->flag & BONE_TIPSEL) {
copy_v3_v3(td->iloc, ebo->tail);
- copy_v3_v3(td->center, (t->around == V3D_LOCAL) ? ebo->head : td->iloc);
+
+ /* don't allow single selected tips to have a modified center,
+ * causes problem with snapping T45974 */
+ copy_v3_v3(td->center,
+ ((t->around == V3D_LOCAL) &&
+ (ebo->flag & BONE_ROOTSEL)) ? ebo->head : td->iloc);
+
td->loc = ebo->tail;
td->flag = TD_SELECTED;
if (ebo->flag & BONE_EDITMODE_LOCKED)
@@ -1297,18 +1337,18 @@ static void createTransMBallVerts(TransInfo *t)
TransDataExtension *tx;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
/* count totals */
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
@@ -1318,7 +1358,7 @@ static void createTransMBallVerts(TransInfo *t)
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (propmode || (ml->flag & SELECT)) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
td->loc = &ml->x;
copy_v3_v3(td->iloc, td->loc);
copy_v3_v3(td->center, td->loc);
@@ -1431,7 +1471,7 @@ static void createTransCurveVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
ListBase *nurbs;
@@ -1446,13 +1486,13 @@ static void createTransCurveVerts(TransInfo *t)
if (bezt->hide == 0) {
if (hide_handles) {
if (bezt->f2 & SELECT) countsel += 3;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
else {
if (bezt->f1 & SELECT) countsel++;
if (bezt->f2 & SELECT) countsel++;
if (bezt->f3 & SELECT) countsel++;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
}
}
@@ -1460,7 +1500,7 @@ static void createTransCurveVerts(TransInfo *t)
else {
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode) count++;
+ if (is_prop_edit) count++;
if (bp->f1 & SELECT) countsel++;
}
}
@@ -1469,7 +1509,7 @@ static void createTransCurveVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
@@ -1504,7 +1544,7 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f1 & SELECT) && hide_handles == 0))
{
@@ -1538,7 +1578,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (propmode || (bezt->f2 & SELECT)) {
+ if (is_prop_edit || (bezt->f2 & SELECT)) {
copy_v3_v3(td->iloc, bezt->vec[1]);
td->loc = bezt->vec[1];
copy_v3_v3(td->center, td->loc);
@@ -1574,7 +1614,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f3 & SELECT) && hide_handles == 0))
{
@@ -1611,17 +1651,17 @@ static void createTransCurveVerts(TransInfo *t)
(void)hdata; /* quiet warning */
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
/* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
* but for now just don't change handle types */
- if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0) {
+ if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
/* sets the handles based on their selection, do this after the data is copied to the TransData */
BKE_nurb_handles_test(nu, !hide_handles);
}
@@ -1631,7 +1671,7 @@ static void createTransCurveVerts(TransInfo *t)
head = tail = td;
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -1656,12 +1696,12 @@ static void createTransCurveVerts(TransInfo *t)
tail++;
}
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1677,14 +1717,14 @@ static void createTransLatticeVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
if (bp->hide == 0) {
if (bp->f1 & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
bp++;
}
@@ -1692,7 +1732,7 @@ static void createTransLatticeVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
@@ -1703,7 +1743,7 @@ static void createTransLatticeVerts(TransInfo *t)
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
if (bp->hide == 0) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
@@ -1711,7 +1751,9 @@ static void createTransLatticeVerts(TransInfo *t)
if (bp->f1 & SELECT) {
td->flag = TD_SELECTED;
}
- else td->flag = 0;
+ else {
+ td->flag = 0;
+ }
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
@@ -1742,7 +1784,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
float mat[4][4];
int i, k, transformparticle;
int count = 0, hasselected = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
@@ -1764,7 +1806,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
hasselected = 1;
transformparticle = 1;
}
- else if (propmode)
+ else if (is_prop_edit)
transformparticle = 1;
}
}
@@ -1814,7 +1856,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (key->flag & PEK_SELECT)
td->flag |= TD_SELECTED;
- else if (!propmode)
+ else if (!is_prop_edit)
td->flag |= TD_SKIP;
unit_m3(td->mtx);
@@ -1843,7 +1885,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
tx++;
tail++;
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1859,7 +1901,8 @@ void flushTransParticles(TransInfo *t)
PTCacheEditKey *key;
TransData *td;
float mat[4][4], imat[4][4], co[3];
- int i, k, propmode = t->flag & T_PROP_EDIT;
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (psys)
psmd = psys_get_modifier(ob, psys);
@@ -1880,7 +1923,7 @@ void flushTransParticles(TransInfo *t)
/* optimization for proportional edit */
- if (!propmode || !compare_v3v3(key->co, co, 0.0001f)) {
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
copy_v3_v3(key->co, co);
point->flag |= PEP_EDIT_RECALC;
}
@@ -1938,17 +1981,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
int i;
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ float dist;
BM_elem_index_set(v, i); /* set_inline */
BM_elem_flag_disable(v, BM_ELEM_TAG);
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- dists[i] = FLT_MAX;
+ dist = FLT_MAX;
}
else {
BLI_LINKSTACK_PUSH(queue, v);
-
- dists[i] = 0.0f;
+ dist = 0.0f;
}
+
+ dists[i] = dists_prev[i] = dist;
}
bm->elem_index_dirty &= ~BM_VERT;
}
@@ -1957,55 +2002,77 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
BMVert *v;
LinkNode *lnk;
+ /* this is correct but slow to do each iteration,
+ * instead sync the dist's while clearing BM_ELEM_TAG (below) */
+#if 0
memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+#endif
while ((v = BLI_LINKSTACK_POP(queue))) {
- /* quick checks */
- bool has_edges = (v->e != NULL);
- bool has_faces = false;
+ BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
/* connected edge-verts */
- if (has_edges) {
- BMIter iter;
- BMEdge *e;
+ if (v->e != NULL) {
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- has_faces |= (BM_edge_is_wire(e) == false);
+ /* would normally use BM_EDGES_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
+
+ /* edge distance */
+ BMVert *v_other = BM_edge_other_vert(e_iter, v);
if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
}
}
- }
- }
- }
-
- /* imaginary edge diagonally across quad */
- if (has_faces) {
- BMIter iter;
- BMLoop *l;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len == 4)) {
- BMVert *v_other = l->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
+ /* face distance */
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ /**
+ * imaginary edge diagonally across quad,
+ * \note, this takes advantage of the rules of winding that we
+ * know 2 or more of a verts edges wont reference the same face twice.
+ * Also, if the edge is hidden, the face will be hidden too.
+ */
+ l_iter_radial = l_first_radial = e_iter->l;
+
+ do {
+ if ((l_iter_radial->v == v) &&
+ (l_iter_radial->f->len == 4) &&
+ (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0))
+ {
+ BMVert *v_other = l_iter_radial->next->next->v;
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
}
}
- }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
}
}
+
/* clear for the next loop */
for (lnk = queue_next; lnk; lnk = lnk->next) {
- BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG);
+ BMVert *v = lnk->link;
+ const int i = BM_elem_index_get(v);
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ /* keep in sync, avoid having to do full memcpy each iteration */
+ dists_prev[i] = dists[i];
}
BLI_LINKSTACK_SWAP(queue, queue_next);
@@ -2063,7 +2130,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
* its possible we have a selected vertex thats not in a face, for now best not crash in that case. */
- fill_vn_i(vert_map, bm->totvert, -1);
+ copy_vn_i(vert_map, bm->totvert, -1);
BM_mesh_elem_table_ensure(bm, htype);
ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
@@ -2144,6 +2211,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
BMEditMesh *em, BMVert *eve, float *bweight,
struct TransIslandData *v_island)
{
+ float *no, _no[3];
BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
td->flag = 0;
@@ -2153,19 +2221,30 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
td->loc = eve->co;
copy_v3_v3(td->iloc, td->loc);
+ if ((t->mode == TFM_SHRINKFATTEN) &&
+ (em->selectmode & SCE_SELECT_FACE) &&
+ BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
+ (BM_vert_normal_update_ex(eve, BM_ELEM_SELECT, _no)))
+ {
+ no = _no;
+ }
+ else {
+ no = eve->no;
+ }
+
if (v_island) {
copy_v3_v3(td->center, v_island->co);
copy_m3_m3(td->axismtx, v_island->axismtx);
}
else if (t->around == V3D_LOCAL) {
copy_v3_v3(td->center, td->loc);
- createSpaceNormal(td->axismtx, eve->no);
+ createSpaceNormal(td->axismtx, no);
}
else {
copy_v3_v3(td->center, td->loc);
/* Setting normals */
- copy_v3_v3(td->axismtx[2], eve->no);
+ copy_v3_v3(td->axismtx[2], no);
td->axismtx[0][0] =
td->axismtx[0][1] =
td->axismtx[0][2] =
@@ -2194,7 +2273,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
}
else if (t->mode == TFM_SHRINKFATTEN) {
td->ext = tx;
- tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, BM_ELEM_SELECT);
+ tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
}
}
@@ -2211,7 +2290,7 @@ static void createTransEditVerts(TransInfo *t)
float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
float *dists = NULL;
int a;
- int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int mirror = 0;
int cd_vert_bweight_offset = -1;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@@ -2251,7 +2330,7 @@ static void createTransEditVerts(TransInfo *t)
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
- if (propmode) {
+ if (prop_mode) {
unsigned int count = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
@@ -2262,7 +2341,7 @@ static void createTransEditVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (propmode & T_PROP_CONNECTED)
+ if (prop_mode & T_PROP_CONNECTED)
dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
}
else {
@@ -2284,7 +2363,7 @@ static void createTransEditVerts(TransInfo *t)
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode & T_PROP_CONNECTED) {
editmesh_set_connectivity_distance(em->bm, mtx, dists);
}
@@ -2298,7 +2377,7 @@ static void createTransEditVerts(TransInfo *t)
if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) {
/* check if we can use deform matrices for modifier from the
* start up to stack, they are more accurate than quats */
- totleft = editbmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos);
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos);
}
/* if we still have more modifiers, also do crazyspace
@@ -2313,7 +2392,7 @@ static void createTransEditVerts(TransInfo *t)
{
mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !propmode);
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
if (mappedcos)
MEM_freeN(mappedcos);
}
@@ -2338,7 +2417,7 @@ static void createTransEditVerts(TransInfo *t)
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ?
&island_info[island_vert_map[a]] : NULL;
float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
@@ -2351,8 +2430,8 @@ static void createTransEditVerts(TransInfo *t)
if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
tob->flag |= TD_SELECTED;
- if (propmode) {
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
tob->dist = dists[a];
}
else {
@@ -2604,24 +2683,23 @@ void flushTransSeq(TransInfo *t)
/* ********************* UV ****************** */
-static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, float *uv, int selected)
+static void UVsToTransData(
+ const float aspect[2], TransData *td, TransData2D *td2d,
+ float *uv, const float *center, bool selected)
{
- float aspx, aspy;
-
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
-
/* uv coords are scaled by aspects. this is needed for rotations and
* proportional editing to be consistent with the stretched uv coords
* that are displayed. this also means that for display and numinput,
- * and when the the uv coords are flushed, these are converted each time */
- td2d->loc[0] = uv[0] * aspx;
- td2d->loc[1] = uv[1] * aspy;
+ * and when the uv coords are flushed, these are converted each time */
+ td2d->loc[0] = uv[0] * aspect[0];
+ td2d->loc[1] = uv[1] * aspect[1];
td2d->loc[2] = 0.0f;
td2d->loc2d = uv;
td->flag = 0;
td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
+ copy_v2_v2(td->center, center ? center : td->loc);
+ td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
memset(td->axismtx, 0, sizeof(td->axismtx));
@@ -2648,36 +2726,43 @@ static void createTransUVs(bContext *C, TransInfo *t)
ToolSettings *ts = CTX_data_tool_settings(C);
TransData *td = NULL;
TransData2D *td2d = NULL;
- MTexPoly *tf;
- MLoopUV *luv;
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMFace *efa;
- BMLoop *l;
BMIter iter, liter;
UvElementMap *elementmap = NULL;
BLI_bitmap *island_enabled = NULL;
+ struct { float co[2]; int co_num; } *island_center = NULL;
int count = 0, countsel = 0, count_rejected = 0;
- const bool propmode = (t->flag & T_PROP_EDIT) != 0;
- const bool propconnected = (t->flag & T_PROP_CONNECTED) != 0;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_island_center = (t->around == V3D_LOCAL);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- if (!ED_space_image_show_uvedit(sima, t->obedit)) return;
+ if (!ED_space_image_show_uvedit(sima, t->obedit))
+ return;
/* count */
- if (propconnected) {
+ if (is_prop_connected || is_island_center) {
/* create element map with island information */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- elementmap = BM_uv_element_map_create(em->bm, false, true);
+ const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
+ elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ if (elementmap == NULL) {
+ return;
}
- else {
- elementmap = BM_uv_element_map_create(em->bm, true, true);
+
+ if (is_prop_connected) {
+ island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ }
+
+ if (is_island_center) {
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
}
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ BMLoop *l;
if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
@@ -2689,14 +2774,25 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
countsel++;
- if (propconnected) {
+ if (is_prop_connected || island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
+ if (is_prop_connected) {
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
+ }
+
+ if (is_island_center) {
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
+ }
+ }
+ }
}
- if (propmode) {
+ if (is_prop_edit) {
count++;
}
}
@@ -2704,13 +2800,19 @@ static void createTransUVs(bContext *C, TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) {
- if (propconnected) {
- MEM_freeN(island_enabled);
+ goto finally;
+ }
+
+ if (is_island_center) {
+ int i;
+
+ for (i = 0; i < elementmap->totalIslands; i++) {
+ mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
+ mul_v2_v2(island_center[i].co, t->aspect);
}
- return;
}
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -2723,56 +2825,88 @@ static void createTransUVs(bContext *C, TransInfo *t)
td2d = t->data2d;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (!propmode && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ MLoopUV *luv;
+ const float *center = NULL;
+
+ if (!is_prop_edit && !selected)
continue;
- if (propconnected) {
+ if (is_prop_connected || is_island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
+
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
+ }
+
+ if (is_island_center) {
+ center = island_center[element->island].co;
}
}
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(sima, td++, td2d++, luv->uv, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
}
}
- if (propconnected) {
+ if (is_prop_connected) {
t->total -= count_rejected;
- BM_uv_element_map_free(elementmap);
- MEM_freeN(island_enabled);
}
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
+
+
+finally:
+ if (is_prop_connected || is_island_center) {
+ BM_uv_element_map_free(elementmap);
+
+ if (is_prop_connected) {
+ MEM_freeN(island_enabled);
+ }
+
+ if (island_center) {
+ MEM_freeN(island_center);
+ }
+ }
}
void flushTransUVs(TransInfo *t)
{
SpaceImage *sima = t->sa->spacedata.first;
TransData2D *td;
- int a, width, height;
- float aspx, aspy, invx, invy;
+ int a;
+ float aspect_inv[2], size[2];
+ const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
+
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- ED_space_image_get_size(sima, &width, &height);
- invx = 1.0f / aspx;
- invy = 1.0f / aspy;
+ if (use_pixel_snap) {
+ int size_i[2];
+ ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
+ size[0] = size_i[0];
+ size[1] = size_i[1];
+ }
/* flush to 2d vector from internally used 3d vector */
for (a = 0, td = t->data2d; a < t->total; a++, td++) {
- td->loc2d[0] = td->loc[0] * invx;
- td->loc2d[1] = td->loc[1] * invy;
+ td->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td->loc2d[1] = td->loc[1] * aspect_inv[1];
- if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
- td->loc2d[0] = (float)floor(width * td->loc2d[0] + 0.5f) / width;
- td->loc2d[1] = (float)floor(height * td->loc2d[1] + 0.5f) / height;
+ if (use_pixel_snap) {
+ td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
+ td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
}
}
}
@@ -2780,44 +2914,45 @@ void flushTransUVs(TransInfo *t)
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
TransData *td;
- int a, clipx = 1, clipy = 1;
- float aspx, aspy, min[2], max[2];
+ int a;
+ bool clipx = true, clipy = true;
+ float min[2], max[2];
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
min[0] = min[1] = 0.0f;
- max[0] = aspx; max[1] = aspy;
+ max[0] = t->aspect[0];
+ max[1] = t->aspect[1];
for (a = 0, td = t->data; a < t->total; a++, td++) {
minmax_v2v2_v2(min, max, td->loc);
}
if (resize) {
- if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx * 0.5f)
+ if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f)
vec[0] *= t->center[0] / (t->center[0] - min[0]);
- else if (max[0] > aspx && t->center[0] < aspx)
- vec[0] *= (t->center[0] - aspx) / (t->center[0] - max[0]);
+ else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0])
+ vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]);
else
clipx = 0;
- if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy * 0.5f)
+ if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f)
vec[1] *= t->center[1] / (t->center[1] - min[1]);
- else if (max[1] > aspy && t->center[1] < aspy)
- vec[1] *= (t->center[1] - aspy) / (t->center[1] - max[1]);
+ else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1])
+ vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]);
else
clipy = 0;
}
else {
if (min[0] < 0.0f)
vec[0] -= min[0];
- else if (max[0] > aspx)
- vec[0] -= max[0] - aspx;
+ else if (max[0] > t->aspect[0])
+ vec[0] -= max[0] - t->aspect[0];
else
clipx = 0;
if (min[1] < 0.0f)
vec[1] -= min[1];
- else if (max[1] > aspy)
- vec[1] -= max[1] - aspy;
+ else if (max[1] > t->aspect[1])
+ vec[1] -= max[1] - t->aspect[1];
else
clipy = 0;
}
@@ -2829,9 +2964,6 @@ void clipUVData(TransInfo *t)
{
TransData *td = NULL;
int a;
- float aspx, aspy;
-
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
for (a = 0, td = t->data; a < t->total; a++, td++) {
if (td->flag & TD_NOACTION)
@@ -2840,8 +2972,8 @@ void clipUVData(TransInfo *t)
if ((td->flag & TD_SKIP) || (!td->loc))
continue;
- td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), aspx);
- td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), aspy);
+ td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
+ td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
}
}
@@ -3115,7 +3247,7 @@ static void posttrans_gpd_clean(bGPdata *gpd)
bGPDframe *gpf, *gpfn;
bool is_double = false;
- BLI_sortlist_r(&gpl->frames, &is_double, gpf_cmp_frame);
+ BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
if (is_double) {
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
@@ -3142,7 +3274,7 @@ static void posttrans_mask_clean(Mask *mask)
MaskLayerShape *masklay_shape, *masklay_shape_next;
bool is_double = false;
- BLI_sortlist_r(&masklay->splines_shapes, &is_double, masklay_shape_cmp_frame);
+ BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
if (is_double) {
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape_next) {
@@ -3164,7 +3296,7 @@ static void posttrans_mask_clean(Mask *mask)
/* Called during special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
*/
-static void posttrans_fcurve_clean(FCurve *fcu, const short use_handle)
+static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
{
float *selcache; /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */
int len, index, i; /* number of frames in cache, item index */
@@ -3186,7 +3318,7 @@ static void posttrans_fcurve_clean(FCurve *fcu, const short use_handle)
for (i = 0; i < fcu->totvert; i++) {
BezTriple *bezt = &fcu->bezt[i];
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
selcache[index] = bezt->vec[1][0];
index++;
len++;
@@ -3200,7 +3332,7 @@ static void posttrans_fcurve_clean(FCurve *fcu, const short use_handle)
for (i = fcu->totvert - 1; i >= 0; i--) {
BezTriple *bezt = &fcu->bezt[i];
- if (BEZSELECTED(bezt) == 0) {
+ if (BEZT_ISSEL_ANY(bezt) == 0) {
/* check beztriple should be removed according to cache */
for (index = 0; index < len; index++) {
if (IS_EQF(bezt->vec[1][0], selcache[index])) {
@@ -3258,76 +3390,90 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
/* ----------------------------- */
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_fcurve_keys(FCurve *fcu, char side, float cfra)
+static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
{
BezTriple *bezt;
- int i, count = 0;
+ int i, count = 0, count_all = 0;
if (ELEM(NULL, fcu, fcu->bezt))
return count;
/* only include points that occur on the right side of cfra */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (bezt->f2 & SELECT) {
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
/* no need to adjust the handle selection since they are assumed
* selected (like graph editor with SIPO_NOHANDLES) */
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- count += 1;
- }
+ if (bezt->f2 & SELECT)
+ count++;
+
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
{
bGPDframe *gpf;
- int count = 0;
+ int count = 0, count_all = 0;
if (gpl == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra))
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ if (gpf->flag & GP_FRAME_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra)
+static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
{
MaskLayerShape *masklayer_shape;
- int count = 0;
+ int count = 0, count_all = 0;
if (masklay == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape; masklayer_shape = masklayer_shape->next) {
- if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
- if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra))
+ if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
+ if (masklayer_shape->flag & MASK_SHAPE_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* This function assigns the information to transdata */
-static void TimeToTransData(TransData *td, float *time, AnimData *adt)
+static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
{
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = time;
td->ival = *(time);
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
/* store the AnimData where this keyframe exists as a keyframe of the
* active action as td->extra.
*/
@@ -3341,7 +3487,7 @@ static void TimeToTransData(TransData *td, float *time, AnimData *adt)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra)
+static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra, bool is_prop_edit, float ypos)
{
BezTriple *bezt;
TransData2D *td2d = *td2dv;
@@ -3352,11 +3498,14 @@ static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FC
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* only add selected keyframes (for now, proportional edit is not enabled) */
- if (bezt->f2 & SELECT) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
+ if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(), so can't use BEZT_ISSEL_ANY() macro */
/* only add if on the right 'side' of the current frame */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- TimeToTransData(td, bezt->vec[1], adt);
+ TimeToTransData(td, bezt->vec[1], adt, ypos);
+ if (bezt->f2 & SELECT)
+ td->flag |= TD_SELECTED;
+
/*set flags to move handles as necessary*/
td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
td2d->h1 = bezt->vec[0];
@@ -3407,19 +3556,22 @@ void flushTransIntFrameActionData(TransInfo *t)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra)
+static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos)
{
bGPDframe *gpf;
int count = 0;
/* check for select frames on right side of current frame */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
+ if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)gpf->framenum;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
@@ -3435,19 +3587,22 @@ static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl,
}
/* refer to comment above #GPLayerToTransData, this is the same but for masks */
-static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra)
+static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra, bool is_prop_edit, float ypos)
{
MaskLayerShape *masklay_shape;
int count = 0;
/* check for select frames on right side of current frame */
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)masklay_shape->frame;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)masklay_shape->frame;
tfd->sdata = &masklay_shape->frame;
@@ -3469,15 +3624,25 @@ static void createTransActionData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
tGPFtransdata *tfd = NULL;
-
+
+ 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);
+
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
int count = 0;
float cfra;
-
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
@@ -3505,7 +3670,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
-
+ int adt_count = 0;
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
*/
@@ -3514,14 +3679,19 @@ static void createTransActionData(bContext *C, TransInfo *t)
else
cfra = (float)CFRA;
- if (ale->type == ANIMTYPE_FCURVE)
- count += count_fcurve_keys(ale->key_data, t->frame_side, cfra);
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
+ adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_GPLAYER)
- count += count_gplayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_MASKLAYER)
- count += count_masklayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else
BLI_assert(0);
+
+ if (adt_count > 0) {
+ count += adt_count;
+ ale->tag = true;
+ }
}
/* stop if trying to build list if nothing selected */
@@ -3558,11 +3728,22 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ if (is_prop_edit && !ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
if (ale->type == ANIMTYPE_GPLAYER) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
int i;
- i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra);
+ i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3570,7 +3751,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
MaskLayer *masklay = (MaskLayer *)ale->data;
int i;
- i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra);
+ i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3578,15 +3759,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
-
- td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra);
+ td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
}
}
@@ -3615,6 +3788,109 @@ static void createTransActionData(bContext *C, TransInfo *t)
*((float *)(t->customData) + 1) = max;
}
+ /* calculate distances for proportional editing */
+ if (is_prop_edit) {
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ /* F-Curve may not have any keyframes */
+ if (!ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ bGPDframe *gpf_iter;
+ int min = INT_MAX;
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf->next) {
+ if (gpf_iter->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
+ int val = abs(gpf->framenum - gpf_iter->framenum);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ MaskLayerShape *masklay_iter;
+ int min = INT_MAX;
+ for (masklay_iter = masklay->splines_shapes.first; masklay_iter; masklay_iter = masklay_iter->next) {
+ if (masklay_iter->flag & MASK_SHAPE_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
+ int val = abs(masklay_shape->frame - masklay_iter->frame);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ else {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ if (bezt->f2 & SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ BezTriple *bezt_iter;
+ int j;
+ float min = FLT_MAX;
+ for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
+ if (bezt_iter->f2 & SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
+ float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
+ if (val < min)
+ min = val;
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ }
+ }
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -3623,6 +3899,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
typedef struct TransDataGraph {
float unit_scale;
+ float offset;
} TransDataGraph;
/* Helper function for createTransGraphEditData, which is responsible for associating
@@ -3631,7 +3908,7 @@ typedef struct TransDataGraph {
static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *tdg,
AnimData *adt, BezTriple *bezt,
int bi, bool selected, bool ishandle, bool intvals,
- float mtx[3][3], float smtx[3][3], float unit_scale)
+ float mtx[3][3], float smtx[3][3], float unit_scale, float offset)
{
float *loc = bezt->vec[bi];
const float *cent = bezt->vec[1];
@@ -3645,26 +3922,26 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
if (adt) {
td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
- td->center[1] = cent[1] * unit_scale;
+ td->center[1] = (cent[1] + offset) * unit_scale;
td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
}
else {
td2d->loc[0] = loc[0];
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
copy_v3_v3(td->center, cent);
- td->center[1] *= unit_scale;
+ td->center[1] = (td->center[1] + offset) * unit_scale;
copy_v3_v3(td->iloc, td->loc);
}
@@ -3704,6 +3981,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
copy_m3_m3(td->smtx, smtx);
tdg->unit_scale = unit_scale;
+ tdg->offset = offset;
}
static bool graph_edit_is_translation_mode(TransInfo *t)
@@ -3716,6 +3994,29 @@ static bool graph_edit_use_local_center(TransInfo *t)
return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
}
+
+static void graph_key_shortest_dist(TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
+{
+ int j = 0;
+ TransData *td_iter = td_start;
+
+ td->dist = FLT_MAX;
+ for (; j < fcu->totvert; j++) {
+ BezTriple *bezt = fcu->bezt + j;
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2 || sel3) {
+ td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+ }
+
+ td_iter += 3;
+ }
+ }
+}
+
static void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
@@ -3734,11 +4035,11 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
BezTriple *bezt;
int count = 0, i;
- float cfra;
float mtx[3][3], smtx[3][3];
const bool is_translation_mode = graph_edit_is_translation_mode(t);
const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
const bool use_local_center = graph_edit_use_local_center(t);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
/* determine what type of data we are operating on */
@@ -3769,7 +4070,14 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
-
+ float cfra;
+ int curvecount = 0;
+ bool selected = false;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL)
+ continue;
+
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
*/
@@ -3777,48 +4085,44 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL)
- continue;
-
+
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = bezt->f2 & SELECT;
- const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2;
- const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2;
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (is_prop_edit) {
+ curvecount += 3;
+ if (sel2 || sel1 || sel3)
+ selected = true;
+ }
+ else {
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ count++;
+ }
- if (is_translation_mode) {
- /* for 'normal' pivots - just include anything that is selected.
- * this works a bit differently in translation modes */
- if (sel2) {
- count++;
- }
- else {
- if (sel1) count++;
- if (sel3) count++;
+ if (sel3) {
+ count++;
+ }
}
- }
- else if (use_local_center) {
- /* for local-pivot we only need to count the number of selected handles only,
- * so that centerpoints don't get moved wrong
- */
- if (bezt->ipo == BEZT_IPO_BEZ) {
- if (sel1) count++;
- if (sel3) count++;
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ count++;
}
- /* else if (sel2) count++; // TODO: could this cause problems? */
- /* - yes this causes problems, because no td is created for the center point */
- }
- else {
- /* for 'normal' pivots - just include anything that is selected */
- if (sel1) count++;
- if (sel2) count++;
- if (sel3) count++;
}
}
}
+
+ if (is_prop_edit) {
+ if (selected) {
+ count += curvecount;
+ ale->tag = true;
+ }
+ }
}
/* stop if trying to build list if nothing selected */
@@ -3864,8 +4168,13 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- bool intvals = (fcu->flag & FCURVE_INT_VALUES);
- float unit_scale;
+ bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
+ float unit_scale, offset;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0))
+ continue;
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
@@ -3874,83 +4183,148 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL)
- continue;
-
- unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag);
+
+ unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = bezt->f2 & SELECT;
- const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2;
- const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2;
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
TransDataCurveHandleFlags *hdata = NULL;
/* short h1=1, h2=1; */ /* UNUSED */
- /* only include handles if selected, irrespective of the interpolation modes.
- * also, only treat handles specially if the center point isn't selected.
- */
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
+ if (is_prop_edit) {
+ bool is_sel = (sel2 || sel1 || sel3);
+ /* we always select all handles for proportional editing if central handle is selected */
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, is_sel, false, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* only include handles if selected, irrespective of the interpolation modes.
+ * also, only treat handles specially if the center point isn't selected.
+ */
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h1 = 0; */ /* UNUSED */
+ }
+
+ if (sel3) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h2 = 0; */ /* UNUSED */
+ }
}
- else {
- /* h1 = 0; */ /* UNUSED */
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ /* move handles relative to center */
+ if (is_translation_mode) {
+ if (sel1) td->flag |= TD_MOVEHANDLE1;
+ if (sel3) td->flag |= TD_MOVEHANDLE2;
+ }
+
+ /* if handles were not selected, store their selection status */
+ if (!(sel1) || !(sel3)) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale, offset);
+
}
-
- if (sel3) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
+ /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
+ * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+ * then check if we're using auto-handles.
+ * - If so, change them auto-handles to aligned handles so that handles get affected too
+ */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
+ {
+ if (hdata && (sel1) && (sel3)) {
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Sets handles based on the selection */
+ testhandles_fcurve(fcu, use_handle);
+ }
+
+ if (is_prop_edit) {
+ /* loop 2: build transdata arrays */
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ TransData *td_start = td;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (ale->tag == 0))
+ continue;
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2) {
+ td->dist = td->rdist = 0.0f;
}
else {
- /* h2 = 0; */ /* UNUSED */
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- /* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) td->flag |= TD_MOVEHANDLE1;
- if (sel3) td->flag |= TD_MOVEHANDLE2;
+ td++;
+
+ if (sel2) {
+ td->dist = td->rdist = 0.0f;
}
-
- /* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
-
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale);
-
- }
- /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
- * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
- * then check if we're using auto-handles.
- * - If so, change them auto-handles to aligned handles so that handles get affected too
- */
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
- {
- if (hdata && (sel1) && (sel3)) {
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
+ td++;
+
+ if (sel3 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
+ td++;
}
}
}
-
- /* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
}
-
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -4130,7 +4504,7 @@ void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
bAnimListElem *ale;
- const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
/* sort and reassign verts */
for (ale = anim_data->first; ale; ale = ale->next) {
@@ -4234,7 +4608,7 @@ void flushTransGraphData(TransInfo *t)
if (td->flag & TD_INTVALUES)
td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f);
else
- td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale;
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
@@ -4493,10 +4867,47 @@ static int SeqToTransData_Recursive(TransInfo *t, ListBase *seqbase, TransData *
}
}
}
-
return tot;
}
+
+static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
+{
+ Sequence *seq;
+ int recursive, count, flag;
+ int max = INT32_MIN, min = INT32_MAX;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+
+ /* just to get the flag since there are corner cases where this isn't totally obvious */
+ SeqTransInfo(t, seq, &recursive, &count, &flag);
+
+ /* use 'flag' which is derived from seq->flag but modified for special cases */
+ if (flag & SELECT) {
+ if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ if (flag & SEQ_LEFTSEL) {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->startdisp, max);
+ }
+ if (flag & SEQ_RIGHTSEL) {
+ min = min_ii(seq->enddisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ else {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ }
+
+ if (ts) {
+ ts->max = max;
+ ts->min = min;
+ }
+}
+
+
static void freeSeqData(TransInfo *t)
{
Editing *ed = BKE_sequencer_editing_get(t->scene, false);
@@ -4659,6 +5070,8 @@ static void freeSeqData(TransInfo *t)
}
if ((t->customData != NULL) && (t->flag & T_FREE_CUSTOMDATA)) {
+ TransSeq *ts = t->customData;
+ MEM_freeN(ts->tdseq);
MEM_freeN(t->customData);
t->customData = NULL;
}
@@ -4678,6 +5091,8 @@ static void createTransSeqData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
+ TransSeq *ts = NULL;
+ int xmouse;
int count = 0;
@@ -4688,12 +5103,11 @@ static void createTransSeqData(bContext *C, TransInfo *t)
t->customFree = freeSeqData;
+ xmouse = (int)UI_view2d_region_to_view_x(v2d, t->imval[0]);
+
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
/* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
}
else {
@@ -4733,15 +5147,19 @@ static void createTransSeqData(bContext *C, TransInfo *t)
return;
}
+ t->customData = ts = MEM_mallocN(sizeof(TransSeq), "transseq");
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransSeq TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransSeq TransData2D");
- tdsq = t->customData = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
+ ts->tdseq = tdsq = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
t->flag |= T_FREE_CUSTOMDATA;
-
-
/* loop 2: build transdata array */
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
+ SeqTransDataBounds(t, ed->seqbasep, ts);
+
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min))
+ ts->snap_left = true;
#undef XXX_DURIAN_ANIM_TX_HACK
}
@@ -4769,7 +5187,6 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
/* (affirmative) returns for specific constraints here... */
/* constraints that require this regardless */
if (ELEM(con->type,
- CONSTRAINT_TYPE_CHILDOF,
CONSTRAINT_TYPE_FOLLOWPATH,
CONSTRAINT_TYPE_CLAMPTO,
CONSTRAINT_TYPE_OBJECTSOLVER,
@@ -4779,7 +5196,14 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
}
/* constraints that require this only under special conditions */
- if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ if (con->type == CONSTRAINT_TYPE_CHILDOF) {
+ /* ChildOf constraint only works when using all location components, see T42256. */
+ bChildOfConstraint *data = (bChildOfConstraint *)con->data;
+
+ if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) && (data->flag & CHILDOF_LOCZ))
+ return true;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
/* CopyRot constraint only does this when rotating, and offset is on */
bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
@@ -4997,7 +5421,9 @@ static void set_trans_object_base_flags(TransInfo *t)
}
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5074,7 +5500,9 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DAG_scene_relations_update(G.main, t->scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5271,7 +5699,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
/* only if bone name matches too...
* NOTE: this will do constraints too, but those are ok to do here too?
*/
- if (pchanName && strcmp(pchanName, pchan->name) == 0)
+ if (pchanName && STREQ(pchanName, pchan->name))
insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
if (pchanName) MEM_freeN(pchanName);
@@ -5514,6 +5942,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
* during cleanup - psy-fi */
freeEdgeSlideTempFaces(sld);
}
+ else if (t->mode == TFM_VERT_SLIDE) {
+ /* as above */
+ VertSlideData *sld = t->customData;
+ projectVertSlideData(t, true);
+ freeVertSlideTempFaces(sld);
+ }
if (t->obedit->type == OB_MESH) {
special_aftertrans_update__mesh(C, t);
@@ -5526,12 +5960,21 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
sld->perc = 0.0;
projectEdgeSlideData(t, false);
}
+ else if (t->mode == TFM_VERT_SLIDE) {
+ VertSlideData *sld = t->customData;
+
+ sld->perc = 0.0;
+ projectVertSlideData(t, false);
+ }
}
}
}
- if (t->spacetype == SPACE_SEQ) {
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* pass */
+ }
+ else if (t->spacetype == SPACE_SEQ) {
/* freeSeqData in transform_conversions.c does this
* keep here so the else at the end wont run... */
@@ -5714,7 +6157,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
bAnimContext ac;
- const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
/* initialize relevant anim-context 'context' data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -5941,7 +6384,7 @@ static void createTransObject(bContext *C, TransInfo *t)
TransData *td = NULL;
TransDataExtension *tx;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
set_trans_object_base_flags(t);
@@ -5954,7 +6397,7 @@ static void createTransObject(bContext *C, TransInfo *t)
return;
}
- if (propmode) {
+ if (is_prop_edit) {
t->total += count_proportional_objects(t);
}
@@ -5987,7 +6430,7 @@ static void createTransObject(bContext *C, TransInfo *t)
}
CTX_DATA_END;
- if (propmode) {
+ if (is_prop_edit) {
View3D *v3d = t->view;
Base *base;
@@ -6141,22 +6584,22 @@ typedef struct TransDataTracking {
static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingTrack *track, MovieTrackingMarker *marker,
- int area, float loc[2], float rel[2], const float off[2], float aspx, float aspy)
+ int area, float loc[2], float rel[2], const float off[2], const float aspect[2])
{
int anchor = area == TRACK_AREA_POINT && off;
tdt->mode = transDataTracking_ModeTracks;
if (anchor) {
- td2d->loc[0] = rel[0] * aspx; /* hold original location */
- td2d->loc[1] = rel[1] * aspy;
+ td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = rel[1] * aspect[1];
tdt->loc = loc;
td2d->loc2d = loc; /* current location */
}
else {
- td2d->loc[0] = loc[0] * aspx; /* hold original location */
- td2d->loc[1] = loc[1] * aspy;
+ td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = loc[1] * aspect[1];
td2d->loc2d = loc; /* current location */
}
@@ -6171,8 +6614,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
if (rel) {
if (!anchor) {
- td2d->loc[0] += rel[0] * aspx;
- td2d->loc[1] += rel[1] * aspy;
+ td2d->loc[0] += rel[0] * aspect[0];
+ td2d->loc[1] += rel[1] * aspect[1];
}
copy_v2_v2(tdt->srelative, rel);
@@ -6187,8 +6630,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
//copy_v3_v3(td->center, td->loc);
td->flag |= TD_INDIVIDUAL_SCALE;
- td->center[0] = marker->pos[0] * aspx;
- td->center[1] = marker->pos[1] * aspy;
+ td->center[0] = marker->pos[0] * aspect[0];
+ td->center[1] = marker->pos[1] * aspect[1];
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
@@ -6203,8 +6646,9 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
unit_m3(td->smtx);
}
-static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d,
- TransDataTracking *tdt, MovieTrackingTrack *track, float aspx, float aspy)
+static void trackToTransData(
+ const int framenr, TransData *td, TransData2D *td2d,
+ TransDataTracking *tdt, MovieTrackingTrack *track, const float aspect[2])
{
MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
@@ -6212,11 +6656,11 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
- track->offset, marker->pos, track->offset, aspx, aspy);
+ track->offset, marker->pos, track->offset, aspect);
if (track->flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
- marker->pos, NULL, NULL, aspx, aspy);
+ marker->pos, NULL, NULL, aspect);
}
if (track->pat_flag & SELECT) {
@@ -6224,28 +6668,28 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
for (a = 0; a < 4; a++) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_PAT,
- marker->pattern_corners[a], marker->pos, NULL, aspx, aspy);
+ marker->pattern_corners[a], marker->pos, NULL, aspect);
}
}
if (track->search_flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
- marker->search_min, marker->pos, NULL, aspx, aspy);
+ marker->search_min, marker->pos, NULL, aspect);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
- marker->search_max, marker->pos, NULL, aspx, aspy);
+ marker->search_max, marker->pos, NULL, aspect);
}
}
static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingPlaneTrack *plane_track, float corner[2],
- float aspx, float aspy)
+ const float aspect[2])
{
tdt->mode = transDataTracking_ModePlaneTracks;
tdt->plane_track = plane_track;
- td2d->loc[0] = corner[0] * aspx; /* hold original location */
- td2d->loc[1] = corner[1] * aspy;
+ td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = corner[1] * aspect[1];
td2d->loc2d = corner; /* current location */
td2d->loc[2] = 0.0f;
@@ -6270,7 +6714,7 @@ static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDa
static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d,
TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track,
- float aspx, float aspy)
+ const float aspect[2])
{
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
int i;
@@ -6279,7 +6723,7 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D
plane_marker->flag &= ~PLANE_MARKER_TRACKED;
for (i = 0; i < 4; i++) {
- planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy);
+ planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
}
}
@@ -6308,7 +6752,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
MovieTrackingPlaneTrack *plane_track;
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
- float aspx, aspy;
/* count */
t->total = 0;
@@ -6343,8 +6786,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
if (t->total == 0)
return;
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
-
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
tdt = t->customData = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
@@ -6355,7 +6796,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- trackToTransData(framenr, td, td2d, tdt, track, aspx, aspy);
+ trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
/* offset */
td++;
@@ -6389,7 +6830,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
plane_track = plane_track->next)
{
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy);
+ planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
td += 4;
td2d += 4;
tdt += 4;
@@ -6601,14 +7042,10 @@ static void cancelTransTracking(TransInfo *t)
void flushTransTracking(TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
int a;
- float aspx, aspy;
-
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
if (t->state == TRANS_CANCEL)
cancelTransTracking(t);
@@ -6622,8 +7059,8 @@ void flushTransTracking(TransInfo *t)
continue;
}
- loc2d[0] = td2d->loc[0] / aspx;
- loc2d[1] = td2d->loc[1] / aspy;
+ loc2d[0] = td2d->loc[0] / t->aspect[0];
+ loc2d[1] = td2d->loc[1] / t->aspect[1];
if (t->flag & T_ALT_TRANSFORM) {
if (t->mode == TFM_RESIZE) {
@@ -6665,8 +7102,8 @@ void flushTransTracking(TransInfo *t)
td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
}
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- td2d->loc2d[0] = td2d->loc[0] / aspx;
- td2d->loc2d[1] = td2d->loc[1] / aspy;
+ td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
+ td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
}
}
}
@@ -6744,9 +7181,10 @@ static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which
}
}
-static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
- TransData *td, TransData2D *td2d, TransDataMasking *tdm,
- const int propmode, const float asp[2])
+static void MaskPointToTransData(
+ Scene *scene, MaskSplinePoint *point,
+ TransData *td, TransData2D *td2d, TransDataMasking *tdm,
+ const bool is_prop_edit, const float asp[2])
{
BezTriple *bezt = &point->bezt;
const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
@@ -6756,7 +7194,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
invert_m3_m3(parent_inverse_matrix, parent_matrix);
- if (propmode || is_sel_point) {
+ if (is_prop_edit || is_sel_point) {
int i;
tdm->point = point;
@@ -6769,7 +7207,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
/* CV coords are scaled by aspects. this is needed for rotations and
* proportional editing to be consistent with the stretched CV coords
* that are displayed. this also means that for display and numinput,
- * and when the the CV coords are flushed, these are converted each time */
+ * and when the CV coords are flushed, these are converted each time */
mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]);
td2d->loc[0] *= asp[0];
td2d->loc[1] *= asp[1];
@@ -6876,7 +7314,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
TransData2D *td2d = NULL;
TransDataMasking *tdm = NULL;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT);
float asp[2];
t->total = 0;
@@ -6926,7 +7364,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
}
}
- if (propmode)
+ if (is_prop_edit)
count += 3;
}
}
@@ -6939,7 +7377,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -6962,10 +7400,10 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
- if (propmode || MASKPOINT_ISSEL_ANY(point)) {
- MaskPointToTransData(scene, point, td, td2d, tdm, propmode, asp);
+ if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
+ MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
- if (propmode || MASKPOINT_ISSEL_KNOT(point)) {
+ if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
td += 3;
td2d += 3;
tdm += 3;
@@ -7198,6 +7636,246 @@ void flushTransPaintCurve(TransInfo *t)
}
+static void createTransGPencil(bContext *C, TransInfo *t)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+ TransData *td = NULL;
+ float mtx[3][3], smtx[3][3];
+
+ const Scene *scene = CTX_data_scene(C);
+ const int cfra = CFRA;
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+
+
+ /* == Grease Pencil Strokes to Transform Data ==
+ * Grease Pencil stroke points can be a mixture of 2D (screen-space),
+ * or 3D coordinates. However, they're always saved as 3D points.
+ * For now, we just do these without creating TransData2D for the 2D
+ * strokes. This may cause issues in future though.
+ */
+ t->total = 0;
+
+ if (gpd == NULL)
+ return;
+
+ /* First Pass: Count the number of datapoints required for the strokes,
+ * (and additional info about the configuration - e.g. 2D/3D?)
+ */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
+ (gpl->actframe != NULL))
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
+ if (is_prop_edit) {
+ /* Proportional Editing... */
+ if (is_prop_edit_connected) {
+ /* connected only - so only if selected */
+ if (gps->flag & GP_STROKE_SELECT)
+ t->total += gps->totpoints;
+ }
+ else {
+ /* everything goes - connection status doesn't matter */
+ t->total += gps->totpoints;
+ }
+ }
+ else {
+ /* only selected stroke points are considered */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ // TODO: 2D vs 3D?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT)
+ t->total++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Stop trying if nothing selected */
+ if (t->total == 0) {
+ return;
+ }
+
+ /* Allocate memory for data */
+ t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(GPencil)");
+ td = t->data;
+
+ unit_m3(smtx);
+ unit_m3(mtx);
+
+ /* Second Pass: Build transdata array */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
+ (gpl->actframe != NULL))
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
+ * spent too much time editing the wrong frame...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if (gpf->framenum != cfra) {
+ bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
+ bGPDframe *gf;
+ bool found = false;
+
+ /* Find frame to insert it before */
+ for (gf = gpf->next; gf; gf = gf->next) {
+ if (gf->framenum > cfra) {
+ /* Add it here */
+ BLI_insertlinkbefore(&gpl->frames, gf, new_frame);
+
+ found = true;
+ break;
+ }
+ else if (gf->framenum == cfra) {
+ /* This only happens when we're editing with framelock on...
+ * - Delete the new frame and don't do anything else here...
+ */
+ //printf("GP Frame convert to TransData - Copy aborted for frame %d -> %d\n", gpf->framenum, gf->framenum);
+ free_gpencil_strokes(new_frame);
+ MEM_freeN(new_frame);
+ new_frame = NULL;
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* Add new frame to the end */
+ BLI_addtail(&gpl->frames, new_frame);
+ }
+
+ /* Edit the new frame instead, if it did get created + added */
+ if (new_frame) {
+ // TODO: tag this one as being "newly created" so that we can remove it if the edit is cancelled
+ new_frame->framenum = cfra;
+
+ gpf = new_frame;
+ }
+ }
+
+ /* Loop over strokes, adding TransData for points as needed... */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ TransData *head = td;
+ TransData *tail = td;
+ bool stroke_ok;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
+ /* What we need to include depends on proportional editing settings... */
+ if (is_prop_edit) {
+ if (is_prop_edit_connected) {
+ /* A) "Connected" - Only those in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+ else {
+ /* B) All points, always */
+ stroke_ok = true;
+ }
+ }
+ else {
+ /* C) Only selected points in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+
+ /* Do stroke... */
+ if (stroke_ok && gps->totpoints) {
+ bGPDspoint *pt;
+ int i;
+
+#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */
+ const float ninv = 1.0f / gps->totpoints;
+ float center[3] = {0.0f};
+
+ /* compute midpoint of stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ madd_v3_v3v3fl(center, center, &pt->x, ninv);
+ }
+#endif
+
+ /* add all necessary points... */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bool point_ok;
+
+ /* include point? */
+ if (is_prop_edit) {
+ /* Always all points in strokes that get included */
+ point_ok = true;
+ }
+ else {
+ /* Only selected points in selected strokes */
+ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
+ }
+
+ /* do point... */
+ if (point_ok) {
+ copy_v3_v3(td->iloc, &pt->x);
+ copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
+
+ td->loc = &pt->x;
+
+ td->flag = 0;
+
+ if (pt->flag & GP_SPOINT_SELECT)
+ td->flag |= TD_SELECTED;
+
+ /* for other transform modes (e.g. shrink-fatten), need to additional data */
+ if (t->mode == TFM_GPENCIL_SHRINKFATTEN) {
+ td->val = &pt->pressure;
+ td->ival = pt->pressure;
+ }
+
+ /* configure 2D points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ // XXX: matrices may need to be different?
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ unit_m3(td->axismtx); // XXX?
+
+ td++;
+ tail++;
+ }
+ }
+
+ /* March over these points, and calculate the proportional editing distances */
+ if (is_prop_edit && (head != tail)) {
+ /* XXX: for now, we are similar enough that this works... */
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+
void createTransData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
@@ -7218,6 +7896,16 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ t->flag |= T_POINTS; // XXX...
+ createTransGPencil(C, t);
+
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
else if (t->spacetype == SPACE_IMAGE) {
t->flag |= T_POINTS | T_2D_EDIT;
if (t->options & CTX_MASK) {
@@ -7246,6 +7934,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransActionData(C, t);
+
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ //set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */
+ sort_trans_data_dist(t);
+ }
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
@@ -7259,13 +7953,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransGraphEditData(C, t);
-#if 0
+
if (t->data && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
- set_prop_dist(t, 1);
+ set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */
sort_trans_data_dist(t);
}
-#endif
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 24dc6f6e74b..dc541c6da42 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -57,7 +57,7 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "RNA_access.h"
@@ -80,6 +80,7 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
+#include "BKE_utildefines.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -87,6 +88,7 @@
#include "ED_keyframing.h"
#include "ED_markers.h"
#include "ED_mesh.h"
+#include "ED_object.h"
#include "ED_particle.h"
#include "ED_screen_types.h"
#include "ED_space_api.h"
@@ -109,21 +111,7 @@
void getViewVector(TransInfo *t, float coord[3], float vec[3])
{
if (t->persp != RV3D_ORTHO) {
- float p1[4], p2[4];
-
- copy_v3_v3(p1, coord);
- p1[3] = 1.0f;
- copy_v3_v3(p2, p1);
- p2[3] = 1.0f;
- mul_m4_v4(t->viewmat, p2);
-
- p2[0] = 2.0f * p2[0];
- p2[1] = 2.0f * p2[1];
- p2[2] = 2.0f * p2[2];
-
- mul_m4_v4(t->viewinv, p2);
-
- sub_v3_v3v3(vec, p1, p2);
+ sub_v3_v3v3(vec, coord, t->viewinv[3]);
}
else {
copy_v3_v3(vec, t->viewinv[2]);
@@ -316,7 +304,7 @@ static bool fcu_test_selected(FCurve *fcu)
return 0;
for (i = 0; i < fcu->totvert; i++, bezt++) {
- if (BEZSELECTED(bezt)) return 1;
+ if (BEZT_ISSEL_ANY(bezt)) return 1;
}
return 0;
@@ -720,7 +708,7 @@ static void recalcData_spaceclip(TransInfo *t)
static void recalcData_objects(TransInfo *t)
{
Base *base = t->scene->basact;
-
+
if (t->obedit) {
if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu = t->obedit->data;
@@ -770,7 +758,14 @@ static void recalcData_objects(TransInfo *t)
}
if ((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
editbmesh_apply_to_mirror(t);
-
+
+ if (t->mode == TFM_EDGE_SLIDE) {
+ projectEdgeSlideData(t, false);
+ }
+ else if (t->mode == TFM_VERT_SLIDE) {
+ projectVertSlideData(t, false);
+ }
+
DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
EDBM_mesh_normals_update(em);
@@ -779,7 +774,7 @@ static void recalcData_objects(TransInfo *t)
else if (t->obedit->type == OB_ARMATURE) { /* no recalc flag, does pose */
bArmature *arm = t->obedit->data;
ListBase *edbo = arm->edbo;
- EditBone *ebo;
+ EditBone *ebo, *ebo_parent;
TransData *td = t->data;
int i;
@@ -789,17 +784,18 @@ static void recalcData_objects(TransInfo *t)
/* Ensure all bones are correctly adjusted */
for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
- if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ if (ebo_parent) {
/* If this bone has a parent tip that has been moved */
- if (ebo->parent->flag & BONE_TIPSEL) {
- copy_v3_v3(ebo->head, ebo->parent->tail);
- if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo->parent->rad_tail;
+ if (ebo_parent->flag & BONE_TIPSEL) {
+ copy_v3_v3(ebo->head, ebo_parent->tail);
+ if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
}
/* If this bone has a parent tip that has NOT been moved */
else {
- copy_v3_v3(ebo->parent->tail, ebo->head);
- if (t->mode == TFM_BONE_ENVELOPE) ebo->parent->rad_tail = ebo->rad_head;
+ copy_v3_v3(ebo_parent->tail, ebo->head);
+ if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
}
}
@@ -820,10 +816,14 @@ static void recalcData_objects(TransInfo *t)
ebo->rad_head *= ebo->length / ebo->oldlength;
ebo->rad_tail *= ebo->length / ebo->oldlength;
ebo->oldlength = ebo->length;
+
+ if (ebo_parent) {
+ ebo_parent->rad_tail = ebo->rad_head;
+ }
}
}
- if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) {
+ if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
/* fix roll */
for (i = 0; i < t->total; i++, td++) {
if (td->extra) {
@@ -974,6 +974,9 @@ void recalcData(TransInfo *t)
else if (t->options & CTX_PAINT_CURVE) {
flushTransPaintCurve(t);
}
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ /* pass? */
+ }
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
}
@@ -1074,6 +1077,8 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
* Setup internal data, mouse, vectors
*
* \note \a op and \a event can be NULL
+ *
+ * \see #saveTransform does the reverse.
*/
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
@@ -1130,6 +1135,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
zero_v3(t->vec);
zero_v3(t->center);
+ zero_v3(t->center_global);
unit_m3(t->mat);
@@ -1165,6 +1171,19 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->spacetype = sa->spacetype;
}
+ /* handle T_ALT_TRANSFORM initialization, we may use for different operators */
+ if (op) {
+ const char *prop_id = NULL;
+ if (t->mode == TFM_SHRINKFATTEN) {
+ prop_id = "use_even_offset";
+ }
+
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) &&
+ RNA_property_is_set(op->ptr, prop))
+ {
+ BKE_BIT_TEST_SET(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
+ }
+ }
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = sa->spacedata.first;
@@ -1188,23 +1207,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_CURSOR;
}
- if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
- RNA_property_is_set(op->ptr, prop)))
- {
- t->current_orientation = RNA_property_enum_get(op->ptr, prop);
-
- if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
- t->current_orientation = V3D_MANIP_GLOBAL;
- }
- }
- else {
- t->current_orientation = v3d->twmode;
- }
+ t->current_orientation = v3d->twmode;
/* exceptional case */
- if (t->around == V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) {
+ if (t->around == V3D_LOCAL) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
- t->options |= CTX_NO_PET;
+ const bool use_island = transdata_check_local_islands(t, t->around);
+
+ if (obedit && !use_island) {
+ t->options |= CTX_NO_PET;
+ }
}
}
@@ -1226,7 +1238,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else {
- RNA_property_boolean_set(op->ptr, prop, t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT);
+ RNA_property_boolean_set(op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
}
}
@@ -1282,6 +1294,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
t->around = V3D_CENTER;
}
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
+ RNA_property_is_set(op->ptr, prop)))
+ {
+ t->current_orientation = RNA_property_enum_get(op->ptr, prop);
+
+ if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
+ t->current_orientation = V3D_MANIP_GLOBAL;
+ }
+ }
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
RNA_property_is_set(op->ptr, prop)))
@@ -1321,7 +1343,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* use settings from scene only if modal */
if (t->flag & T_MODAL) {
if ((t->options & CTX_NO_PET) == 0) {
- if (t->obedit) {
+ if (t->spacetype == SPACE_IPO) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
+ }
+ else if (t->obedit) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
+ }
+ else if (t->options & CTX_GPENCIL_STROKES) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
}
else if (t->options & CTX_MASK) {
@@ -1377,6 +1408,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
#endif
setTransformViewMatrices(t);
+ setTransformViewAspect(t, t->aspect);
initNumInput(&t->num);
}
@@ -1543,6 +1575,19 @@ void calculateCenter2D(TransInfo *t)
}
}
+void calculateCenterGlobal(TransInfo *t)
+{
+ /* setting constraint center */
+ /* note, init functions may over-ride t->center */
+ if (t->flag & (T_EDIT | T_POSE)) {
+ Object *ob = t->obedit ? t->obedit : t->poseobj;
+ mul_v3_m4v3(t->center_global, ob->obmat, t->center);
+ }
+ else {
+ copy_v3_v3(t->center_global, t->center);
+ }
+}
+
void calculateCenterCursor(TransInfo *t, float r_center[3])
{
const float *cursor;
@@ -1571,30 +1616,17 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
{
- float aspx = 1.0, aspy = 1.0;
const float *cursor = NULL;
if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
- if (t->options & CTX_MASK) {
- ED_space_image_get_aspect(sima, &aspx, &aspy);
- }
- else {
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- }
cursor = sima->cursor;
}
else if (t->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(space_clip, &aspx, &aspy);
- }
- else {
- ED_space_clip_get_aspect(space_clip, &aspx, &aspy);
- }
cursor = space_clip->cursor;
}
-
+
if (cursor) {
if (t->options & CTX_MASK) {
float co[2];
@@ -1611,8 +1643,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
BLI_assert(!"Shall not happen");
}
- r_center[0] = co[0] * aspx;
- r_center[1] = co[1] * aspy;
+ r_center[0] = co[0] * t->aspect[0];
+ r_center[1] = co[1] * t->aspect[1];
}
else if (t->options & CTX_PAINT_CURVE) {
if (t->spacetype == SPACE_IMAGE) {
@@ -1621,8 +1653,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
}
}
else {
- r_center[0] = cursor[0] * aspx;
- r_center[1] = cursor[1] * aspy;
+ r_center[0] = cursor[0] * t->aspect[0];
+ r_center[1] = cursor[1] * t->aspect[1];
}
}
}
@@ -1651,8 +1683,9 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
}
}
}
- if (i)
- mul_v3_fl(partial, 1.0f / total);
+ if (total) {
+ mul_v3_fl(partial, 1.0f / (float)total);
+ }
copy_v3_v3(r_center, partial);
}
@@ -1684,63 +1717,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
bool ok = false;
if (t->obedit) {
- switch (t->obedit->type) {
- case OB_MESH:
- {
- BMEditSelection ese;
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
-
- if (BM_select_history_active_get(em->bm, &ese)) {
- BM_editselection_center(&ese, r_center);
- ok = true;
- }
- break;
- }
- case OB_ARMATURE:
- {
- bArmature *arm = t->obedit->data;
- EditBone *ebo = arm->act_edbone;
-
- if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) {
- copy_v3_v3(r_center, ebo->head);
- ok = true;
- }
-
- break;
- }
- case OB_CURVE:
- case OB_SURF:
- {
- float center[3];
- Curve *cu = (Curve *)t->obedit->data;
-
- if (ED_curve_active_center(cu, center)) {
- copy_v3_v3(r_center, center);
- ok = true;
- }
- break;
- }
- case OB_MBALL:
- {
- MetaBall *mb = (MetaBall *)t->obedit->data;
- MetaElem *ml_act = mb->lastelem;
-
- if (ml_act && (!select_only || (ml_act->flag & SELECT))) {
- copy_v3_v3(r_center, &ml_act->x);
- ok = true;
- }
- break;
- }
- case OB_LATTICE:
- {
- BPoint *actbp = BKE_lattice_active_point_get(t->obedit->data);
-
- if (actbp) {
- copy_v3_v3(r_center, actbp->vec);
- ok = true;
- }
- break;
- }
+ if (ED_object_editmode_calc_active_center(t->obedit, select_only, r_center)) {
+ ok = true;
}
}
else if (t->flag & T_POSE) {
@@ -1811,14 +1789,8 @@ void calculateCenter(TransInfo *t)
}
calculateCenter2D(t);
+ calculateCenterGlobal(t);
- /* setting constraint center */
- copy_v3_v3(t->con.center, t->center);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->con.center);
- }
-
/* for panning from cameraview */
if (t->flag & T_OBJECT) {
if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
@@ -1839,7 +1811,7 @@ void calculateCenter(TransInfo *t)
/* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
if (t->mode == TFM_TRANSLATION) {
copy_v3_v3(t->center, axis);
- copy_v3_v3(t->con.center, t->center);
+ copy_v3_v3(t->center_global, t->center);
}
}
}
@@ -1859,7 +1831,7 @@ void calculateCenter(TransInfo *t)
/* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
* and never used in other cases.
*
- * We need special case here as well, since ED_view3d_calc_zfac will crahs when called
+ * We need special case here as well, since ED_view3d_calc_zfac will crash when called
* for a region different from RGN_TYPE_WINDOW.
*/
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
@@ -1876,9 +1848,12 @@ void calculatePropRatio(TransInfo *t)
TransData *td = t->data;
int i;
float dist;
- short connected = t->flag & T_PROP_CONNECTED;
+ const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
+
+ t->proptext[0] = '\0';
if (t->flag & T_PROP_EDIT) {
+ const char *pet_id = NULL;
for (i = 0; i < t->total; i++, td++) {
if (td->flag & TD_SELECTED) {
td->factor = 1.0f;
@@ -1939,6 +1914,9 @@ void calculatePropRatio(TransInfo *t)
case PROP_RANDOM:
td->factor = BLI_frand() * dist;
break;
+ case PROP_INVSQUARE:
+ td->factor = dist * (2.0f - dist);
+ break;
default:
td->factor = 1;
break;
@@ -1947,35 +1925,147 @@ void calculatePropRatio(TransInfo *t)
}
switch (t->prop_mode) {
case PROP_SHARP:
- strcpy(t->proptext, IFACE_("(Sharp)"));
+ pet_id = N_("(Sharp)");
break;
case PROP_SMOOTH:
- strcpy(t->proptext, IFACE_("(Smooth)"));
+ pet_id = N_("(Smooth)");
break;
case PROP_ROOT:
- strcpy(t->proptext, IFACE_("(Root)"));
+ pet_id = N_("(Root)");
break;
case PROP_LIN:
- strcpy(t->proptext, IFACE_("(Linear)"));
+ pet_id = N_("(Linear)");
break;
case PROP_CONST:
- strcpy(t->proptext, IFACE_("(Constant)"));
+ pet_id = N_("(Constant)");
break;
case PROP_SPHERE:
- strcpy(t->proptext, IFACE_("(Sphere)"));
+ pet_id = N_("(Sphere)");
break;
case PROP_RANDOM:
- strcpy(t->proptext, IFACE_("(Random)"));
+ pet_id = N_("(Random)");
+ break;
+ case PROP_INVSQUARE:
+ pet_id = N_("(InvSquare)");
break;
default:
- t->proptext[0] = '\0';
break;
}
+
+ if (pet_id) {
+ BLI_strncpy(t->proptext, IFACE_(pet_id), sizeof(t->proptext));
+ }
}
else {
for (i = 0; i < t->total; i++, td++) {
td->factor = 1.0;
}
- t->proptext[0] = '\0';
}
}
+
+/**
+ * Rotate an element, low level code, ignore protected channels.
+ * (use for objects or pose-bones)
+ * Similar to #ElementRotation.
+ */
+void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
+{
+ float totmat[3][3];
+ float smat[3][3];
+ float fmat[3][3];
+ float obmat[3][3];
+
+ float dmat[3][3]; /* delta rotation */
+ float dmat_inv[3][3];
+
+ mul_m3_m3m3(totmat, mat, td->mtx);
+ mul_m3_m3m3(smat, td->smtx, mat);
+
+ /* logic from BKE_object_rot_to_mat3 */
+ if (use_drot) {
+ if (td->ext->rotOrder > 0) {
+ eulO_to_mat3(dmat, td->ext->drot, td->ext->rotOrder);
+ }
+ else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
+#if 0
+ axis_angle_to_mat3(dmat, td->ext->drotAxis, td->ext->drotAngle);
+#else
+ unit_m3(dmat);
+#endif
+ }
+ else {
+ float tquat[4];
+ normalize_qt_qt(tquat, td->ext->dquat);
+ quat_to_mat3(dmat, tquat);
+ }
+
+ invert_m3_m3(dmat_inv, dmat);
+ }
+
+
+ if (td->ext->rotOrder == ROT_MODE_QUAT) {
+ float quat[4];
+
+ /* calculate the total rotatation */
+ quat_to_mat3(obmat, td->ext->iquat);
+ if (use_drot) {
+ mul_m3_m3m3(obmat, dmat, obmat);
+ }
+
+ /* mat = transform, obmat = object rotation */
+ mul_m3_m3m3(fmat, smat, obmat);
+
+ if (use_drot) {
+ mul_m3_m3m3(fmat, dmat_inv, fmat);
+ }
+
+ mat3_to_quat(quat, fmat);
+
+ /* apply */
+ copy_qt_qt(td->ext->quat, quat);
+ }
+ else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
+ float axis[3], angle;
+
+ /* calculate the total rotatation */
+ axis_angle_to_mat3(obmat, td->ext->irotAxis, td->ext->irotAngle);
+ if (use_drot) {
+ mul_m3_m3m3(obmat, dmat, obmat);
+ }
+
+ /* mat = transform, obmat = object rotation */
+ mul_m3_m3m3(fmat, smat, obmat);
+
+ if (use_drot) {
+ mul_m3_m3m3(fmat, dmat_inv, fmat);
+ }
+
+ mat3_to_axis_angle(axis, &angle, fmat);
+
+ /* apply */
+ copy_v3_v3(td->ext->rotAxis, axis);
+ *td->ext->rotAngle = angle;
+ }
+ else {
+ float eul[3];
+
+ /* calculate the total rotatation */
+ eulO_to_mat3(obmat, td->ext->irot, td->ext->rotOrder);
+ if (use_drot) {
+ mul_m3_m3m3(obmat, dmat, obmat);
+ }
+
+ /* mat = transform, obmat = object rotation */
+ mul_m3_m3m3(fmat, smat, obmat);
+
+ if (use_drot) {
+ mul_m3_m3m3(fmat, dmat_inv, fmat);
+ }
+
+ mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
+
+ /* apply */
+ copy_v3_v3(td->ext->rot, eul);
+ }
+}
+
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 2161e52d7b2..f13bc6b6b55 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -177,7 +177,7 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con
mul_qt_v3(quat, gmat[0]);
/* Y-axis */
- axis_angle_to_quat(quat, axis, M_PI / 2.0);
+ axis_angle_to_quat(quat, axis, M_PI_2);
copy_v3_v3(gmat[1], gmat[0]);
mul_qt_v3(quat, gmat[1]);
@@ -262,13 +262,12 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
/* centroid, boundbox, of selection */
/* returns total items selected */
-int calc_manipulator_stats(const bContext *C)
+static int calc_manipulator_stats(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
Base *base;
@@ -305,48 +304,11 @@ int calc_manipulator_stats(const bContext *C)
BMIter iter;
- /* do vertices/edges/faces for center depending on selection
- * mode. note we can't use just vertex selection flag because
- * it is not flush down on changes */
- if (ts->selectmode & SCE_SELECT_VERTEX) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- totsel++;
- calc_tw_center(scene, eve->co);
- }
- }
- }
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BMIter itersub;
- BMEdge *eed;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- /* check the vertex has a selected edge, only add it once */
- BM_ITER_ELEM (eed, &itersub, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- totsel++;
- calc_tw_center(scene, eve->co);
- break;
- }
- }
- }
- }
- }
- else {
- BMIter itersub;
- BMFace *efa;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- /* check the vertex has a selected face, only add it once */
- BM_ITER_ELEM (efa, &itersub, eve, BM_FACES_OF_VERT) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- totsel++;
- calc_tw_center(scene, eve->co);
- break;
- }
- }
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
}
}
}
@@ -550,7 +512,7 @@ int calc_manipulator_stats(const bContext *C)
for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
if (ek->flag & PEK_SELECT) {
- calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co);
+ calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
totsel++;
}
}
@@ -606,7 +568,7 @@ int calc_manipulator_stats(const bContext *C)
{
if (obedit || ob->mode & OB_MODE_POSE) {
float mat[3][3];
- ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
+ ED_getTransformOrientationMatrix(C, mat, v3d->around);
copy_m4_m3(rv3d->twmat, mat);
break;
}
@@ -621,7 +583,7 @@ int calc_manipulator_stats(const bContext *C)
* and users who select many bones will understand whats going on and what local means
* when they start transforming */
float mat[3][3];
- ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
+ ED_getTransformOrientationMatrix(C, mat, v3d->around);
copy_m4_m3(rv3d->twmat, mat);
break;
}
@@ -640,7 +602,7 @@ int calc_manipulator_stats(const bContext *C)
default: /* V3D_MANIP_CUSTOM */
{
float mat[3][3];
- if (applyTransformOrientation(C, mat, NULL)) {
+ if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) {
copy_m4_m3(rv3d->twmat, mat);
}
break;
@@ -681,7 +643,7 @@ static void test_manipulator_axis(const bContext *C)
static float screen_aligned(RegionView3D *rv3d, float mat[4][4])
{
- glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
+ glTranslate3fv(mat[3]);
/* sets view screen aligned */
glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
@@ -933,6 +895,11 @@ static void postOrtho(const bool ortho)
}
}
+BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags)
+{
+ return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z));
+}
+
static void draw_manipulator_rotate(
View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo,
const bool is_moving, const bool is_picksel)
@@ -946,8 +913,8 @@ static void draw_manipulator_rotate(
const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB;
bool ortho;
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_ROT_C) == 0) return;
+ /* skip drawing if all axes are locked */
+ if (manipulator_rotate_is_visible(drawflags) == false) return;
/* Init stuff */
glDisable(GL_DEPTH_TEST);
@@ -956,7 +923,7 @@ static void draw_manipulator_rotate(
/* prepare for screen aligned draw */
size = len_v3(rv3d->twmat[0]);
glPushMatrix();
- glTranslatef(rv3d->twmat[3][0], rv3d->twmat[3][1], rv3d->twmat[3][2]);
+ glTranslate3fv(rv3d->twmat[3]);
if (arcs) {
/* clipplane makes nice handles, calc here because of multmatrix but with translate! */
@@ -1089,8 +1056,6 @@ static void draw_manipulator_rotate(
glRotatef(90.0, 1.0, 0.0, 0.0);
postOrtho(ortho);
}
-
- if (arcs) glDisable(GL_CLIP_PLANE0);
}
// donut arcs
if (arcs) {
@@ -1397,7 +1362,7 @@ static void draw_manipulator_translate(
manipulator_axis_order(rv3d, axis_order);
- // XXX if (moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
+ // XXX if (moving) glTranslate3fv(t->vec);
glDisable(GL_DEPTH_TEST);
/* center circle, do not add to selection when shift is pressed (planar constraint) */
@@ -1486,8 +1451,8 @@ static void draw_manipulator_rotate_cyl(
int axis_order[3] = {2, 0, 1};
int i;
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_ROT_C) == 0) return;
+ /* skip drawing if all axes are locked */
+ if (manipulator_rotate_is_visible(drawflags) == false) return;
manipulator_axis_order(rv3d, axis_order);
@@ -1850,7 +1815,6 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
}
RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
- //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_translate", 0), event, op->ptr, NULL, false);
}
else if (drawflags & MAN_SCALE_C) {
switch (drawflags) {
@@ -1881,7 +1845,6 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
}
RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
- //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_resize", 0), event, op->ptr, NULL, false);
}
else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
/* Do not pass op->ptr!!! trackball has no "constraint" properties!
@@ -1894,8 +1857,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
}
- WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, &props_ptr);
- //wm_operator_invoke(C, WM_operatortype_find(ot->idname, 0), event, NULL, NULL, false);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
else if (drawflags & MAN_ROT_C) {
@@ -1912,7 +1874,6 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
}
RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
- //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_rotate", 0), event, op->ptr, NULL, false);
}
}
/* after transform, restore drawflags */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 81e065ee33a..c6d0d6cde2e 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -33,11 +33,12 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_editmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -63,23 +64,23 @@ typedef struct TransformModeItem {
static const float VecOne[3] = {1, 1, 1};
-static char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
-static char OP_ROTATION[] = "TRANSFORM_OT_rotate";
-static char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
-static char OP_RESIZE[] = "TRANSFORM_OT_resize";
-static char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
-static char OP_SHEAR[] = "TRANSFORM_OT_shear";
-static char OP_BEND[] = "TRANSFORM_OT_bend";
-static char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
-static char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
-static char OP_TILT[] = "TRANSFORM_OT_tilt";
-static char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
-static char OP_MIRROR[] = "TRANSFORM_OT_mirror";
-static char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
-static char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
-static char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
-static char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
-static char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
+static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
+static const char OP_ROTATION[] = "TRANSFORM_OT_rotate";
+static const char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
+static const char OP_RESIZE[] = "TRANSFORM_OT_resize";
+static const char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
+static const char OP_SHEAR[] = "TRANSFORM_OT_shear";
+static const char OP_BEND[] = "TRANSFORM_OT_bend";
+static const char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
+static const char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
+static const char OP_TILT[] = "TRANSFORM_OT_tilt";
+static const char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
+static const char OP_MIRROR[] = "TRANSFORM_OT_mirror";
+static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
+static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
+static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
+static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
+static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot);
@@ -140,8 +141,10 @@ EnumPropertyItem transform_mode_types[] =
{TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
{TFM_BONESIZE, "BONE_SIZE", 0, "Bonesize", ""},
{TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone_Envelope", ""},
+ {TFM_BONE_ENVELOPE_DIST, "BONE_ENVELOPE_DIST", 0, "Bone_Envelope_Distance", ""},
{TFM_CURVE_SHRINKFATTEN, "CURVE_SHRINKFATTEN", 0, "Curve_Shrinkfatten", ""},
{TFM_MASK_SHRINKFATTEN, "MASK_SHRINKFATTEN", 0, "Mask_Shrinkfatten", ""},
+ {TFM_GPENCIL_SHRINKFATTEN, "GPENCIL_SHRINKFATTEN", 0, "GPencil_Shrinkfatten", ""},
{TFM_BONE_ROLL, "BONE_ROLL", 0, "Bone_Roll", ""},
{TFM_TIME_TRANSLATE, "TIME_TRANSLATE", 0, "Time_Translate", ""},
{TFM_TIME_SLIDE, "TIME_SLIDE", 0, "Time_Slide", ""},
@@ -171,12 +174,12 @@ static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), const
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, IFACE_("Orientation"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Orientation"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation");
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
static void TRANSFORM_OT_select_orientation(struct wmOperatorType *ot)
@@ -324,6 +327,9 @@ static void transformops_loopsel_hack(bContext *C, wmOperator *op)
}
}
}
+#else
+/* prevent removal by cleanup */
+# error "loopslide hack removed!"
#endif /* USE_LOOPSLIDE_HACK */
@@ -484,7 +490,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* add temp handler */
WM_event_add_modal_handler(C, op);
- op->flag |= OP_GRAB_POINTER; // XXX maybe we want this with the manipulator only?
+ op->flag |= OP_IS_MODAL_GRAB_CURSOR; // XXX maybe we want this with the manipulator only?
return OPERATOR_RUNNING_MODAL;
}
}
@@ -521,7 +527,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_enum(ot->srna, "proportional", proportional_editing_items, 0, "Proportional Editing", "");
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
- RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
}
@@ -543,7 +549,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
}
}
}
-
+
+ if (flags & P_GPENCIL_EDIT) {
+ RNA_def_boolean(ot->srna, "gpencil_strokes", 0, "Edit Grease Pencil", "Edit selected Grease Pencil strokes");
+ }
+
if ((flags & P_OPTIONS) && !(flags & P_NO_TEXSPACE)) {
RNA_def_boolean(ot->srna, "texture_space", 0, "Edit Texture Space", "Edit Object data texture space");
prop = RNA_def_boolean(ot->srna, "remove_on_cancel", 0, "Remove on Cancel", "Remove elements on cancel");
@@ -578,7 +588,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS);
+ Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@@ -598,7 +608,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS);
+ Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
}
static int skin_resize_poll(bContext *C)
@@ -633,8 +643,6 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Trackball";
ot->description = "Trackball style rotation of selected items";
@@ -649,16 +657,13 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
/* Maybe we could use float_vector_xyz here too? */
- prop = RNA_def_float_vector(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
- RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
}
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Rotate";
ot->description = "Rotate selected items";
@@ -672,10 +677,9 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
- prop = RNA_def_float(ot->srna, "value", 0.0f, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP);
+ Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT);
}
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
@@ -721,7 +725,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
}
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
@@ -741,7 +745,7 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
// XXX Shear axis?
}
@@ -782,6 +786,8 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
+ RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -803,7 +809,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
}
static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
@@ -821,11 +827,13 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL);
+ Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT);
}
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Edge Slide";
ot->description = "Slide an edge loop along a mesh";
@@ -837,9 +845,12 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
- RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+ RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
+
+ prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
@@ -857,11 +868,11 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
- Transform_Properties(ot, P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
@@ -967,7 +978,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP);
+ Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT);
}
void transform_operatortypes(void)
@@ -1107,8 +1118,10 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac
WM_keymap_add_item(keymap, "NODE_OT_move_detach_links_release", EVT_TWEAK_A, KM_ANY, KM_ALT, 0);
WM_keymap_add_item(keymap, "NODE_OT_move_detach_links", EVT_TWEAK_S, KM_ANY, KM_ALT, 0);
- /* dettach and translate */
- WM_keymap_add_item(keymap, "NODE_OT_detach_translate_attach", FKEY, KM_PRESS, KM_ALT, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap");
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_node_element");
break;
case SPACE_SEQ:
WM_keymap_add_item(keymap, OP_SEQ_SLIDE, GKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index c7d63da8281..a1bb6f4e0f3 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -24,7 +24,6 @@
* \ingroup edtransform
*/
-
#include <string.h>
#include <stddef.h>
#include <ctype.h>
@@ -37,6 +36,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "BLI_math.h"
@@ -53,14 +53,10 @@
#include "BKE_main.h"
#include "BKE_screen.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "ED_armature.h"
-#include "RNA_define.h"
-
-#include "UI_interface.h"
-
#include "transform.h"
/* *********************** TransSpace ************************** */
@@ -90,7 +86,7 @@ static bool uniqueOrientationNameCheck(void *arg, const char *name)
static void uniqueOrientationName(ListBase *lb, char *name)
{
- BLI_uniquename_cb(uniqueOrientationNameCheck, lb, CTX_DATA_(BLF_I18NCONTEXT_ID_SCENE, "Space"), '.', name,
+ BLI_uniquename_cb(uniqueOrientationNameCheck, lb, CTX_DATA_(BLT_I18NCONTEXT_ID_SCENE, "Space"), '.', name,
sizeof(((TransformOrientation *)NULL)->name));
}
@@ -149,7 +145,7 @@ static TransformOrientation *createBoneSpace(bContext *C, ReportList *reports,
float mat[3][3];
float normal[3], plane[3];
- getTransformOrientation(C, normal, plane, 0);
+ getTransformOrientation(C, normal, plane);
if (createSpaceNormalTangent(mat, normal, plane) == 0) {
BKE_reports_prepend(reports, "Cannot use zero-length bone");
@@ -169,7 +165,7 @@ static TransformOrientation *createCurveSpace(bContext *C, ReportList *reports,
float mat[3][3];
float normal[3], plane[3];
- getTransformOrientation(C, normal, plane, 0);
+ getTransformOrientation(C, normal, plane);
if (createSpaceNormalTangent(mat, normal, plane) == 0) {
BKE_reports_prepend(reports, "Cannot use zero-length curve");
@@ -191,7 +187,7 @@ static TransformOrientation *createMeshSpace(bContext *C, ReportList *reports,
float normal[3], plane[3];
int type;
- type = getTransformOrientation(C, normal, plane, 0);
+ type = getTransformOrientation(C, normal, plane);
switch (type) {
case ORIENTATION_VERT:
@@ -392,18 +388,15 @@ void BIF_selectTransformOrientationValue(bContext *C, int orientation)
int BIF_countTransformOrientation(const bContext *C)
{
ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- return BLI_countlist(transform_spaces);
+ return BLI_listbase_count(transform_spaces);
}
-bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name)
+bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name, int index)
{
- View3D *v3d = CTX_wm_view3d(C);
- int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
-
ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- TransformOrientation *ts = BLI_findlink(transform_spaces, selected_index);
+ TransformOrientation *ts = BLI_findlink(transform_spaces, index);
- BLI_assert(selected_index >= 0);
+ BLI_assert(index >= 0);
if (ts) {
if (r_name) {
@@ -447,7 +440,6 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
void initTransformOrientation(bContext *C, TransInfo *t)
{
- View3D *v3d = CTX_wm_view3d(C);
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_active_object(C);
@@ -467,7 +459,7 @@ void initTransformOrientation(bContext *C, TransInfo *t)
case V3D_MANIP_NORMAL:
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
BLI_strncpy(t->spacename, IFACE_("normal"), sizeof(t->spacename));
- ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE));
+ ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
break;
}
/* fall-through */ /* we define 'normal' as 'local' in Object mode */
@@ -485,7 +477,9 @@ void initTransformOrientation(bContext *C, TransInfo *t)
break;
case V3D_MANIP_VIEW:
- if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+ if ((t->spacetype == SPACE_VIEW3D) &&
+ (t->ar->regiontype == RGN_TYPE_WINDOW))
+ {
RegionView3D *rv3d = t->ar->regiondata;
float mat[3][3];
@@ -499,7 +493,7 @@ void initTransformOrientation(bContext *C, TransInfo *t)
}
break;
default: /* V3D_MANIP_CUSTOM */
- if (applyTransformOrientation(C, t->spacemtx, t->spacename)) {
+ if (applyTransformOrientation(C, t->spacemtx, t->spacename, t->current_orientation - V3D_MANIP_CUSTOM)) {
/* pass */
}
else {
@@ -590,14 +584,14 @@ static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const
}
#endif
-int getTransformOrientation(const bContext *C, float normal[3], float plane[3], const bool activeOnly)
+int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around)
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
Object *obedit = CTX_data_edit_object(C);
Base *base;
Object *ob = OBACT;
int result = ORIENTATION_NONE;
+ const bool activeOnly = (around == V3D_ACTIVE);
zero_v3(normal);
zero_v3(plane);
@@ -723,14 +717,15 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
/* should never fail */
if (LIKELY(v_pair[0] && v_pair[1])) {
bool v_pair_swap = false;
- /* Logic explained:
+ /**
+ * Logic explained:
*
* - Edges and vert-pairs treated the same way.
- * - Point the Z axis along the edge vector (towards the active vertex).
- * - Point the Y axis outwards (the same direction as the normals).
+ * - Point the Y axis along the edge vector (towards the active vertex).
+ * - Point the Z axis outwards (the same direction as the normals).
*
- * Note that this is at odds a little with face select (and 3 vertices)
- * which point the Z axis along the normal, however in both cases Z is the dominant axis.
+ * \note Z points outwards - along the normal.
+ * take care making changes here, see: T38592, T43708
*/
/* be deterministic where possible and ensure v_pair[0] is active */
@@ -738,7 +733,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
v_pair_swap = true;
}
else if (eed && BM_edge_is_boundary(eed)) {
- /* pradictable direction for boundary edges */
+ /* predictable direction for boundary edges */
if (eed->l->v != v_pair[0]) {
v_pair_swap = true;
}
@@ -748,8 +743,8 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
SWAP(BMVert *, v_pair[0], v_pair[1]);
}
- add_v3_v3v3(plane, v_pair[0]->no, v_pair[1]->no);
- sub_v3_v3v3(normal, v_pair[0]->co, v_pair[1]->co);
+ add_v3_v3v3(normal, v_pair[0]->no, v_pair[1]->no);
+ sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
/* flip the plane normal so we point outwards */
negate_v3(plane);
}
@@ -859,7 +854,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
/* exception */
if (flag) {
float tvec[3];
- if ((v3d->around == V3D_LOCAL) ||
+ if ((around == V3D_LOCAL) ||
ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
{
BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
@@ -960,8 +955,16 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
/* Vectors from edges don't need the special transpose inverse multiplication */
if (result == ORIENTATION_EDGE) {
+ float tvec[3];
+
mul_mat3_m4_v3(ob->obmat, normal);
mul_mat3_m4_v3(ob->obmat, plane);
+
+ /* align normal to edge direction (so normal is perpendicular to the plane).
+ * 'ORIENTATION_EDGE' will do the other way around.
+ * This has to be done **after** applying obmat, see T45775! */
+ project_v3_v3v3(tvec, normal, plane);
+ sub_v3_v3(normal, tvec);
}
else {
mul_m3_v3(mat, normal);
@@ -1013,6 +1016,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
else {
/* we need the one selected object, if its not active */
+ View3D *v3d = CTX_wm_view3d(C);
ob = OBACT;
if (ob && (ob->flag & SELECT)) {
/* pass */
@@ -1038,14 +1042,22 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
return result;
}
-void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const bool activeOnly)
+int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
+{
+ /* dummy value, not V3D_ACTIVE and not V3D_LOCAL */
+ short around = V3D_CENTER;
+
+ return getTransformOrientation_ex(C, normal, plane, around);
+}
+
+void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const short around)
{
float normal[3] = {0.0, 0.0, 0.0};
float plane[3] = {0.0, 0.0, 0.0};
int type;
- type = getTransformOrientation(C, normal, plane, activeOnly);
+ type = getTransformOrientation_ex(C, normal, plane, around);
switch (type) {
case ORIENTATION_NORMAL:
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index af563f71376..a7aad427dd6 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -59,6 +59,7 @@
#include "BKE_anim.h" /* for duplis */
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_sequencer.h"
#include "BKE_main.h"
#include "BKE_tracking.h"
@@ -219,7 +220,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
h = (((float)hi) / IMG_SIZE_FALLBACK) * G.sima->zoom * yuser_asp;
cpack(0xFFFFFF);
- glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], 0.0f);
+ glTranslate2fv(t->tsnap.snapPoint);
//glRectf(0, 0, 1, 1);
@@ -341,39 +342,14 @@ void applyProject(TransInfo *t)
if (t->tsnap.align && (t->flag & T_OBJECT)) {
/* handle alignment as well */
const float *original_normal;
- float axis[3];
float mat[3][3];
- float angle;
- float totmat[3][3], smat[3][3];
- float eul[3], fmat[3][3], quat[4];
- float obmat[3][3];
/* In pose mode, we want to align normals with Y axis of bones... */
original_normal = td->axismtx[2];
- cross_v3_v3v3(axis, original_normal, no);
- angle = saacos(dot_v3v3(original_normal, no));
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
- axis_angle_to_quat(quat, axis, angle);
-
- quat_to_mat3(mat, quat);
-
- mul_m3_m3m3(totmat, mat, td->mtx);
- mul_m3_m3m3(smat, td->smtx, totmat);
-
- /* calculate the total rotatation in eulers */
- add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
- eulO_to_mat3(obmat, eul, td->ext->rotOrder);
- /* mat = transform, obmat = object rotation */
- mul_m3_m3m3(fmat, smat, obmat);
-
- mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
-
- /* correct back for delta rot */
- sub_v3_v3v3(eul, eul, td->ext->drot);
-
- /* and apply */
- copy_v3_v3(td->ext->rot, eul);
+ transform_data_ext_rotate(td, mat, true);
/* TODO support constraints for rotation too? see ElementRotation */
}
@@ -390,10 +366,11 @@ void applyGridAbsolute(TransInfo *t)
float grid_size = 0.0f;
GearsType grid_action;
TransData *td;
- float imat[4][4];
+ float (*obmat)[4] = NULL;
+ bool use_obmat = false;
int i;
- if (!(activeSnap(t) && (t->tsnap.mode == SCE_SNAP_MODE_GRID)))
+ if (!(activeSnap(t) && (ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))))
return;
grid_action = BIG_GEARS;
@@ -401,9 +378,9 @@ void applyGridAbsolute(TransInfo *t)
grid_action = SMALL_GEARS;
switch (grid_action) {
- case NO_GEARS: grid_size = t->snap[0]; break;
- case BIG_GEARS: grid_size = t->snap[1]; break;
- case SMALL_GEARS: grid_size = t->snap[2]; break;
+ case NO_GEARS: grid_size = t->snap_spatial[0]; break;
+ case BIG_GEARS: grid_size = t->snap_spatial[1]; break;
+ case SMALL_GEARS: grid_size = t->snap_spatial[2]; break;
}
/* early exit on unusable grid size */
if (grid_size == 0.0f)
@@ -411,7 +388,8 @@ void applyGridAbsolute(TransInfo *t)
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
- invert_m4_m4(imat, ob->obmat);
+ obmat = ob->obmat;
+ use_obmat = true;
}
for (i = 0, td = t->data; i < t->total; i++, td++) {
@@ -427,9 +405,8 @@ void applyGridAbsolute(TransInfo *t)
continue;
copy_v3_v3(iloc, td->loc);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, iloc);
+ if (use_obmat) {
+ mul_m4_v3(obmat, iloc);
}
else if (t->flag & T_OBJECT) {
td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
@@ -438,11 +415,11 @@ void applyGridAbsolute(TransInfo *t)
}
mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
- loc[0] = floorf(loc[0]);
- loc[1] = floorf(loc[1]);
- loc[2] = floorf(loc[2]);
+ loc[0] = roundf(loc[0]);
+ loc[1] = roundf(loc[1]);
+ loc[2] = roundf(loc[2]);
mul_v3_fl(loc, grid_size);
-
+
sub_v3_v3v3(tvec, loc, iloc);
mul_m3_v3(td->smtx, tvec);
add_v3_v3(td->loc, tvec);
@@ -460,7 +437,7 @@ void applySnapping(TransInfo *t, float *vec)
t->tsnap.applySnap(t, vec);
}
- else if ((t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) && activeSnap(t)) {
+ else if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t)) {
double current = PIL_check_seconds_timer();
// Time base quirky code to go around findnearest slowness
@@ -583,6 +560,10 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ /* We do our own snapping currently, so nothing here */
+ t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */
+ }
else {
/* Always grid outside of 3D view */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
@@ -638,6 +619,11 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) != 0);
t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) != 0);
}
+
+ /* for now only 3d view (others can be added if we want) */
+ if (t->spacetype == SPACE_VIEW3D) {
+ t->tsnap.snap_spatial_grid = ((t->settings->snap_flag & SCE_SNAP_ABS_GRID) != 0);
+ }
}
t->tsnap.target = snap_target;
@@ -824,14 +810,18 @@ static void ApplySnapRotation(TransInfo *t, float *value)
static void ApplySnapResize(TransInfo *t, float vec[3])
{
+ float dist;
+
if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
- vec[0] = vec[1] = vec[2] = t->tsnap.dist;
+ dist = t->tsnap.dist;
}
else {
float point[3];
getSnapPoint(t, point);
- vec[0] = vec[1] = vec[2] = ResizeBetween(t, t->tsnap.snapTarget, point);
+ dist = ResizeBetween(t, t->tsnap.snapTarget, point);
}
+
+ copy_v3_fl(vec, dist);
}
/********************** DISTANCE **************************/
@@ -843,16 +833,10 @@ static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const f
static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
{
- float angle, start[3], end[3], center[3];
-
- copy_v3_v3(center, t->center);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, center);
- }
+ float angle, start[3], end[3];
- sub_v3_v3v3(start, p1, center);
- sub_v3_v3v3(end, p2, center);
+ sub_v3_v3v3(start, p1, t->center_global);
+ sub_v3_v3v3(end, p2, t->center_global);
// Angle around a constraint axis (error prone, will need debug)
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
@@ -899,17 +883,13 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3])
{
- float d1[3], d2[3], center[3], len_d1;
-
- copy_v3_v3(center, t->center);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, center);
- }
+ float d1[3], d2[3], len_d1;
- sub_v3_v3v3(d1, p1, center);
- sub_v3_v3v3(d2, p2, center);
+ sub_v3_v3v3(d1, p1, t->center_global);
+ sub_v3_v3v3(d2, p2, t->center_global);
+ project_v3_v3v3(d1, d1, d2);
+
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
mul_m3_v3(t->con.pmtx, d1);
mul_m3_v3(t->con.pmtx, d2);
@@ -955,9 +935,9 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
// last_p = LAST_SNAP_POINT;
// }
// else
-// {
+ {
last_p = t->tsnap.snapPoint;
-// }
+ }
for (p1 = depth_peels.first; p1; p1 = p1->next) {
@@ -1001,7 +981,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
break;
}
- new_dist = len_v3v3(last_p, vec);
+ new_dist = len_squared_v3v3(last_p, vec);
if (new_dist < max_dist) {
copy_v3_v3(p, vec);
@@ -1022,6 +1002,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
BLI_freelistN(&depth_peels);
}
else {
+ zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(t, mval, &dist_px, loc, no, t->tsnap.modeSelect);
}
@@ -1047,14 +1028,13 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) {
/* same as above but for UV's */
Image *ima = ED_space_image(t->sa->spacedata.first);
- float aspx, aspy, co[2];
+ float co[2];
UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) {
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
- t->tsnap.snapPoint[0] *= aspx;
- t->tsnap.snapPoint[1] *= aspy;
+ t->tsnap.snapPoint[0] *= t->aspect[0];
+ t->tsnap.snapPoint[1] *= t->aspect[1];
t->tsnap.status |= POINT_INIT;
}
@@ -1115,13 +1095,7 @@ static void TargetSnapCenter(TransInfo *t)
{
/* Only need to calculate once */
if ((t->tsnap.status & TARGET_INIT) == 0) {
- copy_v3_v3(t->tsnap.snapTarget, t->center);
-
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
- }
-
+ copy_v3_v3(t->tsnap.snapTarget, t->center_global);
TargetSnapOffset(t, NULL);
t->tsnap.status |= TARGET_INIT;
@@ -1402,11 +1376,8 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
if (arm->edbo) {
EditBone *eBone;
@@ -1543,8 +1514,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
float ray_start_local[3], ray_normal_local[3], local_scale, len_diff = TRANSFORM_DIST_MAX_RAY;
invert_m4_m4(imat, obmat);
- copy_m3_m4(timat, imat);
- transpose_m3(timat);
+ transpose_m3_m4(timat, imat);
copy_v3_v3(ray_start_local, ray_start);
copy_v3_v3(ray_normal_local, ray_normal);
@@ -1557,8 +1527,17 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
if (do_bb) {
BoundBox *bb = BKE_object_boundbox_get(ob);
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
+
+ if (bb) {
+ BoundBox bb_temp;
+
+ /* We cannot aford a bbox with some null dimension, which may happen in some cases...
+ * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
+ bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
+
+ if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
}
}
else if (do_ray_start_correction) {
@@ -1570,7 +1549,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
len_diff = 0.0f; /* In case BVHTree would fail for some reason... */
treeData.em_evil = em;
- bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 2, 6);
+ bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 2, 6);
if (treeData.tree != NULL) {
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
@@ -1612,7 +1591,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
}
treeData.em_evil = em;
- bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6);
+ bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 4, 6);
hit.index = -1;
hit.dist = *r_depth;
@@ -1765,11 +1744,8 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
switch (snap_mode) {
case SCE_SNAP_MODE_VERTEX:
@@ -1887,8 +1863,16 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f
do_bb = false;
}
else {
+ /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
+ * still set the 'em' to NULL, since we only want the 'dm'. */
+ em = BKE_editmesh_from_object(ob);
+ if (em) {
+ editbmesh_get_derived_cage_and_final(scene, ob, em, CD_MASK_BAREMESH, &dm);
+ }
+ else {
+ dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ }
em = NULL;
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_depth, do_bb);
@@ -1956,21 +1940,32 @@ static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D
(ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
{
Object *ob = base->object;
-
+ Object *ob_snap = ob;
+ bool use_obedit = false;
+
+ /* for linked objects, use the same object but a different matrix */
+ if (obedit && ob->data == obedit->data) {
+ use_obedit = true;
+ ob_snap = obedit;
+ }
+
if (ob->transflag & OB_DUPLI) {
DupliObject *dupli_ob;
ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob);
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- retval |= snapObject(scene, snap_mode, ar, dupli_ob->ob, dupli_ob->mat, false,
+ bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
+ Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
+
+ retval |= snapObject(scene, snap_mode, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli,
r_ob, r_obmat,
ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist);
}
free_object_duplilist(lb);
}
-
- retval |= snapObject(scene, snap_mode, ar, ob, ob->obmat, false,
+
+ retval |= snapObject(scene, snap_mode, ar, ob_snap, ob->obmat, use_obedit,
r_ob, r_obmat,
ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist);
}
@@ -1997,8 +1992,20 @@ static bool snapObjects(Scene *scene, short snap_mode, Base *base_act, View3D *v
bool snapObjectsTransform(TransInfo *t, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode)
{
float ray_dist = TRANSFORM_DIST_MAX_RAY;
- return snapObjects(t->scene, t->scene->toolsettings->snap_mode, t->scene->basact, t->view, t->ar, t->obedit,
- mval, r_dist_px, r_loc, r_no, &ray_dist, mode);
+ Object *obedit = NULL;
+ Base *base_act = NULL;
+
+ if (t->flag & T_EDIT) {
+ obedit = t->obedit;
+ }
+
+ if ((t->options & CTX_GPENCIL_STROKES) == 0) {
+ base_act = t->scene->basact;
+ }
+
+ return snapObjects(
+ t->scene, t->scene->toolsettings->snap_mode, base_act, t->view, t->ar, obedit,
+ mval, r_dist_px, r_loc, r_no, &ray_dist, mode);
}
bool snapObjectsContext(bContext *C, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode)
@@ -2085,110 +2092,108 @@ static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float n
peel->flag = 0;
}
-static bool peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]),
- ListBase *depth_peels)
+struct PeelRayCast_Data {
+ BVHTreeFromMesh bvhdata;
+
+ /* internal vars for adding peel */
+ Object *ob;
+ const float (*obmat)[4];
+ const float (*timat)[3];
+
+ const float *ray_start; /* globalspace */
+
+ const MLoopTri *looptri;
+ const float (*polynors)[3]; /* optional, can be NULL */
+
+ /* output list */
+ ListBase *depth_peels;
+};
+
+static void peelRayCast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ struct PeelRayCast_Data *data = userdata;
+
+ data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
+
+ if (hit->index != -1) {
+ /* get all values in worldspace */
+ float location[3], normal[3];
+ float depth;
+
+ /* worldspace location */
+ mul_v3_m4v3(location, (float (*)[4])data->obmat, hit->co);
+ depth = len_v3v3(location, data->ray_start);
+
+ /* worldspace normal */
+ copy_v3_v3(normal, data->polynors ? data->polynors[data->looptri[hit->index].poly] : hit->no);
+ mul_m3_v3((float (*)[3])data->timat, normal);
+ normalize_v3(normal);
+
+ addDepthPeel(data->depth_peels, depth, location, normal, data->ob);
+ }
+}
+
+static bool peelDerivedMesh(
+ Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
+ const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]),
+ ListBase *depth_peels)
{
bool retval = false;
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumTessFaces(dm);
if (totvert > 0) {
+ const MLoopTri *looptri = dm->getLoopTriArray(dm);
+ const int looptri_num = dm->getNumLoopTri(dm);
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
float ray_start_local[3], ray_normal_local[3];
- int test = 1;
+ bool test = true;
invert_m4_m4(imat, obmat);
- copy_m3_m4(timat, imat);
- transpose_m3(timat);
-
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ transpose_m3_m4(timat, imat);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
/* If number of vert is more than an arbitrary limit,
* test against boundbox first
* */
- if (totface > 16) {
- struct BoundBox *bb = BKE_object_boundbox_get(ob);
- test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL);
- }
-
- if (test == 1) {
- MVert *verts = dm->getVertArray(dm);
- MFace *faces = dm->getTessFaceArray(dm);
- int i;
-
- for (i = 0; i < totface; i++) {
- MFace *f = faces + i;
- float lambda;
- int result;
-
-
- result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001);
-
- if (result) {
- float location[3], normal[3];
- float intersect[3];
- float new_depth;
-
- copy_v3_v3(intersect, ray_normal_local);
- mul_v3_fl(intersect, lambda);
- add_v3_v3(intersect, ray_start_local);
-
- copy_v3_v3(location, intersect);
-
- if (f->v4)
- normal_quad_v3(normal, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co);
- else
- normal_tri_v3(normal, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co);
+ if (looptri_num > 16) {
+ BoundBox *bb = BKE_object_boundbox_get(ob);
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- mul_m3_v3(timat, normal);
- normalize_v3(normal);
+ if (bb) {
+ BoundBox bb_temp;
- addDepthPeel(depth_peels, new_depth, location, normal, ob);
- }
-
- if (f->v4 && result == 0) {
- result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001);
-
- if (result) {
- float location[3], normal[3];
- float intersect[3];
- float new_depth;
-
- copy_v3_v3(intersect, ray_normal_local);
- mul_v3_fl(intersect, lambda);
- add_v3_v3(intersect, ray_start_local);
-
- copy_v3_v3(location, intersect);
-
- if (f->v4)
- normal_quad_v3(normal, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co);
- else
- normal_tri_v3(normal, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co);
+ /* We cannot aford a bbox with some null dimension, which may happen in some cases...
+ * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
+ bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
- mul_m4_v3(obmat, location);
-
- new_depth = len_v3v3(location, ray_start);
-
- mul_m3_v3(timat, normal);
- normalize_v3(normal);
-
- addDepthPeel(depth_peels, new_depth, location, normal, ob);
- }
- }
+ test = BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, NULL);
}
}
+
+ if (test == true) {
+ struct PeelRayCast_Data data;
+
+ data.bvhdata.em_evil = em;
+ bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6);
+
+ if (data.bvhdata.tree != NULL) {
+ data.ob = ob;
+ data.obmat = (const float (*)[4])obmat;
+ data.timat = (const float (*)[3])timat;
+ data.ray_start = ray_start;
+ data.looptri = looptri;
+ data.polynors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
+ data.depth_peels = depth_peels;
+
+ BLI_bvhtree_ray_cast_all(data.bvhdata.tree, ray_start_local, ray_normal_local, 0.0f,
+ peelRayCast_cb, &data);
+ }
+
+ free_bvhtree_from_mesh(&data.bvhdata);
+ }
}
return retval;
@@ -2224,13 +2229,13 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
if (dob != obedit) {
dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
- val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, depth_peels);
}
else {
em = BKE_editmesh_from_object(dob);
dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
- val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, depth_peels);
}
retval = retval || val;
@@ -2248,14 +2253,14 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
if (ob != obedit && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT))) {
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, depth_peels);
dm->release(dm);
}
else if (ob == obedit && mode != SNAP_NOT_OBEDIT) {
BMEditMesh *em = BKE_editmesh_from_object(ob);
DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
- val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, depth_peels);
dm->release(dm);
}
@@ -2265,7 +2270,7 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
}
}
- BLI_sortlist(depth_peels, cmpPeel);
+ BLI_listbase_sort(depth_peels, cmpPeel);
removeDoublesPeel(depth_peels);
return retval;
@@ -2396,7 +2401,7 @@ bool snapNodesContext(bContext *C, const int mval[2], float *r_dist_px, float r_
/*================================================================*/
-static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
+static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action)
@@ -2415,8 +2420,8 @@ void snapGridIncrement(TransInfo *t, float *val)
{
GearsType action;
- // Only do something if using Snap to Grid
- if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT)
+ /* only do something if using absolute or incremental grid snapping */
+ if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))
return;
action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
@@ -2428,35 +2433,77 @@ void snapGridIncrement(TransInfo *t, float *val)
snapGridIncrementAction(t, val, action);
}
+void snapSequenceBounds(TransInfo *t, const int mval[2])
+{
+ float xmouse, ymouse;
+ int frame;
+ int mframe;
+ TransSeq *ts = t->customData;
+ /* reuse increment, strictly speaking could be another snap mode, but leave as is */
+ if (!(t->modifiers & MOD_SNAP_INVERT))
+ return;
+
+ /* convert to frame range */
+ UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse);
+ mframe = iroundf(xmouse);
+ /* now find the closest sequence */
+ frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true);
-static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fac[3], GearsType action)
+ if (!ts->snap_left)
+ frame = frame - (ts->max - ts->min);
+
+ t->values[0] = frame - ts->min;
+}
+
+static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action)
{
+ float asp_local[3] = {1, 1, 1};
+ const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION);
+ const float *asp = use_aspect ? t->aspect : asp_local;
int i;
- float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
- if (max_index > 2) {
- printf("applyGridIncrement: invalid index %d, clamping\n", max_index);
- max_index = 2;
- }
+ BLI_assert(ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID));
+ BLI_assert(max_index <= 2);
- // Early bailing out if no need to snap
- if (fac[action] == 0.0f)
+ /* Early bailing out if no need to snap */
+ if (fac[action] == 0.0f) {
return;
-
- /* evil hack - snapping needs to be adapted for image aspect ratio */
- if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
- if (t->options & CTX_MASK) {
- ED_space_image_get_aspect(t->sa->spacedata.first, asp, asp + 1);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- asp[0] = asp[1] = 1.0;
- }
- else {
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1);
+ }
+
+ if (use_aspect) {
+ /* custom aspect for fcurve */
+ if (t->spacetype == SPACE_IPO) {
+ View2D *v2d = &t->ar->v2d;
+ View2DGrid *grid;
+ SpaceIpo *sipo = t->sa->spacedata.first;
+ int unity = V2D_UNIT_VALUES;
+ int unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
+
+ /* grid */
+ grid = UI_view2d_grid_calc(t->scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, t->ar->winx, t->ar->winy);
+
+ UI_view2d_grid_size(grid, &asp_local[0], &asp_local[1]);
+ UI_view2d_grid_free(grid);
+
+ asp = asp_local;
}
}
- for (i = 0; i <= max_index; i++) {
- val[i] = fac[action] * asp[i] * (float)floor(val[i] / (fac[action] * asp[i]) + 0.5f);
+ /* absolute snapping on grid based on global center */
+ if ((t->tsnap.snap_spatial_grid) && (t->mode == TFM_TRANSLATION)) {
+ for (i = 0; i <= max_index; i++) {
+ /* do not let unconstrained axis jump to absolute grid increments */
+ if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) {
+ const float iter_fac = fac[action] * asp[i];
+ val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i];
+ }
+ }
+ }
+ else {
+ /* relative snapping in fixed increments */
+ for (i = 0; i <= max_index; i++) {
+ const float iter_fac = fac[action] * asp[i];
+ val[i] = iter_fac * roundf(val[i] / iter_fac);
+ }
}
}
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 4400870f1b8..7de788dca56 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -20,14 +20,17 @@
set(INC
../include
- ../../blenfont
../../blenkernel
../../blenlib
+ ../../blentranslation
../../bmesh
+ ../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -67,6 +70,7 @@ set(SRC
../include/ED_node.h
../include/ED_numinput.h
../include/ED_object.h
+ ../include/ED_outliner.h
../include/ED_paint.h
../include/ED_particle.h
../include/ED_physics.h
@@ -91,7 +95,7 @@ set(SRC
../include/UI_view2d.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
diff --git a/source/blender/editors/util/SConscript b/source/blender/editors/util/SConscript
index 0876fe48c91..7d9991e6483 100644
--- a/source/blender/editors/util/SConscript
+++ b/source/blender/editors/util/SConscript
@@ -28,16 +28,20 @@
Import ('env')
sources = env.Glob('*.c')
-defs = [ 'GLEW_STATIC' ]
+
+defs = []
+defs += env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index 104b628c25a..b0970cdfd48 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -310,7 +310,7 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
}
else if (obedit->type == OB_ARMATURE) {
bArmature *arm = obedit->data;
- int totmalloc = BLI_countlist(arm->edbo);
+ int totmalloc = BLI_listbase_count(arm->edbo);
totmalloc *= 2; /* probably overkill but bones can have 2 trans verts each */
@@ -318,9 +318,9 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (ebo->layer & arm->layer) {
- short tipsel = (ebo->flag & BONE_TIPSEL);
- short rootsel = (ebo->flag & BONE_ROOTSEL);
- short rootok = (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && (ebo->parent->flag & BONE_TIPSEL)));
+ const bool tipsel = (ebo->flag & BONE_TIPSEL) != 0;
+ const bool rootsel = (ebo->flag & BONE_ROOTSEL) != 0;
+ const bool rootok = (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && (ebo->parent->flag & BONE_TIPSEL)));
if ((tipsel && rootsel) || (rootsel)) {
/* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
@@ -441,7 +441,7 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
}
else if (obedit->type == OB_MBALL) {
MetaBall *mb = obedit->data;
- int totmalloc = BLI_countlist(mb->editelems);
+ int totmalloc = BLI_listbase_count(mb->editelems);
tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 56b12fcdcda..f727f48e993 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -38,6 +38,7 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_packedFile_types.h"
@@ -48,7 +49,7 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -58,9 +59,12 @@
#include "BKE_paint.h"
#include "ED_armature.h"
+#include "ED_buttons.h"
#include "ED_image.h"
#include "ED_mesh.h"
+#include "ED_node.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_paint.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -107,7 +111,7 @@ void ED_editors_init(bContext *C)
/* image editor paint mode */
if (sce) {
- ED_space_image_paint_update(wm, sce->toolsettings);
+ ED_space_image_paint_update(wm, sce);
}
SWAP(int, reports->flag, reports_flag_prev);
@@ -153,19 +157,20 @@ void ED_editors_exit(bContext *C)
/* flush any temp data from object editing to DNA before writing files,
* rendering, copying, etc. */
-void ED_editors_flush_edits(const bContext *C, bool for_render)
+bool ED_editors_flush_edits(const bContext *C, bool for_render)
{
+ bool has_edited = false;
Object *ob;
- Object *obedit = CTX_data_edit_object(C);
Main *bmain = CTX_data_main(C);
- /* get editmode results */
- if (obedit)
- ED_object_editmode_load(obedit);
+ /* loop through all data to find edit mode or object mode, because during
+ * exiting we might not have a context for edit object and multiple sculpt
+ * objects can exist at the same time */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob && (ob->mode & OB_MODE_SCULPT)) {
+ if (ob->mode & OB_MODE_SCULPT) {
/* flush multires changes (for sculpt) */
multires_force_update(ob);
+ has_edited = true;
if (for_render) {
/* flush changes from dynamic topology sculpt */
@@ -173,11 +178,18 @@ void ED_editors_flush_edits(const bContext *C, bool for_render)
}
else {
/* Set reorder=false so that saving the file doesn't reorder
- * the BMesh's elements */
+ * the BMesh's elements */
BKE_sculptsession_bm_to_me(ob, false);
}
}
+ else if (ob->mode & OB_MODE_EDIT) {
+ /* get editmode results */
+ has_edited = true;
+ ED_object_editmode_load(ob);
+ }
}
+
+ return has_edited;
}
/* ***** XXX: functions are using old blender names, cleanup later ***** */
@@ -210,8 +222,8 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
- pup = uiPupMenuBegin(C, IFACE_("Unpack File"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
props_ptr = uiItemFullO_ptr(layout, ot, IFACE_("Remove Pack"), ICON_NONE,
NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
@@ -223,7 +235,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
- if (strcmp(abs_name, local_name) != 0) {
+ if (!STREQ(abs_name, local_name)) {
switch (checkPackedFile(local_name, pf)) {
case PF_NOFILE:
BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name);
@@ -287,7 +299,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
break;
}
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
/* ********************* generic callbacks for drawcall api *********************** */
@@ -310,3 +322,25 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
glEnd();
setlinestyle(0);
}
+
+/**
+ * Use to free ID references within runtime data (stored outside of DNA)
+ *
+ * \note Typically notifiers take care of this,
+ * but there are times we have to free references immediately, see: T44376
+ */
+void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
+{
+
+ switch (sl->spacetype) {
+ case SPACE_OUTLINER:
+ ED_outliner_id_unref((SpaceOops *)sl, id);
+ break;
+ case SPACE_BUTS:
+ ED_buttons_id_unref((SpaceButs *)sl, id);
+ break;
+ case SPACE_NODE:
+ ED_node_id_unref((SpaceNode *)sl, id);
+ break;
+ }
+}
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index ef95e4cb3ff..bc7a8374c73 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -48,8 +48,6 @@
#include "ED_util.h"
#include "ED_mesh.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
#include "util_intern.h"
@@ -208,7 +206,7 @@ static void undo_clean_stack(bContext *C)
/* for when objects are converted, renamed, or global undo changes pointers... */
if (uel->type == obedit->type) {
- if (strcmp(uel->id.name, obedit->id.name) == 0) {
+ if (STREQ(uel->id.name, obedit->id.name)) {
if (uel->validate_undo == NULL)
is_valid = true;
else if (uel->validate_undo(uel->undodata, editdata))
@@ -307,7 +305,7 @@ void undo_editmode_name(bContext *C, const char *undoname)
UndoElem *uel;
for (uel = undobase.last; uel; uel = uel->prev) {
- if (strcmp(undoname, uel->name) == 0)
+ if (STREQ(undoname, uel->name))
break;
}
if (uel && uel->prev) {
@@ -317,13 +315,13 @@ void undo_editmode_name(bContext *C, const char *undoname)
}
/* undoname optionally, if NULL it just checks for existing undo steps */
-int undo_editmode_valid(const char *undoname)
+bool undo_editmode_is_valid(const char *undoname)
{
if (undoname) {
UndoElem *uel;
for (uel = undobase.last; uel; uel = uel->prev) {
- if (strcmp(undoname, uel->name) == 0)
+ if (STREQ(undoname, uel->name))
break;
}
return uel != NULL;
@@ -334,19 +332,20 @@ int undo_editmode_valid(const char *undoname)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *undo_editmode_get_name(bContext *C, int nr, int *active)
+const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active)
{
UndoElem *uel;
/* prevent wrong numbers to be returned */
undo_clean_stack(C);
- if (active) *active = 0;
+ if (r_active) *r_active = false;
uel = BLI_findlink(&undobase, nr);
if (uel) {
- if (active && uel == curundo)
- *active = 1;
+ if (r_active && (uel == curundo)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index a154f12a786..d2bc8bc80c0 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -73,14 +73,14 @@ void initNumInput(NumInput *n)
{
n->idx_max = 0;
n->unit_sys = USER_UNIT_NONE;
- fill_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
+ copy_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
n->unit_use_radians = false;
n->flag = 0;
- fill_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
+ copy_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
zero_v3(n->val);
- fill_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
- fill_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
+ copy_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
+ copy_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
n->idx = 0;
n->str[0] = '\0';
@@ -103,7 +103,7 @@ void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
if (n->val_flag[i] & NUM_EDITED) {
/* Get the best precision, allows us to draw '10.0001' as '10' instead! */
- prec = uiFloatPrecisionCalc(prec, (double)n->val[i]);
+ prec = UI_calc_float_precision(prec, (double)n->val[i]);
if (i == n->idx) {
const char *heading_exp = "", *trailing_exp = "";
char before_cursor[NUM_STR_REP_LEN];
@@ -365,9 +365,10 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
ascii[0] = '.';
utf8_buf = ascii;
break;
-#if 0 /* Those keys are not directly accessible in all layouts, preventing to generate matching events.
- * So we use a hack (ascii value) instead, see below.
- */
+#if 0
+ /* Those keys are not directly accessible in all layouts, preventing to generate matching events.
+ * So we use a hack (ascii value) instead, see below.
+ */
case EQUALKEY:
case PADASTERKEY:
if (!(n->flag & NUM_EDIT_FULL)) {
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 189a938e3d8..cd68df52ed4 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -29,8 +29,6 @@
* \ingroup edutil
*/
-
-
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -42,11 +40,12 @@
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_screen.h"
#include "ED_armature.h"
@@ -109,7 +108,7 @@ void ED_undo_push(bContext *C, const char *str)
/* do nothing for now */
}
else {
- BKE_write_undo(C, str);
+ BKE_undo_write(C, str);
}
if (wm->file_saved) {
@@ -124,6 +123,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
@@ -146,7 +146,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) {
if (U.uiflag & USER_GLOBALUNDO) {
- ED_viewport_render_kill_jobs(C, true);
+ ED_viewport_render_kill_jobs(wm, bmain, true);
BKE_undo_name(C, undoname);
}
}
@@ -199,7 +199,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
/* for example, texface stores image pointers */
undo_editmode_clear();
- ED_viewport_render_kill_jobs(C, true);
+ ED_viewport_render_kill_jobs(wm, bmain, true);
if (undoname)
BKE_undo_name(C, undoname);
@@ -244,7 +244,7 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
}
/* name optionally, function used to check for operator redo panel */
-int ED_undo_valid(const bContext *C, const char *undoname)
+bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
@@ -263,7 +263,7 @@ int ED_undo_valid(const bContext *C, const char *undoname)
}
else if (obedit) {
if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) {
- return undo_editmode_valid(undoname);
+ return undo_editmode_is_valid(undoname);
}
}
else {
@@ -271,19 +271,19 @@ int ED_undo_valid(const bContext *C, const char *undoname)
/* if below tests fail, global undo gets executed */
if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
- if (ED_undo_paint_valid(UNDO_PAINT_IMAGE, undoname))
+ if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname))
return 1;
}
else if (obact && obact->mode & OB_MODE_SCULPT) {
- if (ED_undo_paint_valid(UNDO_PAINT_MESH, undoname))
+ if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname))
return 1;
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- return PE_undo_valid(CTX_data_scene(C));
+ return PE_undo_is_valid(CTX_data_scene(C));
}
if (U.uiflag & USER_GLOBALUNDO) {
- return BKE_undo_valid(undoname);
+ return BKE_undo_is_valid(undoname);
}
}
return 0;
@@ -379,7 +379,7 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
{
int retval;
- ED_viewport_render_kill_jobs(C, true);
+ ED_viewport_render_kill_jobs(wm, CTX_data_main(C), true);
if (G.debug & G_DEBUG)
printf("redo_cb: operator redo %s\n", op->type->name);
@@ -487,7 +487,8 @@ static int get_undo_system(bContext *C)
static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
- int active, i = 0;
+ int i = 0;
+ bool active;
while (true) {
const char *name = NULL;
@@ -536,8 +537,8 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
EnumPropertyItem *item = rna_undo_itemf(C, undosys, &totitem);
if (totitem > 0) {
- uiPopupMenu *pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
uiLayout *column = NULL;
const int col_size = 20 + totitem / 12;
@@ -558,7 +559,7 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
MEM_freeN(item);
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
}
}
@@ -580,10 +581,10 @@ static int undo_history_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
else if (undosys == UNDOSYSTEM_IMAPAINT) {
- ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item );
+ ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item);
}
else {
- ED_viewport_render_kill_jobs(C, true);
+ ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true);
BKE_undo_number(C, item);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
}
diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/util/util_intern.h
index d366ad7997f..0f650330951 100644
--- a/source/blender/editors/util/util_intern.h
+++ b/source/blender/editors/util/util_intern.h
@@ -35,12 +35,12 @@
/* internal exports only */
/* editmode_undo.c */
-void undo_editmode_name (struct bContext *C, const char *undoname);
-int undo_editmode_valid (const char *undoname);
-const char *undo_editmode_get_name (struct bContext *C, int nr, int *active);
-void *undo_editmode_get_prev (struct Object *ob);
-void undo_editmode_step (struct bContext *C, int step);
-void undo_editmode_number (struct bContext *C, int nr);
+void undo_editmode_name(struct bContext *C, const char *undoname);
+bool undo_editmode_is_valid(const char *undoname);
+const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active);
+void *undo_editmode_get_prev(struct Object *ob);
+void undo_editmode_step(struct bContext *C, int step);
+void undo_editmode_number(struct bContext *C, int nr);
#endif /* __UTIL_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 45edbde7482..a90763eed4e 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -22,12 +22,14 @@ set(INC
../include
../../blenkernel
../../blenlib
- ../../blenfont
+ ../../blentranslation
../../bmesh
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -57,4 +59,6 @@ if(WITH_OPENNL)
)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_uvedit "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript
index 413503191cd..b5cccab4002 100644
--- a/source/blender/editors/uvedit/SConscript
+++ b/source/blender/editors/uvedit/SConscript
@@ -28,17 +28,19 @@
Import ('env')
defs = []
+defs += env['BF_GL_DEFINITIONS']
sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/opennl/extern',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
'../../bmesh',
'../../gpu',
'../../makesdna',
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 6816e785c1f..ab415c0cb83 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -53,7 +53,6 @@
#include "ED_uvedit.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -142,11 +141,25 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
em = BKE_editmesh_from_object(obedit);
if (uvedit_center(scene, em, ima, center)) {
+ float range_xy[2][2] = {
+ {-10.0f, 10.0f},
+ {-10.0f, 10.0f},
+ };
+
copy_v2_v2(uvedit_old_center, center);
+ /* expand UI range by center */
+ CLAMP_MAX(range_xy[0][0], uvedit_old_center[0]);
+ CLAMP_MIN(range_xy[0][1], uvedit_old_center[0]);
+ CLAMP_MAX(range_xy[1][0], uvedit_old_center[1]);
+ CLAMP_MIN(range_xy[1][1], uvedit_old_center[1]);
+
if (!(sima->flag & SI_COORDFLOATS)) {
uvedit_old_center[0] *= imx;
uvedit_old_center[1] *= imy;
+
+ mul_v2_fl(range_xy[0], imx);
+ mul_v2_fl(range_xy[1], imy);
}
if (sima->flag & SI_COORDFLOATS) {
@@ -158,12 +171,12 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
digits = 2;
}
- uiBlockBeginAlign(block);
- uiDefButF(block, NUM, B_UVEDIT_VERTEX, IFACE_("X:"), 0, 0, width, UI_UNIT_Y, &uvedit_old_center[0],
- -10 * imx, 10.0 * imx, step, digits, "");
- uiDefButF(block, NUM, B_UVEDIT_VERTEX, IFACE_("Y:"), width, 0, width, UI_UNIT_Y, &uvedit_old_center[1],
- -10 * imy, 10.0 * imy, step, digits, "");
- uiBlockEndAlign(block);
+ UI_block_align_begin(block);
+ uiDefButF(block, UI_BTYPE_NUM, B_UVEDIT_VERTEX, IFACE_("X:"), 0, 0, width, UI_UNIT_Y, &uvedit_old_center[0],
+ UNPACK2(range_xy[0]), step, digits, "");
+ uiDefButF(block, UI_BTYPE_NUM, B_UVEDIT_VERTEX, IFACE_("Y:"), width, 0, width, UI_UNIT_Y, &uvedit_old_center[1],
+ UNPACK2(range_xy[1]), step, digits, "");
+ UI_block_align_end(block);
}
}
@@ -212,7 +225,7 @@ static void image_panel_uv(const bContext *C, Panel *pa)
uiBlock *block;
block = uiLayoutAbsoluteBlock(pa->layout);
- uiBlockSetHandleFunc(block, do_uvedit_vertex, NULL);
+ UI_block_func_handle_set(block, do_uvedit_vertex, NULL);
uvedit_vertex_buttons(C, block);
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 36c96a8d011..4e9ab680dc6 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -43,7 +43,6 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_alloca.h"
#include "BLI_buffer.h"
#include "BLI_bitmap.h"
@@ -71,7 +70,7 @@
static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset);
-void draw_image_cursor(ARegion *ar, const float cursor[2])
+void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
{
float zoom[2], x_fac, y_fac;
@@ -82,7 +81,7 @@ void draw_image_cursor(ARegion *ar, const float cursor[2])
y_fac = zoom[1];
cpack(0xFFFFFF);
- glTranslatef(cursor[0], cursor[1], 0.0);
+ glTranslate2fv(cursor);
fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac);
fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f);
fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac);
@@ -325,7 +324,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
a = fabsf(uvang[i] - ang[i]) / (float)M_PI;
- weight_to_rgb(col, 1.0f - powf((1.0f - a), 2.0f));
+ weight_to_rgb(col, 1.0f - pow2f(1.0f - a));
glColor3fv(col);
glVertex2fv(luv->uv);
}
@@ -506,6 +505,8 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
mloopuv_base = mloopuv;
for (a = me->totpoly; a > 0; a--, mpoly++) {
+ if ((scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE) && mpoly->mat_nr != ob->actcol - 1)
+ continue;
glBegin(GL_LINE_LOOP);
mloopuv = mloopuv_base + mpoly->loopstart;
@@ -597,7 +598,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
/* first try existing derivedmesh */
if (!draw_uvs_dm_shadow(em->derivedFinal)) {
/* create one if it does not exist */
- cagedm = editbmesh_get_derived_cage_and_final(scene, obedit, me->edit_btmesh, &finaldm, CD_MASK_BAREMESH | CD_MASK_MTFACE);
+ cagedm = editbmesh_get_derived_cage_and_final(
+ scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH | CD_MASK_MTFACE,
+ &finaldm);
/* when sync selection is enabled, all faces are drawn (except for hidden)
* so if cage is the same as the final, theres no point in drawing this */
@@ -946,14 +949,30 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glPointSize(1.0);
}
-void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
+
+static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint)
+{
+ *show_shadow = *show_texpaint = false;
+
+ if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT))
+ return;
+
+ if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
+ struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ *show_shadow = EDBM_mtexpoly_check(em);
+ }
+
+ *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
+}
+
+void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
{
ToolSettings *toolsettings = scene->toolsettings;
- int show_uvedit, show_uvshadow, show_texpaint_uvshadow;
+ bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
- show_texpaint_uvshadow = ED_space_image_show_texpaint(sima, obact);
show_uvedit = ED_space_image_show_uvedit(sima, obedit);
- show_uvshadow = ED_space_image_show_uvshadow(sima, obedit);
+ draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
if (show_uvshadow)
@@ -964,7 +983,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi
draw_uvs_texpaint(sima, scene, obact);
if (show_uvedit && !(toolsettings->use_uv_sculpt))
- draw_image_cursor(ar, sima->cursor);
+ ED_image_draw_cursor(ar, sima->cursor);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 52365ff3478..e028c08091c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -34,17 +34,13 @@
struct MTexPoly;
struct Image;
-struct MTFace;
struct Object;
struct Scene;
struct SpaceImage;
-struct UvElementMap;
struct wmOperatorType;
struct BMEditMesh;
struct BMFace;
struct BMLoop;
-struct BMEdge;
-struct BMVert;
/* visibility and selection */
bool uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
@@ -71,7 +67,6 @@ void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditM
/* utility tool functions */
void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
-void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, float *aspx, float *aspy);
/* operators */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 4b341547370..71d557f6fc7 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -53,6 +53,8 @@
#include "BLI_blenlib.h"
#include "BLI_array.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
@@ -80,6 +82,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "uvedit_intern.h"
@@ -668,6 +672,24 @@ bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2],
return changed;
}
+/* Be careful when using this, it bypasses all synchronization options */
+void ED_uvedit_select_all(BMesh *bm)
+{
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
+}
+
static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -1010,7 +1032,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/* setup */
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
@@ -1096,7 +1118,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/*********************** linked select ***********************/
-static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend)
+static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend, bool select_faces)
{
BMFace *efa;
BMLoop *l;
@@ -1113,7 +1135,9 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
- vmap = BM_uv_vert_map_create(em->bm, 1, limit);
+
+ /* use winding so we don't consider overlapping islands as connected, see T44320 */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, true);
if (vmap == NULL)
return;
@@ -1126,15 +1150,24 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
stack[stacksize] = a;
stacksize++;
flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- break;
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
}
}
}
@@ -1186,13 +1219,21 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!extend) {
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
+ if (select_faces) {
if (flag[a])
- luv->flag |= MLOOPUV_VERTSEL;
+ BM_face_select_set(em->bm, efa, true);
else
- luv->flag &= ~MLOOPUV_VERTSEL;
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (flag[a])
+ luv->flag |= MLOOPUV_VERTSEL;
+ else
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1201,17 +1242,23 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!flag[a]) {
continue;
}
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
break;
- }
}
-
- if (l) {
- break;
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ break;
+ }
+ }
+
+ if (l) {
+ break;
+ }
}
}
@@ -1221,10 +1268,15 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->flag &= ~MLOOPUV_VERTSEL;
+ if (select_faces) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1234,10 +1286,15 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->flag |= MLOOPUV_VERTSEL;
+ if (select_faces) {
+ BM_face_select_set(em->bm, efa, true);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1291,10 +1348,10 @@ static int uv_select_more_less(bContext *C, const bool select)
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (select) {
- EDBM_select_more(em);
+ EDBM_select_more(em, true);
}
else {
- EDBM_select_less(em);
+ EDBM_select_less(em, true);
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -1753,7 +1810,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
if ((vert_arr[uv_b_index].weld == false) &&
(len_manhattan_v2v2(uv_a, uv_b) < threshold))
{
- minmax_v2v2_v2(uv_max, uv_min, uv_b);
+ minmax_v2v2_v2(uv_min, uv_max, uv_b);
BLI_array_append(loop_arr, vert_arr[uv_b_index].uv_loop);
vert_arr[uv_b_index].weld = true;
}
@@ -2069,7 +2126,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* mark 1 vertex as being hit */
hitv = BLI_array_alloca(hitv, hit.efa->len);
hituv = BLI_array_alloca(hituv, hit.efa->len);
- fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
hituv[hit.lindex] = hit.luv->uv;
@@ -2086,7 +2143,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* mark 2 edge vertices as being hit */
hitv = BLI_array_alloca(hitv, hit.efa->len);
hituv = BLI_array_alloca(hituv, hit.efa->len);
- fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
@@ -2136,7 +2193,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
flush = uv_select_edgeloop(scene, ima, em, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
- uv_select_linked(scene, ima, em, limit, &hit, extend);
+ uv_select_linked(scene, ima, em, limit, &hit, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -2357,11 +2414,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
BMEditMesh *em = BKE_editmesh_from_object(obedit);
float limit[2];
int extend;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
NearestHit hit, *hit_p = NULL;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled");
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
return OPERATOR_CANCELLED;
}
@@ -2387,7 +2445,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
hit_p = &hit;
}
- uv_select_linked(scene, ima, em, limit, hit_p, extend);
+ uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -2662,7 +2720,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
uvedit_pixel_to_float(sima, limit, 0.05);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
if (vmap == NULL) {
return;
}
@@ -2753,7 +2811,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
uvedit_pixel_to_float(sima, limit, 0.05);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
if (vmap == NULL) {
return;
}
@@ -3046,9 +3104,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE);
+ const bool use_face_center = (
+ (ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -3171,8 +3230,8 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
static void uv_snap_to_pixel(float uvco[2], float w, float h)
{
- uvco[0] = ((float)((int)((uvco[0] * w) + 0.5f))) / w;
- uvco[1] = ((float)((int)((uvco[1] * h) + 0.5f))) / h;
+ uvco[0] = roundf(uvco[0] * w) / w;
+ uvco[1] = roundf(uvco[1] * h) / h;
}
static void uv_snap_cursor_to_pixels(SpaceImage *sima)
@@ -3273,7 +3332,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tface;
+ MTexPoly *mtexpoly;
MLoopUV *luv;
bool changed = false;
@@ -3281,8 +3340,8 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tface))
+ mtexpoly = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (!uvedit_face_visible_test(scene, ima, efa, mtexpoly))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3859,6 +3918,15 @@ static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e
ARegion *ar = CTX_wm_region(C);
float location[2];
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (event->mval[1] <= 16) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima && ED_space_image_show_cache(sima)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
RNA_float_set_array(op->ptr, "location", location);
@@ -3975,7 +4043,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
/* This code sets editvert->tmp.l to the index. This will be useful later on. */
BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, 0, limit);
+ vmap = BM_uv_vert_map_create(bm, limit, false, false);
BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
/* flags to determine if we uv is separated from first editface match */
@@ -4080,7 +4148,7 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
}
-static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
+static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
@@ -4090,13 +4158,17 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
BMFace *efa;
BMLoop *loop;
BMIter iter, liter;
+ bool clear = RNA_boolean_get(op->ptr, "clear");
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
+ if (clear)
+ BM_elem_flag_disable(loop->e, BM_ELEM_SEAM);
+ else
+ BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
}
}
}
@@ -4112,10 +4184,27 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"), ICON_NONE, op->type->idname, "clear", false);
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"), ICON_NONE, op->type->idname, "clear", true);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
static void UV_OT_mark_seam(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Mark Seams";
+ ot->name = "Mark Seam";
ot->description = "Mark selected UV edges as seams";
ot->idname = "UV_OT_mark_seam";
@@ -4124,7 +4213,10 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_mark_seam_exec;
+ ot->invoke = uv_mark_seam_invoke;
ot->poll = ED_operator_uvedit;
+
+ RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 79f53e1d971..00615f9bef7 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -35,7 +35,6 @@
#include "BLI_boxpack2d.h"
#include "BLI_convexhull2d.h"
-#include "uvedit_intern.h"
#include "uvedit_parametrizer.h"
#include <math.h>
@@ -2673,8 +2672,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
}
for (i = 0; i < ninterior; i++) {
- sys->lambdaPlanar[i] += nlGetVariable(0, i);
- sys->lambdaLength[i] += nlGetVariable(0, ninterior + i);
+ sys->lambdaPlanar[i] += (float)nlGetVariable(0, i);
+ sys->lambdaLength[i] += (float)nlGetVariable(0, ninterior + i);
}
}
@@ -3403,8 +3402,8 @@ static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
static int p_compare_geometric_uv(const void *a, const void *b)
{
- PVert *v1 = *(PVert **)a;
- PVert *v2 = *(PVert **)b;
+ const PVert *v1 = *(const PVert * const *)a;
+ const PVert *v2 = *(const PVert * const *)b;
if (v1->uv[0] < v2->uv[0])
return -1;
@@ -3789,11 +3788,14 @@ static PBool p_node_intersect(SmoothNode *node, float co[2])
/* smoothing */
-static int p_compare_float(const void *a, const void *b)
+static int p_compare_float(const void *a_, const void *b_)
{
- if (*((float *)a) < *((float *)b))
+ const float a = *(const float *)a_;
+ const float b = *(const float *)b_;
+
+ if (a < b)
return -1;
- else if (*((float *)a) == *((float *)b))
+ else if (a == b)
return 0;
else
return 1;
@@ -4194,7 +4196,7 @@ void param_delete(ParamHandle *handle)
static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
ParamKey *vkeys, float **co, float **uv,
- ParamBool *pin, ParamBool *select, float normal[3])
+ ParamBool *pin, ParamBool *select, const float normal[3])
{
int *boundary = BLI_array_alloca(boundary, nverts);
int i;
@@ -4559,7 +4561,7 @@ void param_pack(ParamHandle *handle, float margin, bool do_rotate)
box->index = i; /* warning this index skips PCHART_NOPACK boxes */
if (margin > 0.0f)
- area += sqrtf(box->w * box->h);
+ area += (double)sqrtf(box->w * box->h);
}
if (margin > 0.0f) {
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index fcd5267fd44..828537fd585 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -574,11 +574,11 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
if (edgesin > 0.0f) {
- rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
+ rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
rot_elem++;
}
else {
- rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
+ rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
rot_elem_neg++;
}
}
@@ -1354,16 +1354,15 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
/* Stitch hash initialization functions */
static unsigned int uv_edge_hash(const void *key)
{
- UvEdge *edge = (UvEdge *)key;
- return
- BLI_ghashutil_uinthash(edge->uv2) +
- BLI_ghashutil_uinthash(edge->uv1);
+ const UvEdge *edge = key;
+ return (BLI_ghashutil_uinthash(edge->uv2) +
+ BLI_ghashutil_uinthash(edge->uv1));
}
static bool uv_edge_compare(const void *a, const void *b)
{
- UvEdge *edge1 = (UvEdge *)a;
- UvEdge *edge2 = (UvEdge *)b;
+ const UvEdge *edge1 = a;
+ const UvEdge *edge2 = b;
if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
return 0;
@@ -1602,7 +1601,7 @@ static int stitch_init(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- GHashIterator *ghi;
+ GHashIterator gh_iter;
UvEdge *all_edges;
StitchState *state;
Scene *scene = CTX_data_scene(C);
@@ -1650,17 +1649,17 @@ static int stitch_init(bContext *C, wmOperator *op)
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = BM_uv_element_map_create(state->em->bm, false, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true);
}
else {
- state->element_map = BM_uv_element_map_create(state->em->bm, true, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true);
}
if (!state->element_map) {
state_delete(state);
return 0;
}
- uvedit_get_aspect(scene, obedit, em, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
state->aspect = aspx / aspy;
/* Entirely possible if redoing last operator that static island is bigger than total number of islands.
@@ -1749,14 +1748,11 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
-
- ghi = BLI_ghashIterator_new(edge_hash);
total_edges = BLI_ghash_size(edge_hash);
state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
/* I assume any system will be able to at least allocate an iterator :p */
if (!edges) {
- BLI_ghashIterator_free(ghi);
state_delete(state);
return 0;
}
@@ -1764,12 +1760,12 @@ static int stitch_init(bContext *C, wmOperator *op)
state->total_separate_edges = total_edges;
/* fill the edges with data */
- for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) {
- edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
+ i = 0;
+ GHASH_ITER (gh_iter, edge_hash) {
+ edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
}
/* cleanup temporary stuff */
- BLI_ghashIterator_free(ghi);
MEM_freeN(all_edges);
BLI_ghash_free(edge_hash, NULL, NULL);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 335d8e6589e..f915a4b2e51 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -190,21 +190,21 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit)
return false;
}
-void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy)
+void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy)
{
bool sloppy = true;
bool selected = false;
BMFace *efa;
Image *ima;
- efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
+ efa = BM_mesh_active_face_get(bm, sloppy, selected);
if (efa) {
if (BKE_scene_use_new_shading_nodes(scene)) {
ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
}
else {
- MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ MTexPoly *tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
ima = tf->tpage;
}
@@ -247,11 +247,10 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no);
}
-static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh *em,
+static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
const bool implicit, const bool fill, const bool sel,
const bool correct_aspect)
{
- BMesh *bm = em->bm;
ParamHandle *handle;
BMFace *efa;
BMLoop *l;
@@ -262,20 +261,19 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh
handle = param_construct_begin();
-
if (correct_aspect) {
float aspx, aspy;
- uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
if (aspx != aspy)
param_aspect_ratio(handle, aspx, aspy);
}
/* we need the vert indices */
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
continue;
@@ -299,7 +297,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh
}
if (!implicit) {
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
ParamKey vkeys[2];
vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
@@ -378,7 +376,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
if (correct_aspect) {
float aspx, aspy;
- uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
if (aspx != aspy)
param_aspect_ratio(handle, aspx, aspy);
@@ -522,7 +520,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
ms->blend = RNA_float_get(op->ptr, "blend");
ms->iterations = RNA_int_get(op->ptr, "iterations");
ms->i = 0;
- ms->handle = construct_param_handle(scene, obedit, em, implicit, fill_holes, 1, 1);
+ ms->handle = construct_param_handle(scene, obedit, em->bm, implicit, fill_holes, 1, 1);
ms->lasttime = PIL_check_seconds_timer();
param_stretch_begin(ms->handle);
@@ -683,7 +681,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* identifiers */
ot->name = "Minimize Stretch";
ot->idname = "UV_OT_minimize_stretch";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
ot->description = "Reduce UV stretching by relaxing angles";
/* api callbacks */
@@ -701,16 +699,23 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* ******************** Pack Islands operator **************** */
+void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
+{
+ ParamHandle *handle;
+ handle = construct_param_handle(scene, ob, bm, true, false, selected, correct_aspect);
+ param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
+ param_flush(handle);
+ param_delete(handle);
+}
+
static int pack_islands_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- ParamHandle *handle;
- bool implicit = true;
bool do_rotate = RNA_boolean_get(op->ptr, "rotate");
- if (!uvedit_have_selection(scene, em, implicit)) {
+ if (!uvedit_have_selection(scene, em, true)) {
return OPERATOR_CANCELLED;
}
@@ -719,10 +724,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
else
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
- handle = construct_param_handle(scene, obedit, em, implicit, 0, 1, 1);
- param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
- param_flush(handle);
- param_delete(handle);
+ ED_uvedit_pack_islands(scene, obedit, em->bm, true, true, do_rotate);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -762,7 +764,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- handle = construct_param_handle(scene, obedit, em, implicit, 0, 1, 1);
+ handle = construct_param_handle(scene, obedit, em->bm, implicit, 0, 1, 1);
param_average(handle);
param_flush(handle);
param_delete(handle);
@@ -807,7 +809,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
if (use_subsurf)
liveHandle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true);
else
- liveHandle = construct_param_handle(scene, obedit, em, false, fillholes, false, true);
+ liveHandle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true);
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
}
@@ -1008,7 +1010,7 @@ static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
if (aspx == aspy)
return;
@@ -1072,7 +1074,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
if (scale_to_bounds) {
INIT_MINMAX2(min, max);
-
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
@@ -1082,7 +1084,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
minmax_v2v2_v2(min, max, luv->uv);
}
}
-
+
/* rescale UV to be in 1/1 */
dx = (max[0] - min[0]);
dy = (max[1] - min[1]);
@@ -1098,7 +1100,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
+
luv->uv[0] = (luv->uv[0] - min[0]) * dx;
luv->uv[1] = (luv->uv[1] - min[1]) * dy;
}
@@ -1128,7 +1130,7 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
ParamHandle *handle;
const bool fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
- const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) != 0;
+ const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0;
bool use_subsurf;
modifier_unwrap_state(obedit, scene, &use_subsurf);
@@ -1136,7 +1138,7 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
if (use_subsurf)
handle = construct_param_handle_subsurfed(scene, obedit, em, fill_holes, sel, correct_aspect);
else
- handle = construct_param_handle(scene, obedit, em, false, fill_holes, sel, correct_aspect);
+ handle = construct_param_handle(scene, obedit, em->bm, false, fill_holes, sel, correct_aspect);
param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
param_lscm_solve(handle);
@@ -1599,39 +1601,30 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
/******************* Cube Project operator ****************/
-static int cube_project_exec(bContext *C, wmOperator *op)
+void ED_uvedit_unwrap_cube_project(Object *ob, BMesh *bm, float cube_size, bool use_select)
{
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
/* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
- float cube_size, *loc, dx, dy;
+ float *loc, dx, dy;
int cox, coy;
int cd_loop_uv_offset;
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- loc = obedit->obmat[3];
- cube_size = RNA_float_get(op->ptr, "cube_size");
+ loc = ob->obmat[3];
/* choose x,y,z axis for projection depending on the largest normal
* component, but clusters all together around the center of map. */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
int first = 1;
/* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
axis_dominant_v3(&cox, &coy, efa->no);
@@ -1642,19 +1635,34 @@ static int cube_project_exec(bContext *C, wmOperator *op)
luv->uv[0] = 0.5f + 0.5f * cube_size * (loc[cox] + l->v->co[cox]);
luv->uv[1] = 0.5f + 0.5f * cube_size * (loc[coy] + l->v->co[coy]);
-
+
if (first) {
dx = floor(luv->uv[0]);
dy = floor(luv->uv[1]);
first = 0;
}
-
+
luv->uv[0] -= dx;
luv->uv[1] -= dy;
}
}
+}
+
+static int cube_project_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ float cube_size = RNA_float_get(op->ptr, "cube_size");
+
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_uvedit_unwrap_cube_project(obedit, em->bm, cube_size, true);
uv_map_clip_correct(scene, obedit, em, op);
DAG_id_tag_update(obedit->data, 0);