Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_conversions.c
| Show First 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
| #include "BKE_pointcache.h" | #include "BKE_pointcache.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_rigidbody.h" | #include "BKE_rigidbody.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_sequencer.h" | #include "BKE_sequencer.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_tracking.h" | #include "BKE_tracking.h" | ||||
| #include "BKE_mask.h" | #include "BKE_mask.h" | ||||
| #include "BKE_colortools.h" | |||||
| #include "BIK_api.h" | #include "BIK_api.h" | ||||
| #include "ED_anim_api.h" | #include "ED_anim_api.h" | ||||
| #include "ED_armature.h" | #include "ED_armature.h" | ||||
| #include "ED_particle.h" | #include "ED_particle.h" | ||||
| #include "ED_image.h" | #include "ED_image.h" | ||||
| #include "ED_keyframing.h" | #include "ED_keyframing.h" | ||||
| ▲ Show 20 Lines • Show All 3,503 Lines • ▼ Show 20 Lines | for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| } | } | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { | for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { | ||||
| BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum); | BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum); | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| /* set cache flag to dirty */ | |||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| } | } | ||||
| static void posttrans_mask_clean(Mask *mask) | static void posttrans_mask_clean(Mask *mask) | ||||
| { | { | ||||
| MaskLayer *masklay; | MaskLayer *masklay; | ||||
| for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { | for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { | ||||
| MaskLayerShape *masklay_shape, *masklay_shape_next; | MaskLayerShape *masklay_shape, *masklay_shape_next; | ||||
| ▲ Show 20 Lines • Show All 4,461 Lines • ▼ Show 20 Lines | for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) { | ||||
| PaintCurvePoint *pcp = tdpc->pcp; | PaintCurvePoint *pcp = tdpc->pcp; | ||||
| copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc); | copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc); | ||||
| } | } | ||||
| } | } | ||||
| static void createTransGPencil(bContext *C, TransInfo *t) | static void createTransGPencil(bContext *C, TransInfo *t) | ||||
| { | { | ||||
| Depsgraph *depsgraph = CTX_data_depsgraph(C); \ | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | bGPdata *gpd = ED_gpencil_data_get_active(C); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | |||||
| bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); | |||||
| bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_FRAME_FALLOFF) != 0; | |||||
| Object *obact = CTX_data_active_object(C); | |||||
| bGPDlayer *gpl; | bGPDlayer *gpl; | ||||
| TransData *td = NULL; | TransData *td = NULL; | ||||
| float mtx[3][3], smtx[3][3]; | float mtx[3][3], smtx[3][3]; | ||||
| const Scene *scene = CTX_data_scene(C); | const Scene *scene = CTX_data_scene(C); | ||||
| const int cfra_scene = CFRA; | const int cfra_scene = CFRA; | ||||
| const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; | const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; | ||||
| const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; | const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; | ||||
| TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); | TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); | ||||
| /* == Grease Pencil Strokes to Transform Data == | /* == Grease Pencil Strokes to Transform Data == | ||||
| * Grease Pencil stroke points can be a mixture of 2D (screen-space), | * Grease Pencil stroke points can be a mixture of 2D (screen-space), | ||||
| * or 3D coordinates. However, they're always saved as 3D points. | * or 3D coordinates. However, they're always saved as 3D points. | ||||
| * For now, we just do these without creating TransData2D for the 2D | * For now, we just do these without creating TransData2D for the 2D | ||||
| * strokes. This may cause issues in future though. | * strokes. This may cause issues in future though. | ||||
| */ | */ | ||||
| tc->data_len = 0; | tc->data_len = 0; | ||||
| if (gpd == NULL) | if (gpd == NULL) | ||||
| return; | return; | ||||
| /* initialize falloff curve */ | |||||
| if (is_multiedit) { | |||||
| curvemapping_initialize(ts->gp_sculpt.cur_falloff); | |||||
| } | |||||
| /* First Pass: Count the number of datapoints required for the strokes, | /* First Pass: Count the number of datapoints required for the strokes, | ||||
| * (and additional info about the configuration - e.g. 2D/3D?) | * (and additional info about the configuration - e.g. 2D/3D?) | ||||
| */ | */ | ||||
| for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| /* only editable and visible layers are considered */ | /* only editable and visible layers are considered */ | ||||
| if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { | if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { | ||||
| bGPDframe *gpf = gpl->actframe; | bGPDframe *gpf; | ||||
| bGPDstroke *gps; | bGPDstroke *gps; | ||||
| bGPDframe *init_gpf = gpl->actframe; | |||||
| if (is_multiedit) { | |||||
| init_gpf = gpl->frames.first; | |||||
| } | |||||
| for (gpf = init_gpf; gpf; gpf = gpf->next) { | |||||
| if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { | |||||
| for (gps = gpf->strokes.first; gps; gps = gps->next) { | for (gps = gpf->strokes.first; gps; gps = gps->next) { | ||||
| /* skip strokes that are invalid for current view */ | /* skip strokes that are invalid for current view */ | ||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) { | if (ED_gpencil_stroke_can_use(C, gps) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* check if the color is editable */ | /* check if the color is editable */ | ||||
| if (ED_gpencil_stroke_color_use(gpl, gps) == false) { | if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (is_prop_edit) { | if (is_prop_edit) { | ||||
| /* Proportional Editing... */ | /* Proportional Editing... */ | ||||
| if (is_prop_edit_connected) { | if (is_prop_edit_connected) { | ||||
| /* connected only - so only if selected */ | /* connected only - so only if selected */ | ||||
| if (gps->flag & GP_STROKE_SELECT) | if (gps->flag & GP_STROKE_SELECT) | ||||
| tc->data_len += gps->totpoints; | tc->data_len += gps->totpoints; | ||||
| } | } | ||||
| else { | else { | ||||
| /* everything goes - connection status doesn't matter */ | /* everything goes - connection status doesn't matter */ | ||||
| tc->data_len += gps->totpoints; | tc->data_len += gps->totpoints; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* only selected stroke points are considered */ | /* only selected stroke points are considered */ | ||||
| if (gps->flag & GP_STROKE_SELECT) { | if (gps->flag & GP_STROKE_SELECT) { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| // TODO: 2D vs 3D? | // TODO: 2D vs 3D? | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| if (pt->flag & GP_SPOINT_SELECT) | if (pt->flag & GP_SPOINT_SELECT) | ||||
| tc->data_len++; | tc->data_len++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* if not multiedit out of loop */ | |||||
| if (!is_multiedit) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /* Stop trying if nothing selected */ | /* Stop trying if nothing selected */ | ||||
| if (tc->data_len == 0) { | if (tc->data_len == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Allocate memory for data */ | /* Allocate memory for data */ | ||||
| tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)"); | tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)"); | ||||
| td = tc->data; | td = tc->data; | ||||
| unit_m3(smtx); | unit_m3(smtx); | ||||
| unit_m3(mtx); | unit_m3(mtx); | ||||
| /* Second Pass: Build transdata array */ | /* Second Pass: Build transdata array */ | ||||
| for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| /* only editable and visible layers are considered */ | /* only editable and visible layers are considered */ | ||||
| if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { | if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { | ||||
| const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; | const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; | ||||
| bGPDframe *gpf = gpl->actframe; | bGPDframe *gpf = gpl->actframe; | ||||
| bGPDstroke *gps; | bGPDstroke *gps; | ||||
| float diff_mat[4][4]; | float diff_mat[4][4]; | ||||
| float inverse_diff_mat[4][4]; | float inverse_diff_mat[4][4]; | ||||
| /* calculate difference matrix if parent object */ | bGPDframe *init_gpf = gpl->actframe; | ||||
| if (gpl->parent != NULL) { | if (is_multiedit) { | ||||
| ED_gpencil_parent_location(gpl, diff_mat); | init_gpf = gpl->frames.first; | ||||
| } | |||||
| /* init multiframe falloff options */ | |||||
| int f_init = 0; | |||||
| int f_end = 0; | |||||
| if (use_multiframe_falloff) { | |||||
| BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); | |||||
| } | |||||
| /* calculate difference matrix */ | |||||
| ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); | |||||
| /* undo matrix */ | /* undo matrix */ | ||||
| invert_m4_m4(inverse_diff_mat, diff_mat); | invert_m4_m4(inverse_diff_mat, diff_mat); | ||||
| } | |||||
| /* 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 | * - 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... | * spent too much time editing the wrong frame... | ||||
| */ | */ | ||||
| if (gpf->framenum != cfra) { | // XXX: should this be allowed when framelock is enabled? | ||||
| if ((gpf->framenum != cfra) && (!is_multiedit)) { | |||||
| gpf = BKE_gpencil_frame_addcopy(gpl, cfra); | gpf = BKE_gpencil_frame_addcopy(gpl, cfra); | ||||
| /* in some weird situations (framelock enabled) return NULL */ | /* in some weird situations (framelock enabled) return NULL */ | ||||
| if (gpf == NULL) { | if (gpf == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!is_multiedit) { | |||||
| init_gpf = gpf; | |||||
| } | |||||
| } | } | ||||
| /* Loop over strokes, adding TransData for points as needed... */ | /* Loop over strokes, adding TransData for points as needed... */ | ||||
| for (gpf = init_gpf; gpf; gpf = gpf->next) { | |||||
| if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { | |||||
| /* if multiframe and falloff, recalculate and save value */ | |||||
| float falloff = 1.0f; /* by default no falloff */ | |||||
| if ((is_multiedit) && (use_multiframe_falloff)) { | |||||
| /* Faloff depends on distance to active frame (relative to the overall frame range) */ | |||||
| falloff = BKE_gpencil_multiframe_falloff_calc(gpf, gpl->actframe->framenum, | |||||
| f_init, f_end, ts->gp_sculpt.cur_falloff); | |||||
| } | |||||
| for (gps = gpf->strokes.first; gps; gps = gps->next) { | for (gps = gpf->strokes.first; gps; gps = gps->next) { | ||||
| TransData *head = td; | TransData *head = td; | ||||
| TransData *tail = td; | TransData *tail = td; | ||||
| bool stroke_ok; | bool stroke_ok; | ||||
| /* skip strokes that are invalid for current view */ | /* skip strokes that are invalid for current view */ | ||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) { | if (ED_gpencil_stroke_can_use(C, gps) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* check if the color is editable */ | /* check if the color is editable */ | ||||
| if (ED_gpencil_stroke_color_use(gpl, gps) == false) { | if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* What we need to include depends on proportional editing settings... */ | /* What we need to include depends on proportional editing settings... */ | ||||
| if (is_prop_edit) { | if (is_prop_edit) { | ||||
| if (is_prop_edit_connected) { | if (is_prop_edit_connected) { | ||||
| /* A) "Connected" - Only those in selected strokes */ | /* A) "Connected" - Only those in selected strokes */ | ||||
| stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; | stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; | ||||
| } | } | ||||
| else { | else { | ||||
| /* B) All points, always */ | /* B) All points, always */ | ||||
| stroke_ok = true; | stroke_ok = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* C) Only selected points in selected strokes */ | /* C) Only selected points in selected strokes */ | ||||
| stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; | stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; | ||||
| } | } | ||||
| /* Do stroke... */ | /* Do stroke... */ | ||||
| if (stroke_ok && gps->totpoints) { | if (stroke_ok && gps->totpoints) { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| #if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */ | /* save falloff factor */ | ||||
| const float ninv = 1.0f / gps->totpoints; | gps->runtime.multi_frame_falloff = falloff; | ||||
| float center[3] = {0.0f}; | |||||
| /* compute midpoint of stroke */ | |||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | |||||
| madd_v3_v3v3fl(center, center, &pt->x, ninv); | |||||
| } | |||||
| #endif | |||||
| /* add all necessary points... */ | /* add all necessary points... */ | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| bool point_ok; | bool point_ok; | ||||
| /* include point? */ | /* include point? */ | ||||
| if (is_prop_edit) { | if (is_prop_edit) { | ||||
| /* Always all points in strokes that get included */ | /* Always all points in strokes that get included */ | ||||
| point_ok = true; | point_ok = true; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Only selected points in selected strokes */ | /* Only selected points in selected strokes */ | ||||
| point_ok = (pt->flag & GP_SPOINT_SELECT) != 0; | point_ok = (pt->flag & GP_SPOINT_SELECT) != 0; | ||||
| } | } | ||||
| /* do point... */ | /* do point... */ | ||||
| if (point_ok) { | if (point_ok) { | ||||
| copy_v3_v3(td->iloc, &pt->x); | copy_v3_v3(td->iloc, &pt->x); | ||||
| copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local? | copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local? | ||||
| td->loc = &pt->x; | td->loc = &pt->x; | ||||
| td->flag = 0; | td->flag = 0; | ||||
| if (pt->flag & GP_SPOINT_SELECT) | if (pt->flag & GP_SPOINT_SELECT) | ||||
| td->flag |= TD_SELECTED; | td->flag |= TD_SELECTED; | ||||
| /* for other transform modes (e.g. shrink-fatten), need to additional data */ | /* for other transform modes (e.g. shrink-fatten), need to additional data | ||||
| if (t->mode == TFM_GPENCIL_SHRINKFATTEN) { | * but never for scale or mirror | ||||
| */ | |||||
| if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) { | |||||
| td->val = &pt->pressure; | td->val = &pt->pressure; | ||||
| td->ival = pt->pressure; | td->ival = pt->pressure; | ||||
| } | } | ||||
| /* screenspace needs special matrices... */ | /* screenspace needs special matrices... */ | ||||
| if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) { | if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) { | ||||
| /* screenspace */ | /* screenspace */ | ||||
| td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; | td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; | ||||
| /* apply parent transformations */ | |||||
| if (gpl->parent == NULL) { | |||||
| copy_m3_m4(td->smtx, t->persmat); | |||||
| copy_m3_m4(td->mtx, t->persinv); | |||||
| unit_m3(td->axismtx); | |||||
| } | |||||
| else { | |||||
| /* apply matrix transformation relative to parent */ | /* apply matrix transformation relative to parent */ | ||||
| copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ | copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ | ||||
| copy_m3_m4(td->mtx, diff_mat); /* display position */ | copy_m3_m4(td->mtx, diff_mat); /* display position */ | ||||
| copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ | copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ | ||||
| } | } | ||||
| } | |||||
| else { | else { | ||||
| /* configure 2D dataspace points so that they don't play up... */ | /* configure 2D dataspace points so that they don't play up... */ | ||||
| if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) { | if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) { | ||||
| td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; | td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; | ||||
| // XXX: matrices may need to be different? | // XXX: matrices may need to be different? | ||||
| } | } | ||||
| /* apply parent transformations */ | /* apply parent transformations */ | ||||
| if (gpl->parent == NULL) { | |||||
| copy_m3_m3(td->smtx, smtx); | |||||
| copy_m3_m3(td->mtx, mtx); | |||||
| unit_m3(td->axismtx); // XXX? | |||||
| } | |||||
| else { | |||||
| /* apply matrix transformation relative to parent */ | |||||
| copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ | copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ | ||||
| copy_m3_m4(td->mtx, diff_mat); /* display position */ | copy_m3_m4(td->mtx, diff_mat); /* display position */ | ||||
| copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ | copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ | ||||
| } | } | ||||
| } | |||||
| /* Triangulation must be calculated again, so save the stroke for recalc function */ | /* Triangulation must be calculated again, so save the stroke for recalc function */ | ||||
| td->extra = gps; | td->extra = gps; | ||||
| /* save pointer to object */ | |||||
| td->ob = obact; | |||||
| td++; | td++; | ||||
| tail++; | tail++; | ||||
| } | } | ||||
| } | } | ||||
| /* March over these points, and calculate the proportional editing distances */ | /* March over these points, and calculate the proportional editing distances */ | ||||
| if (is_prop_edit && (head != tail)) { | if (is_prop_edit && (head != tail)) { | ||||
| /* XXX: for now, we are similar enough that this works... */ | /* XXX: for now, we are similar enough that this works... */ | ||||
| calc_distanceCurveVerts(head, tail - 1); | calc_distanceCurveVerts(head, tail - 1); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* if not multiedit out of loop */ | |||||
| if (!is_multiedit) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| static int countAndCleanTransDataContainer(TransInfo *t) | static int countAndCleanTransDataContainer(TransInfo *t) | ||||
| { | { | ||||
| BLI_assert(ELEM(t->data_len_all, 0, -1)); | BLI_assert(ELEM(t->data_len_all, 0, -1)); | ||||
| t->data_len_all = 0; | t->data_len_all = 0; | ||||
| uint data_container_len_orig = t->data_container_len; | uint data_container_len_orig = t->data_container_len; | ||||
| ▲ Show 20 Lines • Show All 323 Lines • Show Last 20 Lines | |||||