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:
authorLukas Tönne <lukas.toenne@gmail.com>2015-01-16 14:50:11 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2015-01-16 14:50:11 +0300
commit6cd3ebfc9fa4838a74192f2e5cc82b5d5d2e6fe7 (patch)
tree546c8e187f3b5185f019153ee083fa246b698436 /source/blender/editors
parent97a50e78ca88b4ffe180bc6567e5ed0358239efe (diff)
parent5684ad80723454f0d910aad3fa48240da19c4e3b (diff)
Merge branch 'master' into alembic_pointcache
Conflicts: release/scripts/addons source/blender/blenkernel/intern/pointcache.c source/blender/blenloader/intern/versioning_270.c source/blender/editors/space_outliner/outliner_draw.c source/blender/makesdna/DNA_modifier_types.h source/blender/makesrna/intern/rna_modifier.c source/blender/modifiers/MOD_modifiertypes.h source/blender/modifiers/intern/MOD_collision.c source/blender/modifiers/intern/MOD_util.c
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c133
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c256
-rw-r--r--source/blender/editors/animation/anim_deps.c2
-rw-r--r--source/blender/editors/animation/anim_draw.c1
-rw-r--r--source/blender/editors/animation/anim_filter.c122
-rw-r--r--source/blender/editors/animation/anim_ops.c69
-rw-r--r--source/blender/editors/animation/drivers.c6
-rw-r--r--source/blender/editors/animation/keyframes_draw.c35
-rw-r--r--source/blender/editors/animation/keyframes_edit.c42
-rw-r--r--source/blender/editors/animation/keyframes_general.c124
-rw-r--r--source/blender/editors/animation/keyframing.c56
-rw-r--r--source/blender/editors/armature/armature_ops.c2
-rw-r--r--source/blender/editors/armature/armature_skinning.c12
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c2
-rw-r--r--source/blender/editors/armature/pose_group.c4
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_utils.c2
-rw-r--r--source/blender/editors/curve/curve_ops.c4
-rw-r--r--source/blender/editors/curve/editcurve.c3
-rw-r--r--source/blender/editors/curve/editfont.c10
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt3
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c851
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c59
-rw-r--r--source/blender/editors/gpencil/gpencil_buttons.c378
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1259
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h93
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c198
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c242
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c943
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c57
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c166
-rw-r--r--source/blender/editors/include/BIF_gl.h10
-rw-r--r--source/blender/editors/include/ED_anim_api.h3
-rw-r--r--source/blender/editors/include/ED_gpencil.h29
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h9
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h11
-rw-r--r--source/blender/editors/include/ED_keyframing.h2
-rw-r--r--source/blender/editors/include/ED_mesh.h8
-rw-r--r--source/blender/editors/include/ED_object.h6
-rw-r--r--source/blender/editors/include/ED_render.h6
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_sculpt.h3
-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.h2
-rw-r--r--source/blender/editors/include/ED_uvedit.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h2
-rw-r--r--source/blender/editors/include/UI_icons.h4
-rw-r--r--source/blender/editors/include/UI_interface.h56
-rw-r--r--source/blender/editors/include/UI_interface_icons.h4
-rw-r--r--source/blender/editors/include/UI_resources.h16
-rw-r--r--source/blender/editors/interface/CMakeLists.txt6
-rw-r--r--source/blender/editors/interface/SConscript4
-rw-r--r--source/blender/editors/interface/interface.c56
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_draw.c6
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c371
-rw-r--r--source/blender/editors/interface/interface_handlers.c181
-rw-r--r--source/blender/editors/interface/interface_icons.c46
-rw-r--r--source/blender/editors/interface/interface_intern.h9
-rw-r--r--source/blender/editors/interface/interface_layout.c34
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_panel.c12
-rw-r--r--source/blender/editors/interface/interface_regions.c6
-rw-r--r--source/blender/editors/interface/interface_style.c4
-rw-r--r--source/blender/editors/interface/interface_templates.c29
-rw-r--r--source/blender/editors/interface/interface_utils.c35
-rw-r--r--source/blender/editors/interface/interface_widgets.c114
-rw-r--r--source/blender/editors/interface/resources.c87
-rw-r--r--source/blender/editors/interface/view2d.c4
-rw-r--r--source/blender/editors/io/io_collada.c57
-rw-r--r--source/blender/editors/io/io_ops.c13
-rw-r--r--source/blender/editors/mask/mask_ops.c4
-rw-r--r--source/blender/editors/mask/mask_relationships.c1
-rw-r--r--source/blender/editors/mesh/editface.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c225
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c3
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c435
-rw-r--r--source/blender/editors/mesh/editmesh_path.c5
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c7
-rw-r--r--source/blender/editors/mesh/editmesh_select.c13
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
-rw-r--r--source/blender/editors/mesh/mesh_data.c22
-rw-r--r--source/blender/editors/metaball/mball_edit.c1
-rw-r--r--source/blender/editors/metaball/mball_ops.c4
-rw-r--r--source/blender/editors/object/CMakeLists.txt1
-rw-r--r--source/blender/editors/object/object_add.c89
-rw-r--r--source/blender/editors/object/object_bake.c3
-rw-r--r--source/blender/editors/object/object_bake_api.c7
-rw-r--r--source/blender/editors/object/object_data_transfer.c675
-rw-r--r--source/blender/editors/object/object_intern.h16
-rw-r--r--source/blender/editors/object/object_lod.c8
-rw-r--r--source/blender/editors/object/object_modifier.c15
-rw-r--r--source/blender/editors/object/object_ops.c9
-rw-r--r--source/blender/editors/object/object_relations.c1
-rw-r--r--source/blender/editors/object/object_shapekey.c7
-rw-r--r--source/blender/editors/object/object_transform.c3
-rw-r--r--source/blender/editors/object/object_vgroup.c1058
-rw-r--r--source/blender/editors/object/object_warp.c1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c5
-rw-r--r--source/blender/editors/physics/physics_fluid.c2
-rw-r--r--source/blender/editors/physics/physics_ops.c4
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c2
-rw-r--r--source/blender/editors/physics/rigidbody_object.c5
-rw-r--r--source/blender/editors/physics/rigidbody_world.c6
-rw-r--r--source/blender/editors/render/render_internal.c28
-rw-r--r--source/blender/editors/render/render_opengl.c13
-rw-r--r--source/blender/editors/render/render_preview.c37
-rw-r--r--source/blender/editors/render/render_shading.c9
-rw-r--r--source/blender/editors/render/render_update.c41
-rw-r--r--source/blender/editors/screen/area.c19
-rw-r--r--source/blender/editors/screen/glutil.c1
-rw-r--r--source/blender/editors/screen/screen_context.c117
-rw-r--r--source/blender/editors/screen/screen_edit.c31
-rw-r--r--source/blender/editors/screen/screen_ops.c20
-rw-r--r--source/blender/editors/screen/screendump.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c21
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c215
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c50
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c25
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c26
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c68
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c9
-rw-r--r--source/blender/editors/sound/sound_ops.c9
-rw-r--r--source/blender/editors/space_action/action_edit.c74
-rw-r--r--source/blender/editors/space_action/action_ops.c6
-rw-r--r--source/blender/editors/space_api/spacetypes.c7
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c6
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c5
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c19
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_ops.c1
-rw-r--r--source/blender/editors/space_clip/clip_draw.c3
-rw-r--r--source/blender/editors/space_clip/clip_editor.c1
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c11
-rw-r--r--source/blender/editors/space_clip/clip_utils.c4
-rw-r--r--source/blender/editors/space_clip/space_clip.c7
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c3
-rw-r--r--source/blender/editors/space_clip/tracking_select.c8
-rw-r--r--source/blender/editors/space_console/console_draw.c1
-rw-r--r--source/blender/editors/space_file/file_draw.c65
-rw-r--r--source/blender/editors/space_file/file_ops.c59
-rw-r--r--source/blender/editors/space_file/filelist.c966
-rw-r--r--source/blender/editors/space_file/filelist.h60
-rw-r--r--source/blender/editors/space_file/filesel.c36
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c63
-rw-r--r--source/blender/editors/space_graph/graph_edit.c15
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c205
-rw-r--r--source/blender/editors/space_graph/graph_select.c85
-rw-r--r--source/blender/editors/space_graph/graph_utils.c1
-rw-r--r--source/blender/editors/space_image/image_buttons.c14
-rw-r--r--source/blender/editors/space_image/image_draw.c15
-rw-r--r--source/blender/editors/space_image/image_ops.c44
-rw-r--r--source/blender/editors/space_image/space_image.c12
-rw-r--r--source/blender/editors/space_info/info_draw.c3
-rw-r--r--source/blender/editors/space_info/textview.c2
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c1
-rw-r--r--source/blender/editors/space_logic/logic_window.c6
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c1
-rw-r--r--source/blender/editors/space_nla/nla_channels.c1
-rw-r--r--source/blender/editors/space_nla/nla_draw.c3
-rw-r--r--source/blender/editors/space_nla/nla_edit.c19
-rw-r--r--source/blender/editors/space_nla/nla_intern.h2
-rw-r--r--source/blender/editors/space_nla/nla_ops.c4
-rw-r--r--source/blender/editors/space_nla/space_nla.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c4
-rw-r--r--source/blender/editors/space_node/node_add.c61
-rw-r--r--source/blender/editors/space_node/node_buttons.c11
-rw-r--r--source/blender/editors/space_node/node_draw.c8
-rw-r--r--source/blender/editors/space_node/node_edit.c46
-rw-r--r--source/blender/editors/space_node/node_group.c12
-rw-r--r--source/blender/editors/space_node/node_relationships.c14
-rw-r--r--source/blender/editors/space_node/node_templates.c2
-rw-r--r--source/blender/editors/space_node/node_toolbar.c9
-rw-r--r--source/blender/editors/space_node/space_node.c15
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c64
-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.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c7
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c430
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c163
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h21
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c172
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c32
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c9
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c14
-rw-r--r--source/blender/editors/space_text/text_draw.c51
-rw-r--r--source/blender/editors/space_text/text_header.c1
-rw-r--r--source/blender/editors/space_text/text_intern.h4
-rw-r--r--source/blender/editors/space_text/text_ops.c91
-rw-r--r--source/blender/editors/space_time/space_time.c15
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c2
-rw-r--r--source/blender/editors/space_userpref/userpref_ops.c1
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c1
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c1
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c109
-rw-r--r--source/blender/editors/space_view3d/drawobject.c34
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c5
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c420
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c181
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h4
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform.c54
-rw-r--r--source/blender/editors/transform/transform.h10
-rw-r--r--source/blender/editors/transform/transform_conversions.c391
-rw-r--r--source/blender/editors/transform/transform_generics.c28
-rw-r--r--source/blender/editors/transform/transform_ops.c25
-rw-r--r--source/blender/editors/transform/transform_orientations.c7
-rw-r--r--source/blender/editors/transform/transform_snap.c35
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/util/editmode_undo.c2
-rw-r--r--source/blender/editors/util/undo.c12
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h1
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c13
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c16
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c13
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c8
246 files changed, 9421 insertions, 5014 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index f384b2f372c..d76eba93640 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -2365,6 +2365,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 */
@@ -3162,6 +3239,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 */
@@ -3407,6 +3485,7 @@ 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)) {
@@ -3431,6 +3510,10 @@ 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 ............................................... */
@@ -3601,18 +3684,6 @@ 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)
{
@@ -3838,7 +3909,7 @@ 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);
View2D *v2d = &ac->ar->v2d;
@@ -3878,6 +3949,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,6 +3962,31 @@ 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... */
@@ -3912,8 +4009,14 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
&ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
- UI_but_func_set(but, achannel_setting_rename_done_cb, ac->ads, NULL);
- UI_but_active_only(C, ac->ar, block, but);
+
+ /* copy what outliner does here, see outliner_buttons */
+ if (UI_but_active_only(C, ac->ar, block, but) == false) {
+ ac->ads->renameIndex = 0;
+
+ /* send notifiers */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
+ }
UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index b6ab0407711..d8ad6506186 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -129,6 +129,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 +137,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;
+ }
}
}
@@ -176,6 +184,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 +193,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:
@@ -268,6 +283,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;
@@ -361,6 +377,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) {
@@ -843,6 +860,13 @@ 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);
return;
@@ -1167,6 +1191,47 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
/* ------------------- */
+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 +1247,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 */
@@ -1585,175 +1650,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 */
@@ -2334,7 +2230,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);
@@ -2736,6 +2632,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) {
@@ -2897,7 +2794,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:
@@ -3042,9 +2945,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);
@@ -3110,10 +3010,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..eb57907c9ec 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -92,7 +92,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 807e1322595..2d7656642d3 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -41,7 +41,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
-#include "BKE_object.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index cedaea716e3..d6daa64a9f2 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -771,6 +771,21 @@ 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_GROUP:
{
bActionGroup *agrp = (bActionGroup *)data;
@@ -1413,27 +1428,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 +1764,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 +1981,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;
@@ -2215,6 +2290,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 +2337,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))
@@ -2349,6 +2429,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 +2452,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;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 0f202003dd8..cbcbc8743f1 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,9 +94,15 @@ 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;
@@ -136,6 +144,25 @@ 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);
+ 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);
+ }
+ }
+}
+static void change_frame_seq_preview_end(bContext *C)
+{
+ if (ED_sequencer_special_preview_get() != NULL) {
+ Scene *scene = CTX_data_scene(C);
+ ED_sequencer_special_preview_clear();
+ 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 +171,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 +182,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 +209,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,6 +242,7 @@ 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;
@@ -198,6 +251,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
/* 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 7bdc49da54e..5799101a7db 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -39,18 +39,12 @@
#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_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
-#include "BKE_material.h"
-#include "BKE_texture.h"
#include "ED_keyframing.h"
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index c5e54cc1c7c..d2dbe961b42 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"
@@ -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;
}
/* ......... */
@@ -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 7f612de14b7..439b3b94974 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"
@@ -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;
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 6e59bb9f463..7ac11c1cd06 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"
@@ -478,6 +479,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,6 +543,31 @@ 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;
+ char *str_start;
+
+ if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
+ bPoseChannel *pchan;
+ int length = 0;
+ char *str_end;
+
+ str_start += 12;
+ str_end = strchr(str_start, '\"');
+ length = str_end - str_start;
+ str_start[length] = 0;
+ pchan = BKE_pose_channel_find_name(ob->pose, str_start);
+ str_start[length] = '\"';
+
+ if (pchan) {
+ aci->is_bone = true;
+ }
+ }
+ }
+
BLI_addtail(&animcopybuf, aci);
/* add selected keyframes to buffer */
@@ -588,19 +615,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 (strcmp(name, fcu->rna_path) == 0) {
+ MEM_freeN(name);
+ break;
+ }
+ MEM_freeN(name);
+ }
+ }
+ else if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) {
+ if ((from_single) || (aci->array_index == fcu->array_index)) {
break;
+ }
}
}
}
@@ -671,8 +744,30 @@ 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;
@@ -727,6 +822,9 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
/* 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 +832,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);
+ 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 +871,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 +919,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
@@ -840,7 +942,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
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,7 +959,7 @@ 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);
+ 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 2c66d92ab58..7e2ce4cd3f1 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -658,7 +658,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 +880,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 +888,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 +907,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 +956,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 +1284,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 ------------------------ */
@@ -1922,17 +1922,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 +1952,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 +1965,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 +1981,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 +1994,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,7 +2007,7 @@ 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)) {
@@ -2018,7 +2018,7 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
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 1;
+ return true;
}
/* try shapekey keyframes (if available, and allowed by filter) */
@@ -2031,7 +2031,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) */
@@ -2045,7 +2045,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;
@@ -2055,13 +2055,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 ------------------- */
@@ -2071,7 +2071,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)) {
@@ -2095,7 +2095,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/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index b7e38546ca2..574258de4f6 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"
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 15f75ada060..3126cca7457 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;
}
}
@@ -164,7 +168,7 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
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);
+ defgroup = BKE_object_defgroup_add_name(ob, bone->name);
if (data->list != NULL) {
hgroup = (bDeformGroup ***) &data->list;
@@ -276,7 +280,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
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 912fbc36d5d..3dbf7b4b65a 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"
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 9c27fe5218a..413a74d24b5 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -365,8 +365,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);
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 15e70980425..2e6eace88aa 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -916,7 +916,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) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 380a3fffc6d..1297755b7d0 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"
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index f1b34182439..0f42dc923a4 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"
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index d1208b8ba1c..99c64be5797 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -85,6 +85,7 @@ typedef struct {
GHash *undoIndex;
ListBase fcurves, drivers;
int actnu;
+ int flag;
} UndoCurve;
/* Definitions needed for shape keys */
@@ -6880,6 +6881,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);
}
@@ -6919,6 +6921,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/editfont.c b/source/blender/editors/curve/editfont.c
index 108166109b8..8393acc6919 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -500,7 +500,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
}
@@ -558,7 +558,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
}
@@ -1835,7 +1835,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_FTFONT, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
}
@@ -1884,8 +1884,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/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 5dc9679777f..58192f59219 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -39,11 +39,12 @@ set(INC_SYS
set(SRC
drawgpencil.c
editaction_gpencil.c
- gpencil_buttons.c
gpencil_edit.c
gpencil_ops.c
gpencil_paint.c
+ gpencil_select.c
gpencil_undo.c
+ gpencil_utils.c
gpencil_intern.h
)
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 5a838d7bc39..895fc6608e2 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>
@@ -58,6 +59,8 @@
#include "ED_gpencil.h"
#include "ED_view3d.h"
+#include "UI_resources.h"
+
#include "gpencil_intern.h"
/* ************************************************** */
@@ -73,6 +76,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,10 +117,10 @@ 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);
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)
@@ -126,7 +132,7 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
/* 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,14 +142,221 @@ 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) */
@@ -160,18 +373,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 +387,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);
+ gluDisk(qobj, 0.0, thickness, 32, 1);
glTranslatef(-co[0], -co[1], 0.0);
gluDeleteQuadric(qobj);
@@ -200,7 +402,7 @@ 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;
@@ -231,8 +433,9 @@ 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) {
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
@@ -244,46 +447,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 +478,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 +489,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 +534,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 +564,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 +582,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;
@@ -448,52 +613,57 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
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 +685,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 +720,302 @@ 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 int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ 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;
- /* loop over layers, drawing them */
+ /* 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();
+
+
+ /* 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, short 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 */
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 +1023,83 @@ 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 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);
+
+ glEnable(GL_POLYGON_SMOOTH);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+
+ /* turn on alpha-blending */
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 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
-
+ glDisable(GL_POLYGON_SMOOTH); // smooth poly 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 +1126,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 +1147,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 +1165,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 +1191,10 @@ 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 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 +1203,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);
@@ -795,15 +1228,15 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
/* 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);
}
-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..97adaea41a8 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;
@@ -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 a7635c12d56..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);
- UI_block_func_set(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... */
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
- /* 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, UI_BTYPE_TOGGLE, 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"));
- UI_but_func_set(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, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete layer"));
- UI_but_func_set(but, gp_ui_dellayer_cb, gpd, gpl);
- }
- UI_block_emboss_set(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);
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
- /* name */
- uiItemR(sub, &ptr, "info", 0, "", ICON_NONE);
-
- /* move up/down */
- UI_block_align_begin(block);
-
- if (gpl->prev) {
- but = uiDefIconBut(block, UI_BTYPE_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"));
- UI_but_func_set(but, gp_ui_layer_up_cb, gpd, gpl);
- }
- if (gpl->next) {
- but = uiDefIconBut(block, UI_BTYPE_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"));
- UI_but_func_set(but, gp_ui_layer_down_cb, gpd, gpl);
- }
-
- UI_block_align_end(block);
-
- /* delete 'button' */
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- /* right-align ............................... */
- sub = uiLayoutRow(row, true);
- uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- block = uiLayoutGetBlock(sub); /* XXX... err... */
-
- but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete layer"));
- UI_but_func_set(but, gp_ui_dellayer_cb, gpd, gpl);
- UI_block_emboss_set(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_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 13334448941..3dae25263e8 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -27,6 +27,7 @@
* \ingroup edgpencil
*/
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -86,50 +87,59 @@
/* ************************************************ */
/* Context Wrangling... */
-/* 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)
+/* 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)
{
- 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) {
+ 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 */
{
- 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;
+ 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 *)CTX_wm_space_data(C);
-
+ 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 *)CTX_wm_space_data(C);
-
+ 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);
@@ -137,8 +147,8 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
}
case SPACE_IMAGE: /* Image/UV Editor */
{
- SpaceImage *sima = (SpaceImage *)CTX_wm_space_data(C);
-
+ 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);
@@ -146,25 +156,25 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
}
case SPACE_CLIP: /* Nodes Editor */
{
- SpaceClip *sc = (SpaceClip *)CTX_wm_space_data(C);
+ 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;
}
}
@@ -174,12 +184,32 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
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)
{
@@ -187,6 +217,9 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
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;
@@ -194,7 +227,7 @@ bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
/* 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;
}
@@ -211,13 +244,22 @@ static int gp_add_poll(bContext *C)
return ED_gpencil_data_get_pointers(C, NULL) != NULL;
}
+/* poll callback for checking if there is an active layer */
+static int gp_active_layer_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ return (gpl != NULL);
+}
+
/* ******************* 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;
@@ -225,14 +267,14 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
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;
}
@@ -243,7 +285,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
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;
@@ -255,7 +297,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
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);
}
@@ -265,7 +307,7 @@ static int gp_data_unlink_poll(bContext *C)
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;
@@ -277,10 +319,10 @@ static int gp_data_unlink_exec(bContext *C, wmOperator *op)
id_us_min(&gpd->id);
*gpd_ptr = NULL;
}
-
+
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
return OPERATOR_FINISHED;
}
@@ -291,7 +333,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
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;
@@ -303,7 +345,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
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");
@@ -311,13 +353,13 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
}
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;
}
@@ -327,20 +369,497 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
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;
+}
+
+/* ************************************************ */
+/* Stroke Editing Operators */
+
+/* poll callback for all stroke editing operators */
+static int gp_stroke_edit_poll(bContext *C)
+{
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+}
+
+/* ************** Duplicate Selected Strokes **************** */
+
+/* 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;
+ }
+ }
+ 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;
+ }
+ else if (i == gps->totpoints - 1) {
+ len = i - start_idx + 1;
+ }
+ //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;
+ }
+ }
+ }
+}
+
+static int gp_duplicate_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;
+ }
+
+ /* 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) {
+ 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);
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Strokes";
+ ot->idname = "GPENCIL_OT_duplicate";
+ ot->description = "Duplicate the selected Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gp_duplicate_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* 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.
+ */
+
+/* list of bGPDstroke instances */
+static ListBase gp_strokes_copypastebuf = {NULL, NULL};
+
+/* 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);
+ }
+
+ gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
+}
+
+/* --------------------- */
+/* Copy selected strokes */
+
+static int gp_strokes_copy_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;
+ }
+
+ /* 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) {
+ 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);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* done - no updates needed */
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Strokes";
+ ot->idname = "GPENCIL_OT_copy";
+ ot->description = "Copy selected Grease Pencil points and strokes";
+
+ /* callbacks */
+ ot->exec = gp_strokes_copy_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ //ot->flag = OPTYPE_REGISTER;
+}
+
+/* --------------------- */
+/* Paste selected strokes */
+
+static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
+{
+ 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;
+ }
+ 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;
+ }
+
+ /* 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) {
+ 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_paste(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Paste Strokes";
+ ot->idname = "GPENCIL_OT_paste";
+ ot->description = "Paste previously copied strokes into active layer";
+
+ /* callbacks */
+ ot->exec = gp_strokes_paste_exec;
+ ot->poll = gp_stroke_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ******************* Delete Active Frame ************************ */
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 +871,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 +881,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,13 +897,315 @@ 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;
}
+/* ******************* Delete Operator ************************ */
+
+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,
+ /* delete selected stroke points (without splitting stroke) */
+ GP_DELETEOP_POINTS_DISSOLVE = 3,
+} eGP_DeleteMode;
+
+
+/* Delete selected strokes */
+static int gp_delete_selected_strokes(bContext *C)
+{
+ 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;
+
+ 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 {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Delete selected points but keep the stroke */
+static int gp_dissolve_selected_points(bContext *C)
+{
+ 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;
+
+ 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--;
+ }
+ }
+
+ /* 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);
+ }
+ 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;
+ }
+
+ changed = true;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Split selected strokes into segments, splitting on selected points */
+static int gp_delete_selected_points(bContext *C)
+{
+ 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;
+
+ 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;
+ }
+ }
+ }
+
+ /* 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);
+ }
+ }
+ }
+
+ /* free islands */
+ MEM_freeN(islands);
+
+ /* Delete the old stroke */
+ 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 {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+
+static int gp_delete_exec(bContext *C, wmOperator *op)
+{
+ 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;
+
+ case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
+ result = gp_delete_selected_points(C);
+ break;
+
+ case GP_DELETEOP_POINTS_DISSOLVE: /* selected points (without splitting the stroke) */
+ result = gp_dissolve_selected_points(C);
+ break;
+
+ case GP_DELETEOP_FRAME: /* active frame */
+ result = gp_actframe_delete_exec(C, op);
+ break;
+ }
+
+ return result;
+}
+
+void GPENCIL_OT_delete(wmOperatorType *ot)
+{
+ 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, "", 0, NULL, NULL},
+ {GP_DELETEOP_POINTS_DISSOLVE, "DISSOLVE_POINTS", 0, "Dissolve Points",
+ "Delete selected points without splitting strokes"},
+ {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");
+}
+
/* ************************************************ */
/* Grease Pencil to Data Operator */
@@ -437,7 +1258,7 @@ static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRN
/* --- */
-/* convert the coordinates from the given stroke point into 3d-coordinates
+/* 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)
@@ -445,7 +1266,7 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin
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);
@@ -453,7 +1274,7 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin
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;
@@ -469,7 +1290,7 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin
mvalf[1] = (float)pt->y / 100.0f * ar->winy;
}
}
-
+
ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
}
}
@@ -485,19 +1306,19 @@ typedef struct tGpTimingData {
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;
@@ -508,9 +1329,9 @@ typedef struct tGpTimingData {
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__);
@@ -518,7 +1339,7 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
MEM_freeN(tmp);
}
-
+
/* times */
tmp = gtd->times;
gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
@@ -526,7 +1347,7 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
MEM_freeN(tmp);
}
-
+
gtd->num_points = nbr;
}
@@ -536,7 +1357,7 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini
{
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;
@@ -546,18 +1367,18 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini
/* 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++;
}
@@ -572,7 +1393,7 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx
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];
@@ -591,16 +1412,16 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx
}
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);
@@ -615,7 +1436,7 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx
break;
}
}
-
+
return j - 1;
}
@@ -623,7 +1444,7 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn
{
int i;
float delta_time = 0.0f;
-
+
for (i = 0; i < gtd->num_points; i++) {
if (gtd->times[i] < 0 && i) {
(*nbr_gaps)++;
@@ -636,7 +1457,7 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn
}
}
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) {
@@ -653,18 +1474,18 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
{
/* 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!
@@ -680,11 +1501,11 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
/* 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
@@ -735,43 +1556,43 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
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 */
@@ -785,35 +1606,35 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
/* 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++) {
@@ -821,9 +1642,9 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
}
printf("\n\n");
}
-
+
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
+
/* send updates */
DAG_id_tag_update(&cu->id, 0);
}
@@ -843,7 +1664,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl
{
copy_v3_v3(bp->vec, p);
bp->vec[3] = 1.0f;
-
+
/* set settings */
bp->f1 = SELECT;
bp->radius = width * rad_fac;
@@ -855,7 +1676,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl
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));
@@ -872,7 +1693,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
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;
@@ -884,7 +1705,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
}
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! */
@@ -893,16 +1714,16 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
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
@@ -915,16 +1736,16 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
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) {
@@ -943,7 +1764,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
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) {
@@ -961,13 +1782,13 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
}
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);
@@ -985,14 +1806,14 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
* 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;
@@ -1000,20 +1821,20 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
{
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) {
@@ -1029,7 +1850,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
/* 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);
@@ -1037,7 +1858,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
if (curnu) {
*curnu = nu;
}
-
+
BKE_nurb_knot_calc_u(nu);
}
@@ -1052,7 +1873,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
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;
@@ -1065,7 +1886,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
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));
@@ -1073,8 +1894,8 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
}
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)
+ 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;
@@ -1083,7 +1904,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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;
@@ -1095,22 +1916,22 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
}
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) {
@@ -1122,11 +1943,11 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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];
@@ -1134,7 +1955,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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
@@ -1147,14 +1968,14 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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);
@@ -1169,7 +1990,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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) {
@@ -1184,25 +2005,25 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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);
}
@@ -1210,7 +2031,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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) {
@@ -1227,51 +2048,51 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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) {
@@ -1284,11 +2105,11 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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);
@@ -1296,10 +2117,10 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
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);
}
@@ -1329,7 +2150,7 @@ static void gp_stroke_finalize_curve_endpoints(Curve *cu)
bp[i].weight = bp[i].radius = 0.0f;
}
}
-
+
/* end */
nu = cu->nurb.last;
i = nu->pntsu - 1;
@@ -1353,13 +2174,13 @@ static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2
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;
@@ -1380,10 +2201,10 @@ 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);
@@ -1391,7 +2212,7 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect)
return 1;
}
}
-
+
return 0;
}
@@ -1409,57 +2230,57 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
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:
+ 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;
@@ -1474,26 +2295,26 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
}
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;
@@ -1513,17 +2334,17 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe
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;
@@ -1536,12 +2357,12 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe
}
prev_time = cur_time;
}
-
+
if (!valid) {
break;
}
} while ((gps = gps->next));
-
+
if (op) {
RNA_boolean_set(op->ptr, "use_timing_data", valid);
}
@@ -1553,7 +2374,7 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN
{
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);
}
@@ -1566,7 +2387,7 @@ static int gp_convert_poll(bContext *C)
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!
*/
@@ -1589,19 +2410,19 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
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)) {
@@ -1611,7 +2432,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
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");
@@ -1626,10 +2447,10 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
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);
@@ -1639,11 +2460,11 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
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;
}
@@ -1657,7 +2478,7 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
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 ||
@@ -1666,16 +2487,16 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
{
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 ||
@@ -1683,31 +2504,31 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
{
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;
}
@@ -1717,9 +2538,9 @@ 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');
}
@@ -1727,35 +2548,35 @@ static void gp_convert_ui(bContext *C, wmOperator *op)
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",
@@ -1765,7 +2586,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot)
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);
@@ -1773,7 +2594,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot)
"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)");
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 28eb1355caf..56420434494 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -31,15 +31,74 @@
#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);
+
+/* ***************************************************** */
+/* Operator Defines */
+
/* drawing ---------- */
void GPENCIL_OT_draw(struct wmOperatorType *ot);
@@ -52,12 +111,32 @@ 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_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_active_frame_delete(struct wmOperatorType *ot);
@@ -76,17 +155,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..6bba7d4f17d 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -36,40 +36,189 @@
#include "BLI_blenlib.h"
+#include "BKE_context.h"
+
+#include "DNA_gpencil_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
#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 */
+ 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_item(keymap, "GPENCIL_OT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_delete", DELKEY, KM_PRESS, 0, 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
+
+ /* 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);
+
+ /* 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 +229,51 @@ 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_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_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 7c1976df3e0..e6f6644fd24 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>
@@ -86,11 +87,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,7 +113,7 @@ 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];
@@ -219,7 +222,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);
@@ -244,13 +247,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
*/
@@ -280,7 +283,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.
@@ -292,7 +295,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);
@@ -328,7 +331,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 */
@@ -345,7 +348,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
gpd->sbuffer_size++;
}
else {
- /* normally, we just reset the endpoint to the latest value
+ /* normally, we just reset the endpoint to the latest value
* - assume that pointers for this are always valid...
*/
pt = ((tGPspoint *)(gpd->sbuffer) + 1);
@@ -439,7 +442,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;
}
@@ -459,12 +462,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;
@@ -483,7 +486,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)
*/
@@ -503,7 +506,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
*/
@@ -570,7 +573,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)
@@ -626,7 +629,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt++;
}
-
+
if (totelem == 2) {
/* last point if applicable */
ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
@@ -747,7 +750,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;
}
@@ -853,8 +856,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))
@@ -862,11 +864,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;
}
@@ -875,58 +877,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(tGPsdata *p, bGPDstroke *gps, bGPDspoint *pt,
- int *r_x, int *r_y)
-{
- ARegion *ar = p->ar;
- View2D *v2d = p->v2d;
- rctf *subrect = p->subrect;
- 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) {
- float vec[3] = {pt->x, pt->y, 0.0f};
- mul_m4_v3(p->mat, vec);
- UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], 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?) */
@@ -940,12 +890,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, 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)) {
@@ -958,7 +908,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++) {
@@ -966,8 +916,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
- gp_point_to_xy(p, gps, pt1, &x0, &y0);
- gp_point_to_xy(p, 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)) ||
@@ -977,7 +927,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))
{
@@ -1003,16 +953,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;
@@ -1043,7 +993,7 @@ static void gp_session_validatebuffer(tGPsdata *p)
/* reset flags */
gpd->sbuffer_sflag = 0;
-
+
/* reset inittime */
p->inittime = 0.0;
}
@@ -1066,8 +1016,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 */
@@ -1076,7 +1027,7 @@ 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)
*/
p->sa = curarea;
@@ -1154,7 +1105,9 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
p->imat[3][0] -= marker->pos[0];
p->imat[3][1] -= marker->pos[1];
}
+
invert_m4_m4(p->mat, p->imat);
+ copy_m4_m4(p->gsc.mat, p->mat);
break;
}
/* unsupported views */
@@ -1199,10 +1152,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 */
@@ -1233,7 +1186,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) {
@@ -1248,7 +1201,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) {
@@ -1264,7 +1217,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) {
@@ -1272,11 +1225,11 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
}
}
}
-
+
/* 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 */
if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) {
if (p->sa->spacetype == SPACE_VIEW3D) {
@@ -1290,7 +1243,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) {
@@ -1340,7 +1307,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)) {
@@ -1395,13 +1362,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);
@@ -1419,7 +1391,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
}
else if (enable) {
/* 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);
}
@@ -1526,13 +1498,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 */
@@ -1626,15 +1598,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;
@@ -1651,6 +1614,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));
+
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
@@ -1721,7 +1693,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
gpencil_draw_apply(op, p);
}
RNA_END;
-
+
/* printf("\tGP - done\n"); */
/* cleanup */
@@ -1747,7 +1719,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* 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");
@@ -1755,12 +1727,12 @@ 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);
@@ -1772,11 +1744,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
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.
- */
- if (event->val == KM_PRESS) {
+ /* 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;
@@ -1833,15 +1802,15 @@ 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;
-
+
p->gpd = NULL;
p->gpl = NULL;
p->gpf = NULL;
@@ -1865,11 +1834,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* better in tools that immediately apply
* in 3D space.
*/
-
+
/* 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;
@@ -1878,7 +1850,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)) {
@@ -1888,7 +1860,7 @@ 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])
@@ -1898,7 +1870,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
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);
@@ -1967,12 +1939,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;
}
@@ -1983,7 +1955,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 {
@@ -2006,7 +1978,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;
@@ -2053,6 +2025,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..7967d6a4d95
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -0,0 +1,943 @@
+/*
+ * ***** 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_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_lasso.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_curve.h"
+#include "BKE_depsgraph.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 "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+#include "ED_keyframing.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;
+
+ 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 location[2] = {0};
+ int mx, my;
+
+ GP_SpaceConversion gsc = {NULL};
+
+ bGPDstroke *hit_stroke = NULL;
+ bGPDspoint *hit_point = NULL;
+
+ /* 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", location);
+
+ mx = location[0];
+ my = location[1];
+
+ /* 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;
+ int hit_index = -1;
+
+ /* firstly, check for hit-point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ int x0, y0;
+
+ gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
+
+ /* do boundbox check first */
+ if (!ELEM(V2D_IS_CLIPPED, x0, x0)) {
+ /* only check if point is inside */
+ if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius_squared) {
+ hit_stroke = gps;
+ hit_point = pt;
+ break;
+ }
+ }
+ }
+
+ /* skip to next stroke if nothing found */
+ if (hit_index == -1)
+ continue;
+ }
+ 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..5f0647fb43d 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,9 +70,9 @@ 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) {
@@ -90,18 +91,18 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
}
}
}
-
+
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..4a913c3d2e5
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_utils.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, 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 "MEM_guardedalloc.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_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 "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+
+#include "gpencil_intern.h"
+
+/* ******************************************************** */
+
+/* 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;
+}
+
+/* ******************************************************** */
+
+/* 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 */
+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];
+
+ 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 */
+ *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 2acba04368c..b06af01bab6 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -56,14 +56,20 @@ void cpack(unsigned int x);
# 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))
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 956ec308daa..50581429700 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -159,6 +159,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSLAT,
ANIMTYPE_DSLINESTYLE,
ANIMTYPE_DSSPK,
+ ANIMTYPE_DSGPENCIL,
ANIMTYPE_SHAPEKEY,
@@ -457,7 +458,7 @@ 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);
/* 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 -------------------------- */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 05fb76b7aea..b0d1be1bf5d 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,6 +30,7 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
+struct ID;
struct ListBase;
struct bContext;
struct bScreen;
@@ -38,11 +39,11 @@ struct ARegion;
struct View3D;
struct SpaceNode;
struct SpaceSeq;
+struct Object;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct PointerRNA;
-struct Panel;
struct ImBuf;
struct wmKeyConfig;
@@ -65,14 +66,32 @@ 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);
/* ----------- 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 +99,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 +116,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 a9995de068e..1188ecd0aa5 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -79,5 +79,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..0359153317b 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -120,8 +120,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 +140,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 197191b4f96..adf82acb399 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -58,6 +58,7 @@ typedef enum eEditKeyframes_Validate {
BEZT_OK_VALUERANGE,
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
+ BEZT_OK_REGION_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -107,6 +108,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) */
@@ -261,7 +270,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..e5b5e79875d 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -293,7 +293,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_mesh.h b/source/blender/editors/include/ED_mesh.h
index 2b4fa1b9196..8eb7fdf0c40 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -220,14 +220,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);
@@ -244,8 +238,6 @@ void ED_vgroup_mirror(struct Object *ob,
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);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 39586039e8f..900da3ee07c 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -209,12 +209,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_render.h b/source/blender/editors/include/ED_render.h
index ab1dbabe793..de3843c91eb 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -40,6 +40,7 @@ struct ScrArea;
struct RegionView3D;
struct RenderEngine;
struct View3D;
+struct wmWindowManager;
/* render_ops.c */
@@ -52,7 +53,7 @@ void ED_render_engine_changed(struct Main *bmain);
void ED_render_engine_area_exit(struct ScrArea *sa);
void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
-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 the preview
@@ -71,8 +72,9 @@ void ED_preview_init_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 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 ed2465647da..b790c656b61 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -107,6 +107,7 @@ 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_retore_temp_type(struct bContext *C, ScrArea *sa, bool is_screen_change);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 85ff9b5d246..d3b1a824104 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -34,6 +34,7 @@ struct ARegion;
struct bContext;
struct Object;
struct RegionView3D;
+struct Scene;
struct ViewContext;
struct rcti;
@@ -41,8 +42,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..cf848098188 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -99,6 +99,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)
@@ -146,6 +147,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_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index bf3b18e143e..3e8f234e979 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -94,6 +94,8 @@ 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);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index bd4f37cfb1e..76ad4ba7bdb 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -309,7 +309,7 @@ void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct AR
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]);
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]);
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]);
void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 618fa44349e..fa349c4f006 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -589,8 +589,8 @@ DEF_ICON(MOD_WARP)
DEF_ICON(MOD_SKIN)
DEF_ICON(MOD_TRIANGULATE)
DEF_ICON(MOD_WIREFRAME)
+DEF_ICON(MOD_DATA_TRANSFER)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK167)
DEF_ICON(BLANK168)
DEF_ICON(BLANK169)
DEF_ICON(BLANK170)
@@ -876,8 +876,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 d93872d81ff..8789e837f17 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -159,31 +159,32 @@ enum {
/* but->flag - general state flags. */
enum {
/* warning, the first 6 flags are internal */
- 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 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 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_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
};
#define UI_PANEL_WIDTH 340
@@ -266,12 +267,12 @@ typedef enum {
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_HSVCIRCLE = (43 << 9),
UI_BTYPE_HOTKEY_EVENT = (46 << 9),
UI_BTYPE_IMAGE = (47 << 9), /* non-interactive image, used for splash screen */
UI_BTYPE_HISTOGRAM = (48 << 9),
@@ -313,6 +314,7 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx,
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);
/* state for scrolldrawing */
#define UI_SCROLL_PRESSED (1 << 0)
@@ -945,6 +947,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 */
@@ -999,6 +1002,7 @@ 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);
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 6104505ef58..74927428363 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -33,6 +33,7 @@
#define __UI_INTERFACE_ICONS_H__
struct bContext;
+struct ID;
struct Image;
struct ImBuf;
struct World;
@@ -63,6 +64,9 @@ 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);
+
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);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 8e37e871501..d289e90c257 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -111,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,
@@ -207,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,
@@ -266,7 +272,7 @@ enum {
TH_NLA_SOUND,
TH_NLA_SOUND_SEL,
- TH_EMBOSS,
+ TH_WIDGET_EMBOSS,
TH_AXIS_X, /* X/Y/Z Axis */
TH_AXIS_Y,
@@ -295,6 +301,11 @@ enum {
struct bTheme;
struct PointerRNA;
+struct bThemeState {
+ struct bTheme *theme;
+ int spacetype, regionid;
+};
+
// THE CODERS API FOR THEMES:
// sets the color
@@ -354,6 +365,9 @@ 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/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index b921d17104c..972eca747b9 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -71,6 +71,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 303ab7ff286..5af8bba5a9f 100644
--- a/source/blender/editors/interface/SConscript
+++ b/source/blender/editors/interface/SConscript
@@ -48,6 +48,10 @@ incs = [
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 93f5a8e58d6..0b1d1c8c30c 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -209,6 +209,11 @@ 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;
+}
/* ******************* block calc ************************* */
void ui_block_translate(uiBlock *block, int x, int y)
@@ -723,6 +728,10 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
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) {
@@ -1712,6 +1721,9 @@ bool ui_but_is_bool(const uiBut *but)
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;
}
@@ -2152,6 +2164,32 @@ bool ui_but_string_set_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_but_string_set(bContext *C, uiBut *but, const char *str)
{
@@ -2599,9 +2637,13 @@ void ui_but_update(uiBut *but)
UI_GET_BUT_VALUE_INIT(but, value);
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 UI_BTYPE_ICON_TOGGLE:
+ 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;
@@ -2631,7 +2673,9 @@ void ui_but_update(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);
}
}
}
@@ -3039,13 +3083,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;
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 7e7806f6ada..24a30ebe3d8 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -34,13 +34,11 @@
#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"
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 4dd952f0753..bcd9b9a5547 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -395,6 +395,12 @@ 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)
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 7fed3772389..d7a4720d595 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -40,6 +40,7 @@
#include "BKE_screen.h"
#include "BKE_report.h"
#include "BKE_idcode.h"
+#include "BKE_unit.h"
#include "RNA_access.h"
@@ -64,6 +65,42 @@
#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)
+{
+ int width;
+ 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_fontstyle_string_width(name);
+ x = x - ar->winrct.xmin;
+ y = y - ar->winrct.ymin;
+
+ y += 20;
+
+ glColor4ub(0, 0, 0, 50);
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
+ UI_draw_roundbox(x, y, x + width + 8, y + 15, 4);
+
+ glColor4ub(255, 255, 255, 255);
+ UI_draw_string(x + 4, y + 4, name);
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/* Eyedropper
@@ -328,7 +365,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;
@@ -369,31 +406,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_fontstyle_string_width(name);
- x = x - ar->winrct.xmin;
- y = y - ar->winrct.ymin;
-
- y += 20;
-
- glColor4ub(0, 0, 0, 50);
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
- UI_draw_roundbox(x, y, x + width + 8, y + 15, 4);
-
- glColor4ub(255, 255, 255, 255);
- UI_draw_string(x + 4, y + 4, name);
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
}
@@ -643,3 +656,309 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/* Depth Dropper
+ *
+ * note: depthdropper is only internal name to avoid confusion in this file
+ */
+
+/** \name Eyedropper (Depth)
+ * \{ */
+
+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->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;
+ 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';
+
+ 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)) {
+ 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));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ 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;
+ depth = ddr->accum_depth * 1.0f / (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;
+
+ /* properties */
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index c841370a8fd..98b065dabcf 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -87,6 +87,10 @@
#include "WM_api.h"
#include "WM_types.h"
+#ifdef WITH_INPUT_IME
+# include "wm_window.h"
+#endif
+
/* place the mouse at the scaled down location when un-grabbing */
#define USE_CONT_MOUSE_CORRECT
/* support dragging toggle buttons */
@@ -103,6 +107,9 @@
#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_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to);
static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to);
@@ -777,11 +784,18 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
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;
@@ -2425,8 +2439,52 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
return changed;
}
+#ifdef WITH_INPUT_IME
+/* 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);
+}
+
+/* should be ui_but_ime_data_get */
+wmIMEData *ui_but_get_ime_data(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;
if (data->str) {
@@ -2482,12 +2540,18 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
but->flag &= ~UI_BUT_REDALERT;
ui_but_update(but);
-
- WM_cursor_modal_set(CTX_wm_window(C), BC_TEXTEDITCURSOR);
+
+ WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+
+#ifdef WITH_INPUT_IME
+ 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_but_is_utf8(but)) {
int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
@@ -2518,7 +2582,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)
@@ -2583,6 +2653,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:
@@ -2603,6 +2681,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);
@@ -2660,7 +2744,7 @@ 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:
@@ -2776,7 +2860,15 @@ 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;
@@ -2806,10 +2898,30 @@ 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 */
@@ -3063,10 +3175,10 @@ 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_but_contains_point_px(but->active->region, but, event->x, event->y) == 0) {
@@ -5694,6 +5806,10 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
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);
@@ -5734,7 +5850,10 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
UI_block_bounds_set_popup(block, 6, -50, 26);
-
+
+#ifdef USE_KEYMAP_ADD_HACK
+ g_kmi_id_hack = kmi_id;
+#endif
return block;
}
@@ -5743,9 +5862,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);
}
@@ -6161,6 +6291,16 @@ 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 */
@@ -6256,6 +6396,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
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 UI_BTYPE_SCROLL:
@@ -6278,7 +6419,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
break;
case UI_BTYPE_ROUNDBOX:
case UI_BTYPE_LABEL:
- case UI_BTYPE_ROW:
case UI_BTYPE_IMAGE:
case UI_BTYPE_PROGRESS_BAR:
case UI_BTYPE_NODE_SOCKET:
@@ -9087,6 +9227,7 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
ui_popup_block_free(C, menu);
UI_popup_handlers_remove(&win->modalhandlers, menu);
+ CTX_wm_menu_set(C, NULL);
#ifdef USE_DRAG_TOGGLE
{
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 51dd9166e46..679681cb372 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -51,6 +51,7 @@
#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"
@@ -587,7 +588,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 +703,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 +756,7 @@ static void init_iconfile_list(struct ListBase *list)
}
}
- BLI_free_filelist(dir, totfile);
+ BLI_filelist_free(dir, totfile, NULL);
dir = NULL;
}
@@ -930,7 +931,8 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
/* 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)
@@ -940,8 +942,17 @@ static void icon_set_image(bContext *C, ID *id, PreviewImage *prv_img, enum eIco
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(scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
+ }
}
PreviewImage *UI_icon_to_preview(int icon_id)
@@ -1148,29 +1159,30 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
}
}
-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 */
/* 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;
}
}
-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);
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);
enum eIconSizes i;
@@ -1182,14 +1194,14 @@ static void ui_id_brush_render(bContext *C, ID *id)
/* 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);
+ icon_set_image(C, NULL, id, pi, i, true);
pi->changed[i] = 0;
}
}
}
-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;
@@ -1242,7 +1254,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;
@@ -1258,7 +1270,7 @@ int ui_id_icon_get(bContext *C, ID *id, const bool big)
case ID_LA: /* fall through */
iconid = BKE_icon_getid(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;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 328822e47ef..54ba3d784d1 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -433,6 +433,7 @@ 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 void ui_region_to_window(const struct ARegion *ar, int *x, int *y);
extern double ui_but_value_get(uiBut *but);
extern void ui_but_value_set(uiBut *but, double value);
@@ -627,6 +628,11 @@ 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_get_ime_data(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);
@@ -653,7 +659,7 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na
void uiStyleInit(void);
/* interface_icons.c */
-int ui_id_icon_get(struct bContext *C, struct ID *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);
@@ -688,5 +694,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 2d952d66638..f02c6a234a9 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -904,7 +904,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) {
@@ -1450,8 +1450,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 = (CollItemSearch *)a;
+ const CollItemSearch *cis2 = (CollItemSearch *)b;
if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
return 1;
@@ -1492,7 +1492,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 */
@@ -1922,17 +1922,9 @@ static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void
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);
@@ -1941,12 +1933,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 */
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 4cb587bc1be..074faaa86bc 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -45,7 +45,6 @@
#include "BKE_global.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"
@@ -950,4 +949,5 @@ void ED_button_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 fc39b63a71d..e68c86353a3 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -753,9 +753,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;
@@ -1226,7 +1230,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;
}
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 6a4bf230591..0ec59e4e4cd 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"
@@ -365,7 +362,8 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* special case enum rna buttons */
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 to select multiple)"), sizeof(data->lines[0]));
+ 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++;
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index d2aa463e3ff..8b2ce90dcf5 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -47,7 +47,9 @@
#include "BLF_api.h"
-#include "BLF_translation.h"
+#ifdef WITH_INTERNATIONAL
+# include "BLF_translation.h"
+#endif
#include "UI_interface.h"
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 95cb36a4672..407843d663c 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"
@@ -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,7 +154,7 @@ 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 == UI_search_item_add(items, name_ui, id, iconid))
break;
@@ -352,6 +350,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");
}
@@ -390,6 +390,10 @@ static const char *template_id_context(StructRNA *type)
case ID_BR: return BLF_I18NCONTEXT_ID_BRUSH;
case ID_PA: return BLF_I18NCONTEXT_ID_PARTICLESETTINGS;
case ID_GD: return BLF_I18NCONTEXT_ID_GPENCIL;
+ case ID_MC: return BLF_I18NCONTEXT_ID_MOVIECLIP;
+ case ID_MSK: return BLF_I18NCONTEXT_ID_MASK;
+ case ID_PAL: return BLF_I18NCONTEXT_ID_PALETTE;
+ case ID_PC: return BLF_I18NCONTEXT_ID_PAINTCURVE;
}
}
return BLF_I18NCONTEXT_DEFAULT;
@@ -473,11 +477,12 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
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, UI_BTYPE_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;
@@ -2667,7 +2672,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;
@@ -2679,15 +2684,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)
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 854f1763370..28bd637ae59 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -83,13 +83,21 @@ 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))
+ 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, UI_BTYPE_NUM_SLIDER, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
else
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:
@@ -107,6 +115,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
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, 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:
{
@@ -390,6 +402,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 c9def075666..04a886ba2a8 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -59,6 +59,10 @@
#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))
@@ -757,10 +761,9 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
/* emboss bottom shadow */
- UI_GetThemeColor4ubv(TH_EMBOSS, emboss);
-
if (wtb->emboss) {
- UI_GetThemeColor4ubv(TH_EMBOSS, emboss);
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
+
if (emboss[3]) {
glColor4ubv(emboss);
glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss);
@@ -1232,6 +1235,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;
@@ -1239,6 +1286,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
const char *drawstr_right = NULL;
bool use_right_only = false;
+#ifdef WITH_INPUT_IME
+ const wmIMEData *ime_data;
+#endif
+
UI_fontstyle_set(fstyle);
if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT))
@@ -1266,13 +1317,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_get_ime_data(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) {
@@ -1298,18 +1366,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);
+
+ 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)
@@ -2780,7 +2874,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);
@@ -2811,7 +2905,9 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
rect1 = *rect;
value = ui_but_value_get(but);
- fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
+ 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);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 5573515391d..aa5b2570952 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)
{
@@ -371,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:
@@ -505,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;
@@ -619,8 +642,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->nla_sound_sel;
break;
- case TH_EMBOSS:
- cp = btheme->tui.emboss; break;
+ case TH_WIDGET_EMBOSS:
+ cp = btheme->tui.widget_emboss; break;
case TH_AXIS_X:
cp = btheme->tui.xaxis; break;
@@ -663,7 +686,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
}
}
- return (unsigned char *)cp;
+ return (const unsigned char *)cp;
}
/* use this call to init new bone color sets in Theme */
@@ -820,7 +843,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
- rgba_char_args_set_fl(btheme->tui.emboss, 1.0f, 1.0f, 1.0f, 0.02f);
+ 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);
@@ -892,6 +915,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;
@@ -1111,6 +1137,9 @@ 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 */
@@ -1193,6 +1222,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)
{
@@ -1534,7 +1575,7 @@ void init_userdef_do_versions(void)
}
if (U.mixbufsize == 0) U.mixbufsize = 2048;
if (strcmp(U.tempdir, "/") == 0) {
- BLI_system_temporary_dir(U.tempdir);
+ BKE_tempdir_system_init(U.tempdir);
}
if (U.autokey_mode == 0) {
/* 'add/replace' but not on */
@@ -2498,10 +2539,36 @@ void init_userdef_do_versions(void)
}
}
- if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) {
+ if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 3)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set_fl(btheme->tui.emboss, 1.0f, 1.0f, 1.0f, 0.02f);
+ rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f);
+ }
+ }
+
+ if (U.versionfile < 273 || (U.versionfile == 273 && U.subversionfile < 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);
}
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index f42e35945d7..de46d47e5a3 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -2305,7 +2305,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));
@@ -2336,7 +2336,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/io/io_collada.c b/source/blender/editors/io/io_collada.c
index bbf4447dd72..491152b02e5 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -298,7 +298,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
RNA_def_boolean(ot->srna,
@@ -365,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");
@@ -372,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 {
@@ -395,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)
@@ -419,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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_OPENFILE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
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");
+ "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,
+ "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/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 93e59f3244e..929c4f74b2f 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -784,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);
@@ -1286,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. */
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/editface.c b/source/blender/editors/mesh/editface.c
index 87b429f1165..113f0f71b53 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"
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 3e403387a67..9b1b0b915c1 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 true;
+}
+
+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 'g'; /* g is grab */
+ return htype;
}
-static short edbm_extrude_edge_ex(
+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,
@@ -362,87 +331,58 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
}
/* 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);
@@ -578,7 +515,6 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
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];
@@ -686,7 +623,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",
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 b08f7ef9613..0a78f299159 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -75,10 +75,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 +103,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 +117,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 {
@@ -529,7 +535,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);
}
@@ -554,7 +560,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;
@@ -603,6 +609,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;
@@ -626,7 +633,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];
@@ -635,37 +646,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 */
@@ -683,6 +699,7 @@ static void add_hit_to_facehits(KnifeTool_OpData *kcd, GHash *facehits, BMFace *
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))
@@ -690,15 +707,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;
+ }
/* Check if edge actually lies within face (might not, if this face is concave) */
- if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) {
+ else if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) {
if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) {
return;
}
}
kfe = new_knife_edge(kcd);
- kfe->draw = true;
+ kfe->is_cut = true;
kfe->basef = f;
if (lh1->v) {
@@ -711,7 +738,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 */
@@ -727,7 +754,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 */
@@ -748,19 +775,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;
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.
@@ -1076,7 +1097,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);
@@ -1098,7 +1119,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);
@@ -1206,9 +1227,82 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
kcd->ortho_extent = max_xyz;
}
-/* 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) {
+ *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;
+}
+
+static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
+{
+ switch (((BMElem *)user_data)->head.htype) {
+ case BM_FACE:
+ return (BMFace *)user_data != f;
+ case BM_EDGE:
+ return !BM_edge_in_face((BMEdge *)user_data, f);
+ case BM_VERT:
+ return !BM_vert_in_face((BMVert *)user_data, f);
+ default:
+ return true;
+ }
+}
+
+
+/**
+ * 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;
@@ -1232,7 +1326,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)) {
@@ -1251,9 +1345,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;
@@ -1295,6 +1399,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];
@@ -1302,7 +1407,6 @@ 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;
@@ -1383,6 +1487,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;
@@ -1397,27 +1506,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;
@@ -1426,44 +1526,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;
+ 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.
+ /* 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 (v->v == NULL) {
- for (ref = v->edges.first; ref; ref = ref->next) {
- kfe = ref->ref;
- if (kfe->e) {
- hit.kfe = kfe;
- break;
- }
- }
- }
-
- 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 (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);
@@ -1486,7 +1597,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 */
@@ -1515,7 +1626,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
float p[3], p_cage[3];
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)) {
+ 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);
@@ -1527,7 +1638,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
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)) {
+ 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);
@@ -1589,6 +1700,10 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, 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;
@@ -1983,34 +2098,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;
-
- for (cur = ((Ref *)lst->first)->next; cur; cur = next) {
- KnifeVert *vcur = cur->ref;
- const float vcur_fac_sq = len_squared_v3v3(v1co, vcur->co);
+ 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);
- 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).
@@ -2341,13 +2439,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);
@@ -2591,6 +2698,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;
@@ -2627,7 +2742,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, e->v1->co, sort_verts_by_dist_cb);
+
for (ref = lst->first; ref; ref = ref->next) {
kfv = ref->ref;
pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co);
@@ -2759,10 +2875,11 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, scene, NULL);
- kcd->bmbvh = BKE_bmbvh_new_from_editmesh(kcd->em,
- BMBVH_RETURN_ORIG |
- (only_select ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN),
- kcd->cagecos, false);
+ kcd->bmbvh = BKE_bmbvh_new_from_editmesh(
+ kcd->em,
+ BMBVH_RETURN_ORIG |
+ ((only_select && cut_through) ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN),
+ kcd->cagecos, false);
kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife");
kcd->vthresh = KMAXDIST - 1;
@@ -3120,16 +3237,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);
@@ -3142,49 +3257,34 @@ static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
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;
+ 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;
-
- 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;
- }
+ LinkNode *p = polys;
+ int isect = 0;
- 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;
}
@@ -3194,6 +3294,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);
@@ -3212,6 +3313,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 */
@@ -3276,7 +3381,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);
}
}
@@ -3309,7 +3417,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_path.c b/source/blender/editors/mesh/editmesh_path.c
index e1ef74cbaf8..4eaac6cc1d3 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"
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 4f149bf2c52..ead243d6de8 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -626,7 +626,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) ||
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 5f3f7cb242c..d3073d519f6 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -38,7 +38,6 @@
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_array.h"
-#include "BLI_smallhash.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -62,8 +61,6 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "GPU_extensions.h"
-
#include "UI_resources.h"
#include "bmesh_tools.h"
@@ -386,8 +383,6 @@ static void findnearestvert__doClosest(void *userData, BMVert *eve, const float
}
-
-
static bool findnearestvert__backbufIndextest(void *handle, unsigned int index)
{
BMEditMesh *em = (BMEditMesh *)handle;
@@ -711,6 +706,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
@@ -888,7 +884,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);
@@ -994,6 +990,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
}
MEM_freeN(groups_array);
+ MEM_freeN(group_index);
if (changed) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -3365,8 +3362,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 a136bc5e0c5..a480b2051cc 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -878,7 +878,7 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
BMesh *bm = em->bm;
BMOperator bmop;
bool is_pair = (bm->totvertsel == 2);
- int len;
+ int len = 0;
bool check_degenerate = true;
const int verts_len = bm->totvertsel;
BMVert **verts;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c6571058040..86cd75eed7a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -232,7 +232,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) {
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index e2ce97a3bdf..152d055d239 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -43,7 +43,6 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -51,7 +50,6 @@
#include "BKE_report.h"
#include "BKE_editmesh.h"
-#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
@@ -571,24 +569,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;
@@ -639,6 +626,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))
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index f6a54beb8c8..57daec49465 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"
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 9b380ff8d48..79437bb05b9 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -56,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
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 24dcf85cec8..c3edd63b2d4 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -69,7 +69,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 +96,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 +106,6 @@
#include "ED_transform.h"
#include "ED_view3d.h"
-#include "UI_interface.h"
#include "UI_resources.h"
#include "GPU_material.h"
@@ -833,24 +830,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);
@@ -902,6 +887,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);
@@ -990,8 +977,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);
}
}
@@ -1299,6 +1289,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)
@@ -1315,8 +1343,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) {
@@ -1356,7 +1384,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);
}
@@ -1372,9 +1400,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) {
@@ -1437,7 +1470,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);
@@ -2279,7 +2312,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 1f1bdbe55e5..758f4d180b9 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 */
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 57fabcb06cf..83eeedfef52 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -1081,8 +1081,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 +1118,8 @@ static int bake_exec(bContext *C, wmOperator *op)
RE_SetReports(re, NULL);
+
+finally:
BLI_freelistN(&bkr.selected_objects);
return result;
}
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..f6cf0312e2d
--- /dev/null
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -0,0 +1,675 @@
+/*
+ * ***** 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 "MEM_guardedalloc.h"
+
+#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_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 "UI_resources.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_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;
+}
+
+/* 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) || !ELEM(OB_MESH, ob_src->type, ob_dst->type)) {
+ 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 = CTX_data_active_object(C);
+
+ ListBase ctx_objects;
+ CollectionPointerLink *ctx_ob_dst;
+
+ bool changed = false;
+
+ 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_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 ? &space_transform_data : NULL;
+
+ 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, max_distance, ray_radius, islands_precision,
+ layers_select_src, layers_select_dst,
+ mix_mode, mix_factor, NULL, false, op->reports))
+ {
+ changed = true;
+ }
+ }
+
+ if (reverse_transfer) {
+ SWAP(Object *, ob_src, ob_dst);
+ }
+ }
+
+ BLI_freelistN(&ctx_objects);
+
+#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_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_max_distance = false;
+ bool use_modifier = false;
+
+ 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, "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);
+
+ /* 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_object_transform", true, "Object Transform",
+ "Evaluate source and destination meshes in their respective object spaces");
+ 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_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);
+
+ 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);
+ }
+ 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);
+ }
+ }
+
+ BLI_freelistN(&ctx_objects);
+ }
+
+ 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_intern.h b/source/blender/editors/object/object_intern.h
index 6fa3caa6172..64fddf1b6a1 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -37,6 +37,11 @@ struct Lattice;
struct Curve;
struct Object;
struct Mesh;
+struct bContext;
+struct StructRNA;
+struct wmOperator;
+
+struct ModifierData;
struct HookModifierData;
/* add hook menu */
@@ -155,6 +160,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);
@@ -214,7 +225,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);
@@ -266,5 +276,9 @@ void OBJECT_OT_lod_remove(struct wmOperatorType *ot);
/* object_random.c */
void OBJECT_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_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 cec5c683221..5a479af83b5 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"
@@ -807,7 +808,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 +820,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 +849,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,7 +1354,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
edit_modifier_properties(ot);
}
@@ -1667,7 +1668,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);
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index bef64fec8d0..15eb9090ce5 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"
@@ -178,7 +177,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);
@@ -250,6 +248,9 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_lod_remove);
WM_operatortype_append(OBJECT_OT_vertex_random);
+
+ WM_operatortype_append(OBJECT_OT_data_transfer);
+ WM_operatortype_append(OBJECT_OT_datalayout_transfer);
}
void ED_operatormacros_object(void)
@@ -421,6 +422,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_relations.c b/source/blender/editors/object/object_relations.c
index 48e617eda11..67b5c8061cd 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -803,6 +803,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;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 6bb23a4a7f0..3fe8c86ef5c 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -75,10 +75,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_insert_shape_key(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;
@@ -320,11 +320,10 @@ 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);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index f19765a5344..92fe5ded4dd 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"
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 49c77770467..e70281c502b 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"
@@ -54,7 +51,6 @@
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
-#include "BLF_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -85,11 +81,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 +117,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_listbase_count(&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,31 +243,6 @@ 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.
@@ -465,34 +356,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)
{
@@ -511,7 +374,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 +386,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 +404,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);
}
@@ -682,7 +545,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 +566,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 +610,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 +685,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 +701,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 +734,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 +787,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 +813,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];
@@ -1498,86 +1024,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_listbase_count(&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;
@@ -2052,7 +1498,7 @@ static void vgroup_normalize_all(Object *ob,
if (dvert_array) {
const int defbase_tot = BLI_listbase_count(&ob->defbase);
- bool *lock_flags = BKE_objdef_lock_flags_get(ob, defbase_tot);
+ bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
if ((lock_active == true) &&
(lock_flags != NULL) &&
@@ -2205,7 +1651,7 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *);
- 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);
@@ -2725,298 +2171,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_listbase_count(&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 +2222,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 +2246,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 +2264,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 +2295,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;
@@ -3226,7 +2371,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 +2399,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 +2466,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 +2498,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 +2631,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 +2697,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 +2819,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);
@@ -3715,7 +2860,7 @@ static int vertex_group_blend_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_blend_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac);
MEM_freeN((void *)vgroup_validmap);
@@ -3791,7 +2936,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 +2977,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 +3015,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 +3079,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 */
@@ -4032,143 +3177,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);
@@ -4297,7 +3305,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 +3322,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];
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 8016dabf3a3..7413bb07c4c 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"
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 637af5d6536..d864934171b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -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);
}
}
}
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_ops.c b/source/blender/editors/physics/physics_ops.c
index 2a8718b3ef5..37cf95e5c2d 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"
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..9b4f128ef86 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -33,16 +33,12 @@
#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"
@@ -50,7 +46,6 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
-#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c
index 1c893992cf2..7bb189bd71b 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"
@@ -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);
}
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index baf25a49f7c..b04f1d3e738 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -75,10 +75,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 +84,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "wm_window.h"
#include "render_intern.h"
@@ -343,7 +340,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;
@@ -416,8 +417,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 +443,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);
@@ -1121,7 +1127,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;
@@ -1439,7 +1445,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 */
@@ -1551,10 +1557,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;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 559c86bf48c..8024add41cf 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -69,7 +69,6 @@
#include "GPU_extensions.h"
#include "GPU_glew.h"
-#include "wm_window.h"
#include "render_intern.h"
@@ -144,8 +143,10 @@ 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);
ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
@@ -187,7 +188,9 @@ 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);
@@ -271,7 +274,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* 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,
+ IB_rect, OB_SOLID, false, true, true,
(draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out);
camera = scene->camera;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 2a0ec853079..ea80a07fdd4 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,14 +79,11 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
-#include "GPU_extensions.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "PIL_time.h"
#include "RE_pipeline.h"
#include "RE_engine.h"
@@ -96,9 +94,7 @@
#include "ED_datafiles.h"
#include "ED_render.h"
-#include "UI_interface.h"
-#include "render_intern.h"
ImBuf *get_brush_icon(Brush *brush)
{
@@ -121,7 +117,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);
@@ -565,8 +561,9 @@ 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;
+ if (re)
+ RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte);
- RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte);
glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
MEM_freeN(rect_byte);
@@ -1101,6 +1098,25 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
+void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
+{
+ IconPreview ip = {0};
+ short stop = false, update = false;
+ float progress = 0.0f;
+
+ 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;
@@ -1180,12 +1196,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 eaa7cf40aca..91c689373be 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -51,7 +51,6 @@
#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"
@@ -65,17 +64,15 @@
#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"
@@ -1481,7 +1478,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 6118db703b4..be42e2ed518 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -41,11 +41,11 @@
#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"
@@ -85,7 +85,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();
@@ -276,7 +280,7 @@ static void material_changed(Main *bmain, Material *ma)
/* 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) {
@@ -290,7 +294,7 @@ static void material_changed(Main *bmain, Material *ma)
BKE_icon_changed(BKE_icon_getid(&parent->id));
if (parent->gpumaterial.first)
- GPU_material_free(parent);
+ GPU_material_free(&parent->gpumaterial);
}
/* find if we have a scene with textured display */
@@ -336,10 +340,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)
@@ -377,7 +381,7 @@ static void texture_changed(Main *bmain, Tex *tex)
BKE_icon_changed(BKE_icon_getid(&ma->id));
if (ma->gpumaterial.first)
- GPU_material_free(ma);
+ GPU_material_free(&ma->gpumaterial);
}
/* find lamps */
@@ -406,6 +410,9 @@ static void texture_changed(Main *bmain, Tex *tex)
}
BKE_icon_changed(BKE_icon_getid(&wo->id));
+
+ if (wo->gpumaterial.first)
+ GPU_material_free(&wo->gpumaterial);
}
/* find compositing nodes */
@@ -451,14 +458,17 @@ static void world_changed(Main *bmain, World *wo)
/* icons */
BKE_icon_changed(BKE_icon_getid(&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)
@@ -478,6 +488,7 @@ 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) {
@@ -487,16 +498,20 @@ static void scene_changed(Main *bmain, Scene *scene)
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);
+ 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)
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 630ff8fecf6..71714bdcda9 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"
@@ -896,7 +895,7 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
{
- AZone *az;
+ AZone *az = NULL;
const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) == 0;
if (is_hidden || !is_fullscreen) {
@@ -907,7 +906,7 @@ static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const
az->edge = edge;
}
- if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
+ if (!is_hidden) {
if (!is_fullscreen) {
if (G.debug_value == 3)
region_azone_icon(sa, az, ar);
@@ -1352,8 +1351,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 */
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index c095dfe7792..134feb59d55 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"
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 18c9a94e46f..ce9c608247b 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,11 +46,13 @@
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_gpencil.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"
@@ -66,12 +69,16 @@ 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;
@@ -392,6 +399,112 @@ 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) {
+ 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;
@@ -400,7 +513,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
op = sfile->op;
}
else if ((op = UI_context_active_operator_get(C))) {
- /* do nothign */
+ /* 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 c179cfc464c..3972d00293c 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1748,6 +1748,13 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
}
}
+ 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;
@@ -1763,6 +1770,21 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
}
+void ED_screen_retore_temp_type(bContext *C, ScrArea *sa, bool is_screen_change)
+{
+ /* 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 (is_screen_change && 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 */
void ED_screen_full_restore(bContext *C, ScrArea *sa)
{
@@ -1789,12 +1811,14 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
else
ED_screen_state_toggle(C, win, sa, state);
}
- else if (sl->spacetype == SPACE_FILE) {
+ else if (sa->flag & AREA_FLAG_TEMP_TYPE) {
ED_screen_full_prevspace(C, sa);
}
else {
ED_screen_state_toggle(C, win, sa, state);
}
+
+ sa->flag &= ~AREA_FLAG_TEMP_TYPE;
}
/* otherwise just tile the area again */
else {
@@ -1857,6 +1881,11 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
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 */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 454bb3b7ca3..39321ec0770 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -43,6 +43,7 @@
#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"
@@ -81,8 +82,6 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "wm_window.h"
-
#include "screen_intern.h" /* own module include */
#define KM_MODAL_CANCEL 1
@@ -2150,6 +2149,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;
@@ -2177,7 +2177,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) {
@@ -3523,12 +3525,14 @@ 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) {
+ return win->screen;
+ }
+ }
- for (window = wm->windows.first; window; window = window->next)
- if (window->screen->animtimer)
- return window->screen;
-
return NULL;
}
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index be5fd48b41a..e7f256e414a 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,7 +286,7 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
ot->flag = 0;
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_SAVE,
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
RNA_def_boolean(ot->srna, "full", 1, "Full Screen",
"Capture the whole window (otherwise only capture the active area)");
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index e27ef705fad..430ea1cc11d 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -341,8 +341,8 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
BKE_paint_reset_overlay_invalid(invalid);
@@ -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(br, len, 1.0f); /* Falloff curve */
buffer[index] = 255 - (GLubyte)(255 * avg);
@@ -464,8 +464,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
BKE_paint_reset_overlay_invalid(PAINT_INVALID_OVERLAY_CURVE);
@@ -595,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);
@@ -1000,9 +1000,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 */
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 8c7c3b102e3..1f5ee708ad0 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -329,7 +329,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 */
@@ -410,8 +410,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 */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 021822793ff..d52b17372f7 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -45,13 +45,11 @@
#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"
@@ -62,15 +60,9 @@
#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"
@@ -85,7 +77,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "GPU_draw.h"
#include "GPU_buffers.h"
@@ -671,22 +662,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));
@@ -1065,7 +1058,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(&settings->unified_paint_settings, &imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT);
paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
}
@@ -1422,7 +1415,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->toolsettings->unified_paint_settings, &imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT);
if (U.glreslimit != 0)
GPU_free_images();
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index ea0e30a6635..95940d89694 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"
@@ -362,7 +359,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(brush, len, radius));
}
}
@@ -689,7 +686,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;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 9cc1906596f..3e675012d05 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -50,7 +50,6 @@
#include "BLF_translation.h"
-#include "PIL_time.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -62,7 +61,6 @@
#include "DNA_object_types.h"
#include "BKE_camera.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
@@ -80,10 +78,8 @@
#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"
@@ -101,7 +97,6 @@
#include "RNA_enum_types.h"
#include "GPU_draw.h"
-#include "GPU_buffers.h"
#include "IMB_colormanagement.h"
@@ -192,7 +187,7 @@ 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;
} ProjPaintImage;
@@ -1339,7 +1334,7 @@ static float project_paint_uvpixel_mask(
/* now we can use the normal as a mask */
if (ps->is_ortho) {
- angle = angle_normalized_v3v3((float *)ps->viewDir, no);
+ angle = angle_normalized_v3v3(ps->viewDir, no);
}
else {
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
@@ -1967,25 +1962,63 @@ 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 void line_rect_clip(
+ 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;
+ if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) < 0) {
+ tmp = rect->xmin;
+ min = min_ff((tmp - l1[0]) / (l2[0] - l1[0]), min);
+ }
+ else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) {
+ tmp = rect->xmax;
+ min = min_ff((tmp - l1[0]) / (l2[0] - l1[0]), min);
+ }
+ if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) < 0) {
+ tmp = rect->ymin;
+ min = min_ff((tmp - l1[1]) / (l2[1] - l1[1]), min);
+ }
+ else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) {
+ tmp = rect->ymax;
+ min = min_ff((tmp - l1[1]) / (l2[1] - l1[1]), min);
+ }
+
+ tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
+
+ uv[0] = (uv1[0] + min * (uv2[0] - uv1[0])) / tmp;
+ uv[1] = (uv1[1] + min * (uv2[1] - uv1[1])) / tmp;
+}
+
+
static void project_bucket_clip_face(
const bool is_ortho,
rctf *bucket_bounds,
float *v1coSS, float *v2coSS, 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));
-
+ bool colinear = false;
+
float bucket_bounds_ss[4][2];
+ /* detect pathological case where face the three vertices are almost colinear in screen space.
+ * mostly those will be culled but when flood filling or with smooth shading */
+ if (dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS) < PROJ_PIXEL_TOLERANCE)
+ colinear = 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 */
if (flip) { /* facing the back? */
@@ -1997,9 +2030,59 @@ 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 (colinear) {
+ 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)) {
+ 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)) {
+ line_rect_clip(bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho);
+ (*tot)++;
}
- *tot = 3;
+ 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)) {
+ line_rect_clip(bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho);
+ (*tot)++;
+ }
+
+ if ((*tot) < 3) { /* no intersections to speak of */
+ *tot = 0;
+ return;
+ }
+
+ /* at this point we have all uv points needed in a row. all that's needed is to invert them if necessary */
+ if (flip) {
+ /* flip only to the middle of the array */
+ int i, max = *tot / 2;
+ for (i = 0; i < max; i++) {
+ SWAP(float, bucket_bounds_uv[i][0], bucket_bounds_uv[max - i][0]);
+ SWAP(float, bucket_bounds_uv[i][1], bucket_bounds_uv[max - i][1]);
+ }
+ }
+
return;
}
@@ -2128,47 +2211,32 @@ static void project_bucket_clip_face(
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);
@@ -2406,8 +2474,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
is_ortho, bucket_bounds,
v1coSS, v2coSS, v3coSS,
uv1co, uv2co, uv3co,
- uv_clip, &uv_clip_tot
- );
+ uv_clip, &uv_clip_tot,
+ ps->do_backfacecull || ps->do_occlude);
/* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
#if 0
@@ -2428,10 +2496,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;
@@ -2821,7 +2889,7 @@ static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int buck
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;
@@ -3092,7 +3160,7 @@ static void project_paint_begin(ProjPaintState *ps)
invert_m4_m4(ps->ob->imat, ps->ob->obmat);
- if (ps->source == PROJ_SRC_VIEW) {
+ if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
/* normal drawing */
ps->winx = ps->ar->winx;
ps->winy = ps->ar->winy;
@@ -3230,7 +3298,7 @@ static void project_paint_begin(ProjPaintState *ps)
CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + 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);
@@ -3426,8 +3494,8 @@ static void project_paint_begin(ProjPaintState *ps)
#ifdef PROJ_DEBUG_WINCLIP
/* ignore faces outside the view */
- if (
- (v1coSS[0] < ps->screenMin[0] &&
+ if ((ps->source != PROJ_SRC_VIEW_FILL) &&
+ ((v1coSS[0] < ps->screenMin[0] &&
v2coSS[0] < ps->screenMin[0] &&
v3coSS[0] < ps->screenMin[0] &&
(mf->v4 && v4coSS[0] < ps->screenMin[0])) ||
@@ -3445,7 +3513,7 @@ static void project_paint_begin(ProjPaintState *ps)
(v1coSS[1] > ps->screenMax[1] &&
v2coSS[1] > ps->screenMax[1] &&
v3coSS[1] > ps->screenMax[1] &&
- (mf->v4 && v4coSS[1] > ps->screenMax[1]))
+ (mf->v4 && v4coSS[1] > ps->screenMax[1])))
)
{
continue;
@@ -3795,10 +3863,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,
@@ -4219,7 +4286,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(ps->brush, dist, brush_radius);
if (falloff > 0.0f) {
float texrgb[3];
@@ -4454,7 +4521,35 @@ 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 side, index;
+
+ index = project_paint_PickFace(ps, pos, w, &side);
+
+ if (index != -1) {
+ MFace *mf;
+ float world[3];
+ UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;
+ mf = ps->dm_mface + index;
+
+ if (side == 0) {
+ interp_v3_v3v3v3(world, ps->dm_mvert[(*(&mf->v1))].co, ps->dm_mvert[(*(&mf->v2))].co, ps->dm_mvert[(*(&mf->v3))].co, w);
+ }
+ else {
+ interp_v3_v3v3v3(world, ps->dm_mvert[(*(&mf->v1))].co, ps->dm_mvert[(*(&mf->v3))].co, ps->dm_mvert[(*(&mf->v4))].co, w);
+ }
+
+ ups->average_stroke_counter++;
+ mul_m4_v3(ps->ob->obmat, world);
+ add_v3_v3(ups->average_stroke_accum, world);
+ ups->last_stroke_valid = true;
+ }
+ }
+
return touch_any;
}
@@ -4626,7 +4721,7 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
paint_brush_init_tex(ps->brush);
- ps->source = PROJ_SRC_VIEW;
+ ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
MEM_freeN(ps);
@@ -4649,10 +4744,6 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
paint_proj_begin_clone(ps, mouse);
- /* special full screen draw mode for fill tool */
- if (ps->tool == PAINT_TOOL_FILL)
- ps->source = PROJ_SRC_VIEW_FILL;
-
return ps;
}
@@ -5130,6 +5221,8 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
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;
}
}
@@ -5288,6 +5381,8 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
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);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 9c4701d0a01..bb875d2ef00 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -207,6 +207,7 @@ static bool paint_brush_update(bContext *C,
UnifiedPaintSettings *ups = stroke->ups;
bool location_sampled = false;
bool location_success = false;
+ bool do_random = 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.
@@ -256,17 +257,13 @@ 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))
+ (brush->mtex.brush_map_mode == 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);
}
@@ -274,7 +271,7 @@ static bool paint_brush_update(bContext *C,
/* take care of mask texture, if any */
if (brush->mask_mtex.tex) {
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);
}
@@ -291,7 +288,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) + M_PI;
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
@@ -328,13 +325,27 @@ 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);
+ }
+ else {
+ 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 (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) {
@@ -651,6 +662,10 @@ PaintStroke *paint_stroke_new(bContext *C,
/* 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);
@@ -675,9 +690,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);
@@ -1064,10 +1082,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if ((br->flag & BRUSH_LINE) && stroke->stroke_started &&
(first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
{
- if (br->flag & BRUSH_RAKE) {
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
- paint_calculate_rake_rotation(stroke->ups, sample_average.mouse);
}
+ paint_calculate_rake_rotation(stroke->ups, br, sample_average.mouse);
}
else if (first_modal ||
/* regular dabs */
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index d41af26a4d1..9c2c13f9a2d 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -48,15 +48,13 @@
#include "BLF_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 */
@@ -397,12 +391,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 ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ 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;
}
@@ -456,16 +450,15 @@ 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);
+ unsigned int totface = me->totface;
MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
- DM_update_materials(dm, ob);
-
if (dm_mtface) {
view3d_set_viewcontext(C, &vc);
@@ -475,7 +468,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
Image *image;
if (use_material)
- image = imapaint_face_image(dm, faceindex);
+ image = imapaint_face_image(ob, me, faceindex);
else
image = imapaint->canvas;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 75bef040d2e..7324cebbf49 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -66,8 +66,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"
@@ -387,7 +385,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
}
/* 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;
}
@@ -937,7 +935,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(brush, dist, brush_size_pressure);
}
}
if (rgba)
@@ -2074,7 +2072,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->toolsettings->unified_paint_settings, &wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
ED_mesh_mirror_spatial_table(ob, NULL, NULL, 's');
@@ -2159,7 +2157,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 +2172,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 +2184,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 */
@@ -2236,9 +2234,9 @@ 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_listbase_count(&ob->defbase);
- wpd->lock_flags = BKE_objdef_lock_flags_get(ob, wpd->defbase_tot);
+ 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 +2316,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 +2680,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->toolsettings->unified_paint_settings, &vp->paint, PAINT_CURSOR_VERTEX_PAINT);
}
/* update modifier stack for mapping requirements */
@@ -3024,7 +3022,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;
}
@@ -3217,7 +3215,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(grad_data->brush, alpha, 1.0f);
if (alpha != 0.0f) {
MDeformVert *dv = &me->dvert[index];
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 1e4931ac792..dbb29997102 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -40,7 +40,6 @@
#include "BLI_dial.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLI_threads.h"
#include "BLF_translation.h"
@@ -56,7 +55,6 @@
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
-#include "BKE_crazyspace.h"
#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_key.h"
@@ -85,7 +83,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RE_render_ext.h"
#include "GPU_buffers.h"
@@ -106,6 +103,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,33 +115,6 @@ 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;
- }
-}
-
-
/* 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)
{
@@ -2957,7 +2929,7 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
/* 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;
@@ -3018,13 +2990,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;
@@ -3138,8 +3107,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;
}
}
@@ -3348,9 +3319,9 @@ 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_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
+static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups,
BrushActionFunc action,
const char symm, const int axis,
const float feather)
@@ -3362,7 +3333,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);
+ action(sd, ob, brush, ups);
}
}
@@ -3400,11 +3371,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);
+ action(sd, ob, brush, ups);
- 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);
}
}
}
@@ -4156,9 +4127,6 @@ static bool 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;
}
@@ -4365,10 +4333,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;
@@ -4985,7 +4949,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(&ts->unified_paint_settings, &ts->sculpt->paint, PAINT_CURSOR_SCULPT);
paint_cursor_start(C, sculpt_poll_view3d);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index d90eaafa379..23bc4a483d3 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"
@@ -237,7 +236,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(&settings->unified_paint_settings, &settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
brush_drawcursor_uvsculpt, NULL);
@@ -558,15 +557,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;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 7ede6c95b9d..d9f4b97fe09 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -72,7 +72,6 @@
#include "ED_sound.h"
#include "ED_util.h"
-#include "sound_intern.h"
/******************** open sound operator ********************/
@@ -143,7 +142,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,7 +183,7 @@ 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_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);
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,7 +205,7 @@ 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_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);
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");
@@ -651,7 +650,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | SOUNDFILE, FILE_SPECIAL, FILE_SAVE,
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_SAVE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
#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);
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index e55ce3ea8eb..bc9c578b558 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -545,7 +545,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 +562,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 +622,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 +639,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 +652,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 +669,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 ************************* */
@@ -965,8 +969,11 @@ static int actkeys_clean_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 cleaning threshold */
thresh = RNA_float_get(op->ptr, "threshold");
@@ -1025,15 +1032,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 +1148,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 +1222,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 +1304,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 +1343,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 +1368,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 +1401,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_ops.c b/source/blender/editors/space_action/action_ops.c
index b99419dec20..0fbacefa8e3 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"
@@ -207,9 +205,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 */
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 77c6cce6cda..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"
@@ -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/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 3b939702c58..a67af289f59 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -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"
@@ -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_listbase_count_ex(&ct->users, ct->index))
+ if (ct->index == BLI_listbase_count_ex(&ct->users, ct->index + 1))
ct->index = 0;
ct->user = BLI_findlink(&ct->users, ct->index);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 4d62f528915..a778df4b783 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 ***************** */
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index fe36d9a9685..f8299a8d335 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -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 ************************/
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index fe5b332aeb1..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"
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..6c55d8d034e 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -63,7 +63,6 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "RNA_access.h"
#include "BLF_api.h"
@@ -1123,7 +1122,7 @@ 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 is_selected_track = (plane_track->flag & SELECT) != 0;
bool draw_plane_quad = plane_track->image == NULL || plane_track->image_opacity == 0.0f;
float px[2];
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index f25f035db32..89693a403fe 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -57,7 +57,6 @@
#include "BKE_tracking.h"
#include "BKE_library.h"
-#include "GPU_extensions.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
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..2a2f15c94bb 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"
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 787a7fca273..e3d45a297a7 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -299,7 +299,7 @@ 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_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);
}
@@ -1307,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);
}
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index a79ac1f7b82..5f919c9b51d 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"
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index bf9b55ba3dd..fc2c0d3d45c 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -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;
}
}
@@ -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;
}
}
@@ -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 bdb57cca81e..742e58d80dd 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,7 +64,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "UI_interface.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -74,7 +72,6 @@
#include "PIL_time.h"
-#include "UI_view2d.h"
#include "clip_intern.h" // own include
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 860d9dc6b3c..bc6ac507f03 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
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_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 6f63f315f74..3f3c14d3a7d 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -47,7 +47,6 @@
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BLF_api.h"
#include "BLF_translation.h"
#include "IMB_imbuf_types.h"
@@ -67,7 +66,6 @@
#include "WM_types.h"
-#include "fsmenu.h"
#include "filelist.h"
#include "file_intern.h" // own include
@@ -113,6 +111,7 @@ 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);
@@ -126,15 +125,22 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
available_w -= chan_offs;
}
}
-
+
/* Is there enough space for the execute / cancel buttons? */
- loadbutton = UI_fontstyle_string_width(params->title) + btn_margin;
- CLAMP_MIN(loadbutton, btn_minw);
- if (available_w <= loadbutton + separator + input_minw || params->title[0] == 0) {
+
+ if (is_browse_only) {
loadbutton = 0;
}
else {
+ loadbutton = UI_fontstyle_string_width(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;
}
@@ -147,7 +153,7 @@ 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) {
int overwrite_alert = file_draw_check_exists(sfile);
@@ -235,33 +241,33 @@ static int get_file_icon(struct direntry *file)
if (strcmp(file->relname, "..") == 0) {
return ICON_FILE_PARENT;
}
- if (file->flags & APPLICATIONBUNDLE) {
+ if (file->flags & FILE_TYPE_APPLICATIONBUNDLE) {
return ICON_UGLYPACKAGE;
}
- if (file->flags & BLENDERFILE) {
+ if (file->flags & FILE_TYPE_BLENDER) {
return ICON_FILE_BLEND;
}
return ICON_FILE_FOLDER;
}
- else if (file->flags & BLENDERFILE)
+ else if (file->flags & FILE_TYPE_BLENDER)
return ICON_FILE_BLEND;
- else if (file->flags & BLENDERFILE_BACKUP)
+ else if (file->flags & FILE_TYPE_BLENDER_BACKUP)
return ICON_FILE_BACKUP;
- else if (file->flags & IMAGEFILE)
+ else if (file->flags & FILE_TYPE_IMAGE)
return ICON_FILE_IMAGE;
- else if (file->flags & MOVIEFILE)
+ else if (file->flags & FILE_TYPE_MOVIE)
return ICON_FILE_MOVIE;
- else if (file->flags & PYSCRIPTFILE)
+ else if (file->flags & FILE_TYPE_PYSCRIPT)
return ICON_FILE_SCRIPT;
- else if (file->flags & SOUNDFILE)
+ else if (file->flags & FILE_TYPE_SOUND)
return ICON_FILE_SOUND;
- else if (file->flags & FTFONTFILE)
+ else if (file->flags & FILE_TYPE_FTFONT)
return ICON_FILE_FONT;
- else if (file->flags & BTXFILE)
+ else if (file->flags & FILE_TYPE_BTX)
return ICON_FILE_BLANK;
- else if (file->flags & COLLADAFILE)
+ else if (file->flags & FILE_TYPE_COLLADA)
return ICON_FILE_BLANK;
- else if (file->flags & TEXTFILE)
+ else if (file->flags & FILE_TYPE_TEXT)
return ICON_FILE_TEXT;
else
return ICON_FILE_BLANK;
@@ -516,10 +522,15 @@ void file_draw_list(const bContext *C, ARegion *ar)
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->active_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->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 20 : 0;
+
+ /* readonly files (".." and ".") must not be drawn as selected - set color back to normal */
+ if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ colorid = TH_BACK;
+ }
draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
}
@@ -536,7 +547,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
is_icon = 1;
}
- file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & IMAGEFILE), do_drag);
+ file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & FILE_TYPE_IMAGE), 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);
@@ -545,7 +556,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_ThemeColor4(TH_TEXT);
- if (file->selflag & EDITING_FILE) {
+ if (file->selflag & FILE_SEL_EDITING) {
uiBut *but;
short width;
@@ -568,11 +579,11 @@ void file_draw_list(const bContext *C, ARegion *ar)
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 &= ~EDITING_FILE;
+ file->selflag &= ~FILE_SEL_EDITING;
}
}
- 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);
}
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 13beba3fff8..3a579820106 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -34,6 +34,7 @@
#include "BLO_readfile.h"
+#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
@@ -219,7 +220,7 @@ 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_select(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
/* Don't act on multiple selected files */
if (sel.first != sel.last) select = 0;
@@ -258,9 +259,25 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
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);
+ int idx;
+
+ file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ /* dont highlight readonly file (".." or ".") on border select */
+ for (idx = sel.last; idx >= 0; idx--) {
+ struct direntry *file = filelist_file(sfile->files, idx);
+
+ if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ file->selflag &= ~FILE_SEL_HIGHLIGHTED;
+ }
+
+ /* active_file gets highlighted as well - make sure it is no readonly file */
+ if (sel.last == idx) {
+ params->active_file = idx;
+ }
+ }
}
params->sel_first = sel.first; params->sel_last = sel.last;
@@ -268,7 +285,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
else {
params->active_file = -1;
params->sel_first = params->sel_last = -1;
- file_deselect_all(sfile, HILITED_FILE);
+ file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -288,7 +305,7 @@ static int file_border_select_exec(bContext *C, wmOperator *op)
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);
@@ -340,8 +357,20 @@ 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->active_file;
+
+ if (idx >= 0) {
+ struct direntry *file = filelist_file(sfile->files, idx);
+ if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ /* skip - If a readonly file (".." or ".") is selected, skip deselect all! */
+ }
+ else {
+ /* 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 (FILE_SELECT_DIR == ret)
@@ -398,11 +427,11 @@ static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* select all only if previously no file was selected */
if (is_selected) {
- filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, SELECTED_FILE, CHECK_ALL);
+ filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
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);
+ filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type);
}
ED_area_tag_redraw(sa);
return OPERATOR_FINISHED;
@@ -472,7 +501,7 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
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);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
}
@@ -504,7 +533,7 @@ static int bookmark_delete_exec(bContext *C, wmOperator *op)
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_redraw(sa);
}
@@ -540,7 +569,7 @@ static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
while (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);
@@ -821,7 +850,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, 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);
+ BLI_make_file_string(G.main->name, filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu_get(), filepath);
WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
@@ -1197,7 +1226,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')
@@ -1481,7 +1510,7 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
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);
+ filelist_select_file(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
sfile->params->renamefile[0] = '\0';
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 871abbda48a..bcef0817ffe 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -45,9 +45,10 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_fileops_types.h"
+#include "BLI_fnmatch.h"
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
-#include "BLI_fileops_types.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -64,8 +65,8 @@
#include "DNA_space_types.h"
-#include "ED_fileselect.h"
#include "ED_datafiles.h"
+#include "ED_fileselect.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -80,6 +81,119 @@
#include "filelist.h"
+
+/* ----------------- FOLDERLIST (previous/next) -------------- */
+
+typedef struct FolderList {
+ struct FolderList *next, *prev;
+ char *foldername;
+} FolderList;
+
+ListBase *folderlist_new(void)
+{
+ ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist");
+ 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 = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList");
+ 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(ListBase), "copy folderlist");
+ 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------------------------ */
+
struct FileList;
typedef struct FileImage {
@@ -91,77 +205,87 @@ typedef struct FileImage {
ImBuf *img;
} FileImage;
-typedef struct ThumbnailJob {
- ListBase loadimages;
- const short *stop;
- const short *do_update;
- struct FileList *filelist;
- ReportList reports;
-} ThumbnailJob;
+typedef struct FileListFilter {
+ bool hide_dot;
+ bool hide_parent;
+ unsigned int filter;
+ char filter_glob[64];
+ char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
+} FileListFilter;
typedef struct FileList {
struct direntry *filelist;
- int *fidx;
int numfiles;
- int numfiltered;
char dir[FILE_MAX];
short prv_w;
short prv_h;
- short hide_dot;
- unsigned int filter;
- char filter_glob[64];
- short changed;
+
+ bool changed;
+
+ short sort;
+ bool need_sorting;
+
+ FileListFilter filter_data;
+ int *fidx; /* Also used to detect when we need to filter! */
+ int numfiltered;
+
+ bool need_thumbnails;
struct BlendHandle *libfiledata;
- short hide_parent;
void (*readf)(struct FileList *);
- bool (*filterf)(struct direntry *file, const char *dir, unsigned int filter, short hide_dot);
-
+ bool (*filterf)(struct direntry *, const char *, FileListFilter *);
} FileList;
-typedef struct FolderList {
- struct FolderList *next, *prev;
- char *foldername;
-} FolderList;
+#define FILENAME_IS_BREADCRUMBS(_n) \
+ ((_n)[0] == '.' && ((_n)[1] == '\0' || ((_n)[1] == '.' && (_n)[2] == '\0')))
#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_from_main(struct FileList *filelist);
+static void filelist_from_library(struct FileList *filelist);
+
+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_filter_clear(FileList *filelist);
+
+/* ********** Sort helpers ********** */
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 !(entry->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP));
return false;
}
-static int compare_name(const void *a1, const void *a2)
+static int compare_direntry_generic(const struct direntry *entry1, const struct direntry *entry2)
{
- const struct direntry *entry1 = a1, *entry2 = a2;
-
/* type is equal to stat.st_mode */
if (compare_is_directory(entry1)) {
@@ -185,35 +309,29 @@ static int compare_name(const void *a1, const void *a2)
if (strcmp(entry1->relname, "..") == 0) return (-1);
if (strcmp(entry2->relname, "..") == 0) return (1);
+ return 0;
+}
+
+static int compare_name(const void *a1, const void *a2)
+{
+ const struct direntry *entry1 = a1, *entry2 = a2;
+ int ret;
+
+ if ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
+ }
+
return (BLI_natstrcmp(entry1->relname, entry2->relname));
}
static int compare_date(const void *a1, const void *a2)
{
const struct direntry *entry1 = a1, *entry2 = a2;
+ int ret;
- /* type is equal to stat.st_mode */
-
- 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;
@@ -224,29 +342,11 @@ static int compare_date(const void *a1, const void *a2)
static int compare_size(const void *a1, const void *a2)
{
const struct direntry *entry1 = a1, *entry2 = a2;
+ int ret;
- /* 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 ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
}
- 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_size < entry2->s.st_size) return 1;
if (entry1->s.st_size > entry2->s.st_size) return -1;
@@ -258,6 +358,11 @@ static int compare_extension(const void *a1, const void *a2)
const struct direntry *entry1 = a1, *entry2 = a2;
const char *sufix1, *sufix2;
const char *nil = "";
+ int ret;
+
+ if ((ret = compare_direntry_generic(entry1, entry2))) {
+ return ret;
+ }
if (!(sufix1 = strstr(entry1->relname, ".blend.gz")))
sufix1 = strrchr(entry1->relname, '.');
@@ -266,126 +371,191 @@ static int compare_extension(const void *a1, const void *a2)
if (!sufix1) sufix1 = nil;
if (!sufix2) sufix2 = nil;
- /* type is equal to stat.st_mode */
+ return (BLI_strcasecmp(sufix1, sufix2));
+}
- 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);
+bool filelist_need_sorting(struct FileList *filelist)
+{
+ return filelist->need_sorting && (filelist->sort != FILE_SORT_NONE);
+}
+
+void filelist_sort(struct FileList *filelist)
+{
+ if (filelist_need_sorting(filelist)) {
+ filelist->need_sorting = false;
+
+ switch (filelist->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;
+ case FILE_SORT_NONE: /* Should never reach this point! */
+ default:
+ BLI_assert(0);
+ return;
+ }
+
+ filelist_filter_clear(filelist);
}
- 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->need_sorting = true;
}
- 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)
{
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->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->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 . */
+ }
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(struct direntry *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->relname, filter);
+
+ if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) {
+ if ((file->type & S_IFDIR) && !(filter->filter & FILE_TYPE_FOLDER)) {
+ is_filtered = false;
}
- else if (file->type & S_IFDIR) {
- if (filter & FOLDERFILE) {
- is_filtered = 1;
+ if (!(file->type & S_IFDIR) && !(file->flags & filter->filter)) {
+ is_filtered = false;
+ }
+ if (is_filtered && (filter->filter_search[0] != '\0')) {
+ if (fnmatch(filter->filter_search, file->relname, 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(struct direntry *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 = !is_hidden_file(file->relname, filter);
+ char dir[FILE_MAXDIR], group[BLO_GROUP_MAX];
+
+ if (BLO_is_a_library(root, dir, group)) {
+ is_filtered = !is_hidden_file(file->relname, filter);
+ if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) {
+ if (is_filtered && (filter->filter_search[0] != '\0')) {
+ if (fnmatch(filter->filter_search, file->relname, 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(struct direntry *file, const char *UNUSED(dir), FileListFilter *filter)
+{
+ return !is_hidden_file(file->relname, filter);
+}
+
+static void filelist_filter_clear(FileList *filelist)
{
- return !is_hidden_file(file->relname, hide_dot);
+ MEM_SAFE_FREE(filelist->fidx);
+ filelist->numfiltered = 0;
}
void filelist_filter(FileList *filelist)
{
int num_filtered = 0;
- int i, j;
+ int *fidx_tmp;
+ int i;
- if (!filelist->filelist)
+ if (!filelist->filelist) {
return;
+ }
- /* How many files are left after filter ? */
+ if (filelist->fidx) {
+ /* Assume it has already been filtered, nothing else to do! */
+ return;
+ }
+
+ fidx_tmp = MEM_mallocN(sizeof(*fidx_tmp) * (size_t)filelist->numfiles, __func__);
+
+ /* Filter remap & count how many files are left after filter in a single loop. */
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->filterf(file, filelist->dir, &filelist->filter_data)) {
+ fidx_tmp[num_filtered++] = i;
}
}
-
- if (filelist->fidx) {
- MEM_freeN(filelist->fidx);
- filelist->fidx = NULL;
- }
- filelist->fidx = (int *)MEM_callocN(num_filtered * sizeof(int), "filteridx");
+
+ /* Note: maybe we could even accept filelist->fidx to be filelist->numfiles -len allocated? */
+ filelist->fidx = (int *)MEM_mallocN(sizeof(*filelist->fidx) * (size_t)num_filtered, __func__);
+ memcpy(filelist->fidx, fidx_tmp, sizeof(*filelist->fidx) * (size_t)num_filtered);
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;
- }
+ MEM_freeN(fidx_tmp);
+}
+
+void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
+ const unsigned int filter,
+ const char *filter_glob, const char *filter_search)
+{
+ if ((filelist->filter_data.hide_dot != hide_dot) ||
+ (filelist->filter_data.hide_parent != hide_parent) ||
+ (filelist->filter_data.filter != filter) ||
+ !STREQ(filelist->filter_data.filter_glob, filter_glob) ||
+ (BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0))
+ {
+ filelist->filter_data.hide_dot = hide_dot;
+ filelist->filter_data.hide_parent = hide_parent;
+
+ filelist->filter_data.filter = filter;
+ BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob));
+ BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, filter_search, '*',
+ sizeof(filelist->filter_data.filter_search));
+
+ /* And now, free filtered data so that we now we have to filter again. */
+ filelist_filter_clear(filelist);
}
}
+/* ********** Icon/image helpers ********** */
+
void filelist_init_icons(void)
{
short x, y, k;
@@ -428,115 +598,86 @@ void filelist_free_icons(void)
}
}
-/* -----------------FOLDERLIST (previous/next) -------------- */
-ListBase *folderlist_new(void)
-{
- ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist");
- return p;
-}
-
-void folderlist_popdir(struct ListBase *folderlist, char *dir)
+void filelist_imgsize(struct FileList *filelist, short w, short h)
{
- 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 */
+ filelist->prv_w = w;
+ filelist->prv_h = h;
}
-void folderlist_pushdir(ListBase *folderlist, const char *dir)
+ImBuf *filelist_getimage(struct FileList *filelist, const int index)
{
- 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 = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList");
- folder->foldername = BLI_strdup(dir);
-
- /* add it to the end of the list */
- BLI_addtail(folderlist, folder);
-}
+ ImBuf *ibuf = NULL;
+ int fidx = 0;
-const char *folderlist_peeklastdir(ListBase *folderlist)
-{
- struct FolderList *folder;
+ BLI_assert(G.background == false);
- if (!folderlist->last)
+ if ((index < 0) || (index >= filelist->numfiltered)) {
return NULL;
+ }
+ fidx = filelist->fidx[index];
+ ibuf = filelist->filelist[fidx].image;
- folder = folderlist->last;
- return folder->foldername;
+ return ibuf;
}
-int folderlist_clear_next(struct SpaceFile *sfile)
+ImBuf *filelist_geticon(struct FileList *filelist, const int index)
{
- 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;
+ ImBuf *ibuf = NULL;
+ struct direntry *file = NULL;
+ int fidx = 0;
- /* eventually clear flist->folders_next */
- return 1;
-}
+ BLI_assert(G.background == false);
-/* 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);
+ if ((index < 0) || (index >= filelist->numfiltered)) {
+ return NULL;
}
-}
-
-ListBase *folderlist_duplicate(ListBase *folderlist)
-{
-
- 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);
+ 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];
}
- return folderlistn;
}
- return NULL;
-}
+ else {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ }
+ if (file->flags & FILE_TYPE_BLENDER) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
+ }
+ else if ((file->flags & FILE_TYPE_MOVIE) || (file->flags & FILE_TYPE_MOVIE_ICON)) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
+ }
+ else if (file->flags & FILE_TYPE_SOUND) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
+ }
+ else if (file->flags & FILE_TYPE_PYSCRIPT) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
+ }
+ else if (file->flags & FILE_TYPE_FTFONT) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
+ }
+ else if (file->flags & FILE_TYPE_TEXT) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
+ }
+ else if (file->flags & FILE_TYPE_IMAGE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
+ }
+ else if (file->flags & FILE_TYPE_BLENDER_BACKUP) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
+ }
-static void filelist_read_main(struct FileList *filelist);
-static void filelist_read_library(struct FileList *filelist);
-static void filelist_read_dir(struct FileList *filelist);
+ return ibuf;
+}
+
+/* ********** Main ********** */
-/* ------------------FILELIST------------------------ */
FileList *filelist_new(short type)
{
FileList *p = MEM_callocN(sizeof(FileList), "filelist");
@@ -558,7 +699,6 @@ FileList *filelist_new(short type)
return p;
}
-
void filelist_free(struct FileList *filelist)
{
if (!filelist) {
@@ -566,18 +706,16 @@ void filelist_free(struct FileList *filelist)
return;
}
- if (filelist->fidx) {
- MEM_freeN(filelist->fidx);
- filelist->fidx = NULL;
- }
+ MEM_SAFE_FREE(filelist->fidx);
+ filelist->numfiltered = 0;
+ memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
+
+ filelist->need_sorting = false;
+ filelist->sort = FILE_SORT_NONE;
- BLI_free_filelist(filelist->filelist, filelist->numfiles);
+ BLI_filelist_free(filelist->filelist, filelist->numfiles, NULL);
filelist->numfiles = 0;
filelist->filelist = NULL;
- filelist->filter = 0;
- filelist->filter_glob[0] = '\0';
- filelist->numfiltered = 0;
- filelist->hide_dot = 0;
}
void filelist_freelib(struct FileList *filelist)
@@ -607,89 +745,11 @@ void filelist_setdir(struct FileList *filelist, const char *dir)
BLI_strncpy(filelist->dir, dir, sizeof(filelist->dir));
}
-void filelist_imgsize(struct FileList *filelist, short w, short h)
-{
- filelist->prv_w = w;
- filelist->prv_h = h;
-}
-
short filelist_changed(struct FileList *filelist)
{
return filelist->changed;
}
-ImBuf *filelist_getimage(struct FileList *filelist, int index)
-{
- ImBuf *ibuf = NULL;
- int fidx = 0;
-
- BLI_assert(G.background == false);
-
- if ((index < 0) || (index >= filelist->numfiltered)) {
- return NULL;
- }
- fidx = filelist->fidx[index];
- ibuf = filelist->filelist[fidx].image;
-
- return ibuf;
-}
-
-ImBuf *filelist_geticon(struct FileList *filelist, int index)
-{
- ImBuf *ibuf = NULL;
- struct direntry *file = NULL;
- int fidx = 0;
-
- BLI_assert(G.background == false);
-
- if ((index < 0) || (index >= filelist->numfiltered)) {
- return NULL;
- }
- 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];
- }
- }
- else {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
- }
-
- if (file->flags & BLENDERFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
- }
- else if ((file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
- }
- else if (file->flags & SOUNDFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
- }
- else if (file->flags & PYSCRIPTFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
- }
- else if (file->flags & FTFONTFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
- }
- else if (file->flags & TEXTFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
- }
- else if (file->flags & IMAGEFILE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
- }
- else if (file->flags & BLENDERFILE_BACKUP) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
- }
-
- return ibuf;
-}
-
struct direntry *filelist_file(struct FileList *filelist, int index)
{
int fidx = 0;
@@ -728,21 +788,6 @@ int filelist_find(struct FileList *filelist, const char *filename)
return fidx;
}
-void filelist_hidedot(struct FileList *filelist, short hide)
-{
- filelist->hide_dot = hide;
-}
-
-void filelist_setfilter(struct FileList *filelist, unsigned int filter)
-{
- filelist->filter = filter;
-}
-
-void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob)
-{
- BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob));
-}
-
/* would recognize .blend as well */
static bool file_is_blend_backup(const char *str)
{
@@ -772,47 +817,47 @@ 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;
}
@@ -828,25 +873,25 @@ int ED_file_extension_icon(const char *path)
{
int type = path_extension_type(path);
- if (type == BLENDERFILE)
+ if (type == FILE_TYPE_BLENDER)
return ICON_FILE_BLEND;
- else if (type == BLENDERFILE_BACKUP)
+ else if (type == FILE_TYPE_BLENDER_BACKUP)
return ICON_FILE_BACKUP;
- else if (type == IMAGEFILE)
+ else if (type == FILE_TYPE_IMAGE)
return ICON_FILE_IMAGE;
- else if (type == MOVIEFILE)
+ else if (type == FILE_TYPE_MOVIE)
return ICON_FILE_MOVIE;
- else if (type == PYSCRIPTFILE)
+ else if (type == FILE_TYPE_PYSCRIPT)
return ICON_FILE_SCRIPT;
- else if (type == SOUNDFILE)
+ else if (type == FILE_TYPE_SOUND)
return ICON_FILE_SOUND;
- else if (type == FTFONTFILE)
+ else if (type == FILE_TYPE_FTFONT)
return ICON_FILE_FONT;
- else if (type == BTXFILE)
+ else if (type == FILE_TYPE_BTX)
return ICON_FILE_BLANK;
- else if (type == COLLADAFILE)
+ else if (type == FILE_TYPE_COLLADA)
return ICON_FILE_BLANK;
- else if (type == TEXTFILE)
+ else if (type == FILE_TYPE_TEXT)
return ICON_FILE_TEXT;
return ICON_FILE_BLANK;
@@ -869,12 +914,11 @@ static void filelist_setfiletypes(struct FileList *filelist)
#endif
file->flags = file_extension_type(filelist->dir, file->relname);
- if (filelist->filter_glob[0] &&
- BLI_testextensie_glob(file->relname, filelist->filter_glob))
+ if (filelist->filter_data.filter_glob[0] &&
+ BLI_testextensie_glob(file->relname, filelist->filter_data.filter_glob))
{
- file->flags = OPERATORFILE;
+ file->flags = FILE_TYPE_OPERATOR;
}
-
}
}
@@ -885,11 +929,15 @@ static void filelist_read_dir(struct FileList *filelist)
filelist->fidx = NULL;
filelist->filelist = NULL;
+ BLI_make_exist(filelist->dir);
BLI_cleanup_dir(G.main->name, filelist->dir);
- filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist));
+ filelist->numfiles = BLI_filelist_dir_contents(filelist->dir, &(filelist->filelist));
+
+ /* We shall *never* get an empty list here, since we now the dir exists and is readable
+ * (ensured by BLI_make_exist()). So we expect at the very least the parent '..' entry. */
+ BLI_assert(filelist->numfiles != 0);
filelist_setfiletypes(filelist);
- filelist_filter(filelist);
}
static void filelist_read_main(struct FileList *filelist)
@@ -907,7 +955,6 @@ static void filelist_read_library(struct FileList *filelist)
int num;
struct direntry *file;
- BLI_make_exist(filelist->dir);
filelist_read_dir(filelist);
file = filelist->filelist;
for (num = 0; num < filelist->numfiles; num++, file++) {
@@ -929,18 +976,15 @@ static void filelist_read_library(struct FileList *filelist)
void filelist_readdir(struct FileList *filelist)
{
filelist->readf(filelist);
-}
-int filelist_empty(struct FileList *filelist)
-{
- return filelist->filelist == NULL;
+ filelist->need_sorting = true;
+ filelist->need_thumbnails = true;
+ filelist_filter_clear(filelist);
}
-void filelist_parent(struct FileList *filelist)
+int filelist_empty(struct FileList *filelist)
{
- BLI_parent_dir(filelist->dir);
- BLI_make_exist(filelist->dir);
- filelist_readdir(filelist);
+ return filelist->filelist == NULL;
}
void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check)
@@ -995,35 +1039,15 @@ bool filelist_is_selected(struct FileList *filelist, int index, FileCheckType ch
}
switch (check) {
case CHECK_DIRS:
- return S_ISDIR(file->type) && (file->selflag & SELECTED_FILE);
+ return S_ISDIR(file->type) && (file->selflag & FILE_SEL_SELECTED);
case CHECK_FILES:
- return S_ISREG(file->type) && (file->selflag & SELECTED_FILE);
+ return S_ISREG(file->type) && (file->selflag & FILE_SEL_SELECTED);
case CHECK_ALL:
default:
- return (file->selflag & SELECTED_FILE) != 0;
+ return (file->selflag & FILE_SEL_SELECTED) != 0;
}
}
-void filelist_sort(struct FileList *filelist, short sort)
-{
- 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;
- }
-
- filelist_filter(filelist);
-}
-
bool filelist_islibrary(struct FileList *filelist, char *dir, char *group)
{
@@ -1042,8 +1066,8 @@ 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 void filelist_from_library(struct FileList *filelist)
{
LinkNode *l, *names, *previews;
struct ImBuf *ima;
@@ -1124,7 +1148,7 @@ void filelist_from_library(struct FileList *filelist)
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;
+ filelist->filelist[i + 1].flags = FILE_TYPE_IMAGE;
}
}
}
@@ -1133,20 +1157,10 @@ void filelist_from_library(struct FileList *filelist)
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);
-}
-
-void filelist_hideparent(struct FileList *filelist, short hide)
-{
- filelist->hide_parent = hide;
}
-void filelist_from_main(struct FileList *filelist)
+static void filelist_from_main(struct FileList *filelist)
{
ID *id;
struct direntry *files, *firstlib = NULL;
@@ -1166,9 +1180,9 @@ void filelist_from_main(struct FileList *filelist)
/* make directories */
#ifdef WITH_FREESTYLE
- filelist->numfiles = 25;
-#else
filelist->numfiles = 24;
+#else
+ filelist->numfiles = 23;
#endif
filelist->filelist = (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
@@ -1178,32 +1192,31 @@ void filelist_from_main(struct FileList *filelist)
}
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[1].relname = BLI_strdup("Scene");
+ filelist->filelist[2].relname = BLI_strdup("Object");
+ filelist->filelist[3].relname = BLI_strdup("Mesh");
+ filelist->filelist[4].relname = BLI_strdup("Curve");
+ filelist->filelist[5].relname = BLI_strdup("Metaball");
+ filelist->filelist[6].relname = BLI_strdup("Material");
+ filelist->filelist[7].relname = BLI_strdup("Texture");
+ filelist->filelist[8].relname = BLI_strdup("Image");
+ filelist->filelist[9].relname = BLI_strdup("Ika");
+ filelist->filelist[10].relname = BLI_strdup("Wave");
+ filelist->filelist[11].relname = BLI_strdup("Lattice");
+ filelist->filelist[12].relname = BLI_strdup("Lamp");
+ filelist->filelist[13].relname = BLI_strdup("Camera");
+ filelist->filelist[14].relname = BLI_strdup("Ipo");
+ filelist->filelist[15].relname = BLI_strdup("World");
+ filelist->filelist[16].relname = BLI_strdup("Screen");
+ filelist->filelist[17].relname = BLI_strdup("VFont");
+ filelist->filelist[18].relname = BLI_strdup("Text");
+ filelist->filelist[19].relname = BLI_strdup("Armature");
+ filelist->filelist[20].relname = BLI_strdup("Action");
+ filelist->filelist[21].relname = BLI_strdup("NodeTree");
+ filelist->filelist[22].relname = BLI_strdup("Speaker");
#ifdef WITH_FREESTYLE
- filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle");
+ filelist->filelist[23].relname = BLI_strdup("FreestyleLineStyle");
#endif
- filelist_sort(filelist, FILE_SORT_ALPHA);
}
else {
@@ -1216,7 +1229,7 @@ void filelist_from_main(struct FileList *filelist)
id = lb->first;
filelist->numfiles = 0;
while (id) {
- if (!filelist->hide_dot || id->name[2] != '.') {
+ if (!filelist->filter_data.hide_dot || id->name[2] != '.') {
filelist->numfiles++;
}
@@ -1224,12 +1237,12 @@ void filelist_from_main(struct FileList *filelist)
}
/* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */
- if (!filelist->hide_parent) filelist->numfiles += 1;
+ if (!filelist->filter_data.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) {
+ if (!filelist->filter_data.hide_parent) {
memset(&(filelist->filelist[0]), 0, sizeof(struct direntry));
filelist->filelist[0].relname = BLI_strdup("..");
filelist->filelist[0].type |= S_IFDIR;
@@ -1243,7 +1256,7 @@ void filelist_from_main(struct FileList *filelist)
while (id) {
ok = 1;
if (ok) {
- if (!filelist->hide_dot || id->name[2] != '.') {
+ if (!filelist->filter_data.hide_dot || id->name[2] != '.') {
memset(files, 0, sizeof(struct direntry));
if (id->lib == NULL) {
files->relname = BLI_strdup(id->name + 2);
@@ -1256,10 +1269,10 @@ void filelist_from_main(struct FileList *filelist)
#if 0 /* XXXXX 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->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->selflag |= FILE_SEL_SELECTED;
}
}
#endif
@@ -1267,7 +1280,7 @@ void filelist_from_main(struct FileList *filelist)
files->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->flags |= 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);
@@ -1292,8 +1305,22 @@ void filelist_from_main(struct FileList *filelist)
qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
}
}
- filelist->filter = 0;
- filelist_filter(filelist);
+}
+
+/* ********** Thumbnails job ********** */
+
+typedef struct ThumbnailJob {
+ ListBase loadimages;
+ ImBuf *static_icons_buffers[BIFICONID_LAST];
+ const short *stop;
+ const short *do_update;
+ struct FileList *filelist;
+ ReportList reports;
+} ThumbnailJob;
+
+bool filelist_need_thumbnails(FileList *filelist)
+{
+ return filelist->need_thumbnails;
}
static void thumbnail_joblist_free(ThumbnailJob *tj)
@@ -1318,18 +1345,18 @@ static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float
tj->do_update = do_update;
while ((*stop == 0) && (limg)) {
- if (limg->flags & IMAGEFILE) {
+ if (limg->flags & FILE_TYPE_IMAGE) {
limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
}
- else if (limg->flags & (BLENDERFILE | BLENDERFILE_BACKUP)) {
+ else if (limg->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
}
- else if (limg->flags & MOVIEFILE) {
+ else if (limg->flags & FILE_TYPE_MOVIE) {
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;
+ limg->flags &= ~FILE_TYPE_MOVIE;
+ limg->flags |= FILE_TYPE_MOVIE_ICON;
}
}
*do_update = true;
@@ -1348,9 +1375,9 @@ static void thumbnails_update(void *tjv)
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;
+ if (limg->flags & FILE_TYPE_MOVIE_ICON) {
+ tj->filelist->filelist[limg->index].flags &= ~FILE_TYPE_MOVIE;
+ tj->filelist->filelist[limg->index].flags |= FILE_TYPE_MOVIE_ICON;
}
limg->done = true;
}
@@ -1359,6 +1386,15 @@ static void thumbnails_update(void *tjv)
}
}
+static void thumbnails_endjob(void *tjv)
+{
+ ThumbnailJob *tj = tjv;
+
+ if (!*tj->stop) {
+ tj->filelist->need_thumbnails = false;
+ }
+}
+
static void thumbnails_free(void *tjv)
{
ThumbnailJob *tj = tjv;
@@ -1378,7 +1414,9 @@ void thumbnails_start(FileList *filelist, const bContext *C)
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))) {
+ if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE |
+ FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))
+ {
FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage");
BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX);
limg->index = idx;
@@ -1395,7 +1433,7 @@ void thumbnails_start(FileList *filelist, const bContext *C)
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_jobs_callbacks(wm_job, thumbnails_startjob, NULL, thumbnails_update, thumbnails_endjob);
/* start the job */
WM_jobs_start(CTX_wm_manager(C), wm_job);
@@ -1403,7 +1441,7 @@ void thumbnails_start(FileList *filelist, const bContext *C)
void thumbnails_stop(wmWindowManager *wm, FileList *filelist)
{
- WM_jobs_kill(wm, filelist, NULL);
+ WM_jobs_kill_type(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL);
}
int thumbnails_running(wmWindowManager *wm, FileList *filelist)
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index c37bb882168..797d54a89b1 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -60,47 +60,53 @@ 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);
+bool filelist_need_sorting(struct FileList *filelist);
+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 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(struct FileList *filelist, const int index);
+
+struct FileList * filelist_new(short type);
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_readdir(struct FileList *filelist);
void filelist_setdir(struct FileList *filelist, const char *dir);
+
+int filelist_empty(struct FileList *filelist);
+int filelist_numfiles(struct FileList *filelist);
struct direntry * filelist_file(struct FileList *filelist, int index);
+int filelist_find(struct FileList *filelist, const char *file);
+
+short filelist_changed(struct FileList *filelist);
+
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);
-
-int filelist_empty(struct FileList *filelist);
-void filelist_parent(struct FileList *filelist);
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);
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);
+bool filelist_need_thumbnails(struct FileList *filelist);
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);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 8b90cf6cc29..3e663275dcd 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"
@@ -157,30 +158,30 @@ 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_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';
@@ -214,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
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;
@@ -253,7 +254,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));
}
@@ -602,9 +603,12 @@ void file_change_dir(bContext *C, int checkdir)
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
-
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';
+
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 */
@@ -634,7 +638,7 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
if (fnmatch(pattern, file->relname, 0) == 0) {
- file->selflag |= SELECTED_FILE;
+ file->selflag |= FILE_SEL_SELECTED;
if (!match) {
BLI_strncpy(matched_file, file->relname, FILE_MAX);
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index f046ac7cdb3..4ab9bc6a849 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -367,7 +367,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* 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);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index d5be04cff20..f0555933146 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"
@@ -193,64 +193,59 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa))
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
- 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->active_file = -1; /* added this so it opens nicer (ton) */
}
- 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);
+ filelist_setsorting(sfile->files, params->sort);
+ filelist_setfilter_options(sfile->files, params->flag & FILE_HIDE_DOT,
+ false, /* TODO hide_parent, should be controllable? */
+ params->flag & FILE_FILTER ? params->filter : 0,
+ params->filter_glob,
+ params->filter_search);
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);
- }
+ filelist_sort(sfile->files);
BLI_strncpy(params->dir, filelist_dir(sfile->files), FILE_MAX);
- if (params->display == FILE_IMGDISPLAY) {
+ }
+ else if (filelist_need_sorting(sfile->files)) {
+ thumbnails_stop(wm, sfile->files);
+ filelist_sort(sfile->files);
+ }
+
+ if ((params->display == FILE_IMGDISPLAY) && filelist_need_thumbnails(sfile->files)) {
+ if (!thumbnails_running(wm, sfile->files)) {
thumbnails_start(sfile->files, C);
}
}
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);
- }
+ /* stop any running thumbnail jobs if we're not displaying them - speedup for NFS */
+ thumbnails_stop(wm, sfile->files);
}
-
+
+ filelist_filter(sfile->files);
+
if (params->renamefile[0] != '\0') {
int idx = filelist_find(sfile->files, params->renamefile);
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
if (file) {
- file->selflag |= EDITING_FILE;
+ file->selflag |= FILE_SEL_EDITING;
}
}
BLI_strncpy(sfile->params->renameedit, sfile->params->renamefile, sizeof(sfile->params->renameedit));
params->renamefile[0] = '\0';
}
- if (sfile->layout) sfile->layout->dirty = true;
+ if (sfile->layout) {
+ sfile->layout->dirty = true;
+ }
}
static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
@@ -656,7 +651,7 @@ 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();
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 53beb5e0659..b87f80c4e62 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -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"
@@ -699,7 +697,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 +714,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 +765,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 +775,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 +787,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 +805,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 ************************* */
@@ -1241,7 +1244,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
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);
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 408c78d194e..50412952139 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -62,6 +62,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);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 62b6b59df29..da308d0b1f1 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"
@@ -200,6 +201,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)
@@ -215,12 +384,16 @@ void graphedit_operatortypes(void)
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);
@@ -359,6 +532,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);
@@ -405,9 +580,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 */
@@ -429,6 +608,19 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
+ /* 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 +630,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 +641,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..78dbae7618b 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -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;
}
@@ -485,6 +491,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)
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index e9c8ae95acd..eea360ced45 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"
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index be65cdb2d4f..05868283b2e 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -977,19 +977,9 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
}
}
-void image_buttons_register(ARegionType *art)
+void image_buttons_register(ARegionType *UNUSED(art))
{
- PanelType *pt;
- const char *category = "Grease Pencil";
-
- 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);
+
}
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 f41e237beb4..7c5aa349fa0 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -854,8 +854,13 @@ void draw_image_main(const bContext *C, ARegion *ar)
draw_render_info(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;
}
@@ -873,12 +878,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_ops.c b/source/blender/editors/space_image/image_ops.c
index 836ff25bddc..9d816853e8e 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -92,6 +92,8 @@
#include "PIL_time.h"
+#include "RE_engine.h"
+
#include "image_intern.h"
/******************** view navigation utilities *********************/
@@ -1052,6 +1054,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
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");
@@ -1070,7 +1073,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
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);
@@ -1084,8 +1087,9 @@ static int image_open_exec(bContext *C, wmOperator *op)
/* 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 */
@@ -1127,7 +1131,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
}
/* 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);
@@ -1203,7 +1207,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- 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_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
}
@@ -1279,7 +1283,7 @@ 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_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
@@ -1322,7 +1326,7 @@ void IMAGE_OT_replace(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- 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_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
}
@@ -1732,7 +1736,7 @@ 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_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);
}
@@ -1880,7 +1884,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);
@@ -2309,7 +2313,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);
@@ -2580,8 +2584,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))
@@ -3015,8 +3020,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));
@@ -3108,8 +3115,21 @@ 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);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 5dc9af2de84..6cf53533618 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -356,7 +356,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
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;
}
@@ -797,7 +797,9 @@ static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *
/* 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:
@@ -860,6 +862,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;
}
}
@@ -908,7 +914,7 @@ 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:
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 86af89bd6a9..e2895109b48 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,8 +44,6 @@
#include "BIF_gl.h"
-#include "ED_datafiles.h"
-#include "ED_types.h"
#include "UI_resources.h"
#include "UI_interface.h"
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/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
index 085fe68df92..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"
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 5464449a94e..21a9246d7e6 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -96,11 +96,7 @@ static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisf
static int vergname(const void *v1, const void *v2)
{
- char **x1, **x2;
-
- x1 = (char **)v1;
- x2 = (char **)v2;
-
+ const char * const *x1 = v1, * const *x2 = v2;
return BLI_natstrcmp(*x1, *x2);
}
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 89cfd389a9d..66023ce1243 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -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) {
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index fbb4d273626..0abe5e42c3e 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) {
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 4cae820de89..ef3c3504a85 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"
@@ -619,7 +618,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;
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index f43982fac8b..a883f350f1c 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -1372,11 +1372,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 */
@@ -2130,9 +2134,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 */
@@ -2246,6 +2254,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,
@@ -2256,6 +2265,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 */
@@ -2321,6 +2331,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");
@@ -2375,10 +2388,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..bd96b5a4de5 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 */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 5e1381db696..b3a875047db 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"
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index cc1d6002134..ec584525aeb 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -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 */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index e0fe622d98d..c45626e4284 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -54,7 +54,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "ED_node.h"
@@ -64,7 +63,6 @@
#include "UI_resources.h"
#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "node_intern.h" /* own include */
@@ -781,8 +779,8 @@ 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);
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 5805c11a438..b6fa4518ed6 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"
@@ -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);
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)) {
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 58d94a28226..76a096b8471 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -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))
{
@@ -197,15 +199,6 @@ void node_buttons_register(ARegionType *art)
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 42259a37f45..16ad63bcafa 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -66,7 +66,10 @@
#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_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
@@ -1130,6 +1133,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);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index a16adb09b4f..1e258368b8b 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"
@@ -342,14 +339,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)
@@ -662,11 +667,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);
}
@@ -1142,7 +1152,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 +1287,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 +1486,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 +1550,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 +1598,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 +1636,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;
@@ -1667,7 +1677,7 @@ 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 +1934,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 +2047,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 +2455,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 de119cf04fb..b69808d4e81 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -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)
@@ -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;
@@ -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_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 8dfc2ac8e83..c8951a1172e 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -57,7 +57,6 @@
#include "BLF_translation.h"
#include "node_intern.h" /* own include */
-#include "NOD_common.h"
/* ****************** Add *********************** */
@@ -368,7 +367,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 +746,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 +802,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 +873,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 +883,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 +941,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) {
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index ab0619604a9..8b68ac013c2 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -30,7 +30,6 @@
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -54,7 +53,6 @@
#include "ED_util.h"
-#include "node_intern.h"
/************************* Node Socket Manipulation **************************/
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/space_node.c b/source/blender/editors/space_node/space_node.c
index e28c775ad88..e3baddef158 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"
@@ -515,6 +513,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;
}
}
@@ -670,7 +673,7 @@ static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *
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;
@@ -699,9 +702,11 @@ static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
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 +773,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/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 61c4fe3cd02..9bc043b384e 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1018,6 +1018,8 @@ 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_PointCache:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
/* Default */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index d735b5e75cf..4f13454ef34 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"
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 6f5bf712d55..23586a6a509 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;
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index f8a90c942bc..4aa36da594b 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1371,59 +1371,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
@@ -1553,10 +1536,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;
}
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 4cf9c0c95c2..d9aff2781f0 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -43,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
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index a94ce52aca5..38a01bcd78c 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -40,7 +40,6 @@
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
-#include "BLF_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -61,7 +60,6 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
-#include "UI_view2d.h"
#include "BKE_sound.h"
@@ -626,7 +624,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
+ 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);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie");
@@ -675,7 +673,7 @@ 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_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);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
@@ -774,7 +772,7 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE,
+ 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);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index d75eeca2c67..70c6da0bfb3 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -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,9 +59,11 @@ 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");
@@ -72,6 +74,7 @@ void sequencer_buttons_register(ARegionType *art)
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 90ba1044677..afb650f8cfd 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"
@@ -69,6 +70,7 @@
#include "WM_api.h"
+
/* own include */
#include "sequencer_intern.h"
@@ -86,9 +88,9 @@
#undef SEQP_BEGIN
#undef SEQ_END
-static void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2);
+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;
@@ -179,14 +181,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;
@@ -194,20 +196,30 @@ 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->mutex)
+ sound->mutex = BLI_mutex_alloc();
+
+ BLI_mutex_lock(sound->mutex);
+ if (!seq->sound->waveform) {
+ if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) {
+ /* prevent sounds from reloading */
+ seq->sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING;
+ BLI_mutex_unlock(sound->mutex);
+ sequencer_preview_add_sound(C, seq);
+ }
+ else {
+ BLI_mutex_unlock(sound->mutex);
+ }
+ return; /* nothing to draw */
+ }
+ BLI_mutex_unlock(sound->mutex);
+
waveform = seq->sound->waveform;
-
- if (!waveform)
- 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);
samplestep = (endsample - startsample) * stepsize / (x2 - x1);
@@ -303,7 +315,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);
@@ -338,7 +350,7 @@ static float draw_seq_handle_size_get_clamped(Sequence *seq, const float pixelx)
const float maxhandle = pixelx * SEQ_HANDLE_SIZE_MAX;
float size = CLAMPIS(seq->handsize, minhandle, maxhandle);
- /* ensure we're not greater then half width */
+ /* ensure we're not greater than half width */
return min_ff(size, ((float)(seq->enddisp - seq->startdisp) / 2.0f) / pixelx);
}
@@ -422,112 +434,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])
{
@@ -634,7 +540,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;
@@ -691,12 +597,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;
@@ -714,8 +725,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 */
@@ -726,11 +737,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);
@@ -740,7 +753,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 */
@@ -773,7 +788,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;
@@ -817,19 +832,29 @@ 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)
@@ -842,9 +867,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;
}
@@ -859,7 +881,10 @@ 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);
/* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Esc pressed somewhere in the past
@@ -924,7 +949,7 @@ 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)
+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;
@@ -980,7 +1005,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
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);
@@ -1055,23 +1080,25 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
/* 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) {
+ 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 (scope) {
IMB_freeImBuf(ibuf);
ibuf = scope;
@@ -1161,6 +1188,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) {
@@ -1183,6 +1218,25 @@ 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 = BLI_rcti_size_x(&ar->winrct) / (float)BLI_rcti_size_y(&ar->winrct);
+ float image_aspect = viewrectx / viewrecty;
+ float imagex, imagey;
+
+ 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 {
glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin);
glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax);
@@ -1190,6 +1244,15 @@ 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);
}
glEnd();
+
+ if (draw_backdrop) {
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+ }
+
glBindTexture(GL_TEXTURE_2D, last_texid);
glDisable(GL_TEXTURE_2D);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA)
@@ -1199,6 +1262,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if (glsl_used)
IMB_colormanagement_finish_glsl_draw();
+ if (cache_handle)
+ IMB_display_buffer_release(cache_handle);
+
+ if (!scope)
+ IMB_freeImBuf(ibuf);
+
+ if (draw_backdrop) {
+ return;
+ }
+
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
float x1 = v2d->tot.xmin;
@@ -1248,9 +1321,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
ED_gpencil_draw_2dimage(C);
}
}
-
- if (!scope)
- IMB_freeImBuf(ibuf);
/* ortho at pixel level */
UI_view2d_view_restore(C);
@@ -1287,9 +1357,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
@@ -1366,6 +1433,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);
@@ -1386,7 +1454,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 */
@@ -1395,7 +1463,16 @@ 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)
@@ -1473,6 +1550,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);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 4ad521993be..81af6dccc70 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -49,7 +49,6 @@
#include "BKE_report.h"
#include "BKE_sound.h"
-#include "IMB_imbuf.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -62,9 +61,11 @@
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_sequencer.h"
+#include "ED_space_api.h"
#include "UI_view2d.h"
+
/* own include */
#include "sequencer_intern.h"
@@ -179,6 +180,10 @@ static void seq_proxy_build_job(const bContext *C)
LinkData *link;
Sequence *seq;
+ 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);
@@ -385,7 +390,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 +499,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);
@@ -1129,7 +1141,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 +1151,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,7 +1252,6 @@ 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];
@@ -1241,6 +1261,7 @@ typedef struct SlipData {
int num_seq;
bool slow;
int slow_offset; /* offset at the point where offset was turned on */
+ void *draw_handle;
} SlipData;
static void transseq_backup(TransSeq *ts, Sequence *seq)
@@ -1274,15 +1295,30 @@ static void transseq_restore(TransSeq *ts, Sequence *seq)
seq->len = ts->len;
}
-static int slip_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool first_level)
+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 (!first_level || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
+ if (!do_trim || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
seq_array[offset + num_items] = seq;
- trim[offset + num_items] = first_level;
+ trim[offset + num_items] = do_trim;
num_items++;
if (seq->type == SEQ_TYPE_META) {
@@ -1322,6 +1358,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
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);
@@ -1344,6 +1381,8 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
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);
@@ -1353,6 +1392,9 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
WM_event_add_modal_handler(C, op);
+ /* notify so we draw extensions immediately */
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
return OPERATOR_RUNNING_MODAL;
}
@@ -1463,6 +1505,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
Scene *scene = CTX_data_scene(C);
SlipData *data = (SlipData *)op->customdata;
ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
switch (event->type) {
case MOUSEMOVE:
@@ -1504,6 +1547,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
case LEFTMOUSE:
{
+ ED_region_draw_cb_exit(ar->type, data->draw_handle);
MEM_freeN(data->seq_array);
MEM_freeN(data->trim);
MEM_freeN(data->ts);
@@ -1532,6 +1576,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
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);
@@ -1587,7 +1633,6 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot)
INT32_MIN, INT32_MAX);
}
-
/* mute operator */
static int sequencer_mute_exec(bContext *C, wmOperator *op)
{
@@ -2810,74 +2855,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;
-
- int dist, best_dist, best_frame = cfra;
- int seq_frames[2], seq_frames_tot;
-
- best_dist = MAXFRAME * 2;
-
- if (ed == NULL) return cfra;
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- int i;
-
- if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
- continue;
- }
-
- if (do_center) {
- seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
- seq_frames_tot = 1;
- }
- else {
- seq_frames[0] = seq->startdisp;
- seq_frames[1] = seq->enddisp;
-
- seq_frames_tot = 2;
- }
-
- for (i = 0; i < seq_frames_tot; i++) {
- const int seq_frame = seq_frames[i];
-
- 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;
- }
- break;
- }
-
- if (dist < best_dist) {
- best_frame = seq_frame;
- best_dist = dist;
- }
- }
- }
-
- return best_frame;
-}
-
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;
@@ -3350,7 +3334,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 */
@@ -3361,13 +3345,43 @@ 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;
+
+ if (ed == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SEQP_BEGIN(ed, seq)
+ {
+ if ((seq->flag & SELECT)) {
+ struct SeqIndexBuildContext *context;
+ short stop = 0, do_update;
+ float progress;
+ context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq);
+ 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
+
+ return OPERATOR_FINISHED;
+}
+
void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
{
/* identifiers */
@@ -3376,8 +3390,8 @@ 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;
@@ -3619,8 +3633,7 @@ 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);
}
-
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 438696d0327..5f1c9317fd9 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -45,6 +45,7 @@ struct ARegion;
struct ARegionType;
struct Scene;
struct Main;
+struct SequencePreview;
/* space_sequencer.c */
struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa);
@@ -52,7 +53,12 @@ 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);
@@ -73,7 +79,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[];
@@ -150,13 +157,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
@@ -199,5 +199,8 @@ void SEQUENCER_OT_strip_modifier_move(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);
+
#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..83f3f9bc961 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"
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 88646b55e23..9b5ef18f7cd 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"
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..da00b0ff6e1
--- /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;
+
+ 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_mutex_lock(sound->mutex);
+ sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
+ BLI_mutex_unlock(sound->mutex);
+
+ 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.0;
+ *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..24b3776da6d 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -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,7 +166,7 @@ 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);
+ const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
float v = (float)rgb_to_luma_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;
@@ -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;
@@ -659,7 +659,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
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;
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 933daf4adee..6792bbe0577 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -357,25 +357,22 @@ 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;
- break;
case SEQ_SELECT_LR_RIGHT:
- x = CFRA + 1;
+ x = CFRA;
break;
}
SEQP_BEGIN (ed, seq)
{
if (x < CFRA) {
- if (seq->enddisp < CFRA) {
+ if (seq->enddisp <= CFRA) {
seq->flag |= SELECT;
recurs_sel_seq(seq);
}
}
else {
- if (seq->startdisp > CFRA) {
+ if (seq->startdisp >= CFRA) {
seq->flag |= SELECT;
recurs_sel_seq(seq);
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index c0cfaed7867..6231f02907a 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -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;
}
}
@@ -559,7 +563,7 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
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,7 +574,7 @@ 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)) {
@@ -585,7 +589,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;
@@ -641,7 +645,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/text_draw.c b/source/blender/editors/space_text/text_draw.c
index c8ca4e1a7da..31662c02966 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -44,6 +44,8 @@
#include "BKE_text.h"
#include "BKE_screen.h"
+#include "ED_text.h"
+
#include "BIF_gl.h"
#include "UI_interface.h"
@@ -380,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;
@@ -423,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;
@@ -431,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]);
}
@@ -1322,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)
@@ -1329,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);
@@ -1393,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);
@@ -1542,3 +1549,37 @@ void text_update_cursor_moved(bContext *C)
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 02bac251065..92a3cce12e6 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"
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 5483cf04db7..f577714c480 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -50,8 +50,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 ARegion *ar, bool center);
-void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *sa, bool center);
+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 ffabefdfb29..1cf0316aa06 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -300,7 +300,7 @@ void TEXT_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FOLDERFILE | TEXTFILE | PYSCRIPTFILE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path
RNA_def_boolean(ot->srna, "internal", 0, "Make internal", "Make text file internal after loading");
}
@@ -577,7 +577,7 @@ 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_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); //XXX TODO, relative_path
}
@@ -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);
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 09b4123a977..820d1d68f8d 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"
@@ -307,6 +308,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 */
@@ -336,16 +340,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);
}
@@ -354,7 +365,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 */
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 0bd094b6a33..f986e909c7f 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 ***************** */
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/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index 17f90fc54e3..d8b18140cde 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -54,7 +54,6 @@
#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 f25e4f143e6..691da78f26b 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"
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index fa9ba23e454..755c633531d 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"
@@ -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);
@@ -562,14 +575,6 @@ 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)
{
Material *ma = give_current_material(Gtexdraw.ob, matnr + 1);
@@ -668,48 +673,48 @@ static void update_tface_color_layer(DerivedMesh *dm)
}
}
-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;
/* 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;
+ MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[origindex] : NULL;
MTFace mtf = {{{0}}};
int matnr = mpoly->mat_nr;
if (tpoly) {
ME_MTEXFACE_CPY(&mtf, tpoly);
}
-
+
return draw_tface__set_draw(&mtf, (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;
+ 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);
@@ -929,24 +934,16 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
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);
+
+ 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);
}
/* draw game engine text hack */
@@ -956,8 +953,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);
@@ -1153,8 +1152,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 */
@@ -1189,7 +1190,7 @@ void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light,
}
dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, GPU_enable_material, NULL, user_data,
- DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH);
+ DM_DRAW_USE_COLORS);
if (use_light) {
draw_mesh_paint_light_end();
@@ -1206,12 +1207,11 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light,
if (me->mloopcol) {
dm->drawMappedFaces(dm, facemask_cb, GPU_enable_material, NULL, user_data,
- DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH);
+ 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, GPU_enable_material, NULL, user_data, 0);
}
if (use_light) {
@@ -1279,7 +1279,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 28f806a9b7b..1cbc8e5567c 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -2953,21 +2953,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);
@@ -3375,7 +3377,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 {
@@ -3773,7 +3774,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
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);
@@ -6859,15 +6860,18 @@ 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) {
+ DM_update_materials(dm, ob);
+ }
+
if (dm) {
has_faces = dm->getNumTessFaces(dm) > 0;
}
@@ -7975,7 +7979,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, 0);
if (check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
@@ -7987,7 +7991,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, 0);
}
}
@@ -8048,9 +8052,9 @@ static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
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, 0);
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/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 59798f97d93..a220e1e39b0 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"
@@ -53,8 +50,6 @@
#include "ED_mesh.h"
-#include "BLF_api.h"
-
#include "view3d_intern.h" // own include
struct GPUTexture;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index b3accb431ee..55d5273b198 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -414,7 +414,7 @@ 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);
}
@@ -599,7 +599,7 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
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;
@@ -665,10 +665,14 @@ static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *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");
+ }
}
@@ -950,8 +954,9 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
case NC_GPENCIL:
- if (wmn->action == NA_EDITED)
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
ED_region_tag_redraw(ar);
+ }
break;
}
}
@@ -1007,6 +1012,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;
}
}
@@ -1104,7 +1113,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:
@@ -1168,7 +1177,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 899be6359ee..88f43ab340f 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -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"
@@ -68,7 +69,6 @@
#include "ED_armature.h"
#include "ED_gpencil.h"
-#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -844,9 +844,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) {
@@ -1185,14 +1185,6 @@ void view3d_buttons_register(ARegionType *art)
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)! */
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index ee0f3da18b4..95e918abdcf 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 */
@@ -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 e921a436c85..65721d52dff 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -787,7 +787,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");
@@ -1362,7 +1371,7 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
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);
@@ -2646,10 +2655,7 @@ static void view3d_draw_objects(
if (!draw_offscreen) {
/* 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) {
@@ -2659,6 +2665,7 @@ static void view3d_draw_objects(
else {
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
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);
@@ -2801,6 +2808,203 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
gpu_update_lamps_shadows(scene, v3d);
}
+/*
+ * Function to clear the view
+ */
+static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool force)
+{
+ /* clear background */
+ if (scene->world && ((v3d->flag3 & V3D_SHOW_WORLD) || force)) {
+ float alpha = (force) ? 1.0f : 0.0;
+ 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);
+
+ /* calculate full shader for background */
+ GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, (v3d->scenelock != 0));
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_QUADS);
+ 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);
+
+ 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] = alpha * 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], alpha);
+ 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_ThemeClearColor(TH_HIGH_GRAD);
+ 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
*/
@@ -2808,6 +3012,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
float viewmat[4][4], float winmat[4][4],
bool do_bgpic, bool do_sky)
{
+ struct bThemeState theme_state;
int bwinx, bwiny;
rcti brect;
@@ -2825,7 +3030,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 */
@@ -2836,25 +3041,18 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
* warning! can be slow so only free animated images - campbell */
GPU_free_images_anim();
}
-
+ /* setup view matrices */
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+
/* 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, true);
}
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);
@@ -2879,8 +3077,7 @@ 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;
}
@@ -2951,13 +3148,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
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, char err_out[256])
{
View3D v3d = {NULL};
ARegion ar = {NULL};
@@ -2972,6 +3169,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;
@@ -3205,178 +3405,6 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A
ED_region_info_draw(ar, rv3d->render_engine->text, 1, fill_color);
}
-/*
- * Function to clear the view
- */
-static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
-{
- /* 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;
- }
- }
-
- 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] = 0;
- }
- }
-
- 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], 0.0f);
- 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_ThemeClearColor(TH_HIGH_GRAD);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
- }
-}
-
-
#ifdef WITH_GAMEENGINE
static void update_lods(Scene *scene, float camera_pos[3])
{
@@ -3422,7 +3450,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
#endif
/* clear the background */
- view3d_main_area_clear(scene, v3d, ar);
+ view3d_main_area_clear(scene, v3d, ar, false);
/* enables anti-aliasing for 3D view drawing */
if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index d3bd59cacc8..aab307babe8 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -49,7 +49,6 @@
#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"
@@ -626,9 +625,9 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
* 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 {
@@ -1119,6 +1118,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 +1154,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 +1230,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 {
@@ -1946,6 +1960,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 +1988,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)
@@ -2214,6 +2238,8 @@ 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,16 +2270,25 @@ 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)
@@ -2315,6 +2350,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 +2425,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;
}
@@ -2486,6 +2524,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 +2552,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)
@@ -2926,8 +2975,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 {
@@ -3970,6 +4021,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,16 +4049,25 @@ 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);
}
- return OPERATOR_RUNNING_MODAL;
+ if (ret & OPERATOR_FINISHED) {
+ viewops_data_free(C, op);
+ }
+
+ return ret;
}
static EnumPropertyItem prop_view_roll_items[] = {
@@ -4279,32 +4341,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);
@@ -4330,7 +4376,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);
}
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 4c19f59a148..11ed9867e2f 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -32,12 +32,9 @@
#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"
@@ -45,8 +42,6 @@
#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"
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 84ac4f7d02d..d3a9f5ca967 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -163,7 +163,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,
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 6a505959820..5df348408df 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);
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 48bc6448194..eba31866f54 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.
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 08a69830c03..38ecbed3b5f 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 */
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index 0e17d8fc354..f127f375a9f 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -39,7 +39,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 9faca757c62..5a3893f733f 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"
@@ -55,7 +53,6 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_draw.h"
#include "GPU_select.h"
#include "WM_api.h"
@@ -64,14 +61,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 */
@@ -356,6 +355,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 +382,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 +496,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);
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 9b9b7a8d258..191eeb05c71 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -42,8 +42,6 @@
#include "BLF_translation.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "BIF_gl.h"
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 9547f0bc77f..b727b96c8cc 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -200,6 +200,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)
@@ -579,7 +585,10 @@ void removeAspectRatio(TransInfo *t, float vec[2])
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);
@@ -2007,6 +2016,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;
@@ -4061,6 +4076,11 @@ static void initTranslation(TransInfo *t)
t->snap[1] = ED_node_grid_size() * NODE_GRID_STEPS;
t->snap[2] = ED_node_grid_size();
}
+ else if (t->spacetype == SPACE_IPO) {
+ t->snap[0] = 0.0f;
+ t->snap[1] = 1.0;
+ t->snap[2] = 0.1f;
+ }
else {
t->snap[0] = 0.0f;
t->snap[1] = t->snap[2] = 1.0f;
@@ -5837,12 +5857,12 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
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)) {
+ if (BM_vert_in_face(sv->v_b, l_ed_sel->radial_next->f)) {
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)) {
+ if (BM_vert_in_face(sv->v_a, l_ed_sel->radial_next->f)) {
f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
}
}
@@ -5902,18 +5922,18 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
BMLoop *l_adj = NULL;
if (sld->perc < 0.0f) {
- if (BM_vert_in_face(e_sel->l->f, sv->v_b)) {
+ if (BM_vert_in_face(sv->v_b, e_sel->l->f)) {
l_adj = e_sel->l;
}
- else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_b)) {
+ else if (BM_vert_in_face(sv->v_b, e_sel->l->radial_next->f)) {
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)) {
+ if (BM_vert_in_face(sv->v_a, e_sel->l->f)) {
l_adj = e_sel->l;
}
- else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_a)) {
+ else if (BM_vert_in_face(sv->v_a, e_sel->l->radial_next->f)) {
l_adj = e_sel->l->radial_next;
}
}
@@ -7121,10 +7141,11 @@ static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN])
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
}
-static void applySeqSlideValue(TransInfo *t, const float val[2])
+static void applySeqSlideValue(TransInfo *t, const float val[2], int frame)
{
TransData *td = t->data;
int i;
+ TransSeq *ts = t->customData;
for (i = 0; i < t->total; i++, td++) {
float tvec[2];
@@ -7139,15 +7160,21 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
mul_v2_fl(tvec, td->factor);
- td->loc[0] = td->iloc[0] + tvec[0];
+ if (t->modifiers & MOD_SNAP_INVERT) {
+ td->loc[0] = frame + td->factor * (td->iloc[0] - ts->min);
+ }
+ else {
+ td->loc[0] = td->iloc[0] + tvec[0];
+ }
+
td->loc[1] = td->iloc[1] + tvec[1];
}
}
-static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
+static void applySeqSlide(TransInfo *t, const int mval[2])
{
char str[MAX_INFO_LEN];
-
+ int snap_frame = 0;
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
@@ -7155,7 +7182,8 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
copy_v3_v3(t->values, tvec);
}
else {
- snapGridIncrement(t, t->values);
+ snap_frame = snapSequenceBounds(t, mval);
+ // snapGridIncrement(t, t->values);
applyNumInput(&t->num, t->values);
}
@@ -7163,7 +7191,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
t->values[1] = floor(t->values[1] + 0.5f);
headerSeqSlide(t, t->values, str);
- applySeqSlideValue(t, t->values);
+ applySeqSlideValue(t, t->values, snap_frame);
recalcData(t);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 67d55639528..0d824be862e 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -173,6 +173,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 */
@@ -545,6 +552,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);
@@ -588,6 +596,8 @@ typedef enum {
void snapGridIncrement(TransInfo *t, float *val);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action);
+int snapSequenceBounds(TransInfo *t, const int mval[2]);
+
bool activeSnap(TransInfo *t);
bool validSnap(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index e2859b2821a..c1350b1f076 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -54,7 +54,6 @@
#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"
@@ -90,7 +89,6 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
-#include "BKE_lattice.h"
#include "BIK_api.h"
@@ -107,6 +105,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 +217,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 +241,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) {
@@ -251,6 +258,10 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
dist_sq = len_squared_v3(vec);
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 {
@@ -2806,8 +2817,8 @@ void flushTransUVs(TransInfo *t)
td->loc2d[1] = td->loc[1] * invy;
if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
- td->loc2d[0] = floorf(width * td->loc2d[0] + 0.5f) / width;
- td->loc2d[1] = floorf(height * td->loc2d[1] + 0.5f) / height;
+ td->loc2d[0] = roundf(width * td->loc2d[0]) / width;
+ td->loc2d[1] = roundf(height * td->loc2d[1]) / height;
}
}
}
@@ -3769,7 +3780,6 @@ 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);
@@ -3804,7 +3814,12 @@ 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;
+
+ /* 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)
*/
@@ -3812,45 +3827,27 @@ 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;
-
- if (is_translation_mode) {
- /* for 'normal' pivots - just include anything that is selected.
- * this works a bit differently in translation modes */
- if (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_translation_mode || !(sel2)) {
+ if (sel1) {
count++;
}
- else {
- if (sel1) 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++;
+
+ if (sel3) {
+ 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++;
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ count++;
}
}
}
@@ -3899,8 +3896,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);
+ bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
float unit_scale;
+ float cfra;
+
+ /* 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)
@@ -3909,19 +3911,15 @@ 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);
/* 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 */
@@ -4528,10 +4526,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);
@@ -4694,6 +4729,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;
}
@@ -4713,6 +4750,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;
@@ -4723,12 +4762,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 {
@@ -4768,15 +4806,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
}
@@ -5572,7 +5614,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
- 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... */
@@ -7239,6 +7284,230 @@ 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 int propedit = (t->flag & T_PROP_EDIT);
+ const int propedit_connected = (t->flag & T_PROP_CONNECTED);
+
+
+ /* == 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) {
+ if (propedit) {
+ /* Proportional Editing... */
+ if (propedit_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;
+
+ /* What we need to include depends on proportional editing settings... */
+ if (propedit) {
+ if (propedit_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 propedit 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 (propedit) {
+ /* 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;
+
+ /* 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 (propedit && (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;
@@ -7259,6 +7528,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) {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 52f02e5dc86..fcf789546e8 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -109,21 +109,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]);
@@ -975,6 +961,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);
}
@@ -1205,7 +1194,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* exceptional case */
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 (!use_island) {
+ t->options |= CTX_NO_PET;
+ }
}
}
@@ -1325,6 +1318,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
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) {
if (ts->proportional_mask) {
t->flag |= T_PROP_EDIT;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index ece681b228e..25dee50a192 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -324,6 +324,9 @@ static void transformops_loopsel_hack(bContext *C, wmOperator *op)
}
}
}
+#else
+/* prevent removal by cleanup */
+# error "loopslide hack removed!"
#endif /* USE_LOOPSLIDE_HACK */
@@ -543,7 +546,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 +585,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 +605,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)
@@ -652,7 +659,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
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);
- 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)
@@ -675,7 +682,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
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);
- 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 +728,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 +748,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?
}
@@ -803,7 +810,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,7 +828,7 @@ 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)
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index ba93d4463b7..79262396fb4 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>
@@ -57,10 +56,6 @@
#include "ED_armature.h"
-#include "RNA_define.h"
-
-#include "UI_interface.h"
-
#include "transform.h"
/* *********************** TransSpace ************************** */
@@ -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;
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index cd636591212..4a2927ace00 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"
@@ -2430,6 +2431,27 @@ void snapGridIncrement(TransInfo *t, float *val)
snapGridIncrementAction(t, val, action);
}
+int 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 0;
+
+ /* 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);
+
+ if (!ts->snap_left)
+ frame = frame - (ts->max - ts->min);
+
+ return frame;
+}
static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action)
{
@@ -2457,6 +2479,19 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1);
}
}
+ else if ((t->spacetype == SPACE_IPO) && (t->mode == TFM_TRANSLATION)) {
+ 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[0], &asp[1]);
+ UI_view2d_grid_free(grid);
+ }
for (i = 0; i <= max_index; i++) {
val[i] = fac[action] * asp[i] * floorf(val[i] / (fac[action] * asp[i]) + 0.5f);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 86b96968047..32d4f2e5a15 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -174,7 +174,7 @@ bool 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);
}
}
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index ef95e4cb3ff..2428ee21367 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"
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 6c0efad6f26..fac57490b44 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>
@@ -47,6 +45,7 @@
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_screen.h"
#include "ED_armature.h"
@@ -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);
@@ -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);
@@ -583,7 +583,7 @@ static int undo_history_exec(bContext *C, wmOperator *op)
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/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index d0db3595c37..a15259e7d2d 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -53,7 +53,6 @@
#include "ED_uvedit.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 4c93cfa2cc5..b2c4970479a 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"
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 8865bc6775b..d1fd8d969a4 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -72,7 +72,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 BMesh *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 b58944e4003..c70fcdbbd94 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -3189,8 +3189,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)
@@ -3877,6 +3877,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);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 79f53e1d971..569fe1c326d 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>
@@ -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;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 9359baa5020..c5931cf2943 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -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;
@@ -1660,7 +1659,7 @@ static int stitch_init(bContext *C, wmOperator *op)
return 0;
}
- uvedit_get_aspect(scene, obedit, em->bm, &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.
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 6a33351753e..b5e27ab0cf6 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -190,7 +190,7 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit)
return false;
}
-void uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, 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;
@@ -264,7 +264,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
if (correct_aspect) {
float aspx, aspy;
- uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
if (aspx != aspy)
param_aspect_ratio(handle, aspx, aspy);
@@ -376,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->bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
if (aspx != aspy)
param_aspect_ratio(handle, aspx, aspy);
@@ -1010,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->bm, &aspx, &aspy);
+ ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
if (aspx == aspy)
return;