diff options
author | Sergej Reich <sergej.reich@googlemail.com> | 2013-09-06 12:35:00 +0400 |
---|---|---|
committer | Sergej Reich <sergej.reich@googlemail.com> | 2013-09-06 12:35:00 +0400 |
commit | 36e6bddb5c155b4ae27a9cd17b4af26bbcdc8dae (patch) | |
tree | 025a56b2e71adc77d53a4a33ac17a6cf55d360c2 /source/blender/editors | |
parent | df3974b6d1c6469ca1a0b8a1c505b09385198780 (diff) | |
parent | 63ade11564798e68943ad5d8c82d45771df67677 (diff) |
svn merge -r59229:59868 ^/trunk/blender
Diffstat (limited to 'source/blender/editors')
138 files changed, 4143 insertions, 1587 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 845ad72d7aa..142342997be 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -1828,7 +1828,7 @@ static void *acf_dsmball_setting_ptr(bAnimListElem *ale, int setting, short *typ switch (setting) { case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(mb->flag, type); + return GET_ACF_FLAG_PTR(mb->flag2, type); case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ @@ -2781,6 +2781,9 @@ static void ANIM_init_channel_typeinfo_data(void) if (ACF_INIT) { ACF_INIT = 0; + /* NOTE: need to keep the order of these synchronized with the definition of + * channel types (eAnim_ChannelType) in ED_anim_api.h + */ animchannelTypeInfo[type++] = NULL; /* None */ animchannelTypeInfo[type++] = NULL; /* AnimData */ animchannelTypeInfo[type++] = NULL; /* Special */ @@ -2808,8 +2811,8 @@ static void ANIM_init_channel_typeinfo_data(void) animchannelTypeInfo[type++] = &ACF_DSMESH; /* Mesh Channel */ animchannelTypeInfo[type++] = &ACF_DSTEX; /* Texture Channel */ animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */ - animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */ + animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 91003674524..041a2c2216e 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1541,10 +1541,16 @@ static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data, static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) { SceneRenderLayer *srl; + FreestyleLineSet *lineset; size_t items = 0; for (srl = sce->r.layers.first; srl; srl = srl->next) { - FreestyleLineSet *lineset; + for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + lineset->linestyle->id.flag |= LIB_DOIT; + } + } + + for (srl = sce->r.layers.first; srl; srl = srl->next) { /* skip render layers without Freestyle enabled */ if (!(srl->layflag & SCE_LAY_FRS)) @@ -1555,6 +1561,10 @@ static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data FreestyleLineStyle *linestyle = lineset->linestyle; ListBase tmp_data = {NULL, NULL}; size_t tmp_items = 0; + + if (!(linestyle->id.flag & LIB_DOIT)) + continue; + linestyle->id.flag &= ~LIB_DOIT; /* add scene-level animation channels */ BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle)) @@ -2533,13 +2543,13 @@ static size_t animdata_filter_remove_invalid(ListBase *anim_data) static size_t animdata_filter_remove_duplis(ListBase *anim_data) { bAnimListElem *ale, *next; - GHash *gh; + GSet *gs; size_t items = 0; /* build new hashtable to efficiently store and retrieve which entries have been * encountered already while searching */ - gh = BLI_ghash_ptr_new("animdata_filter_duplis_remove gh"); + gs = BLI_gset_ptr_new(__func__); /* loop through items, removing them from the list if a similar item occurs already */ for (ale = anim_data->first; ale; ale = next) { @@ -2549,9 +2559,8 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) * - just use ale->data for now, though it would be nicer to involve * ale->type in combination too to capture corner cases (where same data performs differently) */ - if (BLI_ghash_haskey(gh, ale->data) == 0) { + if (BLI_gset_reinsert(gs, ale->data, NULL)) { /* this entry is 'unique' and can be kept */ - BLI_ghash_insert(gh, ale->data, NULL); items++; } else { @@ -2561,7 +2570,7 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) } /* free the hash... */ - BLI_ghash_free(gh, NULL, NULL); + BLI_gset_free(gs, NULL); /* return the number of items still in the list */ return items; diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index df93da8b7c1..826e204d981 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -75,7 +75,8 @@ void free_anim_drivers_copybuf(void); * for the given Animation Data block. This assumes that all the destinations are valid. * * - add: 0 - don't add anything if not found, - * 1 - add new Driver FCurve, + * 1 - add new Driver FCurve (with keyframes for visual tweaking), + * 2 - add new Driver FCurve (with generator, for script backwards compatability) * -1 - add new Driver FCurve without driver stuff (for pasting) */ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add) @@ -114,11 +115,38 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */ if (add > 0) { + BezTriple *bezt; + size_t i; + /* add some new driver data */ fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); + fcu->driver->flag |= DRIVER_FLAG_SHOWDEBUG; - /* add simple generator modifier for driver so that there is some visible representation */ - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + /* F-Modifier or Keyframes? */ + // FIXME: replace these magic numbers with defines + if (add == 2) { + /* Python API Backwards compatability hack: + * Create FModifier so that old scripts won't break + * for now before 2.7 series -- (September 4, 2013) + */ + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + } + else { + /* add 2 keyframes so that user has something to work with + * - These are configured to 0,0 and 1,1 to give a 1-1 mapping + * which can be easily tweaked from there. + */ + insert_vert_fcurve(fcu, 0.0f, 0.0f, INSERTKEY_FAST); + insert_vert_fcurve(fcu, 1.0f, 1.0f, INSERTKEY_FAST); + + /* configure this curve to extrapolate */ + for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) { + bezt->h1 = bezt->h2 = HD_VECT; + } + + fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; + calchandles_fcurve(fcu); + } } /* just add F-Curve to end of driver list */ @@ -166,8 +194,10 @@ short ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int ar /* will only loop once unless the array index was -1 */ for (; array_index < array_index_max; array_index++) { + short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; + /* create F-Curve with Driver */ - fcu = verify_driver_fcurve(id, rna_path, array_index, 1); + fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode); if (fcu && fcu->driver) { ChannelDriver *driver = fcu->driver; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 63acc5a943c..cfc03050a9e 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -256,7 +256,7 @@ int insert_bezt_fcurve(FCurve *fcu, BezTriple *bezt, short flag) dst->f1 = bezt->f1; dst->f2 = bezt->f2; dst->f3 = bezt->f3; - + /* TODO: perform some other operations? */ } } diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 22bd22c8561..0301db4b4cf 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -255,7 +255,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, bDeformGroup *dgroup; bPoseChannel *pchan; Mesh *mesh; - Mat4 *bbone = NULL; + Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL; float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; int numbones, vertsfilled = 0, i, j, segments = 0; @@ -309,7 +309,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) { if (bone->segments > 1) { segments = bone->segments; - bbone = b_bone_spline_setup(pchan, 1); + b_bone_spline_setup(pchan, 1, bbone_array); + bbone = bbone_array; } } } diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 76068c122bf..16d7f9c9420 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -281,7 +281,7 @@ static void laplacian_system_construct_end(LaplacianSystem *sys) sys->varea = MEM_callocN(sizeof(float) * totvert, "LaplacianSystemVarea"); - sys->edgehash = BLI_edgehash_new(); + sys->edgehash = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(sys->totface)); for (a = 0, face = sys->faces; a < sys->totface; a++, face++) { laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]); laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]); diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index f66fb38a2a6..3a09f531d44 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -198,7 +198,7 @@ ReebGraph *newReebGraph(void) rg = MEM_callocN(sizeof(ReebGraph), "reeb graph"); rg->totnodes = 0; - rg->emap = BLI_edgehash_new(); + rg->emap = BLI_edgehash_new(__func__); rg->free_arc = REEB_freeArc; diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index d197697e60b..8a5e4b338d3 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -76,6 +76,7 @@ void CURVE_OT_hide(struct wmOperatorType *ot); void CURVE_OT_reveal(struct wmOperatorType *ot); void CURVE_OT_separate(struct wmOperatorType *ot); +void CURVE_OT_split(struct wmOperatorType *ot); void CURVE_OT_duplicate(struct wmOperatorType *ot); void CURVE_OT_delete(struct wmOperatorType *ot); diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 2452a5d1a4b..1cf194e02c4 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -87,6 +87,7 @@ void ED_operatortypes_curve(void) WM_operatortype_append(CURVE_OT_reveal); WM_operatortype_append(CURVE_OT_separate); + WM_operatortype_append(CURVE_OT_split); WM_operatortype_append(CURVE_OT_duplicate); WM_operatortype_append(CURVE_OT_delete); @@ -244,6 +245,7 @@ void ED_keymap_curve(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "deselect", TRUE); WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "CURVE_OT_make_segment", FKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 660f8098a38..ce0881b2e11 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -106,11 +106,25 @@ typedef struct { Nurb *orig_nu; } CVKeyIndex; -void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus); -static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus); - -/* still need to eradicate a few :( */ -#define CALLOC_STRUCT_N(x, y, name) (x *)MEM_callocN((y) * sizeof(x), name) +typedef enum eVisible_Types { + HIDDEN = true, + VISIBLE = false, +} eVisible_Types; + +typedef enum eEndPoint_Types { + FIRST = true, + LAST = false, +} eEndPoint_Types; + +typedef enum eCurveElem_Types { + CURVE_VERTEX = 0, + CURVE_SEGMENT, +} eCurveElem_Types; + +void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus); +static void select_adjacent_cp(ListBase *editnurb, short next, const bool cont, const bool selstatus); +static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split); +static int curve_delete_selected(Object *obedit, const eCurveElem_Types type, const bool split); static float nurbcircle[8][2] = { {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0}, @@ -149,69 +163,59 @@ static Nurb *get_actNurb(Object *obedit) /* ******************* SELECTION FUNCTIONS ********************* */ -#define HIDDEN 1 -#define VISIBLE 0 - -#define FIRST 1 -#define LAST 0 - /* returns 1 in case (de)selection was successful */ -static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden) +static bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden) { - if (bezt) { - if ((bezt->hide == 0) || (hidden == 1)) { - if (selstatus == 1) { /* selects */ - bezt->f1 |= flag; - bezt->f2 |= flag; - bezt->f3 |= flag; - return 1; - } - else { /* deselects */ - bezt->f1 &= ~flag; - bezt->f2 &= ~flag; - bezt->f3 &= ~flag; - return 1; - } + if ((bezt->hide == 0) || (hidden == HIDDEN)) { + if (selstatus == SELECT) { /* selects */ + bezt->f1 |= flag; + bezt->f2 |= flag; + bezt->f3 |= flag; + return true; + } + else { /* deselects */ + bezt->f1 &= ~flag; + bezt->f2 &= ~flag; + bezt->f3 &= ~flag; + return true; } } - return 0; + return false; } /* returns 1 in case (de)selection was successful */ -static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden) +static bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden) { - if (bp) { - if ((bp->hide == 0) || (hidden == 1)) { - if (selstatus == 1) { - bp->f1 |= flag; - return 1; - } - else { - bp->f1 &= ~flag; - return 1; - } + if ((bp->hide == 0) || (hidden == 1)) { + if (selstatus == SELECT) { + bp->f1 |= flag; + return true; + } + else { + bp->f1 &= ~flag; + return true; } } - return 0; + return false; } -static short swap_selection_beztriple(BezTriple *bezt) +static bool swap_selection_beztriple(BezTriple *bezt) { if (bezt->f2 & SELECT) - return select_beztriple(bezt, DESELECT, 1, VISIBLE); + return select_beztriple(bezt, DESELECT, SELECT, VISIBLE); else - return select_beztriple(bezt, SELECT, 1, VISIBLE); + return select_beztriple(bezt, SELECT, SELECT, VISIBLE); } -static short swap_selection_bpoint(BPoint *bp) +static bool swap_selection_bpoint(BPoint *bp) { if (bp->f1 & SELECT) - return select_bpoint(bp, DESELECT, 1, VISIBLE); + return select_bpoint(bp, DESELECT, SELECT, VISIBLE); else - return select_bpoint(bp, SELECT, 1, VISIBLE); + return select_bpoint(bp, SELECT, SELECT, VISIBLE); } int isNurbsel(Nurb *nu) @@ -361,7 +365,7 @@ static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, void *cv) static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, void *cv) { - return BLI_ghash_pop(editnurb->keyindex, cv, NULL); + return BLI_ghash_popkey(editnurb->keyindex, cv, NULL); } static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, BezTriple *bezt) @@ -674,7 +678,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex) GHash *gh; GHashIterator *hashIter; - gh = BLI_ghash_ptr_new("dupli_keyIndex gh"); + gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex)); for (hashIter = BLI_ghashIterator_new(keyindex); BLI_ghashIterator_done(hashIter) == false; @@ -1463,6 +1467,49 @@ void CURVE_OT_separate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/******************** split operator ***********************/ + +static int curve_split_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + ListBase newnurb = {NULL, NULL}; + + adduplicateflagNurb(obedit, &newnurb, SELECT, true); + + if (newnurb.first != NULL) { + curve_delete_selected(obedit, CURVE_SEGMENT, true); + BLI_movelisttolist(editnurb, &newnurb); + + if (ED_curve_updateAnimPaths(obedit->data)) + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + } + else { + BKE_report(op->reports, RPT_ERROR, "Cannot split current selection"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +void CURVE_OT_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split"; + ot->idname = "CURVE_OT_split"; + ot->description = "Split off selected points from connected unselected points"; + + /* api callbacks */ + ot->exec = curve_split_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ******************* FLAGS ********************* */ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag) @@ -1614,9 +1661,8 @@ static void weightflagNurb(ListBase *editnurb, short flag, float w) } } -static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag) +static int deleteflagNurb(Object *obedit, short flag) { - Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu, *next; @@ -1744,9 +1790,6 @@ static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag) nu = next; } - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - return OPERATOR_FINISHED; } @@ -1869,40 +1912,54 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag) return ok; } -static void adduplicateflagNurb(Object *obedit, short flag) +static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, + const short flag, const bool split) { ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu, *newnu; + Nurb *nu, *newnu, *startnu; BezTriple *bezt, *bezt1; BPoint *bp, *bp1; Curve *cu = (Curve *)obedit->data; - int a, b, starta, enda, newu, newv; + int a, b, starta, enda, diffa, newu, newv; char *usel; cu->lastsel = NULL; nu = editnurb->last; while (nu) { + startnu = NULL; if (nu->type == CU_BEZIER) { bezt = nu->bezt; for (a = 0; a < nu->pntsu; a++) { enda = -1; starta = a; while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) { - select_beztriple(bezt, DESELECT, flag, HIDDEN); + if (!split) select_beztriple(bezt, DESELECT, flag, HIDDEN); enda = a; if (a >= nu->pntsu - 1) break; a++; bezt++; } if (enda >= starta) { - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN"); - memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(editnurb, newnu); - set_actNurb(obedit, newnu); - newnu->pntsu = enda - starta + 1; - newnu->bezt = (BezTriple *)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN"); - memcpy(newnu->bezt, &nu->bezt[starta], newnu->pntsu * sizeof(BezTriple)); + diffa = enda - starta + 1; + + if (startnu != NULL && enda == nu->pntsu - 1) { + /* end point of cyclic spline selected, so merge end points with start points */ + bezt1 = (BezTriple *)MEM_mallocN((startnu->pntsu + diffa) * sizeof(BezTriple), "adduplicateN"); + memcpy(bezt1, &nu->bezt[starta], diffa * sizeof(BezTriple)); + memcpy(&bezt1[diffa], startnu->bezt, startnu->pntsu * sizeof(BezTriple)); + + MEM_freeN(startnu->bezt); + startnu->bezt = bezt1; + startnu->pntsu += diffa; + newnu = startnu; + } + else { + newnu = ED_curve_nurbcpy(nu, diffa); + BLI_addtail(newnurb, newnu); + set_actNurb(obedit, newnu); + memcpy(newnu->bezt, &nu->bezt[starta], newnu->pntsu * sizeof(BezTriple)); + } b = newnu->pntsu; bezt1 = newnu->bezt; @@ -1914,6 +1971,7 @@ static void adduplicateflagNurb(Object *obedit, short flag) if (nu->flagu & CU_NURB_CYCLIC) { if (starta != 0 || enda != nu->pntsu - 1) { newnu->flagu &= ~CU_NURB_CYCLIC; + if (starta == 0) startnu = newnu; } } } @@ -1926,20 +1984,32 @@ static void adduplicateflagNurb(Object *obedit, short flag) enda = -1; starta = a; while (bp->f1 & flag) { - select_bpoint(bp, DESELECT, flag, HIDDEN); + if (!split) select_bpoint(bp, DESELECT, flag, HIDDEN); enda = a; if (a >= nu->pntsu - 1) break; a++; bp++; } if (enda >= starta) { - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN3"); - memcpy(newnu, nu, sizeof(Nurb)); - set_actNurb(obedit, newnu); - BLI_addtail(editnurb, newnu); - newnu->pntsu = enda - starta + 1; - newnu->bp = (BPoint *)MEM_mallocN((enda - starta + 1) * sizeof(BPoint), "adduplicateN4"); - memcpy(newnu->bp, &nu->bp[starta], newnu->pntsu * sizeof(BPoint)); + diffa = enda - starta + 1; + + if (startnu != NULL && enda == nu->pntsu - 1) { + /* end point of cyclic spline selected, so merge end points with start points */ + bp1 = (BPoint *)MEM_mallocN((startnu->pntsu + diffa) * sizeof(BPoint), "adduplicateN2"); + memcpy(bp1, &nu->bp[starta], diffa * sizeof(BPoint)); + memcpy(&bp1[diffa], startnu->bp, startnu->pntsu * sizeof(BPoint)); + + MEM_freeN(startnu->bp); + startnu->bp = bp1; + startnu->pntsu += diffa; + newnu = startnu; + } + else { + newnu = ED_curve_nurbcpy(nu, diffa); + BLI_addtail(newnurb, newnu); + set_actNurb(obedit, newnu); + memcpy(newnu->bp, &nu->bp[starta], newnu->pntsu * sizeof(BPoint)); + } b = newnu->pntsu; bp1 = newnu->bp; @@ -1951,12 +2021,9 @@ static void adduplicateflagNurb(Object *obedit, short flag) if (nu->flagu & CU_NURB_CYCLIC) { if (starta != 0 || enda != nu->pntsu - 1) { newnu->flagu &= ~CU_NURB_CYCLIC; + if (starta == 0) startnu = newnu; } } - - /* knots */ - newnu->knotsu = NULL; - BKE_nurb_knot_calc_u(newnu); } bp++; } @@ -1964,7 +2031,7 @@ static void adduplicateflagNurb(Object *obedit, short flag) else { /* a rectangular area in nurb has to be selected */ if (isNurbsel(nu)) { - usel = MEM_callocN(nu->pntsu, "adduplicateN4"); + usel = MEM_callocN(nu->pntsu, "adduplicateN3"); bp = nu->bp; for (a = 0; a < nu->pntsv; a++) { for (b = 0; b < nu->pntsu; b++, bp++) { @@ -1993,13 +2060,13 @@ static void adduplicateflagNurb(Object *obedit, short flag) if (newu == 1) SWAP(int, newu, newv); - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN5"); + newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN4"); memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(editnurb, newnu); + BLI_addtail(newnurb, newnu); set_actNurb(obedit, newnu); newnu->pntsu = newu; newnu->pntsv = newv; - newnu->bp = (BPoint *)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6"); + newnu->bp = (BPoint *)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN5"); BKE_nurb_order_clamp_u(newnu); BKE_nurb_order_clamp_v(newnu); @@ -2040,6 +2107,22 @@ static void adduplicateflagNurb(Object *obedit, short flag) nu = nu->prev; } + for (nu = newnurb->first; nu; nu = nu->next) { + /* knots done after duplicate as pntsu may change */ + if (nu->pntsv == 1) { + nu->knotsu = NULL; + BKE_nurb_knot_calc_u(nu); + } + + if (split) { + if (nu->type == CU_BEZIER) { + /* recalc first and last */ + BKE_nurb_handle_calc_simple(nu, &nu->bezt[0]); + BKE_nurb_handle_calc_simple(nu, &nu->bezt[nu->pntsu - 1]); + } + } + } + /* actnu changed */ } @@ -2513,7 +2596,8 @@ void CURVE_OT_smooth_tilt(wmOperatorType *ot) /* next == -1 -> select previous */ /* cont == 1 -> select continuously */ /* selstatus, inverts behavior */ -static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus) +static void select_adjacent_cp(ListBase *editnurb, short next, + const bool cont, const bool selstatus) { Nurb *nu; BezTriple *bezt; @@ -2531,10 +2615,10 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short if (next < 0) bezt = &nu->bezt[a - 1]; while (a--) { if (a - abs(next) < 0) break; - if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == 0))) { + if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) { bezt += next; - if (!(bezt->f2 & SELECT) || (selstatus == 0)) { - short sel = select_beztriple(bezt, selstatus, 1, VISIBLE); + if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) { + short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); if ((sel == 1) && (cont == 0)) lastsel = true; } } @@ -2552,10 +2636,10 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short if (next < 0) bp = &nu->bp[a - 1]; while (a--) { if (a - abs(next) < 0) break; - if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == 0))) { + if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) { bp += next; - if (!(bp->f1 & SELECT) || (selstatus == 0)) { - short sel = select_bpoint(bp, selstatus, 1, VISIBLE); + if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) { + short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); if ((sel == 1) && (cont == 0)) lastsel = true; } } @@ -2577,7 +2661,7 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short * doswap: defines if selection state of each first/last control point is swapped * selstatus: selection status in case doswap is false */ -void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus) +void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus) { ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu; @@ -2596,7 +2680,7 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatu a = nu->pntsu; /* which point? */ - if (selfirst == 0) { /* select last */ + if (selfirst == LAST) { /* select last */ bezt = &nu->bezt[a - 1]; } else { /* select first */ @@ -2604,18 +2688,18 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatu } while (a--) { - short sel; + bool sel; if (doswap) sel = swap_selection_beztriple(bezt); - else sel = select_beztriple(bezt, selstatus, 1, VISIBLE); + else sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); - if (sel == 1) break; + if (sel == true) break; } } else { a = nu->pntsu * nu->pntsv; /* which point? */ - if (selfirst == 0) { /* select last */ + if (selfirst == LAST) { /* select last */ bp = &nu->bp[a - 1]; } else { /* select first */ @@ -2624,11 +2708,11 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatu while (a--) { if (bp->hide == 0) { - short sel; + bool sel; if (doswap) sel = swap_selection_bpoint(bp); - else sel = select_bpoint(bp, selstatus, 1, VISIBLE); + else sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); - if (sel == 1) break; + if (sel == true) break; } } } @@ -2639,7 +2723,7 @@ static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); - selectend_nurb(obedit, FIRST, 1, DESELECT); + selectend_nurb(obedit, FIRST, true, DESELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -2664,7 +2748,7 @@ static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); - selectend_nurb(obedit, LAST, 1, DESELECT); + selectend_nurb(obedit, LAST, true, DESELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -2789,11 +2873,11 @@ static int hide_exec(bContext *C, wmOperator *op) sel = 0; while (a--) { if (invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); bezt->hide = 1; } else if (invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); bezt->hide = 1; } if (bezt->hide) sel++; @@ -2807,11 +2891,11 @@ static int hide_exec(bContext *C, wmOperator *op) sel = 0; while (a--) { if (invert == 0 && (bp->f1 & SELECT)) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); bp->hide = 1; } else if (invert && (bp->f1 & SELECT) == 0) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); bp->hide = 1; } if (bp->hide) sel++; @@ -2863,7 +2947,7 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu; while (a--) { if (bezt->hide) { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); bezt->hide = 0; } bezt++; @@ -2874,7 +2958,7 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu * nu->pntsv; while (a--) { if (bp->hide) { - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); bp->hide = 0; } bp++; @@ -3840,7 +3924,7 @@ static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu for (u = 0; u < nu1->pntsu; u++, bp++) { if (u < origu) { *bp = *bp1; bp1++; - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); } else { *bp = *bp2; bp2++; @@ -4148,7 +4232,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool if (extend) { if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); cu->lastsel = bezt; } else { @@ -4160,13 +4244,13 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } else { cu->lastsel = bp; - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); } } else if (deselect) { if (bezt) { if (hand == 1) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); if (bezt == cu->lastsel) cu->lastsel = NULL; } else if (hand == 0) { @@ -4177,7 +4261,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } } else { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); if (cu->lastsel == bp) cu->lastsel = NULL; } } @@ -4185,11 +4269,11 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool if (bezt) { if (hand == 1) { if (bezt->f2 & SELECT) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); if (bezt == cu->lastsel) cu->lastsel = NULL; } else { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); cu->lastsel = bezt; } } @@ -4202,11 +4286,11 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } else { if (bp->f1 & SELECT) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); if (cu->lastsel == bp) cu->lastsel = NULL; } else { - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); cu->lastsel = bp; } } @@ -4217,7 +4301,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); cu->lastsel = bezt; } else { @@ -4229,7 +4313,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } else { cu->lastsel = bp; - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); } } @@ -4944,7 +5028,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu; bezt = nu->bezt; while (a--) { - select_beztriple(bezt, SELECT, 1, VISIBLE); + select_beztriple(bezt, SELECT, SELECT, VISIBLE); bezt++; } break; @@ -4960,7 +5044,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a--) { - select_bpoint(bp, SELECT, 1, VISIBLE); + select_bpoint(bp, SELECT, SELECT, VISIBLE); bp++; } break; @@ -5021,8 +5105,8 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent a = nu->pntsu; bezt = nu->bezt; while (a--) { - if (deselect) select_beztriple(bezt, DESELECT, 1, VISIBLE); - else select_beztriple(bezt, SELECT, 1, VISIBLE); + if (deselect) select_beztriple(bezt, DESELECT, SELECT, VISIBLE); + else select_beztriple(bezt, SELECT, SELECT, VISIBLE); bezt++; } } @@ -5030,8 +5114,8 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a--) { - if (deselect) select_bpoint(bp, DESELECT, 1, VISIBLE); - else select_bpoint(bp, SELECT, 1, VISIBLE); + if (deselect) select_bpoint(bp, DESELECT, SELECT, VISIBLE); + else select_bpoint(bp, SELECT, SELECT, VISIBLE); bp++; } } @@ -5103,10 +5187,10 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op)) for (a = 0; a < nu->pntsv; a++) { for (b = 0; b < nu->pntsu; b++, bp++) { if (direction) { - if (a == v) select_bpoint(bp, SELECT, 1, VISIBLE); + if (a == v) select_bpoint(bp, SELECT, SELECT, VISIBLE); } else { - if (b == u) select_bpoint(bp, SELECT, 1, VISIBLE); + if (b == u) select_bpoint(bp, SELECT, SELECT, VISIBLE); } } } @@ -5217,14 +5301,14 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) /* upper control point */ if (a % nu->pntsu != 0) { tempbp = bp - 1; - if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE); } /* left control point. select only if it is not selected already */ if (a - nu->pntsu > 0) { sel = 0; tempbp = bp + nu->pntsu; - if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE); /* make sure selected bpoint is discarded */ if (sel == 1) BLI_BITMAP_SET(selbpoints, a - nu->pntsu); } @@ -5232,14 +5316,14 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) /* right control point */ if (a + nu->pntsu < nu->pntsu * nu->pntsv) { tempbp = bp - nu->pntsu; - if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE); } /* lower control point. skip next bp in case selection was made */ if (a % nu->pntsu != 1) { sel = 0; tempbp = bp + 1; - if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE); if (sel) { bp++; a--; @@ -5341,7 +5425,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } if (sel != 4) { - select_bpoint(bp, DESELECT, 1, VISIBLE); + select_bpoint(bp, DESELECT, SELECT, VISIBLE); BLI_BITMAP_SET(selbpoints, a); } } @@ -5387,7 +5471,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } if (sel != 2) { - select_beztriple(bezt, DESELECT, 1, VISIBLE); + select_beztriple(bezt, DESELECT, SELECT, VISIBLE); lastsel = true; } else { @@ -5429,7 +5513,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } if (sel != 2) { - select_bpoint(bp, DESELECT, 1, VISIBLE); + select_bpoint(bp, DESELECT, SELECT, VISIBLE); lastsel = true; } else { @@ -5481,7 +5565,7 @@ static void selectrandom_curve(ListBase *editnurb, float randfac) a = nu->pntsu; while (a--) { if (BLI_frand() < randfac) - select_beztriple(bezt, SELECT, 1, VISIBLE); + select_beztriple(bezt, SELECT, SELECT, VISIBLE); bezt++; } } @@ -5491,7 +5575,7 @@ static void selectrandom_curve(ListBase *editnurb, float randfac) while (a--) { if (BLI_frand() < randfac) - select_bpoint(bp, SELECT, 1, VISIBLE); + select_bpoint(bp, SELECT, SELECT, VISIBLE); bp++; } } @@ -5534,15 +5618,13 @@ void CURVE_OT_select_random(wmOperatorType *ot) /********************* every nth number of point *******************/ -static int point_on_nurb(Nurb *nu, void *point) +static bool point_in_nurb(Nurb *nu, void *point) { if (nu->bezt) { - BezTriple *bezt = (BezTriple *)point; - return bezt >= nu->bezt && bezt < &nu->bezt[nu->pntsu]; + return ARRAY_HAS_ITEM((BezTriple *)point, nu->bezt, nu->pntsu); } else { - BPoint *bp = (BPoint *)point; - return bp >= nu->bp && bp < &nu->bp[nu->pntsu * nu->pntsv]; + return ARRAY_HAS_ITEM((BPoint *)point, nu->bp, nu->pntsu); } } @@ -5555,7 +5637,7 @@ static Nurb *get_lastsel_nurb(Curve *cu) return NULL; while (nu) { - if (point_on_nurb(nu, cu->lastsel)) + if (point_in_nurb(nu, cu->lastsel)) return nu; nu = nu->next; @@ -5574,7 +5656,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth) while (a--) { if (abs(start - a) % nth) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); } bezt--; @@ -5597,7 +5679,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth) while (a--) { dist = abs(pnt - startpnt) + abs(row - startrow); if (dist % nth) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); } pnt--; @@ -5672,9 +5754,14 @@ void CURVE_OT_select_nth(wmOperatorType *ot) static int duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); + ListBase newnurb = {NULL, NULL}; - adduplicateflagNurb(obedit, 1); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + adduplicateflagNurb(obedit, &newnurb, SELECT, false); + + if (newnurb.first != NULL) { + BLI_movelisttolist(object_editcurve_get(obedit), &newnurb); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } return OPERATOR_FINISHED; } @@ -5696,37 +5783,31 @@ void CURVE_OT_duplicate(wmOperatorType *ot) /********************** delete operator *********************/ -static int delete_exec(bContext *C, wmOperator *op) +static int curve_delete_selected(Object *obedit, eCurveElem_Types type, const bool split) { - Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditNurb *editnurb = cu->editnurb; ListBase *nubase = &editnurb->nurbs; - Nurb *nu, *nu1; + Nurb *nu, *nu1, *startnu; BezTriple *bezt, *bezt1, *bezt2; BPoint *bp, *bp1, *bp2; - int a, cut = 0, type = RNA_enum_get(op->ptr, "type"); + int a, b, starta, enda, cut = 0; int nuindex = 0; + ListBase newnurb = {NULL, NULL}; if (obedit->type == OB_SURF) { - if (type == 0) { - deleteflagNurb(C, op, 1); + if (type == CURVE_VERTEX) { + return deleteflagNurb(obedit, SELECT); } else { keyIndex_delNurbList(editnurb, nubase); BKE_nurbList_free(nubase); - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + return OPERATOR_FINISHED; } - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); - - return OPERATOR_FINISHED; } - if (type == 0) { + if (type == CURVE_VERTEX) { /* first loop, can we remove entire pieces? */ Nurb *next; nu = nubase->first; @@ -5861,204 +5942,343 @@ static int delete_exec(bContext *C, wmOperator *op) nu = next; } } - else if (type == 1) { /* erase segment */ - /* find the 2 selected points */ - bezt1 = bezt2 = NULL; - bp1 = bp2 = NULL; - nu1 = NULL; - nuindex = 0; + else if (type == CURVE_SEGMENT) { for (nu = nubase->first; nu; nu = nu->next) { + startnu = nu1 = NULL; + starta = enda = cut = -1; + if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - for (a = 0; a < nu->pntsu - 1; a++) { - if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { - bezt1 = bezt; - bezt2 = bezt + 1; - if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { - /* pass */ + for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { + if (!BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + enda = a; + if (starta == -1) starta = a; + if (a < nu->pntsu - 1) continue; + } + else if (a < nu->pntsu - 1 && !BEZSELECTED_HIDDENHANDLES(cu, bezt + 1)) { + /* if just single selected point then continue */ + continue; + } + + if (starta >= 0) { + /* got selected segment, now check where and copy */ + if (starta <= 1 && a == nu->pntsu - 1) { + /* copying all points in spline */ + if (starta == 1 && enda != a) nu->flagu &= ~CU_NURB_CYCLIC; + + starta = 0; + enda = a; + cut = enda - starta + 1; + + nu1 = ED_curve_nurbcpy(nu, cut); + } + else if (starta == 0) { + /* if start of curve copy next end point */ + enda++; + cut = enda - starta + 1; + + bezt1 = &nu->bezt[nu->pntsu - 1]; + bezt2 = &nu->bezt[nu->pntsu - 2]; + + if ((nu->flagu & CU_NURB_CYCLIC) && + BEZSELECTED_HIDDENHANDLES(cu, bezt1) && + BEZSELECTED_HIDDENHANDLES(cu, bezt2)) + { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_beztcpy(editnurb, &nu1->bezt[1], nu->bezt, cut); + starta = nu->pntsu - 1; + cut = 1; + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); + + if (nu->flagu & CU_NURB_CYCLIC) startnu = nu1; + } + } + else if (enda == nu->pntsu - 1) { + /* if end of curve copy previous start point */ + starta--; + cut = enda - starta + 1; + + bezt1 = nu->bezt; + bezt2 = &nu->bezt[1]; + + if ((nu->flagu & CU_NURB_CYCLIC) && + BEZSELECTED_HIDDENHANDLES(cu, bezt1) && + BEZSELECTED_HIDDENHANDLES(cu, bezt2)) + { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_beztcpy(editnurb, &nu1->bezt[cut], nu->bezt, 1); + } + else if (startnu != NULL) { + /* if startnu exists it is a cyclic spline, start and end should be connected */ + bezt1 = (BezTriple *)MEM_mallocN((cut + startnu->pntsu) * sizeof(BezTriple), "delNurb3"); + ED_curve_beztcpy(editnurb, bezt1, &nu->bezt[starta], cut); + ED_curve_beztcpy(editnurb, &bezt1[cut], nu->bezt, startnu->pntsu); + + MEM_freeN(startnu->bezt); + startnu->bezt = bezt1; + startnu->pntsu += cut; + + if (split) { + for (b = 0; b < startnu->pntsu; b++, bezt1++) { + select_beztriple(bezt1, DESELECT, SELECT, true); + } + } + + BKE_nurb_handles_calc(startnu); + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); + } } - else { /* maybe do not make cyclic */ - if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) { - bezt2 = bezt + (nu->pntsu - 1); - if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { - nu->flagu &= ~CU_NURB_CYCLIC; - BKE_nurb_handles_calc(nu); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); + else { + /* mid spline selection, copy adjacent start and end */ + starta--; + enda++; + cut = enda - starta + 1; + + nu1 = ED_curve_nurbcpy(nu, cut); + } + + if (nu1 != NULL) { + ED_curve_beztcpy(editnurb, nu1->bezt, &nu->bezt[starta], cut); + + if (starta != 0 || enda != nu->pntsu - 1) nu1->flagu &= ~CU_NURB_CYCLIC; + + if (split) { + /* deselect for split operator */ + for (b = 0, bezt1 = nu1->bezt; b < nu1->pntsu; b++, bezt1++) { + select_beztriple(bezt1, DESELECT, SELECT, true); } } - return OPERATOR_FINISHED; + BLI_addtail(&newnurb, nu1); + BKE_nurb_handles_calc(nu1); + nu1 = NULL; } - cut = a; - nu1 = nu; - break; + starta = enda = -1; + } + } + + if (!split && cut != -1 && nu->pntsu > 2 && !(nu->flagu & CU_NURB_CYCLIC)) { + /* start and points copied if connecting segment was deleted and not cylic spline */ + bezt1 = nu->bezt; + bezt2 = &nu->bezt[1]; + if (BEZSELECTED_HIDDENHANDLES(cu, bezt1) && BEZSELECTED_HIDDENHANDLES(cu, bezt2)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1); + BLI_addtail(&newnurb, nu1); + } + + bezt1 = &nu->bezt[nu->pntsu - 1]; + bezt2 = &nu->bezt[nu->pntsu - 2]; + if (BEZSELECTED_HIDDENHANDLES(cu, bezt1) && BEZSELECTED_HIDDENHANDLES(cu, bezt2)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1); + BLI_addtail(&newnurb, nu1); } - bezt++; } } else if (nu->pntsv == 1) { - bp = nu->bp; - for (a = 0; a < nu->pntsu - 1; a++) { - if (bp->f1 & SELECT) { - bp1 = bp; - bp2 = bp + 1; - if (bp2->f1 & SELECT) { - /* pass */ + for (a = 0, bp = nu->bp; a < nu->pntsu; a++, bp++) { + if (!(bp->f1 & SELECT)) { + enda = a; + if (starta == -1) starta = a; + if (a < nu->pntsu - 1) continue; + } + else if (a < nu->pntsu - 1 && !((bp + 1)->f1 & SELECT)) { + /* if just single selected point then continue */ + continue; + } + + if (starta >= 0) { + /* got selected segment, now check where and copy */ + if (starta <= 1 && a == nu->pntsu - 1) { + /* copying all points in spline */ + if (starta == 1 && enda != a) nu->flagu &= ~CU_NURB_CYCLIC; + + starta = 0; + enda = a; + cut = enda - starta + 1; + + nu1 = ED_curve_nurbcpy(nu, cut); } - else { /* maybe do not make cyclic */ - if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) { - bp2 = bp + (nu->pntsu - 1); - if (bp2->f1 & SELECT) { - nu->flagu &= ~CU_NURB_CYCLIC; - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); + else if (starta == 0) { + /* if start of curve copy next end point */ + enda++; + cut = enda - starta + 1; + + bp1 = &nu->bp[nu->pntsu - 1]; + bp2 = &nu->bp[nu->pntsu - 2]; + + if ((nu->flagu & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_bpcpy(editnurb, &nu1->bp[1], nu->bp, cut); + starta = nu->pntsu - 1; + cut = 1; + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); + + if (nu->flagu & CU_NURB_CYCLIC) startnu = nu1; + } + } + else if (enda == nu->pntsu - 1) { + /* if end of curve copy previous start point */ + starta--; + cut = enda - starta + 1; + + bp1 = nu->bp; + bp2 = &nu->bp[1]; + + if ((nu->flagu & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_bpcpy(editnurb, &nu1->bp[cut], nu->bp, 1); + } + else if (startnu != NULL) { + /* if startnu exists it is a cyclic spline, start and end should be connected */ + bp1 = (BPoint *)MEM_mallocN((cut + startnu->pntsu) * sizeof(BPoint), "delNurb4"); + ED_curve_bpcpy(editnurb, bp1, &nu->bp[starta], cut); + ED_curve_bpcpy(editnurb, &bp1[cut], nu->bp, startnu->pntsu); + + MEM_freeN(startnu->bp); + startnu->bp = bp1; + startnu->pntsu += cut; + + if (split) { + for (b = 0; b < startnu->pntsu; b++, bp1++) { + select_bpoint(bp1, DESELECT, SELECT, HIDDEN); + } } + + BKE_nurb_order_clamp_u(startnu); + BKE_nurb_knot_calc_u(startnu); + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); } + } + else { + /* mid spline selection, copy adjacent start and end */ + starta--; + enda++; + cut = enda - starta + 1; - return OPERATOR_FINISHED; + nu1 = ED_curve_nurbcpy(nu, cut); } - cut = a; - nu1 = nu; - break; - } - bp++; - } - } - if (nu1) break; - nuindex++; - } - if (nu1) { - if (bezt1) { - if (nu1->pntsu == 2) { /* remove completely */ - if (cu->actnu == nuindex) - cu->actnu = -1; - BLI_remlink(nubase, nu); - BKE_nurb_free(nu); nu = NULL; - } - else if (nu1->flagu & CU_NURB_CYCLIC) { /* cyclic */ - bezt = (BezTriple *)MEM_mallocN((cut + 1) * sizeof(BezTriple), "delNurb1"); - ED_curve_beztcpy(editnurb, bezt, nu1->bezt, cut + 1); - a = nu1->pntsu - cut - 1; - ED_curve_beztcpy(editnurb, nu1->bezt, bezt2, a); - ED_curve_beztcpy(editnurb, &nu1->bezt[a], bezt, cut + 1); + if (nu1 != NULL) { + ED_curve_bpcpy(editnurb, nu1->bp, &nu->bp[starta], cut); - nu1->flagu &= ~CU_NURB_CYCLIC; - MEM_freeN(bezt); - BKE_nurb_handles_calc(nu); - } - else { /* add new curve */ + if (starta != 0 || enda != nu->pntsu - 1) nu1->flagu &= ~CU_NURB_CYCLIC; -/* seems to be an error here... but where? (a can become zero) */ + if (split) { + /* deselect for split operator */ + for (b = 0, bp1 = nu1->bp; b < nu1->pntsu; b++, bp1++) { + select_bpoint(bp1, DESELECT, SELECT, HIDDEN); + } + } - nu = (Nurb *)MEM_mallocN(sizeof(Nurb), "delNurb2"); - memcpy(nu, nu1, sizeof(Nurb)); - BLI_addtail(nubase, nu); - nu->bezt = (BezTriple *)MEM_mallocN((cut + 1) * sizeof(BezTriple), "delNurb3"); - ED_curve_beztcpy(editnurb, nu->bezt, nu1->bezt, cut + 1); - a = nu1->pntsu - cut - 1; + BLI_addtail(&newnurb, nu1); + nu1->knotsu = NULL; + BKE_nurb_order_clamp_u(nu1); + BKE_nurb_knot_calc_u(nu1); + nu1 = NULL; + } + starta = enda = -1; + } + } - bezt = (BezTriple *)MEM_mallocN(a * sizeof(BezTriple), "delNurb4"); - ED_curve_beztcpy(editnurb, bezt, &nu1->bezt[cut + 1], a); - MEM_freeN(nu1->bezt); - nu1->bezt = bezt; - nu1->pntsu = a; - nu->pntsu = cut + 1; - - - BKE_nurb_handles_calc(nu); - BKE_nurb_handles_calc(nu1); - } - } - else if (bp1) { - if (nu1->pntsu == 2) { /* remove completely */ - if (cu->actnu == nuindex) - cu->actnu = -1; - - BLI_remlink(nubase, nu); - BKE_nurb_free(nu); nu = NULL; - } - else if (nu1->flagu & CU_NURB_CYCLIC) { /* cyclic */ - bp = (BPoint *)MEM_mallocN((cut + 1) * sizeof(BPoint), "delNurb5"); - ED_curve_bpcpy(editnurb, bp, nu1->bp, cut + 1); - a = nu1->pntsu - cut - 1; - ED_curve_bpcpy(editnurb, nu1->bp, bp2, a); - ED_curve_bpcpy(editnurb, &nu1->bp[a], bp, cut + 1); - - nu1->flagu &= ~CU_NURB_CYCLIC; - MEM_freeN(bp); - } - else { /* add new curve */ - nu = (Nurb *)MEM_mallocN(sizeof(Nurb), "delNurb6"); - memcpy(nu, nu1, sizeof(Nurb)); - BLI_addtail(nubase, nu); - nu->bp = (BPoint *)MEM_mallocN((cut + 1) * sizeof(BPoint), "delNurb7"); - ED_curve_bpcpy(editnurb, nu->bp, nu1->bp, cut + 1); - a = nu1->pntsu - cut - 1; - bp = (BPoint *)MEM_mallocN(a * sizeof(BPoint), "delNurb8"); - ED_curve_bpcpy(editnurb, bp, &nu1->bp[cut + 1], a); - MEM_freeN(nu1->bp); - nu1->bp = bp; - nu1->pntsu = a; - nu1->knotsu = NULL; - nu->pntsu = cut + 1; - - BKE_nurb_order_clamp_u(nu); - BKE_nurb_knot_calc_u(nu); + if (!split && cut != -1 && nu->pntsu > 2 && !(nu->flagu & CU_NURB_CYCLIC)) { + /* start and points copied if connecting segment was deleted and not cylic spline */ + bp1 = nu->bp; + bp2 = &nu->bp[1]; + if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_bpcpy(editnurb, nu1->bp, bp1, 1); + BLI_addtail(&newnurb, nu1); + nu1->knotsu = NULL; + } - BKE_nurb_order_clamp_u(nu1); - BKE_nurb_knot_calc_u(nu1); + bp1 = &nu->bp[nu->pntsu - 1]; + bp2 = &nu->bp[nu->pntsu - 2]; + if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_bpcpy(editnurb, nu1->bp, bp1, 1); + BLI_addtail(&newnurb, nu1); + nu1->knotsu = NULL; + } } } } - } - else if (type == 2) { - cu->actnu = -1; - keyIndex_delNurbList(editnurb, nubase); + BKE_nurbList_free(nubase); + BLI_movelisttolist(nubase, &newnurb); + } + else { + BLI_assert(0); } - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); - return OPERATOR_FINISHED; } -static int delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int curve_delete_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); - uiPopupMenu *pup; - uiLayout *layout; + eCurveElem_Types type = RNA_enum_get(op->ptr, "type"); + int retval = curve_delete_selected(obedit, type, false); + + if (retval == OPERATOR_FINISHED) { + if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + return retval; + } + + return retval; +} + +static EnumPropertyItem curve_delete_type_items[] = { + {CURVE_VERTEX, "VERTICES", 0, "Vertices", ""}, + {CURVE_SEGMENT, "SEGMENT", 0, "Segments", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem *rna_curve_delete_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), int *free) +{ + Object *obedit; + EnumPropertyItem *item = NULL; + int totitem = 0; + + + if (!C) /* needed for docs and i18n tools */ + return curve_delete_type_items; + + obedit = CTX_data_edit_object(C); if (obedit->type == OB_SURF) { - pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE); - layout = uiPupMenuLayout(pup); - uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 0); - uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 2); - uiPupMenuEnd(C, pup); + RNA_enum_items_add_value(&item, &totitem, curve_delete_type_items, CURVE_VERTEX); } else { - pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE); - layout = uiPupMenuLayout(pup); - uiItemsEnumO(layout, op->type->idname, "type"); - uiPupMenuEnd(C, pup); + RNA_enum_items_add_value(&item, &totitem, curve_delete_type_items, CURVE_VERTEX); + RNA_enum_items_add_value(&item, &totitem, curve_delete_type_items, CURVE_SEGMENT); } - return OPERATOR_CANCELLED; + RNA_enum_item_end(&item, &totitem); + *free = true; + + return item; } void CURVE_OT_delete(wmOperatorType *ot) { - static EnumPropertyItem type_items[] = { - {0, "SELECTED", 0, "Select", ""}, - {1, "SEGMENT", 0, "Segment", ""}, - {2, "ALL", 0, "All", ""}, - {0, NULL, 0, NULL, NULL} - }; + PropertyRNA *prop; /* identifiers */ ot->name = "Delete"; @@ -6066,15 +6286,18 @@ void CURVE_OT_delete(wmOperatorType *ot) ot->idname = "CURVE_OT_delete"; /* api callbacks */ - ot->exec = delete_exec; - ot->invoke = delete_invoke; + ot->exec = curve_delete_exec; + ot->invoke = WM_menu_invoke; ot->poll = ED_operator_editsurfcurve; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Which elements to delete"); + prop = RNA_def_enum(ot->srna, "type", curve_delete_type_items, 0, "Type", "Which elements to delete"); + RNA_def_enum_funcs(prop, rna_curve_delete_type_itemf); + + ot->prop = prop; } /********************** shade smooth/flat operator *********************/ @@ -6345,7 +6568,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type nu->pntsu = 4; nu->pntsv = 1; nu->orderu = 4; - nu->bp = CALLOC_STRUCT_N(BPoint, 4, "addNurbprim3"); + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 4, "addNurbprim3"); bp = nu->bp; for (a = 0; a < 4; a++, bp++) { @@ -6381,7 +6604,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type nu->orderu = 5; nu->flagu = CU_NURB_ENDPOINT; /* endpoint */ nu->resolu = cu->resolu; - nu->bp = CALLOC_STRUCT_N(BPoint, 5, "addNurbprim3"); + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim3"); bp = nu->bp; for (a = 0; a < 5; a++, bp++) { @@ -6414,7 +6637,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type if (cutype == CU_BEZIER) { if (!force_3d) nu->flag |= CU_2D; nu->pntsu = 4; - nu->bezt = CALLOC_STRUCT_N(BezTriple, 4, "addNurbprim1"); + nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1"); nu->flagu = CU_NURB_CYCLIC; bezt = nu->bezt; @@ -6451,7 +6674,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type nu->pntsu = 8; nu->pntsv = 1; nu->orderu = 4; - nu->bp = CALLOC_STRUCT_N(BPoint, 8, "addNurbprim6"); + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 8, "addNurbprim6"); nu->flagu = CU_NURB_CYCLIC; bp = nu->bp; @@ -6484,7 +6707,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type nu->orderu = 4; nu->orderv = 4; nu->flag = CU_SMOOTH; - nu->bp = CALLOC_STRUCT_N(BPoint, 4 * 4, "addNurbprim6"); + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * (4 * 4), "addNurbprim6"); nu->flagu = 0; nu->flagv = 0; bp = nu->bp; @@ -6546,7 +6769,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->flag = CU_SMOOTH; - nu->bp = CALLOC_STRUCT_N(BPoint, 5, "addNurbprim6"); + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim6"); nu->flagu = 0; bp = nu->bp; @@ -7158,6 +7381,22 @@ void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count) keyIndex_updateBP(editnurb, src, dst, count); } +Nurb *ED_curve_nurbcpy(Nurb *src, int count) +{ + Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb"); + memcpy(newnu, src, sizeof(Nurb)); + newnu->pntsu = count; + + if (src->bezt) { + newnu->bezt = (BezTriple *)MEM_mallocN(count * sizeof(BezTriple), "copyNurb2"); + } + else { + newnu->bp = (BPoint *)MEM_mallocN(count * sizeof(BPoint), "copyNurb3"); + } + + return newnu; +} + int ED_curve_actSelection(Curve *cu, float center[3]) { Nurb *nu = get_lastsel_nurb(cu); diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 8d108644470..6adc500baa4 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -47,8 +47,18 @@ if(WITH_BLENDER) # images data_to_c_simple(../../../../release/datafiles/splash.png SRC) + # XXX These are handy, but give nasty "false changes" in svn :/ + #svg_to_png(../../../../release/datafiles/blender_icons.svg + #../../../../release/datafiles/blender_icons16.png + #90 SRC) data_to_c_simple(../../../../release/datafiles/blender_icons16.png SRC) + #svg_to_png(../../../../release/datafiles/blender_icons.svg + #../../../../release/datafiles/blender_icons32.png + #180 SRC) data_to_c_simple(../../../../release/datafiles/blender_icons32.png SRC) + #svg_to_png(../../../../release/datafiles/prvicons.svg + #../../../../release/datafiles/prvicons.png + #90 SRC) data_to_c_simple(../../../../release/datafiles/prvicons.png SRC) # brushes diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 99157b074fd..c5dc8654e9d 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -106,8 +106,8 @@ bGPdata **gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) /* TODO: we can include other data-types such as bones later if need be... */ - /* just in case no active object */ - if (ob) { + /* 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; @@ -192,7 +192,14 @@ bGPdata *gpencil_data_get_active(const bContext *C) /* needed for offscreen rendering */ bGPdata *gpencil_data_get_active_v3d(Scene *scene) { - bGPdata *gpd = scene->basact ? scene->basact->object->gpd : NULL; + Base *base = scene->basact; + bGPdata *gpd = NULL; + /* We have to make sure active object is actually visible and selected, else we must use default scene gpd, + * to be consistent with gpencil_data_get_active's behavior. + */ + if (base && (scene->lay & base->lay) && (base->object->flag & SELECT)) { + gpd = base->object->gpd; + } return gpd ? gpd : scene->gpd; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 4c5727f16ed..da832554443 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1679,7 +1679,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement), * setting the relevant values in context at each step, then applying */ - RNA_BEGIN(op->ptr, itemptr, "stroke") + RNA_BEGIN (op->ptr, itemptr, "stroke") { float mousef[2]; diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 541956136bd..27e62928f1b 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -63,18 +63,18 @@ int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc); struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc); struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float loc[2], float *scale, float *angle); -int ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]); +bool ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]); void ED_clip_update_frame(const struct Main *mainp, int cfra); -int ED_clip_view_selection(const struct bContext *C, struct ARegion *ar, int fit); +bool ED_clip_view_selection(const struct bContext *C, struct ARegion *ar, bool fit); void ED_clip_point_undistorted_pos(struct SpaceClip *sc, const float co[2], float r_co[2]); void ED_clip_point_stable_pos(struct SpaceClip *sc, struct ARegion *ar, float x, float y, float *xr, float *yr); void ED_clip_point_stable_pos__reverse(struct SpaceClip *sc, struct ARegion *ar, const float co[2], float r_co[2]); void ED_clip_mouse_pos(struct SpaceClip *sc, struct ARegion *ar, const int mval[2], float co[2]); -int ED_space_clip_check_show_trackedit(struct SpaceClip *sc); -int ED_space_clip_check_show_maskedit(struct SpaceClip *sc); +bool ED_space_clip_check_show_trackedit(struct SpaceClip *sc); +bool ED_space_clip_check_show_maskedit(struct SpaceClip *sc); struct MovieClip *ED_space_clip_get_clip(struct SpaceClip *sc); void ED_space_clip_set_clip(struct bContext *C, struct bScreen *screen, struct SpaceClip *sc, struct MovieClip *clip); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 1d26204095c..571788f4f8f 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -83,6 +83,7 @@ int CU_select_nth(struct Object *obedit, int nth); void ED_curve_beztcpy(struct EditNurb *editnurb, struct BezTriple *dst, struct BezTriple *src, int count); void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count); +struct Nurb *ED_curve_nurbcpy(struct Nurb *src, int count); int ED_curve_updateAnimPaths(struct Curve *cu); diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 95fad17274e..dc40efc748b 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -222,6 +222,7 @@ short ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks); /* Flags for use by driver creation calls */ typedef enum eCreateDriverFlags { CREATEDRIVER_WITH_DEFAULT_DVAR = (1 << 0), /* create drivers with a default variable for nicer UI */ + CREATEDRIVER_WITH_FMODIFIER = (1 << 1), /* create drivers with Generator FModifier (for backwards compat) */ } eCreateDriverFlags; /* -------- */ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 420ab24e5e9..3e2dbe255df 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -48,6 +48,8 @@ void ED_mask_point_pos(struct ScrArea *sa, struct ARegion *ar, float x, float y, void ED_mask_point_pos__reverse(struct ScrArea *sa, struct ARegion *ar, float x, float y, float *xr, float *yr); +void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]); + void ED_operatortypes_mask(void); void ED_keymap_mask(struct wmKeyConfig *keyconf); void ED_operatormacros_mask(void); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 90b131e5acc..7553cb3699c 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -92,7 +92,7 @@ typedef enum eParentType { PAR_PATH_CONST, PAR_LATTICE, PAR_VERTEX, - PAR_TRIA + PAR_VERTEX_TRI } eParentType; #ifdef __RNA_TYPES_H__ @@ -101,7 +101,7 @@ extern struct EnumPropertyItem prop_make_parent_types[]; #endif int ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob, - struct Object *par, int partype, int xmirror, int keep_transform); + struct Object *par, int partype, bool xmirror, bool keep_transform, const int vert_par[3]); void ED_object_parent_clear(struct Object *ob, int type); struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob); @@ -123,6 +123,7 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, st void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr); +bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, int mode, struct ReportList *reports); void ED_object_toggle_modes(struct bContext *C, int mode); /* bitflags for enter/exit editmode */ diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h index 9f42fd042c3..2b02606c6d9 100644 --- a/source/blender/editors/include/ED_screen_types.h +++ b/source/blender/editors/include/ED_screen_types.h @@ -79,7 +79,7 @@ typedef enum { AE_RIGHT_TO_TOPLEFT, /* Region located on the left, _right_ edge is action zone. Region minimized to the top left */ AE_LEFT_TO_TOPRIGHT, /* Region located on the right, _left_ edge is action zone. Region minimized to the top right */ AE_TOP_TO_BOTTOMRIGHT, /* Region located at the bottom, _top_ edge is action zone. Region minimized to the bottom right */ - AE_BOTTOM_TO_TOPLEFT /* Region located at the top, _bottom_edge is action zone. Region minimized to the top left */ + AE_BOTTOM_TO_TOPLEFT /* Region located at the top, _bottom_ edge is action zone. Region minimized to the top left */ } AZEdge; /* for editing areas/regions */ @@ -87,10 +87,8 @@ typedef struct AZone { struct AZone *next, *prev; ARegion *ar; int type; - /* region-azone, which of the edges */ + /* region-azone, which of the edges (only for AZONE_REGION) */ AZEdge edge; - /* internal */ - short do_draw; /* for draw */ short x1, y1, x2, y2; /* for clip */ diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index ffc9e6651bc..735227ae9b5 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -102,7 +102,7 @@ void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit); void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel); /* uvedit_draw.c */ -void draw_image_cursor(struct SpaceImage *sima, struct ARegion *ar); +void draw_image_cursor(struct ARegion *ar, const float cursor[2]); void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact); /* uvedit_buttons.c */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 3929cf9788c..f8e1bbb2413 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -49,9 +49,7 @@ DEF_ICON(RADIOBUT_OFF) DEF_ICON(RADIOBUT_ON) DEF_ICON(MENU_PANEL) DEF_ICON(BLENDER) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK003) -#endif +DEF_ICON(GRIP) DEF_ICON(DOT) #ifndef DEF_ICON_BLANK_SKIP DEF_ICON(BLANK004) @@ -75,9 +73,9 @@ DEF_ICON(VIEWZOOM) DEF_ICON(ZOOMIN) DEF_ICON(ZOOMOUT) DEF_ICON(PANEL_CLOSE) -DEF_ICON(COPY_ID) //ICON_BLANK009 +DEF_ICON(COPY_ID) DEF_ICON(EYEDROPPER) -DEF_ICON(LINK_AREA) //ICON_BLANK010 +DEF_ICON(LINK_AREA) DEF_ICON(AUTO) DEF_ICON(CHECKBOX_DEHLT) DEF_ICON(CHECKBOX_HLT) @@ -138,7 +136,7 @@ DEF_ICON(SCRIPT) DEF_ICON(PARTICLES) DEF_ICON(PHYSICS) DEF_ICON(SPEAKER) -DEF_ICON(TEXTURE_SHADED) //ICON_BLANK041 +DEF_ICON(TEXTURE_SHADED) #ifndef DEF_ICON_BLANK_SKIP DEF_ICON(BLANK042) DEF_ICON(BLANK043) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9a9cab9b46c..8b395505623 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -32,6 +32,7 @@ #ifndef __UI_INTERFACE_H__ #define __UI_INTERFACE_H__ +#include "BLI_compiler_attrs.h" #include "BLI_sys_types.h" /* size_t */ #include "RNA_types.h" #include "DNA_userdef_types.h" @@ -327,30 +328,14 @@ typedef void (*uiMenuHandleFunc)(struct bContext *C, void *arg, int event); typedef struct uiPopupMenu uiPopupMenu; -struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) ATTR_NONNULL(); void uiPupMenuEnd(struct bContext *C, struct uiPopupMenu *head); struct uiLayout *uiPupMenuLayout(uiPopupMenu *head); -void uiPupMenuOkee(struct bContext *C, const char *opname, const char *str, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 4))) -#endif -; +void uiPupMenuOkee(struct bContext *C, const char *opname, const char *str, ...) ATTR_PRINTF_FORMAT(3, 4); void uiPupMenuSaveOver(struct bContext *C, struct wmOperator *op, const char *filename); -void uiPupMenuNotice(struct bContext *C, const char *str, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; -void uiPupMenuError(struct bContext *C, const char *str, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; +void uiPupMenuNotice(struct bContext *C, const char *str, ...) ATTR_PRINTF_FORMAT(2, 3); +void uiPupMenuError(struct bContext *C, const char *str, ...) ATTR_PRINTF_FORMAT(2, 3); void uiPupMenuReports(struct bContext *C, struct ReportList *reports); void uiPupMenuInvoke(struct bContext *C, const char *idname); /* popup registered menu */ @@ -550,11 +535,7 @@ typedef struct uiStringInfo { /* Note: Expects pointers to uiStringInfo structs as parameters. * Will fill them with translated strings, when possible. * Strings in uiStringInfo must be MEM_freeN'ed by caller. */ -void uiButGetStrInfo(struct bContext *C, uiBut *but, ...) -#ifdef __GNUC__ -__attribute__((sentinel)) -#endif -; +void uiButGetStrInfo(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0); /* Edit i18n stuff. */ /* Name of the main py op from i18n addon. */ @@ -845,7 +826,7 @@ void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color); #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id, struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr, - const char *active_propname, int rows, int maxrows, int layout_type); + const char *active_propname, int rows, int maxrows, int layout_type, int columns); void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 42e9d892871..0c8a39a6714 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -210,6 +210,9 @@ enum { TH_STITCH_PREVIEW_UNSTITCHABLE, TH_STITCH_PREVIEW_ACTIVE, + TH_UV_SHADOW, + TH_UV_OTHERS, + TH_FREESTYLE_EDGE_MARK, TH_FREESTYLE_FACE_MARK, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index e46334b06e7..fb70ad50b5d 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -192,6 +192,7 @@ void UI_view2d_listview_visible_cells(struct View2D *v2d, float columnwidth, flo void UI_view2d_region_to_view(struct View2D *v2d, float x, float y, float *viewx, float *viewy); void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *regionx, int *regiony); void UI_view2d_to_region_no_clip(struct View2D *v2d, float x, float y, int *regionx, int *region_y); +void UI_view2d_to_region_float(struct View2D *v2d, float x, float y, float *regionx, float *regiony); /* utilities */ struct View2D *UI_view2d_fromcontext(const struct bContext *C); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 21a63183c1a..ec5a4d0027d 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -985,7 +985,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, IDPropertyTemplate val = {0}; prop_path = IDP_New(IDP_GROUP, &val, __func__); - prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1); /* len + 1, or else will be truncated */ + prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1); IDP_AddToGroup(prop_path, prop_path_value); /* check each until one works... */ @@ -1807,12 +1807,14 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va static float ui_get_but_step_unit(uiBut *but, float step_default) { int unit_type = RNA_SUBTYPE_UNIT_VALUE(uiButGetUnitType(but)); - float step; + double step; step = bUnit_ClosestScalar(ui_get_but_scale_unit(but, step_default), but->block->unit->system, unit_type); - if (step > 0.0f) { /* -1 is an error value */ - return (float)((double)step / ui_get_but_scale_unit(but, 1.0)) * 100.0f; + /* -1 is an error value */ + if (step != -1.0) { + BLI_assert(step > 0.0); + return (float)(step / ui_get_but_scale_unit(but, 1.0)) * 100.0f; } else { return step_default; @@ -2047,13 +2049,14 @@ bool ui_set_but_string(bContext *C, uiBut *but, const char *str) return false; } -void ui_set_but_default(bContext *C, short all) +void ui_set_but_default(bContext *C, const bool all) { + const char *opstring = "UI_OT_reset_default_button"; PointerRNA ptr; - WM_operator_properties_create(&ptr, "UI_OT_reset_default_button"); + WM_operator_properties_create(&ptr, opstring); RNA_boolean_set(&ptr, "all", all); - WM_operator_name_call(C, "UI_OT_reset_default_button", WM_OP_EXEC_DEFAULT, &ptr); + WM_operator_name_call(C, opstring, WM_OP_EXEC_DEFAULT, &ptr); WM_operator_properties_free(&ptr); } @@ -2230,8 +2233,7 @@ void uiFreeBlock(const bContext *C, uiBlock *block) { uiBut *but; - while ( (but = block->buttons.first) ) { - BLI_remlink(&block->buttons, but); + while ((but = BLI_pophead(&block->buttons))) { ui_free_but(C, but); } @@ -2255,8 +2257,7 @@ void uiFreeBlocks(const bContext *C, ListBase *lb) { uiBlock *block; - while ( (block = lb->first) ) { - BLI_remlink(lb, block); + while ((block = BLI_pophead(lb))) { uiFreeBlock(C, block); } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f9ee2b67e6b..dc7813510ec 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -152,7 +152,9 @@ typedef struct uiHandleButtonData { char *str, *origstr; double value, origvalue, startvalue; float vec[3], origvec[3]; +#if 0 /* UNUSED */ int togdual, togonly; +#endif ColorBand *coba; /* tooltip */ @@ -170,6 +172,7 @@ typedef struct uiHandleButtonData { /* coords are Window/uiBlock relative (depends on the button) */ int draglastx, draglasty; int dragstartx, dragstarty; + int draglastvalue; bool dragchange, draglock; int dragsel; float dragf, dragfstart; @@ -2660,8 +2663,10 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons #ifdef USE_DRAG_TOGGLE if (data->state == BUTTON_STATE_HIGHLIGHT) { if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_is_but_bool(but)) { +#if 0 /* UNUSED */ data->togdual = event->ctrl; data->togonly = !event->shift; +#endif ui_apply_button(C, but->block, but, data, true); button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); data->dragstartx = event->x; @@ -2677,8 +2682,10 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons #endif if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { +#if 0 /* UNUSED */ data->togdual = event->ctrl; data->togonly = !event->shift; +#endif button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; } @@ -3406,6 +3413,100 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut return retval; } +static int ui_do_but_LISTBOX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +{ + uiList *ui_list = but->custom_data; + int *size = (int *)but->poin; + int mx, my, raw_dir_sign; + int retval = WM_UI_HANDLER_CONTINUE; + + mx = event->x; + my = event->y; + + /* We find the direction of the mouse since last time, before converting coordinates into block's space. + * We'll use it to avoid flickering in case some rows are higher than UI_UNIT_Y. + */ + raw_dir_sign = (data->draglasty - my < 0) ? -1 : 1; + data->draglasty = my; + + ui_window_to_block(data->region, block, &mx, &my); + + if (data->state == BUTTON_STATE_NUM_EDITING) { + if (event->type == ESCKEY) { + data->cancel = true; + data->escapecancel = true; + *size = (int)data->origvalue; + button_activate_state(C, but, BUTTON_STATE_EXIT); + ui_list->flag &= ~UILST_RESIZING; + ED_region_tag_redraw(data->region); + } + else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_EXIT); + ui_list->flag &= ~UILST_RESIZING; + ED_region_tag_redraw(data->region); + } + else if (event->type == MOUSEMOVE) { + /* If we switched from dragged to auto size, suspend shrinking dragging and set dragstarty to a temp + * refpoint. + */ + if (data->draglastvalue > 0 && *size == 0) { + data->draglastvalue = *size; + data->dragstartx = data->dragstarty; /* draglasty already used... */ + data->dragstarty = my; + } + else { + int delta = data->dragstarty - my; + /* We only actually do something if the real mousemouve direction matches the "virtual" + * mousemove direction in current block's space. This avoids flickering when drag-resizing lists with + * items drawing higher that UI_UNIT_Y. + */ + if (delta * raw_dir_sign > 0) { + /* Number of rows to show/hide, UI_UNIT_Y should work nice in most cases. */ + delta = (int)floorf(((float)delta / (float)UI_UNIT_Y) + 0.5f); + + /* If we are not in autosize mode, default behavior... */ + if (*size > 0 && delta != 0) { + /* This prevents some instability in case some items draw more/less than UI_UNIT_Y height. */ + delta = (delta < -5) ? -5 : (delta > 5) ? 5 : delta; + /* We can't use ui_numedit_apply()... */ + /* list template will clamp, but we do not want to reach 0 aka autosize mode! */ + *size = max_ii(*size + delta, 1); + + /* Used to detect switch to/from autosize mode. */ + data->draglastvalue = *size; + + data->dragchange = true; + data->applied = data->applied_interactive = true; + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(data->region); + } + /* If we are leaving autosize mode (growing dragging), restore to minimal size. */ + else if (delta > 0) { + /* We can't use ui_numedit_apply()... */ + *size = ui_list->dyn_data->visual_height_min; + + /* Restore real dragstarty value! */ + data->dragstarty = data->dragstartx; + + /* Used to detect switch to/from autosize mode. */ + data->draglastvalue = *size; + + data->dragchange = true; + data->applied = data->applied_interactive = true; + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(data->region); + } + } + } + } + + retval = WM_UI_HANDLER_BREAK; + } + + return retval; +} static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { @@ -5161,13 +5262,12 @@ static bool ui_but_menu(bContext *C, uiBut *but) } /* Show header tools for header buttons. */ - if (CTX_wm_region(C)) { + { ARegion *ar = CTX_wm_region(C); - if (ar->regiontype == RGN_TYPE_HEADER) { - - uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL); - uiItemS(layout); - } + if (ar && (ar->regiontype == RGN_TYPE_HEADER)) { + uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL); + uiItemS(layout); + } } { /* Docs */ @@ -5273,7 +5373,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * ui_but_anim_insert_keyframe(C); } - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(data->region); return WM_UI_HANDLER_BREAK; } @@ -5287,7 +5387,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * else ui_but_anim_add_driver(C); - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(data->region); return WM_UI_HANDLER_BREAK; } @@ -5301,17 +5401,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * else ui_but_anim_add_keyingset(C); - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(data->region); return WM_UI_HANDLER_BREAK; } - /* reset to default */ - /* XXX hardcoded keymap check.... */ - else if (event->type == BACKSPACEKEY && event->val == KM_PRESS) { - /* ctrl+backspace = reset active button; backspace = reset a whole array*/ - if (!(ELEM3(but->type, HSVCIRCLE, HSVCUBE, HISTOGRAM))) - ui_set_but_default(C, !event->ctrl); - } /* handle menu */ else if (event->type == RIGHTMOUSE && event->val == KM_PRESS) { /* RMB has two options now */ @@ -5367,8 +5460,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case NUMSLI: retval = ui_do_but_SLI(C, block, but, data, event); break; - case ROUNDBOX: case LISTBOX: + retval = ui_do_but_LISTBOX(C, block, but, data, event); + break; + case ROUNDBOX: case LABEL: case LISTLABEL: case ROW: @@ -5436,7 +5531,22 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case BUT_EXTRA: break; } - + + + /* reset to default (generic function, only use if not handled by switch above) */ + /* XXX hardcoded keymap check.... */ + if (data->state == BUTTON_STATE_HIGHLIGHT) { + if ((retval == WM_UI_HANDLER_CONTINUE) && + (event->type == BACKSPACEKEY && event->val == KM_PRESS)) + { + /* ctrl+backspace = reset active button; backspace = reset a whole array*/ + ui_set_but_default(C, !event->ctrl); + ED_region_tag_redraw(data->region); + retval = WM_UI_HANDLER_BREAK; + } + } + + return retval; } @@ -5622,8 +5732,6 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) uiBut *but; int mx, my; -// if (!win->active) -// return NULL; if (!ui_mouse_inside_region(ar, x, y)) return NULL; @@ -5768,7 +5876,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s WM_cursor_grab_disable(data->window, NULL); } #else - WM_cursor_grab_disable(data->window, ); + WM_cursor_grab_disable(data->window, NULL); #endif } } @@ -6423,90 +6531,166 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar) { - uiBut *but = ui_list_find_mouse_over(ar, event->x, event->y); + uiBut *but, *dragbut; + uiList *ui_list; + uiListDyn *dyn_data; int retval = WM_UI_HANDLER_CONTINUE; int type = event->type, val = event->val; + int mx, my; + bool is_over_dragbut = false; - if (but) { - uiList *ui_list = but->custom_data; + but = ui_list_find_mouse_over(ar, event->x, event->y); + if (!but) { + return retval; + } - if (ui_list) { - - /* convert pan to scrollwheel */ - if (type == MOUSEPAN) { - ui_pan_to_scroll(event, &type, &val); - - /* if type still is mousepan, we call it handled, since delta-y accumulate */ - /* also see wm_event_system.c do_wheel_ui hack */ - if (type == MOUSEPAN) - retval = WM_UI_HANDLER_BREAK; - } - - if (val == KM_PRESS) { - - if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || - ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) - { - const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop); - int value, min, max; + ui_list = but->custom_data; + if (!ui_list || !ui_list->dyn_data) { + return retval; + } + dyn_data = ui_list->dyn_data; - /* activate up/down the list */ - value = value_orig; + mx = event->x; + my = event->y; + ui_window_to_block(ar, but->block, &mx, &my); - if (ELEM(type, UPARROWKEY, WHEELUPMOUSE)) - value--; - else - value++; + /* Find our "dragging" button. */ + for (dragbut = but->block->buttons.first; dragbut; dragbut = dragbut->next) { + if (dragbut->poin == (void *)ui_list) { + break; + } + } + if (dragbut && dragbut == ui_but_find_mouse_over(ar, event->x, event->y)) { + is_over_dragbut = true; + } - CLAMP(value, 0, ui_list->list_last_len - 1); + if (is_over_dragbut && type == LEFTMOUSE && val == KM_PRESS) { + uiHandleButtonData *data; + int *size = (int *)but->poin; - if (value < ui_list->list_scroll) - ui_list->list_scroll = value; - else if (value >= ui_list->list_scroll + ui_list->list_size) - ui_list->list_scroll = value - ui_list->list_size + 1; + ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE); + button_activate_state(C, but, BUTTON_STATE_INIT); + + data = but->active; + data->dragstarty = my; - RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); - value = CLAMPIS(value, min, max); + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - if (value != value_orig) { - RNA_property_int_set(&but->rnapoin, but->rnaprop, value); - RNA_property_update(C, &but->rnapoin, but->rnaprop); + /* Again, have to override values set by ui_numedit_begin, because our listbox button also has a rnapoin... */ + *size = data->origvalue = (double)dyn_data->visual_height; + ui_list->flag |= UILST_RESIZING; - ui_apply_undo(but); - ED_region_tag_redraw(ar); + retval = WM_UI_HANDLER_BREAK; + } + else { + /* convert pan to scrollwheel */ + if (type == MOUSEPAN) { + ui_pan_to_scroll(event, &type, &val); + + /* if type still is mousepan, we call it handled, since delta-y accumulate */ + /* also see wm_event_system.c do_wheel_ui hack */ + if (type == MOUSEPAN) + retval = WM_UI_HANDLER_BREAK; + } + + if (val == KM_PRESS) { + if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || + ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) + { + const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop); + int value, min, max, inc; + + /* activate up/down the list */ + value = value_orig; + if ((ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0) { + inc = ELEM(type, UPARROWKEY, WHEELUPMOUSE) ? 1 : -1; + } + else { + inc = ELEM(type, UPARROWKEY, WHEELUPMOUSE) ? -1 : 1; + } + + if (dyn_data->items_filter_neworder || dyn_data->items_filter_flags) { + /* If we have a display order different from collection order, we have some work! */ + int *org_order = MEM_mallocN(dyn_data->items_shown * sizeof(int), AT); + int *new_order = dyn_data->items_filter_neworder; + int i, org_idx = -1, len = dyn_data->items_len; + int current_idx = -1; + int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + + for (i = 0; i < len; i++) { + if (!dyn_data->items_filter_flags || + ((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)) + { + org_order[new_order ? new_order[++org_idx] : ++org_idx] = i; + if (i == value) { + current_idx = new_order ? new_order[org_idx] : org_idx; + } + } + else if (i == value && org_idx >= 0) { + current_idx = -(new_order ? new_order[org_idx] : org_idx) - 1; + } + } + /* Now, org_order maps displayed indices to real indices, + * and current_idx either contains the displayed index of active value (positive), + * or its more-nearest one (negated). + */ + if (current_idx < 0) { + current_idx = (current_idx * -1) + (inc < 0 ? inc : inc - 1); + } + else { + current_idx += inc; } + CLAMP(current_idx, 0, dyn_data->items_shown - 1); + value = org_order[current_idx]; + MEM_freeN(org_order); + } + else { + value += inc; + } - retval = WM_UI_HANDLER_BREAK; + CLAMP(value, 0, dyn_data->items_len - 1); + + RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); + CLAMP(value, min, max); + + if (value != value_orig) { + RNA_property_int_set(&but->rnapoin, but->rnaprop, value); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + + ui_apply_undo(but); + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(ar); } - else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { - /* silly replacement for proper grip */ - if (ui_list->list_grip_size == 0) - ui_list->list_grip_size = ui_list->list_size; + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { + /* We now have proper grip, but keep this anyway! */ + if (ui_list->list_grip == 0) + ui_list->list_grip = dyn_data->visual_height; + /* list template will clamp */ + if (type == WHEELUPMOUSE) + ui_list->list_grip--; + else + ui_list->list_grip++; + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(ar); + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { + if (dyn_data->height > dyn_data->visual_height) { + /* list template will clamp */ if (type == WHEELUPMOUSE) - ui_list->list_grip_size--; + ui_list->list_scroll--; else - ui_list->list_grip_size++; - - ui_list->list_grip_size = MAX2(ui_list->list_grip_size, 1); + ui_list->list_scroll++; ED_region_tag_redraw(ar); retval = WM_UI_HANDLER_BREAK; } - else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { - if (ui_list->list_last_len > ui_list->list_size) { - /* list template will clamp */ - if (type == WHEELUPMOUSE) - ui_list->list_scroll--; - else - ui_list->list_scroll++; - - ED_region_tag_redraw(ar); - - retval = WM_UI_HANDLER_BREAK; - } - } } } } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d2a8c47b347..0b02a1a5db4 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -393,7 +393,7 @@ extern bool ui_set_but_string(struct bContext *C, uiBut *but, const char *str); extern bool ui_set_but_string_eval_num(struct bContext *C, uiBut *but, const char *str, double *value); extern int ui_get_but_string_max_length(uiBut *but); -extern void ui_set_but_default(struct bContext *C, short all); +extern void ui_set_but_default(struct bContext *C, const bool all); extern void ui_check_but(uiBut *but); extern bool ui_is_but_float(uiBut *but); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 079ba97aa9d..424d2231a03 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -471,6 +471,8 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in but->type = NUMSLI; if (toggle && but->type == OPTION) but->type = TOG; + if ((a == 0) && (subtype == PROP_AXISANGLE)) + uiButSetUnitType(but, PROP_UNIT_ROTATION); } if (boolarr) { @@ -568,7 +570,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n PropertySubType subtype; int labelw; - sub = uiLayoutRow(layout, FALSE); + sub = uiLayoutRow(layout, layout->align); uiBlockSetCurLayout(block, sub); if (name[0]) { @@ -1465,6 +1467,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna uiBlock *block; StructRNA *icontype; int w, h; + char namestr[UI_MAX_NAME_STR]; /* validate arguments */ prop = RNA_struct_find_property(ptr, propname); @@ -1507,6 +1510,8 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna if (!name) name = RNA_property_ui_name(prop); + name = ui_item_name_add_colon(name, namestr); + /* create button */ block = uiLayoutGetBlock(layout); @@ -2429,6 +2434,15 @@ uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, Pr but->rnapoin = *actptr; but->rnaprop = actprop; + /* Resizing data. */ + /* Note: we can't use usual "num button" value handling, as it only tries rnapoin when it is non-NULL... :/ + * So just setting but->poin, not but->pointype. + */ + but->poin = (void *)&ui_list->list_grip; + but->hardmin = but->softmin = 0.0f; + but->hardmax = but->softmax = 1000.0f; /* Should be more than enough! */ + but->a1 = 0.0f; + /* only for the undo string */ if (but->flag & UI_BUT_UNDO) { but->tip = RNA_property_description(actprop); @@ -2678,8 +2692,9 @@ static void ui_item_align(uiLayout *litem, short nr) BLI_remlink(&litem->root->block->buttons, box->roundbox); BLI_addhead(&litem->root->block->buttons, box->roundbox); } - else + else if (((uiLayout *)item)->align) { ui_item_align((uiLayout *)item, nr); + } } } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 95f47be0b70..832dd4d23ce 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2605,12 +2605,10 @@ static void confirm_cancel_operator(bContext *UNUSED(C), void *opv) WM_operator_free(opv); } -static void vconfirm_opname(bContext *C, const char *opname, const char *title, const char *itemfmt, va_list ap) -#ifdef __GNUC__ -__attribute__ ((format(printf, 4, 0))) -#endif -; -static void vconfirm_opname(bContext *C, const char *opname, const char *title, const char *itemfmt, va_list ap) +static void vconfirm_opname(bContext *C, const char *opname, const char *title, + const char *itemfmt, va_list ap) ATTR_PRINTF_FORMAT(4, 0); +static void vconfirm_opname(bContext *C, const char *opname, const char *title, + const char *itemfmt, va_list ap) { uiPopupBlockHandle *handle; char *s, buf[512]; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 61cc021800e..4e79fd19f24 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1,4 +1,5 @@ /* + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -43,6 +44,7 @@ #include "BLI_rect.h" #include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_fnmatch.h" #include "BLF_api.h" #include "BLF_translation.h" @@ -1017,6 +1019,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); Object *ob; ModifierData *md, *vmd; + VirtualModifierData virtualModifierData; int i, lastCageIndex, cageIndex; /* verify we have valid data */ @@ -1039,7 +1042,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0); /* XXX virtual modifiers are not accesible for python */ - vmd = modifiers_getVirtualModifierList(ob); + vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (i = 0; vmd; i++, vmd = vmd->next) { if (md == vmd) @@ -1145,9 +1148,10 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) uiBlockSetEmboss(block, UI_EMBOSSN); uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSS); - + /* name */ - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco + 0.5f*UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f*UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, + xco + 0.5f * UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f * UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, ""); if (con->flag & CONSTRAINT_DISABLE) uiLayoutSetRedAlert(row, TRUE); @@ -2468,7 +2472,7 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), - int UNUSED(index)) + int UNUSED(index), int UNUSED(flt_flag)) { char *namebuf; const char *name; @@ -2494,30 +2498,245 @@ static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UN } } +static void uilist_draw_filter_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout) +{ + PointerRNA listptr; + uiLayout *row, *subrow; + + RNA_pointer_create(NULL, &RNA_UIList, ui_list, &listptr); + + row = uiLayoutRow(layout, FALSE); + + subrow = uiLayoutRow(row, TRUE); + uiItemR(subrow, &listptr, "filter_name", 0, "", ICON_NONE); + uiItemR(subrow, &listptr, "use_filter_invert", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", + (ui_list->filter_flag & UILST_FLT_EXCLUDE) ? ICON_ZOOM_OUT : ICON_ZOOM_IN); + + subrow = uiLayoutRow(row, TRUE); + uiItemR(subrow, &listptr, "use_filter_sort_alpha", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(subrow, &listptr, "use_filter_sort_reverse", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", + (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_TRIA_UP : ICON_TRIA_DOWN); +} + +typedef struct { + char name[MAX_IDPROP_NAME]; + int org_idx; +} StringCmp; + +static int cmpstringp(const void *p1, const void *p2) +{ + /* Case-insensitive comparison. */ + return BLI_strcasecmp(((StringCmp *) p1)->name, ((StringCmp *) p2)->name); +} + +static void uilist_filter_items_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct PointerRNA *dataptr, + const char *propname) +{ + uiListDyn *dyn_data = ui_list->dyn_data; + PropertyRNA *prop = RNA_struct_find_property(dataptr, propname); + + const char *filter_raw = ui_list->filter_byname; + char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = NULL; + bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0; + bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0; + int len = RNA_property_collection_length(dataptr, prop); + + dyn_data->items_shown = dyn_data->items_len = len; + + if (len && (order_by_name || filter_raw[0])) { + StringCmp *names = NULL; + int order_idx = 0, i = 0; + + if (order_by_name) { + names = MEM_callocN(sizeof(StringCmp) * len, AT); + } + if (filter_raw[0]) { + size_t idx = 0, slen = strlen(filter_raw); + + dyn_data->items_filter_flags = MEM_callocN(sizeof(int) * len, AT); + dyn_data->items_shown = 0; + + /* Implicitly add heading/trailing wildcards if needed. */ + if (len + 3 <= 32) { + filter = filter_buff; + } + else { + filter = filter_dyn = MEM_mallocN((slen + 3) * sizeof(char), AT); + } + if (filter_raw[idx] != '*') { + filter[idx++] = '*'; + } + memcpy(filter + idx, filter_raw, slen); + idx += slen; + if (filter[idx - 1] != '*') { + filter[idx++] = '*'; + } + filter[idx] = '\0'; + } + + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + char *namebuf; + const char *name; + bool do_order = false; + + namebuf = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); + name = namebuf ? namebuf : ""; + + if (filter[0]) { + /* Case-insensitive! */ + if (fnmatch(filter, name, FNM_CASEFOLD) == 0) { + dyn_data->items_filter_flags[i] = UILST_FLT_ITEM; + if (!filter_exclude) { + dyn_data->items_shown++; + do_order = order_by_name; + } + //printf("%s: '%s' matches '%s'\n", __func__, name, filter); + } + else if (filter_exclude) { + dyn_data->items_shown++; + do_order = order_by_name; + } + } + else { + do_order = order_by_name; + } + + if (do_order) { + names[order_idx].org_idx = order_idx; + BLI_strncpy(names[order_idx++].name, name, MAX_IDPROP_NAME); + } + + /* free name */ + if (namebuf) { + MEM_freeN(namebuf); + } + i++; + } + RNA_PROP_END; + + if (order_by_name) { + int new_idx; + /* note: order_idx equals either to ui_list->items_len if no filtering done, + * or to ui_list->items_shown if filter is enabled, + * or to (ui_list->items_len - ui_list->items_shown) if filtered items are excluded. + * This way, we only sort items we actually intend to draw! + */ + qsort(names, order_idx, sizeof(StringCmp), cmpstringp); + + dyn_data->items_filter_neworder = MEM_mallocN(sizeof(int) * order_idx, AT); + for (new_idx = 0; new_idx < order_idx; new_idx++) { + dyn_data->items_filter_neworder[names[new_idx].org_idx] = new_idx; + } + } + + if (filter_dyn) { + MEM_freeN(filter_dyn); + } + if (names) { + MEM_freeN(names); + } + } +} + +typedef struct { + PointerRNA item; + int org_idx; + int flt_flag; +} _uilist_item; + +typedef struct { + int visual_items; /* Visual number of items (i.e. number of items we have room to display). */ + int start_idx; /* Index of first item to display. */ + int end_idx; /* Index of last item to display + 1. */ +} uiListLayoutdata; + +static void prepare_list(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns, + uiListLayoutdata *layoutdata) +{ + uiListDyn *dyn_data = ui_list->dyn_data; + int activei_row, max_scroll; + + /* default rows */ + if (rows == 0) + rows = 5; + dyn_data->visual_height_min = rows; + if (maxrows == 0) + maxrows = 5; + if (columns == 0) + columns = 9; + + if (ui_list->list_grip >= rows) { + maxrows = rows = ui_list->list_grip; + } + else { + ui_list->list_grip = 0; /* Reset to auto-size mode. */ + /* Prevent auto-size mode to take effect while grab-resizing! */ + if (ui_list->flag & UILST_RESIZING) { + maxrows = rows; + } + } + + if (columns > 1) { + dyn_data->height = (int)ceil((double)len / (double)columns); + activei_row = (int)floor((double)activei / (double)columns); + } + else { + dyn_data->height = len; + activei_row = activei; + } + + /* Expand size if needed and possible. */ + if ((ui_list->list_grip == 0) && (rows != maxrows) && (dyn_data->height > rows)) { + rows = min_ii(dyn_data->height, maxrows); + } + + /* If list length changes or list is tagged to check this, and active is out of view, scroll to it .*/ + if (ui_list->list_last_len != len || ui_list->flag & UILST_SCROLL_TO_ACTIVE_ITEM) { + if (activei_row < ui_list->list_scroll) { + ui_list->list_scroll = activei_row; + } + else if (activei_row >= ui_list->list_scroll + rows) { + ui_list->list_scroll = activei_row - rows + 1; + } + ui_list->flag &= ~UILST_SCROLL_TO_ACTIVE_ITEM; + } + + max_scroll = max_ii(0, dyn_data->height - rows); + CLAMP(ui_list->list_scroll, 0, max_scroll); + ui_list->list_last_len = len; + dyn_data->visual_height = rows; + layoutdata->visual_items = rows * columns; + layoutdata->start_idx = ui_list->list_scroll * columns; + layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len); +} + void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, - const char *active_propname, int rows, int maxrows, int layout_type) + const char *active_propname, int rows, int maxrows, int layout_type, int columns) { uiListType *ui_list_type; uiList *ui_list = NULL; + uiListDyn *dyn_data; ARegion *ar; uiListDrawItemFunc draw_item; + uiListDrawFilterFunc draw_filter; + uiListFilterItemsFunc filter_items; PropertyRNA *prop = NULL, *activeprop; PropertyType type, activetype; + _uilist_item *items_ptr = NULL; StructRNA *ptype; - uiLayout *box, *row, *col, *sub, *overlap; + uiLayout *glob = NULL, *box, *row, *col, *subrow, *sub, *overlap; uiBlock *block, *subblock; uiBut *but; + uiListLayoutdata layoutdata; char ui_list_id[UI_MAX_NAME_STR]; char numstr[32]; int rnaicon = ICON_NONE, icon = ICON_NONE; int i = 0, activei = 0; int len = 0; - int items; - int found; - int min, max; /* validate arguments */ /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */ @@ -2580,6 +2799,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co } draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default; + draw_filter = ui_list_type->draw_filter ? ui_list_type->draw_filter : uilist_draw_filter_default; + filter_items = ui_list_type->filter_items ? ui_list_type->filter_items : uilist_filter_items_default; /* Find or add the uiList to the current Region. */ /* We tag the list id with the list type... */ @@ -2589,146 +2810,211 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id)); if (!ui_list) { - ui_list = MEM_callocN(sizeof(uiList), __func__); + ui_list = MEM_callocN(sizeof(uiList), AT); BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id)); BLI_addtail(&ar->ui_lists, ui_list); } + if (!ui_list->dyn_data) { + ui_list->dyn_data = MEM_callocN(sizeof(uiListDyn), AT); + } + dyn_data = ui_list->dyn_data; + /* Because we can't actually pass type across save&load... */ ui_list->type = ui_list_type; ui_list->layout_type = layout_type; + /* Reset filtering data. */ + if (dyn_data->items_filter_flags) { + MEM_freeN(dyn_data->items_filter_flags); + dyn_data->items_filter_flags = NULL; + } + if (dyn_data->items_filter_neworder) { + MEM_freeN(dyn_data->items_filter_neworder); + dyn_data->items_filter_neworder = NULL; + } + dyn_data->items_len = dyn_data->items_shown = -1; + + /* Filter list items! (not for compact layout, though) */ + if (dataptr->data && prop) { + int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0; + int items_shown, idx = 0; +#if 0 + int prev_ii = -1, prev_i; +#endif + + if (layout_type == UILST_LAYOUT_COMPACT) { + dyn_data->items_len = dyn_data->items_shown = RNA_property_collection_length(dataptr, prop); + } + else { + //printf("%s: filtering...\n", __func__); + filter_items(ui_list, C, dataptr, propname); + //printf("%s: filtering done.\n", __func__); + } + + items_shown = dyn_data->items_shown; + if (items_shown >= 0) { + items_ptr = MEM_mallocN(sizeof(_uilist_item) * items_shown, AT); + //printf("%s: items shown: %d.\n", __func__, items_shown); + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + if (!dyn_data->items_filter_flags || + ((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)) + { + int ii; + if (dyn_data->items_filter_neworder) { + ii = dyn_data->items_filter_neworder[idx++]; + ii = order_reverse ? items_shown - ii - 1 : ii; + } + else { + ii = order_reverse ? items_shown - ++idx : idx++; + } + //printf("%s: ii: %d\n", __func__, ii); + items_ptr[ii].item = itemptr; + items_ptr[ii].org_idx = i; + items_ptr[ii].flt_flag = dyn_data->items_filter_flags ? dyn_data->items_filter_flags[i] : 0; + + if (activei == i) { + activei = ii; + } +# if 0 /* For now, do not alter active element, even if it will be hidden... */ + else if (activei < i) { + /* We do not want an active but invisible item! + * Only exception is when all items are filtered out... + */ + if (prev_ii >= 0) { + activei = prev_ii; + RNA_property_int_set(active_dataptr, activeprop, prev_i); + } + else { + activei = ii; + RNA_property_int_set(active_dataptr, activeprop, i); + } + } + prev_i = i; + prev_ii = ii; +#endif + } + i++; + } + RNA_PROP_END; + } + if (dyn_data->items_shown >= 0) { + len = dyn_data->items_shown; + } + else { + len = dyn_data->items_len; + } + } + switch (layout_type) { case UILST_LAYOUT_DEFAULT: - /* default rows */ - if (rows == 0) - rows = 5; - if (maxrows == 0) - maxrows = 5; - if (ui_list->list_grip_size != 0) - rows = ui_list->list_grip_size; - /* layout */ box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); - row = uiLayoutRow(box, FALSE); + glob = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(glob, FALSE); col = uiLayoutColumn(row, TRUE); /* init numbers */ - RNA_property_int_range(active_dataptr, activeprop, &min, &max); - - if (prop) - len = RNA_property_collection_length(dataptr, prop); - items = CLAMPIS(len, rows, MAX2(rows, maxrows)); - - /* if list length changes and active is out of view, scroll to it */ - if ((ui_list->list_last_len != len) && - (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) - { - ui_list->list_scroll = activei; - } - - ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items); - ui_list->list_scroll = max_ii(ui_list->list_scroll, 0); - ui_list->list_size = items; - ui_list->list_last_len = len; + prepare_list(ui_list, len, activei, rows, maxrows, 1, &layoutdata); if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { - if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) { - subblock = uiLayoutGetBlock(col); - overlap = uiLayoutOverlap(col); + for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) { + PointerRNA *itemptr = &items_ptr[i].item; + int org_i = items_ptr[i].org_idx; + int flt_flag = items_ptr[i].flt_flag; + subblock = uiLayoutGetBlock(col); + + overlap = uiLayoutOverlap(col); - uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); + uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); - /* list item behind label & other buttons */ - sub = uiLayoutRow(overlap, FALSE); + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); - but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, - active_dataptr, activeprop, 0, 0, i, 0, 0, NULL); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - sub = uiLayoutRow(overlap, FALSE); + sub = uiLayoutRow(overlap, FALSE); - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - if (icon == ICON_DOT) - icon = ICON_NONE; - draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, sub, dataptr, itemptr, icon, active_dataptr, active_propname, + org_i, flt_flag); - /* If we are "drawing" active item, set all labels as active. */ - if (i == activei) { - ui_layout_list_set_labels_active(sub); - } - uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); + /* If we are "drawing" active item, set all labels as active. */ + if (i == activei) { + ui_layout_list_set_labels_active(sub); } - i++; + + uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); } - RNA_PROP_END; } /* add dummy buttons to fill space */ - while (i < ui_list->list_scroll + items) { - if (i >= ui_list->list_scroll) - uiItemL(col, "", ICON_NONE); - i++; + for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) { + uiItemL(col, "", ICON_NONE); } /* add scrollbar */ - if (len > items) { + if (len > layoutdata.visual_items) { col = uiLayoutColumn(row, FALSE); - uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll, - 0, len - items, items, 0, ""); + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, + dyn_data->visual_height, 0, ""); } break; case UILST_LAYOUT_COMPACT: row = uiLayoutRow(layout, TRUE); - if (dataptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { - found = (activei == i); - - if (found) { - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - if (icon == ICON_DOT) - icon = ICON_NONE; - draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i); - } + if (dataptr->data && prop && dyn_data->items_shown > 0) { + PointerRNA *itemptr = &items_ptr[activei].item; + int org_i = items_ptr[activei].org_idx; - i++; - } - RNA_PROP_END; + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, row, dataptr, itemptr, icon, active_dataptr, active_propname, org_i, 0); } - /* if list is empty, add in dummy button */ - if (i == 0) + else { uiItemL(row, "", ICON_NONE); + } /* next/prev button */ - BLI_snprintf(numstr, sizeof(numstr), "%d :", i); + BLI_snprintf(numstr, sizeof(numstr), "%d :", dyn_data->items_shown); but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, active_dataptr, activeprop, 0, 0, 0, 0, 0, ""); - if (i == 0) + if (dyn_data->items_shown == 0) uiButSetFlag(but, UI_BUT_DISABLED); break; case UILST_LAYOUT_GRID: box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); - col = uiLayoutColumn(box, TRUE); - row = uiLayoutRow(col, FALSE); + glob = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(glob, FALSE); + col = uiLayoutColumn(row, TRUE); + subrow = NULL; /* Quite gcc warning! */ + + prepare_list(ui_list, len, activei, rows, maxrows, columns, &layoutdata); if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { + for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) { + PointerRNA *itemptr = &items_ptr[i].item; + int org_i = items_ptr[i].org_idx; + int flt_flag = items_ptr[i].flt_flag; + /* create button */ - if (!(i % 9)) - row = uiLayoutRow(col, FALSE); + if (!(i % columns)) + subrow = uiLayoutRow(col, FALSE); - subblock = uiLayoutGetBlock(row); - overlap = uiLayoutOverlap(row); + subblock = uiLayoutGetBlock(subrow); + overlap = uiLayoutOverlap(subrow); uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); @@ -2736,13 +3022,14 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co sub = uiLayoutRow(overlap, FALSE); but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, - active_dataptr, activeprop, 0, 0, i, 0, 0, NULL); + active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL); uiButSetFlag(but, UI_BUT_NO_TOOLTIP); sub = uiLayoutRow(overlap, FALSE); - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + draw_item(ui_list, C, sub, dataptr, itemptr, icon, active_dataptr, active_propname, + org_i, flt_flag); /* If we are "drawing" active item, set all labels as active. */ if (i == activei) { @@ -2750,13 +3037,67 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co } uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); + } + } - i++; + /* add dummy buttons to fill space */ + for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) { + if (!(i % columns)) { + subrow = uiLayoutRow(col, FALSE); } - RNA_PROP_END; + uiItemL(subrow, "", ICON_NONE); + } + + /* add scrollbar */ + if (len > layoutdata.visual_items) { + col = uiLayoutColumn(row, FALSE); + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, + dyn_data->visual_height, 0, ""); } break; } + + if (glob) { + row = uiLayoutRow(glob, TRUE); + subblock = uiLayoutGetBlock(row); + uiBlockSetEmboss(subblock, UI_EMBOSSN); + + if (ui_list->filter_flag & UILST_FLT_SHOW) { + but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_DOWN, 0, 0, + UI_UNIT_X, UI_UNIT_Y * 0.6f, &(ui_list->filter_flag), 0, 0, 0, 0, + TIP_("Hide filtering options")); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.6f, ui_list, + 0.0, 0.0, 0, -1, ""); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + uiBlockSetEmboss(subblock, UI_EMBOSS); + + col = uiLayoutColumn(glob, FALSE); + subblock = uiLayoutGetBlock(col); + uiDefBut(subblock, SEPR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.05f, NULL, 0.0, 0.0, 0, 0, ""); + + draw_filter(ui_list, C, col); + } + else { + but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_RIGHT, 0, 0, + UI_UNIT_X, UI_UNIT_Y * 0.6f, &(ui_list->filter_flag), 0, 0, 0, 0, + TIP_("Show filtering options")); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.6f, ui_list, + 0.0, 0.0, 0, -1, ""); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + uiBlockSetEmboss(subblock, UI_EMBOSS); + } + } + + if (items_ptr) { + MEM_freeN(items_ptr); + } } /************************* Operator Search Template **************************/ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 594d3e40dcd..b469dc994bc 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2850,6 +2850,16 @@ static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UN rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta; } +/* labels use Editor theme colors for text */ +static void widget_state_label(uiWidgetType *wt, int state) +{ + /* call this for option button */ + widget_state(wt, state); + if (state & UI_SELECT) + UI_GetThemeColor3ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text); + else + UI_GetThemeColor3ubv(TH_TEXT, (unsigned char *)wt->wcol.text); +} static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign) { @@ -2970,9 +2980,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) case UI_WTYPE_LISTLABEL: wt.wcol_theme = &btheme->tui.wcol_list_item; - /* fall-through */ /* we use usual label code too. */ + wt.draw = NULL; + /* Can't use usual label code. */ + break; case UI_WTYPE_LABEL: wt.draw = NULL; + wt.state = widget_state_label; break; case UI_WTYPE_TOGGLE: diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 1ef4d43c9f3..ace35f0276e 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -484,6 +484,14 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo case TH_STITCH_PREVIEW_ACTIVE: cp = ts->preview_stitch_active; break; + + case TH_UV_OTHERS: + cp = ts->uv_others; + break; + case TH_UV_SHADOW: + cp = ts->uv_shadow; + break; + case TH_MARKER_OUTLINE: cp = ts->marker_outline; break; case TH_MARKER: @@ -918,6 +926,9 @@ void ui_theme_init_default(void) rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0); rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140); + rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255); + rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255); + /* space text */ btheme->text = btheme->tv3d; rgba_char_args_set(btheme->text.back, 153, 153, 153, 255); @@ -2205,7 +2216,15 @@ void init_userdef_do_versions(void) } /* NOTE!! from now on use U.versionfile and U.subversionfile */ - + + if (U.versionfile < 269 || (U.versionfile == 268 && U.subversionfile < 3)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255); + rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255); + } + } + if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f656d22fc64..037fa7c6a94 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -2029,6 +2029,17 @@ void UI_view2d_to_region_no_clip(View2D *v2d, float x, float y, int *regionx, in } } +void UI_view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony) +{ + /* express given coordinates as proportional values */ + x = -v2d->cur.xmin / BLI_rctf_size_x(&v2d->cur); + y = -v2d->cur.ymin / BLI_rctf_size_y(&v2d->cur); + + /* convert proportional distances to screen coordinates */ + *regionx = v2d->mask.xmin + x * BLI_rcti_size_x(&v2d->mask); + *regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask); +} + /* *********************************************************************** */ /* Utilities */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 929b7ae2a5d..3e9e16b285c 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -128,7 +128,7 @@ static int view_pan_init(bContext *C, wmOperator *op) } /* apply transform to view (i.e. adjust 'cur' rect) */ -static void view_pan_apply(wmOperator *op) +static void view_pan_apply(bContext *C, wmOperator *op) { v2dViewPanData *vpd = op->customdata; View2D *v2d = vpd->v2d; @@ -153,6 +153,7 @@ static void view_pan_apply(wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(vpd->ar); + WM_event_add_mousemove(C); UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY); @@ -181,7 +182,7 @@ static int view_pan_exec(bContext *C, wmOperator *op) if (!view_pan_init(C, op)) return OPERATOR_CANCELLED; - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; } @@ -209,7 +210,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "deltax", event->prevx - event->x); RNA_int_set(op->ptr, "deltay", event->prevy - event->y); - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; } @@ -246,7 +247,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) vpd->lastx = event->x; vpd->lasty = event->y; - view_pan_apply(op); + view_pan_apply(C, op); break; } /* XXX - Mode switching isn't implemented. See comments in 36818. @@ -333,7 +334,7 @@ static int view_scrollright_exec(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "deltay", 0); /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -377,7 +378,7 @@ static int view_scrollleft_exec(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "deltay", 0); /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -425,7 +426,7 @@ static int view_scrolldown_exec(bContext *C, wmOperator *op) } /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -475,7 +476,7 @@ static int view_scrollup_exec(bContext *C, wmOperator *op) } /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index a1bb7a8ae88..70fa97bebc1 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -106,6 +106,24 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", filepath); BLI_ensure_extension(filepath, sizeof(filepath), ".dae"); + + /* Avoid File write exceptions in Collada */ + if (!BLI_exists(filepath)) { + BLI_make_existing_file(filepath); + if (!BLI_file_touch(filepath)) { + BKE_report(op->reports, RPT_ERROR, "Can't create export file"); + fprintf(stdout, "Collada export: Can not create: %s\n", filepath); + return OPERATOR_CANCELLED; + } + } + else if (!BLI_file_is_writable(filepath)) { + BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file"); + fprintf(stdout, "Collada export: Can not modify: %s\n", filepath); + return OPERATOR_CANCELLED; + } + + /* Now the exporter can create and write the export file */ + /* Options panel */ apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers"); export_mesh_type = RNA_enum_get(op->ptr, "export_mesh_type_selection"); @@ -129,6 +147,8 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) /* get editmode results */ ED_object_editmode_load(CTX_data_edit_object(C)); + + if (collada_export(CTX_data_scene(C), filepath, apply_modifiers, diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 9c270144a0a..4cc9d3b59b1 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -737,3 +737,159 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Location of vertex in normalized space", -1.0f, 1.0f); } + +/******************** common primitive functions *********************/ + +static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2], + int num_points, char handle_type) +{ + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + Mask *mask; + MaskLayer *mask_layer; + MaskSpline *new_spline; + float scale, location[2], frame_size[2]; + int i, width, height; + int size = RNA_float_get(op->ptr, "size"); + + ED_mask_get_size(sa, &width, &height); + scale = (float)size / max_ii(width, height); + + /* Get location in mask space. */ + frame_size[0] = width; + frame_size[1] = height; + RNA_float_get_array(op->ptr, "location", location); + location[0] /= width; + location[1] /= height; + BKE_mask_coord_from_frame(location, location, frame_size); + + /* Make it so new primitive is centered to mouse location. */ + location[0] -= 0.5f * scale; + location[1] -= 0.5f * scale; + + mask_layer = ED_mask_layer_ensure(C); + mask = CTX_data_edit_mask(C); + + ED_mask_select_toggle_all(mask, SEL_DESELECT); + + new_spline = BKE_mask_spline_add(mask_layer); + new_spline->flag = MASK_SPLINE_CYCLIC | SELECT; + new_spline->tot_point = num_points; + new_spline->points = MEM_recallocN(new_spline->points, + sizeof(MaskSplinePoint) * new_spline->tot_point); + + mask_layer->act_spline = new_spline; + mask_layer->act_point = NULL; + + for (i = 0; i < num_points; i++) { + MaskSplinePoint *new_point = &new_spline->points[i]; + + copy_v2_v2(new_point->bezt.vec[1], points[i]); + mul_v2_fl(new_point->bezt.vec[1], scale); + add_v2_v2(new_point->bezt.vec[1], location); + + new_point->bezt.h1 = handle_type; + new_point->bezt.h2 = handle_type; + BKE_mask_point_select_set(new_point, true); + } + + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + + /* TODO: only update this spline */ + BKE_mask_update_display(mask, CFRA); + + return OPERATOR_FINISHED; +} + +static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ScrArea *sa = CTX_wm_area(C); + float cursor[2]; + int width, height; + + ED_mask_get_size(sa, &width, &height); + ED_mask_cursor_location_get(sa, cursor); + + cursor[0] *= width; + cursor[1] *= height; + + RNA_float_set_array(op->ptr, "location", cursor); + + return op->type->exec(C, op); +} + +static void define_prinitive_add_properties(wmOperatorType *ot) +{ + RNA_def_float(ot->srna, "size", 100, -FLT_MAX, FLT_MAX, + "Size", "Size of new circle", -FLT_MAX, FLT_MAX); + RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, + "Location", "Location of new circle", -FLT_MAX, FLT_MAX); +} + +/******************** primitive add circle *********************/ + +static int primitive_circle_add_exec(bContext *C, wmOperator *op) +{ + const float points[4][2] = {{0.0f, 0.5f}, + {0.5f, 1.0f}, + {1.0f, 0.5f}, + {0.5f, 0.0f}}; + int num_points = sizeof(points) / (2 * sizeof(float)); + + create_primitive_from_points(C, op, points, num_points, HD_AUTO); + + return OPERATOR_FINISHED; +} + +void MASK_OT_primitive_circle_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Circle"; + ot->description = "Add new circle-shaped spline"; + ot->idname = "MASK_OT_primitive_circle_add"; + + /* api callbacks */ + ot->exec = primitive_circle_add_exec; + ot->invoke = primitive_add_invoke; + ot->poll = ED_operator_mask; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + define_prinitive_add_properties(ot); +} + +/******************** primitive add suqare *********************/ + +static int primitive_square_add_exec(bContext *C, wmOperator *op) +{ + const float points[4][2] = {{0.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 1.0f}, + {1.0f, 0.0f}}; + int num_points = sizeof(points) / (2 * sizeof(float)); + + create_primitive_from_points(C, op, points, num_points, HD_VECT); + + return OPERATOR_FINISHED; +} + +void MASK_OT_primitive_square_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Square"; + ot->description = "Add new square-shaped spline"; + ot->idname = "MASK_OT_primitive_square_add"; + + /* api callbacks */ + ot->exec = primitive_square_add_exec; + ot->invoke = primitive_add_invoke; + ot->poll = ED_operator_mask; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + define_prinitive_add_properties(ot); +} diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 9ae5b436fb3..62eb9cc240a 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -363,6 +363,40 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *ar, float *scalex, float *s } } +void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2]) +{ + if (sa) { + switch (sa->spacetype) { + case SPACE_CLIP: + { + SpaceClip *space_clip = sa->spacedata.first; + copy_v2_v2(cursor, space_clip->cursor); + break; + } + case SPACE_SEQ: + { + zero_v2(cursor); + break; + } + case SPACE_IMAGE: + { + SpaceImage *space_image = sa->spacedata.first; + copy_v2_v2(cursor, space_image->cursor); + break; + } + default: + /* possible other spaces from which mask editing is available */ + BLI_assert(0); + zero_v2(cursor); + break; + } + } + else { + BLI_assert(0); + zero_v2(cursor); + } +} + /********************** registration *********************/ void ED_operatortypes_mask(void) @@ -376,6 +410,8 @@ void ED_operatortypes_mask(void) /* add */ WM_operatortype_append(MASK_OT_add_vertex); WM_operatortype_append(MASK_OT_add_feather_vertex); + WM_operatortype_append(MASK_OT_primitive_circle_add); + WM_operatortype_append(MASK_OT_primitive_square_add); /* geometry */ WM_operatortype_append(MASK_OT_switch_direction); @@ -417,6 +453,9 @@ void ED_operatortypes_mask(void) /* layers */ WM_operatortype_append(MASK_OT_layer_move); + + /* duplicate */ + WM_operatortype_append(MASK_OT_duplicate); } void ED_keymap_mask(wmKeyConfig *keyconf) @@ -429,6 +468,9 @@ void ED_keymap_mask(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MASK_OT_new", NKEY, KM_PRESS, KM_ALT, 0); + /* add menu */ + WM_keymap_add_menu(keymap, "MASK_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0); + /* mask mode supports PET now */ ED_keymap_proportional_cycle(keyconf, keymap); ED_keymap_proportional_maskmode(keyconf, keymap); @@ -500,6 +542,9 @@ void ED_keymap_mask(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MASK_OT_shape_key_insert", IKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MASK_OT_shape_key_clear", IKEY, KM_PRESS, KM_ALT, 0); + /* duplicate */ + WM_keymap_add_item(keymap, "MASK_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); + /* for image editor only */ WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0); @@ -514,7 +559,6 @@ void ED_keymap_mask(wmKeyConfig *keyconf) void ED_operatormacros_mask(void) { - /* XXX: just for sample */ wmOperatorType *ot; wmOperatorTypeMacro *otmacro; @@ -531,4 +575,11 @@ void ED_operatormacros_mask(void) WM_operatortype_macro_define(ot, "MASK_OT_add_feather_vertex"); otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point"); RNA_boolean_set(otmacro->ptr, "slide_feather", TRUE); + + ot = WM_operatortype_append_macro("MASK_OT_duplicate_move", "Add Duplicate", "Duplicate mask and move", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MASK_OT_duplicate"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", FALSE); } diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index bd148c48980..51705aa5837 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -42,9 +42,12 @@ struct wmOperatorType; /* mask_add.c */ void MASK_OT_add_vertex(struct wmOperatorType *ot); void MASK_OT_add_feather_vertex(struct wmOperatorType *ot); +void MASK_OT_primitive_circle_add(struct wmOperatorType *ot); +void MASK_OT_primitive_square_add(struct wmOperatorType *ot); /* mask_ops.c */ struct Mask *ED_mask_new(struct bContext *C, const char *name); +struct MaskLayer *ED_mask_layer_ensure(struct bContext *C); void MASK_OT_new(struct wmOperatorType *ot); void MASK_OT_layer_new(struct wmOperatorType *ot); @@ -75,6 +78,8 @@ struct MaskSplinePoint *ED_mask_point_find_nearest( void MASK_OT_layer_move(struct wmOperatorType *ot); +void MASK_OT_duplicate(struct wmOperatorType *ot); + /* mask_relationships.c */ void MASK_OT_parent_set(struct wmOperatorType *ot); void MASK_OT_parent_clear(struct wmOperatorType *ot); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index c9d3bd19941..5ca0d133b0e 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -292,6 +292,26 @@ Mask *ED_mask_new(bContext *C, const char *name) return mask; } +/* Get ative layer. Will create mask/layer to be sure there's an active layer. */ +MaskLayer *ED_mask_layer_ensure(bContext *C) +{ + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *mask_layer; + + if (mask == NULL) { + /* If there's no active mask, create one. */ + mask = ED_mask_new(C, NULL); + } + + mask_layer = BKE_mask_layer_active(mask); + if (mask_layer == NULL) { + /* If there's no active mask layer, create one. */ + mask_layer = BKE_mask_layer_new(mask, ""); + } + + return mask_layer; +} + static int mask_new_exec(bContext *C, wmOperator *op) { char name[MAX_ID_NAME - 2]; @@ -1467,3 +1487,110 @@ void MASK_OT_layer_move(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move the active layer"); } + +/******************** duplicate *********************/ + +static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *mask_layer = BKE_mask_layer_active(mask); + MaskSpline *spline; + + if (mask_layer == NULL) { + return OPERATOR_CANCELLED; + } + + for (spline = mask_layer->splines.last; + spline; + spline = spline->prev) + { + MaskSplinePoint *point = spline->points; + int i = 0; + while (i < spline->tot_point) { + int start = i, end = -1; + /* Find next selected segment. */ + while (MASKPOINT_ISSEL_ANY(point)) { + BKE_mask_point_select_set(point, false); + end = i; + if (i >= spline->tot_point - 1) { + break; + } + i++; + point++; + } + if (end >= start) { + MaskSpline *new_spline = BKE_mask_spline_add(mask_layer); + MaskSplinePoint *new_point; + int b; + + /* BKE_mask_spline_add might allocate the points, need to free them in this case. */ + if (new_spline->points) { + MEM_freeN(new_spline->points); + } + + /* Copy options from old spline. */ + new_spline->flag = spline->flag; + new_spline->offset_mode = spline->offset_mode; + new_spline->weight_interp = spline->weight_interp; + new_spline->parent = spline->parent; + + /* Allocate new points and copy them from old spline. */ + new_spline->tot_point = end - start + 1; + new_spline->points = MEM_mallocN(sizeof(MaskSplinePoint) * new_spline->tot_point, + "duplicated mask points"); + + memcpy(new_spline->points, spline->points + start, + new_spline->tot_point * sizeof(MaskSplinePoint)); + + /* Select points and duplicate their UWs (if needed). */ + for (b = 0, new_point = new_spline->points; + b < new_spline->tot_point; + b++, new_point++) + { + if (new_point->uw) { + new_point->uw = MEM_dupallocN(new_point->uw); + } + BKE_mask_point_select_set(new_point, true); + } + + /* Clear cyclic flag if we didn't copy the whole spline. */ + if (new_spline->flag & MASK_SPLINE_CYCLIC) { + if (start != 0 || end != spline->tot_point - 1) { + new_spline->flag &= ~MASK_SPLINE_CYCLIC; + } + } + + /* Flush selection to splines. */ + new_spline->flag |= SELECT; + spline->flag &= ~SELECT; + + mask_layer->act_spline = new_spline; + } + i++; + point++; + } + } + + /* TODO: only update edited splines */ + BKE_mask_update_display(mask, CFRA); + + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + + return OPERATOR_FINISHED; +} + +void MASK_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Mask"; + ot->description = "Duplicate selected control points and segments between them"; + ot->idname = "MASK_OT_duplicate"; + + /* api callbacks */ + ot->exec = mask_duplicate_exec; + ot->poll = ED_maskedit_mask_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c index 6ced2423074..9cc1702addb 100644 --- a/source/blender/editors/mask/mask_relationships.c +++ b/source/blender/editors/mask/mask_relationships.c @@ -137,6 +137,7 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) sub_parent_name = track->name; parent_type = MASK_PARENT_POINT_TRACK; + memset(orig_corners, 0, sizeof(orig_corners)); } else if ((plane_track = BKE_tracking_plane_track_get_active(tracking)) != NULL) { MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 69ef4715df6..8d91b300ff3 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC editface.c editmesh_add.c editmesh_bevel.c + editmesh_bisect.c editmesh_extrude.c editmesh_inset.c editmesh_knife.c diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c new file mode 100644 index 00000000000..5968e0991d1 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -0,0 +1,331 @@ +/* + * ***** 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) 2013 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_bisect.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "BLI_math.h" + +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" + + +#include "mesh_intern.h" /* own include */ + +static int mesh_bisect_exec(bContext *C, wmOperator *op); + +/* -------------------------------------------------------------------- */ +/* Model Helpers */ + +typedef struct { + /* modal only */ + BMBackup mesh_backup; + bool is_first; + short twtype; +} BisectData; + +static bool mesh_bisect_interactive_calc( + bContext *C, wmOperator *op, + BMEditMesh *em, + float plane_co[3], float plane_no[3]) +{ + wmGesture *gesture = op->customdata; + BisectData *opdata; + + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + int x_start = RNA_int_get(op->ptr, "xstart"); + int y_start = RNA_int_get(op->ptr, "ystart"); + int x_end = RNA_int_get(op->ptr, "xend"); + int y_end = RNA_int_get(op->ptr, "yend"); + + /* reference location (some point infront of the view) for finding a point on a plane */ + const float *co_ref = rv3d->ofs; + float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2]; + float co_a[3], co_b[3]; + const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); + + opdata = gesture->userdata; + + /* view vector */ + ED_view3d_win_to_vector(ar, co_a_ss, co_a); + + /* view delta */ + sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss); + ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac); + + /* cross both to get a normal */ + cross_v3_v3v3(plane_no, co_a, co_b); + normalize_v3(plane_no); /* not needed but nicer for user */ + + /* point on plane, can use either start or endpoint */ + ED_view3d_win_to_3d(ar, co_ref, co_a_ss, plane_co); + + if (opdata->is_first == false) + EDBM_redo_state_restore(opdata->mesh_backup, em, false); + + opdata->is_first = false; + + return true; +} + +static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret; + + /* if the properties are set or there is no rv3d, + * skip model and exec immediately */ + + if ((CTX_wm_region_view3d(C) == NULL) || + (RNA_struct_property_is_set(op->ptr, "plane_co") && + RNA_struct_property_is_set(op->ptr, "plane_no"))) + { + return mesh_bisect_exec(C, op); + } + + ret = WM_gesture_straightline_invoke(C, op, event); + if (ret & OPERATOR_RUNNING_MODAL) { + View3D *v3d = CTX_wm_view3d(C); + + wmGesture *gesture = op->customdata; + BisectData *opdata; + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data"); + opdata->mesh_backup = EDBM_redo_state_store(em); + opdata->is_first = true; + gesture->userdata = opdata; + + /* misc other vars */ + G.moving = G_TRANSFORM_EDIT; + opdata->twtype = v3d->twtype; + v3d->twtype = 0; + } + return ret; +} + +static void edbm_bisect_exit(bContext *C, BisectData *opdata) +{ + View3D *v3d = CTX_wm_view3d(C); + EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); + v3d->twtype = opdata->twtype; + G.moving = 0; +} + +static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + wmGesture *gesture = op->customdata; + BisectData *opdata = gesture->userdata; + BisectData opdata_back = *opdata; /* annoyance, WM_gesture_straightline_modal, frees */ + int ret; + + ret = WM_gesture_straightline_modal(C, op, event); + + if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { + edbm_bisect_exit(C, &opdata_back); + } + + return ret; +} + +/* End Model Helpers */ +/* -------------------------------------------------------------------- */ + + + +static int mesh_bisect_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + + /* both can be NULL, fallbacks values are used */ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm; + BMOperator bmop; + float plane_co[3]; + float plane_no[3]; + float imat[4][4]; + + const float thresh = RNA_float_get(op->ptr, "threshold"); + const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); + const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner"); + const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer"); + + PropertyRNA *prop_plane_co; + PropertyRNA *prop_plane_no; + + prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); + if (RNA_property_is_set(op->ptr, prop_plane_co)) { + RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co); + } + else { + copy_v3_v3(plane_co, give_cursor(scene, v3d)); + RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); + } + + prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); + if (RNA_property_is_set(op->ptr, prop_plane_no)) { + RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no); + } + else { + if (rv3d) { + copy_v3_v3(plane_no, rv3d->viewinv[1]); + } + else { + /* fallback... */ + plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f; + } + RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); + } + + + + /* -------------------------------------------------------------------- */ + /* Modal support */ + /* Note: keep this isolated, exec can work wihout this */ + if ((op->customdata != NULL) && + mesh_bisect_interactive_calc(C, op, em, plane_co, plane_no)) + { + /* write back to the props */ + RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); + RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); + } + /* End Modal */ + /* -------------------------------------------------------------------- */ + + + + bm = em->bm; + + invert_m4_m4(imat, obedit->obmat); + mul_m4_v3(imat, plane_co); + mul_mat3_m4_v3(imat, plane_no); + + EDBM_op_init(em, &bmop, op, + "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b", + BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer); + BMO_op_exec(bm, &bmop); + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + if (use_fill) { + float normal_fill[3]; + BMOperator bmop_fill; + BMOperator bmop_attr; + + normalize_v3_v3(normal_fill, plane_no); + if (clear_outer == true && clear_inner == false) { + negate_v3(normal_fill); + } + + /* Fill */ + BMO_op_initf( + bm, &bmop_fill, op->flag, + "triangle_fill edges=%S normal=%v use_dissolve=%b", + &bmop, "geom_cut.out", normal_fill, true); + BMO_op_exec(bm, &bmop_fill); + + /* Copy Attributes */ + BMO_op_initf(bm, &bmop_attr, op->flag, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + &bmop_fill, "geom.out", false, true); + BMO_op_exec(bm, &bmop_attr); + + BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + + BMO_op_finish(bm, &bmop_attr); + BMO_op_finish(bm, &bmop_fill); + } + + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + return OPERATOR_CANCELLED; + } + else { + EDBM_update_generic(em, true, true); + EDBM_selectmode_flush(em); + return OPERATOR_FINISHED; + } +} + + +void MESH_OT_bisect(struct wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bisect"; + ot->description = "Enforce symmetry (both form and topological) across an axis"; + ot->idname = "MESH_OT_bisect"; + + /* api callbacks */ + ot->exec = mesh_bisect_exec; + ot->invoke = mesh_bisect_invoke; + ot->modal = mesh_bisect_modal; + ot->cancel = WM_gesture_straightline_cancel; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + + prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -FLT_MAX, FLT_MAX, + "Plane Point", "A point on the plane", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -FLT_MAX, FLT_MAX, + "Plane Normal", "The direction the plane points", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut"); + RNA_def_boolean(ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane"); + RNA_def_boolean(ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry infront of the plane"); + + RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1); + + WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); +} diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index dba19ee5da6..3966826a5b2 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -228,10 +228,8 @@ static bool edbm_inset_calc(wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } else { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE, BM_ELEM_SELECT, false); - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, false); - /* re-select faces so the verts and edges get selected too */ - BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_in, "faces", BM_FACE, BM_ELEM_SELECT, true); } if (!EDBM_op_finish(em, &bmop, op, true)) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 2e73cbd02ed..cc3d486c2f3 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -499,10 +499,12 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) { KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL; - if (kcd->prev.vert && kcd->prev.vert == kcd->curr.vert) - return; - if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge) + if ((kcd->prev.vert && kcd->prev.vert == kcd->curr.vert) || + (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge)) + { + kcd->prev = kcd->curr; return; + } kfe->draw = true; @@ -573,10 +575,17 @@ static int verge_linehit(const void *vlh1, const void *vlh2) if (lh1->l < lh2->l) return -1; else if (lh1->l > lh2->l) return 1; + else if (lh1->v && lh2->v) { + /* want like verts to sort together; just compare pointers */ + if (lh1->v < lh2->v) return -1; + else if (lh1->v > lh2->v) return 1; + else return 0; + } else return 0; } /* If there's a linehit connected (same face) as testi in range [firsti, lasti], return the first such, else -1. + * It also counts as connected if both linehits are snapped to the same vertex. * If testi is out of range, look for connection to f instead, if f is non-NULL */ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, int firsti, int lasti) { @@ -589,6 +598,11 @@ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, i { return i; } + else if (kcd->linehits[testi].v && + kcd->linehits[testi].v == kcd->linehits[i].v) + { + return i; + } } else if (f) { if (find_ref(&kcd->linehits[i].kfe->faces, f)) @@ -598,13 +612,38 @@ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, i return -1; } -/* Sort in order of distance along cut line, but take care when distances are equal */ -static void knife_sort_linehits(KnifeTool_OpData *kcd) +/* Sort in order of distance along cut line. + * Remove any successive linehits that are snapped to the same vertex. + * If joinfaces, treat hits at same distance as follows: try to find + * ordering so that preceding and succeeding hits will share a face. + */ +static void knife_sort_linehits(KnifeTool_OpData *kcd, bool joinfaces) { int i, j, k, nexti, nsame; qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); + /* Remove duplicated linehits snapped to same vertex */ + i = j = 0; /* loop copies from j to i */ + while (j < kcd->totlinehit) { + nsame = 0; + if (kcd->linehits[j].v) { + for (k = j + 1; k < kcd->totlinehit; k++) { + if (kcd->linehits[k].v != kcd->linehits[j].v) + break; + nsame++; + } + } + if (i != j) + kcd->linehits[i] = kcd->linehits[j]; + i++; + j += 1 + nsame; + } + kcd->totlinehit = i; + + if (!joinfaces) + return; + /* for ranges of equal "l", swap if neccesary to make predecessor and * successor faces connected to the linehits at either end of the range */ for (i = 0; i < kcd->totlinehit - 1; i = nexti) { @@ -653,6 +692,7 @@ static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, K knife_edge_append_face(kcd, kfenew, f); } +#if 0 static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace *facef, ListBase *lst) { BMIter bmiter; @@ -685,20 +725,33 @@ static void knife_get_edge_faces(KnifeTool_OpData *kcd, KnifeEdge *kfe, ListBase } } } +#endif + +static void copy_hit_from_posdata(BMEdgeHit *lh, KnifePosData *pos, float lambda) +{ + lh->kfe = pos->edge; + lh->v = pos->vert; + lh->f = pos->bmface; + copy_v3_v3(lh->hit, pos->co); + copy_v3_v3(lh->cagehit, pos->cage); + copy_v3_v3(lh->realhit, pos->co); + lh->l = lambda; + /* perc and schit not used by callers of this function */ +} /* BMESH_TODO: add more functionality to cut-through: * - cutting "in face" (e.g., holes) should cut in all faces, not just visible one * - perhaps improve O(n^2) algorithm used here */ static void knife_cut_through(KnifeTool_OpData *kcd) { - BMEdgeHit *lh, *lh2; + BMEdgeHit *lh, *lh2, *linehits; BMFace *f; - KnifeEdge *kfe, *kfe2, *kfe3; - KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL; - ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL}; - Ref *r, *r2; + KnifeEdge *kfe, *kfe2; + KnifeVert *v1, *v2, *lastv; + ListBase *faces1, *faces2; KnifeEdge **splitkfe; - int i, j; + bool needprev, needcurr; + int i, j, n; if (!kcd->totlinehit) { /* if no linehits then no interesting back face stuff to do */ @@ -706,93 +759,68 @@ static void knife_cut_through(KnifeTool_OpData *kcd) return; } - /* TODO: probably don't need to sort at all */ - qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); - splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through"); + /* sort eliminates hits on same vertices */ + knife_sort_linehits(kcd, false); - if (kcd->prev.vert) { - if (kcd->prev.vert == kcd->curr.vert) - return; - firstv = kcd->prev.vert; - knife_get_vert_faces(kcd, firstv, kcd->prev.bmface, &firstfaces); - } - else if (kcd->prev.edge) { - if (kcd->prev.edge == kcd->curr.edge) - return; - firstv = knife_split_edge(kcd, kcd->prev.edge, kcd->prev.co, &kfe3); - knife_get_edge_faces(kcd, kcd->prev.edge, &firstfaces); + /* code is cleaner if make prev and curr into hits (if they are on edges or verts) */ + n = kcd->totlinehit; + needprev = ((kcd->prev.vert && kcd->prev.vert != kcd->linehits[0].v) || kcd->prev.edge); + needcurr = ((kcd->curr.vert && kcd->curr.vert != kcd->linehits[n - 1].v) || kcd->curr.edge); + n += needprev + needcurr; + linehits = MEM_callocN(n * sizeof(BMEdgeHit), "knife_cut_through"); + i = 0; + if (needprev) { + copy_hit_from_posdata(&linehits[0], &kcd->prev, 0.0f); + i++; } + memcpy(linehits + i, kcd->linehits, kcd->totlinehit * sizeof(BMEdgeHit)); + i += kcd->totlinehit; + if (needcurr) + copy_hit_from_posdata(&linehits[i], &kcd->curr, 1.0f); - if (kcd->curr.vert) { - lastv = kcd->curr.vert; - knife_get_vert_faces(kcd, lastv, kcd->curr.bmface, &lastfaces); - } - else if (kcd->curr.edge) { - lastv = knife_split_edge(kcd, kcd->curr.edge, kcd->curr.co, &kfe3); - knife_get_edge_faces(kcd, kcd->curr.edge, &lastfaces); - } - - if (firstv) { - /* For each face incident to firstv, - * find the first following linehit (if any) sharing that face and connect */ - for (r = firstfaces.first; r; r = r->next) { - bool found = false; - f = r->ref; - for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) { - kfe2 = lh2->kfe; - for (r2 = kfe2->faces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); - knife_add_single_cut_through(kcd, firstv, v2, f); - found = true; - break; - } - } - } - if (!found && lastv) { - for (r2 = lastfaces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - knife_add_single_cut_through(kcd, firstv, lastv, f); - break; - } - } - } - } - } - for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) { + splitkfe = MEM_callocN(n * sizeof(KnifeEdge *), "knife_cut_through"); + + lastv = NULL; + for (i = 0, lh = linehits; i < n; i++, lh++) { kfe = lh->kfe; + v1 = NULL; - /* For each face attached to edge for this linehit, - * find the first following linehit (if any) sharing that face and connect */ - for (r = kfe->faces.first; r; r = r->next) { - bool found = false; - f = r->ref; - for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) { - kfe2 = lh2->kfe; - for (r2 = kfe2->faces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); - v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); - knife_add_single_cut_through(kcd, v1, v2, f); - found = true; - break; - } - } + /* get faces incident on hit lh */ + if (lh->v) { + v1 = lh->v; + faces1 = &v1->faces; + } + else if (kfe) { + faces1 = &kfe->faces; + } + + /* For each following hit, connect if lh1 an lh2 share a face */ + for (j = i + 1, lh2 = lh + 1; j < n; j++, lh2++) { + kfe2 = lh2->kfe; + v2 = NULL; + if (lh2->v) { + v2 = lh2->v; + faces2 = &v2->faces; } - if (!found && lastv) { - for (r2 = lastfaces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); - knife_add_single_cut_through(kcd, v1, lastv, f); - break; - } - } + else if (kfe2) { + faces2 = &kfe2->faces; + } + + f = knife_find_common_face(faces1, faces2); + if (f) { + if (!v1) + v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); + if (!v2) + v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); + knife_add_single_cut_through(kcd, v1, v2, f); + lastv = v2; } } } MEM_freeN(splitkfe); + MEM_freeN(linehits); MEM_freeN(kcd->linehits); kcd->linehits = NULL; kcd->totlinehit = 0; @@ -816,7 +844,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd) BMEdgeHit *lh, *lastlh, *firstlh; int i; - knife_sort_linehits(kcd); + knife_sort_linehits(kcd, true); lh = kcd->linehits; lastlh = firstlh = NULL; @@ -848,14 +876,14 @@ static void knife_add_cut(KnifeTool_OpData *kcd) continue; /* first linehit may be down face parallel to view */ - if (!lastlh && fabsf(lh->l) < KNIFE_FLT_EPS) + if (!lastlh && !lh->v && fabsf(lh->l) < KNIFE_FLT_EPS) continue; if (kcd->prev.is_space) { kcd->prev.is_space = 0; copy_v3_v3(kcd->prev.co, lh->hit); copy_v3_v3(kcd->prev.cage, lh->cagehit); - kcd->prev.vert = NULL; + kcd->prev.vert = lh->v; kcd->prev.edge = lh->kfe; kcd->prev.bmface = lh->f; continue; @@ -1181,9 +1209,9 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, BLI_array_declare(edges); BVHTreeOverlap *results, *result; BMLoop **ls; - float cos[9], lambda; + float cos[9], tri_norm[3], tri_plane[4], isects[2][3], lambda; unsigned int tot = 0; - int i; + int i, j, n_isects; /* for comparing distances, error of intersection depends on triangle scale. * need to scale down before squaring for accurate comparison */ @@ -1194,6 +1222,9 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, copy_v3_v3(cos + 3, v2); copy_v3_v3(cos + 6, v3); + normal_tri_v3(tri_norm, v1, v2, v3); + plane_from_point_normal_v3(tri_plane, v1, tri_norm); + BLI_bvhtree_insert(tree2, 0, cos, 3); BLI_bvhtree_balance(tree2); @@ -1217,11 +1248,24 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, continue; /* We already found a hit on this knife edge */ } - if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) { + n_isects = 0; + if (fabsf(dist_to_plane_v3(kfe->v1->cageco, tri_plane)) < KNIFE_FLT_EPS && + fabsf(dist_to_plane_v3(kfe->v2->cageco, tri_plane)) < KNIFE_FLT_EPS) + { + /* both kfe ends are in cutting triangle */ + copy_v3_v3(isects[0], kfe->v1->cageco); + copy_v3_v3(isects[1], kfe->v2->cageco); + n_isects = 2; + } + else if (isect_line_tri_epsilon_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL, depsilon)) { + /* kfe intersects cutting triangle lambda of the way along kfe */ + interp_v3_v3v3(isects[0], kfe->v1->cageco, kfe->v2->cageco, lambda); + n_isects = 1; + } + for (j = 0; j < n_isects; j++) { float p[3], no[3], view[3], sp[2]; - interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda); - + copy_v3_v3(p, isects[j]); if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) { continue; } @@ -1268,7 +1312,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, add_v3_v3(p1, no); /* ray cast */ - f_hit = BKE_bmbvh_ray_cast(bmtree, p1, no, NULL, NULL, NULL); + f_hit = BKE_bmbvh_ray_cast(bmtree, p1, no, KNIFE_FLT_EPS, NULL, NULL, NULL); } /* ok, if visible add the new point */ @@ -1283,6 +1327,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, hit.kfe = kfe; hit.v = NULL; + hit.l = 0.0f; knife_find_basef(kfe); hit.f = kfe->basef; @@ -1292,7 +1337,6 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc); copy_v3_v3(hit.realhit, p); - /* BMESH_TODO: should also snap to vertices */ if (kcd->snap_midpoints) { float perc = hit.perc; @@ -1310,6 +1354,12 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc); interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc); } + else if (hit.perc < KNIFE_FLT_EPS || hit.perc > 1.0f - KNIFE_FLT_EPS) { + /* snap to vert */ + hit.v = (hit.perc < KNIFE_FLT_EPS) ? kfe->v1 : kfe->v2; + copy_v3_v3(hit.hit, hit.v->co); + copy_v3_v3(hit.cagehit, hit.v->co); + } else { copy_v3_v3(hit.hit, p); } @@ -1502,7 +1552,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); sub_v3_v3v3(ray, origin_ofs, origin); - f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, NULL, co, cageco); + f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, 0.0f, NULL, co, cageco); if (is_space) *is_space = !f; @@ -1652,7 +1702,7 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo if (fptr) *fptr = f; - if (cure && p) { + if (cure) { if (!kcd->ignore_edge_snapping || !(cure->e)) { KnifeVert *edgesnap = NULL; @@ -1745,7 +1795,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo if (fptr) *fptr = f; - if (curv && p) { + if (curv) { copy_v3_v3(p, curv->co); copy_v3_v3(cagep, curv->cageco); @@ -1993,7 +2043,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { if (!kfv->v) { /* shouldn't we be at least copying the normal? - if not some comment here should explain why - campbell */ - kfv->v = BM_vert_create(bm, kfv->co, NULL); + kfv->v = BM_vert_create(bm, kfv->co, NULL, BM_CREATE_NOP); kfv->flag = 1; BMO_elem_flag_enable(bm, kfv->v, DEL); } @@ -2683,7 +2733,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha BM_edge_select_set(bm, l_new->e, true); } } - else { + else if (f_new) { BM_elem_select_copy(bm, bm, f_new, f); } diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index e7eaa625843..18db21a8726 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -52,6 +52,9 @@ #include "WM_types.h" +#include "bmesh.h" +#include "bmesh_tools.h" + #include "mesh_intern.h" /* own include */ struct UserData { diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 1360a180b2d..84952297235 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -50,6 +50,9 @@ #include "ED_transform.h" #include "ED_view3d.h" +#include "bmesh.h" +#include "bmesh_tools.h" + #include "mesh_intern.h" /* own include */ /** @@ -60,23 +63,29 @@ * point and would result in the same distance. */ #define INSET_DEFAULT 0.00001f -static float edbm_rip_edgedist(ARegion *ar, float mat[4][4], - const float co1[3], const float co2[3], const float mvalf[2], - const float inset) +static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4], + const float co1[3], const float co2[3], const float mvalf[2], + const float inset) { - float vec1[2], vec2[2]; + float vec1[2], vec2[2], dist_sq; ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); if (inset != 0.0f) { - const float dist = inset / len_v2v2(vec1, vec2); - interp_v2_v2v2(vec1, vec1, vec2, dist); - interp_v2_v2v2(vec2, vec2, vec1, dist); + const float dist_2d = len_v2v2(vec1, vec2); + if (dist_2d > FLT_EPSILON) { + const float dist = inset / dist_2d; + BLI_assert(finite(dist)); + interp_v2_v2v2(vec1, vec1, vec2, dist); + interp_v2_v2v2(vec2, vec2, vec1, dist); + } } - /* TODO: use dist_squared_to_line_segment_v2() looks like we only ever use for comparison */ - return dist_to_line_segment_v2(mvalf, vec1, vec2); + dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2); + BLI_assert(finite(dist_sq)); + + return dist_sq; } #if 0 @@ -488,7 +497,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u /* face should never exist */ BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false); - f = BM_face_create_quad_tri_v(bm, f_verts, f_verts[3] ? 4 : 3, f_example, false); + f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true); l_iter = BM_FACE_FIRST_LOOP(f); @@ -525,11 +534,11 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BMIter iter, liter; BMLoop *l; BMEdge *e, *e2; - BMVert *v, *ripvert = NULL; + BMVert *v; const int totvert_orig = bm->totvert; int i; float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; - float dist = FLT_MAX; + float dist_sq = FLT_MAX; float d; bool is_wire; @@ -562,15 +571,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve if (v->e) { /* find closest edge to mouse cursor */ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - int is_boundary = BM_edge_is_boundary(e); + const bool is_boundary = BM_edge_is_boundary(e); /* consider wire as boundary for this purpose, * otherwise we can't a face away from a wire edge */ totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e)); if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { if (is_boundary == false && BM_edge_is_manifold(e)) { - d = edbm_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); - if (d < dist) { - dist = d; + d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); + if ((e2 == NULL) || (d < dist_sq)) { + dist_sq = d; e2 = e; } } @@ -596,10 +605,9 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve float l_mid_co[3]; l = l_all[i1]; edbm_calc_loop_co(l, l_mid_co); - d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); - - if (d < dist) { - dist = d; + d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); + if ((e2 == NULL) || (d < dist_sq)) { + dist_sq = d; /* find the edge that is not in this loop */ e2 = NULL; @@ -647,7 +655,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_select_history_remove(bm, ese.ele); } - dist = FLT_MAX; + dist_sq = FLT_MAX; /* in the loop below we find the best vertex to drag based on its connected geometry, * either by its face corner, or connected edge (when no faces are attached) */ @@ -658,12 +666,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) { if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) { float l_mid_co[3]; - edbm_calc_loop_co(l, l_mid_co); - d = edbm_rip_edgedist(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); + edbm_calc_loop_co(l, l_mid_co); + d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); - if (d < dist) { - dist = d; + if (d < dist_sq) { + dist_sq = d; vi_best = i; } } @@ -674,12 +682,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) { if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { float e_mid_co[3]; - mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); - d = edbm_rip_edgedist(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); + mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); + d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); - if (d < dist) { - dist = d; + if (d < dist_sq) { + dist_sq = d; vi_best = i; } } @@ -730,19 +738,36 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve /* rip two adjacent edges */ if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) { /* Don't run the edge split operator in this case */ + BMVert *v_rip; - BM_elem_flag_enable(e2, BM_ELEM_TAG); /* only for face-fill (we don't call the operator) */ + l = BM_edge_vert_share_loop(e2->l, v); + + /* only tag for face-fill (we don't call the operator) */ + if (BM_edge_is_boundary(e2)) { + BM_elem_flag_enable(e2, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(l->e, BM_ELEM_TAG); + BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG); + } /* keep directly before edgesplit */ if (do_fill) { fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); } - l = e2->l; - ripvert = BM_face_vert_separate(bm, l->f, v); +#if 0 + v_rip = BM_face_vert_separate(bm, l->f, v); +#else + v_rip = BM_face_loop_separate(bm, l); +#endif + + BLI_assert(v_rip); - BLI_assert(ripvert); - if (!ripvert) { + if (v_rip) { + BM_vert_select_set(bm, v_rip, true); + } + else { if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); return OPERATOR_CANCELLED; } @@ -769,37 +794,28 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_mesh_edgesplit(em->bm, true, true, true); } - dist = FLT_MAX; + dist_sq = FLT_MAX; { /* --- select which vert --- */ BMVert *v_best = NULL; - float l_prev_co[3], l_next_co[3], l_corner_co[3]; - float scale; + float l_corner_co[3]; - dist = FLT_MAX; + dist_sq = FLT_MAX; BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { /* disable by default, re-enable winner at end */ BM_vert_select_set(bm, v, false); + BM_select_history_remove(bm, v); BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - /* calculate a point in the face, rather then calculate the middle, - * make a vector pointing between the 2 edges attached to this loop */ - sub_v3_v3v3(l_prev_co, l->prev->v->co, l->v->co); - sub_v3_v3v3(l_next_co, l->next->v->co, l->v->co); - - scale = normalize_v3(l_prev_co) + normalize_v3(l_next_co); - mul_v3_fl(l_prev_co, scale); - mul_v3_fl(l_next_co, scale); - - add_v3_v3v3(l_corner_co, l_prev_co, l_next_co); - add_v3_v3(l_corner_co, l->v->co); - d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); - if (d < dist) { + /* check if v_best is null in the _rare_ case there are numeric issues */ + edbm_calc_loop_co(l, l_corner_co); + d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); + if ((v_best == NULL) || (d < dist_sq)) { v_best = v; - dist = d; + dist_sq = d; } } } @@ -965,7 +981,7 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) BMesh *bm = em->bm; BMIter iter; BMEdge *e; - int singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); + const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); int ret; /* running in face mode hardly makes sense, so convert to region loop and rip */ diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index f4a55af742c..806ae96cb61 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2510,7 +2510,7 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op) int offset = RNA_int_get(op->ptr, "offset"); /* so input of offset zero ends up being (nth - 1) */ - offset = (offset + (nth - 1)) % nth; + offset = mod_i(offset, nth); if (edbm_deselect_nth(em, nth, offset) == false) { BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face"); @@ -2538,7 +2538,7 @@ void MESH_OT_select_nth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100); - RNA_def_int(ot->srna, "offset", 0, 0, INT_MAX, "Offset", "", 0, 100); + RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100); } void em_setup_viewcontext(bContext *C, ViewContext *vc) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 38ce56b4bc7..75ff5256e10 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -29,6 +29,8 @@ * \ingroup edmesh */ +#include <stddef.h> + #include "MEM_guardedalloc.h" #include "DNA_key_types.h" @@ -43,6 +45,7 @@ #include "BLI_noise.h" #include "BLI_math.h" #include "BLI_rand.h" +#include "BLI_sort_utils.h" #include "BKE_material.h" #include "BKE_context.h" @@ -892,14 +895,30 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; BMOperator bmop; + ListBase bm_selected_store = {NULL, NULL}; + + /* de-select all would clear otherwise */ + SWAP(ListBase, bm->selected, bm_selected_store); EDBM_op_init(em, &bmop, op, "duplicate geom=%hvef", BM_ELEM_SELECT); - BMO_op_exec(em->bm, &bmop); + BMO_op_exec(bm, &bmop); EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + + /* rebuild editselection */ + bm->selected = bm_selected_store; + + if (bm->selected.first) { + BMOpSlot *slot_vert_map_out = BMO_slot_get(bmop.slots_out, "vert_map.out"); + BMOpSlot *slot_edge_map_out = BMO_slot_get(bmop.slots_out, "edge_map.out"); + BMOpSlot *slot_face_map_out = BMO_slot_get(bmop.slots_out, "face_map.out"); + + BMO_mesh_selected_remap(bm, slot_vert_map_out, slot_edge_map_out, slot_face_map_out); + } if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; @@ -2292,7 +2311,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__); /* get the cut curve */ - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]); } @@ -2816,6 +2835,146 @@ void MESH_OT_fill(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division"); } + +/* -------------------------------------------------------------------- */ +/* Grid Fill (and helper functions) */ + +static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v)) +{ + return BM_elem_flag_test_bool(e, BM_ELEM_TAG); +} + +static float edbm_fill_grid_vert_tag_angle(BMVert *v) +{ + BMIter iter; + BMEdge *e_iter; + BMVert *v_pair[2]; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) { + v_pair[i++] = BM_edge_other_vert(e_iter, v); + } + } + BLI_assert(i == 2); + + return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)); +} + +/** + * non-essential utility function to select 2 open edge loops from a closed loop. + */ +static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc) +{ + BMEdge *e; + BMIter iter; + int count; + int span = *r_span; + + ListBase eloops = {NULL}; + struct BMEdgeLoopStore *el_store; + // LinkData *el_store; + + /* select -> tag */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + + count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm); + el_store = eloops.first; + + if (count == 1 && BM_edgeloop_is_closed(el_store) && (BM_edgeloop_length_get(el_store) & 1) == 0) { + /* be clever! detect 2 edge loops from one closed edge loop */ + const int verts_len = BM_edgeloop_length_get(el_store); + ListBase *verts = BM_edgeloop_verts_get(el_store); + BMVert *v_act = BM_mesh_active_vert_get(bm); + LinkData *v_act_link; + BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__); + int i; + + if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) { + /* pass */ + } + else { + /* find the vertex with the best angle (a corner vertex) */ + LinkData *v_link, *v_link_best = NULL; + float angle_best = -1.0f; + for (v_link = verts->first; v_link; v_link = v_link->next) { + const float angle = edbm_fill_grid_vert_tag_angle(v_link->data); + if ((angle > angle_best) || (v_link_best == NULL)) { + angle_best = angle; + v_link_best = v_link; + } + } + + v_act_link = v_link_best; + v_act = v_act_link->data; + } + + if (offset != 0) { + v_act_link = BLI_findlink(verts, offset); + v_act = v_act_link->data; + } + + /* set this vertex first */ + BLI_rotatelist_first(verts, v_act_link); + BM_edgeloop_edges_get(el_store, edges); + + + if (span_calc) { + /* calculate the span by finding the next corner in 'verts' + * we dont know what defines a corner exactly so find the 4 verts + * in the loop with the greatest angle. + * Tag them and use the first tagged vertex to calcualte the span. + * + * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each + * vert, but advantage of de-duplicating is minimal. */ + struct SortPointerByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); + LinkData *v_link; + for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) { + BMVert *v = v_link->data; + const float angle = edbm_fill_grid_vert_tag_angle(v); + ele_sort[i].sort_value = angle; + ele_sort[i].data = v; + + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + + qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse); + + for (i = 0; i < 4; i++) { + BMVert *v = ele_sort[i].data; + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + + /* now find the first... */ + for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) { + BMVert *v = v_link->data; + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + if (v != v_act) { + span = i; + break; + } + } + } + MEM_freeN(ele_sort); + } + /* end span calc */ + + + /* un-flag 'rails' */ + for (i = 0; i < span; i++) { + BM_elem_flag_disable(edges[i], BM_ELEM_TAG); + BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG); + } + MEM_freeN(edges); + } + /* else let the bmesh-operator handle it */ + + BM_mesh_edgeloops_free(&eloops); + + *r_span = span; +} + static int edbm_fill_grid_exec(bContext *C, wmOperator *op) { BMOperator bmop; @@ -2824,10 +2983,43 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); const int totedge_orig = em->bm->totedge; const int totface_orig = em->bm->totface; + const bool use_prepare = true; + + + if (use_prepare) { + /* use when we have a single loop selected */ + PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span"); + PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset"); + bool calc_span; + + const int clamp = em->bm->totvertsel; + int span; + int offset; + + if (RNA_property_is_set(op->ptr, prop_span)) { + span = RNA_property_int_get(op->ptr, prop_span); + span = min_ii(span, (clamp / 2) - 1); + calc_span = false; + } + else { + span = clamp / 4; + calc_span = true; + } + + offset = RNA_property_int_get(op->ptr, prop_offset); + offset = mod_i(offset, clamp); + + /* in simple cases, move selection for tags, but also support more advanced cases */ + edbm_fill_grid_prepare(em->bm, offset, &span, calc_span); + + RNA_property_int_set(op->ptr, prop_span, span); + } + /* end tricky prepare code */ + if (!EDBM_op_init(em, &bmop, op, "grid_fill edges=%he mat_nr=%i use_smooth=%b", - BM_ELEM_SELECT, em->mat_nr, use_smooth)) + use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, em->mat_nr, use_smooth)) { return OPERATOR_CANCELLED; } @@ -2855,6 +3047,8 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) void MESH_OT_fill_grid(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Grid Fill"; ot->description = "Fill grid from two loops"; @@ -2866,6 +3060,12 @@ void MESH_OT_fill_grid(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int edbm_fill_holes_exec(bContext *C, wmOperator *op) @@ -4441,10 +4641,17 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMOperator bmop; - EDBM_op_init(em, &bmop, op, "symmetrize input=%hvef direction=%i", - BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction")); + const float thresh = RNA_float_get(op->ptr, "threshold"); + + EDBM_op_init(em, &bmop, op, + "symmetrize input=%hvef direction=%i dist=%f", + BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh); BMO_op_exec(em->bm, &bmop); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; } @@ -4472,6 +4679,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items, BMO_SYMMETRIZE_NEGATIVE_X, "Direction", "Which sides to copy from and to"); + RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Threshold", "", 0.00001, 0.1); } static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 46cab3b4416..a64a23a9f4a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1481,7 +1481,7 @@ int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d) static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) { - BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, NULL, r_hitout, NULL); + BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); if (f && BM_edge_in_face(e, f)) return NULL; diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 1dcc0e64183..ed026258e4b 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -95,6 +95,8 @@ void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot); /* *** editmesh_bevel.c *** */ void MESH_OT_bevel(struct wmOperatorType *ot); +/* *** editmesh_bisect.c *** */ +void MESH_OT_bisect(struct wmOperatorType *ot); /* *** editmesh_extrude.c *** */ void MESH_OT_extrude_repeat(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 66e577975b6..d889ed1bc74 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -350,7 +350,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, co[1] = bmin[1] + v[1] * ch; co[2] = bmin[2] + v[2] * cs; SWAP(float, co[1], co[2]); - BM_vert_create(em->bm, co, NULL, 0); + BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP); } /* create custom data layer to save polygon idx */ @@ -381,7 +381,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, for (j = nv; j < ndv; j++) { copy_v3_v3(co, &dverts[3 * (vbase + j)]); SWAP(float, co[1], co[2]); - BM_vert_create(em->bm, co, NULL, 0); + BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP); } /* need to rebuild entirely because array size changes */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index b5352fb35f4..c98ad13acf6 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -175,6 +175,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_convex_hull); #endif + WM_operatortype_append(MESH_OT_bisect); WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetry_snap); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index d012a8ac656..ce1cacdfb3a 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -178,7 +178,6 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (kb->data) MEM_freeN(kb->data); kb->data = MEM_callocN(sizeof(float) * 3 * totvert, "join_shapekey"); kb->totelem = totvert; - kb->weights = NULL; } } else if (haskey) { @@ -1136,7 +1135,7 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em) mesh_octree_table(ob, em, NULL, 'e'); - fhash = BLI_ghash_new(mirror_facehash, mirror_facecmp, "mirror_facehash gh"); + fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface); for (a = 0, mf = mface; a < me->totface; a++, mf++) BLI_ghash_insert(fhash, mf, mf); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index de0af1d1bb8..b79eeee49d7 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -112,6 +112,8 @@ MetaElem *add_metaball_primitive(bContext *UNUSED(C), Object *obedit, float mat[ ml = BKE_mball_element_add(mball, type); ml->rad *= dia; + mball->wiresize *= dia; + mball->rendersize *= dia; copy_v3_v3(&ml->x, mat[3]); ml->flag |= SELECT; @@ -499,19 +501,13 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo /* free all MetaElems from ListBase */ static void freeMetaElemlist(ListBase *lb) { - MetaElem *ml, *next; + MetaElem *ml; if (lb == NULL) return; - ml = lb->first; - while (ml) { - next = ml->next; - BLI_remlink(lb, ml); + while ((ml = BLI_pophead(lb))) { MEM_freeN(ml); - ml = next; } - - lb->first = lb->last = NULL; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index ce61b4fce50..b907cba33e2 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1243,7 +1243,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob->parent = NULL; ob->constraints.first = ob->constraints.last = NULL; - ob->disp.first = ob->disp.last = NULL; + ob->curve_cache = NULL; ob->transflag &= ~OB_DUPLI; ob->lay = base->lay; @@ -1385,7 +1385,7 @@ static EnumPropertyItem convert_target_items[] = { static void curvetomesh(Scene *scene, Object *ob) { - if (ob->disp.first == NULL) + if (ELEM(NULL, ob->curve_cache, ob->curve_cache->disp.first)) BKE_displist_make_curveTypes(scene, ob, 0); /* force creation */ BKE_mesh_from_nurbs(ob); /* also does users */ @@ -1553,7 +1553,7 @@ static int convert_exec(bContext *C, wmOperator *op) cu = newob->data; - if (!newob->disp.first) + if ( !newob->curve_cache || !newob->curve_cache->disp.first) BKE_displist_make_curveTypes(scene, newob, 0); newob->type = OB_CURVE; @@ -1595,7 +1595,7 @@ static int convert_exec(bContext *C, wmOperator *op) curvetomesh(scene, newob); /* meshes doesn't use displist */ - BKE_displist_free(&newob->disp); + BKE_object_free_curve_cache(newob); } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { @@ -1616,7 +1616,7 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; /* meshes doesn't use displist */ - BKE_displist_free(&newob->disp); + BKE_object_free_curve_cache(newob); } curvetomesh(scene, newob); @@ -1635,7 +1635,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; } - if (!baseob->disp.first) { + if (!baseob->curve_cache || !baseob->curve_cache->disp.first) { BKE_displist_make_mball(scene, baseob); } @@ -1658,7 +1658,7 @@ static int convert_exec(bContext *C, wmOperator *op) for (a = 0; a < newob->totcol; a++) id_us_plus((ID *)me->mat[a]); } - BKE_mesh_from_metaball(&baseob->disp, newob->data); + BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data); if (obact->type == OB_MBALL) { basact = basen; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 7f7a0777bbf..c69210e2450 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -79,6 +79,7 @@ #include "BKE_softbody.h" #include "BKE_modifier.h" #include "BKE_editmesh.h" +#include "BKE_report.h" #include "ED_armature.h" #include "ED_curve.h" @@ -556,11 +557,20 @@ void ED_object_editmode_enter(bContext *C, int flag) if (flag & EM_WAITCURSOR) waitcursor(0); } -static int editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int editmode_toggle_exec(bContext *C, wmOperator *op) { + const int mode_flag = OB_MODE_EDIT; + const bool is_mode_set = CTX_data_edit_object(C); ToolSettings *toolsettings = CTX_data_tool_settings(C); - if (!CTX_data_edit_object(C)) + if (!is_mode_set) { + Scene *scene = CTX_data_scene(C); + if (!ED_object_mode_compat_set(C, scene->basact->object, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (!is_mode_set) ED_object_editmode_enter(C, EM_WAITCURSOR); else ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ @@ -582,10 +592,7 @@ static int editmode_toggle_poll(bContext *C) if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) return 0; - return (ob->type == OB_MESH || ob->type == OB_ARMATURE || - ob->type == OB_FONT || ob->type == OB_MBALL || - ob->type == OB_LATTICE || ob->type == OB_SURF || - ob->type == OB_CURVE); + return (ELEM7(ob->type, OB_MESH, OB_ARMATURE, OB_FONT, OB_MBALL, OB_LATTICE, OB_SURF, OB_CURVE)); } void OBJECT_OT_editmode_toggle(wmOperatorType *ot) @@ -598,7 +605,6 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot) /* api callbacks */ ot->exec = editmode_toggle_exec; - ot->poll = editmode_toggle_poll; /* flags */ @@ -607,16 +613,25 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot) /* *************************** */ -static int posemode_exec(bContext *C, wmOperator *UNUSED(op)) +static int posemode_exec(bContext *C, wmOperator *op) { Base *base = CTX_data_active_base(C); + Object *ob = base->object; + const int mode_flag = OB_MODE_POSE; + const bool is_mode_set = (ob->mode & mode_flag) != 0; - if (base->object->type == OB_ARMATURE) { - if (base->object == CTX_data_edit_object(C)) { + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (ob->type == OB_ARMATURE) { + if (ob == CTX_data_edit_object(C)) { ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO); ED_armature_enter_posemode(C, base); } - else if (base->object->mode & OB_MODE_POSE) + else if (is_mode_set) ED_armature_exit_posemode(C, base); else ED_armature_enter_posemode(C, base); @@ -1417,8 +1432,9 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) space = size[0] / size[1]; } else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { - Curve *cu = ob->data; - space = cu->size[0] / cu->size[1]; + float size[3]; + BKE_curve_texspace_get(ob->data, NULL, NULL, size); + space = size[0] / size[1]; } x = ibuf->x / space; @@ -1500,19 +1516,21 @@ static const char *object_mode_op_string(int mode) } /* checks the mode to be set is compatible with the object - * should be made into a generic function */ -static bool object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *ob) + * should be made into a generic function + */ +static bool object_mode_compat_test(Object *ob, ObjectMode mode) { - ObjectMode mode = RNA_enum_get(op->ptr, "mode"); - if (ob) { if (mode == OB_MODE_OBJECT) return true; switch (ob->type) { case OB_MESH: - if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) + if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | + OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) + { return true; + } break; case OB_CURVE: case OB_SURF: @@ -1535,6 +1553,30 @@ static bool object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object * return false; } +/** + * Sets the mode to a compatible state (use before entering the mode). + * + * This is so each mode's exec function can call + */ +bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *reports) +{ + bool ok; + if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { + const char *opstring = object_mode_op_string(ob->mode); + WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); + ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); + if (!ok) { + wmOperatorType *ot = WM_operatortype_find(opstring, false); + BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); + } + } + else { + ok = true; + } + + return ok; +} + static int object_mode_set_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -1542,25 +1584,31 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) ObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT; int toggle = RNA_boolean_get(op->ptr, "toggle"); - if (!ob || !object_mode_set_compat(C, op, ob)) + if (!ob || !object_mode_compat_test(ob, mode)) return OPERATOR_PASS_THROUGH; - /* Exit current mode if it's not the mode we're setting */ - if (ob->mode != OB_MODE_OBJECT && ob->mode != mode) - WM_operator_name_call(C, object_mode_op_string(ob->mode), WM_OP_EXEC_REGION_WIN, NULL); + if (ob->mode != mode) { + /* we should be able to remove this call, each operator calls */ + ED_object_mode_compat_set(C, ob, mode, op->reports); + } - if (mode != OB_MODE_OBJECT) { + /* Exit current mode if it's not the mode we're setting */ + if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) { /* Enter new mode */ - if (ob->mode != mode || toggle) - WM_operator_name_call(C, object_mode_op_string(mode), WM_OP_EXEC_REGION_WIN, NULL); - - if (toggle) { - if (ob->mode == mode) - /* For toggling, store old mode so we know what to go back to */ - ob->restore_mode = restore_mode; - else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { - WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL); - } + WM_operator_name_call(C, object_mode_op_string(mode), WM_OP_EXEC_REGION_WIN, NULL); + } + + if (toggle) { + /* Special case for Object mode! */ + if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && ob->restore_mode != OB_MODE_OBJECT) { + WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL); + } + else if (ob->mode == mode) { + /* For toggling, store old mode so we know what to go back to */ + ob->restore_mode = restore_mode; + } + else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { + WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL); } } @@ -1569,6 +1617,8 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) void OBJECT_OT_mode_set(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Set Object Mode"; ot->description = "Sets the object interaction mode"; @@ -1584,14 +1634,20 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", ""); RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); + prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } void ED_object_toggle_modes(bContext *C, int mode) { + /* Couldn't we use object_mode_op_string() here? + * Also, if several bits are set in mode, several toggle ops will be called, is this expected? + * If so, would be nice to explain why. ;) --mont29 + */ if (mode & OB_MODE_SCULPT) WM_operator_name_call(C, "SCULPT_OT_sculptmode_toggle", WM_OP_EXEC_REGION_WIN, NULL); if (mode & OB_MODE_VERTEX_PAINT) diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 03d51fcbe82..0ba84e27420 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -637,9 +637,9 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, cu = ob->data; BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tessellated/bevel vertices"); - vertexCos = BKE_curve_vertexCos_get(cu, &cu->nurb, &numVerts); + vertexCos = BKE_curve_nurbs_vertexCos_get(&cu->nurb, &numVerts); mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0); - BK_curve_vertexCos_apply(cu, &cu->nurb, vertexCos); + BK_curve_nurbs_vertexCos_apply(&cu->nurb, vertexCos); MEM_freeN(vertexCos); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 52f51cfcf48..be4948d8a80 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -55,6 +55,7 @@ #include "BLI_listbase.h" #include "BLI_linklist.h" #include "BLI_string.h" +#include "BLI_kdtree.h" #include "BLI_utildefines.h" #include "BLF_translation.h" @@ -584,12 +585,12 @@ EnumPropertyItem prop_make_parent_types[] = { {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""}, {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""}, {PAR_VERTEX, "VERTEX", 0, "Vertex", ""}, - {PAR_TRIA, "TRIA", 0, "Triangle", ""}, + {PAR_VERTEX_TRI, "VERTEX_TRI", 0, "Vertex (Triangle)", ""}, {0, NULL, 0, NULL, NULL} }; int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par, - int partype, int xmirror, int keep_transform) + int partype, bool xmirror, bool keep_transform, const int vert_par[3]) { bPoseChannel *pchan = NULL; int pararm = ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); @@ -718,8 +719,17 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object if (pchan->bone) pchan->bone->flag |= BONE_RELATIVE_PARENTING; } - else + else if (partype == PAR_VERTEX) { + ob->partype = PARVERT1; + ob->par1 = vert_par[0]; + } + else if (partype == PAR_VERTEX_TRI) { + ob->partype = PARVERT3; + copy_v3_v3_int(&ob->par1, vert_par); + } + else { ob->partype = PAROBJECT; /* note, dna define, not operator property */ + } /* constraint */ if (partype == PAR_PATH_CONST) { @@ -766,25 +776,83 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object return 1; } + + +static void parent_set_vert_find(KDTree *tree, Object *child, int vert_par[3], bool is_tri) +{ + const float *co_find = child->obmat[3]; + if (is_tri) { + KDTreeNearest nearest[3]; + int tot; + + tot = BLI_kdtree_find_nearest_n(tree, co_find, NULL, nearest, 3); + BLI_assert(tot == 3); + + vert_par[0] = nearest[0].index; + vert_par[1] = nearest[1].index; + vert_par[2] = nearest[2].index; + + BLI_assert(min_iii(UNPACK3(vert_par)) >= 0); + } + else { + vert_par[0] = BLI_kdtree_find_nearest(tree, co_find, NULL, NULL); + BLI_assert(vert_par[0] >= 0); + vert_par[1] = 0; + vert_par[2] = 0; + } +} + static int parent_set_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *par = ED_object_active_context(C); int partype = RNA_enum_get(op->ptr, "type"); - int xmirror = RNA_boolean_get(op->ptr, "xmirror"); - int keep_transform = RNA_boolean_get(op->ptr, "keep_transform"); - int ok = 1; + bool xmirror = RNA_boolean_get(op->ptr, "xmirror"); + bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform"); + bool ok = true; + + /* vertex parent (kdtree) */ + const bool is_vert_par = ELEM(partype, PAR_VERTEX, PAR_VERTEX_TRI); + const bool is_tri = partype == PAR_VERTEX_TRI; + int tree_tot; + struct KDTree *tree = NULL; + int vert_par[3] = {0, 0, 0}; + int *vert_par_p = is_vert_par ? vert_par : NULL; + + + if (is_vert_par) { + tree = BKE_object_as_kdtree(par, &tree_tot); + BLI_assert(tree != NULL); + + if (tree_tot < (is_tri ? 3 : 1)) { + BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent"); + ok = false; + goto cleanup; + } + } + + /* Non vertex-parent */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform)) { - ok = 0; + if (is_vert_par) { + parent_set_vert_find(tree, ob, vert_par, is_tri); + } + + if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { + ok = false; break; } } CTX_DATA_END; + +cleanup: + if (is_vert_par) { + BLI_kdtree_free(tree); + } + if (!ok) return OPERATOR_CANCELLED; @@ -835,6 +903,12 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE); } + /* vertex parenting */ + if (OB_TYPE_SUPPORT_PARVERT(ob->type)) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX_TRI); + } + uiPupMenuEnd(C, pup); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 366aa72f2b8..36ce72f1cab 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -562,6 +562,21 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } + else if (ob->type == OB_EMPTY) { + /* It's possible for empties too, even though they don't + * really have obdata, since we can simply apply the maximum + * scaling to the empty's drawsize. + * + * Core Assumptions: + * 1) Most scaled empties have uniform scaling + * (i.e. for visibility reasons), AND/OR + * 2) Preserving non-uniform scaling is not that important, + * and is something that many users would be willing to + * sacrifice for having an easy way to do this. + */ + float max_scale = MAX3(ob->size[0], ob->size[1], ob->size[2]); + ob->empty_drawsize *= max_scale; + } else { continue; } @@ -589,8 +604,10 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo } CTX_DATA_END; - if (!change) + if (!change) { + BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; + } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -768,7 +785,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } if (ctx_ob_act) { - BLI_rotatelist(&ctx_data_list, (LinkData *)ctx_ob_act); + BLI_rotatelist_first(&ctx_data_list, (LinkData *)ctx_ob_act); } for (tob = bmain->object.first; tob; tob = tob->id.next) { diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 294b0632015..b68fa150777 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -1561,9 +1561,12 @@ static void getVerticalAndHorizontalChange(const float norm[3], float d, const f /* A = Q - ((Q - P).N)N * D = (a * x0 + b * y0 +c * z0 + d) */ float projA[3], projB[3]; + float plane[4]; - closest_to_plane_v3(projA, coord, norm, start); - closest_to_plane_v3(projB, coord, norm, end); + plane_from_point_normal_v3(plane, coord, norm); + + closest_to_plane_v3(projA, plane, start); + closest_to_plane_v3(projB, plane, end); /* (vertical and horizontal refer to the plane's y and xz respectively) * vertical distance */ dists[index] = dot_v3v3(norm, end) + d; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index d6bb394ff79..1a561efd217 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -69,6 +69,7 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "ED_object.h" #include "ED_physics.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -2452,7 +2453,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) copy_v3_v3(co, point->keys->co); mul_m4_v3(mat, co); - totn= BLI_kdtree_find_n_nearest(tree, 10, co, NULL, nearest); + totn = BLI_kdtree_find_nearest_n(tree, co, NULL, nearest, 10); for (n=0; n<totn; n++) { /* this needs a custom threshold still */ @@ -3458,7 +3459,7 @@ static int brush_add(PEData *data, short number) float maxd, totw=0.0, weight[3]; psys_particle_on_dm(psmd->dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0, 0); - maxw= BLI_kdtree_find_n_nearest(tree, 3, co1, NULL, ptn); + maxw = BLI_kdtree_find_nearest_n(tree, co1, NULL, ptn, 3); maxd= ptn[maxw-1].dist; @@ -4345,23 +4346,36 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, static int particle_edit_toggle_poll(bContext *C) { - Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (!scene || !ob || ob->id.lib) + if (ob == NULL || ob->type != OB_MESH) return 0; - - return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)); + if (!ob->data || ((ID *)ob->data)->lib) + return 0; + if (CTX_data_edit_object(C)) + return 0; + + return (ob->particlesystem.first || + modifiers_findByType(ob, eModifierType_Cloth) || + modifiers_findByType(ob, eModifierType_Softbody)); } -static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int particle_edit_toggle_exec(bContext *C, wmOperator *op) { - Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_PARTICLE_EDIT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } - if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { + if (!is_mode_set) { PTCacheEdit *edit; - ob->mode |= OB_MODE_PARTICLE_EDIT; + ob->mode |= mode_flag; edit= PE_create_current(scene, ob); /* mesh may have changed since last entering editmode. @@ -4373,7 +4387,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL); } else { - ob->mode &= ~OB_MODE_PARTICLE_EDIT; + ob->mode &= ~mode_flag; toggle_particle_cursor(C, 0); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 3a6bd05df0b..0d6e6fb5ac1 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -164,7 +164,7 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat IMB_partial_display_buffer_update(ibuf, rectf, NULL, rr->rectx, rxmin, rymin, &scene->view_settings, &scene->display_settings, - rxmin, rymin, rxmin + xmax, rymin + ymax, TRUE); + rxmin, rymin, rxmin + xmax, rymin + ymax, true); } /* ****************************** render invoking ***************** */ @@ -270,6 +270,7 @@ typedef struct RenderJob { short anim, write_still; Image *image; ImageUser iuser; + bool image_outdated; short *stop; short *do_update; float *progress; @@ -409,9 +410,19 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec void *lock; /* only update if we are displaying the slot being rendered */ - if (ima->render_slot != ima->last_render_slot) + if (ima->render_slot != ima->last_render_slot) { + rj->image_outdated = true; return; + } + else if (rj->image_outdated) { + /* update entire render */ + rj->image_outdated = false; + BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE); + *(rj->do_update) = TRUE; + return; + } + /* update part of render */ ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); if (ibuf) { image_buffer_rect_update(rj->scene, rr, ibuf, renrect); @@ -491,7 +502,9 @@ static void render_endjob(void *rjv) * engine API, so lets use simple and robust way for now * - sergey - */ - if (rj->scene->r.layers.first != rj->scene->r.layers.last) { + if (rj->scene->r.layers.first != rj->scene->r.layers.last || + rj->image_outdated) + { void *lock; Image *ima = rj->image; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); @@ -804,6 +817,11 @@ static bool render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d return true; } +static bool render_view3d_is_valid(RenderPreview *rp) +{ + return (rp->rv3d->render_engine != NULL); +} + /* called by renderer, checks job value */ static int render_view3d_break(void *rpv) { @@ -813,8 +831,9 @@ static int render_view3d_break(void *rpv) return 1; /* during render, rv3d->engine can get freed */ - if (rp->rv3d->render_engine == NULL) + if (render_view3d_is_valid(rp) == false) { *rp->stop = 1; + } return *(rp->stop); } @@ -928,8 +947,11 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda RE_Database_Preprocess(re); /* conversion not completed, need to do it again */ - if (!rstats->convertdone) - rp->engine->job_update_flag |= PR_UPDATE_DATABASE; + if (!rstats->convertdone) { + if (render_view3d_is_valid(rp)) { + rp->engine->job_update_flag |= PR_UPDATE_DATABASE; + } + } // printf("dbase update\n"); } @@ -1116,7 +1138,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) /* Try using GLSL display transform. */ if (force_fallback == false) { - if (IMB_colormanagement_setup_glsl_draw(NULL, &scene->display_settings, TRUE)) { + if (IMB_colormanagement_setup_glsl_draw(NULL, &scene->display_settings, true, false)) { glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT, diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index e21e889d99d..57416a59aa1 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -591,7 +591,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) ibuf_save = ibuf; if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) { - ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, TRUE, TRUE, &scene->view_settings, + ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format); needs_free = TRUE; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 4bd8a7d426a..2bf8a48edc4 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -587,6 +587,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; SpaceButs *sbuts = sa->spacedata.first; + ShaderPreview *sp = WM_jobs_customdata(wm, sa); rcti newrect; int ok; int newx = BLI_rcti_size_x(rect); @@ -608,9 +609,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r *rect = newrect; /* start a new preview render job if signalled through sbuts->preview, - * or if no render result was found and no preview render job is running */ + * if no render result was found and no preview render job is running, + * or if the job is running and the size of preview changed */ if ((sbuts->spacetype == SPACE_BUTS && sbuts->preview) || - (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW))) + (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) || + (sp && (ABS(sp->sizex - newx) >= 2 || ABS(sp->sizey - newy) > 2))) { sbuts->preview = 0; ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index e805b3f30fc..7cbc8c9b277 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1806,7 +1806,7 @@ void ED_region_header_init(ARegion *ar) /* UI_UNIT_Y is defined as U variable now, depending dpi */ int ED_area_headersize(void) { - return (int)(1.3f * UI_UNIT_Y); + return (int)(HEADERY * UI_DPI_FAC); } void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_color[4]) diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 723dce5e226..13befeceee9 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -1091,15 +1091,18 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, if (ibuf->rect_float) { if (ibuf->float_colorspace) { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - ibuf->float_colorspace, TRUE); + ibuf->float_colorspace, + true, false); } else { - ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, TRUE); + ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, + true, false); } } else { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - ibuf->rect_colorspace, FALSE); + ibuf->rect_colorspace, + false, false); } if (ok) { @@ -1178,7 +1181,7 @@ int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int ro GPU_offscreen_bind(ofs); - if (!IMB_colormanagement_setup_transform_from_role_glsl(role, TRUE)) { + if (!IMB_colormanagement_setup_transform_from_role_glsl(role, true)) { GPU_offscreen_unbind(ofs); GPU_offscreen_free(ofs); return FALSE; diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 498762f1603..10c2ecd6fd9 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -327,10 +327,12 @@ static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa) static short testsplitpoint(ScrArea *sa, char dir, float fac) { short x, y; + const short area_min_x = AREAMINX; + const short area_min_y = ED_area_headersize(); // area big enough? - if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * AREAMINX)) return 0; - if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * AREAMINY)) return 0; + if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * area_min_x)) return 0; + if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * area_min_y)) return 0; // to be sure CLAMP(fac, 0.0f, 1.0f); @@ -338,10 +340,10 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac) if (dir == 'h') { y = sa->v1->vec.y + fac * (sa->v2->vec.y - sa->v1->vec.y); - if (y - sa->v1->vec.y < AREAMINY) - y = sa->v1->vec.y + AREAMINY; - else if (sa->v2->vec.y - y < AREAMINY) - y = sa->v2->vec.y - AREAMINY; + if (y - sa->v1->vec.y < area_min_y) + y = sa->v1->vec.y + area_min_y; + else if (sa->v2->vec.y - y < area_min_y) + y = sa->v2->vec.y - area_min_y; else y -= (y % AREAGRID); return y; @@ -349,10 +351,10 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac) else { x = sa->v1->vec.x + fac * (sa->v4->vec.x - sa->v1->vec.x); - if (x - sa->v1->vec.x < AREAMINX) - x = sa->v1->vec.x + AREAMINX; - else if (sa->v4->vec.x - x < AREAMINX) - x = sa->v4->vec.x - AREAMINX; + if (x - sa->v1->vec.x < area_min_x) + x = sa->v1->vec.x + area_min_x; + else if (sa->v4->vec.x - x < area_min_x) + x = sa->v4->vec.x - area_min_x; else x -= (x % AREAGRID); return x; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 3066b733fc5..a02bd1ea391 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -696,28 +696,39 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) { sActionzoneData *sad = op->customdata; - int deltax, deltay; - int mindelta = sad->az->type == AZONE_REGION ? 1 : 12; switch (event->type) { case MOUSEMOVE: + { + bool is_gesture; + + const int delta_x = (event->x - sad->x); + const int delta_y = (event->y - sad->y); + /* calculate gesture direction */ - deltax = (event->x - sad->x); - deltay = (event->y - sad->y); - - if (deltay > ABS(deltax)) + if (delta_y > ABS(delta_x)) sad->gesture_dir = 'n'; - else if (deltax > ABS(deltay)) + else if (delta_x > ABS(delta_y)) sad->gesture_dir = 'e'; - else if (deltay < -ABS(deltax)) + else if (delta_y < -ABS(delta_x)) sad->gesture_dir = 's'; else sad->gesture_dir = 'w'; + if (sad->az->type == AZONE_AREA) { + /* once we drag outside the actionzone, register a gesture + * check we're not on an edge so join finds the other area */ + is_gesture = ((is_in_area_actionzone(sad->sa1, &event->x) != sad->az) && + (screen_find_active_scredge(CTX_wm_screen(C), event->x, event->y) == NULL)); + } + else { + const int delta_min = 1; + is_gesture = (ABS(delta_x) > delta_min || ABS(delta_y) > delta_min); + } + /* gesture is large enough? */ - if (ABS(deltax) > mindelta || ABS(deltay) > mindelta) { - - /* second area, for join */ + if (is_gesture) { + /* second area, for join when (sa1 != sa2) */ sad->sa2 = screen_areahascursor(CTX_wm_screen(C), event->x, event->y); /* apply sends event */ actionzone_apply(C, op, sad->az->type); @@ -726,6 +737,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_FINISHED; } break; + } case ESCKEY: actionzone_exit(op); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index db6380e920f..345db7a0ed0 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -71,18 +71,6 @@ #include <assert.h> -static int planes_contain_v3(float (*planes)[4], int totplane, const float p[3]) -{ - int i; - - for (i = 0; i < totplane; i++) { - if (dot_v3v3(planes[i], p) + planes[i][3] > 0) - return 0; - } - - return 1; -} - /* return true if the element should be hidden/shown */ static int is_effected(PartialVisArea area, float planes[4][4], @@ -95,7 +83,7 @@ static int is_effected(PartialVisArea area, return mask > 0.5f; } else { - int inside = planes_contain_v3(planes, 4, co); + bool inside = isect_point_planes_v3(planes, 4, co); return ((inside && area == PARTIALVIS_INSIDE) || (!inside && area == PARTIALVIS_OUTSIDE)); } @@ -235,20 +223,20 @@ static void partialvis_update_grids(Object *ob, } static void partialvis_update_bmesh_verts(BMesh *bm, - GHash *verts, - PartialVisAction action, - PartialVisArea area, - float planes[4][4], - int *any_changed, - int *any_visible) + GSet *verts, + PartialVisAction action, + PartialVisArea area, + float planes[4][4], + int *any_changed, + int *any_visible) { - GHashIterator gh_iter; + GSetIterator gs_iter; - GHASH_ITER (gh_iter, verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); float *vmask = CustomData_bmesh_get(&bm->vdata, - v->head.data, - CD_PAINT_MASK); + v->head.data, + CD_PAINT_MASK); /* hide vertex if in the hide volume */ if (is_effected(area, planes, v->co, *vmask)) { @@ -272,7 +260,7 @@ static void partialvis_update_bmesh(Object *ob, float planes[4][4]) { BMesh *bm; - GHash *unique, *other; + GSet *unique, *other; int any_changed = 0, any_visible = 0; bm = BKE_pbvh_get_bmesh(pbvh); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index fcf00d4ab2c..feff02fa121 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -82,6 +82,7 @@ #include "UI_view2d.h" #include "ED_image.h" +#include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_uvedit.h" @@ -1006,9 +1007,12 @@ void PAINT_OT_sample_color(wmOperatorType *ot) static int texture_paint_toggle_poll(bContext *C) { - if (CTX_data_edit_object(C)) + Object *ob = CTX_data_active_object(C); + if (ob == NULL || ob->type != OB_MESH) return 0; - if (CTX_data_active_object(C) == NULL) + if (!ob->data || ((ID *)ob->data)->lib) + return 0; + if (CTX_data_edit_object(C)) return 0; return 1; @@ -1018,25 +1022,20 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - Mesh *me = NULL; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - if (BKE_object_obdata_is_libdata(ob)) { - BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); - return OPERATOR_CANCELLED; + const int mode_flag = OB_MODE_TEXTURE_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + Mesh *me; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } } me = BKE_mesh_from_object(ob); - if (!(ob->mode & OB_MODE_TEXTURE_PAINT) && !me) { - BKE_report(op->reports, RPT_ERROR, "Can only enter texture paint mode for mesh objects"); - return OPERATOR_CANCELLED; - } - - if (ob->mode & OB_MODE_TEXTURE_PAINT) { - ob->mode &= ~OB_MODE_TEXTURE_PAINT; + if (ob->mode & mode_flag) { + ob->mode &= ~mode_flag; if (U.glreslimit != 0) GPU_free_images(); @@ -1045,7 +1044,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 0); } else { - ob->mode |= OB_MODE_TEXTURE_PAINT; + ob->mode |= mode_flag; if (me->mtface == NULL) me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index db55dc271f1..dfada683dda 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3883,7 +3883,7 @@ static void *do_projectpaint_thread(void *ph_v) float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch); - IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, TRUE, ps->reproject_ibuf->rect_colorspace); + IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace); mul_v4_v4fl(newColor_f, newColor_f, mask); blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, @@ -4279,9 +4279,6 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m return ps; } - /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */ - curvemapping_initialize(ps->brush->curve); - paint_brush_init_tex(ps->brush); ps->source = PROJ_SRC_VIEW; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index bdf542526ee..0b0607babc1 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -1011,7 +1011,8 @@ typedef enum { RC_COLOR = 1, RC_ROTATION = 2, RC_ZOOM = 4, - RC_WEIGHT = 8 + RC_WEIGHT = 8, + RC_SECONDARY_ROTATION = 16 } RCFlags; static void set_brush_rc_path(PointerRNA *ptr, const char *brush_path, @@ -1043,7 +1044,10 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *paint, RNA_string_set(ptr, "data_path_secondary", ""); } set_brush_rc_path(ptr, brush_path, "color_path", "cursor_color_add"); - set_brush_rc_path(ptr, brush_path, "rotation_path", "texture_slot.angle"); + if (flags & RC_SECONDARY_ROTATION) + set_brush_rc_path(ptr, brush_path, "rotation_path", "mask_texture_slot.angle"); + else + set_brush_rc_path(ptr, brush_path, "rotation_path", "texture_slot.angle"); RNA_string_set(ptr, "image_id", brush_path); if (flags & RC_COLOR) @@ -1055,6 +1059,11 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *paint, else RNA_string_set(ptr, "zoom_path", ""); + if (flags & RC_SECONDARY_ROTATION) + RNA_boolean_set(ptr, "secondary_tex", true); + else + RNA_boolean_set(ptr, "secondary_tex", false); + MEM_freeN(brush_path); } @@ -1064,6 +1073,7 @@ static void ed_keymap_paint_brush_radial_control(wmKeyMap *keymap, const char *p wmKeyMapItem *kmi; /* only size needs to follow zoom, strength shows fixed size circle */ int flags_nozoom = flags & (~RC_ZOOM); + int flags_noradial_secondary = flags & (~(RC_SECONDARY_ROTATION | RC_ZOOM)); kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); set_brush_rc_props(kmi->ptr, paint, "size", "use_unified_size", flags); @@ -1078,7 +1088,12 @@ static void ed_keymap_paint_brush_radial_control(wmKeyMap *keymap, const char *p if (flags & RC_ROTATION) { kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); - set_brush_rc_props(kmi->ptr, paint, "texture_slot.angle", NULL, flags_nozoom); + set_brush_rc_props(kmi->ptr, paint, "texture_slot.angle", NULL, flags_noradial_secondary); + } + + if (flags & RC_SECONDARY_ROTATION) { + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + set_brush_rc_props(kmi->ptr, paint, "mask_texture_slot.angle", NULL, flags_nozoom); } } @@ -1265,7 +1280,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) ed_keymap_paint_brush_switch(keymap, "image_paint"); ed_keymap_paint_brush_size(keymap, "tool_settings.image_paint.brush.size"); - ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION); + ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION | RC_SECONDARY_ROTATION); ed_keymap_stencil(keymap); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 36e1b1feb38..e41d4a741ae 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -46,6 +46,7 @@ #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "WM_api.h" #include "WM_types.h" @@ -477,6 +478,9 @@ PaintStroke *paint_stroke_new(bContext *C, stroke->redraw = redraw; stroke->done = done; stroke->event_type = event_type; /* for modal, return event */ + + /* initialize here to avoid initialization conflict with threaded strokes */ + curvemapping_initialize(br->curve); BKE_paint_set_overlay_override(br->overlay_flags); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 2c654507015..538e8394b1f 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -61,6 +61,7 @@ #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_colortools.h" #include "WM_api.h" #include "WM_types.h" @@ -68,12 +69,14 @@ #include "GPU_buffers.h" #include "ED_armature.h" +#include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" #include "paint_intern.h" /* own include */ + /* check if we can do partial updates and have them draw realtime * (without rebuilding the 'derivedFinal') */ static int vertex_paint_use_fast_update_check(Object *ob) @@ -916,15 +919,13 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { - float delta[2]; - float dist_squared; - float factor = 1.0; + const float dist_squared = len_squared_v2v2(mval, co_ss); - sub_v2_v2v2(delta, mval, co_ss); - dist_squared = dot_v2v2(delta, delta); /* len squared */ if (dist_squared <= brush_size_pressure * brush_size_pressure) { Brush *brush = BKE_paint_brush(&vp->paint); const float dist = sqrtf(dist_squared); + float factor; + if (brush->mtex.tex && rgba) { if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL); @@ -935,6 +936,9 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co } factor = rgba[3]; } + else { + factor = 1.0f; + } return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); } } @@ -2025,41 +2029,28 @@ static void do_weight_paint_vertex( /* *************** set wpaint operator ****************** */ -static int wpaint_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* toggle */ +/** + * \note Keep in sync with #vpaint_mode_toggle_exec + */ +static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_WEIGHT_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; Scene *scene = CTX_data_scene(C); VPaint *wp = scene->toolsettings->wpaint; Mesh *me; - - me = BKE_mesh_from_object(ob); - if (ob->id.lib || me == NULL) return OPERATOR_PASS_THROUGH; - - if (ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT; - else ob->mode |= OB_MODE_WEIGHT_PAINT; - - - /* Weightpaint works by overriding colors in mesh, - * so need to make sure we recalc on enter and - * exit (exit needs doing regardless because we - * should redeform). - */ - DAG_id_tag_update(&me->id, 0); - - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (wp == NULL) - wp = scene->toolsettings->wpaint = new_vpaint(1); - BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); - paint_cursor_start(C, weight_paint_poll); - - mesh_octree_table(ob, NULL, NULL, 's'); - - ED_vgroup_sync_from_pose(ob); + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } } - else { - mesh_octree_table(NULL, NULL, NULL, 'e'); - mesh_mirrtopo_table(NULL, 'e'); + + me = BKE_mesh_from_object(ob); + + if (ob->mode & mode_flag) { + ob->mode &= ~mode_flag; if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { BKE_mesh_flush_select_from_verts(me); @@ -2067,10 +2058,35 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* togg else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { BKE_mesh_flush_select_from_polys(me); } + + /* weight paint spesific */ + mesh_octree_table(NULL, NULL, NULL, 'e'); + mesh_mirrtopo_table(NULL, 'e'); + } + else { + ob->mode |= mode_flag; + + if (wp == NULL) + wp = scene->toolsettings->wpaint = new_vpaint(1); + + paint_cursor_start(C, weight_paint_poll); + + BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); + + /* weight paint spesific */ + mesh_octree_table(ob, NULL, NULL, 's'); + ED_vgroup_sync_from_pose(ob); } + /* Weightpaint works by overriding colors in mesh, + * so need to make sure we recalc on enter and + * exit (exit needs doing regardless because we + * should redeform). + */ + DAG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); - + return OPERATOR_FINISHED; } @@ -2078,12 +2094,12 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* togg static int paint_poll_test(bContext *C) { Object *ob = CTX_data_active_object(C); - if (CTX_data_edit_object(C)) - return 0; - if (CTX_data_active_object(C) == NULL) + if (ob == NULL || ob->type != OB_MESH) return 0; if (!ob->data || ((ID *)ob->data)->lib) return 0; + if (CTX_data_edit_object(C)) + return 0; return 1; } @@ -2633,7 +2649,7 @@ void PAINT_OT_weight_set(wmOperatorType *ot) /* api callbacks */ ot->exec = weight_paint_set_exec; - ot->poll = mask_paint_poll; /* it was facemask_paint_poll */ + ot->poll = mask_paint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2641,40 +2657,41 @@ void PAINT_OT_weight_set(wmOperatorType *ot) /* ************ set / clear vertex paint mode ********** */ - -static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) /* toggle */ +/** + * \note Keep in sync with #wpaint_mode_toggle_exec + */ +static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_VERTEX_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; Scene *scene = CTX_data_scene(C); VPaint *vp = scene->toolsettings->vpaint; Mesh *me; - - me = BKE_mesh_from_object(ob); - - if (me == NULL || BKE_object_obdata_is_libdata(ob)) { - ob->mode &= ~OB_MODE_VERTEX_PAINT; - return OPERATOR_PASS_THROUGH; - } - - if (me && me->mloopcol == NULL) { - make_vertexcol(ob); + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } } + + me = BKE_mesh_from_object(ob); /* toggle: end vpaint */ - if (ob->mode & OB_MODE_VERTEX_PAINT) { - - ob->mode &= ~OB_MODE_VERTEX_PAINT; + if (is_mode_set) { + ob->mode &= ~mode_flag; if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { BKE_mesh_flush_select_from_polys(me); } } else { - ob->mode |= OB_MODE_VERTEX_PAINT; - /* Turn off weight painting */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) - wpaint_mode_toggle_exec(C, op); - + ob->mode |= mode_flag; + + if (me->mloopcol == NULL) { + make_vertexcol(ob); + } + if (vp == NULL) vp = scene->toolsettings->vpaint = new_vpaint(0); @@ -3407,6 +3424,9 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) ToolSettings *ts = CTX_data_tool_settings(C); VPaint *wp = ts->wpaint; struct Brush *brush = BKE_paint_brush(&wp->paint); + + curvemapping_initialize(brush->curve); + data.brush = brush; data.weightpaint = BKE_brush_weight_get(scene, brush); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 2edd00c015d..9ba4f507b69 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -70,6 +70,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_subsurf.h" +#include "BKE_colortools.h" #include "BIF_glutil.h" @@ -77,6 +78,7 @@ #include "WM_types.h" #include "ED_sculpt.h" +#include "ED_object.h" #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" /* for crazyspace correction */ @@ -91,6 +93,7 @@ #include "GPU_buffers.h" #include "bmesh.h" +#include "bmesh_tools.h" #include <math.h> #include <stdlib.h> @@ -150,6 +153,7 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) { Mesh *me = (Mesh *)ob->data; ModifierData *md; + VirtualModifierData virtualModifierData; if (ob->sculpt && ob->sculpt->bm) { /* can't combine multires and dynamic topology */ @@ -161,7 +165,7 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) return NULL; } - for (md = modifiers_getVirtualModifierList(ob); md; md = md->next) { + for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) { if (md->type == eModifierType_Multires) { MultiresModifierData *mmd = (MultiresModifierData *)md; @@ -180,8 +184,9 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) static int sculpt_has_active_modifiers(Scene *scene, Object *ob) { ModifierData *md; + VirtualModifierData virtualModifierData; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { @@ -198,6 +203,7 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) ModifierData *md; Mesh *me = (Mesh *)ob->data; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); + VirtualModifierData virtualModifierData; if (mmd || ob->sculpt->bm) return 0; @@ -206,7 +212,7 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) return 1; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { @@ -327,7 +333,7 @@ typedef struct { /* Original coordinate, normal, and mask */ const float *co; float mask; - short no[3]; + const short *no; } SculptOrigVertData; @@ -378,11 +384,10 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, } if (orig_data->normals) { - copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]); + orig_data->no = orig_data->normals[iter->i]; } else { - /* TODO: log doesn't store normals yet */ - normal_float_to_short_v3(orig_data->no, iter->bm_vert->no); + orig_data->no = BM_log_original_vert_no(orig_data->bm_log, iter->bm_vert); } } else if (orig_data->unode->type == SCULPT_UNDO_MASK) { @@ -3422,7 +3427,7 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) /* Need to allocate a bigger buffer for bigger brush size */ ss->texcache_side = 2 * radius; if (!ss->texcache || ss->texcache_side > ss->texcache_actual) { - ss->texcache = BKE_brush_gen_texture_cache(brush, radius); + ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false); ss->texcache_actual = ss->texcache_side; ss->tex_pool = BKE_image_pool_new(); } @@ -3716,7 +3721,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio Brush *brush = BKE_paint_brush(&sd->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); - float rot[3][3], scale[3], loc[3]; + float mat[3][3]; + float viewDir[3] = {0.0f, 0.0f, 1.0f}; int i; int mode; @@ -3768,6 +3774,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio brush = br; cache->saved_smooth_size = BKE_brush_size_get(scene, brush); BKE_brush_size_set(scene, brush, size); + curvemapping_initialize(brush->curve); } } } @@ -3784,12 +3791,13 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio /* cache projection matrix */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - mat4_to_loc_rot_size(loc, rot, scale, ob->obmat); - /* transposing an orthonormal matrix inverts */ - transpose_m3(rot); - ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal); - /* This takes care of rotated mesh. Instead of rotating every normal, we inverse rotate view normal. */ - mul_m3_v3(rot, cache->true_view_normal); + invert_m4_m4(ob->imat, ob->obmat); + copy_m3_m4(mat, cache->vc->rv3d->viewinv); + mul_m3_v3(mat, viewDir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, viewDir); + normalize_v3_v3(cache->true_view_normal, viewDir); + /* Initialize layer brush displacements and persistent coords */ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { /* not supported yet for multires or dynamic topology */ @@ -4561,7 +4569,9 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) static void sculpt_dynamic_topology_triangulate(BMesh *bm) { - BM_mesh_triangulate(bm, false, false, NULL, NULL); + if (bm->totloop != bm->totface * 3) { + BM_mesh_triangulate(bm, false, false, NULL, NULL); + } } void sculpt_pbvh_clear(Object *ob) @@ -4800,8 +4810,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) /* Symmetrize and re-triangulate */ BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, - "symmetrize input=%avef direction=%i", - sd->symmetrize_direction); + "symmetrize input=%avef direction=%i dist=%f", + sd->symmetrize_direction, 0.00001f); sculpt_dynamic_topology_triangulate(ss->bm); /* Finish undo */ @@ -4907,21 +4917,31 @@ int ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) return ret; } -static int sculpt_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); - Mesh *me = ob->data; + const int mode_flag = OB_MODE_SCULPT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + Mesh *me; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); int flush_recalc = 0; + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + me = BKE_mesh_from_object(ob); + /* multires in sculpt mode could have different from object mode subdivision level */ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; /* if object has got active modifiers, it's dm could be different in sculpt mode */ flush_recalc |= sculpt_has_active_modifiers(scene, ob); - if (ob->mode & OB_MODE_SCULPT) { + if (is_mode_set) { if (mmd) multires_force_update(ob); @@ -4936,13 +4956,13 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) } /* Leave sculptmode */ - ob->mode &= ~OB_MODE_SCULPT; + ob->mode &= ~mode_flag; free_sculptsession(ob); } else { /* Enter sculptmode */ - ob->mode |= OB_MODE_SCULPT; + ob->mode |= mode_flag; /* Remove dynamic-topology flag; this will be enabled if the * file was saved with dynamic topology on, but we don't diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 51e740e539f..8508123f942 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -150,20 +150,31 @@ static void set_texture_context(const bContext *C, SpaceButs *sbuts) bool valid_particles = ED_texture_context_check_particles(C); bool valid_others = ED_texture_context_check_others(C); + /* this is similar to direct user action, no need to keep "better" ctxt in _prev */ if ((sbuts->mainb == BCONTEXT_WORLD) && valid_world) { - sbuts->texture_context = SB_TEXC_WORLD; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_WORLD; } else if ((sbuts->mainb == BCONTEXT_MATERIAL) && valid_material) { - sbuts->texture_context = SB_TEXC_MATERIAL; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_MATERIAL; } else if ((sbuts->mainb == BCONTEXT_DATA) && valid_lamp) { - sbuts->texture_context = SB_TEXC_LAMP; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_LAMP; } else if ((sbuts->mainb == BCONTEXT_PARTICLE) && valid_particles) { - sbuts->texture_context = SB_TEXC_PARTICLES; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_PARTICLES; } else if ((ELEM(sbuts->mainb, BCONTEXT_MODIFIER, BCONTEXT_PHYSICS)) && valid_others) { - sbuts->texture_context = SB_TEXC_OTHER; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_OTHER; + } + /* Else, try to revive a previous "better" ctxt... */ + else if ((sbuts->texture_context_prev != sbuts->texture_context) && + (((sbuts->texture_context_prev == SB_TEXC_WORLD) && valid_world) || + ((sbuts->texture_context_prev == SB_TEXC_MATERIAL) && valid_material) || + ((sbuts->texture_context_prev == SB_TEXC_LAMP) && valid_lamp) || + ((sbuts->texture_context_prev == SB_TEXC_PARTICLES) && valid_particles) || + ((sbuts->texture_context_prev == SB_TEXC_OTHER) && valid_others))) + { + sbuts->texture_context = sbuts->texture_context_prev; } /* Else, just be sure that current context is valid! */ else if (((sbuts->texture_context == SB_TEXC_WORLD) && !valid_world) || @@ -172,13 +183,9 @@ static void set_texture_context(const bContext *C, SpaceButs *sbuts) ((sbuts->texture_context == SB_TEXC_PARTICLES) && !valid_particles) || ((sbuts->texture_context == SB_TEXC_OTHER) && !valid_others)) { - if (valid_others) { - sbuts->texture_context = SB_TEXC_OTHER; - } - else if (valid_world) { - sbuts->texture_context = SB_TEXC_WORLD; - } - else if (valid_material) { + /* this is default fallback, do keep "better" ctxt in _prev */ + sbuts->texture_context_prev = sbuts->texture_context; + if (valid_material) { sbuts->texture_context = SB_TEXC_MATERIAL; } else if (valid_lamp) { @@ -187,6 +194,12 @@ static void set_texture_context(const bContext *C, SpaceButs *sbuts) else if (valid_particles) { sbuts->texture_context = SB_TEXC_PARTICLES; } + else if (valid_world) { + sbuts->texture_context = SB_TEXC_WORLD; + } + else if (valid_others) { + sbuts->texture_context = SB_TEXC_OTHER; + } } } } diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index 18248f4775b..50bb8a0e061 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -238,7 +238,8 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) { MarkerUpdateCb *cb = (MarkerUpdateCb *) arg_cb; MovieTrackingMarker *marker; - int width, height, ok = FALSE; + int width, height; + bool ok = false; BKE_movieclip_get_size(cb->clip, cb->user, &width, &height); @@ -252,7 +253,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) DAG_id_tag_update(&cb->clip->id, 0); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - ok = TRUE; + ok = true; } else if (event == B_MARKER_PAT_DIM) { float dim[2], pat_dim[2], pat_min[2], pat_max[2]; @@ -276,7 +277,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) BKE_tracking_marker_clamp(cb->marker, CLAMP_PAT_DIM); - ok = TRUE; + ok = true; } else if (event == B_MARKER_SEARCH_POS) { float delta[2], side[2]; @@ -292,7 +293,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_POS); - ok = TRUE; + ok = true; } else if (event == B_MARKER_SEARCH_DIM) { float dim[2], search_dim[2]; @@ -313,12 +314,12 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_DIM); - ok = TRUE; + ok = true; } else if (event == B_MARKER_FLAG) { marker->flag = cb->marker_flag; - ok = TRUE; + ok = true; } else if (event == B_MARKER_OFFSET) { float offset[2], delta[2]; @@ -337,7 +338,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) DAG_id_tag_update(&cb->clip->id, 0); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - ok = TRUE; + ok = true; } if (ok) diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index eb58bdc7696..4f3f81e38dc 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -127,9 +127,11 @@ static int generic_track_get_marker_framenr(MovieTrackingTrack *track, MovieTrac int marker_index) { if (track) { + BLI_assert(marker_index < track->markersnr); return track->markers[marker_index].framenr; } else if (plane_track) { + BLI_assert(marker_index < plane_track->markersnr); return plane_track->markers[marker_index].framenr; } @@ -140,6 +142,7 @@ static bool generic_track_is_marker_enabled(MovieTrackingTrack *track, MovieTrac int marker_index) { if (track) { + BLI_assert(marker_index < track->markersnr); return (track->markers[marker_index].flag & MARKER_DISABLED) == 0; } else if (plane_track) { @@ -153,9 +156,11 @@ static bool generic_track_is_marker_keyframed(MovieTrackingTrack *track, MovieTr int marker_index) { if (track) { + BLI_assert(marker_index < track->markersnr); return (track->markers[marker_index].flag & MARKER_TRACKED) == 0; } else if (plane_track) { + BLI_assert(marker_index < plane_track->markersnr); return (plane_track->markers[marker_index].flag & PLANE_MARKER_TRACKED) == 0; } @@ -212,6 +217,8 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc a++; } + a = min_ii(a, markersnr - 1); + if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) { framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); @@ -235,11 +242,11 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc glColor4ub(255, 0, 0, 96); for (i = sfra, a = 0; i <= efra; i++) { - int ok = FALSE; + bool ok = false; while (a < n) { if (cameras[a].framenr == i) { - ok = TRUE; + ok = true; break; } else if (cameras[a].framenr > i) { @@ -280,11 +287,11 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; char str[256] = {0}; - int block = FALSE; + bool block = false; if (tracking->stats) { BLI_strncpy(str, tracking->stats->message, sizeof(str)); - block = TRUE; + block = true; } else { if (sc->flag & SC_LOCK_SELECTION) @@ -490,7 +497,7 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT float marker_pos[2], int width, int height) { int tiny = sc->flag & SC_SHOW_TINY_MARKER; - int show_search = FALSE; + bool show_search = false; float px[2]; UI_ThemeColor(TH_MARKER_OUTLINE); @@ -553,8 +560,8 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT glEnd(); } - show_search = TRACK_VIEW_SELECTED(sc, track) && - ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0); + show_search = (TRACK_VIEW_SELECTED(sc, track) && + ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0; if (sc->flag & SC_SHOW_MARKER_SEARCH && show_search) { glBegin(GL_LINE_LOOP); glVertex2f(marker->search_min[0], marker->search_min[1]); @@ -593,7 +600,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra float marker_pos[2], int width, int height, int act, int sel) { int tiny = sc->flag & SC_SHOW_TINY_MARKER; - int show_search = 0; + bool show_search = false; float col[3], scol[3], px[2]; track_colors(track, act, col, scol); @@ -708,8 +715,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra } /* search */ - show_search = TRACK_VIEW_SELECTED(sc, track) && - ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0); + show_search = (TRACK_VIEW_SELECTED(sc, track) && + ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0; if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) { if (track->flag & TRACK_LOCKED) { if (act) @@ -997,17 +1004,6 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra } } -static void view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony) -{ - /* express given coordinates as proportional values */ - x = -v2d->cur.xmin / BLI_rctf_size_x(&v2d->cur); - y = -v2d->cur.ymin / BLI_rctf_size_y(&v2d->cur); - - /* convert proportional distances to screen coordinates */ - *regionx = v2d->mask.xmin + x * BLI_rcti_size_x(&v2d->mask); - *regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask); -} - static void plane_track_colors(bool is_active, float color[3], float selected_color[3]) { UI_GetThemeColor3fv(TH_MARKER, color); @@ -1071,8 +1067,6 @@ static void draw_plane_marker_ex(SpaceClip *sc, MovieTrackingPlaneTrack *plane_t else if (tiny) { glLineStipple(3, 0xaaaa); glEnable(GL_LINE_STIPPLE); - glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(GL_NOR); } /* Draw rectangle itself. */ @@ -1120,10 +1114,7 @@ static void draw_plane_marker_ex(SpaceClip *sc, MovieTrackingPlaneTrack *plane_t } } else if (tiny) { - glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_LINE_STIPPLE); - glLineStipple(3, 0xaaaa); - glEnable(GL_LINE_STIPPLE); } } @@ -1173,7 +1164,7 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, * to avoid this flickering, calculate base point in the same way as it happens * in UI_view2d_to_region_no_clip, but do it in floats here */ - view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); + UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); @@ -1416,7 +1407,7 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, if ((sc->flag & SC_SHOW_GRID) == 0 && (sc->flag & SC_MANUAL_CALIBRATION) == 0) return; - view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); + UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 08d0af817a8..0d64a3ce594 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -262,15 +262,15 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale /* returns color in SRGB */ /* matching ED_space_image_color_sample() */ -int ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3]) +bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3]) { ImBuf *ibuf; float fx, fy, co[2]; - int ret = FALSE; + bool ret = false; ibuf = ED_space_clip_get_buffer(sc); if (!ibuf) { - return FALSE; + return false; } /* map the mouse coords to the backdrop image space */ @@ -290,12 +290,12 @@ int ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_ if (ibuf->rect_float) { fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x)); linearrgb_to_srgb_v3_v3(r_col, fp); - ret = TRUE; + ret = true; } else if (ibuf->rect) { cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x); rgb_uchar_to_float(r_col, cp); - ret = TRUE; + ret = true; } } @@ -325,11 +325,12 @@ void ED_clip_update_frame(const Main *mainp, int cfra) } } -static int selected_boundbox(SpaceClip *sc, float min[2], float max[2]) +static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2]) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTrackingTrack *track; - int width, height, ok = FALSE; + int width, height; + bool ok = false; ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -362,7 +363,7 @@ static int selected_boundbox(SpaceClip *sc, float min[2], float max[2]) minmax_v2v2_v2(min, max, pos); - ok = TRUE; + ok = true; } } @@ -372,7 +373,7 @@ static int selected_boundbox(SpaceClip *sc, float min[2], float max[2]) return ok; } -int ED_clip_view_selection(const bContext *C, ARegion *ar, int fit) +bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit) { SpaceClip *sc = CTX_wm_space_clip(C); int w, h, frame_width, frame_height; @@ -381,10 +382,10 @@ int ED_clip_view_selection(const bContext *C, ARegion *ar, int fit) ED_space_clip_get_size(sc, &frame_width, &frame_height); if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) - return FALSE; + return false; if (!selected_boundbox(sc, min, max)) - return FALSE; + return false; /* center view */ clip_view_center_to_point(sc, (max[0] + min[0]) / (2 * frame_width), @@ -412,7 +413,7 @@ int ED_clip_view_selection(const bContext *C, ARegion *ar, int fit) sc->zoom = newzoom; } - return TRUE; + return true; } void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[2]) @@ -500,22 +501,22 @@ void ED_clip_mouse_pos(SpaceClip *sc, ARegion *ar, const int mval[2], float co[2 ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &co[0], &co[1]); } -int ED_space_clip_check_show_trackedit(SpaceClip *sc) +bool ED_space_clip_check_show_trackedit(SpaceClip *sc) { if (sc) { return ELEM3(sc->mode, SC_MODE_TRACKING, SC_MODE_RECONSTRUCTION, SC_MODE_DISTORTION); } - return FALSE; + return false; } -int ED_space_clip_check_show_maskedit(SpaceClip *sc) +bool ED_space_clip_check_show_maskedit(SpaceClip *sc) { if (sc) { return sc->mode == SC_MODE_MASKEDIT; } - return FALSE; + return false; } /* ******** clip editing functions ******** */ diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c index 973200dc340..173d65ee4fc 100644 --- a/source/blender/editors/space_clip/clip_graph_draw.c +++ b/source/blender/editors/space_clip/clip_graph_draw.c @@ -126,7 +126,7 @@ static void tracking_segment_end_cb(void *UNUSED(userdata)) static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord, int scene_framenr, float val) { - struct { MovieTrackingTrack *act_track; int sel; float xscale, yscale, hsize; } *data = userdata; + struct { MovieTrackingTrack *act_track; bool sel; float xscale, yscale, hsize; } *data = userdata; int sel = 0, sel_flag; if (track != data->act_track) @@ -151,7 +151,7 @@ static void draw_tracks_curves(View2D *v2d, SpaceClip *sc) MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); int width, height; - struct { MovieTrackingTrack *act_track; int sel; float xscale, yscale, hsize; } userdata; + struct { MovieTrackingTrack *act_track; bool sel; float xscale, yscale, hsize; } userdata; BKE_movieclip_get_size(clip, &sc->user, &width, &height); @@ -160,7 +160,7 @@ static void draw_tracks_curves(View2D *v2d, SpaceClip *sc) /* non-selected knot handles */ userdata.hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); - userdata.sel = FALSE; + userdata.sel = false; userdata.act_track = act_track; UI_view2d_getscale(v2d, &userdata.xscale, &userdata.yscale); clip_graph_tracking_values_iterate(sc, sc->flag & SC_SHOW_GRAPH_SEL_ONLY, sc->flag & SC_SHOW_GRAPH_HIDDEN, diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index cdb0fdadebd..393f92f5af5 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -96,8 +96,8 @@ static void toggle_selection_cb(void *userdata, MovieTrackingMarker *marker) /******************** mouse select operator ********************/ typedef struct { - int coord, /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */ - has_prev; /* if there's valid coordinate of previous point of curve segment */ + int coord; /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */ + bool has_prev; /* if there's valid coordinate of previous point of curve segment */ float min_dist, /* minimal distance between mouse and currently found entuty */ mouse_co[2], /* mouse coordinate */ @@ -134,7 +134,7 @@ static void find_nearest_tracking_segment_end_cb(void *userdata) { MouseSelectUserData *data = userdata; - data->has_prev = FALSE; + data->has_prev = false; } static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *track, @@ -163,7 +163,7 @@ static void mouse_select_init_data(MouseSelectUserData *userdata, float *co) copy_v2_v2(userdata->mouse_co, co); } -static int mouse_select_knot(bContext *C, float co[2], int extend) +static bool mouse_select_knot(bContext *C, float co[2], bool extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -200,15 +200,15 @@ static int mouse_select_knot(bContext *C, float co[2], int extend) else userdata.marker->flag |= MARKER_GRAPH_SEL_Y; - return TRUE; + return true; } } } - return FALSE; + return false; } -static int mouse_select_curve(bContext *C, float co[2], int extend) +static bool mouse_select_curve(bContext *C, float co[2], bool extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -242,15 +242,15 @@ static int mouse_select_curve(bContext *C, float co[2], int extend) toggle_selection_cb); } - return TRUE; + return true; } - return FALSE; + return false; } -static int mouse_select(bContext *C, float co[2], int extend) +static int mouse_select(bContext *C, float co[2], bool extend) { - int sel = FALSE; + bool sel = false; /* first try to select knot on selected curves */ sel = mouse_select_knot(C, co, extend); @@ -269,7 +269,7 @@ static int mouse_select(bContext *C, float co[2], int extend) static int select_exec(bContext *C, wmOperator *op) { float co[2]; - int extend = RNA_boolean_get(op->ptr, "extend"); + bool extend = RNA_boolean_get(op->ptr, "extend"); RNA_float_get_array(op->ptr, "location", co); @@ -313,7 +313,8 @@ void CLIP_OT_graph_select(wmOperatorType *ot) typedef struct BorderSelectuserData { rctf rect; - int change, mode, extend; + int mode; + bool change, extend; } BorderSelectuserData; static void border_select_cb(void *userdata, MovieTrackingTrack *UNUSED(track), @@ -352,13 +353,17 @@ static int border_select_graph_exec(bContext *C, wmOperator *op) BorderSelectuserData userdata; rcti rect; + if (act_track == NULL) { + return OPERATOR_CANCELLED; + } + /* get rectangle from operator */ WM_operator_properties_border_to_rcti(op, &rect); UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &userdata.rect.xmin, &userdata.rect.ymin); UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &userdata.rect.xmax, &userdata.rect.ymax); - userdata.change = FALSE; + userdata.change = false; userdata.mode = RNA_int_get(op->ptr, "gesture_mode"); userdata.extend = RNA_boolean_get(op->ptr, "extend"); diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 8d112b7413c..e6f1813b3a4 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -112,6 +112,8 @@ void CLIP_OT_prefetch(struct wmOperatorType *ot); void CLIP_OT_set_scene_frames(wmOperatorType *ot); +void CLIP_OT_cursor_set(struct wmOperatorType *ot); + /* clip_toolbar.c */ struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa); void CLIP_OT_tools(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index de19df9abe2..f96a0e71dfc 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -181,7 +181,7 @@ static int open_exec(bContext *C, wmOperator *op) PointerRNA fileptr; PropertyRNA *prop; char dir_only[FILE_MAX], file_only[FILE_MAX]; - int relative = RNA_boolean_get(op->ptr, "relative_path"); + bool relative = RNA_boolean_get(op->ptr, "relative_path"); RNA_string_get(op->ptr, "directory", dir_only); if (relative) @@ -353,7 +353,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event) WM_event_add_modal_handler(C, op); } -static void view_pan_exit(bContext *C, wmOperator *op, int cancel) +static void view_pan_exit(bContext *C, wmOperator *op, bool cancel) { ViewPanData *vpd = op->customdata; @@ -502,7 +502,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event) WM_event_add_modal_handler(C, op); } -static void view_zoom_exit(bContext *C, wmOperator *op, int cancel) +static void view_zoom_exit(bContext *C, wmOperator *op, bool cancel) { SpaceClip *sc = CTX_wm_space_clip(C); ViewZoomData *vpd = op->customdata; @@ -736,7 +736,7 @@ static int view_all_exec(bContext *C, wmOperator *op) ARegion *ar; int w, h, width, height; float aspx, aspy; - int fit_view = RNA_boolean_get(op->ptr, "fit_view"); + bool fit_view = RNA_boolean_get(op->ptr, "fit_view"); float zoomx, zoomy; /* retrieve state */ @@ -782,6 +782,8 @@ static int view_all_exec(bContext *C, wmOperator *op) void CLIP_OT_view_all(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View All"; ot->idname = "CLIP_OT_view_all"; @@ -792,7 +794,8 @@ void CLIP_OT_view_all(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* properties */ - RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /********************** view selected operator *********************/ @@ -943,7 +946,8 @@ typedef struct ProxyBuildJob { Scene *scene; struct Main *main; MovieClip *clip; - int clip_flag, stop; + int clip_flag; + bool stop; struct IndexBuildContext *index_context; } ProxyJob; @@ -1123,10 +1127,10 @@ static void *do_proxy_thread(void *data_v) ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect, NULL, "proxy frame"); BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, NULL, cfra, - data->build_sizes, data->build_count, FALSE); + data->build_sizes, data->build_count, false); BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, data->distortion, cfra, - data->build_undistort_sizes, data->build_undistort_count, TRUE); + data->build_undistort_sizes, data->build_undistort_count, true); IMB_freeImBuf(ibuf); @@ -1455,6 +1459,51 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot) ot->exec = clip_set_scene_frames_exec; } +/******************** set 3d cursor operator ********************/ + +static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op) +{ + SpaceClip *sclip = CTX_wm_space_clip(C); + + RNA_float_get_array(op->ptr, "location", sclip->cursor); + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); + + return OPERATOR_FINISHED; +} + +static int clip_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceClip *sclip = CTX_wm_space_clip(C); + float location[2]; + + ED_clip_mouse_pos(sclip, ar, event->mval, location); + RNA_float_set_array(op->ptr, "location", location); + + return clip_set_2d_cursor_exec(C, op); +} + +void CLIP_OT_cursor_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set 2D Cursor"; + ot->description = "Set 2D cursor location"; + ot->idname = "CLIP_OT_cursor_set"; + + /* api callbacks */ + ot->exec = clip_set_2d_cursor_exec; + ot->invoke = clip_set_2d_cursor_invoke; + ot->poll = ED_space_clip_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", + "Cursor location in normalized clip coordinates", -10.0f, 10.0f); +} + /********************** macroses *********************/ void ED_operatormacros_clip(void) diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 72a3cb98a6a..635aa388541 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -76,7 +76,8 @@ void clip_graph_tracking_values_iterate_track( BKE_movieclip_get_size(clip, &sc->user, &width, &height); for (coord = 0; coord < 2; coord++) { - int i, open = FALSE, prevfra = 0; + int i, prevfra = 0; + bool open = false; float prevval = 0.0f; for (i = 0; i < track->markersnr; i++) { @@ -88,7 +89,7 @@ void clip_graph_tracking_values_iterate_track( if (segment_end) segment_end(userdata); - open = FALSE; + open = false; } continue; @@ -98,7 +99,7 @@ void clip_graph_tracking_values_iterate_track( if (segment_start) segment_start(userdata, track, coord); - open = TRUE; + open = true; prevval = marker->pos[coord]; } @@ -184,7 +185,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); - int has_bundle = FALSE, update_stab = FALSE; + bool has_bundle = false, update_stab = false; if (track == act_track) tracking->act_track = NULL; @@ -192,19 +193,19 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) if (track == stab->rot_track) { stab->rot_track = NULL; - update_stab = TRUE; + update_stab = true; } /* handle reconstruction display in 3d viewport */ if (track->flag & TRACK_HAS_BUNDLE) - has_bundle = TRUE; + has_bundle = true; /* Make sure no plane will use freed track */ for (plane_track = plane_tracks_base->first; plane_track; plane_track = next_plane_track) { - bool found = false; + bool found = false; int i; next_plane_track = plane_track->next; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 8213853c937..8ecf9635af9 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -56,6 +56,7 @@ #include "ED_screen.h" #include "ED_clip.h" #include "ED_transform.h" +#include "ED_uvedit.h" /* just for draw_image_cursor */ #include "IMB_imbuf.h" @@ -442,6 +443,7 @@ static void clip_operatortypes(void) WM_operatortype_append(CLIP_OT_view_ndof); WM_operatortype_append(CLIP_OT_prefetch); WM_operatortype_append(CLIP_OT_set_scene_frames); + WM_operatortype_append(CLIP_OT_cursor_set); /* ** clip_toolbar.c ** */ WM_operatortype_append(CLIP_OT_tools); @@ -724,6 +726,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf) RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_ALL); RNA_boolean_set(kmi->ptr, "clear_active", FALSE); + /* Cursor */ + WM_keymap_add_item(keymap, "CLIP_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0); + /* ******** Hotkeys avalaible for preview region only ******** */ keymap = WM_keymap_find(keyconf, "Clip Graph Editor", SPACE_CLIP, 0); @@ -854,36 +859,36 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ARegion *ar_preview = ED_clip_has_preview_region(C, sa); ARegion *ar_properties = ED_clip_has_properties_region(sa); ARegion *ar_channels = ED_clip_has_channels_region(sa); - int main_visible = FALSE, preview_visible = FALSE, tools_visible = FALSE; - int tool_props_visible = FALSE, properties_visible = FALSE, channels_visible = FALSE; - int view_changed = FALSE; + bool main_visible = false, preview_visible = false, tools_visible = false; + bool tool_props_visible = false, properties_visible = false, channels_visible = false; + bool view_changed = false; switch (sc->view) { case SC_VIEW_CLIP: - main_visible = TRUE; - preview_visible = FALSE; - tools_visible = TRUE; - tool_props_visible = TRUE; - properties_visible = TRUE; - channels_visible = FALSE; + main_visible = true; + preview_visible = false; + tools_visible = true; + tool_props_visible = true; + properties_visible = true; + channels_visible = false; break; case SC_VIEW_GRAPH: - main_visible = FALSE; - preview_visible = TRUE; - tools_visible = FALSE; - tool_props_visible = FALSE; - properties_visible = FALSE; - channels_visible = FALSE; + main_visible = false; + preview_visible = true; + tools_visible = false; + tool_props_visible = false; + properties_visible = false; + channels_visible = false; reinit_preview_region(C, ar_preview); break; case SC_VIEW_DOPESHEET: - main_visible = FALSE; - preview_visible = TRUE; - tools_visible = FALSE; - tool_props_visible = FALSE; - properties_visible = FALSE; - channels_visible = TRUE; + main_visible = false; + preview_visible = true; + tools_visible = false; + tool_props_visible = false; + properties_visible = false; + channels_visible = true; reinit_preview_region(C, ar_preview); break; @@ -893,12 +898,12 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) { ar_main->flag &= ~RGN_FLAG_HIDDEN; ar_main->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) { ar_main->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } else { @@ -906,11 +911,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_main->flag |= RGN_FLAG_HIDDEN; ar_main->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_main->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) { ar_main->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -918,11 +923,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_properties && (ar_properties->flag & RGN_FLAG_HIDDEN)) { ar_properties->flag &= ~RGN_FLAG_HIDDEN; ar_properties->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_properties && ar_properties->alignment != RGN_ALIGN_RIGHT) { ar_properties->alignment = RGN_ALIGN_RIGHT; - view_changed = TRUE; + view_changed = true; } } else { @@ -930,11 +935,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_properties->flag |= RGN_FLAG_HIDDEN; ar_properties->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_properties->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_properties && ar_properties->alignment != RGN_ALIGN_NONE) { ar_properties->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -942,11 +947,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_tools && (ar_tools->flag & RGN_FLAG_HIDDEN)) { ar_tools->flag &= ~RGN_FLAG_HIDDEN; ar_tools->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_tools && ar_tools->alignment != RGN_ALIGN_LEFT) { ar_tools->alignment = RGN_ALIGN_LEFT; - view_changed = TRUE; + view_changed = true; } } else { @@ -954,11 +959,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_tools->flag |= RGN_FLAG_HIDDEN; ar_tools->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_tools->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_tools && ar_tools->alignment != RGN_ALIGN_NONE) { ar_tools->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -966,11 +971,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_tool_props && (ar_tool_props->flag & RGN_FLAG_HIDDEN)) { ar_tool_props->flag &= ~RGN_FLAG_HIDDEN; ar_tool_props->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_tool_props && (ar_tool_props->alignment != (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) { ar_tool_props->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - view_changed = TRUE; + view_changed = true; } } else { @@ -978,11 +983,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_tool_props->flag |= RGN_FLAG_HIDDEN; ar_tool_props->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_tool_props->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_tool_props && ar_tool_props->alignment != RGN_ALIGN_NONE) { ar_tool_props->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -991,11 +996,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_preview->flag &= ~RGN_FLAG_HIDDEN; ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; ar_preview->v2d.cur = ar_preview->v2d.tot; - view_changed = TRUE; + view_changed = true; } if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) { ar_preview->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } else { @@ -1003,11 +1008,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_preview->flag |= RGN_FLAG_HIDDEN; ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_preview->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) { ar_preview->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -1015,11 +1020,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_channels && (ar_channels->flag & RGN_FLAG_HIDDEN)) { ar_channels->flag &= ~RGN_FLAG_HIDDEN; ar_channels->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_channels && ar_channels->alignment != RGN_ALIGN_LEFT) { ar_channels->alignment = RGN_ALIGN_LEFT; - view_changed = TRUE; + view_changed = true; } } else { @@ -1027,11 +1032,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_channels->flag |= RGN_FLAG_HIDDEN; ar_channels->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_channels->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_channels && ar_channels->alignment != RGN_ALIGN_NONE) { ar_channels->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -1116,6 +1121,8 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); + float aspx, aspy, zoomx, zoomy, x, y; + int width, height; /* if tracking is in progress, we should synchronize framenr from clipuser * so latest tracked frame would be shown */ @@ -1147,29 +1154,38 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) clip_draw_main(C, sc, ar); - if (sc->mode == SC_MODE_MASKEDIT) { + /* TODO(sergey): would be nice to find a way to de-duplicate all this space conversions */ + UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); + ED_space_clip_get_size(sc, &width, &height); + ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy); + ED_space_clip_get_aspect(sc, &aspx, &aspy); + if (sc->mode == SC_MODE_MASKEDIT) { Mask *mask = CTX_data_edit_mask(C); if (mask) { ScrArea *sa = CTX_wm_area(C); - int width, height; - float aspx, aspy; - ED_mask_get_size(sa, &width, &height); - ED_space_clip_get_aspect(sc, &aspx, &aspy); + int mask_width, mask_height; + ED_mask_get_size(sa, &mask_width, &mask_height); ED_mask_draw_region(mask, ar, sc->mask_info.draw_flag, sc->mask_info.draw_type, - width, height, + mask_width, mask_height, aspx, aspy, TRUE, TRUE, sc->stabmat, C); } - - } + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(zoomx, zoomy, 0); + glMultMatrixf(sc->stabmat); + glScalef(width, height, 0); + draw_image_cursor(ar, sc->cursor); + glPopMatrix(); + if (sc->flag & SC_SHOW_GPENCIL) { /* Grease Pencil */ - clip_draw_grease_pencil((bContext *)C, TRUE); + clip_draw_grease_pencil((bContext *)C, true); } /* reset view matrix */ @@ -1177,7 +1193,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) if (sc->flag & SC_SHOW_GPENCIL) { /* draw Grease Pencil - screen space only */ - clip_draw_grease_pencil((bContext *)C, FALSE); + clip_draw_grease_pencil((bContext *)C, false); } } diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index e14fc8ad399..8106befcab8 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -593,14 +593,14 @@ static int mouse_on_tilt(SpaceClip *sc, MovieTrackingMarker *marker, float co[2] return mouse_on_slide_zone(sc, marker, TRACK_AREA_PAT, co, slider, 0.0f, width, height); } -static int slide_check_corners(float (*corners)[2]) +static bool slide_check_corners(float (*corners)[2]) { int i, next, prev; float cross = 0.0f; float p[2] = {0.0f, 0.0f}; if (!isect_point_quad_v2(p, corners[0], corners[1], corners[2], corners[3])) - return FALSE; + return false; for (i = 0; i < 4; i++) { float v1[2], v2[2], cur_cross; @@ -618,12 +618,12 @@ static int slide_check_corners(float (*corners)[2]) cross = cur_cross; } else if (cross * cur_cross < 0.0f) { - return FALSE; + return false; } } } - return TRUE; + return true; } static void hide_cursor(bContext *C) @@ -664,25 +664,25 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even while (track) { if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - int ok = FALSE; + bool ok = false; if ((marker->flag & MARKER_DISABLED) == 0) { if (mouse_on_offset(sc, track, marker, co, width, height)) { area = TRACK_AREA_POINT; action = SLIDE_ACTION_POS; - ok = TRUE; + ok = true; } if (!ok && (sc->flag & SC_SHOW_MARKER_SEARCH)) { if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 1, 0.0f, width, height)) { area = TRACK_AREA_SEARCH; action = SLIDE_ACTION_OFFSET; - ok = TRUE; + ok = true; } else if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 0, 0.0f, width, height)) { area = TRACK_AREA_SEARCH; action = SLIDE_ACTION_SIZE; - ok = TRUE; + ok = true; } } @@ -693,7 +693,7 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even area = TRACK_AREA_PAT; action = SLIDE_ACTION_POS; corner = current_corner; - ok = TRUE; + ok = true; } else { #if 0 @@ -702,18 +702,18 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even if (mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 1, 12.0f, width, height)) { area = TRACK_AREA_PAT; action = SLIDE_ACTION_OFFSET; - ok = TRUE; + ok = true; } if (!ok && mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 0, 12.0f, width, height)) { area = TRACK_AREA_PAT; action = SLIDE_ACTION_SIZE; - ok = TRUE; + ok = true; } #endif if (!ok && mouse_on_tilt(sc, marker, co, width, height)) { area = TRACK_AREA_PAT; action = SLIDE_ACTION_TILT_SIZE; - ok = TRUE; + ok = true; } } } @@ -1145,18 +1145,18 @@ static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit *frames_limit_r = frames_limit; } -static int track_markers_check_direction(int backwards, int curfra, int efra) +static bool track_markers_check_direction(int backwards, int curfra, int efra) { if (backwards) { if (curfra < efra) - return FALSE; + return false; } else { if (curfra > efra) - return FALSE; + return false; } - return TRUE; + return true; } static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards) @@ -1960,7 +1960,7 @@ static int count_selected_bundles(bContext *C) static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4]) { bConstraint *con; - int found = FALSE; + bool found = false; for (con = ob->constraints.first; con; con = con->next) { bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); @@ -1979,7 +1979,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat mul_m4_m4m4(invmat, invmat, data->invmat); - found = TRUE; + found = true; } } @@ -2099,7 +2099,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb { Object *camera = get_camera_with_movieclip(scene, clip); int is_camera = tracking_object->flag & TRACKING_OBJECT_CAMERA; - int flip = FALSE; + bool flip = false; float mat[4][4], vec[3], obmat[4][4], dvec[3]; BKE_object_to_mat4(ob, obmat); @@ -2127,7 +2127,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb if (axis == 'X') { if (fabsf(dvec[1]) < 1e-3f) { - flip = TRUE; + flip = true; mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f; mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f; @@ -2151,7 +2151,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb } else { if (fabsf(dvec[0]) < 1e-3f) { - flip = TRUE; + flip = true; mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f; mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f; diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 6e4d10173fb..7cb5f9b5dc0 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -461,7 +461,8 @@ static int border_select_exec(bContext *C, wmOperator *op) ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); rcti rect; rctf rectf; - int change = FALSE, mode, extend; + bool change = false; + int mode, extend; int framenr = ED_space_clip_get_clip_frame_number(sc); /* get rectangle from operator */ @@ -490,7 +491,7 @@ static int border_select_exec(bContext *C, wmOperator *op) BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); } - change = TRUE; + change = true; } } @@ -520,7 +521,7 @@ static int border_select_exec(bContext *C, wmOperator *op) } } - change = TRUE; + change = true; } } @@ -569,7 +570,7 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); rcti rect; - int change = FALSE; + bool change = false; int framenr = ED_space_clip_get_clip_frame_number(sc); /* get rectangle from operator */ @@ -596,7 +597,7 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); } - change = TRUE; + change = true; } } @@ -630,7 +631,7 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor } } - change = TRUE; + change = true; } } @@ -713,7 +714,8 @@ static int circle_select_exec(bContext *C, wmOperator *op) MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); - int x, y, radius, width, height, mode, change = FALSE; + int x, y, radius, width, height, mode; + bool change = false; float zoomx, zoomy, offset[2], ellipse[2]; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -745,7 +747,7 @@ static int circle_select_exec(bContext *C, wmOperator *op) else BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); - change = TRUE; + change = true; } } @@ -772,7 +774,7 @@ static int circle_select_exec(bContext *C, wmOperator *op) } } - change = TRUE; + change = true; } } @@ -824,7 +826,7 @@ static int select_all_exec(bContext *C, wmOperator *op) ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); int action = RNA_enum_get(op->ptr, "action"); int framenr = ED_space_clip_get_clip_frame_number(sc); - int has_selection = FALSE; + bool has_selection = false; if (action == SEL_TOGGLE) { action = SEL_SELECT; @@ -877,7 +879,7 @@ static int select_all_exec(bContext *C, wmOperator *op) } if (TRACK_VIEW_SELECTED(sc, track)) - has_selection = TRUE; + has_selection = true; } for (plane_track = plane_tracks_base->first; @@ -899,7 +901,7 @@ static int select_all_exec(bContext *C, wmOperator *op) } if (plane_track->flag & SELECT) { - has_selection = TRUE; + has_selection = true; } } @@ -945,7 +947,7 @@ static int select_groped_exec(bContext *C, wmOperator *op) track = tracksbase->first; while (track) { - int ok = FALSE; + bool ok = false; marker = BKE_tracking_marker_get(track, framenr); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 8f25ac38963..19a6296993d 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -152,17 +152,27 @@ static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; /* ******************* SORT ******************* */ +static bool compare_is_directory(const struct direntry *entry) +{ + /* for library browse .blend files may be treated as directories, but + * for sorting purposes they should be considered regular files */ + if (S_ISDIR(entry->type)) + return !(entry->flags & (BLENDERFILE | BLENDERFILE_BACKUP)); + + return false; +} + static int compare_name(const void *a1, const void *a2) { const struct direntry *entry1 = a1, *entry2 = a2; /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); @@ -188,11 +198,11 @@ static int compare_date(const void *a1, const void *a2) /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); @@ -221,11 +231,11 @@ static int compare_size(const void *a1, const void *a2) /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); @@ -262,11 +272,11 @@ static int compare_extension(const void *a1, const void *a2) /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 85e4d255603..9d762c80405 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -59,6 +59,7 @@ #include "BLI_dynstr.h" #include "BLI_utildefines.h" #include "BLI_fileops_types.h" +#include "BLI_fnmatch.h" #include "BKE_context.h" #include "BKE_global.h" @@ -81,12 +82,6 @@ #include "file_intern.h" #include "filelist.h" -#if defined WIN32 && !defined _LIBC -# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ -#else -# include <fnmatch.h> -#endif - FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) { if (!sfile->params) { @@ -115,6 +110,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) /* set the parameters from the operator, if it exists */ if (op) { + PropertyRNA *prop; const short is_files = (RNA_struct_find_property(op->ptr, "files") != NULL); const short is_filepath = (RNA_struct_find_property(op->ptr, "filepath") != NULL); const short is_filename = (RNA_struct_find_property(op->ptr, "filename") != NULL); @@ -163,30 +159,30 @@ short ED_fileselect_set_params(SpaceFile *sfile) } params->filter = 0; - if (RNA_struct_find_property(op->ptr, "filter_blender")) - params->filter |= RNA_boolean_get(op->ptr, "filter_blender") ? BLENDERFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_backup")) - params->filter |= RNA_boolean_get(op->ptr, "filter_backup") ? BLENDERFILE_BACKUP : 0; - if (RNA_struct_find_property(op->ptr, "filter_image")) - params->filter |= RNA_boolean_get(op->ptr, "filter_image") ? IMAGEFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_movie")) - params->filter |= RNA_boolean_get(op->ptr, "filter_movie") ? MOVIEFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_python")) - params->filter |= RNA_boolean_get(op->ptr, "filter_python") ? PYSCRIPTFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_font")) - params->filter |= RNA_boolean_get(op->ptr, "filter_font") ? FTFONTFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_sound")) - params->filter |= RNA_boolean_get(op->ptr, "filter_sound") ? SOUNDFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_text")) - params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_folder")) - params->filter |= RNA_boolean_get(op->ptr, "filter_folder") ? FOLDERFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_btx")) - params->filter |= RNA_boolean_get(op->ptr, "filter_btx") ? BTXFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_collada")) - params->filter |= RNA_boolean_get(op->ptr, "filter_collada") ? COLLADAFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_glob")) { - RNA_string_get(op->ptr, "filter_glob", params->filter_glob); + if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_backup"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE_BACKUP : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_image"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? IMAGEFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_movie"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? MOVIEFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_python"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? PYSCRIPTFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_font"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FTFONTFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_sound"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? SOUNDFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? TEXTFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FOLDERFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BTXFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? COLLADAFILE : 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); } else { diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 6f3d0367574..9758e2e9135 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -148,7 +148,6 @@ static void file_free(SpaceLink *sl) static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa) { SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; - //printf("file_init\n"); /* refresh system directory list */ fsmenu_refresh_system_category(fsmenu_get()); @@ -313,7 +312,6 @@ static void file_main_area_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); - FileLayout *layout = NULL; View2D *v2d = &ar->v2d; View2DScrollers *scrollers; @@ -323,15 +321,14 @@ static void file_main_area_draw(const bContext *C, ARegion *ar) if (!sfile->files || filelist_empty(sfile->files)) file_refresh(C, NULL); - layout = ED_fileselect_get_layout(sfile, ar); - /* clear and setup matrix */ UI_GetThemeColor3fv(TH_BACK, col); glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); /* Allow dynamically sliders to be set, saves notifiers etc. */ - if (layout && (layout->flag == FILE_LAYOUT_VER)) { + + if (params->display == FILE_IMGDISPLAY) { v2d->scroll = V2D_SCROLL_RIGHT; v2d->keepofs &= ~V2D_LOCKOFS_Y; v2d->keepofs |= V2D_LOCKOFS_X; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 9d22d6fcc95..5546682e470 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -882,8 +882,12 @@ static void delete_graph_keys(bAnimContext *ac) delete_fcurve_keys(fcu); /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) + if ((fcu->totvert == 0) && + (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && + (fcu->driver == NULL)) + { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); + } } /* free filtered list */ @@ -1676,7 +1680,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) /* FIXME: there are more complicated methods that will be needed to fix more cases than just some */ for (f = 0; f < 3; f++) { FCurve *fcu = euf->fcurves[f]; - BezTriple *bezt, *prev = NULL; + BezTriple *bezt, *prev; unsigned int i; /* skip if not enough vets to do a decent analysis of... */ @@ -1684,29 +1688,19 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) continue; /* prev follows bezt, bezt = "current" point to be fixed */ - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, prev = bezt, bezt++) { - /* our method depends on determining a "difference" from the previous vert */ - if (prev == NULL) - continue; + /* our method depends on determining a "difference" from the previous vert */ + for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) { + const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f; /* > 180 degree flip? */ - if (fabs(prev->vec[1][1] - bezt->vec[1][1]) >= M_PI) { + if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { /* 360 degrees to add/subtract frame value until difference is acceptably small that there's no more flip */ - const float fac = 2.0f * (float)M_PI; + const float fac = sign * 2.0f * (float)M_PI; - if (prev->vec[1][1] > bezt->vec[1][1]) { - while (fabsf(bezt->vec[1][1] - prev->vec[1][1]) >= (float)M_PI) { - bezt->vec[0][1] += fac; - bezt->vec[1][1] += fac; - bezt->vec[2][1] += fac; - } - } - else { /* if (prev->vec[1][1] < bezt->vec[1][1]) */ - while (fabsf(bezt->vec[1][1] - prev->vec[1][1]) >= (float)M_PI) { - bezt->vec[0][1] -= fac; - bezt->vec[1][1] -= fac; - bezt->vec[2][1] -= fac; - } + while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { + bezt->vec[0][1] += fac; + bezt->vec[1][1] += fac; + bezt->vec[2][1] += fac; } } } diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index cbec3072c44..d87bd9a5077 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -149,17 +149,37 @@ static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short d static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) { bAnimContext ac; + bAnimListElem *ale_active = NULL; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + + /* find active F-Curve, and preserve this for later + * or else it becomes annoying with the current active + * curve keeps fading out even while you're editing it + */ + ale_active = get_active_fcurve_channel(&ac); + /* 'standard' behavior - check if selected, then apply relevant selection */ if (RNA_boolean_get(op->ptr, "invert")) deselect_graph_keys(&ac, 0, SELECT_INVERT, TRUE); else deselect_graph_keys(&ac, 1, SELECT_ADD, TRUE); + /* restore active F-Curve... */ + if (ale_active) { + FCurve *fcu = (FCurve *)ale_active->data; + + /* all others should not be disabled, so we should be able to just set this directly... + * - selection needs to be set too, or else this won't work... + */ + fcu->flag |= (FCURVE_SELECTED | FCURVE_ACTIVE); + + MEM_freeN(ale_active); + ale_active = NULL; + } + /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -1049,10 +1069,7 @@ static tNearestVertInfo *get_best_nearest_fcurve_vert(ListBase *matches) /* if list only has 1 item, remove it from the list and return */ if (matches->first == matches->last) { /* need to remove from the list, otherwise it gets freed and then we can't return it */ - nvi = matches->first; - BLI_remlink(matches, nvi); - - return nvi; + return BLI_pophead(matches); } /* try to find the first selected F-Curve vert, then take the one after it */ @@ -1075,9 +1092,7 @@ static tNearestVertInfo *get_best_nearest_fcurve_vert(ListBase *matches) /* if we're still here, this means that we failed to find anything appropriate in the first pass, * so just take the first item now... */ - nvi = matches->first; - BLI_remlink(matches, nvi); - return nvi; + return BLI_pophead(matches); } /* Find the nearest vertices (either a handle or the keyframe) that are nearest to the mouse cursor (in area coordinates) diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 2da3f3adb67..6a3259e030e 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -646,12 +646,13 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot) * Default behavior is to reset the position of the image and set the zoom to 1 * If the image will not fit within the window rectangle, the zoom is adjusted */ -static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int image_view_all_exec(bContext *C, wmOperator *op) { SpaceImage *sima; ARegion *ar; float aspx, aspy, zoomx, zoomy, w, h; int width, height; + int fit_view = RNA_boolean_get(op->ptr, "fit_view"); /* retrieve state */ sima = CTX_wm_space_image(C); @@ -667,14 +668,25 @@ static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) width = BLI_rcti_size_x(&ar->winrct) + 1; height = BLI_rcti_size_y(&ar->winrct) + 1; - if ((w >= width || h >= height) && (width > 0 && height > 0)) { - /* find the zoom value that will fit the image in the image space */ - zoomx = width / w; - zoomy = height / h; - sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL); + if (fit_view) { + const int margin = 5; /* margin from border */ + + zoomx = (float) width / (w + 2 * margin); + zoomy = (float) height / (h + 2 * margin); + + sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL); + } + else { + if ((w >= width || h >= height) && (width > 0 && height > 0)) { + zoomx = (float) width / w; + zoomy = (float) height / h; + + /* find the zoom value that will fit the image in the image space */ + sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL); + } + else + sima_zoom_set(sima, ar, 1.0f, NULL); } - else - sima_zoom_set(sima, ar, 1.0f, NULL); sima->xof = sima->yof = 0.0f; @@ -685,6 +697,8 @@ static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) void IMAGE_OT_view_all(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View All"; ot->idname = "IMAGE_OT_view_all"; @@ -693,6 +707,10 @@ void IMAGE_OT_view_all(wmOperatorType *ot) /* api callbacks */ ot->exec = image_view_all_exec; ot->poll = space_image_main_area_poll; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /********************** view selected operator *********************/ @@ -1318,7 +1336,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id); const short relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")); const short save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy")); - const short save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); + const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); ImageFormatData *imf = &simopts->im_format; short ok = FALSE; @@ -1344,7 +1362,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI } } - colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, TRUE, &imf->view_settings, &imf->display_settings, imf); + colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { Scene *scene = CTX_data_scene(C); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index c0ef59e9e25..5a8292abcab 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -277,6 +277,10 @@ static void image_keymap(struct wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Image", SPACE_IMAGE, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); + + kmi = WM_keymap_add_item(keymap, "IMAGE_OT_view_all", FKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "fit_view", TRUE); + WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); @@ -670,7 +674,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) } else if (sima->mode == SI_MODE_MASK) { mask = ED_space_image_get_mask(sima); - draw_image_cursor(sima, ar); + draw_image_cursor(ar, sima->cursor); } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -719,7 +723,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) ED_mask_draw_frames(mask, ar, CFRA, mask->sfra, mask->efra); - draw_image_cursor(sima, ar); + draw_image_cursor(ar, sima->cursor); } /* scrollers? */ diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 98c9c8d15fe..c1cddf092aa 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -115,8 +115,8 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { int totv = 0, totf = 0, tottri = 0; - if (ob->disp.first) - BKE_displist_count(&ob->disp, &totv, &totf, &tottri); + if (ob->curve_cache && ob->curve_cache->disp.first) + BKE_displist_count(&ob->curve_cache->disp, &totv, &totf, &tottri); totv *= totob; totf *= totob; diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index aed5699a9d7..2c89d6f6448 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -427,8 +427,6 @@ static const char *sensor_name(int type) switch (type) { case SENS_ALWAYS: return "Always"; - case SENS_TOUCH: - return "Touch"; case SENS_NEAR: return "Near"; case SENS_KEYBOARD: @@ -1233,11 +1231,6 @@ static void draw_sensor_ray(uiLayout *layout, PointerRNA *ptr, bContext *C) uiItemR(row, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); } -static void draw_sensor_touch(uiLayout *layout, PointerRNA *ptr) -{ - uiItemR(layout, ptr, "material", 0, NULL, ICON_NONE); -} - static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) { uiLayout *box; @@ -1292,9 +1285,6 @@ static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) case SENS_RAY: draw_sensor_ray(box, ptr, C); break; - case SENS_TOUCH: - draw_sensor_touch(box, ptr); - break; } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 5cc22b25f72..4e98c9fd894 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -809,9 +809,13 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin } static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ +{ + uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE); uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE); + + if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) + uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE); } static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -907,6 +911,11 @@ static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); } +static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE); +} + static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "component", 0, "", ICON_NONE); @@ -1039,6 +1048,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_BSDF_REFRACTION: ntype->uifunc = node_shader_buts_glossy; break; + case SH_NODE_SUBSURFACE_SCATTERING: + ntype->uifunc = node_shader_buts_subsurface; + break; case SH_NODE_BSDF_TOON: ntype->uifunc = node_shader_buts_toon; break; @@ -1620,12 +1632,14 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C active_index = RNA_int_get(ptr, "active_input_index"); /* using different collection properties if multilayer format is enabled */ if (multilayer) { - uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index", + 0, 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); } else { - uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index", + 0, 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); } @@ -3061,7 +3075,16 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa { float dist, vec[4][2]; float deltax, deltay; + float cursor[2] = {0.0f, 0.0f}; int toreroute, fromreroute; + + /* this function can be called with snode null (via cut_links_intersect) */ + /* XXX map snode->cursor back to view space */ + if (snode) { + cursor[0] = snode->cursor[0] * UI_DPI_FAC; + cursor[1] = snode->cursor[1] * UI_DPI_FAC; + } + /* in v0 and v3 we put begin/end points */ if (link->fromsock) { vec[0][0] = link->fromsock->locx; @@ -3070,7 +3093,7 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa } else { if (snode == NULL) return 0; - copy_v2_v2(vec[0], snode->cursor); + copy_v2_v2(vec[0], cursor); fromreroute = 0; } if (link->tosock) { @@ -3080,7 +3103,7 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa } else { if (snode == NULL) return 0; - copy_v2_v2(vec[3], snode->cursor); + copy_v2_v2(vec[3], cursor); toreroute = 0; } diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index c9618daa7c5..00769975893 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -84,10 +84,6 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx node->locy = locy + 60.0f; /* arbitrary... so its visible, (0,0) is top of node */ nodeSetSelected(node, TRUE); - /* node location is mapped */ - locx /= UI_DPI_FAC; - locy /= UI_DPI_FAC; - node->locx = locx; node->locy = locy + 60.0f; @@ -215,7 +211,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) int i = 0; /* Get the cut path */ - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { float loc[2]; @@ -417,9 +413,8 @@ static int node_add_mask_poll(bContext *C) return ED_operator_node_editable(C) && snode->nodetree->type == NTREE_COMPOSIT; } -static int node_add_mask_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int node_add_mask_exec(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); bNode *node; ID *mask = NULL; @@ -435,9 +430,6 @@ static int node_add_mask_invoke(bContext *C, wmOperator *op, const wmEvent *even ED_preview_kill_jobs(C); - /* convert mouse coordinates to v2d space */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], - &snode->cursor[0], &snode->cursor[1]); node = node_add_node(C, NULL, CMP_NODE_MASK, snode->cursor[0], snode->cursor[1]); if (!node) { @@ -462,7 +454,7 @@ void NODE_OT_add_mask(wmOperatorType *ot) ot->idname = "NODE_OT_add_mask"; /* callbacks */ - ot->invoke = node_add_mask_invoke; + ot->exec = node_add_mask_exec; ot->poll = node_add_mask_poll; /* flags */ diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index f95e895bef2..53b373e728e 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -145,13 +145,15 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa) split = uiLayoutRow(row, TRUE); col = uiLayoutColumn(split, TRUE); uiItemL(col, IFACE_("Inputs:"), ICON_NONE); - uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input", 0, 0, 0); + uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input", + 0, 0, 0, 0); opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_IN); col = uiLayoutColumn(split, TRUE); uiItemL(col, IFACE_("Outputs:"), ICON_NONE); - uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output", 0, 0, 0); + uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output", + 0, 0, 0, 0); opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_OUT); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index dce04bb8c42..b40a7e4702e 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -1075,31 +1075,31 @@ int node_get_resize_cursor(int directions) return CURSOR_EDIT; } -void node_set_cursor(wmWindow *win, SpaceNode *snode) +void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]) { bNodeTree *ntree = snode->edittree; bNode *node; bNodeSocket *sock; - int cursor = CURSOR_STD; + int wmcursor = CURSOR_STD; if (ntree) { - if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN | SOCK_OUT)) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) { /* pass */ } else { /* check nodes front to back */ for (node = ntree->nodes.last; node; node = node->prev) { - if (BLI_rctf_isect_pt(&node->totr, snode->cursor[0], snode->cursor[1])) + if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) break; /* first hit on node stops */ } if (node) { - int dir = node->typeinfo->resize_area_func(node, snode->cursor[0], snode->cursor[1]); - cursor = node_get_resize_cursor(dir); + int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]); + wmcursor = node_get_resize_cursor(dir); } } } - WM_cursor_set(win, cursor); + WM_cursor_set(win, wmcursor); } void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) @@ -1251,6 +1251,7 @@ static void draw_group_overlay(const bContext *C, ARegion *ar) void drawnodespace(const bContext *C, ARegion *ar) { + wmWindow *win = CTX_wm_window(C); View2DScrollers *scrollers; SpaceNode *snode = CTX_wm_space_node(C); View2D *v2d = &ar->v2d; @@ -1259,7 +1260,13 @@ void drawnodespace(const bContext *C, ARegion *ar) glClear(GL_COLOR_BUFFER_BIT); UI_view2d_view_ortho(v2d); - + + /* XXX snode->cursor set in coordspace for placing new nodes, used for drawing noodles too */ + UI_view2d_region_to_view(&ar->v2d, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin, + &snode->cursor[0], &snode->cursor[1]); + snode->cursor[0] /= UI_DPI_FAC; + snode->cursor[1] /= UI_DPI_FAC; + ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); /* only set once */ diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index b7e9cb0268f..3ba749a8eff 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1056,7 +1056,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) /* checks snode->mouse position, and returns found node/socket */ /* type is SOCK_IN and/or SOCK_OUT */ -int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out) +int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out) { bNode *node; bNodeSocket *sock; @@ -1068,10 +1068,10 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so /* check if we click in a socket */ for (node = snode->edittree->nodes.first; node; node = node->next) { - rect.xmin = snode->cursor[0] - (NODE_SOCKSIZE + 4); - rect.ymin = snode->cursor[1] - (NODE_SOCKSIZE + 4); - rect.xmax = snode->cursor[0] + (NODE_SOCKSIZE + 4); - rect.ymax = snode->cursor[1] + (NODE_SOCKSIZE + 4); + rect.xmin = cursor[0] - (NODE_SOCKSIZE + 4); + rect.ymin = cursor[1] - (NODE_SOCKSIZE + 4); + rect.xmax = cursor[0] + (NODE_SOCKSIZE + 4); + rect.ymax = cursor[1] + (NODE_SOCKSIZE + 4); if (!(node->flag & NODE_HIDDEN)) { /* extra padding inside and out - allow dragging on the text areas too */ @@ -2087,17 +2087,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceNode *snode = CTX_wm_space_node(C); - - /* convert mouse coordinates to v2d space */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]); - - return node_clipboard_paste_exec(C, op); -} - void NODE_OT_clipboard_paste(wmOperatorType *ot) { /* identifiers */ @@ -2107,7 +2096,6 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot) /* api callbacks */ ot->exec = node_clipboard_paste_exec; - ot->invoke = node_clipboard_paste_invoke; ot->poll = ED_operator_node_editable; /* flags */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 1a2e90e5522..9b7b00fba00 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -84,7 +84,7 @@ void node_draw_nodetree(const struct bContext *C, struct ARegion *ar, struct Spa struct bNodeTree *ntree, bNodeInstanceKey parent_key); void drawnodespace(const bContext *C, ARegion *ar); -void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode); +void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]); /* DPI scaled coords */ void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry); void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry); @@ -129,6 +129,7 @@ void NODE_OT_view_selected(struct wmOperatorType *ot); void NODE_OT_backimage_move(struct wmOperatorType *ot); void NODE_OT_backimage_zoom(struct wmOperatorType *ot); +void NODE_OT_backimage_fit(struct wmOperatorType *ot); void NODE_OT_backimage_sample(struct wmOperatorType *ot); /* drawnode.c */ @@ -182,7 +183,7 @@ int composite_node_editable(struct bContext *C); int node_has_hidden_sockets(bNode *node); void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set); int node_render_changed_exec(bContext *, struct wmOperator *); -int node_find_indicated_socket(struct SpaceNode *snode, struct bNode **nodep, struct bNodeSocket **sockp, int in_out); +int node_find_indicated_socket(struct SpaceNode *snode, struct bNode **nodep, struct bNodeSocket **sockp, float cursor[2], int in_out); void NODE_OT_duplicate(struct wmOperatorType *ot); void NODE_OT_delete(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 566bb1600cc..f0d3deb24df 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -98,6 +98,7 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_backimage_move); WM_operatortype_append(NODE_OT_backimage_zoom); + WM_operatortype_append(NODE_OT_backimage_fit); WM_operatortype_append(NODE_OT_backimage_sample); WM_operatortype_append(NODE_OT_add_file); @@ -249,6 +250,7 @@ void node_keymap(struct wmKeyConfig *keyconf) RNA_float_set(kmi->ptr, "factor", 0.83333f); kmi = WM_keymap_add_item(keymap, "NODE_OT_backimage_zoom", VKEY, KM_PRESS, KM_ALT, 0); RNA_float_set(kmi->ptr, "factor", 1.2f); + WM_keymap_add_item(keymap, "NODE_OT_backimage_fit", HOMEKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "NODE_OT_backimage_sample", ACTIONMOUSE, KM_PRESS, KM_ALT, 0); kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 244b222811e..4b5cc9e42b6 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -443,18 +443,19 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) bNodeSocket *tsock = NULL; bNodeLink *link; LinkData *linkdata; + float cursor[2]; int in_out; in_out = nldrag->in_out; UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], - &snode->cursor[0], &snode->cursor[1]); + &cursor[0], &cursor[1]); switch (event->type) { case MOUSEMOVE: if (in_out == SOCK_OUT) { - if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) { + if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; @@ -480,7 +481,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) } } else { - if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) { + if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; @@ -550,7 +551,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* return 1 when socket clicked */ -static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) +static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], int detach) { bNode *node; bNodeSocket *sock; @@ -560,7 +561,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) int num_links; /* output indicated? */ - if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -596,7 +597,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) } } /* or an input? */ - else if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) { + else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -644,14 +645,16 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); bNodeLinkDrag *nldrag; + float cursor[2]; + int detach = RNA_boolean_get(op->ptr, "detach"); UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], - &snode->cursor[0], &snode->cursor[1]); + &cursor[0], &cursor[1]); ED_preview_kill_jobs(C); - nldrag = node_link_init(snode, detach); + nldrag = node_link_init(snode, cursor, detach); if (nldrag) { op->customdata = nldrag; @@ -762,7 +765,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) float mcoords[256][2]; int i = 0; - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { float loc[2]; @@ -1065,18 +1068,23 @@ void NODE_OT_join(wmOperatorType *ot) /* ****************** Attach ******************* */ -static int node_attach_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { + ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; bNode *frame; + float cursor[2]; + + /* convert mouse coordinates to v2d space */ + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]); /* check nodes front to back */ for (frame = ntree->nodes.last; frame; frame = frame->prev) { /* skip selected, those are the nodes we want to attach */ if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) continue; - if (BLI_rctf_isect_pt(&frame->totr, snode->cursor[0], snode->cursor[1])) + if (BLI_rctf_isect_pt(&frame->totr, cursor[0], cursor[1])) break; } if (frame) { @@ -1116,16 +1124,6 @@ static int node_attach_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int node_attach_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceNode *snode = CTX_wm_space_node(C); - - /* convert mouse coordinates to v2d space */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]); - - return node_attach_exec(C, op); -} void NODE_OT_attach(wmOperatorType *ot) { @@ -1135,7 +1133,7 @@ void NODE_OT_attach(wmOperatorType *ot) ot->idname = "NODE_OT_attach"; /* api callbacks */ - ot->exec = node_attach_exec; + ot->invoke = node_attach_invoke; ot->poll = ED_operator_node_editable; diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index e17699309ef..6ce31783bff 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -306,24 +306,21 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i { bNode *node, *tnode; bNodeSocket *sock, *tsock; - float mx, my; + float cursor[2]; int selected = 0; /* get mouse coordinates in view2d space */ - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my); - /* node_find_indicated_socket uses snode->mx/my */ - snode->cursor[0] = mx; - snode->cursor[1] = my; + UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]); if (extend) { /* first do socket selection, these generally overlap with nodes. * socket selection only in extend mode. */ - if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { node_socket_toggle(node, sock, 1); selected = 1; } - else if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) { + else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { if (sock->flag & SELECT) { node_socket_deselect(node, sock, 1); } @@ -341,7 +338,7 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i } else { /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, mx, my); + node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); if (node) { if ((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0) { @@ -362,7 +359,7 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i else { /* extend == 0 */ /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, mx, my); + node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); if (node) { for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 9e6e1e628f6..e47a1315663 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -327,6 +327,60 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot) RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f); } +static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + ARegion *ar = CTX_wm_region(C); + + Image *ima; + ImBuf *ibuf; + + const float pad = 32.0f; + + void *lock; + + float facx, facy; + + ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); + ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf == NULL) { + BKE_image_release_ibuf(ima, ibuf, lock); + return OPERATOR_CANCELLED; + } + + facx = 1.0f * (ar->sizex - pad) / (ibuf->x * snode->zoom); + facy = 1.0f * (ar->sizey - pad) / (ibuf->y * snode->zoom); + + BKE_image_release_ibuf(ima, ibuf, lock); + + snode->zoom *= min_ff(facx, facy); + + snode->xof = 0; + snode->yof = 0; + + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + +void NODE_OT_backimage_fit(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name = "Background Image Fit"; + ot->idname = "NODE_OT_backimage_fit"; + ot->description = "Zoom in/out the background image"; + + /* api callbacks */ + ot->exec = backimage_fit_exec; + ot->poll = composite_node_active; + + /* flags */ + ot->flag = OPTYPE_BLOCKING; + +} + /******************** sample backdrop operator ********************/ typedef struct ImageSampleInfo { diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 922912fa540..a59b2fc21df 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -602,8 +602,14 @@ static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(&ar->v2d, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin, &snode->cursor[0], &snode->cursor[1]); + + /* here snode->cursor is used to detect the node edge for sizing */ + node_set_cursor(win, snode, snode->cursor); - node_set_cursor(win, snode); + /* XXX snode->cursor is in placing new nodes space */ + snode->cursor[0] /= UI_DPI_FAC; + snode->cursor[1] /= UI_DPI_FAC; + } /* Initialize main area, setting handlers. */ diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 44d5672e7da..6200b98350f 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1389,6 +1389,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto tselem_draw_icon_uibut(&arg, ICON_GROUP); break; case ID_LI: tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break; + case ID_LS: + tselem_draw_icon_uibut(&arg, ICON_BRUSH_DATA); break; /* FIXME proper icon */ } } } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 1e9b681197c..2de8f52d677 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1469,7 +1469,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "child", childname); ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, FALSE, FALSE); + ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL); DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1525,7 +1525,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) } if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) { - if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, FALSE, FALSE)) { + if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL)) { DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index c1950e62817..a0af9340fe2 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_treehash.h" #include "ED_armature.h" #include "ED_object.h" @@ -113,7 +114,7 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_LA: case ID_AR: case ID_CA: case ID_SPK: case ID_MA: case ID_TE: case ID_IP: case ID_IM: case ID_SO: case ID_KE: case ID_WO: case ID_AC: - case ID_NLA: case ID_TXT: case ID_GR: + case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; break; @@ -299,17 +300,13 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); if (base) { - SpaceOops *soops = CTX_wm_space_outliner(C); - // check also library later if (scene->obedit == base->object) ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); te->directdata = NULL; - BLI_ghash_remove(soops->treehash, tselem, NULL, NULL); tselem->id = NULL; - BLI_ghash_insert(soops->treehash, tselem, tselem); } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 404821900df..b86fba1398a 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -32,15 +32,6 @@ #include <math.h> #include <string.h> -#if defined WIN32 && !defined _LIBC || defined __sun -# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ -#else -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -# include <fnmatch.h> -#endif - #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" @@ -59,12 +50,14 @@ #include "DNA_sequence_types.h" #include "DNA_speaker_types.h" #include "DNA_object_types.h" +#include "DNA_linestyle_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_ghash.h" #include "BLI_mempool.h" +#include "BLI_fnmatch.h" #include "BLF_translation.h" @@ -74,6 +67,7 @@ #include "BKE_modifier.h" #include "BKE_sequencer.h" #include "BKE_idcode.h" +#include "BKE_treehash.h" #include "ED_armature.h" #include "ED_screen.h" @@ -116,9 +110,8 @@ static void outliner_storage_cleanup(SpaceOops *soops) if (BLI_mempool_count(ts) == unused) { BLI_mempool_destroy(ts); soops->treestore = NULL; - if (soops->treehash) { - BLI_ghash_free(soops->treehash, NULL, NULL); + BKE_treehash_free(soops->treehash); soops->treehash = NULL; } } @@ -135,14 +128,9 @@ static void outliner_storage_cleanup(SpaceOops *soops) } BLI_mempool_destroy(ts); soops->treestore = new_ts; - if (soops->treehash) { /* update hash table to fix broken pointers */ - BLI_ghash_clear(soops->treehash, NULL, NULL); - BLI_mempool_iternew(soops->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLI_ghash_insert(soops->treehash, tselem, tselem); - } + BKE_treehash_rebuild_from_treestore(soops->treehash, soops->treestore); } } } @@ -150,63 +138,22 @@ static void outliner_storage_cleanup(SpaceOops *soops) } } -/* This function hashes only by type, nr and id, while cmp function also compares 'used' flag; - * This is done to skip full treehash rebuild in outliner_storage_cleanup */ -static unsigned int tse_hash(const void *ptr) -{ - const TreeStoreElem *tse = (const TreeStoreElem *)ptr; - unsigned int hash; - BLI_assert(tse->type || !tse->nr); - hash = BLI_ghashutil_inthash(SET_INT_IN_POINTER((tse->nr << 16) + tse->type)); - hash ^= BLI_ghashutil_inthash(tse->id); - return hash; -} - -static int tse_cmp(const void *a, const void *b) -{ - const TreeStoreElem *tse_a = (const TreeStoreElem *)a; - const TreeStoreElem *tse_b = (const TreeStoreElem *)b; - return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || - tse_a->id != tse_b->id || tse_a->used != tse_b->used; -} - -static TreeStoreElem *lookup_treehash(GHash *th, short type, short nr, short used, ID *id) -{ - TreeStoreElem tse_template; - tse_template.type = type; - tse_template.nr = type ? nr : 0; // we're picky! :) - tse_template.id = id; - tse_template.used = used; - return BLI_ghash_lookup(th, &tse_template); -} - static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr) { - /* When treestore comes directly from readfile.c, treehash is empty; - * In this case we don't want to get TSE_CLOSED while adding elements one by one, - * that is why this function restores treehash */ - bool restore_treehash = (soops->treestore && !soops->treehash); TreeStoreElem *tselem; if (soops->treestore == NULL) { /* if treestore was not created in readfile.c, create it here */ soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); + } if (soops->treehash == NULL) { - soops->treehash = BLI_ghash_new(tse_hash, tse_cmp, "treehash"); - BLI_ghash_flag_set(soops->treehash, GHASH_FLAG_ALLOW_DUPES); - } - - if (restore_treehash) { - BLI_mempool_iter iter; - BLI_mempool_iternew(soops->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLI_ghash_insert(soops->treehash, tselem, tselem); - } + soops->treehash = BKE_treehash_create_from_treestore(soops->treestore); } - /* check for unused tree elements is in treestore */ - tselem = lookup_treehash(soops->treehash, type, nr, 0, id); + /* find any unused tree element in treestore and mark it as used + * (note that there may be multiple unused elements in case of linked objects) */ + tselem = BKE_treehash_lookup_unused(soops->treehash, type, nr, id); if (tselem) { te->store_elem = tselem; tselem->used = 1; @@ -221,7 +168,7 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty tselem->used = 0; tselem->flag = TSE_CLOSED; te->store_elem = tselem; - BLI_ghash_insert(soops->treehash, tselem, tselem); + BKE_treehash_add_element(soops->treehash, tselem); } /* ********************************************************* */ @@ -266,7 +213,7 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse) if (tse->id == NULL) return NULL; /* check if 'tse' is in treestore */ - tselem = lookup_treehash(soops->treehash, tse->type, tse->nr, tse->used, tse->id); + tselem = BKE_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id); if (tselem) return outliner_find_tree_element(&soops->tree, tselem); @@ -430,6 +377,28 @@ static bool outliner_animdata_test(AnimData *adt) return false; } +static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) +{ + SceneRenderLayer *srl; + FreestyleLineSet *lineset; + + for (srl = sce->r.layers.first; srl; srl = srl->next) { + for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + lineset->linestyle->id.flag |= LIB_DOIT; + } + } + for (srl = sce->r.layers.first; srl; srl = srl->next) { + for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + FreestyleLineStyle *linestyle = lineset->linestyle; + + if (!(linestyle->id.flag & LIB_DOIT)) + continue; + linestyle->id.flag &= ~LIB_DOIT; + outliner_add_element(soops, lb, linestyle, te, 0, 0); + } + } +} + static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) { SceneRenderLayer *srl; @@ -455,6 +424,8 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); outliner_add_element(soops, lb, sce->world, te, 0, 0); + + outliner_add_line_styles(soops, lb, sce, te); } // can be inlined if necessary @@ -813,6 +784,14 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor } break; } + case ID_LS: + { + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; + + if (outliner_animdata_test(linestyle->adt)) + outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0); + break; + } } } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 874852ee320..d695ffa46d5 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -43,6 +43,7 @@ #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_scene.h" +#include "BKE_treehash.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -435,7 +436,7 @@ static void outliner_free(SpaceLink *sl) BLI_mempool_destroy(soutliner->treestore); } if (soutliner->treehash) { - BLI_ghash_free(soutliner->treehash, NULL, NULL); + BKE_treehash_free(soutliner->treehash); } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 68fd09f5fb7..ebec818bb36 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -1086,10 +1086,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq type = GL_FLOAT; if (ibuf->float_colorspace) { - glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->float_colorspace, TRUE); + glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->float_colorspace, true); } else { - glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, TRUE); + glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, true); } } else if (ibuf->rect) { @@ -1097,7 +1097,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq format = GL_RGBA; type = GL_UNSIGNED_BYTE; - glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->rect_colorspace, FALSE); + glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->rect_colorspace, false); } else { format = GL_RGBA; diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 68428cd890f..18733d4e409 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -152,7 +152,8 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) info->colfp = info->colf; /* sequencer's image buffers are in non-linear space, need to make them linear */ - BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->colf); + copy_v4_v4(info->linearcol, info->colf); + BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol); info->color_manage = TRUE; } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 04b2a21bf79..84c6329db53 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -491,6 +491,7 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa case ND_MARKERS: case ND_RENDER_OPTIONS: /* for FPS and FPS Base */ case ND_SEQUENCER: + case ND_RENDER_RESULT: 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 95fd7fce878..e92cab72042 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -1133,23 +1133,23 @@ static void draw_cursor(SpaceText *st, ARegion *ar) wrap_offset_in_line(st, ar, text->sell, text->selc, &offl, &offc); - y1 = ar->winy - 2 - (vsell - offl) * lheight; - y2 = y1 - (lheight * visible_lines + TXT_LINE_SPACING); + y1 = ar->winy - (vsell - offl) * lheight; + y2 = y1 - (lheight * visible_lines); } else { - y1 = ar->winy - 2 - vsell * lheight; - y2 = y1 - (lheight + TXT_LINE_SPACING); + y1 = ar->winy - vsell * lheight; + y2 = y1 - (lheight); } if (!(y1 < 0 || y2 > ar->winy)) { /* check we need to draw */ - x1 = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; + x1 = 0; // st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; x2 = x1 + ar->winx; glColor4ub(255, 255, 255, 32); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glRecti(x1 - 4, y1, x2, y2 + TXT_LINE_SPACING); + glRecti(x1 - 4, y1, x2, y2); glDisable(GL_BLEND); } } @@ -1317,15 +1317,13 @@ void draw_text_main(SpaceText *st, ARegion *ar) int wraplinecount = 0, wrap_skip = 0; int margin_column_x; - /* dpi controlled line height and font size */ - st->lheight_dpi = (U.widget_unit * st->lheight) / 20; - - if (st->lheight_dpi) st->viewlines = (int)ar->winy / (st->lheight_dpi + TXT_LINE_SPACING); - else st->viewlines = 0; - /* if no text, nothing to do */ if (!text) return; + + /* 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; text_update_drawcache(st, ar); diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index 371ccfd9bd9..b4c2062ab00 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -54,10 +54,10 @@ void text_scroll_to_cursor(struct SpaceText *st, struct ScrArea *sa); void text_update_cursor_moved(struct bContext *C); /* TXT_OFFSET used to be 35 when the scrollbar was on the left... */ -#define TXT_OFFSET ((int)(0.75f * U.widget_unit)) +#define TXT_OFFSET ((int)(0.2f * U.widget_unit)) #define TXT_SCROLL_WIDTH U.widget_unit #define TXT_SCROLL_SPACE ((int)(0.1f * U.widget_unit)) -#define TXT_LINE_SPACING ((int)(0.2f * U.widget_unit)) /* space between lines */ +#define TXT_LINE_SPACING ((int)(0.3f * st->lheight_dpi)) /* space between lines */ #define TEXTXLOC (st->cwidth * st->linenrs_tot) #define SUGG_LIST_SIZE 7 diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index dec61a0e1ca..2c2a8b255da 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -949,7 +949,7 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); if (txt_has_sel(text)) { - txt_order_cursors(text); + txt_order_cursors(text, false); txt_indent(text); } else @@ -983,7 +983,7 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_order_cursors(text); + txt_order_cursors(text, false); txt_unindent(text); text_update_edited(text); @@ -1063,7 +1063,7 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_order_cursors(text); + txt_order_cursors(text, false); txt_comment(text); text_update_edited(text); @@ -1096,7 +1096,7 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_order_cursors(text); + txt_order_cursors(text, false); txt_uncomment(text); text_update_edited(text); @@ -1861,11 +1861,23 @@ static int text_move_cursor(bContext *C, int type, int select) break; case PREV_CHAR: - txt_move_left(text, select); + if (txt_has_sel(text) && !select) { + txt_order_cursors(text, false); + txt_pop_sel(text); + } + else { + txt_move_left(text, select); + } break; case NEXT_CHAR: - txt_move_right(text, select); + if (txt_has_sel(text) && !select) { + txt_order_cursors(text, true); + txt_pop_sel(text); + } + else { + txt_move_right(text, select); + } break; case PREV_LINE: @@ -2086,10 +2098,17 @@ void TEXT_OT_overwrite_toggle(wmOperatorType *ot) static void txt_screen_clamp(SpaceText *st, ARegion *ar) { - int last; - last = text_get_total_lines(st, ar); - last = last - (st->viewlines / 2); - CLAMP(st->top, 0, last); + if (st->top <= 0) { + st->top = 0; + } + else { + int last; + last = text_get_total_lines(st, ar); + last = last - (st->viewlines / 2); + if (last > 0 && st->top > last) { + st->top = last; + } + } } /* Moves the view vertically by the specified number of lines */ diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index d3d8868520d..6961ada462d 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -34,7 +34,6 @@ #include <string.h> #include <math.h> - #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" @@ -1099,12 +1098,14 @@ static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, if ((segments > 1) && (pchan)) { float dlen = length / (float)segments; - Mat4 *bbone = b_bone_spline_setup(pchan, 0); + Mat4 bbone[MAX_BBONE_SUBDIV]; int a; - - for (a = 0; a < segments; a++, bbone++) { + + b_bone_spline_setup(pchan, 0, bbone); + + for (a = 0; a < segments; a++) { glPushMatrix(); - glMultMatrixf(bbone->mat); + glMultMatrixf(bbone[a].mat); if (dt == OB_SOLID) drawsolidcube_size(xwidth, dlen, zwidth); else drawcube_size(xwidth, dlen, zwidth); glPopMatrix(); @@ -1235,6 +1236,7 @@ static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float len static void draw_wire_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone) { + Mat4 bbones_array[MAX_BBONE_SUBDIV]; Mat4 *bbones = NULL; int segments = 0; float length; @@ -1243,8 +1245,10 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons segments = pchan->bone->segments; length = pchan->bone->length; - if (segments > 1) - bbones = b_bone_spline_setup(pchan, 0); + if (segments > 1) { + b_bone_spline_setup(pchan, 0, bbones_array); + bbones = bbones_array; + } } else length = ebone->length; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 62e3f8471a3..ac216907c7f 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1900,9 +1900,9 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob) const bool is_edit = (lt->editlatt != NULL); /* now we default make displist, this will modifiers work for non animated case */ - if (ob->disp.first == NULL) + if (ELEM(NULL, ob->curve_cache, ob->curve_cache->disp.first)) BKE_lattice_modifiers_calc(scene, ob); - dl = BKE_displist_find(&ob->disp, DL_VERTS); + dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS); if (is_edit) { lt = lt->editlatt->latt; @@ -3094,9 +3094,6 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, BMVert *eve_act = NULL; bool use_occlude_wire = (v3d->flag2 & V3D_OCCLUDE_WIRE) && (dt > OB_WIRE); - // BLI_assert(!cageDM || !(cageDM->dirty & DM_DIRTY_NORMALS)); - BLI_assert(!finalDM || !(finalDM->dirty & DM_DIRTY_NORMALS)); - if (em->bm->selected.last) { BMEditSelection *ese = em->bm->selected.last; /* face is handeled above */ @@ -3369,8 +3366,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if (!dm) return; - if (dm) BLI_assert(!(dm->dirty & DM_DIRTY_NORMALS)); - /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). * Note: Last "preview-active" modifier in stack will win! */ if (DM_get_tessface_data_layer(dm, CD_PREVIEW_MCOL) && modifiers_isPreview(ob)) @@ -3971,7 +3966,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 case OB_CURVE: cu = ob->data; - lb = &ob->disp; + lb = &ob->curve_cache->disp; if (solid) { dl = lb->first; @@ -4021,7 +4016,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 break; case OB_SURF: - lb = &ob->disp; + lb = &ob->curve_cache->disp; if (solid) { dl = lb->first; @@ -4049,8 +4044,11 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 case OB_MBALL: if (BKE_mball_is_basis(ob)) { - lb = &ob->disp; - if (lb->first == NULL) BKE_displist_make_mball(scene, ob); + lb = ob->curve_cache ? &ob->curve_cache->disp : NULL; + if (ELEM(lb, lb->first, NULL)) { + BKE_displist_make_mball(scene, ob); + lb = &ob->curve_cache->disp; + } if (lb->first == NULL) { return true; } @@ -4566,7 +4564,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pdd->ma_col = ma_col; } - psys->lattice = psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* circles don't use drawdata, so have to add a special case here */ if ((pdd || draw_as == PART_DRAW_CIRC) && draw_as != PART_DRAW_PATH) { @@ -4892,9 +4890,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; } - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice = NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } if (pdd) { @@ -5642,7 +5640,7 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) { UI_ThemeColor(TH_WIRE_EDIT); - for (bl = cu->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) { + for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) { BevPoint *bevp = (BevPoint *)(bl + 1); int nr = bl->nr; int skip = nu->resolu / 16; @@ -6065,7 +6063,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d, } else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) { Curve *cu = ob->data; - if ((cu->flag & CU_PATH) && cu->path && cu->path->data) { + if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) { float mindist, guidevec1[4], guidevec2[3]; //if (has_ipo_code(ob->ipo, OB_PD_FSTR)) @@ -6248,7 +6246,7 @@ static void draw_bounding_volume(Scene *scene, Object *ob, char type) bb = BKE_mesh_boundbox_get(ob); } else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - bb = ob->bb ? ob->bb : ( (Curve *)ob->data)->bb; + bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { @@ -6283,9 +6281,7 @@ static void drawtexspace(Object *ob) BKE_mesh_texspace_get(ob->data, loc, NULL, size); } else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - Curve *cu = ob->data; - copy_v3_v3(size, cu->size); - copy_v3_v3(loc, cu->loc); + BKE_curve_texspace_get(ob->data, loc, NULL, size); } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; @@ -6323,7 +6319,6 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, glDepthMask(0); if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; DerivedMesh *dm = ob->derivedFinal; bool has_faces = false; @@ -6331,16 +6326,16 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, has_faces = dm->getNumTessFaces(dm); } else { - has_faces = BKE_displist_has_faces(&ob->disp); + has_faces = BKE_displist_has_faces(&ob->curve_cache->disp); } - if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { draw_index_wire = false; if (dm) { draw_mesh_object_outline(v3d, ob, dm); } else { - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } draw_index_wire = true; } @@ -6348,7 +6343,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { if ((base->flag & OB_FROMDUPLI) == 0) - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } } else if (ob->type == OB_ARMATURE) { @@ -6375,8 +6370,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; - if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { if (ob->type == OB_CURVE) draw_index_wire = false; @@ -6384,7 +6378,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign drawCurveDMWired(ob); } else { - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } if (ob->type == OB_CURVE) @@ -6393,7 +6387,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign } else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } } @@ -6662,23 +6656,17 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* faceselect exception: also draw solid when (dt == wire), except in editmode */ if (is_obact && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { - if (ob->type == OB_MESH) { - - if (ob->mode & OB_MODE_EDIT) { - /* pass */ + if (ob->type == OB_MESH) { + if (dt < OB_SOLID) { + zbufoff = 1; + dt = OB_SOLID; } - else { - if (dt < OB_SOLID) { - zbufoff = 1; - dt = OB_SOLID; - } - - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - dt = OB_PAINT; - } - glEnable(GL_DEPTH_TEST); + if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { + dt = OB_PAINT; } + + glEnable(GL_DEPTH_TEST); } else { if (dt < OB_SOLID) { @@ -6703,7 +6691,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* bad exception, solve this! otherwise outline shows too late */ if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* still needed for curves hidden in other layers. depgraph doesnt handle that yet */ - if (ob->disp.first == NULL) BKE_displist_make_curveTypes(scene, ob, 0); + if (ELEM(NULL, ob->curve_cache, ob->curve_cache->disp.first)) { + BKE_displist_make_curveTypes(scene, ob, 0); + } } /* draw outline for selected objects, mesh does itself */ @@ -6807,7 +6797,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_bounding_volume(scene, ob, ob->boundtype); } } - else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); } @@ -6825,7 +6815,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_bounding_volume(scene, ob, ob->boundtype); } } - else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); //XXX old animsys if (cu->path) @@ -7050,6 +7040,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short // get view vector copy_v3_v3(viewnormal, rv3d->viewinv[2]); + invert_m4_m4(ob->imat, ob->obmat); mul_mat3_m4_v3(ob->imat, viewnormal); normalize_v3(viewnormal); diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 542ed7af0e6..a7940faa47d 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -83,6 +83,7 @@ struct GPUTexture; #ifdef DEBUG_DRAW_TIME # include "PIL_time.h" +# include "PIL_time_utildefines.h" #endif static int intersect_edges(float *points, float a, float b, float c, float d, float edges[12][2][3]) diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index bae2134591a..4ebd9706ac9 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -220,10 +220,10 @@ void ED_view3d_clipping_enable(void) static bool view3d_clipping_test(const float co[3], float clip[6][4]) { - if (0.0f < clip[0][3] + dot_v3v3(co, clip[0])) - if (0.0f < clip[1][3] + dot_v3v3(co, clip[1])) - if (0.0f < clip[2][3] + dot_v3v3(co, clip[2])) - if (0.0f < clip[3][3] + dot_v3v3(co, clip[3])) + if (plane_point_side_v3(clip[0], co) > 0.0f) + if (plane_point_side_v3(clip[1], co) > 0.0f) + if (plane_point_side_v3(clip[2], co) > 0.0f) + if (plane_point_side_v3(clip[3], co) > 0.0f) return false; return true; @@ -2073,7 +2073,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas bb = *bb_tmp; /* must make a copy */ /* disable boundbox check for list creation */ - BKE_object_boundbox_flag(dob->ob, OB_BB_DISABLED, 1); + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); /* need this for next part of code */ unit_m4(dob->ob->obmat); /* obmat gets restored */ @@ -2083,7 +2083,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas glEndList(); use_displist = true; - BKE_object_boundbox_flag(dob->ob, OB_BB_DISABLED, 0); + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); } } if (use_displist) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 7b8c197f3e6..f78d8981400 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3533,6 +3533,189 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); } + +/* ************************ viewroll ******************************** */ + +static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4], const float dvec[3], float angle) +{ + RegionView3D *rv3d = ar->regiondata; + float quat_mul[4]; + + /* camera axis */ + axis_angle_to_quat(quat_mul, dvec, angle); + + mul_qt_qtqt(quat, orig_quat, quat_mul); + rv3d->view = RV3D_VIEW_USER; +} + +static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) +{ + float angle = 0.0; + + { + float len1, len2, tot; + + tot = vod->ar->winrct.xmax - vod->ar->winrct.xmin; + len1 = (vod->ar->winrct.xmax - x) / tot; + len2 = (vod->ar->winrct.xmax - vod->origx) / tot; + angle = (len1 - len2) * (float)M_PI * 4.0f; + } + + if (angle != 0.0f) + view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle); + + if (vod->rv3d->viewlock & RV3D_BOXVIEW) + view3d_boxview_sync(vod->sa, vod->ar); + + ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->ar); +} + +static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->origkey && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewroll_apply(vod, event->x, event->y); + } + else if (event_code == VIEW_CONFIRM) { + ED_view3d_depth_tag_update(vod->rv3d); + viewops_data_free(C, op); + + return OPERATOR_FINISHED; + } + + return OPERATOR_RUNNING_MODAL; +} + +static int viewroll_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + RegionView3D *rv3d; + ARegion *ar; + float mousevec[3]; + + if (op->customdata) { + ViewOpsData *vod = op->customdata; + ar = vod->ar; + v3d = vod->v3d; + } + else { + ar = CTX_wm_region(C); + v3d = CTX_wm_view3d(C); + } + + negate_v3_v3(mousevec, ((RegionView3D *)ar->regiondata)->viewinv[2]); + normalize_v3(mousevec); + + rv3d = ar->regiondata; + if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + const float angle = RNA_float_get(op->ptr, "angle"); + float mousevec[3]; + float quat_new[4]; + + normalize_v3_v3(mousevec, rv3d->viewinv[2]); + negate_v3(mousevec); + view_roll_angle(ar, quat_new, rv3d->viewquat, mousevec, angle); + + view3d_smooth_view(C, v3d, ar, NULL, NULL, NULL, quat_new, NULL, NULL); + + viewops_data_free(C, op); + return OPERATOR_FINISHED; + } + else { + viewops_data_free(C, op); + return OPERATOR_CANCELLED; + } +} + +static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + /* makes op->customdata */ + viewops_data_create(C, op, event); + vod = op->customdata; + + if (RNA_struct_property_is_set(op->ptr, "angle")) { + viewroll_exec(C, op); + } + else { + /* overwrite the mouse vector with the view direction */ + normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); + negate_v3(vod->mousevec); + + if (event->type == MOUSEROTATE) { + vod->origx = vod->oldx = event->x; + viewroll_apply(vod, event->prevx, event->prevy); + ED_view3d_depth_tag_update(vod->rv3d); + + viewops_data_free(C, op); + return OPERATOR_FINISHED; + } + else { + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + } + return OPERATOR_FINISHED; +} + +static int viewroll_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op); + + return OPERATOR_CANCELLED; +} + +void VIEW3D_OT_view_roll(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "View Roll"; + ot->description = "Roll the view"; + ot->idname = "VIEW3D_OT_view_roll"; + + /* api callbacks */ + ot->invoke = viewroll_invoke; + ot->exec = viewroll_exec; + ot->modal = viewroll_modal; + ot->poll = ED_operator_rv3d_user_region_poll; + ot->cancel = viewroll_cancel; + + /* flags */ + ot->flag = 0; + + /* properties */ + ot->prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); +} + static EnumPropertyItem prop_view_pan_items[] = { {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"}, {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"}, diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index a1a13130b27..9341ea9d3e6 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -159,6 +159,11 @@ void fly_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); + WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); + WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); + WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); + WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); + WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X); WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z); @@ -580,6 +585,12 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event) double time_currwheel; float time_wheel; + /* not quite correct but avoids confusion WASD/arrow keys 'locking up' */ + if (fly->axis == -1) { + fly->axis = 2; + fly->speed = fabsf(fly->speed); + } + time_currwheel = PIL_check_seconds_timer(); time_wheel = (float)(time_currwheel - fly->time_lastwheel); fly->time_lastwheel = time_currwheel; @@ -599,6 +610,12 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event) double time_currwheel; float time_wheel; + /* not quite correct but avoids confusion WASD/arrow keys 'locking up' */ + if (fly->axis == -1) { + fly->axis = 2; + fly->speed = -fabsf(fly->speed); + } + time_currwheel = PIL_check_seconds_timer(); time_wheel = (float)(time_currwheel - fly->time_lastwheel); fly->time_lastwheel = time_currwheel; @@ -806,9 +823,10 @@ static void flyMoveCamera(bContext *C, RegionView3D *rv3d, FlyInfo *fly, static int flyApply(bContext *C, FlyInfo *fly) { -#define FLY_ROTATE_FAC 2.5f /* more is faster */ +#define FLY_ROTATE_FAC 10.0f /* more is faster */ #define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */ #define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */ +#define FLY_SMOOTH_FAC 20.0f /* higher value less lag */ /* fly mode - Shift+F * a fly loop where the user can move move the view as if they are flying @@ -1052,7 +1070,7 @@ static int flyApply(bContext *C, FlyInfo *fly) } /* impose a directional lag */ - interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * 5.0f)))); + interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * FLY_SMOOTH_FAC)))); if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = fly->root_parent ? fly->root_parent : fly->v3d->camera; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 085af4e5c18..54999b1ae95 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -95,6 +95,7 @@ void VIEW3D_OT_view_persportho(struct wmOperatorType *ot); void VIEW3D_OT_background_image_add(struct wmOperatorType *ot); void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot); void VIEW3D_OT_view_orbit(struct wmOperatorType *ot); +void VIEW3D_OT_view_roll(struct wmOperatorType *ot); void VIEW3D_OT_clip_border(struct wmOperatorType *ot); void VIEW3D_OT_cursor3d(struct wmOperatorType *ot); void VIEW3D_OT_manipulator(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index d13ab15d837..2023513ad92 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -368,7 +368,7 @@ void lattice_foreachScreenVert( Object *obedit = vc->obedit; Lattice *lt = obedit->data; BPoint *bp = lt->editlatt->latt->def; - DispList *dl = BKE_displist_find(&obedit->disp, DL_VERTS); + DispList *dl = obedit->curve_cache ? BKE_displist_find(&obedit->curve_cache->disp, DL_VERTS) : NULL; float *co = dl ? dl->verts : NULL; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 6780b71c906..e7da921bba2 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -138,6 +138,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_view_all); WM_operatortype_append(VIEW3D_OT_viewnumpad); WM_operatortype_append(VIEW3D_OT_view_orbit); + WM_operatortype_append(VIEW3D_OT_view_roll); WM_operatortype_append(VIEW3D_OT_view_pan); WM_operatortype_append(VIEW3D_OT_view_persportho); WM_operatortype_append(VIEW3D_OT_background_image_add); @@ -283,7 +284,9 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD6, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP); - + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / -12); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / 12); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_PANUP); @@ -294,6 +297,9 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPUP); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPDOWN); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / -12); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / 12); + /* active aligned, replaces '*' key in 2.4x */ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT, 0); RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 5e71913ea4a..28ffdea0e6c 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -405,15 +405,15 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float float line_end[3]; if (rv3d->is_persp) { - float mousevec[3]; + float mousevec[3], lambda; copy_v3_v3(line_sta, rv3d->viewinv[3]); ED_view3d_win_to_vector(ar, mval, mousevec); add_v3_v3v3(line_end, line_sta, mousevec); - if (isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], true) == 0) { - /* highly unlikely to ever happen, mouse vector parallel with view plane */ - zero_v3(out); - } + /* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the + * view no matter what, so apply the unsigned factor instead */ + lambda = line_plane_factor_v3(depth_pt, rv3d->viewinv[2], line_sta, line_end); + interp_v3_v3v3(out, line_sta, line_end, fabsf(lambda)); } else { float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 44c338d22b9..0246e2b75a9 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -40,6 +40,7 @@ #include "BLI_rect.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLI_callbacks.h" #include "BKE_anim.h" #include "BKE_action.h" @@ -617,7 +618,7 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[4][4], const BoundB int a, flag = -1, fl; if (bb == NULL) return true; - if (bb->flag & OB_BB_DISABLED) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; mul_m4_m4m4(mat, rv3d->persmat, obmat); @@ -1433,6 +1434,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) { #ifdef WITH_GAMEENGINE Scene *startscene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C); ARegion *ar, *prevar = CTX_wm_region(C); wmWindow *prevwin = CTX_wm_window(C); @@ -1449,6 +1451,8 @@ static int game_engine_exec(bContext *C, wmOperator *op) * the window manager until after this operator exits */ WM_redraw_windows(C); + BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_PRE); + rv3d = CTX_wm_region_view3d(C); /* sa = CTX_wm_area(C); */ /* UNUSED */ ar = CTX_wm_region(C); @@ -1504,6 +1508,8 @@ static int game_engine_exec(bContext *C, wmOperator *op) BKE_scene_set_background(CTX_data_main(C), startscene); //XXX BKE_scene_update_for_newframe(bmain, scene, scene->lay); + BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST); + return OPERATOR_FINISHED; #else (void)C; /* unused */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 6d801b86685..82c117a7486 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1749,29 +1749,32 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) // If modal, save settings back in scene if not set as operator argument if (t->flag & T_MODAL) { - /* save settings if not set in operator */ - if ((prop = RNA_struct_find_property(op->ptr, "proportional")) && - !RNA_property_is_set(op->ptr, prop)) - { - if (t->obedit) - ts->proportional = proportional; - else if (t->options & CTX_MASK) - ts->proportional_mask = (proportional != PROP_EDIT_OFF); - else - ts->proportional_objects = (proportional != PROP_EDIT_OFF); - } - if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) && - !RNA_property_is_set(op->ptr, prop)) - { - ts->proportional_size = t->prop_size; - } + /* skip saving proportional edit if it was not actually used */ + if (!(t->options & CTX_NO_PET)) { + if ((prop = RNA_struct_find_property(op->ptr, "proportional")) && + !RNA_property_is_set(op->ptr, prop)) + { + if (t->obedit) + ts->proportional = proportional; + else if (t->options & CTX_MASK) + ts->proportional_mask = (proportional != PROP_EDIT_OFF); + else + ts->proportional_objects = (proportional != PROP_EDIT_OFF); + } - if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && - !RNA_property_is_set(op->ptr, prop)) - { - ts->prop_mode = t->prop_mode; + if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) && + !RNA_property_is_set(op->ptr, prop)) + { + ts->proportional_size = t->prop_size; + } + + if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && + !RNA_property_is_set(op->ptr, prop)) + { + ts->prop_mode = t->prop_mode; + } } /* do we check for parameter? */ @@ -4825,7 +4828,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, float tvec[3]; if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, - l_tmp->v->co, plane_no, false)) + l_tmp->v->co, plane_no)) { const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co); /* allow some overlap to avoid missing the intersection because of float precision */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 4954f861934..a0550c99988 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -350,6 +350,7 @@ typedef struct TransInfo { struct ToolSettings *settings; struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ + struct ReportList *reports; /* assign from the operator, or can be NULL */ int mval[2]; /* current mouse position */ float zfac; /* use for 3d view */ struct Object *obedit; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index fd8fba91fc9..a73bf86feb1 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -727,6 +727,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) RegionView3D *rv3d = CTX_wm_region_view3d(C); float tmat[4][4], imat[4][4]; float center[3]; + int depth_test_enabled; UI_ThemeColor(TH_GRID); @@ -759,10 +760,17 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) glScalef(1.0f / aspx, 1.0f / aspy, 1.0); } + depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); + if (depth_test_enabled) + glDisable(GL_DEPTH_TEST); + set_inverted_drawing(1); drawcircball(GL_LINE_LOOP, center, t->prop_size, imat); set_inverted_drawing(0); + if (depth_test_enabled) + glEnable(GL_DEPTH_TEST); + glPopMatrix(); } } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 1849bfecc51..73c0b3c0ff4 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -275,6 +275,13 @@ static void createTransTexspace(TransInfo *t) id = ob->data; if (id == NULL || !ELEM3(GS(id->name), ID_ME, ID_CU, ID_MB)) { + BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform"); + t->total = 0; + return; + } + + if (BKE_object_obdata_is_libdata(ob)) { + BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform"); t->total = 0; return; } @@ -990,8 +997,7 @@ static void createTransPose(TransInfo *t, Object *ob) if (arm->flag & ARM_RESTPOS) { if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) { - // XXX use transform operator reports - // BKE_report(op->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled"); + BKE_report(t->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled"); return; } } @@ -1031,8 +1037,7 @@ static void createTransPose(TransInfo *t, Object *ob) } if (td != (t->data + t->total)) { - // XXX use transform operator reports - // BKE_report(op->reports, RPT_DEBUG, "Bone selection count error"); + BKE_report(t->reports, RPT_DEBUG, "Bone selection count error"); } /* initialize initial auto=ik chainlen's? */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 4c7ac4193b3..359f6425126 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1063,6 +1063,7 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even t->ar = ar; t->obedit = obedit; t->settings = ts; + t->reports = op ? op->reports : NULL; if (obedit) { copy_m3_m4(t->obedit_mat, obedit->obmat); @@ -1522,7 +1523,6 @@ void calculateCenterCursor2D(TransInfo *t) if (t->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; - /* only space supported right now but may change */ if (t->options & CTX_MASK) { ED_space_image_get_aspect(sima, &aspx, &aspy); } @@ -1531,17 +1531,37 @@ void calculateCenterCursor2D(TransInfo *t) } cursor = sima->cursor; } + else if (t->spacetype == SPACE_CLIP) { + SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first; + if (t->options & CTX_MOVIECLIP) { + ED_space_clip_get_aspect_dimension_aware(space_clip, &aspx, &aspy); + } + else { + ED_space_clip_get_aspect(space_clip, &aspx, &aspy); + } + cursor = space_clip->cursor; + } if (cursor) { if (t->options & CTX_MASK) { float co[2]; float frame_size[2]; - SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; - ED_space_image_get_size_fl(sima, frame_size); - - BKE_mask_coord_from_frame(co, cursor, frame_size); - ED_space_image_get_aspect(sima, &aspx, &aspy); + if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; + ED_space_image_get_size_fl(sima, frame_size); + BKE_mask_coord_from_frame(co, cursor, frame_size); + ED_space_image_get_aspect(sima, &aspx, &aspy); + } + else if (t->spacetype == SPACE_CLIP) { + SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first; + ED_space_clip_get_size_fl(space_clip, frame_size); + BKE_mask_coord_from_frame(co, cursor, frame_size); + ED_space_clip_get_aspect(space_clip, &aspx, &aspy); + } + else { + BLI_assert(!"Shall not happen"); + } t->center[0] = co[0] * aspx; t->center[1] = co[1] * aspy; @@ -1620,7 +1640,7 @@ void calculateCenter(TransInfo *t) calculateCenterMedian(t); break; case V3D_CURSOR: - if (t->spacetype == SPACE_IMAGE) + if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) calculateCenterCursor2D(t); else if (t->spacetype == SPACE_IPO) calculateCenterCursorGraph2D(t); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 909ca68cc20..86bdcbdb394 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1147,7 +1147,7 @@ static void TargetSnapClosest(TransInfo *t) } } -static bool snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[4][4], float timat[3][3], +static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], float obmat[4][4], float timat[3][3], const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) { @@ -1234,7 +1234,7 @@ static bool snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], s return retval; } -static bool snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4], float timat[3][3], +static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], float obmat[4][4], float timat[3][3], const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) { @@ -1518,6 +1518,45 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes return retval; } +/* may extend later (for now just snaps to empty center) */ +static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float mval[2], + float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +{ + float imat[4][4]; + float ray_start_local[3], ray_normal_local[3]; + bool retval = false; + + if (ob->transflag & OB_DUPLI) { + return retval; + } + /* for now only vertex supported */ + if (snap_mode != SCE_SNAP_MODE_VERTEX) { + return retval; + } + + invert_m4_m4(imat, obmat); + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + switch (snap_mode) { + case SCE_SNAP_MODE_VERTEX: + { + const float zero_co[3] = {0.0f}; + retval |= snapVertex(ar, zero_co, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + break; + } + default: + break; + } + + return retval; +} + static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit, Object **r_ob, float r_obmat[4][4], const float ray_start[3], const float ray_normal[3], const float mval[2], @@ -1545,6 +1584,9 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f else if (ob->type == OB_ARMATURE) { retval = snapArmature(snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); } + else if (ob->type == OB_EMPTY) { + retval = snapEmpty(snap_mode, ar, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + } if (retval) { if (r_ob) { diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c index bed8aaaddf2..721a7a3b855 100644 --- a/source/blender/editors/util/crazyspace.c +++ b/source/blender/editors/util/crazyspace.c @@ -260,11 +260,12 @@ int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em int i, a, numleft = 0, numVerts = 0; int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; + VirtualModifierData virtualModifierData; modifiers_clearErrors(ob); dm = NULL; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* compute the deformation matrices and coordinates for the first * modifiers with on cage editing that are enabled and support computing @@ -314,6 +315,7 @@ int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformma MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); int has_multires = mmd != NULL && mmd->sculptlvl > 0; int numleft = 0; + VirtualModifierData virtualModifierData; if (has_multires) { *deformmats = NULL; @@ -322,7 +324,7 @@ int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformma } dm = NULL; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (; md; md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -375,7 +377,8 @@ void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3 float (*origVerts)[3] = MEM_dupallocN(deformedVerts); float *quats = NULL; int i, deformed = 0; - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); Mesh *me = (Mesh *)ob->data; for (; md; md = md->next) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index a873702b5b8..d20ef0e70e0 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -69,7 +69,7 @@ #define USE_EDBM_LOOPTRIS -void draw_image_cursor(SpaceImage *sima, ARegion *ar) +void draw_image_cursor(ARegion *ar, const float cursor[2]) { float zoom[2], x_fac, y_fac; @@ -80,7 +80,7 @@ void draw_image_cursor(SpaceImage *sima, ARegion *ar) y_fac = zoom[1]; cpack(0xFFFFFF); - glTranslatef(sima->cursor[0], sima->cursor[1], 0.0); + glTranslatef(cursor[0], cursor[1], 0.0); fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac); fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f); fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac); @@ -108,7 +108,7 @@ void draw_image_cursor(SpaceImage *sima, ARegion *ar) fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac); fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac); - glTranslatef(-sima->cursor[0], -sima->cursor[1], 0.0); + glTranslatef(-cursor[0], -cursor[1], 0.0); setlinestyle(0); } @@ -158,7 +158,7 @@ static int draw_uvs_dm_shadow(DerivedMesh *dm) /* draw shadow mesh - this is the mesh with the modifier applied */ if (dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { - glColor3ub(112, 112, 112); + UI_ThemeColor(TH_UV_SHADOW); dm->drawUVEdges(dm); return 1; } @@ -362,7 +362,7 @@ static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage) { Base *base; - glColor3ub(96, 96, 96); + UI_ThemeColor(TH_UV_OTHERS); for (base = scene->base.first; base; base = base->next) { Object *ob = base->object; @@ -404,7 +404,7 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) if (sima->flag & SI_DRAW_OTHER) draw_uvs_other(scene, ob, curimage); - glColor3ub(112, 112, 112); + UI_ThemeColor(TH_UV_SHADOW); if (me->mtpoly) { MPoly *mpoly = me->mpoly; @@ -884,7 +884,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi draw_uvs_texpaint(sima, scene, obact); if (show_uvedit && !(toolsettings->use_uv_sculpt)) - draw_image_cursor(sima, ar); + draw_image_cursor(ar, sima->cursor); } } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 0b514e3f6fd..8c299cccbc2 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3823,6 +3823,12 @@ static void UV_OT_reveal(wmOperatorType *ot) /******************** set 3d cursor operator ********************/ +static int uv_set_2d_cursor_poll(bContext *C) +{ + return ED_operator_uvedit_space_image(C) || + ED_space_image_maskedit_poll(C); +} + static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); @@ -3858,7 +3864,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot) /* api callbacks */ ot->exec = uv_set_2d_cursor_exec; ot->invoke = uv_set_2d_cursor_invoke; - ot->poll = ED_operator_uvedit_space_image; + ot->poll = uv_set_2d_cursor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; |