diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-06-04 10:39:04 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-06-04 10:39:04 +0300 |
commit | 95011f6d484b369db92ae13c674a6522d664ea8f (patch) | |
tree | 91ba2719c9f3096fad0f1f768aa7b1c4d79aa32a /source/blender/editors/gpencil | |
parent | 0911acb5cf49c5ba05b1df045b41697704aa288a (diff) | |
parent | 44505b38df557a5711703613685a1dec9fc2c3d9 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender/editors/gpencil')
-rw-r--r-- | source/blender/editors/gpencil/drawgpencil.c | 26 | ||||
-rw-r--r-- | source/blender/editors/gpencil/editaction_gpencil.c | 152 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_brush.c | 446 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_convert.c | 324 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_data.c | 164 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_edit.c | 576 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_interpolate.c | 280 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_ops.c | 162 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_paint.c | 480 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_select.c | 324 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_undo.c | 52 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_utils.c | 148 |
12 files changed, 1567 insertions, 1567 deletions
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 50a6e9125a0..a30cb578046 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -249,7 +249,7 @@ static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short immBeginAtMost(GWN_PRIM_LINE_STRIP, totpoints - i + 1); /* need to roll-back one point to ensure that there are no gaps in the stroke */ - if (i != 0) { + if (i != 0) { gp_set_tpoint_varying_color(pt - 1, ink, color); immVertex2iv(pos, &(pt - 1)->x); ++draw_points; @@ -389,7 +389,7 @@ static void gp_draw_stroke_volumetric_3d( const bGPDspoint *pt = points; for (int i = 0; i < totpoints && pt; i++, pt++) { - gp_set_point_varying_color(pt, ink, color); + gp_set_point_varying_color(pt, ink, color); immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */ immVertex3fv(pos, &pt->x); /* we can adjust size in vertex shader based on view/projection! */ } @@ -650,7 +650,7 @@ static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thi immBeginAtMost(GWN_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add); /* need to roll-back one point to ensure that there are no gaps in the stroke */ - if (i != 0) { + if (i != 0) { const bGPDspoint *pt2 = pt - 1; mul_v3_m4v3(fpt, diff_mat, &pt2->x); gp_set_point_varying_color(pt2, ink, color); @@ -1322,7 +1322,7 @@ void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type) UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color); color[3] = 0.6f; - int dflag = 0; + int dflag = 0; /* if 3d stuff, enable flags */ if (type == REGION_DRAW_POST_VIEW) { dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); @@ -1366,7 +1366,7 @@ static void gp_draw_data_layers( /* set basic stroke thickness */ glLineWidth(lthick); - + /* Add layer drawing settings to the set of "draw flags" * NOTE: If the setting doesn't apply, it *must* be cleared, * as dflag's carry over from the previous layer @@ -1386,7 +1386,7 @@ static void gp_draw_data_layers( GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL); #undef GP_DRAWFLAG_APPLY - + /* Draw 'onionskins' (frame left + right) * - It is only possible to show these if the option is enabled * - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing @@ -1394,8 +1394,8 @@ static void gp_draw_data_layers( * - The per-layer "always show" flag however overrides the playback/render restriction, * allowing artists to selectively turn onionskins on/off during playback */ - if ((gpl->flag & GP_LAYER_ONIONSKIN) && - ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS))) + if ((gpl->flag & GP_LAYER_ONIONSKIN) && + ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS))) { /* Drawing method - only immediately surrounding (gstep = 0), * or within a frame range on either side (gstep > 0) @@ -1430,7 +1430,7 @@ static void gp_draw_data_layers( { /* Buffer stroke needs to be drawn with a different linestyle * to help differentiate them from normal strokes. - * + * * It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints */ @@ -1465,7 +1465,7 @@ static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) int font_id = BLF_default(); BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - + int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; int yco = (rect.ymax - U.widget_unit); @@ -1499,7 +1499,7 @@ static void gp_draw_data( /* turn on smooth lines (i.e. anti-aliasing) */ glEnable(GL_LINE_SMOOTH); - /* XXX: turn on some way of ensuring that the polygon edges get smoothed + /* XXX: turn on some way of ensuring that the polygon edges get smoothed * GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up * creating internal white rays due to the ways it accumulates stuff */ @@ -1643,7 +1643,7 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); int dflag = 0; - + /* check that we have grease-pencil stuff to draw */ if (sa == NULL) return; bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX @@ -1725,7 +1725,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, } /* draw it! */ - gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); + gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); } void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 90d44503013..5e62a87caf3 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -66,18 +66,18 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *)) { bGPDframe *gpf; - + /* error checker */ if (gpl == NULL) return false; - + /* do loop */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { /* execute callback */ if (gpf_cb(gpf, scene)) return true; } - + /* nothing to return */ return false; } @@ -90,19 +90,19 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) { bGPDframe *gpf; CfraElem *ce; - + /* error checking */ if (ELEM(NULL, gpl, elems)) return; - + /* loop through gp-frames, adding */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) { ce = MEM_callocN(sizeof(CfraElem), "CfraElem"); - + ce->cfra = (float)gpf->framenum; ce->sel = (gpf->flag & GP_FRAME_SELECT) ? 1 : 0; - + BLI_addtail(elems, ce); } } @@ -115,17 +115,17 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) bool ED_gplayer_frame_select_check(bGPDlayer *gpl) { bGPDframe *gpf; - + /* error checking */ if (gpl == NULL) return false; - + /* stop at the first one found */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { if (gpf->flag & GP_FRAME_SELECT) return true; } - + /* not found */ return false; } @@ -135,7 +135,7 @@ static void gpframe_select(bGPDframe *gpf, short select_mode) { if (gpf == NULL) return; - + switch (select_mode) { case SELECT_ADD: gpf->flag |= GP_FRAME_SELECT; @@ -153,11 +153,11 @@ static void gpframe_select(bGPDframe *gpf, short select_mode) void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode) { bGPDframe *gpf; - + /* error checking */ if (gpl == NULL) return; - + /* handle according to mode */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { gpframe_select(gpf, select_mode); @@ -170,7 +170,7 @@ void ED_gplayer_frame_select_set(bGPDlayer *gpl, short mode) /* error checking */ if (gpl == NULL) return; - + /* now call the standard function */ ED_gpencil_select_frames(gpl, mode); } @@ -179,12 +179,12 @@ void ED_gplayer_frame_select_set(bGPDlayer *gpl, short mode) void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode) { bGPDframe *gpf; - + if (gpl == NULL) return; - + gpf = BKE_gpencil_layer_find_frame(gpl, selx); - + if (gpf) { gpframe_select(gpf, select_mode); } @@ -194,10 +194,10 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode) void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short select_mode) { bGPDframe *gpf; - + if (gpl == NULL) return; - + /* only select those frames which are in bounds */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { if (IN_RANGE(gpf->framenum, min, max)) @@ -209,21 +209,21 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode) { bGPDframe *gpf; - + if (gpl == NULL) return; - + /* only select frames which are within the region */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { /* construct a dummy point coordinate to do this testing with */ float pt[2] = {0}; - + pt[0] = gpf->framenum; pt[1] = ked->channel_y; - + /* check the necessary regions */ if (tool == BEZT_OK_CHANNEL_LASSO) { - /* Lasso */ + /* Lasso */ if (keyframe_region_lasso_test(ked->data, pt)) gpframe_select(gpf, select_mode); } @@ -243,21 +243,21 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) { bGPDframe *gpf, *gpfn; bool changed = false; - + /* error checking */ if (gpl == NULL) return false; - + /* check for frames to delete */ for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; - + if (gpf->flag & GP_FRAME_SELECT) { BKE_gpencil_layer_delframe(gpl, gpf); changed = true; } } - + return changed; } @@ -265,23 +265,23 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) void ED_gplayer_frames_duplicate(bGPDlayer *gpl) { bGPDframe *gpf, *gpfn; - + /* error checking */ if (gpl == NULL) return; - + /* duplicate selected frames */ for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; - + /* duplicate this frame */ if (gpf->flag & GP_FRAME_SELECT) { bGPDframe *gpfd; - + /* duplicate frame, and deselect self */ gpfd = BKE_gpencil_frame_duplicate(gpf); gpf->flag &= ~GP_FRAME_SELECT; - + BLI_insertlinkafter(&gpl->frames, gpf, gpfd); } } @@ -293,10 +293,10 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl) void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) { bGPDframe *gpf; - + if (gpl == NULL) return; - + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { if (gpf->flag & GP_FRAME_SELECT) { gpf->key_type = type; @@ -327,7 +327,7 @@ void ED_gpencil_anim_copybuf_free(void) { BKE_gpencil_free_layers(&gp_anim_copybuf); BLI_listbase_clear(&gp_anim_copybuf); - + gp_anim_copy_firstframe = 999999999; gp_anim_copy_lastframe = -999999999; gp_anim_copy_cfra = 0; @@ -344,23 +344,23 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; - + Scene *scene = ac->scene; - - + + /* clear buffer first */ ED_gpencil_anim_copybuf_free(); - + /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - + /* assume that each of these is a GP layer */ for (ale = anim_data.first; ale; ale = ale->next) { ListBase copied_frames = {NULL, NULL}; bGPDlayer *gpl = (bGPDlayer *)ale->data; bGPDframe *gpf; - + /* loop over frames, and copy only selected frames */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { /* if frame is selected, make duplicate it and its strokes */ @@ -368,41 +368,41 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) /* make a copy of this frame */ bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf); BLI_addtail(&copied_frames, new_frame); - + /* extend extents for keyframes encountered */ if (gpf->framenum < gp_anim_copy_firstframe) - gp_anim_copy_firstframe = gpf->framenum; + gp_anim_copy_firstframe = gpf->framenum; if (gpf->framenum > gp_anim_copy_lastframe) gp_anim_copy_lastframe = gpf->framenum; } } - + /* create a new layer in buffer if there were keyframes here */ if (BLI_listbase_is_empty(&copied_frames) == false) { bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer"); BLI_addtail(&gp_anim_copybuf, new_layer); - + /* move over copied frames */ BLI_movelisttolist(&new_layer->frames, &copied_frames); BLI_assert(copied_frames.first == NULL); - + /* make a copy of the layer's name - for name-based matching later... */ BLI_strncpy(new_layer->info, gpl->info, sizeof(new_layer->info)); } } - + /* in case 'relative' paste method is used */ gp_anim_copy_cfra = CFRA; - + /* clean up */ ANIM_animdata_freelist(&anim_data); - + /* check if anything ended up in the buffer */ if (ELEM(NULL, gp_anim_copybuf.first, gp_anim_copybuf.last)) { BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); return false; } - + /* report success */ return true; } @@ -414,22 +414,22 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; - + Scene *scene = ac->scene; bool no_name = false; int offset = 0; - + /* check if buffer is empty */ if (BLI_listbase_is_empty(&gp_anim_copybuf)) { BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste"); return false; } - + /* check if single channel in buffer (disregard names if so) */ if (gp_anim_copybuf.first == gp_anim_copybuf.last) { no_name = true; } - + /* methods of offset (eKeyPasteOffset) */ switch (offset_mode) { case KEYFRAME_PASTE_OFFSET_CFRA_START: @@ -446,19 +446,19 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) break; } - + /* filter data */ // TODO: try doing it with selection, then without selection imits filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - + /* from selected channels */ for (ale = anim_data.first; ale; ale = ale->next) { bGPDlayer *gpld = (bGPDlayer *)ale->data; bGPDlayer *gpls = NULL; bGPDframe *gpfs, *gpf; - - + + /* find suitable layer from buffer to use to paste from */ for (gpls = gp_anim_copybuf.first; gpls; gpls = gpls->next) { /* check if layer name matches */ @@ -466,21 +466,21 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) break; } } - + /* this situation might occur! */ if (gpls == NULL) continue; - + /* add frames from buffer */ for (gpfs = gpls->frames.first; gpfs; gpfs = gpfs->next) { /* temporarily apply offset to buffer-frame while copying */ gpfs->framenum += offset; - + /* get frame to copy data into (if no frame returned, then just ignore) */ gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, 1); if (gpf) { bGPDstroke *gps, *gpsn; - + /* This should be the right frame... as it may be a pre-existing frame, * must make sure that only compatible stroke types get copied over * - We cannot just add a duplicate frame, as that would cause errors @@ -495,19 +495,19 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* duplicate triangle information */ gpsn->triangles = MEM_dupallocN(gps->triangles); /* append stroke to frame */ - BLI_addtail(&gpf->strokes, gpsn); + BLI_addtail(&gpf->strokes, gpsn); } - + /* if no strokes (i.e. new frame) added, free gpf */ if (BLI_listbase_is_empty(&gpf->strokes)) BKE_gpencil_layer_delframe(gpld, gpf); } - + /* unapply offset from buffer-frame */ gpfs->framenum -= offset; } } - + /* clean up */ ANIM_animdata_freelist(&anim_data); return true; @@ -574,37 +574,37 @@ void ED_gplayer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode) static short mirror_gpf_cframe(bGPDframe *gpf, Scene *scene) { int diff; - + if (gpf->flag & GP_FRAME_SELECT) { diff = CFRA - gpf->framenum; gpf->framenum = CFRA + diff; } - + return 0; } static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *UNUSED(scene)) { int diff; - + if (gpf->flag & GP_FRAME_SELECT) { diff = -gpf->framenum; gpf->framenum = diff; } - + return 0; } static short mirror_gpf_xaxis(bGPDframe *gpf, Scene *UNUSED(scene)) { int diff; - + /* NOTE: since we can't really do this, we just do the same as for yaxis... */ if (gpf->flag & GP_FRAME_SELECT) { diff = -gpf->framenum; gpf->framenum = diff; } - + return 0; } @@ -613,7 +613,7 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene) static TimeMarker *marker; static short initialized = 0; int diff; - + /* In order for this mirror function to work without * any extra arguments being added, we use the case * of bezt==NULL to denote that we should find the @@ -621,7 +621,7 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene) * to use this way, as it will be set to null after * each cycle in which this is called. */ - + if (gpf) { /* mirroring time */ if ((gpf->flag & GP_FRAME_SELECT) && (marker)) { @@ -644,7 +644,7 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene) } } } - + return 0; } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 1cb882e9a43..c2e532be0b3 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -87,54 +87,54 @@ typedef struct tGP_BrushEditData { /* Current editor/region/etc. */ /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */ Scene *scene; - + ScrArea *sa; ARegion *ar; - + /* Current GPencil datablock */ bGPdata *gpd; - + /* Brush Settings */ GP_BrushEdit_Settings *settings; GP_EditBrush_Data *brush; - + eGP_EditBrush_Types brush_type; eGP_EditBrush_Flag flag; - + /* Space Conversion Data */ GP_SpaceConversion gsc; - - + + /* Is the brush currently painting? */ bool is_painting; - + /* Start of new sculpt stroke */ bool first; - + /* Current frame */ int cfra; - - + + /* Brush Runtime Data: */ /* - position and pressure * - the *_prev variants are the previous values */ int mval[2], mval_prev[2]; float pressure, pressure_prev; - + /* - effect vector (e.g. 2D/3D translation for grab brush) */ float dvec[3]; - + /* brush geometry (bounding box) */ rcti brush_rect; - + /* Custom data for certain brushes */ /* - map from bGPDstroke's to structs containing custom data about those strokes */ GHash *stroke_customdata; /* - general customdata */ void *customdata; - - + + /* Timer for in-place accumulation of brush effect */ wmTimer *timer; bool timerTick; /* is this event from a timer */ @@ -170,12 +170,12 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso) { /* The basic setting is the brush's setting (from the panel) */ bool invert = ((gso->brush->flag & GP_EDITBRUSH_FLAG_INVERT) != 0); - + /* During runtime, the user can hold down the Ctrl key to invert the basic behaviour */ if (gso->flag & GP_EDITBRUSH_FLAG_INVERT) { invert ^= true; } - + return invert; } @@ -183,26 +183,26 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso) static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2]) { GP_EditBrush_Data *brush = gso->brush; - + /* basic strength factor from brush settings */ float influence = brush->strength; - + /* use pressure? */ if (brush->flag & GP_EDITBRUSH_FLAG_USE_PRESSURE) { influence *= gso->pressure; } - + /* distance fading */ if (brush->flag & GP_EDITBRUSH_FLAG_USE_FALLOFF) { float distance = (float)len_v2v2_int(gso->mval, co); float fac; - + CLAMP(distance, 0.0f, (float)radius); fac = 1.0f - (distance / (float)radius); - + influence *= fac; } - + /* return influence */ return influence; } @@ -241,7 +241,7 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) { gp_smooth_stroke_thickness(gps, i, inf); } - + return true; } @@ -254,13 +254,13 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in { bGPDspoint *pt = gps->points + i; float inf; - + /* Compute strength of effect * - We divide the strength by 10, so that users can set "sane" values. * Otherwise, good default values are in the range of 0.093 */ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; - + /* apply */ // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff if (gp_brush_invert_check(gso)) { @@ -271,7 +271,7 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in /* make line thicker - increase stroke pressure */ pt->pressure += inf; } - + /* Pressure should stay within [0.0, 1.0] * However, it is nice for volumetric strokes to be able to exceed * the upper end of this range. Therefore, we don't actually clamp @@ -279,7 +279,7 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in */ if (pt->pressure < 0.0f) pt->pressure = 0.0f; - + return true; } @@ -333,7 +333,7 @@ typedef struct tGPSB_Grab_StrokeData { int *points; /* array of influence weights for each of the included points */ float *weights; - + /* capacity of the arrays */ int capacity; /* actual number of items currently stored */ @@ -344,9 +344,9 @@ typedef struct tGPSB_Grab_StrokeData { static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps) { tGPSB_Grab_StrokeData *data = NULL; - + BLI_assert(gps->totpoints > 0); - + /* Check if there are buffers already (from a prior run) */ if (BLI_ghash_haskey(gso->stroke_customdata, gps)) { /* Ensure that the caches are empty @@ -355,25 +355,25 @@ static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps) */ data = BLI_ghash_lookup(gso->stroke_customdata, gps); BLI_assert(data != NULL); - + data->size = 0; /* minimum requirement - so that we can repopulate again */ - + memset(data->points, 0, sizeof(int) * data->capacity); memset(data->weights, 0, sizeof(float) * data->capacity); } else { /* Create new instance */ data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data"); - + data->capacity = gps->totpoints; data->size = 0; - + data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices"); data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights"); - + /* hook up to the cache */ BLI_ghash_insert(gso->stroke_customdata, gps, data); - } + } } /* store references to stroke points in the initial stage */ @@ -382,15 +382,15 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, { tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); float inf = gp_brush_influence_calc(gso, radius, co); - + BLI_assert(data != NULL); BLI_assert(data->size < data->capacity); - + /* insert this point into the set of affected points */ data->points[data->size] = i; data->weights[data->size] = inf; data->size++; - + /* done */ return true; } @@ -406,13 +406,13 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso) RegionView3D *rv3d = gso->ar->regiondata; float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d)->location; float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - + float mval_f[2]; - + /* convert from 2D screenspace to 3D... */ mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]); mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]); - + ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac); } else { @@ -435,7 +435,7 @@ static void gp_brush_grab_apply_cached( for (i = 0; i < data->size; i++) { bGPDspoint *pt = &gps->points[data->points[i]]; float delta[3] = {0.0f}; - + /* adjust the amount of displacement to apply */ mul_v3_v3fl(delta, gso->dvec, data->weights[i]); if (!parented) { @@ -454,7 +454,7 @@ static void gp_brush_grab_apply_cached( invert_m4_m4(inverse_diff_mat, diff_mat); mul_m4_v3(inverse_diff_mat, &pt->x); } - + } } @@ -462,11 +462,11 @@ static void gp_brush_grab_apply_cached( static void gp_brush_grab_stroke_free(void *ptr) { tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr; - + /* free arrays */ MEM_freeN(data->points); MEM_freeN(data->weights); - + /* ... and this item itself, since it was also allocated */ MEM_freeN(data); } @@ -481,10 +481,10 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, bGPDspoint *pt = gps->points + i; float inf = gp_brush_influence_calc(gso, radius, co); float delta[3] = {0.0f}; - + /* adjust the amount of displacement to apply */ mul_v3_v3fl(delta, gso->dvec, inf); - + /* apply */ add_v3_v3(&pt->x, delta); @@ -506,12 +506,12 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) RegionView3D *rv3d = gso->ar->regiondata; float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d)->location; float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - + float mval_f[2] = {UNPACK2(gso->mval)}; float mval_prj[2]; float dvec[3]; - - + + if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { sub_v2_v2v2(mval_f, mval_prj, mval_f); ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac); @@ -537,17 +537,17 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, bGPDspoint *pt = gps->points + i; float fac, inf; float vec[3]; - + /* Scale down standard influence value to get it more manageable... * - No damping = Unmanageable at > 0.5 strength * - Div 10 = Not enough effect * - Div 5 = Happy medium... (by trial and error) */ inf = gp_brush_influence_calc(gso, radius, co) / 5.0f; - + /* 1) Make this point relative to the cursor/midpoint (dvec) */ sub_v3_v3v3(vec, &pt->x, gso->dvec); - + /* 2) Shrink the distance by pulling the point towards the midpoint * (0.0 = at midpoint, 1 = at edge of brush region) * OR @@ -562,10 +562,10 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, fac = 1.0f - (inf * inf); /* squared to temper the effect... */ } mul_v3_fl(vec, fac); - + /* 3) Translate back to original space, with the shrinkage applied */ add_v3_v3v3(&pt->x, gso->dvec, vec); - + /* done */ return true; } @@ -582,16 +582,16 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, { bGPDspoint *pt = gps->points + i; float angle, inf; - + /* Angle to rotate by */ inf = gp_brush_influence_calc(gso, radius, co); angle = DEG2RADF(1.0f) * inf; - + if (gp_brush_invert_check(gso)) { /* invert angle that we rotate by */ angle *= -1; } - + /* Rotate in 2D or 3D space? */ if (gps->flag & GP_STROKE_3DSPACE) { /* Perform rotation in 3D space... */ @@ -599,13 +599,13 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, float rmat[3][3]; float axis[3]; float vec[3]; - + /* Compute rotation matrix - rotate around view vector by angle */ negate_v3_v3(axis, rv3d->persinv[2]); normalize_v3(axis); - + axis_angle_normalized_to_mat3(rmat, axis, angle); - + /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */ sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */ mul_m3_v3(rmat, vec); @@ -615,20 +615,20 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, const float axis[3] = {0.0f, 0.0f, 1.0f}; float vec[3] = {0.0f}; float rmat[3][3]; - + /* Express position of point relative to cursor, ready to rotate */ // XXX: There is still some offset here, but it's close to working as expected... vec[0] = (float)(co[0] - gso->mval[0]); vec[1] = (float)(co[1] - gso->mval[1]); - + /* rotate point */ axis_angle_normalized_to_mat3(rmat, axis, angle); mul_m3_v3(rmat, vec); - + /* Convert back to screen-coordinates */ vec[0] += (float)gso->mval[0]; vec[1] += (float)gso->mval[1]; - + /* Map from screen-coordinates to final coordinate space */ if (gps->flag & GP_STROKE_2DSPACE) { View2D *v2d = gso->gsc.v2d; @@ -639,7 +639,7 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, copy_v2_v2(&pt->x, vec); } } - + /* done */ return true; } @@ -653,7 +653,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in const int radius, const int co[2]) { bGPDspoint *pt = gps->points + i; - + /* Amount of jitter to apply depends on the distance of the point to the cursor, * as well as the strength of the brush */ @@ -766,13 +766,13 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in typedef struct tGPSB_CloneBrushData { /* midpoint of the strokes on the clipboard */ float buffer_midpoint[3]; - + /* number of strokes in the paste buffer (and/or to be created each time) */ size_t totitems; - + /* for "stamp" mode, the currently pasted brushes */ bGPDstroke **new_strokes; - + /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */ GHash *new_colors; } tGPSB_CloneBrushData; @@ -782,43 +782,43 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data; bGPDstroke *gps; - + /* init custom data */ gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData"); - + /* compute midpoint of strokes on clipboard */ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { const float dfac = 1.0f / ((float)gps->totpoints); float mid[3] = {0.0f}; - + bGPDspoint *pt; int i; - + /* compute midpoint of this stroke */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { float co[3]; - + mul_v3_v3fl(co, &pt->x, dfac); add_v3_v3(mid, co); } - + /* combine this stroke's data with the main data */ add_v3_v3(data->buffer_midpoint, mid); data->totitems++; } } - + /* Divide the midpoint by the number of strokes, to finish averaging it */ if (data->totitems > 1) { mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems); } - + /* Create a buffer for storing the current strokes */ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) { data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array"); } - + /* Init colormap for mapping between the pasted stroke's source colour(names) * and the final colours that will be used here instead... */ @@ -829,19 +829,19 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) static void gp_brush_clone_free(tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; - + /* free strokes array */ if (data->new_strokes) { MEM_freeN(data->new_strokes); data->new_strokes = NULL; } - + /* free copybuf colormap */ if (data->new_colors) { BLI_ghash_free(data->new_colors, NULL, NULL); data->new_colors = NULL; } - + /* free the customdata itself */ MEM_freeN(data); gso->customdata = NULL; @@ -851,44 +851,44 @@ static void gp_brush_clone_free(tGP_BrushEditData *gso) static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; - + Scene *scene = gso->scene; bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); bGPDstroke *gps; - + float delta[3]; size_t strokes_added = 0; - + /* Compute amount to offset the points by */ /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */ - + gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */ sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint); - + /* Copy each stroke into the layer */ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { bGPDstroke *new_stroke; bGPDspoint *pt; int i; - + /* Make a new stroke */ new_stroke = MEM_dupallocN(gps); - + new_stroke->points = MEM_dupallocN(gps->points); new_stroke->triangles = MEM_dupallocN(gps->triangles); - + new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); - + /* Fix color references */ BLI_assert(new_stroke->colorname[0] != '\0'); new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname); - + BLI_assert(new_stroke->palcolor != NULL); BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname)); - + /* Adjust all the stroke's points, so that the strokes * get pasted relative to where the cursor is now */ @@ -896,7 +896,7 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) /* assume that the delta can just be applied, and then everything works */ add_v3_v3(&pt->x, delta); } - + /* Store ref for later */ if ((data->new_strokes) && (strokes_added < data->totitems)) { data->new_strokes[strokes_added] = new_stroke; @@ -911,31 +911,31 @@ static void gp_brush_clone_adjust(tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; size_t snum; - + /* Compute the amount of movement to apply (overwrites dvec) */ gp_brush_grab_calc_dvec(gso); - + /* For each of the stored strokes, apply the offset to each point */ /* NOTE: Again this assumes that in the 3D view, we only have 3d space and not screenspace strokes... */ for (snum = 0; snum < data->totitems; snum++) { bGPDstroke *gps = data->new_strokes[snum]; bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (gso->brush->flag & GP_EDITBRUSH_FLAG_USE_FALLOFF) { /* "Smudge" Effect when falloff is enabled */ float delta[3] = {0.0f}; int sco[2] = {0}; float influence; - + /* compute influence on point */ gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]); influence = gp_brush_influence_calc(gso, gso->brush->size, sco); - + /* adjust the amount of displacement to apply */ mul_v3_v3fl(delta, gso->dvec, influence); - + /* apply */ add_v3_v3(&pt->x, delta); } @@ -967,7 +967,7 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) gp_brush_clone_add(C, gso); } } - + return true; } @@ -1007,7 +1007,7 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customda static void gpencil_toggle_brush_cursor(bContext *C, bool enable) { GP_BrushEdit_Settings *gset = gpsculpt_get_settings(CTX_data_scene(C)); - + if (gset->paintcursor && !enable) { /* clear cursor */ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); @@ -1015,8 +1015,8 @@ static void gpencil_toggle_brush_cursor(bContext *C, bool enable) } else if (enable) { /* enable cursor */ - gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), - NULL, + gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), + NULL, gp_brush_drawcursor, NULL); } } @@ -1029,15 +1029,15 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) { const char *brush_name = NULL; char str[UI_MAX_DRAW_STR] = ""; - + RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name); - + BLI_snprintf(str, sizeof(str), IFACE_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit" " | Ctrl to Invert Action | Wheel Up/Down for Size " " | Shift-Wheel Up/Down for Strength"), (brush_name) ? brush_name : "<?>"); - + ED_area_headerprint(CTX_wm_area(C), str); } @@ -1050,36 +1050,36 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); tGP_BrushEditData *gso; - + /* setup operator data */ gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData"); op->customdata = gso; - + /* store state */ gso->settings = gpsculpt_get_settings(scene); gso->brush = gpsculpt_get_brush(scene); - + gso->brush_type = gso->settings->brushtype; - - + + gso->is_painting = false; gso->first = true; - + gso->gpd = ED_gpencil_data_get_active(C); gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */ - + gso->scene = scene; - + gso->sa = CTX_wm_area(C); gso->ar = CTX_wm_region(C); - + /* initialise custom data for brushes */ switch (gso->brush_type) { case GP_EDITBRUSH_TYPE_CLONE: { bGPDstroke *gps; bool found = false; - + /* check that there are some usable strokes in the buffer */ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { @@ -1087,12 +1087,12 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) break; } } - + if (found == false) { /* STOP HERE! Nothing to paste! */ - BKE_report(op->reports, RPT_ERROR, + BKE_report(op->reports, RPT_ERROR, "Copy some strokes to the clipboard before using the Clone brush to paste copies of them"); - + MEM_freeN(gso); op->customdata = NULL; return false; @@ -1103,30 +1103,30 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) } break; } - + case GP_EDITBRUSH_TYPE_GRAB: { /* initialise the cache needed for this brush */ gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash"); break; } - + /* Others - No customdata needed */ default: break; } - - + + /* setup space conversions */ gp_point_conversion_init(C, &gso->gsc); - + /* update header */ gpsculpt_brush_header_set(C, gso); - + /* setup cursor drawing */ WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR); gpencil_toggle_brush_cursor(C, true); - + return true; } @@ -1134,7 +1134,7 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) { tGP_BrushEditData *gso = op->customdata; wmWindow *win = CTX_wm_window(C); - + /* free brush-specific data */ switch (gso->brush_type) { case GP_EDITBRUSH_TYPE_GRAB: @@ -1146,18 +1146,18 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free); break; } - + case GP_EDITBRUSH_TYPE_CLONE: { /* Free customdata */ gp_brush_clone_free(gso); break; } - + default: break; } - + /* unregister timer (only used for realtime) */ if (gso->timer) { WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer); @@ -1167,7 +1167,7 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) ED_area_headerprint(CTX_wm_area(C), NULL); WM_cursor_modal_restore(win); gpencil_toggle_brush_cursor(C, false); - + /* free operator data */ MEM_freeN(gso); op->customdata = NULL; @@ -1188,18 +1188,18 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) bGPdata *gpd = gso->gpd; bGPDlayer *gpl; int cfra = CFRA; - + /* only try to add a new frame if this is the first stroke, or the frame has changed */ if ((gpd == NULL) || (cfra == gso->cfra)) return; - + /* go through each layer, and ensure that we've got a valid frame to use */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; - - /* Make a new frame to work on if the layer's frame and the current scene frame don't match up + + /* Make a new frame to work on if the layer's frame and the current scene frame don't match up * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame... */ @@ -1209,7 +1209,7 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) } } } - + /* save off new current frame, so that next update works fine */ gso->cfra = cfra; } @@ -1224,7 +1224,7 @@ static bool gpsculpt_brush_do_stroke( GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; const int radius = gso->brush->size; - + bGPDspoint *pt1, *pt2; int pc1[2] = {0}; int pc2[2] = {0}; @@ -1241,7 +1241,7 @@ static bool gpsculpt_brush_do_stroke( gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); } - + /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ @@ -1252,14 +1252,14 @@ static bool gpsculpt_brush_do_stroke( } } else { - /* Loop over the points in the stroke, checking for intersections + /* Loop over the points in the stroke, checking for intersections * - an intersection means that we touched the stroke */ for (i = 0; (i + 1) < gps->totpoints; i++) { /* Get points to work with */ pt1 = gps->points + i; pt2 = gps->points + i + 1; - + /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) { @@ -1292,14 +1292,14 @@ static bool gpsculpt_brush_do_stroke( if (gp_stroke_inside_circle(gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { /* Apply operation to these points */ bool ok = false; - + /* To each point individually... */ ok = apply(gso, gps, i, radius, pc1); - + /* Only do the second point if this is the last segment, * and it is unlikely that the point will get handled - * otherwise. - * + * otherwise. + * * NOTE: There is a small risk here that the second point wasn't really * actually in-range. In that case, it only got in because * the line linking the points was! @@ -1311,13 +1311,13 @@ static bool gpsculpt_brush_do_stroke( else { include_last = true; } - + changed |= ok; } else if (include_last) { /* This case is for cases where for whatever reason the second vert (1st here) doesn't get included * because the whole edge isn't in bounds, but it would've qualified since it did with the - * previous step (but wasn't added then, to avoid double-ups) + * previous step (but wasn't added then, to avoid double-ups) */ changed |= apply(gso, gps, i, radius, pc1); include_last = false; @@ -1325,7 +1325,7 @@ static bool gpsculpt_brush_do_stroke( } } } - + return changed; } @@ -1333,7 +1333,7 @@ static bool gpsculpt_brush_do_stroke( static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) { bool changed = false; - + /* Calculate brush-specific data which applies equally to all points */ switch (gso->brush_type) { case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */ @@ -1343,7 +1343,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) gp_brush_grab_calc_dvec(gso); break; } - + case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */ case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */ { @@ -1351,19 +1351,19 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) gp_brush_calc_midpoint(gso); break; } - + case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Random jitter */ { /* compute the displacement vector for the cursor (in data space) */ gp_brush_grab_calc_dvec(gso); break; } - + default: break; } - - + + /* Find visible strokes, and perform operations on those if hit */ float diff_mat[4][4]; bool parented = false; @@ -1373,7 +1373,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) bGPDframe *gpf = gpl->actframe; if (gpf == NULL) continue; - + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); @@ -1382,7 +1382,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) else { parented = false; } - + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) @@ -1477,34 +1477,34 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt float mousef[2]; int mouse[2]; bool changed = false; - + /* Get latest mouse coordinates */ RNA_float_get_array(itemptr, "mouse", mousef); gso->mval[0] = mouse[0] = (int)(mousef[0]); gso->mval[1] = mouse[1] = (int)(mousef[1]); - + gso->pressure = RNA_float_get(itemptr, "pressure"); - + if (RNA_boolean_get(itemptr, "pen_flip")) gso->flag |= GP_EDITBRUSH_FLAG_INVERT; else gso->flag &= ~GP_EDITBRUSH_FLAG_INVERT; - - + + /* Store coordinates as reference, if operator just started running */ if (gso->first) { gso->mval_prev[0] = gso->mval[0]; gso->mval_prev[1] = gso->mval[1]; gso->pressure_prev = gso->pressure; } - + /* Update brush_rect, so that it represents the bounding rectangle of brush */ gso->brush_rect.xmin = mouse[0] - radius; gso->brush_rect.ymin = mouse[1] - radius; gso->brush_rect.xmax = mouse[0] + radius; gso->brush_rect.ymax = mouse[1] + radius; - - + + /* Apply brush */ if (gso->brush_type == GP_EDITBRUSH_TYPE_CLONE) { changed = gpsculpt_brush_apply_clone(C, gso); @@ -1512,13 +1512,13 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt else { changed = gpsculpt_brush_apply_standard(C, gso); } - - + + /* Updates */ if (changed) { WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } - + /* Store values for next step */ gso->mval_prev[0] = gso->mval[0]; gso->mval_prev[1] = gso->mval[1]; @@ -1535,24 +1535,24 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven PointerRNA itemptr; float mouse[2]; int tablet = 0; - + mouse[0] = event->mval[0] + 1; mouse[1] = event->mval[1] + 1; - + /* fill in stroke */ RNA_collection_add(op->ptr, "stroke", &itemptr); - + RNA_float_set_array(&itemptr, "mouse", mouse); RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false); RNA_boolean_set(&itemptr, "is_start", gso->first); - + /* handle pressure sensitivity (which is supplied by tablets) */ if (event->tablet_data) { const wmTabletData *wmtab = event->tablet_data; float pressure = wmtab->Pressure; - + tablet = (wmtab->Active != EVT_TABLET_NONE); - + /* special exception here for too high pressure values on first touch in * windows for some tablets: clamp the values to be sane */ @@ -1564,7 +1564,7 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven else { RNA_float_set(&itemptr, "pressure", 1.0f); } - + /* apply */ gpsculpt_brush_apply(C, op, &itemptr); } @@ -1574,15 +1574,15 @@ static int gpsculpt_brush_exec(bContext *C, wmOperator *op) { if (!gpsculpt_brush_init(C, op)) return OPERATOR_CANCELLED; - - RNA_BEGIN(op->ptr, itemptr, "stroke") + + RNA_BEGIN(op->ptr, itemptr, "stroke") { gpsculpt_brush_apply(C, op, &itemptr); } RNA_END; - + gpsculpt_brush_exit(C, op); - + return OPERATOR_FINISHED; } @@ -1594,13 +1594,13 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); bool needs_timer = false; float brush_rate = 0.0f; - + /* init painting data */ if (!gpsculpt_brush_init(C, op)) return OPERATOR_CANCELLED; - + gso = op->customdata; - + /* initialise type-specific data (used for the entire session) */ switch (gso->brush_type) { /* Brushes requiring timer... */ @@ -1608,7 +1608,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve brush_rate = 0.01f; // XXX: hardcoded needs_timer = true; break; - + case GP_EDITBRUSH_TYPE_STRENGTH: brush_rate = 0.01f; // XXX: hardcoded needs_timer = true; @@ -1618,39 +1618,39 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve brush_rate = 0.001f; // XXX: hardcoded needs_timer = true; break; - + case GP_EDITBRUSH_TYPE_TWIST: brush_rate = 0.01f; // XXX: hardcoded needs_timer = true; break; - + default: break; } - + /* register timer for increasing influence by hovering over an area */ if (needs_timer) { gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate); } - + /* register modal handler */ WM_event_add_modal_handler(C, op); - + /* start drawing immediately? */ if (is_modal == false) { ARegion *ar = CTX_wm_region(C); - + /* ensure that we'll have a new frame to draw on */ gpsculpt_brush_init_stroke(gso); - + /* apply first dab... */ gso->is_painting = true; gpsculpt_brush_apply_event(C, op, event); - + /* redraw view with feedback */ ED_region_tag_redraw(ar); } - + return OPERATOR_RUNNING_MODAL; } @@ -1661,7 +1661,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); bool redraw_region = false; bool redraw_toolsettings = false; - + /* The operator can be in 2 states: Painting and Idling */ if (gso->is_painting) { /* Painting */ @@ -1671,11 +1671,11 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even case INBETWEEN_MOUSEMOVE: /* apply brush effect at new position */ gpsculpt_brush_apply_event(C, op, event); - + /* force redraw, so that the cursor will at least be valid */ redraw_region = true; break; - + /* Timer Tick - Only if this was our own timer */ case TIMER: if (event->customdata == gso->timer) { @@ -1684,7 +1684,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->timerTick = false; } break; - + /* Adjust brush settings */ /* FIXME: Step increments and modifier keys are hardcoded here! */ case WHEELUPMOUSE: @@ -1699,12 +1699,12 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->brush->size += 3; CLAMP_MAX(gso->brush->size, 300); } - + redraw_region = true; redraw_toolsettings = true; break; - - case WHEELDOWNMOUSE: + + case WHEELDOWNMOUSE: case PADMINUS: if (event->shift) { /* decrease strength */ @@ -1716,11 +1716,11 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->brush->size -= 3; CLAMP_MIN(gso->brush->size, 1); } - + redraw_region = true; redraw_toolsettings = true; break; - + /* Painting mbut release = Stop painting (back to idle) */ case LEFTMOUSE: //BLI_assert(event->val == KM_RELEASE); @@ -1731,12 +1731,12 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even else { /* end sculpt session, since we're not modal */ gso->is_painting = false; - + gpsculpt_brush_exit(C, op); return OPERATOR_FINISHED; } break; - + /* Abort painting if any of the usual things are tried */ case MIDDLEMOUSE: case RIGHTMOUSE: @@ -1748,34 +1748,34 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even else { /* Idling */ BLI_assert(is_modal == true); - + switch (event->type) { /* Painting mbut press = Start painting (switch to painting state) */ case LEFTMOUSE: /* do initial "click" apply */ gso->is_painting = true; gso->first = true; - + gpsculpt_brush_init_stroke(gso); gpsculpt_brush_apply_event(C, op, event); break; - + /* Exit modal operator, based on the "standard" ops */ case RIGHTMOUSE: case ESCKEY: gpsculpt_brush_exit(C, op); return OPERATOR_FINISHED; - + /* MMB is often used for view manipulations */ case MIDDLEMOUSE: return OPERATOR_PASS_THROUGH; - + /* Mouse movements should update the brush cursor - Just redraw the active region */ case MOUSEMOVE: case INBETWEEN_MOUSEMOVE: redraw_region = true; break; - + /* Adjust brush settings */ /* FIXME: Step increments and modifier keys are hardcoded here! */ case WHEELUPMOUSE: @@ -1790,12 +1790,12 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->brush->size += 3; CLAMP_MAX(gso->brush->size, 300); } - + redraw_region = true; redraw_toolsettings = true; break; - - case WHEELDOWNMOUSE: + + case WHEELDOWNMOUSE: case PADMINUS: if (event->shift) { /* decrease strength */ @@ -1807,41 +1807,41 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->brush->size -= 3; CLAMP_MIN(gso->brush->size, 1); } - + redraw_region = true; redraw_toolsettings = true; break; - + /* Change Frame - Allowed */ case LEFTARROWKEY: case RIGHTARROWKEY: case UPARROWKEY: case DOWNARROWKEY: return OPERATOR_PASS_THROUGH; - + /* Camera/View Manipulations - Allowed */ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: return OPERATOR_PASS_THROUGH; - + /* Unhandled event */ default: break; } } - + /* Redraw region? */ if (redraw_region) { ARegion *ar = CTX_wm_region(C); ED_region_tag_redraw(ar); } - + /* Redraw toolsettings (brush settings)? */ if (redraw_toolsettings) { WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); } - + return OPERATOR_RUNNING_MODAL; } @@ -1854,7 +1854,7 @@ void GPENCIL_OT_brush_paint(wmOperatorType *ot) ot->name = "Stroke Sculpt"; ot->idname = "GPENCIL_OT_brush_paint"; ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX - + /* api callbacks */ ot->exec = gpsculpt_brush_exec; ot->invoke = gpsculpt_brush_invoke; @@ -1869,7 +1869,7 @@ void GPENCIL_OT_brush_paint(wmOperatorType *ot) PropertyRNA *prop; prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index e503b35d878..72331d9e588 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -179,7 +179,7 @@ static void gp_strokepoint_convertcoords( else { const float *fp = ED_view3d_cursor3d_get(scene, v3d)->location; float mvalf[2]; - + /* get screen coordinate */ if (gps->flag & GP_STROKE_2DSPACE) { View2D *v2d = &ar->v2d; @@ -195,7 +195,7 @@ static void gp_strokepoint_convertcoords( mvalf[1] = (float)pt->y / 100.0f * ar->winy; } } - + ED_view3d_win_to_3d(v3d, ar, fp, mvalf, p3d); } } @@ -211,19 +211,19 @@ typedef struct tGpTimingData { bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */ float gap_duration, gap_randomness; /* To be used with CustomGap mode*/ int seed; - + /* Data set from points, used to compute final timing FCurve */ int num_points, cur_point; - + /* Distances */ float *dists; float tot_dist; - + /* Times */ float *times; /* Note: Gap times will be negative! */ float tot_time, gap_tot_time; double inittime; - + /* Only used during creation of dists & times lists. */ float offset_time; } tGpTimingData; @@ -234,9 +234,9 @@ typedef struct tGpTimingData { static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) { float *tmp; - + BLI_assert(nbr > gtd->num_points); - + /* distances */ tmp = gtd->dists; gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__); @@ -244,7 +244,7 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points); MEM_freeN(tmp); } - + /* times */ tmp = gtd->times; gtd->times = MEM_callocN(sizeof(float) * nbr, __func__); @@ -252,7 +252,7 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr) memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points); MEM_freeN(tmp); } - + gtd->num_points = nbr; } @@ -262,7 +262,7 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini { float delta_time = 0.0f; const int cur_point = gtd->cur_point; - + if (!cur_point) { /* Special case, first point, if time is not 0.0f we have to compensate! */ gtd->offset_time = -time; @@ -272,18 +272,18 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini /* This is a gap, negative value! */ gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time); delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1]; - + gtd->gap_tot_time += delta_time; } else { gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time); delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]); } - + gtd->tot_time += delta_time; gtd->tot_dist += delta_dist; gtd->dists[cur_point] = gtd->tot_dist; - + gtd->cur_point++; } @@ -298,7 +298,7 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx float *next_delta_time) { int j; - + for (j = idx + 1; j < gtd->num_points; j++) { if (gtd->times[j] < 0) { gtd->times[j] = -gtd->times[j]; @@ -317,16 +317,16 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx } else { float delta, min, max; - + /* This code ensures that if the first gaps have been shorter than average gap_duration, * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa! */ delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps)); - + /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */ min = -gtd->gap_randomness - delta; CLAMP(min, -gtd->gap_randomness, 0.0f); - + /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */ max = gtd->gap_randomness - delta; CLAMP(max, 0.0f, gtd->gap_randomness); @@ -341,7 +341,7 @@ static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx break; } } - + return j - 1; } @@ -349,7 +349,7 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn { int i; float delta_time = 0.0f; - + for (i = 0; i < gtd->num_points; i++) { if (gtd->times[i] < 0 && i) { (*nbr_gaps)++; @@ -362,7 +362,7 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn } } gtd->tot_time -= delta_time; - + *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration; gtd->tot_time += *tot_gaps_time; if (G.debug & G_DEBUG) { @@ -379,18 +379,18 @@ static void gp_stroke_path_animation_add_keyframes(Depsgraph *depsgraph, ReportL { /* Use actual recorded timing! */ const float time_start = (float)gtd->start_frame; - + float last_valid_time = 0.0f; int end_stroke_idx = -1, start_stroke_idx = 0; float end_stroke_time = 0.0f; - + /* CustomGaps specific */ float delta_time = 0.0f, next_delta_time = 0.0f; int nbr_done_gaps = 0; - + int i; float cfra; - + /* This is a bit tricky, as: * - We can't add arbitrarily close points on FCurve (in time). * - We *must* have all "caps" points of all strokes in FCurve, as much as possible! @@ -406,11 +406,11 @@ static void gp_stroke_path_animation_add_keyframes(Depsgraph *depsgraph, ReportL /* This one should *never* be negative! */ end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range); } - + /* Simple proportional stuff... */ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen; cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range); - + /* And now, the checks about timing... */ if (i == start_stroke_idx) { /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and @@ -462,43 +462,43 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu PointerRNA ptr; PropertyRNA *prop = NULL; int nbr_gaps = 0, i; - + if (gtd->mode == GP_STROKECONVERT_TIMING_NONE) return; - + /* gap_duration and gap_randomness are in frames, but we need seconds!!! */ gtd->gap_duration = FRA2TIME(gtd->gap_duration); gtd->gap_randomness = FRA2TIME(gtd->gap_randomness); - + /* Enable path! */ cu->flag |= CU_PATH; cu->pathlen = gtd->frame_range; - + /* Get RNA pointer to read/write path time values */ RNA_id_pointer_create((ID *)cu, &ptr); prop = RNA_struct_find_property(&ptr, "eval_time"); - + /* Ensure we have an F-Curve to add keyframes to */ act = verify_adt_action((ID *)cu, true); fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true); - + if (G.debug & G_DEBUG) { printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); for (i = 0; i < gtd->num_points; i++) { printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); } } - + if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) { float cfra; - + /* Linear extrapolation! */ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; - + cu->ctime = 0.0f; cfra = (float)gtd->start_frame; insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); - + cu->ctime = cu->pathlen; if (gtd->realtime) { cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ @@ -512,35 +512,35 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu /* Use actual recorded timing! */ RNG *rng = BLI_rng_new(0); float time_range; - + /* CustomGaps specific */ float tot_gaps_time = 0.0f; - + /* Pre-process gaps, in case we don't want to keep their original timing */ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time); } - + if (gtd->realtime) { time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ } else { time_range = (float)(gtd->end_frame - gtd->start_frame); } - + if (G.debug & G_DEBUG) { printf("GP Stroke Path Conversion: Starting keying!\n"); } - + gp_stroke_path_animation_add_keyframes(depsgraph, reports, ptr, prop, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time); - + BLI_rng_free(rng); } - + /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */ calchandles_fcurve(fcu); - + if (G.debug & G_DEBUG) { printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); for (i = 0; i < gtd->num_points; i++) { @@ -548,9 +548,9 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu } printf("\n\n"); } - + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - + /* send updates */ DEG_id_tag_update(&cu->id, 0); } @@ -570,7 +570,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl { copy_v3_v3(bp->vec, p); bp->vec[3] = 1.0f; - + /* set settings */ bp->f1 = SELECT; bp->radius = width * rad_fac; @@ -582,7 +582,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl else if (bp->weight > minmax_weights[1]) { minmax_weights[1] = bp->weight; } - + /* Update timing data */ if (do_gtd) { gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); @@ -599,7 +599,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0); int i, old_nbp = 0; - + /* create new 'nurb' or extend current one within the curve */ if (nu) { old_nbp = nu->pntsu; @@ -611,7 +611,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv } else { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)"); - + nu->pntsu = gps->totpoints + add_start_end_points; nu->pntsv = 1; nu->orderu = 2; /* point-to-point! */ @@ -620,16 +620,16 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->knotsu = NULL; - + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints"); - + stitch = false; /* Security! */ } - + if (do_gtd) { gp_timing_data_set_nbr(gtd, nu->pntsu); } - + /* If needed, make the link between both strokes with two zero-radius additional points */ /* About "zero-radius" point interpolations: * - If we have at least two points in current curve (most common case), we linearly extrapolate @@ -642,16 +642,16 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv if (curnu && !stitch && old_nbp) { float p1[3], p2[3], p[3], next_p[3]; float dt1 = 0.0f, dt2 = 0.0f; - + BLI_assert(gps->prev != NULL); - + prev_bp = NULL; if ((old_nbp > 1) && (gps->prev->totpoints > 1)) { /* Only use last curve segment if previous stroke was not a single-point one! */ prev_bp = &nu->bp[old_nbp - 2]; } bp = &nu->bp[old_nbp - 1]; - + /* First point */ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); if (prev_bp) { @@ -670,7 +670,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv bp++; gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1, 0.0f, rad_fac, minmax_weights); - + /* Second point */ /* Note dt2 is always negative, which marks the gap. */ if (gps->totpoints > 1) { @@ -688,13 +688,13 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv } bp++; gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights); - + old_nbp += 2; } else if (add_start_point) { float p[3], next_p[3]; float dt = 0.0f; - + gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); if (gps->totpoints > 1) { gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); @@ -712,14 +712,14 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv * would not work (it would be *before* gtd->inittime, which is not supported currently). */ gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); - + old_nbp++; } - + if (old_nbp) { prev_bp = &nu->bp[old_nbp - 1]; } - + /* add points */ for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp]; i < gps->totpoints; @@ -727,20 +727,20 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv { float p[3]; float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC; - + /* get coordinates to add at */ gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect); - + gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights); - + prev_bp = bp; } if (add_end_point) { float p[3]; float dt = 0.0f; - + if (gps->totpoints > 1) { interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC); if (do_gtd) { @@ -756,7 +756,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv /* Note bp has already been incremented in main loop above, so it points to the right place. */ gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); } - + /* add nurb to curve */ if (!curnu || !*curnu) { BLI_addtail(&cu->nurb, nu); @@ -764,7 +764,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv if (curnu) { *curnu = nu; } - + BKE_nurb_knot_calc_u(nu); } @@ -779,7 +779,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p); copy_v3_v3(bezt->vec[2], h2); - + /* set settings */ bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; @@ -792,7 +792,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, else if (bezt->weight > minmax_weights[1]) { minmax_weights[1] = bezt->weight; } - + /* Update timing data */ if (do_gtd) { gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p)); @@ -810,7 +810,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0); float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3]; const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); - + /* create new 'nurb' or extend current one within the curve */ if (nu) { old_nbezt = nu->pntsu; @@ -822,22 +822,22 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu } else { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); - + nu->pntsu = gps->totpoints + add_start_end_points; nu->resolu = 12; nu->resolv = 12; nu->type = CU_BEZIER; nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts"); - + stitch = false; /* Security! */ } - + if (do_gtd) { gp_timing_data_set_nbr(gtd, nu->pntsu); } - + tot = gps->totpoints; - + /* get initial coordinates */ pt = gps->points; if (tot) { @@ -849,11 +849,11 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); } } - + /* If needed, make the link between both strokes with two zero-radius additional points */ if (curnu && old_nbezt) { BLI_assert(gps->prev != NULL); - + /* Update last point's second handle */ if (stitch) { bezt = &nu->bezt[old_nbezt - 1]; @@ -861,7 +861,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu copy_v3_v3(bezt->vec[2], h2); pt++; } - + /* Create "link points" */ /* About "zero-radius" point interpolations: * - If we have at least two points in current curve (most common case), we linearly extrapolate @@ -874,14 +874,14 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu else { float p1[3], p2[3]; float dt1 = 0.0f, dt2 = 0.0f; - + prev_bezt = NULL; if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) { /* Only use last curve segment if previous stroke was not a single-point one! */ prev_bezt = &nu->bezt[old_nbezt - 2]; } bezt = &nu->bezt[old_nbezt - 1]; - + /* First point */ if (prev_bezt) { interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC); @@ -896,7 +896,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC); } } - + /* Second point */ /* Note dt2 is always negative, which marks the gap. */ if (tot > 1) { @@ -911,25 +911,25 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC); } } - + /* Second handle of last point of previous stroke. */ interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC); copy_v3_v3(bezt->vec[2], h2); - + /* First point */ interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC); bezt++; gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1, 0.0f, rad_fac, minmax_weights); - + /* Second point */ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC); bezt++; gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights); - + old_nbezt += 2; copy_v3_v3(p3d_prev, p2); } @@ -937,7 +937,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu else if (add_start_point) { float p[3]; float dt = 0.0f; - + if (gps->totpoints > 1) { interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC); if (do_gtd) { @@ -954,51 +954,51 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu bezt = &nu->bezt[old_nbezt]; gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); - + old_nbezt++; copy_v3_v3(p3d_prev, p); } - + if (old_nbezt) { prev_bezt = &nu->bezt[old_nbezt - 1]; } - + /* add points */ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) { float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC; - + if (i || old_nbezt) { interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC); } - + if (i < tot - 1) { interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC); } - + gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur, do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights); - + /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); - + if (i + 2 < tot) { gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); } - + prev_bezt = bezt; } if (add_end_point) { float p[3]; float dt = 0.0f; - + if (gps->totpoints > 1) { interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC); if (do_gtd) { @@ -1011,11 +1011,11 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu p[0] += GAP_DFAC; /* Rather arbitrary... */ dt = GAP_DFAC; /* Rather arbitrary too! */ } - + /* Second handle of last point of this stroke. */ interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC); copy_v3_v3(prev_bezt->vec[2], h2); - + /* The end point */ interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC); @@ -1023,10 +1023,10 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); } - + /* must calculate handles or else we crash */ BKE_nurb_handles_calc(nu); - + if (!curnu || !*curnu) { BLI_addtail(&cu->nurb, nu); } @@ -1056,7 +1056,7 @@ static void gp_stroke_finalize_curve_endpoints(Curve *cu) bp[i].weight = bp[i].radius = 0.0f; } } - + /* end */ nu = cu->nurb.last; i = nu->pntsu - 1; @@ -1080,13 +1080,13 @@ static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2 const float delta = minmax_weights[0]; float fac; int i; - + /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */ if (IS_EQF(delta, minmax_weights[1])) fac = 1.0f; else fac = 1.0f / (minmax_weights[1] - delta); - + for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->bezt) { BezTriple *bezt = nu->bezt; @@ -1107,10 +1107,10 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) { View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - + if (v3d) { RegionView3D *rv3d = ar->regiondata; - + /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { Scene *scene = CTX_data_scene(C); @@ -1119,7 +1119,7 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) return 1; } } - + return 0; } @@ -1138,23 +1138,23 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG Nurb *nu = NULL; Base *base_new = NULL; float minmax_weights[2] = {1.0f, 0.0f}; - + /* camera framing */ rctf subrect, *subrect_ptr = NULL; - + /* error checking */ if (ELEM(NULL, gpd, gpl, gpf)) return; - + /* only convert if there are any strokes on this layer's frame to convert */ if (BLI_listbase_is_empty(&gpf->strokes)) return; - + /* initialize camera framing */ if (gp_camera_view_subrect(C, &subrect)) { subrect_ptr = &subrect; } - + /* init the curve object (remove rotation and get curve data from it) * - must clear transforms set on object, as those skew our results */ @@ -1162,32 +1162,32 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE); BKE_collection_object_add(bmain, collection, ob); base_new = BKE_view_layer_base_find(view_layer, ob); - + cu->flag |= CU_3D; - + gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime; - + /* add points to curve */ for (gps = gpf->strokes.first; gps; gps = gps->next) { const bool add_start_point = (link_strokes && !(prev_gps)); const bool add_end_point = (link_strokes && !(gps->next)); - + /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */ bool stitch = false; if (prev_gps) { bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1]; bGPDspoint *pt2 = &gps->points[0]; - + if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) { stitch = true; } } - + /* Decide whether we connect this stroke to previous one */ if (!(stitch || link_strokes)) { nu = NULL; } - + switch (mode) { case GP_STROKECONVERT_PATH: gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, @@ -1204,26 +1204,26 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG } prev_gps = gps; } - + /* If link_strokes, be sure first and last points have a zero weight/size! */ if (link_strokes) { gp_stroke_finalize_curve_endpoints(cu); } - + /* Update curve's weights, if needed */ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) { gp_stroke_norm_curve_weights(cu, minmax_weights); } - + /* Create the path animation, if needed */ gp_stroke_path_animation(C, reports, cu, gtd); - + if (mode == GP_STROKECONVERT_POLY) { for (nu = cu->nurb.first; nu; nu = nu->next) { BKE_nurb_type_convert(nu, CU_POLY, false); } } - + /* set the layer and select */ base_new->flag |= SELECT; BKE_scene_object_base_flag_sync_from_base(base_new); @@ -1243,17 +1243,17 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe double base_time, cur_time, prev_time = -1.0; int i; bool valid = true; - + if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first)) return false; - + do { base_time = cur_time = gps->inittime; if (cur_time <= prev_time) { valid = false; break; } - + prev_time = cur_time; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { cur_time = base_time + (double)pt->time; @@ -1266,12 +1266,12 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe } prev_time = cur_time; } - + if (!valid) { break; } } while ((gps = gps->next)); - + if (op) { RNA_boolean_set(op->ptr, "use_timing_data", valid); } @@ -1283,7 +1283,7 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN { int start_frame = RNA_int_get(ptr, "start_frame"); int end_frame = RNA_int_get(ptr, "end_frame"); - + if (end_frame <= start_frame) { RNA_int_set(ptr, "end_frame", start_frame + 1); } @@ -1297,7 +1297,7 @@ static int gp_convert_poll(bContext *C) ScrArea *sa = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - + /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!), * and if we are not in edit mode! */ @@ -1320,19 +1320,19 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes"); bool valid_timing; tGpTimingData gtd; - + /* check if there's data to work with */ if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on"); return OPERATOR_CANCELLED; } - + if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) { BKE_report(op->reports, RPT_WARNING, "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!"); } valid_timing = RNA_property_boolean_get(op->ptr, prop); - + gtd.mode = RNA_enum_get(op->ptr, "timing_mode"); /* Check for illegal timing mode! */ if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) { @@ -1342,7 +1342,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) if (!link_strokes) { gtd.mode = GP_STROKECONVERT_TIMING_NONE; } - + /* grab all relevant settings */ gtd.frame_range = RNA_int_get(op->ptr, "frame_range"); gtd.start_frame = RNA_int_get(op->ptr, "start_frame"); @@ -1357,10 +1357,10 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f; gtd.inittime = 0.0; gtd.offset_time = 0.0f; - + /* perform conversion */ gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, >d); - + /* free temp memory */ if (gtd.dists) { MEM_freeN(gtd.dists); @@ -1370,11 +1370,11 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) MEM_freeN(gtd.times); gtd.times = NULL; } - + /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - + /* done */ return OPERATOR_FINISHED; } @@ -1388,7 +1388,7 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) float gap_duration = RNA_float_get(ptr, "gap_duration"); float gap_randomness = RNA_float_get(ptr, "gap_randomness"); const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data"); - + /* Always show those props */ if (STREQ(prop_id, "type") || STREQ(prop_id, "use_normalize_weights") || @@ -1397,16 +1397,16 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { return true; } - + /* Never show this prop */ if (STREQ(prop_id, "use_timing_data")) return false; - + if (link_strokes) { /* Only show when link_stroke is true */ if (STREQ(prop_id, "timing_mode")) return true; - + if (timing_mode != GP_STROKECONVERT_TIMING_NONE) { /* Only show when link_stroke is true and stroke timing is enabled */ if (STREQ(prop_id, "frame_range") || @@ -1414,31 +1414,31 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { return true; } - + /* Only show if we have valid timing data! */ if (valid_timing && STREQ(prop_id, "use_realtime")) return true; - + /* Only show if realtime or valid_timing is false! */ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame")) return true; - + if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { /* Only show for custom gaps! */ if (STREQ(prop_id, "gap_duration")) return true; - + /* Only show randomness for non-null custom gaps! */ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f)) return true; - + /* Only show seed for randomize action! */ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f)) return true; } } } - + /* Else, hidden! */ return false; } @@ -1448,9 +1448,9 @@ static void gp_convert_ui(bContext *C, wmOperator *op) uiLayout *layout = op->layout; wmWindowManager *wm = CTX_wm_manager(C); PointerRNA ptr; - + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - + /* Main auto-draw call */ uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, UI_BUT_LABEL_ALIGN_NONE, false); } @@ -1458,35 +1458,35 @@ static void gp_convert_ui(bContext *C, wmOperator *op) void GPENCIL_OT_convert(wmOperatorType *ot) { PropertyRNA *prop; - + /* identifiers */ ot->name = "Convert Grease Pencil"; ot->idname = "GPENCIL_OT_convert"; ot->description = "Convert the active Grease Pencil layer to a new Curve Object"; - + /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gp_convert_layer_exec; ot->poll = gp_convert_poll; ot->ui = gp_convert_ui; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to"); - + RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight", "Normalize weight (set from stroke width)"); RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac", "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f); RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes", "Whether to link strokes with zero-radius sections of curves"); - + prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL, "Timing Mode", "How to use timing data stored in strokes"); RNA_def_enum_funcs(prop, rna_GPConvert_mode_items); - + RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range", "The duration of evaluation of the path control curve", 1, 1000); RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame", @@ -1496,7 +1496,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot) prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame", "The end frame of the path control curve (if Realtime is not set)", 1, 100000); RNA_def_property_update_runtime(prop, gp_convert_set_end_frame); - + RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration", "Custom Gap mode: (Average) length of gaps, in frames " "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f); @@ -1504,7 +1504,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot) "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f); RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed", "Custom Gap mode: Random generator seed", 0, 100); - + /* Note: Internal use, this one will always be hidden by UI code... */ prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing", "Whether the converted Grease Pencil layer has valid timing data (internal use)"); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 9d183222c2d..2e8e48b2f15 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -93,7 +93,7 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) else { /* decrement user count and add new datablock */ bGPdata *gpd = (*gpd_ptr); - + id_us_min(&gpd->id); *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); @@ -106,10 +106,10 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -120,7 +120,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot) ot->idname = "GPENCIL_OT_data_add"; ot->description = "Add new Grease Pencil data-block"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_data_add_exec; ot->poll = gp_add_poll; @@ -132,7 +132,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot) static int gp_data_unlink_poll(bContext *C) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + /* if we have access to some active data, make sure there's a datablock before enabling this */ return (gpd_ptr && *gpd_ptr); } @@ -142,7 +142,7 @@ static int gp_data_unlink_poll(bContext *C) static int gp_data_unlink_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); return OPERATOR_CANCELLED; @@ -154,10 +154,10 @@ static int gp_data_unlink_exec(bContext *C, wmOperator *op) id_us_min(&gpd->id); *gpd_ptr = NULL; } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -168,7 +168,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) ot->idname = "GPENCIL_OT_data_unlink"; ot->description = "Unlink active Grease Pencil data-block"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_data_unlink_exec; ot->poll = gp_data_unlink_poll; @@ -193,7 +193,7 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) } if (*gpd_ptr == NULL) *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); - + /* if not exist brushes, create a new set */ if (ts) { if (BLI_listbase_is_empty(&ts->gp_brushes)) { @@ -204,10 +204,10 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) /* add new layer now */ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -217,9 +217,9 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot) ot->name = "Add New Layer"; ot->idname = "GPENCIL_OT_layer_add"; ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block"; - + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_layer_add_exec; ot->poll = gp_add_poll; @@ -231,16 +231,16 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - + /* sanity checks */ if (ELEM(NULL, gpd, gpl)) return OPERATOR_CANCELLED; - + if (gpl->flag & GP_LAYER_LOCKED) { BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers"); return OPERATOR_CANCELLED; } - + /* make the layer before this the new active layer * - use the one after if this is the first * - if this is the only layer, this naturally becomes NULL @@ -249,13 +249,13 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op) BKE_gpencil_layer_setactive(gpd, gpl->prev); else BKE_gpencil_layer_setactive(gpd, gpl->next); - + /* delete the layer now... */ BKE_gpencil_layer_delete(gpd, gpl); - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -265,9 +265,9 @@ void GPENCIL_OT_layer_remove(wmOperatorType *ot) ot->name = "Remove Layer"; ot->idname = "GPENCIL_OT_layer_remove"; ot->description = "Remove active Grease Pencil layer"; - + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_layer_remove_exec; ot->poll = gp_active_layer_poll; @@ -284,18 +284,18 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - + int direction = RNA_enum_get(op->ptr, "type"); - + /* sanity checks */ if (ELEM(NULL, gpd, gpl)) return OPERATOR_CANCELLED; - + BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */ if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) { WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } - + return OPERATOR_FINISHED; } @@ -306,19 +306,19 @@ void GPENCIL_OT_layer_move(wmOperatorType *ot) {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Move Grease Pencil Layer"; ot->idname = "GPENCIL_OT_layer_move"; ot->description = "Move the active Grease Pencil layer up/down in the list"; - + /* api callbacks */ ot->exec = gp_layer_move_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", ""); } @@ -329,22 +329,22 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); bGPDlayer *new_layer; - + /* sanity checks */ if (ELEM(NULL, gpd, gpl)) return OPERATOR_CANCELLED; - + /* make copy of layer, and add it immediately after the existing layer */ new_layer = BKE_gpencil_layer_duplicate(gpl); BLI_insertlinkafter(&gpd->layers, gpl, new_layer); - + /* ensure new layer has a unique name, and is now the active layer */ BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info)); BKE_gpencil_layer_setactive(gpd, new_layer); - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -354,11 +354,11 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot) ot->name = "Duplicate Layer"; ot->idname = "GPENCIL_OT_layer_duplicate"; ot->description = "Make a copy of the active Grease Pencil layer"; - + /* callbacks */ ot->exec = gp_layer_copy_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -370,14 +370,14 @@ static int gp_hide_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd); bool unselected = RNA_boolean_get(op->ptr, "unselected"); - + /* sanity checks */ if (ELEM(NULL, gpd, layer)) return OPERATOR_CANCELLED; - + if (unselected) { bGPDlayer *gpl; - + /* hide unselected */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { if (gpl != layer) { @@ -389,10 +389,10 @@ static int gp_hide_exec(bContext *C, wmOperator *op) /* hide selected/active */ layer->flag |= GP_LAYER_HIDE; } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -402,14 +402,14 @@ void GPENCIL_OT_hide(wmOperatorType *ot) ot->name = "Hide Layer(s)"; ot->idname = "GPENCIL_OT_hide"; ot->description = "Hide selected/unselected Grease Pencil layers"; - + /* callbacks */ ot->exec = gp_hide_exec; ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */ - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers"); } @@ -452,7 +452,7 @@ static int gp_reveal_exec(bContext *C, wmOperator *op) /* sanity checks */ if (gpd == NULL) return OPERATOR_CANCELLED; - + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { if (gpl->flag & GP_LAYER_HIDE) { @@ -476,10 +476,10 @@ static int gp_reveal_exec(bContext *C, wmOperator *op) } } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -489,11 +489,11 @@ void GPENCIL_OT_reveal(wmOperatorType *ot) ot->name = "Show All Layers"; ot->idname = "GPENCIL_OT_reveal"; ot->description = "Show all Grease Pencil layers"; - + /* callbacks */ ot->exec = gp_reveal_exec; ot->poll = gp_reveal_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -507,19 +507,19 @@ static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl; - + /* sanity checks */ if (gpd == NULL) return OPERATOR_CANCELLED; - + /* make all layers non-editable */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { gpl->flag |= GP_LAYER_LOCKED; } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -529,11 +529,11 @@ void GPENCIL_OT_lock_all(wmOperatorType *ot) ot->name = "Lock All Layers"; ot->idname = "GPENCIL_OT_lock_all"; ot->description = "Lock all Grease Pencil layers to prevent them from being accidentally modified"; - + /* callbacks */ ot->exec = gp_lock_all_exec; ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */ - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -544,19 +544,19 @@ static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl; - + /* sanity checks */ if (gpd == NULL) return OPERATOR_CANCELLED; - + /* make all layers editable again */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { gpl->flag &= ~GP_LAYER_LOCKED; } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -566,11 +566,11 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot) ot->name = "Unlock All Layers"; ot->idname = "GPENCIL_OT_unlock_all"; ot->description = "Unlock all Grease Pencil layers so that they can be edited"; - + /* callbacks */ ot->exec = gp_unlock_all_exec; ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */ - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -584,21 +584,21 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) bGPDlayer *gpl; int flags = GP_LAYER_LOCKED; bool isolate = false; - + if (RNA_boolean_get(op->ptr, "affect_visibility")) flags |= GP_LAYER_HIDE; - + if (ELEM(NULL, gpd, layer)) { BKE_report(op->reports, RPT_ERROR, "No active layer to isolate"); return OPERATOR_CANCELLED; } - + /* Test whether to isolate or clear all flags */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* Skip if this is the active layer */ if (gpl == layer) continue; - + /* If the flags aren't set, that means that the layer is * not alone, so we have some layers to isolate still */ @@ -607,7 +607,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) break; } } - + /* Set/Clear flags as appropriate */ /* TODO: Include onionskinning on this list? */ if (isolate) { @@ -625,10 +625,10 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) gpl->flag &= ~flags; } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -638,14 +638,14 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot) ot->name = "Isolate Layer"; ot->idname = "GPENCIL_OT_layer_isolate"; ot->description = "Toggle whether the active layer is the only one that can be edited and/or visible"; - + /* callbacks */ ot->exec = gp_isolate_layer_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling the editability, also affect the visibility"); @@ -712,13 +712,13 @@ static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UN { uiPopupMenu *pup; uiLayout *layout; - + /* call the menu, which will call this operator again, hence the canceled */ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); layout = UI_popup_menu_layout(pup); uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer"); UI_popup_menu_end(C, pup); - + return OPERATOR_INTERFACE; } @@ -727,7 +727,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op) bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = NULL; int layer_num = RNA_enum_get(op->ptr, "layer"); - + /* Get layer or create new one */ if (layer_num == -1) { /* Create layer */ @@ -736,19 +736,19 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op) else { /* Try to get layer */ gpl = BLI_findlink(&gpd->layers, layer_num); - + if (gpl == NULL) { BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num); return OPERATOR_CANCELLED; } } - + /* Set active layer */ BKE_gpencil_layer_setactive(gpd, gpl); - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -758,15 +758,15 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot) ot->name = "Change Layer"; ot->idname = "GPENCIL_OT_layer_change"; ot->description = "Change active Grease Pencil layer"; - + /* callbacks */ ot->invoke = gp_layer_change_invoke; ot->exec = gp_layer_change_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* gp layer to use (dynamic enum) */ ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", ""); RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index cf9cbbe3765..9f01c1d0cd7 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -93,10 +93,10 @@ static int gpencil_editmode_toggle_poll(bContext *C) static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + if (gpd == NULL) return OPERATOR_CANCELLED; - + /* Just toggle editmode flag... */ gpd->flag ^= GP_DATA_STROKE_EDITMODE; /* recalculate parent matrix */ @@ -107,7 +107,7 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); - + return OPERATOR_FINISHED; } @@ -117,11 +117,11 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot) ot->name = "Strokes Edit Mode Toggle"; ot->idname = "GPENCIL_OT_editmode_toggle"; ot->description = "Enter/Exit edit mode for Grease Pencil strokes"; - + /* callbacks */ ot->exec = gpencil_editmode_toggle_exec; ot->poll = gpencil_editmode_toggle_poll; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; } @@ -182,10 +182,10 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co { bGPDspoint *pt; int i; - + int start_idx = -1; - - + + /* Step through the original stroke's points: * - We accumulate selected points (from start_idx to current index) * and then convert that to a new stroke @@ -200,7 +200,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co } else { size_t len = 0; - + /* is this the end of current island yet? * 1) Point i-1 was the last one that was selected * 2) Point i is the last in the array @@ -212,29 +212,29 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co len = i - start_idx + 1; } //printf("copying from %d to %d = %d\n", start_idx, i, len); - + /* make copies of the relevant data */ if (len) { bGPDstroke *gpsd; - + /* make a stupid copy first of the entire stroke (to get the flags too) */ gpsd = MEM_dupallocN(gps); BLI_strncpy(gpsd->tmp_layerinfo, layername, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */ - + /* initialize triangle memory - will be calculated on next redraw */ gpsd->triangles = NULL; gpsd->flag |= GP_STROKE_RECALC_CACHES; gpsd->tot_triangles = 0; - + /* now, make a new points array, and copy of the relevant parts */ gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy"); memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len); gpsd->totpoints = len; - + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; BLI_addtail(new_strokes, gpsd); - + /* cleanup + reset for next */ start_idx = -1; } @@ -245,12 +245,12 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co static int gp_duplicate_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); return OPERATOR_CANCELLED; } - + /* for each visible (and editable) layer's selected strokes, * copy the strokes into a temporary buffer, then append * once all done @@ -260,22 +260,22 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) ListBase new_strokes = {NULL, NULL}; bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; - + if (gpf == NULL) continue; - + /* make copies of selected strokes, and deselect these once we're done */ for (gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - + if (gps->flag & GP_STROKE_SELECT) { if (gps->totpoints == 1) { /* Special Case: If there's just a single point in this stroke... */ bGPDstroke *gpsd; - + /* make direct copies of the stroke and its points */ gpsd = MEM_dupallocN(gps); BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); @@ -284,7 +284,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) /* triangle information - will be calculated on next redraw */ gpsd->flag |= GP_STROKE_RECALC_CACHES; gpsd->triangles = NULL; - + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; BLI_addtail(&new_strokes, gpsd); @@ -293,23 +293,23 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */ gp_duplicate_points(gps, &new_strokes, gpl->info); } - + /* deselect original stroke, or else the originals get moved too * (when using the copy + move macro) */ gps->flag &= ~GP_STROKE_SELECT; } } - + /* add all new strokes in temp buffer to the frame (preventing double-copies) */ BLI_movelisttolist(&gpf->strokes, &new_strokes); BLI_assert(new_strokes.first == NULL); } CTX_DATA_END; - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -319,11 +319,11 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot) ot->name = "Duplicate Strokes"; ot->idname = "GPENCIL_OT_duplicate"; ot->description = "Duplicate the selected Grease Pencil strokes"; - + /* callbacks */ ot->exec = gp_duplicate_exec; ot->poll = gp_stroke_edit_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -352,7 +352,7 @@ static GHash *gp_strokes_copypastebuf_colors = NULL; void ED_gpencil_strokes_copybuf_free(void) { bGPDstroke *gps, *gpsn; - + /* Free the palettes buffer * NOTE: This is done before the strokes so that the name ptrs (keys) are still safe */ @@ -360,17 +360,17 @@ void ED_gpencil_strokes_copybuf_free(void) BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN); gp_strokes_copypastebuf_colors = NULL; } - + /* Free the stroke buffer */ for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) { gpsn = gps->next; - + if (gps->points) MEM_freeN(gps->points); if (gps->triangles) MEM_freeN(gps->triangles); - + BLI_freelinkN(&gp_strokes_copypastebuf, gps); } - + gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL; } @@ -381,18 +381,18 @@ GHash *gp_copybuf_validate_colormap(bGPdata *gpd) { GHash *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors"); GHashIterator gh_iter; - + /* If there's no active palette yet (i.e. new datablock), add one */ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); if (palette == NULL) { palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true); } - + /* For each color, figure out what to map to... */ GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) { bGPDpalettecolor *palcolor; char *name = BLI_ghashIterator_getKey(&gh_iter); - + /* Look for existing color to map to */ /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */ palcolor = BKE_gpencil_palettecolor_getbyname(palette, name); @@ -400,17 +400,17 @@ GHash *gp_copybuf_validate_colormap(bGPdata *gpd) /* Doesn't Exist - Create new matching color for this palette */ /* XXX: This still doesn't fix the pasting across file boundaries problem... */ bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter); - + palcolor = MEM_dupallocN(src_color); BLI_addtail(&palette->colors, palcolor); - + BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info)); } - + /* Store this mapping (for use later when pasting) */ BLI_ghash_insert(new_colors, name, palcolor); } - + return new_colors; } @@ -420,15 +420,15 @@ GHash *gp_copybuf_validate_colormap(bGPdata *gpd) static int gp_strokes_copy_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); return OPERATOR_CANCELLED; } - + /* clear the buffer first */ ED_gpencil_strokes_copybuf_free(); - + /* for each visible (and editable) layer's selected strokes, * copy the strokes into a temporary buffer, then append * once all done @@ -437,31 +437,31 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; - + if (gpf == NULL) continue; - + /* make copies of selected strokes, and deselect these once we're done */ for (gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; - + if (gps->flag & GP_STROKE_SELECT) { if (gps->totpoints == 1) { /* Special Case: If there's just a single point in this stroke... */ bGPDstroke *gpsd; - + /* make direct copies of the stroke and its points */ gpsd = MEM_dupallocN(gps); BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */ gpsd->points = MEM_dupallocN(gps->points); - + /* triangles cache - will be recalculated on next redraw */ gpsd->flag |= GP_STROKE_RECALC_CACHES; gpsd->tot_triangles = 0; gpsd->triangles = NULL; - + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; BLI_addtail(&gp_strokes_copypastebuf, gpsd); @@ -474,26 +474,26 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) } } CTX_DATA_END; - + /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */ if (gp_strokes_copypastebuf.first) { gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors"); - + for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, gps->colorname) == false) { bGPDpalettecolor *color = MEM_dupallocN(gps->palcolor); - + BLI_ghash_insert(gp_strokes_copypastebuf_colors, gps->colorname, color); gps->palcolor = color; } } } } - + /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); // XXX? - + /* done */ return OPERATOR_FINISHED; } @@ -504,11 +504,11 @@ void GPENCIL_OT_copy(wmOperatorType *ot) ot->name = "Copy Strokes"; ot->idname = "GPENCIL_OT_copy"; ot->description = "Copy selected Grease Pencil points and strokes"; - + /* callbacks */ ot->exec = gp_strokes_copy_exec; ot->poll = gp_stroke_edit_poll; - + /* flags */ //ot->flag = OPTYPE_REGISTER; } @@ -537,10 +537,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */ bGPDframe *gpf; - + eGP_PasteMode type = RNA_enum_get(op->ptr, "type"); GHash *new_colors; - + /* check for various error conditions */ if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); @@ -562,14 +562,14 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) /* Check that some of the strokes in the buffer can be used */ bGPDstroke *gps; bool ok = false; - + for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { ok = true; break; } } - + if (ok == false) { /* XXX: this check is not 100% accurate (i.e. image editor is incompatible with normal 2D strokes), * but should be enough to give users a good idea of what's going on @@ -578,28 +578,28 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Cannot paste 2D strokes in 3D View"); else BKE_report(op->reports, RPT_ERROR, "Cannot paste 3D strokes in 2D editors"); - + return OPERATOR_CANCELLED; } } - + /* Deselect all strokes first */ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } - + gps->flag &= ~GP_STROKE_SELECT; } CTX_DATA_END; - + /* Ensure that all the necessary colors exist */ new_colors = gp_copybuf_validate_colormap(gpd); - + /* Copy over the strokes from the buffer (and adjust the colors) */ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { @@ -611,7 +611,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) gpl = CTX_data_active_gpencil_layer(C); } } - + /* Ensure we have a frame to draw into * NOTE: Since this is an op which creates strokes, * we are obliged to add a new frame if one @@ -622,33 +622,33 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) /* Create new stroke */ bGPDstroke *new_stroke = MEM_dupallocN(gps); new_stroke->tmp_layerinfo[0] = '\0'; - + new_stroke->points = MEM_dupallocN(gps->points); - + new_stroke->flag |= GP_STROKE_RECALC_CACHES; new_stroke->triangles = NULL; - + new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); - + /* Fix color references */ BLI_assert(new_stroke->colorname[0] != '\0'); new_stroke->palcolor = BLI_ghash_lookup(new_colors, new_stroke->colorname); - + BLI_assert(new_stroke->palcolor != NULL); BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname)); - + /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */ } } } - + /* free temp data */ BLI_ghash_free(new_colors, NULL, NULL); - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -659,19 +659,19 @@ void GPENCIL_OT_paste(wmOperatorType *ot) {GP_COPY_MERGE, "MERGE", 0, "Merge", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Paste Strokes"; ot->idname = "GPENCIL_OT_paste"; ot->description = "Paste previously copied strokes or copy and merge in active layer"; - + /* callbacks */ ot->exec = gp_strokes_paste_exec; ot->poll = gp_strokes_paste_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", ""); } @@ -682,13 +682,13 @@ static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *U { uiPopupMenu *pup; uiLayout *layout; - + /* call the menu, which will call this operator again, hence the canceled */ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); layout = UI_popup_menu_layout(pup); uiItemsEnumO(layout, "GPENCIL_OT_move_to_layer", "layer"); UI_popup_menu_end(C, pup); - + return OPERATOR_INTERFACE; } @@ -699,7 +699,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) bGPDlayer *target_layer = NULL; ListBase strokes = {NULL, NULL}; int layer_num = RNA_enum_get(op->ptr, "layer"); - + /* Get layer or create new one */ if (layer_num == -1) { /* Create layer */ @@ -708,13 +708,13 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) else { /* Try to get layer */ target_layer = BLI_findlink(&gpd->layers, layer_num); - + if (target_layer == NULL) { BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num); return OPERATOR_CANCELLED; } } - + /* Extract all strokes to move to this layer * NOTE: We need to do this in a two-pass system to avoid conflicts with strokes * getting repeatedly moved @@ -723,19 +723,19 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps, *gpsn; - + /* skip if no frame with strokes, or if this is the layer we're moving strokes to */ if ((gpl == target_layer) || (gpf == NULL)) continue; - + /* make copies of selected strokes, and deselect these once we're done */ for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; - + /* TODO: Don't just move entire strokes - instead, only copy the selected portions... */ if (gps->flag & GP_STROKE_SELECT) { BLI_remlink(&gpf->strokes, gps); @@ -744,19 +744,19 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) } } CTX_DATA_END; - + /* Paste them all in one go */ if (strokes.first) { Scene *scene = CTX_data_scene(C); bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, true); - + BLI_movelisttolist(&gpf->strokes, &strokes); BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL)); } - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -766,15 +766,15 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) ot->name = "Move Strokes to Layer"; ot->idname = "GPENCIL_OT_move_to_layer"; ot->description = "Move selected strokes to another layer"; // XXX: allow moving individual points too? - + /* callbacks */ ot->invoke = gp_move_to_layer_invoke; ot->exec = gp_move_to_layer_exec; ot->poll = gp_stroke_edit_poll; // XXX? - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* gp layer to use (dynamic enum) */ ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", ""); RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf); @@ -797,7 +797,7 @@ static int UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C) else { CTX_wm_operator_poll_msg_set(C, "Active region not set"); } - + return 0; } @@ -814,8 +814,8 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */ WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL); } - - /* Go through each layer, adding a frame after the active one + + /* Go through each layer, adding a frame after the active one * and/or shunting all the others out of the way */ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) @@ -832,15 +832,15 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) gpf->framenum += 1; } } - + /* 2) Now add a new frame, with nothing in it */ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); } CTX_DATA_END; - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -851,11 +851,11 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) ot->idname = "GPENCIL_OT_blank_frame_add"; ot->description = "Insert a blank frame on the current frame " "(all subsequently existing frames, if any, are shifted right by one frame)"; - + /* callbacks */ ot->exec = gp_blank_frame_add_exec; ot->poll = gp_add_poll; - + /* properties */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "all_layers", false, "All Layers", "Create blank frame in all layers, not only active"); @@ -867,7 +867,7 @@ static int gp_actframe_delete_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - + /* only if there's an active layer with an active frame */ return (gpl && gpl->actframe); } @@ -879,7 +879,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); - + /* if there's no existing Grease-Pencil data there, add some */ if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No grease pencil data"); @@ -889,13 +889,13 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No active frame to delete"); return OPERATOR_CANCELLED; } - + /* delete it... */ BKE_gpencil_layer_delframe(gpl, gpf); - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -905,9 +905,9 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->name = "Delete Active Frame"; ot->idname = "GPENCIL_OT_active_frame_delete"; ot->description = "Delete the active frame for the active Grease Pencil Layer"; - + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_actframe_delete_exec; ot->poll = gp_actframe_delete_poll; @@ -918,7 +918,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) static int gp_actframe_delete_all_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + /* 1) There must be grease pencil data * 2) Hopefully some of the layers have stuff we can use */ @@ -929,26 +929,26 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); bool success = false; - + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { /* try to get the "active" frame - but only if it actually occurs on this frame */ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); - + if (gpf == NULL) continue; - + /* delete it... */ BKE_gpencil_layer_delframe(gpl, gpf); - + /* we successfully modified something */ success = true; } CTX_DATA_END; - + /* updates */ if (success) { - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } else { @@ -963,9 +963,9 @@ void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) ot->name = "Delete All Active Frames"; ot->idname = "GPENCIL_OT_active_frames_delete_all"; ot->description = "Delete the active frame(s) of all editable Grease Pencil layers"; - + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* callbacks */ ot->exec = gp_actframe_delete_all_exec; ot->poll = gp_actframe_delete_all_poll; @@ -988,36 +988,36 @@ typedef enum eGP_DeleteMode { static int gp_delete_selected_strokes(bContext *C) { bool changed = false; - + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps, *gpsn; - + if (gpf == NULL) continue; - + /* simply delete strokes which are selected */ for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; - + /* free stroke if selected */ if (gps->flag & GP_STROKE_SELECT) { /* free stroke memory arrays, then stroke itself */ if (gps->points) MEM_freeN(gps->points); if (gps->triangles) MEM_freeN(gps->triangles); BLI_freelinkN(&gpf->strokes, gps); - + changed = true; } } } CTX_DATA_END; - + if (changed) { WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1033,34 +1033,34 @@ static int gp_delete_selected_strokes(bContext *C) static int gp_dissolve_selected_points(bContext *C) { bool changed = false; - + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps, *gpsn; - + if (gpf == NULL) continue; - + /* simply delete points from selected strokes * NOTE: we may still have to remove the stroke if it ends up having no points! */ for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ if (ED_gpencil_stroke_color_use(gpl, gps) == false) continue; - + if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; - + int tot = gps->totpoints; /* number of points in new buffer */ - + /* First Pass: Count how many points are selected (i.e. how many to remove) */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { @@ -1068,7 +1068,7 @@ static int gp_dissolve_selected_points(bContext *C) tot--; } } - + /* if no points are left, we simply delete the entire stroke */ if (tot <= 0) { /* remove the entire stroke */ @@ -1082,35 +1082,35 @@ static int gp_dissolve_selected_points(bContext *C) /* just copy all unselected into a smaller buffer */ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy"); bGPDspoint *npt = new_points; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if ((pt->flag & GP_SPOINT_SELECT) == 0) { *npt = *pt; npt++; } } - + /* free the old buffer */ MEM_freeN(gps->points); - + /* save the new buffer */ gps->points = new_points; gps->totpoints = tot; - + /* triangles cache needs to be recalculated */ gps->flag |= GP_STROKE_RECALC_CACHES; gps->tot_triangles = 0; - + /* deselect the stroke, since none of its selected points will still be selected */ gps->flag &= ~GP_STROKE_SELECT; } - + changed = true; } } } CTX_DATA_END; - + if (changed) { WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1150,10 +1150,10 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); bool in_island = false; int num_islands = 0; - + bGPDspoint *pt; int i; - + /* First Pass: Identify start/end of islands */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & tag_flags) { @@ -1163,7 +1163,7 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke else { /* unselected - start of a new island? */ int idx; - + if (in_island) { /* extend existing island */ idx = num_islands - 1; @@ -1173,37 +1173,37 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke /* start of new island */ in_island = true; num_islands++; - + idx = num_islands - 1; islands[idx].start_idx = islands[idx].end_idx = i; } } } - + /* Watch out for special case where No islands = All points selected = Delete Stroke only */ if (num_islands) { /* there are islands, so create a series of new strokes, adding them before the "next" stroke */ int idx; - + /* Create each new stroke... */ for (idx = 0; idx < num_islands; idx++) { tGPDeleteIsland *island = &islands[idx]; bGPDstroke *new_stroke = MEM_dupallocN(gps); - + /* initialize triangle memory - to be calculated on next redraw */ new_stroke->triangles = NULL; new_stroke->flag |= GP_STROKE_RECALC_CACHES; new_stroke->tot_triangles = 0; - + /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ new_stroke->totpoints = island->end_idx - island->start_idx + 1; new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment"); - + /* Copy over the relevant points */ memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints); - - - /* Each island corresponds to a new stroke. We must adjust the + + + /* Each island corresponds to a new stroke. We must adjust the * timings of these new strokes: * * Each point's timing data is a delta from stroke's inittime, so as we erase some points from @@ -1215,15 +1215,15 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke bGPDspoint *pts; float delta = gps->points[island->start_idx].time; int j; - + new_stroke->inittime += (double)delta; - + pts = new_stroke->points; for (j = 0; j < new_stroke->totpoints; j++, pts++) { pts->time -= delta; } } - + /* Add new stroke to the frame */ if (next_stroke) { BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke); @@ -1233,10 +1233,10 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke } } } - + /* free islands */ MEM_freeN(islands); - + /* Delete the old stroke */ MEM_freeN(gps->points); if (gps->triangles) { @@ -1250,40 +1250,40 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke static int gp_delete_selected_points(bContext *C) { bool changed = false; - + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { bGPDframe *gpf = gpl->actframe; bGPDstroke *gps, *gpsn; - + if (gpf == NULL) continue; - + /* simply delete strokes which are selected */ for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ if (ED_gpencil_stroke_color_use(gpl, gps) == false) continue; - - + + if (gps->flag & GP_STROKE_SELECT) { /* deselect old stroke, since it will be used as template for the new strokes */ gps->flag &= ~GP_STROKE_SELECT; - + /* delete unwanted points by splitting stroke into several smaller ones */ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT); - + changed = true; } } } CTX_DATA_END; - + if (changed) { WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1299,21 +1299,21 @@ static int gp_delete_exec(bContext *C, wmOperator *op) { eGP_DeleteMode mode = RNA_enum_get(op->ptr, "type"); int result = OPERATOR_CANCELLED; - + switch (mode) { case GP_DELETEOP_STROKES: /* selected strokes */ result = gp_delete_selected_strokes(C); break; - + case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */ result = gp_delete_selected_points(C); break; - + case GP_DELETEOP_FRAME: /* active frame */ result = gp_actframe_delete_exec(C, op); break; } - + return result; } @@ -1325,20 +1325,20 @@ void GPENCIL_OT_delete(wmOperatorType *ot) {GP_DELETEOP_FRAME, "FRAME", 0, "Frame", "Delete active frame"}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Delete"; ot->idname = "GPENCIL_OT_delete"; ot->description = "Delete selected Grease Pencil strokes, vertices, or frames"; - + /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gp_delete_exec; ot->poll = gp_stroke_edit_poll; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; - + /* props */ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data"); } @@ -1373,7 +1373,7 @@ static int gp_snap_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); ScrArea *sa = CTX_wm_area(C); - + return (gpd != NULL) && ((sa != NULL) && (sa->spacetype == SPACE_VIEW3D)); } @@ -1384,29 +1384,29 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) bGPdata *gpd = ED_gpencil_data_get_active(C); RegionView3D *rv3d = CTX_wm_region_data(C); const float gridf = rv3d->gridview; - + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; - + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); } - + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; int i; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ if (ED_gpencil_stroke_color_use(gpl, gps) == false) continue; - + // TODO: if entire stroke is selected, offset entire stroke by same amount? for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { /* only if point is selected */ @@ -1420,11 +1420,11 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) /* apply parent transformations */ float fpt[3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - + fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf); fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf); fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf); - + /* return data */ copy_v3_v3(&pt->x, fpt); gp_apply_parent_point(gpl, pt); @@ -1434,7 +1434,7 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) } } } - + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1445,11 +1445,11 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot) ot->name = "Snap Selection to Grid"; ot->idname = "GPENCIL_OT_snap_to_grid"; ot->description = "Snap selected points to the nearest grid points"; - + /* callbacks */ ot->exec = gp_snap_to_grid; ot->poll = gp_snap_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -1459,28 +1459,28 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot) static int gp_snap_to_cursor(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - + const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d)->location; - + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; - + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); } - + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; int i; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; @@ -1490,14 +1490,14 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) /* only continue if this stroke is selected (editable doesn't guarantee this)... */ if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - + if (use_offset) { float offset[3]; - + /* compute offset from first point of stroke to cursor */ /* TODO: Allow using midpoint instead? */ sub_v3_v3v3(offset, cursor_global, &gps->points->x); - + /* apply offset to all points in the stroke */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { add_v3_v3(&pt->x, offset); @@ -1515,10 +1515,10 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) } } } - + } } - + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1529,14 +1529,14 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot) ot->name = "Snap Selection to Cursor"; ot->idname = "GPENCIL_OT_snap_to_cursor"; ot->description = "Snap selected points/strokes to the cursor"; - + /* callbacks */ ot->exec = gp_snap_to_cursor; ot->poll = gp_snap_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ ot->prop = RNA_def_boolean(ot->srna, "use_offset", true, "With Offset", "Offset the entire stroke instead of selected points only"); @@ -1547,33 +1547,33 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot) static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - + float *cursor = ED_view3d_cursor3d_get(scene, v3d)->location; float centroid[3] = {0.0f}; float min[3], max[3]; size_t count = 0; - + INIT_MINMAX(min, max); - + /* calculate midpoints from selected points */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; - + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); } - + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; int i; - + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; @@ -1583,7 +1583,7 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) /* only continue if this stroke is selected (editable doesn't guarantee this)... */ if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { if (gpl->parent == NULL) { @@ -1594,18 +1594,18 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) /* apply parent transformations */ float fpt[3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - + add_v3_v3(centroid, fpt); minmax_v3v3_v3(min, max, fpt); } count++; } } - + } } } - + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN && count) { mul_v3_fl(centroid, 1.0f / (float)count); copy_v3_v3(cursor, centroid); @@ -1614,7 +1614,7 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) mid_v3_v3v3(cursor, min, max); } - + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1625,11 +1625,11 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) ot->name = "Snap Cursor to Selected Points"; ot->idname = "GPENCIL_OT_snap_cursor_to_selected"; ot->description = "Snap cursor to center of selected points"; - + /* callbacks */ ot->exec = gp_snap_cursor_to_sel; ot->poll = gp_snap_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -1685,27 +1685,27 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); const int type = RNA_enum_get(op->ptr, "type"); - + /* sanity checks */ if (ELEM(NULL, gpd)) return OPERATOR_CANCELLED; - + /* loop all selected strokes */ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { if (gpl->actframe == NULL) continue; - + for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { bGPDpalettecolor *palcolor = gps->palcolor; - + /* skip strokes that are not selected or invalid for current view */ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) continue; /* skip hidden or locked colors */ if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED)) continue; - + switch (type) { case GP_STROKE_CYCLIC_CLOSE: /* Close all (enable) */ @@ -1726,10 +1726,10 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) } } CTX_DATA_END; - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -1745,19 +1745,19 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Set Cyclical State"; ot->idname = "GPENCIL_OT_stroke_cyclical_set"; ot->description = "Close or open the selected stroke adding an edge from last to first point"; - + /* api callbacks */ ot->exec = gp_stroke_cyclical_set_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", ""); } @@ -1768,11 +1768,11 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) static void gpencil_flip_stroke(bGPDstroke *gps) { int end = gps->totpoints - 1; - + for (int i = 0; i < gps->totpoints / 2; i++) { bGPDspoint *point, *point2; bGPDspoint pt; - + /* save first point */ point = &gps->points[i]; pt.x = point->x; @@ -1782,7 +1782,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) pt.pressure = point->pressure; pt.strength = point->strength; pt.time = point->time; - + /* replace first point with last point */ point2 = &gps->points[end]; point->x = point2->x; @@ -1792,7 +1792,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) point->pressure = point2->pressure; point->strength = point2->strength; point->time = point2->time; - + /* replace last point with first saved before */ point = &gps->points[end]; point->x = pt.x; @@ -1802,7 +1802,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) point->pressure = pt.pressure; point->strength = pt.strength; point->time = pt.time; - + end--; } } @@ -1812,10 +1812,10 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float float pressure, float strength, float deltatime) { bGPDspoint *newpoint; - + gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); gps->totpoints++; - + newpoint = &gps->points[gps->totpoints - 1]; newpoint->x = point->x * delta[0]; newpoint->y = point->y * delta[1]; @@ -1834,28 +1834,28 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, co int i; float delta[3] = {1.0f, 1.0f, 1.0f}; float deltatime = 0.0f; - + /* sanity checks */ if (ELEM(NULL, gps_a, gps_b)) return; - + if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) return; - + /* define start and end points of each stroke */ float sa[3], sb[3], ea[3], eb[3]; pt = &gps_a->points[0]; copy_v3_v3(sa, &pt->x); - + pt = &gps_a->points[gps_a->totpoints - 1]; copy_v3_v3(ea, &pt->x); - + pt = &gps_b->points[0]; copy_v3_v3(sb, &pt->x); - + pt = &gps_b->points[gps_b->totpoints - 1]; copy_v3_v3(eb, &pt->x); - + /* review if need flip stroke B */ float ea_sb = len_squared_v3v3(ea, sb); float ea_eb = len_squared_v3v3(ea, eb); @@ -1863,19 +1863,19 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, co if (ea_eb < ea_sb) { gpencil_flip_stroke(gps_b); } - + /* don't visibly link the first and last points? */ if (leave_gaps) { /* 1st: add one tail point to start invisible area */ point = gps_a->points[gps_a->totpoints - 1]; deltatime = point.time; gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f); - + /* 2nd: add one head point to finish invisible area */ point = gps_b->points[0]; gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime); } - + /* 3rd: add all points */ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { /* check if still room in buffer */ @@ -1892,25 +1892,25 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) bGPDstroke *gps, *gpsn; bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - + bGPDframe *gpf_a = NULL; bGPDstroke *stroke_a = NULL; bGPDstroke *stroke_b = NULL; bGPDstroke *new_stroke = NULL; - + const int type = RNA_enum_get(op->ptr, "type"); const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps"); - + /* sanity checks */ if (ELEM(NULL, gpd)) return OPERATOR_CANCELLED; - + if (activegpl->flag & GP_LAYER_LOCKED) return OPERATOR_CANCELLED; - + BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY)); - - + + /* read all selected strokes */ bool first = false; CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) @@ -1918,7 +1918,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) bGPDframe *gpf = gpl->actframe; if (gpf == NULL) continue; - + for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; if (gps->flag & GP_STROKE_SELECT) { @@ -1930,10 +1930,10 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) if (ED_gpencil_stroke_color_use(gpl, gps) == false) { continue; } - + /* to join strokes, cyclic must be disabled */ gps->flag &= ~GP_STROKE_CYCLIC; - + /* saves first frame and stroke */ if (!first) { first = true; @@ -1942,7 +1942,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) } else { stroke_b = gps; - + /* create a new stroke if was not created before (only created if something to join) */ if (new_stroke == NULL) { new_stroke = MEM_dupallocN(stroke_a); @@ -1950,7 +1950,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) new_stroke->triangles = NULL; new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; - + /* if new, set current color */ if (type == GP_STROKE_JOINCOPY) { new_stroke->palcolor = palcolor; @@ -1958,10 +1958,10 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) new_stroke->flag |= GP_STROKE_RECALC_COLOR; } } - + /* join new_stroke and stroke B. New stroke will contain all the previous data */ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps); - + /* if join only, delete old strokes */ if (type == GP_STROKE_JOIN) { if (stroke_a) { @@ -1981,21 +1981,21 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) } } CTX_DATA_END; - + /* add new stroke if was not added before */ if (type == GP_STROKE_JOINCOPY) { if (new_stroke) { /* Add a new frame if needed */ if (activegpl->actframe == NULL) activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum); - + BLI_addtail(&activegpl->actframe->strokes, new_stroke); } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -2006,19 +2006,19 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot) {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Join Strokes"; ot->idname = "GPENCIL_OT_stroke_join"; ot->description = "Join selected strokes (optionally as new stroke)"; - + /* api callbacks */ ot->exec = gp_stroke_join_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", ""); RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them"); @@ -2040,7 +2040,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) bGPDframe *gpf = gpl->actframe; if (gpf == NULL) continue; - + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { if (gps->flag & GP_STROKE_SELECT) { /* skip strokes that are invalid for current view */ @@ -2051,17 +2051,17 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) if (ED_gpencil_stroke_color_use(gpl, gps) == false) { continue; } - + /* flip stroke */ gpencil_flip_stroke(gps); } } } CTX_DATA_END; - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -2071,11 +2071,11 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) ot->name = "Flip Stroke"; ot->idname = "GPENCIL_OT_stroke_flip"; ot->description = "Change direction of the points of the selected strokes"; - + /* api callbacks */ ot->exec = gp_stroke_flip_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -2103,19 +2103,19 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); GP_SpaceConversion gsc = {NULL}; eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type"); - + /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); - + /* init autodist for geometry projection */ if (mode == GP_REPROJECT_SURFACE) { struct Depsgraph *depsgraph = CTX_data_depsgraph(C); view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar); ED_view3d_autodist_init(depsgraph, gsc.ar, CTX_wm_view3d(C), 0); } - + // TODO: For deforming geometry workflow, create new frames? - + /* Go through each editable + selected stroke, adjusting each of its points one by one... */ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) { @@ -2123,17 +2123,17 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) bGPDspoint *pt; int i; float inverse_diff_mat[4][4]; - + /* Compute inverse matrix for unapplying parenting once instead of doing per-point */ /* TODO: add this bit to the iteration macro? */ if (gpl->parent) { invert_m4_m4(inverse_diff_mat, diff_mat); } - + /* Adjust each point */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { float xy[2]; - + /* 3D to Screenspace */ /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace * coordinates, resulting in lost precision, which in turn causes stairstepping @@ -2147,7 +2147,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) gp_point_to_parent_space(pt, diff_mat, &pt2); gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); } - + /* Project screenspace back to 3D space (from current perspective) * so that all points have been treated the same way */ @@ -2159,10 +2159,10 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) /* Geometry - Snap to surfaces of visible geometry */ /* XXX: There will be precision loss (possible stairstep artifacts) from this conversion to satisfy the API's */ const int screen_co[2] = {(int)xy[0], (int)xy[1]}; - + int depth_margin = 0; // XXX: 4 for strokes, 0 for normal float depth; - + /* XXX: The proper procedure computes the depths into an array, to have smooth transitions when all else fails... */ if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) { ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth); @@ -2172,7 +2172,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) gp_point_xy_to_3d(&gsc, scene, xy, &pt->x); } } - + /* Unapply parent corrections */ if (gpl->parent) { mul_m4_v3(inverse_diff_mat, &pt->x); @@ -2181,7 +2181,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) } } GP_EDITABLE_STROKES_END; - + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -2189,29 +2189,29 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) void GPENCIL_OT_reproject(wmOperatorType *ot) { static const EnumPropertyItem reproject_type[] = { - {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar", + {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar", "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint " "using 'Cursor' Stroke Placement"}, {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface", "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Reproject Strokes"; ot->idname = "GPENCIL_OT_reproject"; ot->description = "Reproject the selected strokes from the current viewpoint as if they had been newly drawn " "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, " "or for matching deforming geometry)"; - + /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gp_strokes_reproject_exec; ot->poll = gp_strokes_reproject_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_PLANAR, "Projection Type", ""); } diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 83e2a85db49..ff3f5b20858 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -89,18 +89,18 @@ static int gpencil_view3d_poll(bContext *C) { bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - + /* only 3D view */ ScrArea *sa = CTX_wm_area(C); if (sa && sa->spacetype != SPACE_VIEW3D) { return 0; } - + /* need data to interpolate */ if (ELEM(NULL, gpd, gpl)) { return 0; } - + return 1; } @@ -108,13 +108,13 @@ static int gpencil_view3d_poll(bContext *C) static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) { bGPDspoint *prev, *pt, *next; - + /* update points */ for (int i = 0; i < new_stroke->totpoints; i++) { prev = &gps_from->points[i]; pt = &new_stroke->points[i]; next = &gps_to->points[i]; - + /* Interpolate all values */ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor); @@ -130,32 +130,32 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) { tGPDinterpolate_layer *tgpil; const float shift = tgpi->shift; - + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { bGPDstroke *new_stroke; const float factor = tgpil->factor + shift; - + for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { bGPDstroke *gps_from, *gps_to; int stroke_idx; - + if (new_stroke->totpoints == 0) { continue; } - + /* get strokes to interpolate */ stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); - + gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx); gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx); - + /* update points position */ if ((gps_from) && (gps_to)) { gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); } } } - + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } @@ -164,7 +164,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) { ToolSettings *ts = CTX_data_tool_settings(C); eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag; - + /* get layers */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ @@ -175,12 +175,12 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } - + /* read strokes */ for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { bGPDstroke *gps_to; int fFrame; - + /* only selected */ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { continue; @@ -193,14 +193,14 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { continue; } - + /* get final stroke to interpolate */ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); if (gps_to == NULL) { continue; } - + return true; } } @@ -213,18 +213,18 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) bGPdata *gpd = tgpi->gpd; bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDframe *actframe = active_gpl->actframe; - + /* save initial factor for active layer to define shift limits */ tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1); - + /* limits are 100% below 0 and 100% over the 100% */ tgpi->low_limit = -1.0f - tgpi->init_factor; tgpi->high_limit = 2.0f - tgpi->init_factor; - + /* set layers */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { tGPDinterpolate_layer *tgpil; - + /* all layers or only active */ if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) { continue; @@ -233,32 +233,32 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } - + /* create temp data for each layer */ tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); - + tgpil->gpl = gpl; tgpil->prevFrame = gpl->actframe; tgpil->nextFrame = gpl->actframe->next; - + BLI_addtail(&tgpi->ilayers, tgpil); - + /* create a new temporary frame */ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe"); tgpil->interFrame->framenum = tgpi->cframe; - + /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); - + /* create new strokes data with interpolated points reading original stroke */ for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { bGPDstroke *gps_to; int fFrame; - + bGPDstroke *new_stroke; bool valid = true; - - + + /* only selected */ if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { valid = false; @@ -267,19 +267,19 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) if (ED_gpencil_stroke_can_use(C, gps_from) == false) { valid = false; } - + /* check if the color is editable */ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { valid = false; } - + /* get final stroke to interpolate */ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); if (gps_to == NULL) { valid = false; } - + /* create new stroke */ new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); @@ -306,7 +306,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); new_stroke->flag |= GP_STROKE_RECALC_CACHES; } - + /* add to strokes */ BLI_addtail(&tgpil->interFrame->strokes, new_stroke); } @@ -339,14 +339,14 @@ static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, co { float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f; float mpos = event->x - tgpi->ar->winrct.xmin; - + if (mpos >= mid) { tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid; } else { tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid); } - + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); } @@ -357,19 +357,19 @@ static void gpencil_interpolate_status_indicators(tGPDinterpolate *p) Scene *scene = p->scene; char status_str[UI_MAX_DRAW_STR]; char msg_str[UI_MAX_DRAW_STR]; - + BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"), UI_MAX_DRAW_STR); - + if (hasNumInput(&p->num)) { char str_offs[NUM_STR_REP_LEN]; - + outputNumInput(&p->num, str_offs, &scene->unit); BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); } else { BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f)); } - + ED_area_headerprint(p->sa, status_str); } @@ -391,7 +391,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi = op->customdata; tGPDinterpolate_layer *tgpil; - + /* don't assume that operator data exists at all */ if (tgpi) { /* remove drawing handler */ @@ -401,21 +401,21 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) if (tgpi->draw_handle_3d) { ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); } - + /* clear status message area */ ED_area_headerprint(tgpi->sa, NULL); - + /* finally, free memory used by temp data */ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { BKE_gpencil_free_strokes(tgpil->interFrame); MEM_freeN(tgpil->interFrame); } - + BLI_freelistN(&tgpi->ilayers); MEM_freeN(tgpi); } WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* clear pointer */ op->customdata = NULL; } @@ -425,24 +425,24 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte { ToolSettings *ts = CTX_data_tool_settings(C); bGPdata *gpd = CTX_data_gpencil_data(C); - + /* set current scene and window */ tgpi->scene = CTX_data_scene(C); tgpi->sa = CTX_wm_area(C); tgpi->ar = CTX_wm_region(C); tgpi->flag = ts->gp_interpolate.flag; - + /* set current frame number */ tgpi->cframe = tgpi->scene->r.cfra; - + /* set GP datablock */ tgpi->gpd = gpd; - + /* set interpolation weight */ tgpi->shift = RNA_float_get(op->ptr, "shift"); /* set layers */ gp_interpolate_set_points(C, tgpi); - + return 1; } @@ -450,10 +450,10 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); - + /* define initial values */ gp_interpolate_set_init_values(C, op, tgpi); - + /* return context data for running operator */ return tgpi; } @@ -462,7 +462,7 @@ static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *o static int gpencil_interpolate_init(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi; - + /* check context */ tgpi = op->customdata = gp_session_init_interpolation(C, op); if (tgpi == NULL) { @@ -470,7 +470,7 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op) gpencil_interpolate_exit(C, op); return 0; } - + /* everything is now setup ok */ return 1; } @@ -492,19 +492,19 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); return OPERATOR_CANCELLED; } - + /* cannot interpolate in extremes */ if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); return OPERATOR_CANCELLED; } - + /* need editable strokes */ if (!gp_interpolate_check_todo(C, gpd)) { BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes"); return OPERATOR_CANCELLED; } - + /* try to initialize context data needed */ if (!gpencil_interpolate_init(C, op)) { if (op->customdata) @@ -514,24 +514,24 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent else { tgpi = op->customdata; } - + /* Enable custom drawing handlers - * It needs 2 handlers because strokes can in 3d space and screen space - * and each handler use different coord system + * It needs 2 handlers because strokes can in 3d space and screen space + * and each handler use different coord system */ tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL); tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW); - + /* set cursor to indicate modal */ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); - + /* update shift indicator in header */ gpencil_interpolate_status_indicators(tgpi); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* add a modal handler for this operator */ WM_event_add_modal_handler(C, op); - + return OPERATOR_RUNNING_MODAL; } @@ -544,7 +544,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent bGPDstroke *gps_src, *gps_dst; tGPDinterpolate_layer *tgpil; const bool has_numinput = hasNumInput(&tgpi->num); - + switch (event->type) { case LEFTMOUSE: /* confirm */ case RETKEY: @@ -552,19 +552,19 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent /* return to normal cursor and header status */ ED_area_headerprint(tgpi->sa, NULL); WM_cursor_modal_restore(win); - + /* insert keyframes as required... */ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN; - + /* copy strokes */ BLI_listbase_clear(&gpf_dst->strokes); for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) { if (gps_src->totpoints == 0) { continue; } - + /* make copy of source stroke, then adjust pointer to points too */ gps_dst = MEM_dupallocN(gps_src); gps_dst->points = MEM_dupallocN(gps_src->points); @@ -573,34 +573,34 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent BLI_addtail(&gpf_dst->strokes, gps_dst); } } - + /* clean up temp data */ gpencil_interpolate_exit(C, op); - + /* done! */ return OPERATOR_FINISHED; } - + case ESCKEY: /* cancel */ case RIGHTMOUSE: { /* return to normal cursor and header status */ ED_area_headerprint(tgpi->sa, NULL); WM_cursor_modal_restore(win); - + /* clean up temp data */ gpencil_interpolate_exit(C, op); - + /* canceled! */ return OPERATOR_CANCELLED; } - + case WHEELUPMOUSE: { tgpi->shift = tgpi->shift + 0.01f; CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); - + /* update screen */ gpencil_interpolate_update(C, op, tgpi); break; @@ -610,7 +610,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent tgpi->shift = tgpi->shift - 0.01f; CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); - + /* update screen */ gpencil_interpolate_update(C, op, tgpi); break; @@ -621,7 +621,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent if (has_numinput == false) { /* update shift based on position of mouse */ gpencil_mouse_update_shift(tgpi, op, event); - + /* update screen */ gpencil_interpolate_update(C, op, tgpi); } @@ -632,21 +632,21 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) { const float factor = tgpi->init_factor; float value; - + /* Grab shift from numeric input, and store this new value (the user see an int) */ value = (factor + tgpi->shift) * 100.0f; applyNumInput(&tgpi->num, &value); tgpi->shift = value / 100.0f; - + /* recalculate the shift to get the right value in the frame scale */ tgpi->shift = tgpi->shift - factor; - + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); - + /* update screen */ gpencil_interpolate_update(C, op, tgpi); - + break; } else { @@ -655,7 +655,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent } } } - + /* still running... */ return OPERATOR_RUNNING_MODAL; } @@ -673,16 +673,16 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot) ot->name = "Grease Pencil Interpolation"; ot->idname = "GPENCIL_OT_interpolate"; ot->description = "Interpolate grease pencil strokes between frames"; - + /* callbacks */ ot->invoke = gpencil_interpolate_invoke; ot->modal = gpencil_interpolate_modal; ot->cancel = gpencil_interpolate_cancel; ot->poll = gpencil_view3d_poll; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - + /* properties */ RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f); } @@ -695,14 +695,14 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting const float begin = 0.0f; const float change = 1.0f; const float duration = 1.0f; - + const float back = ipo_settings->back; const float amplitude = ipo_settings->amplitude; const float period = ipo_settings->period; - + eBezTriple_Easing easing = ipo_settings->easing; float result = time; - + switch (ipo_settings->type) { case GP_IPO_BACK: switch (easing) { @@ -715,7 +715,7 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_back_ease_in_out(time, begin, change, duration, back); break; - + default: /* default/auto: same as ease out */ result = BLI_easing_back_ease_out(time, begin, change, duration, back); break; @@ -733,13 +733,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_bounce_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease out */ result = BLI_easing_bounce_ease_out(time, begin, change, duration); break; } break; - + case GP_IPO_CIRC: switch (easing) { case BEZT_IPO_EASE_IN: @@ -751,7 +751,7 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_circ_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_circ_ease_in(time, begin, change, duration); break; @@ -769,13 +769,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_cubic_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_cubic_ease_in(time, begin, change, duration); break; } break; - + case GP_IPO_ELASTIC: switch (easing) { case BEZT_IPO_EASE_IN: @@ -787,13 +787,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period); break; - + default: /* default/auto: same as ease out */ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); break; } break; - + case GP_IPO_EXPO: switch (easing) { case BEZT_IPO_EASE_IN: @@ -805,13 +805,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_expo_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_expo_ease_in(time, begin, change, duration); break; } break; - + case GP_IPO_QUAD: switch (easing) { case BEZT_IPO_EASE_IN: @@ -823,13 +823,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_quad_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_quad_ease_in(time, begin, change, duration); break; } break; - + case GP_IPO_QUART: switch (easing) { case BEZT_IPO_EASE_IN: @@ -841,13 +841,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_quart_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_quart_ease_in(time, begin, change, duration); break; } break; - + case GP_IPO_QUINT: switch (easing) { case BEZT_IPO_EASE_IN: @@ -859,13 +859,13 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_quint_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_quint_ease_in(time, begin, change, duration); break; } break; - + case GP_IPO_SINE: switch (easing) { case BEZT_IPO_EASE_IN: @@ -877,18 +877,18 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting case BEZT_IPO_EASE_IN_OUT: result = BLI_easing_sine_ease_in_out(time, begin, change, duration); break; - + default: /* default/auto: same as ease in */ result = BLI_easing_sine_ease_in(time, begin, change, duration); break; } break; - + default: printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type); break; } - + return result; } @@ -897,12 +897,12 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDframe *actframe = active_gpl->actframe; - + Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate; eGP_Interpolate_SettingsFlag flag = ipo_settings->flag; - + /* cannot interpolate if not between 2 frames */ if (ELEM(NULL, actframe, actframe->next)) { BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); @@ -913,13 +913,13 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); return OPERATOR_CANCELLED; } - + /* loop all layer to check if need interpolation */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { bGPDframe *prevFrame, *nextFrame; bGPDstroke *gps_from, *gps_to; int cframe, fFrame; - + /* all layers or only active */ if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { continue; @@ -928,19 +928,19 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } - + /* store extremes */ prevFrame = gpl->actframe; nextFrame = gpl->actframe->next; - + /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { bGPDframe *interFrame = NULL; float factor; - + /* get interpolation factor */ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); - + if (ipo_settings->type == GP_IPO_CURVEMAP) { /* custom curvemap */ if (ipo_settings->custom_ipo) { @@ -954,11 +954,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) /* easing equation... */ factor = gp_interpolate_seq_easing_calc(ipo_settings, factor); } - + /* create new strokes data with interpolated points reading original stroke */ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { bGPDstroke *new_stroke; - + /* only selected */ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { continue; @@ -971,20 +971,20 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { continue; } - + /* get final stroke to interpolate */ fFrame = BLI_findindex(&prevFrame->strokes, gps_from); gps_to = BLI_findlink(&nextFrame->strokes, fFrame); if (gps_to == NULL) { continue; } - + /* create a new frame if needed */ if (interFrame == NULL) { interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } - + /* create new stroke */ new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); @@ -999,19 +999,19 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; } - + /* update points position */ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); - + /* add to strokes */ BLI_addtail(&interFrame->strokes, new_stroke); } } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -1021,11 +1021,11 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) ot->name = "Interpolate Sequence"; ot->idname = "GPENCIL_OT_interpolate_sequence"; ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames"; - + /* api callbacks */ ot->exec = gpencil_interpolate_seq_exec; ot->poll = gpencil_view3d_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -1045,7 +1045,7 @@ static int gpencil_interpolate_reverse_poll(bContext *C) CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown"); return 0; } - + return 1; } @@ -1059,11 +1059,11 @@ static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) bGPDframe *start_key = NULL; bGPDframe *end_key = NULL; bGPDframe *gpf, *gpfn; - + /* Only continue if we're currently on a breakdown keyframe */ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) continue; - + /* Search left for "start_key" (i.e. the first breakdown to remove) */ gpf = gpl->actframe; while (gpf) { @@ -1077,7 +1077,7 @@ static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) break; } } - + /* Search right for "end_key" (i.e. the last breakdown to remove) */ gpf = gpl->actframe; while (gpf) { @@ -1091,36 +1091,36 @@ static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) break; } } - + /* Did we find anything? */ /* NOTE: We should only proceed if there's something before/after these extents... * Otherwise, there's just an extent of breakdowns with no keys to interpolate between */ - if ((start_key && end_key) && + if ((start_key && end_key) && ELEM(NULL, start_key->prev, end_key->next) == false) { /* Set actframe to the key before start_key, since the keys have been removed now */ gpl->actframe = start_key->prev; - + /* Free each frame we're removing (except the last one) */ for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) { gpfn = gpf->next; - + /* free strokes and their associated memory */ BKE_gpencil_free_strokes(gpf); BLI_freelinkN(&gpl->frames, gpf); } - + /* Now free the last one... */ BKE_gpencil_free_strokes(end_key); BLI_freelinkN(&gpl->frames, end_key); } } CTX_DATA_END; - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -1130,11 +1130,11 @@ void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot) ot->name = "Remove Breakdowns"; ot->idname = "GPENCIL_OT_interpolate_reverse"; ot->description = "Remove breakdown frames generated by interpolating between two Grease Pencil frames"; - + /* callbacks */ ot->exec = gpencil_interpolate_reverse_exec; ot->poll = gpencil_interpolate_reverse_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 2119569298d..cb6ccc8d8ef 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -57,28 +57,28 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil", 0, 0); wmKeyMapItem *kmi; - + /* Draw --------------------------------------- */ /* draw */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); RNA_boolean_set(kmi->ptr, "wait_for_input", false); - + /* draw - straight lines */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT); RNA_boolean_set(kmi->ptr, "wait_for_input", false); - + /* draw - poly lines */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY); RNA_boolean_set(kmi->ptr, "wait_for_input", false); - + /* erase */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); RNA_boolean_set(kmi->ptr, "wait_for_input", false); - + /* Tablet Mappings for Drawing ------------------ */ /* For now, only support direct drawing using the eraser, as most users using a tablet * may still want to use that as their primary pointing device! @@ -88,24 +88,24 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); RNA_boolean_set(kmi->ptr, "wait_for_input", false); #endif - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); RNA_boolean_set(kmi->ptr, "wait_for_input", false); - + /* Viewport Tools ------------------------------- */ - + /* Enter EditMode */ WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, DKEY); - + /* Pie Menu - For standard tools */ WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_tool_palette", QKEY, KM_PRESS, 0, DKEY); WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_settings_palette", WKEY, KM_PRESS, 0, DKEY); - + /* Add Blank Frame */ /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */ WM_keymap_add_item(keymap, "GPENCIL_OT_blank_frame_add", BKEY, KM_PRESS, 0, DKEY); - + /* Delete Active Frame - For easier video tutorials/review sessions */ /* NOTE: This works even when not in EditMode */ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY); @@ -125,81 +125,81 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0); wmKeyMapItem *kmi; - + /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */ keymap->poll = gp_stroke_editmode_poll; - + /* ----------------------------------------------- */ - + /* Exit EditMode */ WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); - + /* Pie Menu - For settings/tools easy access */ WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY); - + /* Brush Settings */ /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain * that the only data being edited is that of the Grease Pencil strokes */ - + /* CTRL + FKEY = Eraser Radius */ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius"); - + /* Interpolation */ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); /* Sculpting ------------------------------------- */ - + /* Brush-Based Editing: - * EKEY + LMB = Single stroke, draw immediately + * EKEY + LMB = Single stroke, draw immediately * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc. * * For the modal version, use D+E -> Sculpt */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY); RNA_boolean_set(kmi->ptr, "wait_for_input", false); - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY); RNA_boolean_set(kmi->ptr, "wait_for_input", false); /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/ - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY); RNA_boolean_set(kmi->ptr, "wait_for_input", false); /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/ - - + + /* Shift-FKEY = Sculpt Strength */ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0); RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength"); - + /* FKEY = Sculpt Brush Size */ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size"); - - + + /* Selection ------------------------------------- */ /* select all */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0); RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); RNA_enum_set(kmi->ptr, "action", SEL_INVERT); - + /* circle select */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_circle", CKEY, KM_PRESS, 0, 0); - + /* border select */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0); - + /* lasso select */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - + /* In the Node Editor, lasso select needs ALT modifier too (as somehow CTRL+LMB drag gets taken for "cut" quite early) * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey * combo doesn't seem to see much use under standard scenarios? @@ -208,57 +208,57 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - + /* normal select */ WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "toggle", true); - + /* whole stroke select */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "entire_strokes", true); - + /* select linked */ /* NOTE: While LKEY is redundant, not having it breaks the mode illusion too much */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0); - + /* select grouped */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0); - + /* select more/less */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); - + /* Editing ----------------------------------------- */ - + /* duplicate and move selected points */ WM_keymap_add_item(keymap, "GPENCIL_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); - + /* delete */ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", DELKEY, KM_PRESS, 0, 0); - + WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0); - + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0); - + /* menu edit specials */ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_edit_specials", WKEY, KM_PRESS, 0, 0); /* join strokes */ WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL, 0); - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); RNA_enum_set(kmi->ptr, "type", GP_STROKE_JOINCOPY); - + /* copy + paste */ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); - + #ifdef __APPLE__ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0); @@ -266,50 +266,50 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) /* snap */ WM_keymap_add_menu(keymap, "GPENCIL_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0); - - + + /* convert to geometry */ WM_keymap_add_item(keymap, "GPENCIL_OT_convert", CKEY, KM_PRESS, KM_ALT, 0); - - + + /* Show/Hide */ /* NOTE: These are available only in EditMode now, since they clash with general-purpose hotkeys */ WM_keymap_add_item(keymap, "GPENCIL_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0); - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "unselected", false); - + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "unselected", true); WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0); - + /* Isolate Layer */ WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0); - + /* Move to Layer */ WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0); /* Transform Tools */ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0); - + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0); - + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0); - + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0); - + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0); - + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_bend", WKEY, KM_PRESS, KM_SHIFT, 0); - + WM_keymap_add_item(keymap, "TRANSFORM_OT_tosphere", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0); - + WM_keymap_add_item(keymap, "TRANSFORM_OT_shear", SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0); - + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0); RNA_enum_set(kmi->ptr, "mode", TFM_GPENCIL_SHRINKFATTEN); - + /* Proportional Editing */ ED_keymap_proportional_cycle(keyconf, keymap); ED_keymap_proportional_editmode(keyconf, keymap, true); @@ -328,11 +328,11 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf) void ED_operatortypes_gpencil(void) { /* Drawing ----------------------- */ - + WM_operatortype_append(GPENCIL_OT_draw); - + /* Editing (Strokes) ------------ */ - + WM_operatortype_append(GPENCIL_OT_editmode_toggle); WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle); @@ -341,41 +341,41 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_select_circle); WM_operatortype_append(GPENCIL_OT_select_border); WM_operatortype_append(GPENCIL_OT_select_lasso); - + WM_operatortype_append(GPENCIL_OT_select_linked); WM_operatortype_append(GPENCIL_OT_select_grouped); WM_operatortype_append(GPENCIL_OT_select_more); WM_operatortype_append(GPENCIL_OT_select_less); WM_operatortype_append(GPENCIL_OT_select_first); WM_operatortype_append(GPENCIL_OT_select_last); - + WM_operatortype_append(GPENCIL_OT_duplicate); WM_operatortype_append(GPENCIL_OT_delete); WM_operatortype_append(GPENCIL_OT_dissolve); WM_operatortype_append(GPENCIL_OT_copy); WM_operatortype_append(GPENCIL_OT_paste); - + WM_operatortype_append(GPENCIL_OT_move_to_layer); WM_operatortype_append(GPENCIL_OT_layer_change); - + WM_operatortype_append(GPENCIL_OT_snap_to_grid); WM_operatortype_append(GPENCIL_OT_snap_to_cursor); WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected); - + WM_operatortype_append(GPENCIL_OT_reproject); - + WM_operatortype_append(GPENCIL_OT_brush_paint); - + /* Editing (Buttons) ------------ */ - + WM_operatortype_append(GPENCIL_OT_data_add); WM_operatortype_append(GPENCIL_OT_data_unlink); - + WM_operatortype_append(GPENCIL_OT_layer_add); WM_operatortype_append(GPENCIL_OT_layer_remove); WM_operatortype_append(GPENCIL_OT_layer_move); WM_operatortype_append(GPENCIL_OT_layer_duplicate); - + WM_operatortype_append(GPENCIL_OT_hide); WM_operatortype_append(GPENCIL_OT_reveal); WM_operatortype_append(GPENCIL_OT_lock_all); @@ -384,10 +384,10 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_merge); WM_operatortype_append(GPENCIL_OT_blank_frame_add); - + WM_operatortype_append(GPENCIL_OT_active_frame_delete); WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); - + WM_operatortype_append(GPENCIL_OT_convert); WM_operatortype_append(GPENCIL_OT_stroke_arrange); @@ -423,7 +423,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_brush_select); /* Editing (Time) --------------- */ - + /* Interpolation */ WM_operatortype_append(GPENCIL_OT_interpolate); WM_operatortype_append(GPENCIL_OT_interpolate_sequence); @@ -434,7 +434,7 @@ void ED_operatormacros_gpencil(void) { wmOperatorType *ot; wmOperatorTypeMacro *otmacro; - + /* Duplicate + Move = Interactively place newly duplicated strokes */ ot = WM_operatortype_append_macro("GPENCIL_OT_duplicate_move", "Duplicate Strokes", "Make copies of the selected Grease Pencil strokes and move them", diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index f9b5966dee3..c28d80a801f 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -117,35 +117,35 @@ typedef enum eGPencil_PaintFlags { typedef struct tGPsdata { Scene *scene; /* current scene from context */ struct Depsgraph *depsgraph; - + wmWindow *win; /* window where painting originated */ ScrArea *sa; /* area where painting originated */ ARegion *ar; /* region where painting originated */ View2D *v2d; /* needed for GP_STROKE_2DSPACE */ rctf *subrect; /* for using the camera rect within the 3d view */ rctf subrect_data; - + GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */ - + PointerRNA ownerPtr; /* pointer to owner of gp-datablock */ bGPdata *gpd; /* gp-datablock layer comes from */ bGPDlayer *gpl; /* layer we're working on */ bGPDframe *gpf; /* frame we're working on */ - + char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */ - + eGPencil_PaintStatus status; /* current status of painting */ eGPencil_PaintModes paintmode; /* mode for painting */ eGPencil_PaintFlags flags; /* flags that can get set during runtime (eGPencil_PaintFlags) */ - + short radius; /* radius of influence for eraser */ - + int mval[2]; /* current mouse-position */ int mvalo[2]; /* previous recorded mouse-position */ - + float pressure; /* current stylus pressure */ float opressure; /* previous stylus pressure */ - + /* These need to be doubles, as (at least under unix) they are in seconds since epoch, * float (and its 7 digits precision) is definitively not enough here! * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least. @@ -153,13 +153,13 @@ typedef struct tGPsdata { double inittime; /* Used when converting to path */ double curtime; /* Used when converting to path */ double ocurtime; /* Used when converting to path */ - + float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space * to region space */ float mat[4][4]; - + float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */ - + void *erasercursor; /* radial cursor data for drawing eraser */ bGPDpalettecolor *palettecolor; /* current palette color */ @@ -216,7 +216,7 @@ static int gpencil_draw_poll(bContext *C) else { CTX_wm_operator_poll_msg_set(C, "Active region not set"); } - + return 0; } @@ -237,12 +237,12 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3]) { View3D *v3d = p->sa->spacedata.first; const float *fp = ED_view3d_cursor3d_get(p->scene, v3d)->location; - + /* the reference point used depends on the owner... */ #if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */ if (p->ownerPtr.type == &RNA_Object) { Object *ob = (Object *)p->ownerPtr.data; - + /* active Object * - use relative distance of 3D-cursor from object center */ @@ -263,24 +263,24 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) { int dx = abs(mval[0] - pmval[0]); int dy = abs(mval[1] - pmval[1]); - + /* if buffer is empty, just let this go through (i.e. so that dots will work) */ if (p->gpd->sbuffer_size == 0) return true; - + /* check if mouse moved at least certain distance on both axes (best case) * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand */ else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) return true; - + /* check if the distance since the last point is significant enough * - prevents points being added too densely * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though */ else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX) return true; - + /* mouse 'didn't move' */ else return false; @@ -349,7 +349,7 @@ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth) { bGPdata *gpd = p->gpd; - + /* in 3d-space - pt->x/y/z are 3 side-by-side floats */ if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) { if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) { @@ -362,7 +362,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] float rvec[3], dvec[3]; float mval_f[2] = {UNPACK2(mval)}; float zfac; - + /* Current method just converts each point in screen-coordinates to * 3D-coordinates using the 3D-cursor as reference. In general, this * works OK, but it could of course be improved. @@ -371,10 +371,10 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] * - investigate using nearest point(s) on a previous stroke as * reference point instead or as offset, for easier stroke matching */ - + gp_get_3d_reference(p, rvec); zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL); - + if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { sub_v2_v2v2(mval_f, mval_prj, mval_f); ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac); @@ -385,13 +385,13 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] } } } - + /* 2d - on 'canvas' (assume that p->v2d is set) */ else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) { UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]); mul_v3_m4v3(out, p->imat, out); } - + /* 2d - relative to screen (viewport area) */ else { if (p->subrect == NULL) { /* normal 3D view */ @@ -477,7 +477,7 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ /* interpolate with previous point for smoother transitions */ mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f); - pt->pressure = mpressure; + pt->pressure = mpressure; CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f); } @@ -499,13 +499,13 @@ static short gp_stroke_addpoint( if (gpd->sbuffer_size == 0) { /* first point in buffer (start point) */ pt = (tGPspoint *)(gpd->sbuffer); - + /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->strength = 1.0f; pt->time = (float)(curtime - p->inittime); - + /* increment buffer size */ gpd->sbuffer_size++; } @@ -514,17 +514,17 @@ static short gp_stroke_addpoint( * - assume that pointers for this are always valid... */ pt = ((tGPspoint *)(gpd->sbuffer) + 1); - + /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->strength = 1.0f; pt->time = (float)(curtime - p->inittime); - + /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */ gpd->sbuffer_size = 2; } - + /* can keep carrying on this way :) */ return GP_STROKEADD_NORMAL; } @@ -532,10 +532,10 @@ static short gp_stroke_addpoint( /* check if still room in buffer */ if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX) return GP_STROKEADD_OVERFLOW; - + /* get pointer to destination point */ pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size); - + /* store settings */ /* pressure */ if (brush->flag & GP_BRUSH_USE_PRESSURE) { @@ -597,10 +597,10 @@ static short gp_stroke_addpoint( /* point time */ pt->time = (float)(curtime - p->inittime); - + /* increment counters */ gpd->sbuffer_size++; - + /* check if another operation can still occur */ if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX) return GP_STROKEADD_FULL; @@ -608,17 +608,17 @@ static short gp_stroke_addpoint( return GP_STROKEADD_NORMAL; } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { - + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); /* get pointer to destination point */ pt = (tGPspoint *)(gpd->sbuffer); - + /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->strength = 1.0f; pt->time = (float)(curtime - p->inittime); - + /* if there's stroke for this poly line session add (or replace last) point * to stroke. This allows to draw lines more interactively (see new segment * during mouse slide, e.g.) @@ -626,15 +626,15 @@ static short gp_stroke_addpoint( if (gp_stroke_added_check(p)) { bGPDstroke *gps = p->gpf->strokes.last; bGPDspoint *pts; - + /* first time point is adding to temporary buffer -- need to allocate new point in stroke */ if (gpd->sbuffer_size == 0) { gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); gps->totpoints++; } - + pts = &gps->points[gps->totpoints - 1]; - + /* special case for poly lines: normally, * depth is needed only when creating new stroke from buffer, * but poly lines are converting to stroke instantly, @@ -642,12 +642,12 @@ static short gp_stroke_addpoint( */ if (gpencil_project_check(p)) { View3D *v3d = p->sa->spacedata.first; - + view3d_region_operator_needs_opengl(p->win, p->ar); ED_view3d_autodist_init( p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); } - + /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); /* if axis locked, reproject to plane locked (only in 3d space) */ @@ -665,11 +665,11 @@ static short gp_stroke_addpoint( /* force fill recalc */ gps->flag |= GP_STROKE_RECALC_CACHES; } - + /* increment counters */ if (gpd->sbuffer_size == 0) gpd->sbuffer_size++; - + return GP_STROKEADD_NORMAL; } @@ -688,15 +688,15 @@ static void gp_stroke_simplify(tGPsdata *p) short num_points = gpd->sbuffer_size; short flag = gpd->sbuffer_sflag; short i, j; - + /* only simplify if simplification is enabled, and we're not doing a straight line */ if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)) return; - + /* don't simplify if less than 4 points in buffer */ if ((num_points <= 4) || (old_points == NULL)) return; - + /* clear buffer (but don't free mem yet) so that we can write to it * - firstly set sbuffer to NULL, so a new one is allocated * - secondly, reset flag after, as it gets cleared auto @@ -704,7 +704,7 @@ static void gp_stroke_simplify(tGPsdata *p) gpd->sbuffer = NULL; gp_session_validatebuffer(p); gpd->sbuffer_sflag = flag; - + /* macro used in loop to get position of new point * - used due to the mixture of datatypes in use here */ @@ -715,30 +715,30 @@ static void gp_stroke_simplify(tGPsdata *p) pressure += old_points[offs].pressure * sfac; \ time += old_points[offs].time * sfac; \ } (void)0 - + /* XXX Here too, do not lose start and end points! */ gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time); for (i = 0, j = 0; i < num_points; i++) { if (i - j == 3) { float co[2], pressure, time; int mco[2]; - + /* initialize values */ co[0] = 0.0f; co[1] = 0.0f; pressure = 0.0f; time = 0.0f; - + /* using macro, calculate new point */ GP_SIMPLIFY_AVPOINT(j, -0.25f); GP_SIMPLIFY_AVPOINT(j + 1, 0.75f); GP_SIMPLIFY_AVPOINT(j + 2, 0.75f); GP_SIMPLIFY_AVPOINT(j + 3, -0.25f); - + /* set values for adding */ mco[0] = (int)co[0]; mco[1] = (int)co[1]; - + /* ignore return values on this... assume to be ok for now */ gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time); @@ -747,7 +747,7 @@ static void gp_stroke_simplify(tGPsdata *p) } gp_stroke_addpoint(p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure, p->inittime + (double)old_points[num_points - 1].time); - + /* free old buffer */ MEM_freeN(old_points); } @@ -762,11 +762,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) tGPspoint *ptc; bGPDbrush *brush = p->brush; ToolSettings *ts = p->scene->toolsettings; - + int i, totelem; /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; - + /* get total number of points to allocate space for * - drawing straight-lines only requires the endpoints */ @@ -774,14 +774,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) totelem = (gpd->sbuffer_size >= 2) ? 2 : gpd->sbuffer_size; else totelem = gpd->sbuffer_size; - + /* exit with error if no valid points from this stroke */ if (totelem == 0) { if (G.debug & G_DEBUG) printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->sbuffer_size); return; } - + /* special case for poly line -- for already added stroke during session * coordinates are getting added to stroke immediately to allow more * interactive behavior @@ -791,23 +791,23 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) return; } } - + /* allocate memory for a new stroke */ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); - + /* copy appropriate settings for stroke */ gps->totpoints = totelem; gps->thickness = brush->thickness; gps->flag = gpd->sbuffer_sflag; gps->inittime = p->inittime; - + /* enable recalculation flag by default (only used if hq fill) */ gps->flag |= GP_STROKE_RECALC_CACHES; /* allocate enough memory for a continuous array for storage points */ int sublevel = brush->sublevel; int new_totpoints = gps->totpoints; - + for (i = 0; i < sublevel; i++) { new_totpoints += new_totpoints - 1; } @@ -818,14 +818,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gps->tot_triangles = 0; /* set pointer to first non-initialized point */ pt = gps->points + (gps->totpoints - totelem); - + /* copy points from the buffer to the stroke */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { /* straight lines only -> only endpoints */ { /* first point */ ptc = gpd->sbuffer; - + /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* if axis locked, reproject to plane locked (only in 3d space) */ @@ -841,14 +841,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; - + pt++; } - + if (totelem == 2) { /* last point if applicable */ ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1); - + /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* if axis locked, reproject to plane locked (only in 3d space) */ @@ -870,7 +870,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { /* first point */ ptc = gpd->sbuffer; - + /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); /* if axis locked, reproject to plane locked (only in 3d space) */ @@ -1012,7 +1012,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gps->palcolor = palcolor; BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); - /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head + /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist * when drawing the background */ @@ -1060,7 +1060,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons mul_v3_m4v3(fpt, diff_mat, &pt->x); const float depth_pt = view3d_point_depth(rv3d, fpt); - + if (depth_pt > depth_mval) { return true; } @@ -1075,13 +1075,13 @@ static float gp_stroke_eraser_calc_influence(tGPsdata *p, const int mval[2], con /* Linear Falloff... */ float distance = (float)len_v2v2_int(mval, co); float fac; - + CLAMP(distance, 0.0f, (float)radius); fac = 1.0f - (distance / (float)radius); - + /* Control this further using pen pressure */ fac *= p->pressure; - + /* Return influence factor computed here */ return fac; } @@ -1142,15 +1142,15 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, * below which we would have invisible strokes */ const float cull_thresh = (gps->thickness) ? 1.0f / ((float)gps->thickness) : 1.0f; - + /* Amount to decrease the pressure of each point with each stroke */ // TODO: Fetch from toolsettings, or compute based on thickness instead? const float strength = 0.1f; - + /* Perform culling? */ bool do_cull = false; - - + + /* Clear Tags * * Note: It's better this way, as we are sure that @@ -1161,7 +1161,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, bGPDspoint *pt = &gps->points[i]; pt->flag &= ~GP_SPOINT_TAG; } - + /* First Pass: Loop over the points in the stroke * 1) Thin out parts of the stroke under the brush * 2) Tag "too thin" parts for removal (in second pass) @@ -1174,7 +1174,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* only process if it hasn't been masked out... */ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) continue; - + if (gpl->parent == NULL) { gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); @@ -1207,7 +1207,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, */ pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength; pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength / 2.0f; - + /* 2) Tag any point with overly low influence for removal in the next pass */ if (pt1->pressure < cull_thresh) { pt1->flag |= GP_SPOINT_TAG; @@ -1221,7 +1221,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, } } } - + /* Second Pass: Remove any points that are tagged */ if (do_cull) { gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG); @@ -1235,13 +1235,13 @@ static void gp_stroke_doeraser(tGPsdata *p) bGPDlayer *gpl; bGPDstroke *gps, *gpn; rcti rect; - + /* rect is rectangle of eraser */ rect.xmin = p->mval[0] - p->radius; rect.ymin = p->mval[1] - p->radius; rect.xmax = p->mval[0] + p->radius; rect.ymax = p->mval[1] + p->radius; - + if (p->sa->spacetype == SPACE_VIEW3D) { if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) { View3D *v3d = p->sa->spacedata.first; @@ -1249,14 +1249,14 @@ static void gp_stroke_doeraser(tGPsdata *p) ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0); } } - + /* loop over all layers too, since while it's easy to restrict editing to * only a subset of layers, it is harder to perform the same erase operation * on multiple layers... */ for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) { bGPDframe *gpf = gpl->actframe; - + /* only affect layer if it's editable (and visible) */ if (gpencil_layer_is_editable(gpl) == false) { continue; @@ -1264,7 +1264,7 @@ static void gp_stroke_doeraser(tGPsdata *p) else if (gpf == NULL) { continue; } - + /* loop over strokes, checking segments for intersections */ for (gps = gpf->strokes.first; gps; gps = gpn) { gpn = gps->next; @@ -1289,7 +1289,7 @@ static void gp_stroke_doeraser(tGPsdata *p) static void gp_session_validatebuffer(tGPsdata *p) { bGPdata *gpd = p->gpd; - + /* clear memory of buffer (or allocate it if starting a new session) */ if (gpd->sbuffer) { /* printf("\t\tGP - reset sbuffer\n"); */ @@ -1299,13 +1299,13 @@ static void gp_session_validatebuffer(tGPsdata *p) /* printf("\t\tGP - allocate sbuffer\n"); */ gpd->sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); } - + /* reset indices */ gpd->sbuffer_size = 0; - + /* reset flags */ gpd->sbuffer_sflag = 0; - + /* reset inittime */ p->inittime = 0.0; } @@ -1316,7 +1316,7 @@ static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette) bGPDpalettecolor *palcolor; palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); - + return palcolor; } @@ -1389,7 +1389,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) ScrArea *curarea = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); ToolSettings *ts = CTX_data_tool_settings(C); - + /* make sure the active view (at the starting time) is a 3d-view */ if (curarea == NULL) { p->status = GP_STATUS_ERROR; @@ -1397,22 +1397,22 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) printf("Error: No active view for painting\n"); return 0; } - + /* pass on current scene and window */ p->scene = CTX_data_scene(C); p->depsgraph = CTX_data_depsgraph(C); p->win = CTX_wm_window(C); - + unit_m4(p->imat); unit_m4(p->mat); - + switch (curarea->spacetype) { /* supported views first */ case SPACE_VIEW3D: { /* View3D *v3d = curarea->spacedata.first; */ /* RegionView3D *rv3d = ar->regiondata; */ - + /* set current area * - must verify that region data is 3D-view (and not something else) */ @@ -1420,7 +1420,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) p->sa = curarea; p->ar = ar; p->align_flag = &ts->gpencil_v3d_align; - + if (ar->regiondata == NULL) { p->status = GP_STATUS_ERROR; if (G.debug & G_DEBUG) @@ -1432,7 +1432,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) case SPACE_NODE: { /* SpaceNode *snode = curarea->spacedata.first; */ - + /* set current area */ p->sa = curarea; p->ar = ar; @@ -1443,13 +1443,13 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) case SPACE_SEQ: { SpaceSeq *sseq = curarea->spacedata.first; - + /* set current area */ p->sa = curarea; p->ar = ar; p->v2d = &ar->v2d; p->align_flag = &ts->gpencil_seq_align; - + /* check that gpencil data is allowed to be drawn */ if (sseq->mainb == SEQ_DRAW_SEQUENCE) { p->status = GP_STATUS_ERROR; @@ -1462,7 +1462,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) case SPACE_IMAGE: { /* SpaceImage *sima = curarea->spacedata.first; */ - + /* set the current area */ p->sa = curarea; p->ar = ar; @@ -1474,7 +1474,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) { SpaceClip *sc = curarea->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); - + if (clip == NULL) { p->status = GP_STATUS_ERROR; return false; @@ -1485,15 +1485,15 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) p->ar = ar; p->v2d = &ar->v2d; p->align_flag = &ts->gpencil_v2d_align; - + invert_m4_m4(p->imat, sc->unistabmat); - + /* custom color for new layer */ p->custom_color[0] = 1.0f; p->custom_color[1] = 0.0f; p->custom_color[2] = 0.5f; p->custom_color[3] = 0.9f; - + if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { int framenr = ED_space_clip_get_clip_frame_number(sc); MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking); @@ -1508,7 +1508,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) return false; } } - + invert_m4_m4(p->mat, p->imat); copy_m4_m4(p->gsc.mat, p->mat); break; @@ -1522,7 +1522,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) return 0; } } - + /* get gp-data */ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr); if (gpd_ptr == NULL) { @@ -1537,14 +1537,14 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) *gpd_ptr = BKE_gpencil_data_addnew("GPencil"); p->gpd = *gpd_ptr; } - + if (ED_gpencil_session_active() == 0) { /* initialize undo stack, * also, existing undo stack would make buffer drawn */ gpencil_undo_init(p->gpd); } - + /* clear out buffer (stored in gp-data), in case something contaminated it */ gp_session_validatebuffer(p); /* set brush and create a new one if null */ @@ -1567,12 +1567,12 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) static tGPsdata *gp_session_initpaint(bContext *C) { tGPsdata *p = NULL; - + /* create new context data */ p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data"); - + gp_session_initdata(C, p); - + /* radius for eraser circle is defined in userprefs now */ /* NOTE: we do this here, so that if we exit immediately, * erase size won't get lost @@ -1587,18 +1587,18 @@ static tGPsdata *gp_session_initpaint(bContext *C) static void gp_session_cleanup(tGPsdata *p) { bGPdata *gpd = (p) ? p->gpd : NULL; - + /* error checking */ if (gpd == NULL) return; - + /* free stroke buffer */ if (gpd->sbuffer) { /* printf("\t\tGP - free sbuffer\n"); */ MEM_freeN(gpd->sbuffer); gpd->sbuffer = NULL; } - + /* clear flags */ gpd->sbuffer_size = 0; gpd->sbuffer_sflag = 0; @@ -1610,12 +1610,12 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps { Scene *scene = p->scene; ToolSettings *ts = scene->toolsettings; - + /* get active layer (or add a new one if non-existent) */ p->gpl = BKE_gpencil_layer_getactive(p->gpd); if (p->gpl == NULL) { p->gpl = BKE_gpencil_layer_addnew(p->gpd, "GP_Layer", true); - + if (p->custom_color[3]) copy_v3_v3(p->gpl->color, p->custom_color); } @@ -1625,7 +1625,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps printf("Error: Cannot paint on locked layer\n"); return; } - + /* get active frame (add a new one if not matching frame) */ if (paintmode == GP_PAINTMODE_ERASER) { /* Eraser mode: @@ -1634,12 +1634,12 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps * (to avoid problems with other tools which expect it to exist) */ bool has_layer_to_erase = false; - + for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) { /* Skip if layer not editable */ if (gpencil_layer_is_editable(gpl) == false) continue; - + /* Add a new frame if needed (and based off the active frame, * as we need some existing strokes to erase) * @@ -1651,16 +1651,16 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); has_layer_to_erase = true; } - + /* XXX: we omit GP_FRAME_PAINT here for now, * as it is only really useful for doing * paintbuffer drawing */ } - + /* Ensure this gets set... */ p->gpf = p->gpl->actframe; - + /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on * (though this is only available in editmode) */ @@ -1669,7 +1669,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps p->flags |= GP_PAINTFLAG_SELECTMASK; } } - + if (has_layer_to_erase == false) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) @@ -1680,14 +1680,14 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps else { /* Drawing Modes - Add a new frame if needed on the active layer */ short add_frame_mode; - + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) add_frame_mode = GP_GETFRAME_ADD_COPY; else add_frame_mode = GP_GETFRAME_ADD_NEW; - + p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); - + if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; if (G.debug & G_DEBUG) @@ -1698,12 +1698,12 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps p->gpf->flag |= GP_FRAME_PAINT; } } - + /* set 'eraser' for this stroke if using eraser */ p->paintmode = paintmode; if (p->paintmode == GP_PAINTMODE_ERASER) { p->gpd->sbuffer_sflag |= GP_STROKE_ERASER; - + /* check if we should respect depth while erasing */ if (p->sa->spacetype == SPACE_VIEW3D) { if (p->gpl->flag & GP_LAYER_NO_XRAY) { @@ -1714,25 +1714,25 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps else { /* disable eraser flags - so that we can switch modes during a session */ p->gpd->sbuffer_sflag &= ~GP_STROKE_ERASER; - + if (p->sa->spacetype == SPACE_VIEW3D) { if (p->gpl->flag & GP_LAYER_NO_XRAY) { p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH; } } } - + /* set 'initial run' flag, which is only used to denote when a new stroke is starting */ p->flags |= GP_PAINTFLAG_FIRSTRUN; - - + + /* when drawing in the camera view, in 2D space, set the subrect */ p->subrect = NULL; if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { if (p->sa->spacetype == SPACE_VIEW3D) { View3D *v3d = p->sa->spacedata.first; RegionView3D *rv3d = p->ar->regiondata; - + /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */ @@ -1740,21 +1740,21 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps } } } - + /* init stroke point space-conversion settings... */ p->gsc.gpd = p->gpd; p->gsc.gpl = p->gpl; - + p->gsc.sa = p->sa; p->gsc.ar = p->ar; p->gsc.v2d = p->v2d; - + p->gsc.subrect_data = p->subrect_data; p->gsc.subrect = p->subrect; - + copy_m4_m4(p->gsc.mat, p->mat); - - + + /* check if points will need to be made in view-aligned space */ if (*p->align_flag & GP_PROJECT_VIEWSPACE) { switch (p->sa->spacetype) { @@ -1776,7 +1776,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps case SPACE_IMAGE: { SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first; - + /* only set these flags if the image editor doesn't have an image active, * otherwise user will be confused by strokes not appearing after they're drawn * @@ -1810,12 +1810,12 @@ static void gp_paint_strokeend(tGPsdata *p) */ if (gpencil_project_check(p)) { View3D *v3d = p->sa->spacedata.first; - + /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(p->win, p->ar); ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); } - + /* check if doing eraser or not */ if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) { /* simplify stroke before transferring? */ @@ -1824,7 +1824,7 @@ static void gp_paint_strokeend(tGPsdata *p) /* transfer stroke to frame */ gp_stroke_newfrombuffer(p); } - + /* clean up buffer now */ gp_session_validatebuffer(p); } @@ -1839,7 +1839,7 @@ static void gp_paint_cleanup(tGPsdata *p) /* finish off a stroke */ gp_paint_strokeend(p); } - + /* "unlock" frame */ if (p->gpf) p->gpf->flag &= ~GP_FRAME_PAINT; @@ -1912,7 +1912,7 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event) const wmTabletData *wmtab = event->tablet_data; return (wmtab->Active == EVT_TABLET_ERASER); } - + return false; } @@ -1921,13 +1921,13 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event) static void gpencil_draw_exit(bContext *C, wmOperator *op) { tGPsdata *p = op->customdata; - + /* clear undo stack */ gpencil_undo_finish(); - + /* restore cursor to indicate end of drawing */ WM_cursor_modal_restore(CTX_wm_window(C)); - + /* don't assume that operator data exists at all */ if (p) { /* check size of buffer before cleanup, to determine if anything happened here */ @@ -1941,15 +1941,15 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) * have been toggled at some point. */ U.gp_eraser = p->radius; - + /* cleanup */ gp_paint_cleanup(p); gp_session_cleanup(p); - + /* finally, free the temp data */ MEM_freeN(p); } - + op->customdata = NULL; } @@ -1966,7 +1966,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p; eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode"); - + /* check context */ p = op->customdata = gp_session_initpaint(C); if ((p == NULL) || (p->status == GP_STATUS_ERROR)) { @@ -1974,7 +1974,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) gpencil_draw_exit(C, op); return 0; } - + /* init painting data */ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C)); if (p->status == GP_STATUS_ERROR) { @@ -1988,7 +1988,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) else { p->keymodifier = -1; } - + /* everything is now setup ok */ return 1; } @@ -2015,7 +2015,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p) if (GPENCIL_SKETCH_SESSIONS_ON(p->scene)) ED_area_headerprint(p->sa, IFACE_("Grease Pencil: Drawing/erasing stroke... Release to end stroke")); break; - + case GP_STATUS_IDLING: /* print status info */ switch (p->paintmode) { @@ -2035,13 +2035,13 @@ static void gpencil_draw_status_indicators(tGPsdata *p) ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | " "ESC/Enter to end (or click outside this area)")); break; - + default: /* unhandled future cases */ ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)")); break; } break; - + case GP_STATUS_ERROR: case GP_STATUS_DONE: /* clear status string */ @@ -2076,7 +2076,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph gp_paint_strokeend(p); /* And start a new one!!! Else, projection errors! */ gp_paint_initstroke(p, p->paintmode, depsgraph); - + /* start a new stroke, starting from previous point */ /* XXX Must manually reset inittime... */ /* XXX We only need to reuse previous point if overflow! */ @@ -2093,12 +2093,12 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph /* the painting operation cannot continue... */ BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke"); p->status = GP_STATUS_ERROR; - + if (G.debug & G_DEBUG) printf("Error: Grease-Pencil Paint - Add Point Invalid\n"); return; } - + /* store used values */ p->mvalo[0] = p->mval[0]; p->mvalo[1] = p->mval[1]; @@ -2114,13 +2114,13 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg PointerRNA itemptr; float mousef[2]; int tablet = 0; - + /* convert from window-space to area-space mouse coordinates * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... */ p->mval[0] = event->mval[0] + 1; p->mval[1] = event->mval[1] + 1; - + /* verify key status for straight lines */ if ((event->ctrl > 0) || (event->alt > 0)) { if (p->straight[0] == 0) { @@ -2146,14 +2146,14 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg } p->curtime = PIL_check_seconds_timer(); - + /* handle pressure sensitivity (which is supplied by tablets) */ if (event->tablet_data) { const wmTabletData *wmtab = event->tablet_data; - + tablet = (wmtab->Active != EVT_TABLET_NONE); p->pressure = wmtab->Pressure; - + /* Hack for pressure sensitive eraser on D+RMB when using a tablet: * The pen has to float over the tablet surface, resulting in * zero pressure (T47101). Ignore pressure values if floating @@ -2170,11 +2170,11 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg /* No tablet data -> No pressure info is available */ p->pressure = 1.0f; } - + /* special exception for start of strokes (i.e. maybe for just a dot) */ if (p->flags & GP_PAINTFLAG_FIRSTRUN) { p->flags &= ~GP_PAINTFLAG_FIRSTRUN; - + p->mvalo[0] = p->mval[0]; p->mvalo[1] = p->mval[1]; p->opressure = p->pressure; @@ -2188,7 +2188,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg if (tablet && (p->pressure >= 0.99f)) return; } - + /* check if alt key is pressed and limit to straight lines */ if (p->straight[0] != 0) { if (p->straight[0] == 1) { @@ -2203,15 +2203,15 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg /* fill in stroke data (not actually used directly by gpencil_draw_apply) */ RNA_collection_add(op->ptr, "stroke", &itemptr); - + mousef[0] = p->mval[0]; mousef[1] = p->mval[1]; RNA_float_set_array(&itemptr, "mouse", mousef); RNA_float_set(&itemptr, "pressure", p->pressure); RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0); - + RNA_float_set(&itemptr, "time", p->curtime - p->inittime); - + /* apply the current latest drawing point */ gpencil_draw_apply(op, p, depsgraph); @@ -2226,9 +2226,9 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) { tGPsdata *p = NULL; Depsgraph *depsgraph = CTX_data_depsgraph(C); - + /* printf("GPencil - Starting Re-Drawing\n"); */ - + /* try to initialize context data needed while drawing */ if (!gpencil_draw_init(C, op, NULL)) { if (op->customdata) MEM_freeN(op->customdata); @@ -2237,25 +2237,25 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } else p = op->customdata; - + /* printf("\tGP - Start redrawing stroke\n"); */ - + /* 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") { float mousef[2]; - + /* printf("\t\tGP - stroke elem\n"); */ - + /* get relevant data for this point from stroke */ RNA_float_get_array(&itemptr, "mouse", mousef); p->mval[0] = (int)mousef[0]; p->mval[1] = (int)mousef[1]; p->pressure = RNA_float_get(&itemptr, "pressure"); p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime; - + if (RNA_boolean_get(&itemptr, "is_start")) { /* if first-run flag isn't set already (i.e. not true first stroke), * then we must terminate the previous one first before continuing @@ -2266,30 +2266,30 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) gp_paint_initstroke(p, p->paintmode, depsgraph); } } - + /* if first run, set previous data too */ if (p->flags & GP_PAINTFLAG_FIRSTRUN) { p->flags &= ~GP_PAINTFLAG_FIRSTRUN; - + p->mvalo[0] = p->mval[0]; p->mvalo[1] = p->mval[1]; p->opressure = p->pressure; p->ocurtime = p->curtime; } - + /* apply this data as necessary now (as per usual) */ gpencil_draw_apply(op, p, depsgraph); } RNA_END; - + /* printf("\tGP - done\n"); */ - + /* cleanup */ gpencil_draw_exit(C, op); - + /* refreshes */ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* done */ return OPERATOR_FINISHED; } @@ -2300,10 +2300,10 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p = NULL; - + if (G.debug & G_DEBUG) printf("GPencil - Starting Drawing\n"); - + /* try to initialize context data needed while drawing */ if (!gpencil_draw_init(C, op, event)) { if (op->customdata) @@ -2314,17 +2314,17 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event } else p = op->customdata; - + /* TODO: set any additional settings that we can take from the events? * TODO? if tablet is erasing, force eraser to be on? */ - + /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */ - + /* if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { gpencil_draw_toggle_eraser_cursor(C, p, true); } - /* set cursor + /* set cursor * NOTE: This may change later (i.e. intentionally via brush toggle, * or unintentionally if the user scrolls outside the area)... */ @@ -2345,7 +2345,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */ op->flag |= OP_IS_MODAL_CURSOR_REGION; } - + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* add a modal handler for this operator, so that we can then draw continuous strokes */ WM_event_add_modal_handler(C, op); @@ -2362,7 +2362,7 @@ static bool gpencil_area_exists(bContext *C, ScrArea *sa_test) static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) { tGPsdata *p = op->customdata; - + /* we must check that we're still within the area that we're set up to work from * otherwise we could crash (see bug #20586) */ @@ -2370,21 +2370,21 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) printf("\t\t\tGP - wrong area execution abort!\n"); p->status = GP_STATUS_ERROR; } - + /* printf("\t\tGP - start stroke\n"); */ - + /* we may need to set up paint env again if we're resuming */ /* XXX: watch it with the paintmode! in future, * it'd be nice to allow changing paint-mode when in sketching-sessions */ - + if (gp_session_initdata(C, p)) gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C)); - + if (p->status != GP_STATUS_ERROR) { p->status = GP_STATUS_PAINTING; op->flag &= ~OP_IS_MODAL_CURSOR_REGION; } - + return op->customdata; } @@ -2395,12 +2395,12 @@ static void gpencil_stroke_end(wmOperator *op) gp_paint_cleanup(p); gpencil_undo_push(p->gpd); - + gp_session_cleanup(p); - + p->status = GP_STATUS_IDLING; op->flag |= OP_IS_MODAL_CURSOR_REGION; - + p->gpd = NULL; p->gpl = NULL; p->gpf = NULL; @@ -2434,7 +2434,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) tGPsdata *p = op->customdata; ToolSettings *ts = CTX_data_tool_settings(C); int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */ - + /* if (event->type == NDOF_MOTION) * return OPERATOR_PASS_THROUGH; * ------------------------------- @@ -2447,7 +2447,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * better in tools that immediately apply * in 3D space. */ - + if (p->status == GP_STATUS_IDLING) { ARegion *ar = CTX_wm_region(C); p->ar = ar; @@ -2484,9 +2484,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_RUNNING_MODAL; } } - + //printf("\tGP - handle modal event...\n"); - + /* exit painting mode (and/or end current stroke) * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] */ @@ -2504,7 +2504,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; } - + /* toggle painting mode upon mouse-button movement * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only) * - RIGHTMOUSE = polyline (hotkey) / eraser (all) @@ -2515,14 +2515,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* if painting, end stroke */ if (p->status == GP_STATUS_PAINTING) { int sketch = 0; - + /* basically, this should be mouse-button up = end stroke * BUT what happens next depends on whether we 'painting sessions' is enabled */ sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene); /* polyline drawing is also 'sketching' -- all knots should be added during one session */ sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY); - + if (sketch) { /* end stroke only, and then wait to resume painting soon */ /* printf("\t\tGP - end stroke only\n"); */ @@ -2533,13 +2533,13 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) */ if (p->paintmode == GP_PAINTMODE_ERASER) { p->paintmode = RNA_enum_get(op->ptr, "mode"); - + /* if the original mode was *still* eraser, * we'll let it say for now, since this gives * users an opportunity to have visual feedback * when adjusting eraser size */ - if (p->paintmode != GP_PAINTMODE_ERASER) { + if (p->paintmode != GP_PAINTMODE_ERASER) { /* turn off cursor... * NOTE: this should be enough for now * Just hiding this makes it seem like @@ -2548,10 +2548,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_draw_toggle_eraser_cursor(C, p, false); } } - + /* we've just entered idling state, so this event was processed (but no others yet) */ estate = OPERATOR_RUNNING_MODAL; - + /* stroke could be smoothed, send notifier to refresh screen */ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } @@ -2571,7 +2571,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } else if (event->val == KM_PRESS) { bool in_bounds = false; - + /* Check if we're outside the bounds of the active region * NOTE: An exception here is that if launched from the toolbar, * whatever region we're now in should become the new region @@ -2579,13 +2579,13 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) { /* Change to whatever region is now under the mouse */ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y); - + if (G.debug & G_DEBUG) { printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n", current_region, p->ar, event->x, event->y, p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax); } - + if (current_region) { /* Assume that since we found the cursor in here, it is in bounds * and that this should be the region that we begin drawing in @@ -2597,14 +2597,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Out of bounds, or invalid in some other way */ p->status = GP_STATUS_ERROR; estate = OPERATOR_CANCELLED; - + if (G.debug & G_DEBUG) printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__); } } else if (p->ar) { rcti region_rect; - + /* Perform bounds check using */ ED_region_visible_rect(p->ar, ®ion_rect); in_bounds = BLI_rcti_isect_pt_v(®ion_rect, event->mval); @@ -2613,11 +2613,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* No region */ p->status = GP_STATUS_ERROR; estate = OPERATOR_CANCELLED; - + if (G.debug & G_DEBUG) printf("%s: No active region found in GP Paint session data\n", __func__); } - + if (in_bounds) { /* Switch paintmode (temporarily if need be) based on which button was used * NOTE: This is to make it more convenient to erase strokes when using drawing sessions @@ -2630,18 +2630,18 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* restore drawmode to default */ p->paintmode = RNA_enum_get(op->ptr, "mode"); } - + gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER); - + /* not painting, so start stroke (this should be mouse-button down) */ p = gpencil_stroke_begin(C, op); - + if (p->status == GP_STATUS_ERROR) { estate = OPERATOR_CANCELLED; } } else if (p->status != GP_STATUS_ERROR) { - /* User clicked outside bounds of window while idling, so exit paintmode + /* User clicked outside bounds of window while idling, so exit paintmode * NOTE: Don't enter this case if an error occurred while finding the * region (as above) */ @@ -2662,7 +2662,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) op->flag |= OP_IS_MODAL_CURSOR_REGION; } } - + /* handle mode-specific events */ if (p->status == GP_STATUS_PAINTING) { /* handle painting mouse-movements? */ @@ -2695,19 +2695,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) case PADPLUSKEY: p->radius += 5; break; - + case WHEELUPMOUSE: /* smaller */ case PADMINUS: p->radius -= 5; - + if (p->radius <= 0) p->radius = 1; break; } - + /* force refresh */ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ - + /* event handled, so just tag as running modal */ estate = OPERATOR_RUNNING_MODAL; } @@ -2719,7 +2719,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_RUNNING_MODAL; } } - + /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ if (0 == gpencil_area_exists(C, p->sa)) estate = OPERATOR_CANCELLED; @@ -2728,7 +2728,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_draw_status_indicators(p); gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */ } - + /* process last operations before exiting */ switch (estate) { case OPERATOR_FINISHED: @@ -2736,11 +2736,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_draw_exit(C, op); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); break; - + case OPERATOR_CANCELLED: gpencil_draw_exit(C, op); break; - + case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH: /* event doesn't need to be handled */ #if 0 @@ -2749,7 +2749,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) #endif break; } - + /* return status code */ return estate; } @@ -2767,28 +2767,28 @@ static const EnumPropertyItem prop_gpencil_drawmodes[] = { void GPENCIL_OT_draw(wmOperatorType *ot) { PropertyRNA *prop; - + /* identifiers */ ot->name = "Grease Pencil Draw"; ot->idname = "GPENCIL_OT_draw"; ot->description = "Make annotations on the active data"; - + /* api callbacks */ ot->exec = gpencil_draw_exec; ot->invoke = gpencil_draw_invoke; ot->modal = gpencil_draw_modal; ot->cancel = gpencil_draw_cancel; ot->poll = gpencil_draw_poll; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - + /* settings for drawing */ ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements"); prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - + /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index dc3483163bf..ac0b046e499 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -70,14 +70,14 @@ static int gpencil_select_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + /* we just need some visible strokes, and to be in editmode */ if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { /* TODO: include a check for visible strokes? */ if (gpd->layers.first) return true; } - + return false; } @@ -88,16 +88,16 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); int action = RNA_enum_get(op->ptr, "action"); - + if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); return OPERATOR_CANCELLED; } - + /* for "toggle", test for existing selected strokes */ if (action == SEL_TOGGLE) { action = SEL_SELECT; - + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { if (gps->flag & GP_STROKE_SELECT) { @@ -107,7 +107,7 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) } CTX_DATA_END; } - + /* if deselecting, we need to deselect strokes across all frames * - Currently, an exception is only given for deselection * Selecting and toggling should only affect what's visible, @@ -122,21 +122,21 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { bGPDframe *gpf; - + /* deselect all strokes on all frames */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { bGPDstroke *gps; - + for (gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; int i; - + /* only edit strokes that are valid in this view... */ if (ED_gpencil_stroke_can_use(C, gps)) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } - + gps->flag &= ~GP_STROKE_SELECT; } } @@ -151,7 +151,7 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) bGPDspoint *pt; int i; bool selected = false; - + /* Change selection status of all points, then make the stroke match */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { switch (action) { @@ -165,11 +165,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) pt->flag ^= GP_SPOINT_SELECT; break; } - + if (pt->flag & GP_SPOINT_SELECT) selected = true; } - + /* Change status of stroke */ if (selected) gps->flag |= GP_STROKE_SELECT; @@ -178,7 +178,7 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) } CTX_DATA_END; } - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -190,14 +190,14 @@ void GPENCIL_OT_select_all(wmOperatorType *ot) ot->name = "(De)select All Strokes"; ot->idname = "GPENCIL_OT_select_all"; ot->description = "Change selection of all Grease Pencil strokes currently visible"; - + /* callbacks */ ot->exec = gpencil_select_all_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + WM_operator_properties_select_all(ot); } @@ -207,26 +207,26 @@ void GPENCIL_OT_select_all(wmOperatorType *ot) static int gpencil_select_linked_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - + if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); return OPERATOR_CANCELLED; } - + /* select all points in selected strokes */ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag |= GP_SPOINT_SELECT; } } } CTX_DATA_END; - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -238,11 +238,11 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot) ot->name = "Select Linked"; ot->idname = "GPENCIL_OT_select_linked"; ot->description = "Select all points in same strokes as already selected points"; - + /* callbacks */ ot->exec = gpencil_select_linked_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -253,10 +253,10 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot) typedef enum eGP_SelectGrouped { /* Select strokes in the same layer */ GP_SEL_SAME_LAYER = 0, - + /* Select strokes with the same color */ GP_SEL_SAME_COLOR = 1, - + /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */ /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */ } eGP_SelectGrouped; @@ -267,16 +267,16 @@ typedef enum eGP_SelectGrouped { static void gp_select_same_layer(bContext *C) { Scene *scene = CTX_data_scene(C); - + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); bGPDstroke *gps; bool found = false; - + if (gpf == NULL) continue; - + /* Search for a selected stroke */ for (gps = gpf->strokes.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { @@ -286,18 +286,18 @@ static void gp_select_same_layer(bContext *C) } } } - + /* Select all if found */ if (found) { for (gps = gpf->strokes.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag |= GP_SPOINT_SELECT; } - + gps->flag |= GP_STROKE_SELECT; } } @@ -310,11 +310,11 @@ static void gp_select_same_layer(bContext *C) static void gp_select_same_color(bContext *C) { /* First, build set containing all the colors of selected strokes - * - We use the palette names, so that we can select all strokes with one + * - We use the palette names, so that we can select all strokes with one * (potentially missing) color, and remap them to something else */ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors"); - + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { if (gps->flag & GP_STROKE_SELECT) { @@ -325,7 +325,7 @@ static void gp_select_same_color(bContext *C) } } CTX_DATA_END; - + /* Second, select any visible stroke that uses these colors */ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { @@ -333,11 +333,11 @@ static void gp_select_same_color(bContext *C) /* select this stroke */ bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag |= GP_SPOINT_SELECT; } - + gps->flag |= GP_STROKE_SELECT; } } @@ -350,7 +350,7 @@ static void gp_select_same_color(bContext *C) static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) { eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type"); - + switch (mode) { case GP_SEL_SAME_LAYER: gp_select_same_layer(C); @@ -358,12 +358,12 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) case GP_SEL_SAME_COLOR: gp_select_same_color(C); break; - + default: BLI_assert(!"unhandled select grouped gpencil mode"); break; } - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -376,20 +376,20 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot) {GP_SEL_SAME_COLOR, "COLOR", 0, "Color", "Shared colors"}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Select Grouped"; ot->idname = "GPENCIL_OT_select_grouped"; ot->description = "Select all strokes with similar characteristics"; - + /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gpencil_select_grouped_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", ""); } @@ -401,33 +401,33 @@ static int gpencil_select_first_exec(bContext *C, wmOperator *op) { const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); const bool extend = RNA_boolean_get(op->ptr, "extend"); - + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { /* skip stroke if we're only manipulating selected strokes */ if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { continue; } - + /* select first point */ BLI_assert(gps->totpoints >= 1); - + gps->points->flag |= GP_SPOINT_SELECT; gps->flag |= GP_STROKE_SELECT; - + /* deselect rest? */ if ((extend == false) && (gps->totpoints > 1)) { /* start from index 1, to skip the first point that we'd just selected... */ bGPDspoint *pt = &gps->points[1]; int i = 1; - + for (; i < gps->totpoints; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } } } CTX_DATA_END; - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -439,18 +439,18 @@ void GPENCIL_OT_select_first(wmOperatorType *ot) ot->name = "Select First"; ot->idname = "GPENCIL_OT_select_first"; ot->description = "Select first point in Grease Pencil strokes"; - + /* callbacks */ ot->exec = gpencil_select_first_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only", "Only select the first point of strokes that already have points selected"); - + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); } @@ -461,33 +461,33 @@ static int gpencil_select_last_exec(bContext *C, wmOperator *op) { const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); const bool extend = RNA_boolean_get(op->ptr, "extend"); - + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { /* skip stroke if we're only manipulating selected strokes */ if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { continue; } - + /* select last point */ BLI_assert(gps->totpoints >= 1); - + gps->points[gps->totpoints - 1].flag |= GP_SPOINT_SELECT; gps->flag |= GP_STROKE_SELECT; - + /* deselect rest? */ if ((extend == false) && (gps->totpoints > 1)) { /* don't include the last point... */ bGPDspoint *pt = gps->points; int i = 1; - + for (; i < gps->totpoints - 1; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } } } CTX_DATA_END; - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -499,18 +499,18 @@ void GPENCIL_OT_select_last(wmOperatorType *ot) ot->name = "Select Last"; ot->idname = "GPENCIL_OT_select_last"; ot->description = "Select last point in Grease Pencil strokes"; - + /* callbacks */ ot->exec = gpencil_select_last_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "only_selected_strokes", false, "Selected Strokes Only", "Only select the last point of strokes that already have points selected"); - + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); } @@ -525,8 +525,8 @@ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) bGPDspoint *pt; int i; bool prev_sel; - - /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)... + + /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)... * - This pass covers the "after" edges of selection islands */ prev_sel = false; @@ -543,8 +543,8 @@ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) prev_sel = false; } } - - /* Second Pass: Go in reverse order, doing the same as before (except in opposite order) + + /* Second Pass: Go in reverse order, doing the same as before (except in opposite order) * - This pass covers the "before" edges of selection islands */ prev_sel = false; @@ -563,7 +563,7 @@ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) } } CTX_DATA_END; - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -575,11 +575,11 @@ void GPENCIL_OT_select_more(wmOperatorType *ot) ot->name = "Select More"; ot->idname = "GPENCIL_OT_select_more"; ot->description = "Grow sets of selected Grease Pencil points"; - + /* callbacks */ ot->exec = gpencil_select_more_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -595,8 +595,8 @@ static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) bGPDspoint *pt; int i; bool prev_sel; - - /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)... + + /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)... * - This pass covers the "after" edges of selection islands */ prev_sel = false; @@ -613,8 +613,8 @@ static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) prev_sel = false; } } - - /* Second Pass: Go in reverse order, doing the same as before (except in opposite order) + + /* Second Pass: Go in reverse order, doing the same as before (except in opposite order) * - This pass covers the "before" edges of selection islands */ prev_sel = false; @@ -634,7 +634,7 @@ static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) } } CTX_DATA_END; - + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -646,11 +646,11 @@ void GPENCIL_OT_select_less(wmOperatorType *ot) ot->name = "Select Less"; ot->idname = "GPENCIL_OT_select_less"; ot->description = "Shrink sets of selected Grease Pencil points"; - + /* callbacks */ ot->exec = gpencil_select_less_exec; ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -671,7 +671,7 @@ static bool gp_stroke_do_circle_sel( int x0 = 0, y0 = 0, x1 = 0, y1 = 0; int i; bool changed = false; - + if (gps->totpoints == 1) { if (!parented) { gp_point_to_xy(gsc, gps, gps->points, &x0, &y0); @@ -681,7 +681,7 @@ static bool gp_stroke_do_circle_sel( gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); } - + /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { /* only check if point is inside */ @@ -695,13 +695,13 @@ static bool gp_stroke_do_circle_sel( gps->points->flag &= ~GP_SPOINT_SELECT; gps->flag &= ~GP_STROKE_SELECT; } - + return true; } } } else { - /* Loop over the points in the stroke, checking for intersections + /* Loop over the points in the stroke, checking for intersections * - an intersection means that we touched the stroke */ for (i = 0; (i + 1) < gps->totpoints; i++) { @@ -720,43 +720,43 @@ static bool gp_stroke_do_circle_sel( gp_point_to_parent_space(pt2, diff_mat, &npt); gp_point_to_xy(gsc, gps, &npt, &x1, &y1); } - + /* check that point segment of the boundbox of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) { int mval[2] = {mx, my}; int mvalo[2] = {mx, my}; /* dummy - this isn't used... */ - + /* check if point segment of stroke had anything to do with * eraser region (either within stroke painted, or on its lines) * - this assumes that linewidth is irrelevant */ if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) { - /* change selection of stroke, and then of both points + /* change selection of stroke, and then of both points * (as the last point otherwise wouldn't get selected - * as we only do n-1 loops through) + * as we only do n-1 loops through) */ if (select) { pt1->flag |= GP_SPOINT_SELECT; pt2->flag |= GP_SPOINT_SELECT; - + changed = true; } else { pt1->flag &= ~GP_SPOINT_SELECT; pt2->flag &= ~GP_SPOINT_SELECT; - + changed = true; } } } } - + /* Ensure that stroke selection is in sync with its points */ BKE_gpencil_stroke_sync_selection(gps); } - + return changed; } @@ -764,36 +764,36 @@ static bool gp_stroke_do_circle_sel( static int gpencil_circle_select_exec(bContext *C, wmOperator *op) { ScrArea *sa = CTX_wm_area(C); - + const int mx = RNA_int_get(op->ptr, "x"); const int my = RNA_int_get(op->ptr, "y"); const int radius = RNA_int_get(op->ptr, "radius"); - + bool select = !RNA_boolean_get(op->ptr, "deselect"); - + GP_SpaceConversion gsc = {NULL}; rcti rect = {0}; /* for bounding rect around circle (for quicky intersection testing) */ - + bool changed = false; - - + + /* sanity checks */ if (sa == NULL) { BKE_report(op->reports, RPT_ERROR, "No active area"); return OPERATOR_CANCELLED; } - + /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); - - + + /* rect is rectangle of selection circle */ rect.xmin = mx - radius; rect.ymin = my - radius; rect.xmax = mx + radius; rect.ymax = my + radius; - - + + /* find visible strokes, and select if hit */ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) { @@ -807,7 +807,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op) if (changed) { WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } - + return OPERATOR_FINISHED; } @@ -817,17 +817,17 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot) ot->name = "Circle Select"; ot->description = "Select Grease Pencil strokes using brush selection"; ot->idname = "GPENCIL_OT_select_circle"; - + /* callbacks */ ot->invoke = WM_gesture_circle_invoke; ot->modal = WM_gesture_circle_modal; ot->exec = gpencil_circle_select_exec; ot->poll = gpencil_select_poll; ot->cancel = WM_gesture_circle_cancel; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ WM_operator_properties_gesture_circle_select(ot); } @@ -838,45 +838,45 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot) static int gpencil_border_select_exec(bContext *C, wmOperator *op) { ScrArea *sa = CTX_wm_area(C); - + const bool select = !RNA_boolean_get(op->ptr, "deselect"); const bool extend = RNA_boolean_get(op->ptr, "extend"); - + GP_SpaceConversion gsc = {NULL}; rcti rect = {0}; - + bool changed = false; - - + + /* sanity checks */ if (sa == NULL) { BKE_report(op->reports, RPT_ERROR, "No active area"); return OPERATOR_CANCELLED; } - + /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); - - + + /* deselect all strokes first? */ if (select && !extend) { CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } - + gps->flag &= ~GP_STROKE_SELECT; } CTX_DATA_END; } - + /* get settings from operator */ WM_operator_properties_border_to_rcti(op, &rect); - + /* select/deselect points */ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) { @@ -919,7 +919,7 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op) if (changed) { WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } - + return OPERATOR_FINISHED; } @@ -929,18 +929,18 @@ void GPENCIL_OT_select_border(wmOperatorType *ot) ot->name = "Border Select"; ot->description = "Select Grease Pencil strokes within a rectangular region"; ot->idname = "GPENCIL_OT_select_border"; - + /* callbacks */ ot->invoke = WM_gesture_border_invoke; ot->exec = gpencil_border_select_exec; ot->modal = WM_gesture_border_modal; ot->cancel = WM_gesture_border_cancel; - + ot->poll = gpencil_select_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* rna */ WM_operator_properties_gesture_border_select(ot); } @@ -952,41 +952,41 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) { GP_SpaceConversion gsc = {NULL}; rcti rect = {0}; - + const bool extend = RNA_boolean_get(op->ptr, "extend"); const bool select = !RNA_boolean_get(op->ptr, "deselect"); - + int mcords_tot; const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); - + bool changed = false; - + /* sanity check */ if (mcords == NULL) return OPERATOR_PASS_THROUGH; - + /* compute boundbox of lasso (for faster testing later) */ BLI_lasso_boundbox(&rect, mcords, mcords_tot); - + /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); - + /* deselect all strokes first? */ if (select && !extend) { CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { bGPDspoint *pt; int i; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } - + gps->flag &= ~GP_STROKE_SELECT; } CTX_DATA_END; } - + /* select/deselect points */ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) { @@ -1027,12 +1027,12 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) /* cleanup */ MEM_freeN((void *)mcords); - + /* updates */ if (changed) { WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } - + return OPERATOR_FINISHED; } @@ -1041,16 +1041,16 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot) ot->name = "Lasso Select Strokes"; ot->description = "Select Grease Pencil strokes using lasso selection"; ot->idname = "GPENCIL_OT_select_lasso"; - + ot->invoke = WM_gesture_lasso_invoke; ot->modal = WM_gesture_lasso_modal; ot->exec = gpencil_lasso_select_exec; ot->poll = gpencil_select_poll; ot->cancel = WM_gesture_lasso_cancel; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ WM_operator_properties_gesture_lasso_select(ot); } @@ -1061,36 +1061,36 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot) static int gpencil_select_exec(bContext *C, wmOperator *op) { ScrArea *sa = CTX_wm_area(C); - + /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ const float radius = 0.75f * U.widget_unit; const int radius_squared = (int)(radius * radius); - + bool extend = RNA_boolean_get(op->ptr, "extend"); bool deselect = RNA_boolean_get(op->ptr, "deselect"); bool toggle = RNA_boolean_get(op->ptr, "toggle"); bool whole = RNA_boolean_get(op->ptr, "entire_strokes"); - + int mval[2] = {0}; - + GP_SpaceConversion gsc = {NULL}; - + bGPDstroke *hit_stroke = NULL; bGPDspoint *hit_point = NULL; int hit_distance = radius_squared; - + /* sanity checks */ if (sa == NULL) { BKE_report(op->reports, RPT_ERROR, "No active area"); return OPERATOR_CANCELLED; } - + /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); - + /* get mouse location */ RNA_int_get_array(op->ptr, "location", mval); - + /* First Pass: Find stroke point which gets hit */ /* XXX: maybe we should go from the top of the stack down instead... */ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) @@ -1133,38 +1133,38 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) if (ELEM(NULL, hit_stroke, hit_point)) { return OPERATOR_CANCELLED; } - + /* adjust selection behaviour - for toggle option */ if (toggle) { deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0; } - + /* If not extending selection, deselect everything else */ if (extend == false) { CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) - { + { /* deselect stroke and its points if selected */ if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; - + /* deselect points */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { pt->flag &= ~GP_SPOINT_SELECT; } - + /* deselect stroke itself too */ gps->flag &= ~GP_STROKE_SELECT; } } CTX_DATA_END; } - + /* Perform selection operations... */ if (whole) { bGPDspoint *pt; int i; - + /* entire stroke's points */ for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) { if (deselect == false) @@ -1172,7 +1172,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) else pt->flag &= ~GP_SPOINT_SELECT; } - + /* stroke too... */ if (deselect == false) hit_stroke->flag |= GP_STROKE_SELECT; @@ -1189,17 +1189,17 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) else { /* deselect point */ hit_point->flag &= ~GP_SPOINT_SELECT; - + /* ensure that stroke is selected correctly */ BKE_gpencil_stroke_sync_selection(hit_stroke); } } - + /* updates */ if (hit_point != NULL) { WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } - + return OPERATOR_FINISHED; } @@ -1212,26 +1212,26 @@ static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *eve void GPENCIL_OT_select(wmOperatorType *ot) { PropertyRNA *prop; - + /* identifiers */ ot->name = "Select"; ot->description = "Select Grease Pencil strokes and/or stroke points"; ot->idname = "GPENCIL_OT_select"; - + /* callbacks */ ot->invoke = gpencil_select_invoke; ot->exec = gpencil_select_exec; ot->poll = gpencil_select_poll; - + /* flag */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ WM_operator_properties_mouse_select(ot); - + prop = RNA_def_boolean(ot->srna, "entire_strokes", false, "Entire Strokes", "Select entire strokes instead of just the nearest stroke vertex"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - + prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN); } diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 202d7630ae0..5e2be7c41f0 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -55,7 +55,7 @@ typedef struct bGPundonode { struct bGPundonode *next, *prev; - + char name[BKE_UNDO_STR_MAX]; struct bGPdata *gpd; } bGPundonode; @@ -71,9 +71,9 @@ int ED_gpencil_session_active(void) int ED_undo_gpencil_step(bContext *C, int step, const char *name) { bGPdata **gpd_ptr = NULL, *new_gpd = NULL; - + gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + if (step == 1) { /* undo */ //printf("\t\tGP - undo step\n"); if (cur_node->prev) { @@ -92,18 +92,18 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) } } } - + if (new_gpd) { if (gpd_ptr) { if (*gpd_ptr) { bGPdata *gpd = *gpd_ptr; bGPDlayer *gpl, *gpld; - + BKE_gpencil_free_layers(&gpd->layers); - + /* copy layers */ BLI_listbase_clear(&gpd->layers); - + for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) { /* make a copy of source layer and its data */ gpld = BKE_gpencil_layer_duplicate(gpl); @@ -112,9 +112,9 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) } } } - + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -129,7 +129,7 @@ static void gpencil_undo_free_node(bGPundonode *undo_node) * or else the real copy will segfault when accessed */ undo_node->gpd->adt = NULL; - + BKE_gpencil_free(undo_node->gpd, false); MEM_freeN(undo_node->gpd); } @@ -137,65 +137,65 @@ static void gpencil_undo_free_node(bGPundonode *undo_node) void gpencil_undo_push(bGPdata *gpd) { bGPundonode *undo_node; - + //printf("\t\tGP - undo push\n"); - + if (cur_node) { /* remove all un-done nodes from stack */ undo_node = cur_node->next; - + while (undo_node) { bGPundonode *next_node = undo_node->next; - + gpencil_undo_free_node(undo_node); BLI_freelinkN(&undo_nodes, undo_node); - + undo_node = next_node; } } - + /* limit number of undo steps to the maximum undo steps - * - to prevent running out of memory during **really** + * - to prevent running out of memory during **really** * long drawing sessions (triggering swapping) */ /* TODO: Undo-memory constraint is not respected yet, but can be added if we have any need for it */ if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) { /* remove anything older than n-steps before cur_node */ int steps = 0; - + undo_node = (cur_node) ? cur_node : undo_nodes.last; while (undo_node) { bGPundonode *prev_node = undo_node->prev; - + if (steps >= U.undosteps) { gpencil_undo_free_node(undo_node); BLI_freelinkN(&undo_nodes, undo_node); } - + steps++; undo_node = prev_node; } } - + /* create new undo node */ undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node"); undo_node->gpd = BKE_gpencil_data_duplicate(G.main, gpd, true); - + cur_node = undo_node; - + BLI_addtail(&undo_nodes, undo_node); } void gpencil_undo_finish(void) { bGPundonode *undo_node = undo_nodes.first; - + while (undo_node) { gpencil_undo_free_node(undo_node); undo_node = undo_node->next; } - + BLI_freelistN(&undo_nodes); - + cur_node = NULL; } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 0e08630d8bc..861fdcac080 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -82,16 +82,16 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr */ if (sa) { SpaceLink *sl = sa->spacedata.first; - + switch (sa->spacetype) { case SPACE_VIEW3D: /* 3D-View */ { BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src, GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT)); - + if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) { /* legacy behaviour for usage with old addons requiring object-linked to objects */ - + /* just in case no active/selected object... */ if (ob && (ob->flag & SELECT)) { /* for now, as long as there's an object, default to using that in 3D-View */ @@ -109,21 +109,21 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr case SPACE_NODE: /* Nodes Editor */ { SpaceNode *snode = (SpaceNode *)sl; - + /* return the GP data for the active node block/node */ if (snode && snode->nodetree) { /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */ if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr); return &snode->nodetree->gpd; } - + /* even when there is no node-tree, don't allow this to flow to scene */ return NULL; } case SPACE_SEQ: /* Sequencer */ { SpaceSeq *sseq = (SpaceSeq *)sl; - + /* for now, Grease Pencil data is associated with the space (actually preview region only) */ /* XXX our convention for everything else is to link to data though... */ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr); @@ -132,7 +132,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr case SPACE_IMAGE: /* Image/UV Editor */ { SpaceImage *sima = (SpaceImage *)sl; - + /* for now, Grease Pencil data is associated with the space... */ /* XXX our convention for everything else is to link to data though... */ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr); @@ -142,23 +142,23 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr { SpaceClip *sc = (SpaceClip *)sl; MovieClip *clip = ED_space_clip_get_clip(sc); - + if (clip) { if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking); - + if (!track) return NULL; - + if (ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr); - + return &track->gpd; } else { if (ptr) RNA_id_pointer_create(&clip->id, ptr); - + return &clip->gpd; } } @@ -168,7 +168,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr return NULL; } } - + /* just fall back on the scene's GP data */ if (ptr) RNA_id_pointer_create((ID *)scene, ptr); return (scene) ? &scene->gpd : NULL; @@ -181,7 +181,7 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); Object *ob = CTX_data_active_object(C); - + return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr); } @@ -211,7 +211,7 @@ bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, ViewLayer *view_layer) /* We have to make sure active object is actually visible and selected, else we must use default scene gpd, * to be consistent with ED_gpencil_data_get_active's behavior. */ - + if (base && TESTBASE(base)) { gpd = base->object->gpd; } @@ -239,7 +239,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra) } } } - + if (ob && ob->gpd) { bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->gpd); if (gpl) { @@ -253,7 +253,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra) } } } - + return false; } @@ -272,7 +272,7 @@ int gp_active_layer_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - + return (gpl != NULL); } @@ -317,25 +317,25 @@ const EnumPropertyItem *ED_gpencil_layers_enum_itemf( EnumPropertyItem *item = NULL, item_tmp = {0}; int totitem = 0; int i = 0; - + if (ELEM(NULL, C, gpd)) { return DummyRNA_DEFAULT_items; } - + /* Existing layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) { item_tmp.identifier = gpl->info; item_tmp.name = gpl->info; item_tmp.value = i; - + if (gpl->flag & GP_LAYER_ACTIVE) item_tmp.icon = ICON_GREASEPENCIL; - else + else item_tmp.icon = ICON_NONE; - + RNA_enum_item_add(&item, &totitem, &item_tmp); } - + RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -351,11 +351,11 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf( EnumPropertyItem *item = NULL, item_tmp = {0}; int totitem = 0; int i = 0; - + if (ELEM(NULL, C, gpd)) { return DummyRNA_DEFAULT_items; } - + /* Create new layer */ /* TODO: have some way of specifying that we don't want this? */ { @@ -365,25 +365,25 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf( item_tmp.value = -1; item_tmp.icon = ICON_ZOOMIN; RNA_enum_item_add(&item, &totitem, &item_tmp); - + /* separator */ RNA_enum_item_add_separator(&item, &totitem); } - + /* Existing layers */ for (gpl = gpd->layers.first, i = 0; gpl; gpl = gpl->next, i++) { item_tmp.identifier = gpl->info; item_tmp.name = gpl->info; item_tmp.value = i; - + if (gpl->flag & GP_LAYER_ACTIVE) item_tmp.icon = ICON_GREASEPENCIL; - else + else item_tmp.icon = ICON_NONE; - + RNA_enum_item_add(&item, &totitem, &item_tmp); } - + RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -412,11 +412,11 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]), const float mval_fl[2] = {mval[0], mval[1]}; const float screen_co_a[2] = {x0, y0}; const float screen_co_b[2] = {x1, y1}; - + if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) { return true; } - + /* not inside */ return false; } @@ -469,7 +469,7 @@ bool ED_gpencil_stroke_color_use(const bGPDlayer *gpl, const bGPDstroke *gps) if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) return false; } - + return true; } @@ -524,16 +524,16 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - + /* zero out the storage (just in case) */ memset(r_gsc, 0, sizeof(GP_SpaceConversion)); unit_m4(r_gsc->mat); - + /* store settings */ r_gsc->sa = sa; r_gsc->ar = ar; r_gsc->v2d = &ar->v2d; - + /* init region-specific stuff */ if (sa->spacetype == SPACE_VIEW3D) { wmWindow *win = CTX_wm_window(C); @@ -541,13 +541,13 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) struct Depsgraph *depsgraph = CTX_data_depsgraph(C); View3D *v3d = (View3D *)CTX_wm_space_data(C); RegionView3D *rv3d = ar->regiondata; - + /* init 3d depth buffers */ view3d_operator_needs_opengl(C); - + view3d_region_operator_needs_opengl(win, ar); ED_view3d_autodist_init(depsgraph, ar, v3d, 0); - + /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */ @@ -563,7 +563,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) * \param diff_mat Matrix with the difference between original parent matrix * \param[out] r_pt Pointer to new point after apply matrix */ -void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt) +void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt) { float fpt[3]; @@ -626,12 +626,12 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, View2D *v2d = gsc->v2d; rctf *subrect = gsc->subrect; int xyval[2]; - + /* sanity checks */ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D)); BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D)); - - + + if (gps->flag & GP_STROKE_3DSPACE) { if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { *r_x = xyval[0]; @@ -679,12 +679,12 @@ void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, View2D *v2d = gsc->v2d; rctf *subrect = gsc->subrect; float xyval[2]; - + /* sanity checks */ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D)); BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D)); - - + + if (gps->flag & GP_STROKE_3DSPACE) { if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { *r_x = xyval[0]; @@ -698,10 +698,10 @@ void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, else if (gps->flag & GP_STROKE_2DSPACE) { float vec[3] = {pt->x, pt->y, 0.0f}; int t_x, t_y; - + mul_m4_v3(gsc->mat, vec); UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y); - + if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) { /* XXX: Or should we just always use the values as-is? */ *r_x = 0.0f; @@ -748,22 +748,22 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen float *rvec = ED_view3d_cursor3d_get(scene, v3d)->location; float ref[3] = {rvec[0], rvec[1], rvec[2]}; float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - + float mval_f[2], mval_prj[2]; float dvec[3]; - + copy_v2_v2(mval_f, screen_co); - + if (ED_view3d_project_float_global(gsc->ar, ref, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { sub_v2_v2v2(mval_f, mval_prj, mval_f); ED_view3d_win_to_delta(gsc->ar, mval_f, dvec, zfac); sub_v3_v3v3(r_out, rvec, dvec); - + return true; } else { zero_v3(r_out); - + return false; } } @@ -780,19 +780,19 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) bGPDspoint *pt = &gps->points[i]; float pressure = 0.0f; float sco[3] = {0.0f}; - + /* Do nothing if not enough points to smooth out */ if (gps->totpoints <= 2) { return false; } - + /* Only affect endpoints by a fraction of the normal strength, * to prevent the stroke from shrinking too much */ if ((i == 0) || (i == gps->totpoints - 1)) { inf *= 0.1f; } - + /* Compute smoothed coordinate by taking the ones nearby */ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */ { @@ -800,14 +800,14 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) const int steps = 2; const float average_fac = 1.0f / (float)(steps * 2 + 1); int step; - + /* add the point itself */ madd_v3_v3fl(sco, &pt->x, average_fac); - + if (affect_pressure) { pressure += pt->pressure * average_fac; } - + /* n-steps before/after current point */ // XXX: review how the endpoints are treated by this algorithm // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight @@ -815,17 +815,17 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) bGPDspoint *pt1, *pt2; int before = i - step; int after = i + step; - + CLAMP_MIN(before, 0); CLAMP_MAX(after, gps->totpoints - 1); - + pt1 = &gps->points[before]; pt2 = &gps->points[after]; - + /* add both these points to the average-sum (s += p[i]/n) */ madd_v3_v3fl(sco, &pt1->x, average_fac); madd_v3_v3fl(sco, &pt2->x, average_fac); - + #if 0 /* XXX: Disabled because get weird result */ /* do pressure too? */ @@ -836,17 +836,17 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) #endif } } - + /* Based on influence factor, blend between original and optimal smoothed coordinate */ interp_v3_v3v3(&pt->x, &pt->x, sco, inf); - + #if 0 /* XXX: Disabled because get weird result */ if (affect_pressure) { pt->pressure = pressure; } #endif - + return true; } @@ -939,22 +939,22 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints) gps->points[new_totpoints - y] = gps->points[i]; y += 2; } - + /* Create interpolated points */ for (int i = 0; i < new_totpoints - 1; i += 2) { bGPDspoint *prev = &gps->points[i]; bGPDspoint *pt = &gps->points[i + 1]; bGPDspoint *next = &gps->points[i + 2]; - + /* Interpolate all values */ interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f); - + pt->pressure = interpf(prev->pressure, next->pressure, 0.5f); pt->strength = interpf(prev->strength, next->strength, 0.5f); CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = interpf(prev->time, next->time, 0.5f); } - + /* Update to new total number of points */ gps->totpoints = new_totpoints; } @@ -987,12 +987,12 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush) float normal[3]; cross_v3_v3v3(normal, v1, v2); normalize_v3(normal); - + /* get orthogonal vector to plane to rotate random effect */ float ortho[3]; cross_v3_v3v3(ortho, v1, normal); normalize_v3(ortho); - + /* Read all points and apply shift vector (first and last point not modified) */ for (int i = 1; i < gps->totpoints - 1; ++i) { bGPDspoint *pt = &gps->points[i]; |