void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); ob_to_keylist(ads, ob, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); scene_to_keylist(ads, sce, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); summary_to_keylist(ac, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
/* helper for time_draw_keyframes() */ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) { bDopeSheet ads = {NULL}; DLRBT_Tree keys; ActKeyColumn *ak; float fac1 = (GS(id->name) == ID_GD) ? 0.8f : 0.6f; /* draw GPencil keys taller, to help distinguish them */ float fac2 = 1.0f - fac1; float ymin = v2d->tot.ymin; float ymax = v2d->tot.ymax * fac1 + ymin * fac2; /* init binarytree-list for getting keyframes */ BLI_dlrbTree_init(&keys); /* init dopesheet settings */ if (onlysel) ads.filterflag |= ADS_FILTER_ONLYSEL; /* populate tree with keyframe nodes */ switch (GS(id->name)) { case ID_SCE: scene_to_keylist(&ads, (Scene *)id, &keys, NULL); break; case ID_OB: ob_to_keylist(&ads, (Object *)id, &keys, NULL); break; case ID_GD: gpencil_to_keylist(&ads, (bGPdata *)id, &keys); break; case ID_CF: cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL); break; default: break; } /* build linked-list for searching */ BLI_dlrbTree_linkedlist_sync(&keys); /* start drawing keyframes * - we use the binary-search capabilities of the tree to only start from * the first visible keyframe (last one can then be easily checked) * - draw within a single GL block to be faster */ glBegin(GL_LINES); for (ak = time_cfra_find_ak(keys.root, v2d->cur.xmin); (ak) && (ak->cfra <= v2d->cur.xmax); ak = ak->next) { glVertex2f(ak->cfra, ymin); glVertex2f(ak->cfra, ymax); } glEnd(); // GL_LINES /* free temp stuff */ BLI_dlrbTree_free(&keys); }
void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos) { DLRBT_Tree keys, blocks; short locked = (act && act->id.lib != NULL); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); action_to_keylist(adt, act, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; bool locked = (act && ID_IS_LINKED(act)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); action_to_keylist(adt, act, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; bool locked = (agrp->flag & AGRP_PROTECTED) || ((adt && adt->action) && ID_IS_LINKED(adt->action)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); agroup_to_keylist(adt, agrp, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos) { DLRBT_Tree keys, blocks; short locked = (agrp->flag & AGRP_PROTECTED) || ((adt && adt->action) && (adt->action->id.lib)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); agroup_to_keylist(adt, agrp, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; bool locked = (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); fcurve_to_keylist(adt, fcu, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
/* operator init */ static int pose_slide_init(bContext *C, wmOperator *op, short mode) { tPoseSlideOp *pso; bAction *act = NULL; /* init slide-op data */ pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp"); /* get info from context */ pso->scene = CTX_data_scene(C); pso->ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); pso->arm = (pso->ob) ? pso->ob->data : NULL; pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */ pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */ pso->cframe = pso->scene->r.cfra; pso->mode = mode; /* set range info from property values - these may get overridden for the invoke() */ pso->percentage = RNA_float_get(op->ptr, "percentage"); pso->prevFrame = RNA_int_get(op->ptr, "prev_frame"); pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); /* check the settings from the context */ if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) return 0; else act = pso->ob->adt->action; /* for each Pose-Channel which gets affected, get the F-Curves for that channel * and set the relevant transform flags... */ poseAnim_mapping_get(C, &pso->pfLinks, pso->ob, act); /* set depsgraph flags */ /* make sure the lock is set OK, unlock can be accidentally saved? */ pso->ob->pose->flag |= POSE_LOCKED; pso->ob->pose->flag &= ~POSE_DO_UNLOCK; /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up * to the caller of this (usually only invoke() will do it, to make things more efficient). */ BLI_dlrbTree_init(&pso->keys); /* initialise numeric input */ initNumInput(&pso->num); pso->num.idx_max = 0; /* one axis */ pso->num.val_flag[0] |= NUM_NO_NEGATIVE; pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */ /* return status is whether we've got all the data we were requested to get */ return 1; }
void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos) { DLRBT_Tree keys, blocks; short locked = (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || ((adt && adt->action) && (adt->action->id.lib)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); fcurve_to_keylist(adt, fcu, &keys, &blocks); BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); draw_keylist(v2d, &keys, &blocks, ypos, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); }
void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos) { DLRBT_Tree keys; BLI_dlrbTree_init(&keys); mask_to_keylist(ads, masklay, &keys); BLI_dlrbTree_linkedlist_sync(&keys); draw_keylist(v2d, &keys, NULL, ypos, (masklay->flag & MASK_LAYERFLAG_LOCKED)); BLI_dlrbTree_free(&keys); }
void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos) { DLRBT_Tree keys; BLI_dlrbTree_init(&keys); gpl_to_keylist(ads, gpl, &keys); BLI_dlrbTree_linkedlist_sync(&keys); draw_keylist(v2d, &keys, NULL, ypos, (gpl->flag & GP_LAYER_LOCKED)); BLI_dlrbTree_free(&keys); }
void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos) { DLRBT_Tree keys; BLI_dlrbTree_init(&keys); gpencil_to_keylist(ads, gpd, &keys); BLI_dlrbTree_linkedlist_sync(&keys); draw_keylist(v2d, &keys, NULL, ypos, 0); BLI_dlrbTree_free(&keys); }
/* draw the keyframes in the specified Action */ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax) { DLRBT_Tree keys; ActKeyColumn *ak; float xscale, f1, f2; float color[4]; /* get a list of the keyframes with NLA-scaling applied */ BLI_dlrbTree_init(&keys); action_to_keylist(adt, act, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); if (ELEM(NULL, act, keys.first)) return; /* draw a darkened region behind the strips * - get and reset the background color, this time without the alpha to stand out better * (amplified alpha is used instead) */ nla_action_get_color(adt, act, color); color[3] *= 2.5f; glColor4fv(color); /* - draw a rect from the first to the last frame (no extra overlaps for now) * that is slightly stumpier than the track background (hardcoded 2-units here) */ f1 = ((ActKeyColumn *)keys.first)->cfra; f2 = ((ActKeyColumn *)keys.last)->cfra; glRectf(f1, ymin + 2, f2, ymax - 2); /* get View2D scaling factor */ UI_view2d_scale_get(v2d, &xscale, NULL); /* for now, color is hardcoded to be black */ glColor3f(0.0f, 0.0f, 0.0f); /* just draw each keyframe as a simple dot (regardless of the selection status) * - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction */ for (ak = keys.first; ak; ak = ak->next) draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f); /* free icons */ BLI_dlrbTree_free(&keys); }
/* get frame on which the "hold" for the bone ends * XXX: this may not really work that well if a bone moves on some channels and not others * if this happens to be a major issue, scrap this, and just make this happen * independently per F-Curve */ static float pose_propagate_get_boneHoldEndFrame(Object *ob, tPChanFCurveLink *pfl, float startFrame) { DLRBT_Tree keys, blocks; ActKeyBlock *ab; AnimData *adt = ob->adt; LinkData *ld; float endFrame = startFrame; /* set up optimized data-structures for searching for relevant keyframes + holds */ BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); for (ld = pfl->fcurves.first; ld; ld = ld->next) { FCurve *fcu = (FCurve *)ld->data; fcurve_to_keylist(adt, fcu, &keys, &blocks); } BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); /* find the long keyframe (i.e. hold), and hence obtain the endFrame value * - the best case would be one that starts on the frame itself */ ab = (ActKeyBlock *)BLI_dlrbTree_search_exact(&blocks, compare_ab_cfraPtr, &startFrame); if (actkeyblock_is_valid(ab, &keys) == 0) { /* There are only two cases for no-exact match: * 1) the current frame is just before another key but not on a key itself * 2) the current frame is on a key, but that key doesn't link to the next * * If we've got the first case, then we can search for another block, * otherwise forget it, as we'd be overwriting some valid data. */ if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &startFrame) == NULL) { /* we've got case 1, so try the one after */ ab = (ActKeyBlock *)BLI_dlrbTree_search_next(&blocks, compare_ab_cfraPtr, &startFrame); if (actkeyblock_is_valid(ab, &keys) == 0) { /* try the block before this frame then as last resort */ ab = (ActKeyBlock *)BLI_dlrbTree_search_prev(&blocks, compare_ab_cfraPtr, &startFrame); /* whatever happens, stop searching now... */ if (actkeyblock_is_valid(ab, &keys) == 0) { /* restrict range to just the frame itself * i.e. everything is in motion, so no holds to safely overwrite */ ab = NULL; } } } else { /* we've got case 2 - set ab to NULL just in case, since we shouldn't do anything in this case */ ab = NULL; } } /* check if we can go any further than we've already gone */ if (ab) { /* go to next if it is also valid and meets "extension" criteria */ while (ab->next) { ActKeyBlock *abn = (ActKeyBlock *)ab->next; /* must be valid */ if (actkeyblock_is_valid(abn, &keys) == 0) break; /* should start on the same frame that the last ended on */ if (ab->end != abn->start) break; /* should have the same number of curves */ if (ab->totcurve != abn->totcurve) break; /* should have the same value * XXX: this may be a bit fuzzy on larger data sets, so be careful */ if (ab->val != abn->val) break; /* we can extend the bounds to the end of this "next" block now */ ab = abn; } /* end frame can now take the value of the end of the block */ endFrame = ab->end; } /* free temp memory */ BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); /* return the end frame we've found */ return endFrame; }
/* draw the keyframes in the specified Action */ static void nla_action_draw_keyframes( View2D *v2d, AnimData *adt, bAction *act, float y, float ymin, float ymax) { /* get a list of the keyframes with NLA-scaling applied */ DLRBT_Tree keys; BLI_dlrbTree_init(&keys); action_to_keylist(adt, act, &keys, 0); if (ELEM(NULL, act, keys.first)) { return; } /* draw a darkened region behind the strips * - get and reset the background color, this time without the alpha to stand out better * (amplified alpha is used instead) */ float color[4]; nla_action_get_color(adt, act, color); color[3] *= 2.5f; GPUVertFormat *format = immVertexFormat(); uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformColor4fv(color); /* - draw a rect from the first to the last frame (no extra overlaps for now) * that is slightly stumpier than the track background (hardcoded 2-units here) */ float f1 = ((ActKeyColumn *)keys.first)->cfra; float f2 = ((ActKeyColumn *)keys.last)->cfra; immRectf(pos_id, f1, ymin + 2, f2, ymax - 2); immUnbindProgram(); /* count keys before drawing */ /* Note: It's safe to cast DLRBT_Tree, as it's designed to degrade down to a ListBase */ uint key_len = BLI_listbase_count((ListBase *)&keys); if (key_len > 0) { format = immVertexFormat(); pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); uint color_id = GPU_vertformat_attr_add( format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); uint outline_color_id = GPU_vertformat_attr_add( format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); GPU_program_point_size(true); immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1); immBegin(GPU_PRIM_POINTS, key_len); /* - disregard the selection status of keyframes so they draw a certain way * - size is 6.0f which is smaller than the editable keyframes, so that there is a distinction */ for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) { draw_keyframe_shape(ak->cfra, y, 6.0f, false, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f, pos_id, size_id, color_id, outline_color_id, flags_id, KEYFRAME_HANDLE_NONE, KEYFRAME_EXTREME_NONE); } immEnd(); GPU_program_point_size(false); immUnbindProgram(); } /* free icons */ BLI_dlrbTree_free(&keys); }
/* Draw the given motion path for an Object or a Bone * - assumes that the viewport has already been initialized properly * i.e. draw_motion_paths_init() has been called */ void draw_motion_path_instance(Scene *scene, Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath) { //RegionView3D *rv3d = ar->regiondata; bMotionPathVert *mpv, *mpv_start; int i, stepsize = avs->path_step; int sfra, efra, sind, len; /* get frame ranges */ if (avs->path_type == MOTIONPATH_TYPE_ACFRA) { /* With "Around Current", we only choose frames from around * the current frame to draw. */ sfra = CFRA - avs->path_bc; efra = CFRA + avs->path_ac; } else { /* Use the current display range */ sfra = avs->path_sf; efra = avs->path_ef; } /* no matter what, we can only show what is in the cache and no more * - abort if whole range is past ends of path * - otherwise clamp endpoints to extents of path */ if (sfra < mpath->start_frame) { /* start clamp */ sfra = mpath->start_frame; } if (efra > mpath->end_frame) { /* end clamp */ efra = mpath->end_frame; } if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) { /* whole path is out of bounds */ return; } len = efra - sfra; if ((len <= 0) || (mpath->points == NULL)) { return; } /* get pointers to parts of path */ sind = sfra - mpath->start_frame; mpv_start = (mpath->points + sind); /* draw curve-line of path */ glShadeModel(GL_SMOOTH); glBegin(GL_LINE_STRIP); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT); float intensity; /* how faint */ int frame = sfra + i; int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */ /* set color * - more intense for active/selected bones, less intense for unselected bones * - black for before current frame, green for current frame, blue for after current frame * - intensity decreases as distance from current frame increases */ #define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min) if (frame < CFRA) { /* black - before cfra */ if (sel) { /* intensity = 0.5f; */ intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f); } else { /* intensity = 0.8f; */ intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f); } UI_ThemeColorBlend(TH_WIRE, blend_base, intensity); } else if (frame > CFRA) { /* blue - after cfra */ if (sel) { /* intensity = 0.5f; */ intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f); } else { /* intensity = 0.8f; */ intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f); } UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity); } else { /* green - on cfra */ if (sel) { intensity = 0.5f; } else { intensity = 0.99f; } UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); } #undef SET_INTENSITY /* draw a vertex with this color */ glVertex3fv(mpv->co); } glEnd(); glShadeModel(GL_FLAT); glPointSize(1.0); /* draw little black point at each frame * NOTE: this is not really visible/noticeable */ glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) glVertex3fv(mpv->co); glEnd(); /* Draw little white dots at each framestep value */ UI_ThemeColor(TH_TEXT_HI); glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) glVertex3fv(mpv->co); glEnd(); /* Draw big green dot where the current frame is * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter */ if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) && (sfra < CFRA) && (CFRA <= efra)) { UI_ThemeColor(TH_CFRAME); glPointSize(6.0f); glBegin(GL_POINTS); mpv = mpv_start + (CFRA - sfra); glVertex3fv(mpv->co); glEnd(); UI_ThemeColor(TH_TEXT_HI); } /* XXX, this isn't up to date but probably should be kept so. */ invert_m4_m4(ob->imat, ob->obmat); /* Draw frame numbers at each framestep value */ if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) { unsigned char col[4]; UI_GetThemeColor3ubv(TH_TEXT_HI, col); col[3] = 255; for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) { int frame = sfra + i; char numstr[32]; size_t numstr_len; float co[3]; /* only draw framenum if several consecutive highlighted points don't occur on same point */ if (i == 0) { numstr_len = sprintf(numstr, " %d", frame); mul_v3_m4v3(co, ob->imat, mpv->co); view3d_cached_text_draw_add(co, numstr, numstr_len, 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); } else if ((i >= stepsize) && (i < len - stepsize)) { bMotionPathVert *mpvP = (mpv - stepsize); bMotionPathVert *mpvN = (mpv + stepsize); if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) { numstr_len = sprintf(numstr, " %d", frame); mul_v3_m4v3(co, ob->imat, mpv->co); view3d_cached_text_draw_add(co, numstr, numstr_len, 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); } } } } /* Keyframes - dots and numbers */ if (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) { unsigned char col[4]; AnimData *adt = BKE_animdata_from_id(&ob->id); DLRBT_Tree keys; /* build list of all keyframes in active action for object or pchan */ BLI_dlrbTree_init(&keys); if (adt) { /* it is assumed that keyframes for bones are all grouped in a single group * unless an option is set to always use the whole action */ if ((pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) { bActionGroup *agrp = BKE_action_group_find_name(adt->action, pchan->name); if (agrp) { agroup_to_keylist(adt, agrp, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); } } else { action_to_keylist(adt, adt->action, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); } } /* Draw slightly-larger yellow dots at each keyframe */ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col); col[3] = 255; glPointSize(4.0f); glColor3ubv(col); glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { int frame = sfra + i; float mframe = (float)(frame); if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) glVertex3fv(mpv->co); } glEnd(); /* Draw frame numbers of keyframes */ if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) { float co[3]; for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { float mframe = (float)(sfra + i); if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) { char numstr[32]; size_t numstr_len; numstr_len = sprintf(numstr, " %d", (sfra + i)); mul_v3_m4v3(co, ob->imat, mpv->co); view3d_cached_text_draw_add(co, numstr, numstr_len, 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); } } } BLI_dlrbTree_free(&keys); } }
static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); bGPdata *gpd = CTX_data_gpencil_data(C); Mask *mask = CTX_data_edit_mask(C); bDopeSheet ads = {NULL}; DLRBT_Tree keys; ActKeyColumn *aknext, *akprev; float cfranext, cfraprev; bool donenext = false, doneprev = false; int nextcount = 0, prevcount = 0; cfranext = cfraprev = (float)(CFRA); /* init binarytree-list for getting keyframes */ BLI_dlrbTree_init(&keys); /* seed up dummy dopesheet context with flags to perform necessary filtering */ if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) { /* only selected channels are included */ ads.filterflag |= ADS_FILTER_ONLYSEL; } /* populate tree with keyframe nodes */ scene_to_keylist(&ads, scene, &keys, NULL); if (ob) ob_to_keylist(&ads, ob, &keys, NULL); gpencil_to_keylist(&ads, gpd, &keys); if (mask) { MaskLayer *masklay = BKE_mask_layer_active(mask); mask_to_keylist(&ads, masklay, &keys); } /* build linked-list for searching */ BLI_dlrbTree_linkedlist_sync(&keys); /* find matching keyframe in the right direction */ do { aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext); if (aknext) { if (CFRA == (int)aknext->cfra) { /* make this the new starting point for the search and ignore */ cfranext = aknext->cfra; } else { /* this changes the frame, so set the frame and we're done */ if (++nextcount == U.view_frame_keyframes) donenext = true; } cfranext = aknext->cfra; } } while ((aknext != NULL) && (donenext == false)); do { akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev); if (akprev) { if (CFRA == (int)akprev->cfra) { /* make this the new starting point for the search */ } else { /* this changes the frame, so set the frame and we're done */ if (++prevcount == U.view_frame_keyframes) doneprev = true; } cfraprev = akprev->cfra; } } while ((akprev != NULL) && (doneprev == false)); /* free temp stuff */ BLI_dlrbTree_free(&keys); /* any success? */ if (doneprev || donenext) { if (doneprev) *prevfra = cfraprev; else *prevfra = CFRA - (cfranext - CFRA); if (donenext) *nextfra = cfranext; else *nextfra = CFRA + (CFRA - cfraprev); return true; } return false; }
/* This tool automagically generates/validates poselib data so that it corresponds to the data * in the action. This is for use in making existing actions usable as poselibs. */ static int poselib_sanitise_exec (bContext *C, wmOperator *op) { Object *ob = get_poselib_object(C); bAction *act = (ob)? ob->poselib : NULL; DLRBT_Tree keys; ActKeyColumn *ak; TimeMarker *marker, *markern; /* validate action */ if (act == NULL) { BKE_report(op->reports, RPT_WARNING, "No Action to validate"); return OPERATOR_CANCELLED; } /* determine which frames have keys */ BLI_dlrbTree_init(&keys); action_to_keylist(NULL, act, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); /* for each key, make sure there is a corresponding pose */ for (ak= keys.first; ak; ak= ak->next) { /* check if any pose matches this */ // TODO: don't go looking through the list like this every time... for (marker= act->markers.first; marker; marker= marker->next) { if (IS_EQ(marker->frame, (double)ak->cfra)) { marker->flag = -1; break; } } /* add new if none found */ if (marker == NULL) { /* add pose to poselib */ marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker"); BLI_strncpy(marker->name, "Pose", sizeof(marker->name)); marker->frame= (int)ak->cfra; marker->flag= -1; BLI_addtail(&act->markers, marker); } } /* remove all untagged poses (unused), and remove all tags */ for (marker= act->markers.first; marker; marker= markern) { markern= marker->next; if (marker->flag != -1) BLI_freelinkN(&act->markers, marker); else marker->flag = 0; } /* free temp memory */ BLI_dlrbTree_free(&keys); /* send notifiers for this - using keyframe editing notifiers, since action * may be being shown in anim editors as active action */ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); return OPERATOR_FINISHED; }
static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_mode, bool column, bool same_channel) { ListBase anim_data = {NULL, NULL}; DLRBT_Tree anim_keys; bAnimListElem *ale; int filter; View2D *v2d = &ac->ar->v2d; bDopeSheet *ads = NULL; int channel_index; bool found = false; float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ float selx = 0.0f; /* frame of keyframe under mouse */ float key_hsize; float x, y; rctf rectf; /* get dopesheet info */ if (ac->datatype == ANIMCONT_DOPESHEET) ads = ac->data; /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space), * on either side of mouse click (size of keyframe icon) */ key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; /* standard channel height (to allow for some slop) */ key_hsize = roundf(key_hsize / 2.0f); /* half-size (for either side), but rounded up to nearest int (for easier targetting) */ UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin); UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax); /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* try to get channel */ ale = BLI_findlink(&anim_data, channel_index); if (ale == NULL) { /* channel not found */ printf("Error: animation channel (index = %d) not found in mouse_action_keys()\n", channel_index); ANIM_animdata_freelist(&anim_data); return; } else { /* found match - must return here... */ AnimData *adt = ANIM_nla_mapping_get(ac, ale); ActKeyColumn *ak, *akn = NULL; /* make list of keyframes */ BLI_dlrbTree_init(&anim_keys); if (ale->key_data) { switch (ale->datatype) { case ALE_SCE: { Scene *scene = (Scene *)ale->key_data; scene_to_keylist(ads, scene, &anim_keys, NULL); break; } case ALE_OB: { Object *ob = (Object *)ale->key_data; ob_to_keylist(ads, ob, &anim_keys, NULL); break; } case ALE_ACT: { bAction *act = (bAction *)ale->key_data; action_to_keylist(adt, act, &anim_keys, NULL); break; } case ALE_FCURVE: { FCurve *fcu = (FCurve *)ale->key_data; fcurve_to_keylist(adt, fcu, &anim_keys, NULL); break; } } } else if (ale->type == ANIMTYPE_SUMMARY) { /* dopesheet summary covers everything */ summary_to_keylist(ac, &anim_keys, NULL); } else if (ale->type == ANIMTYPE_GROUP) { // TODO: why don't we just give groups key_data too? bActionGroup *agrp = (bActionGroup *)ale->data; agroup_to_keylist(adt, agrp, &anim_keys, NULL); } else if (ale->type == ANIMTYPE_GPLAYER) { // TODO: why don't we just give gplayers key_data too? bGPDlayer *gpl = (bGPDlayer *)ale->data; gpl_to_keylist(ads, gpl, &anim_keys); } else if (ale->type == ANIMTYPE_MASKLAYER) { // TODO: why don't we just give masklayers key_data too? MaskLayer *masklay = (MaskLayer *)ale->data; mask_to_keylist(ads, masklay, &anim_keys); } /* start from keyframe at root of BST, traversing until we find one within the range that was clicked on */ for (ak = anim_keys.root; ak; ak = akn) { if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) { /* set the frame to use, and apply inverse-correction for NLA-mapping * so that the frame will get selected by the selection functions without * requiring to map each frame once again... */ selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); frame = ak->cfra; found = true; break; } else if (ak->cfra < rectf.xmin) akn = ak->right; else akn = ak->left; } /* remove active channel from list of channels for separate treatment (since it's needed later on) */ BLI_remlink(&anim_data, ale); /* cleanup temporary lists */ BLI_dlrbTree_free(&anim_keys); /* free list of channels, since it's not used anymore */ ANIM_animdata_freelist(&anim_data); } /* for replacing selection, firstly need to clear existing selection */ if (select_mode == SELECT_REPLACE) { /* reset selection mode for next steps */ select_mode = SELECT_ADD; /* deselect all keyframes */ deselect_action_keys(ac, 0, SELECT_SUBTRACT); /* highlight channel clicked on */ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) { /* deselect all other channels first */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); /* Highlight Action-Group or F-Curve? */ if (ale && ale->data) { if (ale->type == ANIMTYPE_GROUP) { bActionGroup *agrp = ale->data; agrp->flag |= AGRP_SELECTED; ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); } else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { FCurve *fcu = ale->data; fcu->flag |= FCURVE_SELECTED; ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); } } } else if (ac->datatype == ANIMCONT_GPENCIL) { /* deselect all other channels first */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); /* Highlight GPencil Layer */ if ((ale && ale->data) && (ale->type == ANIMTYPE_GPLAYER)) { bGPDlayer *gpl = ale->data; gpl->flag |= GP_LAYER_SELECT; //gpencil_layer_setactive(gpd, gpl); } } else if (ac->datatype == ANIMCONT_MASK) { /* deselect all other channels first */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); /* Highlight GPencil Layer */ if ((ale && ale->data) && (ale->type == ANIMTYPE_MASKLAYER)) { MaskLayer *masklay = ale->data; masklay->flag |= MASK_LAYERFLAG_SELECT; //gpencil_layer_setactive(gpd, gpl); } } } /* only select keyframes if we clicked on a valid channel and hit something */ if (ale) { if (found) { /* apply selection to keyframes */ if (column) { /* select all keyframes in the same frame as the one we hit on the active channel * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here * does that itself again as it needs to work on multiple datablocks */ actkeys_mselect_column(ac, select_mode, frame); } else if (same_channel) { /* select all keyframes in the active channel */ actkeys_mselect_channel_only(ac, ale, select_mode); } else { /* select the nominated keyframe on the given frame */ actkeys_mselect_single(ac, ale, select_mode, selx); } } /* free this channel */ MEM_freeN(ale); } }