diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-16 14:50:11 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-16 14:50:11 +0300 |
commit | 6cd3ebfc9fa4838a74192f2e5cc82b5d5d2e6fe7 (patch) | |
tree | 546c8e187f3b5185f019153ee083fa246b698436 /source/blender/editors | |
parent | 97a50e78ca88b4ffe180bc6567e5ed0358239efe (diff) | |
parent | 5684ad80723454f0d910aad3fa48240da19c4e3b (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')
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, >d); - + /* 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 = <->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(<->id); + BKE_object_defgroup_data_create(<->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; |