static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, const bool add_end_point, tGpTimingData *gtd) { bGPDspoint *pt; Nurb *nu = (curnu) ? *curnu : NULL; BezTriple *bezt, *prev_bezt = NULL; int i, tot, old_nbezt = 0; 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; /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke, * so no need to add it. * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes. */ BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points); } 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) { gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect); if (tot > 1) { gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect); } if (stitch && tot > 2) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } } /* If needed, make the link between both strokes with two zero-radius additional points */ if (curnu && old_nbezt) { BLI_assert(gps->prev != NULL); /* Update last point's second handle */ if (stitch) { bezt = &nu->bezt[old_nbezt - 1]; interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC); 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 * the last segment to get the first point (p1) position and timing. * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point * with the first point of the current stroke. * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated * if it exists, else (if the stroke is a single point), linear interpolation with last curve point... */ 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); if (do_gtd) { const int idx = gps->prev->totpoints - 1; dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC); } } else { interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC); if (do_gtd) { 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) { interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC); if (do_gtd) { dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC); } } else { interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC); if (do_gtd) { 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); } } 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) { dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC); } } else { copy_v3_v3(p, p3d_cur); p[0] -= GAP_DFAC; /* Rather arbitrary... */ dt = -GAP_DFAC; /* Rather arbitrary too! */ } interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC); bezt = &nu->bezt[old_nbezt]; gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights); old_nbezt++; copy_v3_v3(p3d_prev, p); } if (old_nbezt) { prev_bezt = &nu->bezt[old_nbezt - 1]; } /* add points */ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) { float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC; if (i || old_nbezt) { interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC); } if (i < tot - 1) { interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC); } gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur, do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights); /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); if (i + 2 < tot) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } prev_bezt = bezt; } if (add_end_point) { float p[3]; float dt = 0.0f; if (gps->totpoints > 1) { interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC); if (do_gtd) { const int idx = gps->totpoints - 1; dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC); } } else { copy_v3_v3(p, prev_bezt->vec[1]); 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); /* Note bezt has already been incremented in main loop above, so it points to the right place. */ 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); } if (curnu) { *curnu = nu; } }
Nurb *ED_curve_add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob) { static int xzproj = 0; /* this function calls itself... */ ListBase *editnurb = object_editcurve_get(obedit); RegionView3D *rv3d = ED_view3d_context_rv3d(C); Nurb *nu = NULL; BezTriple *bezt; BPoint *bp; Curve *cu = (Curve *)obedit->data; float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f}; float umat[4][4], viewmat[4][4]; float fac; int a, b; const float grid = 1.0f; const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc const int stype = (type & CU_PRIMITIVE); unit_m4(umat); unit_m4(viewmat); if (rv3d) { copy_m4_m4(viewmat, rv3d->viewmat); copy_v3_v3(zvec, rv3d->viewinv[2]); } BKE_nurbList_flag_set(editnurb, 0); /* these types call this function to return a Nurb */ if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "addNurbprim"); nu->type = cutype; nu->resolu = cu->resolu; nu->resolv = cu->resolv; } switch (stype) { case CU_PRIM_CURVE: /* curve */ nu->resolu = cu->resolu; if (cutype == CU_BEZIER) { nu->pntsu = 2; nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1"); bezt = nu->bezt; bezt->h1 = bezt->h2 = HD_ALIGN; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->radius = 1.0; bezt->vec[1][0] += -grid; bezt->vec[0][0] += -1.5f * grid; bezt->vec[0][1] += -0.5f * grid; bezt->vec[2][0] += -0.5f * grid; bezt->vec[2][1] += 0.5f * grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt++; bezt->h1 = bezt->h2 = HD_ALIGN; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->radius = bezt->weight = 1.0; bezt->vec[0][0] = 0; bezt->vec[0][1] = 0; bezt->vec[1][0] = grid; bezt->vec[1][1] = 0; bezt->vec[2][0] = grid * 2; bezt->vec[2][1] = 0; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); BKE_nurb_handles_calc(nu); } else { nu->pntsu = 4; nu->pntsv = 1; nu->orderu = 4; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 4, "addNurbprim3"); bp = nu->bp; for (a = 0; a < 4; a++, bp++) { bp->vec[3] = 1.0; bp->f1 = SELECT; bp->radius = bp->weight = 1.0; } bp = nu->bp; bp->vec[0] += -1.5f * grid; bp++; bp->vec[0] += -grid; bp->vec[1] += grid; bp++; bp->vec[0] += grid; bp->vec[1] += grid; bp++; bp->vec[0] += 1.5f * grid; bp = nu->bp; for (a = 0; a < 4; a++, bp++) mul_m4_v3(mat, bp->vec); if (cutype == CU_NURBS) { nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ BKE_nurb_knot_calc_u(nu); } } break; case CU_PRIM_PATH: /* 5 point path */ nu->pntsu = 5; nu->pntsv = 1; nu->orderu = 5; nu->flagu = CU_NURB_ENDPOINT; /* endpoint */ nu->resolu = cu->resolu; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim3"); bp = nu->bp; for (a = 0; a < 5; a++, bp++) { bp->vec[3] = 1.0; bp->f1 = SELECT; bp->radius = bp->weight = 1.0; } bp = nu->bp; bp->vec[0] += -2.0f * grid; bp++; bp->vec[0] += -grid; bp++; bp++; bp->vec[0] += grid; bp++; bp->vec[0] += 2.0f * grid; bp = nu->bp; for (a = 0; a < 5; a++, bp++) mul_m4_v3(mat, bp->vec); if (cutype == CU_NURBS) { nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ BKE_nurb_knot_calc_u(nu); } break; case CU_PRIM_CIRCLE: /* circle */ nu->resolu = cu->resolu; if (cutype == CU_BEZIER) { nu->pntsu = 4; nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1"); nu->flagu = CU_NURB_CYCLIC; bezt = nu->bezt; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][0] += -grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; bezt++; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][1] += grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; bezt++; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][0] += grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; bezt++; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][1] += -grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; BKE_nurb_handles_calc(nu); } else if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 8; nu->pntsv = 1; nu->orderu = 4; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 8, "addNurbprim6"); nu->flagu = CU_NURB_CYCLIC; bp = nu->bp; for (a = 0; a < 8; a++) { bp->f1 = SELECT; if (xzproj == 0) { bp->vec[0] += nurbcircle[a][0] * grid; bp->vec[1] += nurbcircle[a][1] * grid; } else { bp->vec[0] += 0.25f * nurbcircle[a][0] * grid - 0.75f * grid; bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; } if (a & 1) bp->vec[3] = 0.25 * M_SQRT2; else bp->vec[3] = 1.0; mul_m4_v3(mat, bp->vec); bp->radius = bp->weight = 1.0; bp++; } BKE_nurb_knot_calc_u(nu); } break; case CU_PRIM_PATCH: /* 4x4 patch */ if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 4; nu->pntsv = 4; nu->orderu = 4; nu->orderv = 4; nu->flag = CU_SMOOTH; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * (4 * 4), "addNurbprim6"); nu->flagu = 0; nu->flagv = 0; bp = nu->bp; for (a = 0; a < 4; a++) { for (b = 0; b < 4; b++) { bp->f1 = SELECT; fac = (float)a - 1.5f; bp->vec[0] += fac * grid; fac = (float)b - 1.5f; bp->vec[1] += fac * grid; if ((a == 1 || a == 2) && (b == 1 || b == 2)) { bp->vec[2] += grid; } mul_m4_v3(mat, bp->vec); bp->vec[3] = 1.0; bp++; } } BKE_nurb_knot_calc_u(nu); BKE_nurb_knot_calc_v(nu); } break; case CU_PRIM_TUBE: /* Cylinder */ if (cutype == CU_NURBS) { nu = ED_curve_add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ nu->resolu = cu->resolu; nu->flag = CU_SMOOTH; BLI_addtail(editnurb, nu); /* temporal for extrude and translate */ vec[0] = vec[1] = 0.0; vec[2] = -grid; mul_mat3_m4_v3(mat, vec); ed_editnurb_translate_flag(editnurb, SELECT, vec); ed_editnurb_extrude_flag(cu->editnurb, SELECT); mul_v3_fl(vec, -2.0f); ed_editnurb_translate_flag(editnurb, SELECT, vec); BLI_remlink(editnurb, nu); a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a-- > 0) { bp->f1 |= SELECT; bp++; } } break; case CU_PRIM_SPHERE: /* sphere */ if (cutype == CU_NURBS) { float tmp_cent[3] = {0.f, 0.f, 0.f}; float tmp_vec[3] = {0.f, 0.f, 1.f}; nu->pntsu = 5; nu->pntsv = 1; nu->orderu = 3; nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->flag = CU_SMOOTH; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim6"); nu->flagu = 0; bp = nu->bp; for (a = 0; a < 5; a++) { bp->f1 = SELECT; bp->vec[0] += nurbcircle[a][0] * grid; bp->vec[2] += nurbcircle[a][1] * grid; if (a & 1) bp->vec[3] = 0.5 * M_SQRT2; else bp->vec[3] = 1.0; mul_m4_v3(mat, bp->vec); bp++; } nu->flagu = CU_NURB_BEZIER; BKE_nurb_knot_calc_u(nu); BLI_addtail(editnurb, nu); /* temporal for spin */ if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent); else if ((U.flag & USER_ADD_VIEWALIGNED)) ed_editnurb_spin(viewmat, obedit, zvec, mat[3]); else ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]); BKE_nurb_knot_calc_v(nu); a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a-- > 0) { bp->f1 |= SELECT; bp++; } BLI_remlink(editnurb, nu); } break; case CU_PRIM_DONUT: /* torus */ if (cutype == CU_NURBS) { float tmp_cent[3] = {0.f, 0.f, 0.f}; float tmp_vec[3] = {0.f, 0.f, 1.f}; xzproj = 1; nu = ED_curve_add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ xzproj = 0; nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->flag = CU_SMOOTH; BLI_addtail(editnurb, nu); /* temporal for spin */ /* same as above */ if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent); else if ((U.flag & USER_ADD_VIEWALIGNED)) ed_editnurb_spin(viewmat, obedit, zvec, mat[3]); else ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]); BLI_remlink(editnurb, nu); a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a-- > 0) { bp->f1 |= SELECT; bp++; } } break; default: /* should never happen */ BLI_assert(!"invalid nurbs type"); return NULL; } BLI_assert(nu != NULL); if (nu) { /* should always be set */ if ((obedit->type != OB_SURF) && ((cu->flag & CU_3D) == 0)) { nu->flag |= CU_2D; } nu->flag |= CU_SMOOTH; cu->actnu = BLI_listbase_count(editnurb); cu->actvert = CU_ACT_NONE; BKE_nurb_test2D(nu); } return nu; }
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; int a, change = 1; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob->type == OB_MESH) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing"); change = 0; } } else if (ob->type == OB_ARMATURE) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing"); change = 0; } } else if (ob->type == OB_LATTICE) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user lattice, doing nothing"); change = 0; } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu; if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing"); change = 0; } cu = ob->data; if (!(cu->flag & CU_3D) && (apply_rot || apply_loc)) { BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing"); change = 0; } if (cu->key) { BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing"); change = 0; } } } CTX_DATA_END; if (!change) return OPERATOR_CANCELLED; change = 0; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mvert; multiresModifier_scale_disp(scene, ob); /* adjust data */ mvert = me->mvert; for (a = 0; a < me->totvert; a++, mvert++) mul_m4_v3(mat, mvert->co); if (me->key) { KeyBlock *kb; for (kb = me->key->block.first; kb; kb = kb->next) { float *fp = kb->data; for (a = 0; a < kb->totelem; a++, fp += 3) mul_m4_v3(mat, fp); } } /* update normals */ BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BPoint *bp = lt->def; int a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { mul_m4_v3(mat, bp->vec); bp++; } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; scale = mat3_to_scale(rsmat); for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { a = nu->pntsu; for (bezt = nu->bezt; a--; bezt++) { mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); bezt->radius *= scale; } BKE_nurb_handles_calc(nu); } else { a = nu->pntsu * nu->pntsv; for (bp = nu->bp; a--; bp++) mul_m4_v3(mat, bp->vec); } } } else continue; if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); change = 1; } CTX_DATA_END; if (!change) return OPERATOR_CANCELLED; WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
/* convert stroke to 3d bezier */ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, float minmax_weights[2], float rad_fac, int stitch, tGpTimingData *gtd) { bGPDspoint *pt; Nurb *nu = (curnu) ? *curnu : NULL; BezTriple *bezt, *prev_bezt = NULL; int i, tot, old_nbezt = 0; float p3d_cur[3], p3d_prev[3], p3d_next[3]; const int do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); /* create new 'nurb' or extend current one within the curve */ if (nu) { old_nbezt = nu->pntsu; /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke, * so no need to add it. * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes. */ BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2)); } else { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); nu->pntsu = gps->totpoints; nu->resolu = 12; nu->resolv = 12; nu->type = CU_BEZIER; nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints * sizeof(BezTriple), "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) { gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect); if (tot > 1) { gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect); } if (stitch && tot > 2) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } } /* If needed, make the link between both strokes with two zero-radius additional points */ if (curnu && old_nbezt) { /* Update last point's second handle */ if (stitch) { float h2[3]; bezt = nu->bezt + old_nbezt - 1; interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC); 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 * the last segment to get the first point (p1) position and timing. * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point * with the first point of the current stroke. * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated * if it exists, else (if the stroke is a single point), linear interpolation with last curve point... */ else { float h1[3], h2[3], p1[3], p2[3]; float delta_time; prev_bezt = NULL; if (old_nbezt > 1 && gps->prev && 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; if (prev_bezt) { interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC); } else { interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC); } if (tot > 1) { interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC); } else { interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC); } /* Second handle of last point */ 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++; copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p1); copy_v3_v3(bezt->vec[2], h2); bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; minmax_weights[0] = bezt->radius = bezt->weight = 0.0f; if (do_gtd) { if (prev_bezt) { delta_time = gtd->tot_time + (gtd->tot_time - gtd->times[gtd->cur_point - 1]) * GAP_DFAC; } else { delta_time = gtd->tot_time + (((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC; } gp_timing_data_add_point(gtd, gtd->inittime, delta_time, len_v3v3((bezt - 1)->vec[1], p1)); } /* Second point */ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC); interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC); bezt++; copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p2); copy_v3_v3(bezt->vec[2], h2); bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; minmax_weights[0] = bezt->radius = bezt->weight = 0.0f; if (do_gtd) { /* This negative delta_time marks the gap! */ if (tot > 1) { delta_time = ((gps->points + 1)->time - gps->points->time) * -GAP_DFAC; } else { delta_time = -(((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC; } gp_timing_data_add_point(gtd, gps->inittime, delta_time, len_v3v3(p1, p2)); } old_nbezt += 2; copy_v3_v3(p3d_prev, p2); } } if (old_nbezt && do_gtd) { 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 h1[3], h2[3]; float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC; if (i || old_nbezt) { interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC); } if (i < tot - 1) { interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC); } else { interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC); } copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p3d_cur); copy_v3_v3(bezt->vec[2], h2); /* set settings */ bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->radius = width * rad_fac; bezt->weight = width; CLAMP(bezt->weight, 0.0f, 1.0f); if (bezt->weight < minmax_weights[0]) { minmax_weights[0] = bezt->weight; } else if (bezt->weight > minmax_weights[1]) { minmax_weights[1] = bezt->weight; } /* Update timing data */ if (do_gtd) { gp_timing_data_add_point(gtd, gps->inittime, pt->time, prev_bezt ? len_v3v3(prev_bezt->vec[1], p3d_cur) : 0.0f); } /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); if (i + 2 < tot) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } prev_bezt = bezt; } /* must calculate handles or else we crash */ BKE_nurb_handles_calc(nu); if (!curnu || !*curnu) { BLI_addtail(&cu->nurb, nu); } if (curnu) { *curnu = nu; } }
static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (obdata->lib) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ELEM(ob->type, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; Curve *cu; cu = ob->data; if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { BKE_reportf(reports, RPT_ERROR, "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (cu->key) { BKE_reportf(reports, RPT_ERROR, "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } } CTX_DATA_END; if (!changed) return OPERATOR_CANCELLED; changed = false; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat, true); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { float tmat[3][3]; /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mvert; int a; if (apply_scale) multiresModifier_scale_disp(scene, ob); /* adjust data */ mvert = me->mvert; for (a = 0; a < me->totvert; a++, mvert++) mul_m4_v3(mat, mvert->co); if (me->key) { KeyBlock *kb; for (kb = me->key->block.first; kb; kb = kb->next) { float *fp = kb->data; for (a = 0; a < kb->totelem; a++, fp += 3) mul_m4_v3(mat, fp); } } /* update normals */ BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BPoint *bp = lt->def; int a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { mul_m4_v3(mat, bp->vec); bp++; } } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; ED_mball_transform(mb, mat); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; int a; scale = mat3_to_scale(rsmat); for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { a = nu->pntsu; for (bezt = nu->bezt; a--; bezt++) { mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); bezt->radius *= scale; } BKE_nurb_handles_calc(nu); } else { a = nu->pntsu * nu->pntsv; for (bp = nu->bp; a--; bp++) mul_m4_v3(mat, bp->vec); } } } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); /* applying scale on camera actually scales clip's reconstruction. * of there's clip assigned to camera nothing to do actually. */ if (!clip) continue; if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } else if (ob->type == OB_EMPTY) { /* It's possible for empties too, even though they don't * really have obdata, since we can simply apply the maximum * scaling to the empty's drawsize. * * Core Assumptions: * 1) Most scaled empties have uniform scaling * (i.e. for visibility reasons), AND/OR * 2) Preserving non-uniform scaling is not that important, * and is something that many users would be willing to * sacrifice for having an easy way to do this. */ if ((apply_loc == false) && (apply_rot == false) && (apply_scale == true)) { float max_scale = max_fff(fabsf(ob->size[0]), fabsf(ob->size[1]), fabsf(ob->size[2])); ob->empty_drawsize *= max_scale; } } else { continue; } if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); changed = true; } CTX_DATA_END; if (!changed) { BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
/* convert stroke to 3d bezier */ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect) { bGPDspoint *pt; Nurb *nu; BezTriple *bezt; int i, tot; float p3d_cur[3], p3d_prev[3], p3d_next[3]; /* create new 'nurb' within the curve */ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); nu->pntsu = gps->totpoints; nu->resolu = 12; nu->resolv = 12; nu->type = CU_BEZIER; nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints * sizeof(BezTriple), "bezts"); tot = gps->totpoints; /* get initial coordinates */ pt = gps->points; if (tot) { gp_strokepoint_convertcoords(C, gps, pt, p3d_cur, subrect); if (tot > 1) { gp_strokepoint_convertcoords(C, gps, pt + 1, p3d_next, subrect); } } /* add points */ for (i = 0, bezt = nu->bezt; i < tot; i++, pt++, bezt++) { float h1[3], h2[3]; if (i) interp_v3_v3v3(h1, p3d_cur, p3d_prev, 0.3); else interp_v3_v3v3(h1, p3d_cur, p3d_next, -0.3); if (i < tot - 1) interp_v3_v3v3(h2, p3d_cur, p3d_next, 0.3); else interp_v3_v3v3(h2, p3d_cur, p3d_prev, -0.3); copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p3d_cur); copy_v3_v3(bezt->vec[2], h2); /* set settings */ bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f; /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); if (i + 2 < tot) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } } /* must calculate handles or else we crash */ BKE_nurb_handles_calc(nu); /* add nurb to curve */ BLI_addtail(&cu->nurb, nu); }