Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/curve/editcurve.c
| Context not available. | |||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /***************** rip edge move operator ********************/ | |||||
| void copy_and_increment(int **pos, void **dest, int value, void *src, bool is_bezier) | |||||
| { | |||||
| /*copy src to dest and value to pos then increment both dest and pos*/ | |||||
| **pos = value; | |||||
| (*pos)++; | |||||
| if (is_bezier) { | |||||
| BezTriple *src_bezt = src; | |||||
| BezTriple **dest_bez = dest; | |||||
| **dest_bez = *src_bezt; | |||||
| BEZT_SEL_ALL(*dest_bez); | |||||
| (*dest_bez)++; | |||||
| } | |||||
| else { | |||||
| BPoint *src_bp = src; | |||||
| BPoint **dest_bp = dest; | |||||
| **dest_bp = *src_bp; | |||||
| (*dest_bp)++; | |||||
| } | |||||
| } | |||||
| static int curve_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) | |||||
| { | |||||
| ARegion *ar = CTX_wm_region(C); | |||||
| RegionView3D *rv3d = CTX_wm_region_view3d(C); | |||||
| Object *obedit = CTX_data_edit_object(C); | |||||
| Curve *cu = obedit->data; | |||||
| EditNurb *editnurb = cu->editnurb; | |||||
| float ProjectMat[4][4]; | |||||
| const float mval_fl[2] = { UNPACK2(event->mval) }; | |||||
| float cent_sco[2]; | |||||
| float mval_dir[2]; | |||||
| int total_rips = 0; //Total points ripped | |||||
| bool mid_select, changed = false; | |||||
| ED_view3d_ob_project_mat_get(rv3d, obedit, ProjectMat); | |||||
| zero_v2(cent_sco); | |||||
| for (Nurb *nu = editnurb->nurbs.first; nu; nu = nu->next) { | |||||
| if (nu->type == CU_BEZIER) { | |||||
| BezTriple *bezt = nu->bezt; | |||||
| for (int i = 0; i < nu->pntsu; i++, bezt++) { | |||||
| if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) { | |||||
| /* Calculate total number of points to be ripped */ | |||||
| if (nu->flagu == CU_NURB_CYCLIC) { //if prev and next are selected then current point will not be ripped | |||||
| mid_select = BEZT_ISSEL_ANY_HIDDENHANDLES(cu, BKE_nurb_bezt_get_next(nu, bezt)) & | |||||
| BEZT_ISSEL_ANY_HIDDENHANDLES(cu, BKE_nurb_bezt_get_prev(nu, bezt)); | |||||
| if (!mid_select) | |||||
| total_rips++; | |||||
| } | |||||
| else if (i > 0 && i < nu->pntsu - 1) { | |||||
| mid_select = BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt - 1) & BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt + 1); | |||||
| if (!mid_select) | |||||
| total_rips++; | |||||
| } | |||||
| else | |||||
| total_rips++; | |||||
| float bezt_sco[2]; | |||||
| ED_view3d_project_float_v2_m4(ar, bezt->vec[1], bezt_sco, ProjectMat); | |||||
| add_v2_v2(cent_sco, bezt_sco); | |||||
| } | |||||
| } | |||||
| mul_v2_fl(cent_sco, 1.0f / (float)total_rips); | |||||
| sub_v2_v2v2(mval_dir, mval_fl, cent_sco); | |||||
| normalize_v2(mval_dir); | |||||
| BezTriple *bezt_new = MEM_mallocN((nu->pntsu + total_rips) * sizeof(BezTriple), __func__); | |||||
| int *store_loc = MEM_mallocN(total_rips * sizeof(int), __func__); //Array to store location of new BezTriple inserted | |||||
| int *pos = store_loc; | |||||
| BezTriple *save_bez = MEM_mallocN(total_rips * sizeof(BezTriple), __func__); //Array to store data of new BezTriple inserted | |||||
| BezTriple *store_bez = save_bez; | |||||
| bezt = nu->bezt; | |||||
| /* Get points that are ripped from src and store location, data in store_loc and save_bez */ | |||||
| for (int i = 0; i < nu->pntsu; i++, bezt++) { | |||||
| if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) { | |||||
| BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt), *prev = BKE_nurb_bezt_get_prev(nu, bezt); | |||||
| if (next != NULL && prev != NULL && !BEZT_ISSEL_ANY_HIDDENHANDLES(cu, next) | |||||
| && !BEZT_ISSEL_ANY_HIDDENHANDLES(cu, prev)) { | |||||
| float bezt_sco[2]; //if both previous and next exist rip from closest | |||||
| ED_view3d_project_float_v2_m4(ar, bezt->vec[1], bezt_sco, ProjectMat); | |||||
| float prev_sco[2], prev_dir[2]; | |||||
| ED_view3d_project_float_v2_m4(ar, prev->vec[1], prev_sco, ProjectMat); | |||||
| sub_v2_v2v2(prev_dir, prev_sco, bezt_sco); | |||||
| normalize_v2(prev_dir); | |||||
| float next_sco[2], next_dir[2]; | |||||
| ED_view3d_project_float_v2_m4(ar, next->vec[1], next_sco, ProjectMat); | |||||
| sub_v2_v2v2(next_dir, next_sco, bezt_sco); | |||||
| normalize_v2(next_dir); | |||||
| float angle_prev = angle_normalized_v2v2(mval_dir, prev_dir); | |||||
| float angle_next = angle_normalized_v2v2(mval_dir, next_dir); | |||||
| if (angle_next < angle_prev) { | |||||
| copy_and_increment(&pos, &store_bez, i + 1, bezt, true); | |||||
| } | |||||
| else { | |||||
| copy_and_increment(&pos, &store_bez, i, bezt, true); | |||||
| } | |||||
| BEZT_DESEL_ALL(bezt); | |||||
| changed = true; | |||||
| } | |||||
| else if (next != NULL && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, next)) { | |||||
| /*if next exists and is selected skip to last selected point and rip first and last BezTriple selected*/ | |||||
| if (nu->flagu == CU_NURB_CYCLIC && prev != NULL && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, prev)) { | |||||
| continue; //if prev point is selected, continue and loop to that point then operate | |||||
| } | |||||
| copy_and_increment(&pos, &store_bez, i + 1, bezt, true); | |||||
| int skip = 1; | |||||
| while (BKE_nurb_bezt_get_next(nu, next) && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, BKE_nurb_bezt_get_next(nu, next))) { | |||||
| next = BKE_nurb_bezt_get_next(nu, next); | |||||
| if (next == bezt) { //if all points are selected, do nothing | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| skip++; | |||||
| } | |||||
| copy_and_increment(&pos, &store_bez, i + skip, next, true); | |||||
| BEZT_DESEL_ALL(bezt); | |||||
| BEZT_DESEL_ALL(next); | |||||
| i += skip; | |||||
| bezt += skip; | |||||
| changed = true; | |||||
| } | |||||
| else if (prev == NULL) { | |||||
| copy_and_increment(&pos, &store_bez, i + 1, bezt, true); | |||||
| BEZT_DESEL_ALL(bezt); | |||||
| changed = true; | |||||
| } | |||||
| else if (next == NULL) { | |||||
| copy_and_increment(&pos, &store_bez, i, bezt, true); | |||||
| BEZT_DESEL_ALL(bezt); | |||||
| changed = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| pos = store_loc; | |||||
| store_bez = save_bez; | |||||
| bezt = nu->bezt; | |||||
| /* store old bezt and new bezt that are ripped(stored in save_bez) in bezt_new */ | |||||
| if (changed) { | |||||
| int i, j; | |||||
| for (i = 0, j = 0; i < nu->pntsu;) { | |||||
| if (i == *pos) { | |||||
| ED_curve_beztcpy(editnurb, bezt_new + i + j, store_bez, 1); | |||||
| store_bez++; | |||||
| pos++; | |||||
| j++; | |||||
| } | |||||
| else { | |||||
| ED_curve_beztcpy(editnurb, bezt_new + i + j, bezt, 1); | |||||
| i++; | |||||
| bezt++; | |||||
| } | |||||
| } | |||||
| if (nu->flagu == CU_NURB_CYCLIC && i == *pos) { //if curve is cyclic and last BezTriple is selected | |||||
| ED_curve_beztcpy(editnurb, bezt_new + i + j, store_bez, 1); | |||||
| pos++; | |||||
| store_bez++; | |||||
| j++; | |||||
| } | |||||
| if (j < total_rips) { //if curve is cyclic and any points (0, 1, ..... ,i) and n are selected; 0 < i < n | |||||
| BezTriple *bez_temp = MEM_mallocN((nu->pntsu + total_rips) * sizeof(BezTriple), __func__); | |||||
| ED_curve_beztcpy(editnurb, bez_temp, bezt_new, *pos % nu->pntsu); | |||||
| ED_curve_beztcpy(editnurb, bez_temp + *pos % nu->pntsu, store_bez, 1); | |||||
| ED_curve_beztcpy(editnurb, bez_temp + *pos % nu->pntsu + 1, bezt_new + *pos % nu->pntsu, nu->pntsu + total_rips - *pos % nu->pntsu - 1); | |||||
| MEM_freeN(bezt_new); | |||||
| bezt_new = bez_temp; | |||||
| } | |||||
| MEM_freeN(store_loc); | |||||
| MEM_freeN(save_bez); | |||||
| MEM_freeN(nu->bezt); | |||||
| nu->bezt = bezt_new; | |||||
| nu->pntsu += total_rips; | |||||
| } | |||||
| } | |||||
| else { | |||||
| BPoint *bp = nu->bp; | |||||
| for (int i = 0; i < nu->pntsu; i++, bp++) { | |||||
| if (bp->f1 & SELECT) { | |||||
| /* Calculate total number of points to be ripped */ | |||||
| if (nu->flagu == CU_NURB_CYCLIC) { //if prev and next are selected then current point will not be ripped | |||||
| mid_select = BKE_nurb_bpoint_get_next(nu, bp)->f1 & BKE_nurb_bpoint_get_prev(nu, bp)->f1 & SELECT; | |||||
| if (!mid_select) | |||||
| total_rips++; | |||||
| } | |||||
| else if (i > 0 && i < nu->pntsu - 1) { | |||||
| mid_select = (bp - 1)->f1 & (bp + 1)->f1 & SELECT; | |||||
| if (!mid_select) { | |||||
| total_rips++; | |||||
| } | |||||
| } | |||||
| else | |||||
| total_rips++; | |||||
| float bp_sco[2]; | |||||
| ED_view3d_project_float_v2_m4(ar, bp->vec, bp_sco, ProjectMat); | |||||
| add_v2_v2(cent_sco, bp_sco); | |||||
| } | |||||
| } | |||||
| mul_v2_fl(cent_sco, 1.0f / (float)total_rips); | |||||
| sub_v2_v2v2(mval_dir, mval_fl, cent_sco); | |||||
| normalize_v2(mval_dir); | |||||
| BPoint *bp_new = MEM_mallocN((nu->pntsu + total_rips) * sizeof(BPoint), __func__); | |||||
| int *store_loc = MEM_mallocN(total_rips * sizeof(int), __func__); //Array to store location of new BPoints inserted | |||||
| int *pos = store_loc; | |||||
| BPoint *save_bp = MEM_mallocN(total_rips * sizeof(BPoint), __func__); //Array to store data of new BPoints inserted | |||||
| BPoint *store_bp = save_bp; | |||||
| bp = nu->bp; | |||||
| for (int i = 0; i < nu->pntsu; i++, bp++) { | |||||
| if (bp->f1 & SELECT) { | |||||
| BPoint *next = BKE_nurb_bpoint_get_next(nu, bp), *prev = BKE_nurb_bpoint_get_prev(nu, bp); | |||||
| if (next != NULL && prev != NULL && !(next->f1 & SELECT) && !(prev->f1 & SELECT)) { | |||||
| float bp_sco[2]; //if both previous and next exist rip from closest | |||||
| ED_view3d_project_float_v2_m4(ar, bp->vec, bp_sco, ProjectMat); | |||||
| float prev_sco[2], prev_dir[2]; | |||||
| ED_view3d_project_float_v2_m4(ar, prev->vec, prev_sco, ProjectMat); | |||||
| sub_v2_v2v2(prev_dir, prev_sco, bp_sco); | |||||
| normalize_v2(prev_dir); | |||||
| float next_sco[2], next_dir[2]; | |||||
| ED_view3d_project_float_v2_m4(ar, next->vec, next_sco, ProjectMat); | |||||
| sub_v2_v2v2(next_dir, next_sco, bp_sco); | |||||
| normalize_v2(next_dir); | |||||
| float angle_prev = angle_normalized_v2v2(mval_dir, prev_dir); | |||||
| float angle_next = angle_normalized_v2v2(mval_dir, next_dir); | |||||
| if (angle_next < angle_prev) { | |||||
| copy_and_increment(&pos, &store_bp, i + 1, bp, false); | |||||
| } | |||||
| else { | |||||
| copy_and_increment(&pos, &store_bp, i, bp, false); | |||||
| } | |||||
| bp->f1 &= ~SELECT; | |||||
| changed = true; | |||||
| } | |||||
| else if (next != NULL && next->f1 & SELECT) { | |||||
| /*if next exists and is selected skip to last selected point and rip first and last BPoints selected*/ | |||||
| if (nu->flagu == CU_NURB_CYCLIC && prev!= NULL && prev->f1 & SELECT) { | |||||
| continue; //if prev point is selected, continue and loop to that point then operate | |||||
| } | |||||
| copy_and_increment(&pos, &store_bp, i + 1, bp, false); | |||||
| int skip = 1; | |||||
| while (BKE_nurb_bpoint_get_next(nu, next) && (BKE_nurb_bpoint_get_next(nu, next)->f1 & SELECT)) { | |||||
| next = BKE_nurb_bpoint_get_next(nu, next); | |||||
| if (next == bp) { //if all points are selected, do nothing | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| skip++; | |||||
| } | |||||
| copy_and_increment(&pos, &store_bp, i + skip, next, false); | |||||
| bp->f1 &= ~SELECT; | |||||
| next->f1 &= ~SELECT; | |||||
| i += skip; | |||||
| bp += skip; | |||||
| changed = true; | |||||
| } | |||||
| else if (prev == NULL) { | |||||
| copy_and_increment(&pos, &store_bp, i + 1, bp, false); | |||||
| bp->f1 &= ~SELECT; | |||||
| changed = true; | |||||
| } | |||||
| else if (next == NULL) { | |||||
| copy_and_increment(&pos, &store_bp, i, bp, false); | |||||
| bp->f1 &= ~SELECT; | |||||
| changed = true; | |||||
| } | |||||
| } | |||||
| } | |||||
| pos = store_loc; | |||||
| store_bp = save_bp; | |||||
| bp = nu->bp; | |||||
| /* store old BPoints and new BPoints (stored in save_bp) in bp_new */ | |||||
| if (changed) { | |||||
| int i, j; | |||||
| for (i = 0, j = 0; i < nu->pntsu;) { | |||||
| if (i == *pos) { | |||||
| ED_curve_bpcpy(editnurb, bp_new + i + j, store_bp, 1); | |||||
| store_bp++; | |||||
| pos++; | |||||
| j++; | |||||
| } | |||||
| else { | |||||
| ED_curve_bpcpy(editnurb, bp_new + i + j, bp, 1); | |||||
| i++; | |||||
| bp++; | |||||
| } | |||||
| } | |||||
| if (nu-> flagu == CU_NURB_CYCLIC && i == *pos) { //if curve is cyclic and last BPoint is selected | |||||
| ED_curve_bpcpy(editnurb, bp_new + i + j, store_bp, 1); | |||||
| pos++; | |||||
| store_bp++; | |||||
| j++; | |||||
| } | |||||
| if(j < total_rips) { //if curve is cyclic and any points (0, 1, ..... ,i) and n are selected; 0 < i < n | |||||
| BPoint *bp_temp = MEM_mallocN((nu->pntsu + total_rips) * sizeof(BPoint), __func__); | |||||
| ED_curve_bpcpy(editnurb, bp_temp, bp_new, *pos % nu->pntsu); | |||||
| ED_curve_bpcpy(editnurb, bp_temp + *pos % nu->pntsu, store_bp, 1); | |||||
| ED_curve_bpcpy(editnurb, bp_temp + *pos % nu->pntsu + 1, bp_new + *pos % nu->pntsu, nu->pntsu + total_rips - *pos % nu->pntsu - 1); | |||||
| MEM_freeN(bp_new); | |||||
| bp_new = bp_temp; | |||||
| } | |||||
| MEM_freeN(store_loc); | |||||
| MEM_freeN(save_bp); | |||||
| MEM_freeN(nu->bp); | |||||
| nu->bp = bp_new; | |||||
| nu->pntsu += total_rips; | |||||
| BKE_nurb_knot_calc_u(nu); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (changed) { | |||||
| if (ED_curve_updateAnimPaths(obedit->data)) { | |||||
| WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); | |||||
| } | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); | |||||
| DAG_id_tag_update(obedit->data, 0); | |||||
| } | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void CURVE_OT_rip_edge(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Curve Rip Operator"; | |||||
| ot->idname = "CURVE_OT_rip_edge"; | |||||
| ot->description = "Rip the selected point(s)"; | |||||
| /* api callbacks */ | |||||
| ot->invoke = curve_rip_edge_invoke; | |||||
| ot->poll = ED_operator_editsurfcurve; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | |||||
| Context not available. | |||||