2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Joshua Leung (full recode)
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/animation/keyframes_draw.c
29 * \ingroup edanimation
33 /* System includes ----------------------------------------------------- */
40 #include "MEM_guardedalloc.h"
42 #include "BLI_dlrbTree.h"
43 #include "BLI_utildefines.h"
45 #include "DNA_anim_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_gpencil_types.h"
49 #include "DNA_mask_types.h"
51 #include "BKE_fcurve.h"
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
58 #include "ED_anim_api.h"
59 #include "ED_keyframes_draw.h"
61 /* *************************** Keyframe Processing *************************** */
63 /* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
65 /* Comparator callback used for ActKeyColumns and cframe float-value pointer */
66 /* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
67 short compare_ak_cfraPtr(void *node, void *data)
69 ActKeyColumn *ak = (ActKeyColumn *)node;
70 const float *cframe = data;
73 if (IS_EQT(val, ak->cfra, BEZT_BINARYSEARCH_THRESH))
78 else if (val > ak->cfra)
86 /* Comparator callback used for ActKeyColumns and BezTriple */
87 static short compare_ak_bezt(void *node, void *data)
89 ActKeyColumn *ak = (ActKeyColumn *)node;
90 BezTriple *bezt = (BezTriple *)data;
92 if (bezt->vec[1][0] < ak->cfra)
94 else if (bezt->vec[1][0] > ak->cfra)
100 /* New node callback used for building ActKeyColumns from BezTriples */
101 static DLRBT_Node *nalloc_ak_bezt(void *data)
103 ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
104 BezTriple *bezt = (BezTriple *)data;
106 /* store settings based on state of BezTriple */
107 ak->cfra = bezt->vec[1][0];
108 ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
109 ak->key_type = BEZKEYTYPE(bezt);
111 /* set 'modified', since this is used to identify long keyframes */
114 return (DLRBT_Node *)ak;
117 /* Node updater callback used for building ActKeyColumns from BezTriples */
118 static void nupdate_ak_bezt(void *node, void *data)
120 ActKeyColumn *ak = (ActKeyColumn *)node;
121 BezTriple *bezt = (BezTriple *)data;
123 /* set selection status and 'touched' status */
124 if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
127 /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
128 if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME)
129 ak->key_type = BEZT_KEYTYPE_KEYFRAME;
134 /* Comparator callback used for ActKeyColumns and GPencil frame */
135 static short compare_ak_gpframe(void *node, void *data)
137 ActKeyColumn *ak = (ActKeyColumn *)node;
138 bGPDframe *gpf = (bGPDframe *)data;
140 if (gpf->framenum < ak->cfra)
142 else if (gpf->framenum > ak->cfra)
148 /* New node callback used for building ActKeyColumns from GPencil frames */
149 static DLRBT_Node *nalloc_ak_gpframe(void *data)
151 ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
152 bGPDframe *gpf = (bGPDframe *)data;
154 /* store settings based on state of BezTriple */
155 ak->cfra = gpf->framenum;
156 ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
157 ak->key_type = gpf->key_type;
159 /* set 'modified', since this is used to identify long keyframes */
162 return (DLRBT_Node *)ak;
165 /* Node updater callback used for building ActKeyColumns from GPencil frames */
166 static void nupdate_ak_gpframe(void *node, void *data)
168 ActKeyColumn *ak = (ActKeyColumn *)node;
169 bGPDframe *gpf = (bGPDframe *)data;
171 /* set selection status and 'touched' status */
172 if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT;
175 /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
176 if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME)
177 ak->key_type = BEZT_KEYTYPE_KEYFRAME;
182 /* Comparator callback used for ActKeyColumns and GPencil frame */
183 static short compare_ak_masklayshape(void *node, void *data)
185 ActKeyColumn *ak = (ActKeyColumn *)node;
186 MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
188 if (masklay_shape->frame < ak->cfra)
190 else if (masklay_shape->frame > ak->cfra)
196 /* New node callback used for building ActKeyColumns from GPencil frames */
197 static DLRBT_Node *nalloc_ak_masklayshape(void *data)
199 ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
200 MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
202 /* store settings based on state of BezTriple */
203 ak->cfra = masklay_shape->frame;
204 ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
206 /* set 'modified', since this is used to identify long keyframes */
209 return (DLRBT_Node *)ak;
212 /* Node updater callback used for building ActKeyColumns from GPencil frames */
213 static void nupdate_ak_masklayshape(void *node, void *data)
215 ActKeyColumn *ak = (ActKeyColumn *)node;
216 MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
218 /* set selection status and 'touched' status */
219 if (masklay_shape->flag & MASK_SHAPE_SELECT) ak->sel = SELECT;
224 /* --------------- */
226 /* Add the given BezTriple to the given 'list' of Keyframes */
227 static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt)
229 if (ELEM(NULL, keys, bezt))
232 BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
235 /* Add the given GPencil Frame to the given 'list' of Keyframes */
236 static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
238 if (ELEM(NULL, keys, gpf))
241 BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
244 /* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
245 static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
247 if (ELEM(NULL, keys, masklay_shape))
250 BLI_dlrbTree_add(keys, compare_ak_masklayshape, nalloc_ak_masklayshape, nupdate_ak_masklayshape, masklay_shape);
253 /* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
255 /* Comparator callback used for ActKeyBlock and cframe float-value pointer */
256 /* NOTE: this is exported to other modules that use the ActKeyBlocks for finding long-keyframes */
257 short compare_ab_cfraPtr(void *node, void *data)
259 ActKeyBlock *ab = (ActKeyBlock *)node;
260 const float *cframe = data;
265 else if (val > ab->start)
271 /* --------------- */
273 /* Create a ActKeyColumn for a pair of BezTriples */
274 static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
276 ActKeyBlock *ab = MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");
278 ab->start = prev->vec[1][0];
279 ab->end = beztn->vec[1][0];
280 ab->val = beztn->vec[1][1];
282 ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
288 static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt, BezTriple *beztn)
290 ActKeyBlock *new_ab = NULL;
291 BezTriple *prev = NULL;
293 /* get the BezTriple immediately before the given one which has the same value */
294 if (beztn != first_bezt) {
295 /* XXX: Unless I'm overlooking some details from the past, this should be sufficient?
296 * The old code did some elaborate stuff trying to find keyframe columns for
297 * the given BezTriple, then step backwards to the column before that, and find
298 * an appropriate BezTriple with matching values there. Maybe that was warranted
299 * in the past, but now, that list is only ever filled with keyframes from the
302 * -- Aligorith (20140415)
308 /* check if block needed - same value(s)?
309 * -> firstly, handles must have same central value as each other
310 * -> secondly, handles which control that section of the curve must be constant
312 if (prev == NULL) return;
313 if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
315 if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
316 if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
319 /* if there are no blocks already, just add as root */
320 if (blocks->root == NULL) {
321 /* just add this as the root, then call the tree-balancing functions to validate */
322 new_ab = bezts_to_new_actkeyblock(prev, beztn);
323 blocks->root = (DLRBT_Node *)new_ab;
326 ActKeyBlock *ab, *abn = NULL;
328 /* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there
329 * Note: we perform a tree traversal here NOT a standard linked-list traversal...
330 * Note: we can't search from end to try to optimize this as it causes errors there's
331 * an A ___ B |---| B situation
333 // FIXME: here there is a bug where we are trying to get the summary for the following channels
334 // A|--------------|A ______________ B|--------------|B
335 // A|------------------------------------------------|A
336 // A|----|A|---|A|-----------------------------------|A
337 for (ab = blocks->root; ab; ab = abn) {
338 /* check if this is a match, or whether we go left or right
339 * NOTE: we now use a float threshold to prevent precision errors causing problems with summaries
341 if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
342 /* set selection status and 'touched' status */
343 if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT;
346 /* done... no need to insert */
350 ActKeyBlock **abnp = NULL; /* branch to go down - used to hook new blocks to parents */
352 /* check if go left or right, but if not available, add new node */
353 if (ab->start < prev->vec[1][0])
358 /* if this does not exist, add a new node, otherwise continue... */
360 /* add a new node representing this, and attach it to the relevant place */
361 new_ab = bezts_to_new_actkeyblock(prev, beztn);
372 /* now, balance the tree taking into account this newly added node */
373 BLI_dlrbTree_insert(blocks, (DLRBT_Node *)new_ab);
378 /* Handle the 'touched' status of ActKeyColumn tree nodes */
379 static void set_touched_actkeycolumn(ActKeyColumn *ak)
385 /* deal with self first */
392 set_touched_actkeycolumn(ak->left);
393 set_touched_actkeycolumn(ak->right);
396 /* Handle the 'touched' status of ActKeyBlock tree nodes */
397 static void set_touched_actkeyblock(ActKeyBlock *ab)
403 /* deal with self first */
410 set_touched_actkeyblock(ab->left);
411 set_touched_actkeyblock(ab->right);
416 /* Checks if ActKeyBlock should exist... */
417 bool actkeyblock_is_valid(ActKeyBlock *ab, DLRBT_Tree *keys)
420 short startCurves, endCurves, totCurves;
422 /* check that block is valid */
426 /* find out how many curves occur at each keyframe */
427 ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->start);
428 startCurves = (ak) ? ak->totcurve : 0;
430 ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->end);
431 endCurves = (ak) ? ak->totcurve : 0;
433 /* only draw keyblock if it appears in at all of the keyframes at lowest end */
434 if (!startCurves && !endCurves)
437 totCurves = (startCurves > endCurves) ? endCurves : startCurves;
438 return (ab->totcurve >= totCurves);
441 /* *************************** Keyframe Drawing *************************** */
443 /* coordinates for diamond shape */
444 static const float _unit_diamond_shape[4][2] = {
445 {0.0f, 1.0f}, /* top vert */
446 {1.0f, 0.0f}, /* mid-right */
447 {0.0f, -1.0f}, /* bottom vert */
448 {-1.0f, 0.0f} /* mid-left */
451 /* draw a simple diamond shape with OpenGL */
452 void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha)
454 static GLuint displist1 = 0;
455 static GLuint displist2 = 0;
457 /* initialize 2 display lists for diamond shape - one empty, one filled */
458 if (displist1 == 0) {
459 displist1 = glGenLists(1);
460 glNewList(displist1, GL_COMPILE);
462 glBegin(GL_LINE_LOOP);
463 glVertex2fv(_unit_diamond_shape[0]);
464 glVertex2fv(_unit_diamond_shape[1]);
465 glVertex2fv(_unit_diamond_shape[2]);
466 glVertex2fv(_unit_diamond_shape[3]);
471 if (displist2 == 0) {
472 displist2 = glGenLists(1);
473 glNewList(displist2, GL_COMPILE);
476 glVertex2fv(_unit_diamond_shape[0]);
477 glVertex2fv(_unit_diamond_shape[1]);
478 glVertex2fv(_unit_diamond_shape[2]);
479 glVertex2fv(_unit_diamond_shape[3]);
485 /* tweak size of keyframe shape according to type of keyframe
486 * - 'proper' keyframes have key_type = 0, so get drawn at full size
488 hsize -= 0.5f * key_type;
490 /* adjust view transform before starting */
491 glTranslatef(x, y, 0.0f);
492 glScalef(1.0f / xscale * hsize, hsize, 1.0f);
494 /* anti-aliased lines for more consistent appearance */
495 glEnable(GL_LINE_SMOOTH);
498 if (ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH)) {
501 /* get interior colors from theme (for selected and unselected only) */
503 case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */
505 if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN_SELECT, inner_col);
506 else UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN, inner_col);
509 case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */
511 if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME_SELECT, inner_col);
512 else UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME, inner_col);
515 case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */
517 if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_JITTER_SELECT, inner_col);
518 else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col);
521 case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
524 if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME_SELECT, inner_col);
525 else UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME, inner_col);
530 /* NOTE: we don't use the straight alpha from the theme, or else effects such as
531 * graying out protected/muted channels doesn't work correctly!
533 inner_col[3] *= alpha;
534 glColor4fv(inner_col);
536 /* draw the "filled in" interior poly now */
537 glCallList(displist2);
540 if (ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH)) {
543 /* exterior - black frame */
544 if (sel) UI_GetThemeColor4fv(TH_KEYBORDER_SELECT, border_col);
545 else UI_GetThemeColor4fv(TH_KEYBORDER, border_col);
547 border_col[3] *= alpha;
548 glColor4fv(border_col);
550 glCallList(displist1);
553 glDisable(GL_LINE_SMOOTH);
555 /* restore view transform */
556 glScalef(xscale / hsize, 1.0f / hsize, 1.0f);
557 glTranslatef(-x, -y, 0.0f);
560 static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, short channelLocked)
566 float iconsize = U.widget_unit / 4.0f;
569 /* get View2D scaling factor */
570 UI_view2d_scale_get(v2d, &xscale, NULL);
572 /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */
573 /* TODO: allow this opacity factor to be themed? */
574 alpha = (channelLocked) ? 0.25f : 1.0f;
578 float sel_color[4], unsel_color[4];
580 /* cache colours first */
581 UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
582 UI_GetThemeColor4fv(TH_STRIP, unsel_color);
584 sel_color[3] *= alpha;
585 unsel_color[3] *= alpha;
587 /* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */
588 for (ab = blocks->first; ab; ab = ab->next) {
589 if (actkeyblock_is_valid(ab, keys)) {
592 glColor4fv(sel_color);
594 glColor4fv(unsel_color);
596 glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
603 for (ak = keys->first; ak; ak = ak->next) {
604 /* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw
605 * - this might give some improvements, since we current have to flip between view/region matrices
607 if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax) == 0)
610 /* draw using OpenGL - uglier but faster */
611 /* NOTE1: a previous version of this didn't work nice for some intel cards
612 * NOTE2: if we wanted to go back to icons, these are icon = (ak->sel & SELECT) ? ICON_SPACE2 : ICON_SPACE3; */
613 draw_keyframe_shape(ak->cfra, ypos, xscale, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha);
620 /* *************************** Channel Drawing Funcs *************************** */
622 void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos)
624 DLRBT_Tree keys, blocks;
626 BLI_dlrbTree_init(&keys);
627 BLI_dlrbTree_init(&blocks);
629 summary_to_keylist(ac, &keys, &blocks);
631 BLI_dlrbTree_linkedlist_sync(&keys);
632 BLI_dlrbTree_linkedlist_sync(&blocks);
634 draw_keylist(v2d, &keys, &blocks, ypos, 0);
636 BLI_dlrbTree_free(&keys);
637 BLI_dlrbTree_free(&blocks);
640 void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
642 DLRBT_Tree keys, blocks;
644 BLI_dlrbTree_init(&keys);
645 BLI_dlrbTree_init(&blocks);
647 scene_to_keylist(ads, sce, &keys, &blocks);
649 BLI_dlrbTree_linkedlist_sync(&keys);
650 BLI_dlrbTree_linkedlist_sync(&blocks);
652 draw_keylist(v2d, &keys, &blocks, ypos, 0);
654 BLI_dlrbTree_free(&keys);
655 BLI_dlrbTree_free(&blocks);
658 void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos)
660 DLRBT_Tree keys, blocks;
662 BLI_dlrbTree_init(&keys);
663 BLI_dlrbTree_init(&blocks);
665 ob_to_keylist(ads, ob, &keys, &blocks);
667 BLI_dlrbTree_linkedlist_sync(&keys);
668 BLI_dlrbTree_linkedlist_sync(&blocks);
670 draw_keylist(v2d, &keys, &blocks, ypos, 0);
672 BLI_dlrbTree_free(&keys);
673 BLI_dlrbTree_free(&blocks);
676 void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos)
678 DLRBT_Tree keys, blocks;
680 short locked = (fcu->flag & FCURVE_PROTECTED) ||
681 ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
682 ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action));
684 BLI_dlrbTree_init(&keys);
685 BLI_dlrbTree_init(&blocks);
687 fcurve_to_keylist(adt, fcu, &keys, &blocks);
689 BLI_dlrbTree_linkedlist_sync(&keys);
690 BLI_dlrbTree_linkedlist_sync(&blocks);
692 draw_keylist(v2d, &keys, &blocks, ypos, locked);
694 BLI_dlrbTree_free(&keys);
695 BLI_dlrbTree_free(&blocks);
698 void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos)
700 DLRBT_Tree keys, blocks;
702 short locked = (agrp->flag & AGRP_PROTECTED) ||
703 ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action));
705 BLI_dlrbTree_init(&keys);
706 BLI_dlrbTree_init(&blocks);
708 agroup_to_keylist(adt, agrp, &keys, &blocks);
710 BLI_dlrbTree_linkedlist_sync(&keys);
711 BLI_dlrbTree_linkedlist_sync(&blocks);
713 draw_keylist(v2d, &keys, &blocks, ypos, locked);
715 BLI_dlrbTree_free(&keys);
716 BLI_dlrbTree_free(&blocks);
719 void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
721 DLRBT_Tree keys, blocks;
723 short locked = (act && ID_IS_LINKED_DATABLOCK(act));
725 BLI_dlrbTree_init(&keys);
726 BLI_dlrbTree_init(&blocks);
728 action_to_keylist(adt, act, &keys, &blocks);
730 BLI_dlrbTree_linkedlist_sync(&keys);
731 BLI_dlrbTree_linkedlist_sync(&blocks);
733 draw_keylist(v2d, &keys, &blocks, ypos, locked);
735 BLI_dlrbTree_free(&keys);
736 BLI_dlrbTree_free(&blocks);
739 void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos)
743 BLI_dlrbTree_init(&keys);
745 gpencil_to_keylist(ads, gpd, &keys);
747 BLI_dlrbTree_linkedlist_sync(&keys);
749 draw_keylist(v2d, &keys, NULL, ypos, 0);
751 BLI_dlrbTree_free(&keys);
754 void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
758 BLI_dlrbTree_init(&keys);
760 gpl_to_keylist(ads, gpl, &keys);
762 BLI_dlrbTree_linkedlist_sync(&keys);
764 draw_keylist(v2d, &keys, NULL, ypos, (gpl->flag & GP_LAYER_LOCKED));
766 BLI_dlrbTree_free(&keys);
769 void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos)
773 BLI_dlrbTree_init(&keys);
775 mask_to_keylist(ads, masklay, &keys);
777 BLI_dlrbTree_linkedlist_sync(&keys);
779 draw_keylist(v2d, &keys, NULL, ypos, (masklay->flag & MASK_LAYERFLAG_LOCKED));
781 BLI_dlrbTree_free(&keys);
784 /* *************************** Keyframe List Conversions *************************** */
786 void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
789 ListBase anim_data = {NULL, NULL};
793 /* get F-Curves to take keyframes from */
794 filter = ANIMFILTER_DATA_VISIBLE;
795 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
797 /* loop through each F-Curve, grabbing the keyframes */
798 for (ale = anim_data.first; ale; ale = ale->next) {
799 /* Why not use all #eAnim_KeyType here?
800 * All of the other key types are actually "summaries" themselves, and will just end up duplicating stuff
801 * that comes up through standard filtering of just F-Curves.
802 * Given the way that these work, there isn't really any benefit at all from including them. - Aligorith */
804 switch (ale->datatype) {
806 fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
809 mask_to_keylist(ac->ads, ale->data, keys);
812 gpl_to_keylist(ac->ads, ale->data, keys);
815 // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
820 ANIM_animdata_freelist(&anim_data);
824 void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree *blocks)
826 bAnimContext ac = {NULL};
827 ListBase anim_data = {NULL, NULL};
831 bAnimListElem dummychan = {NULL};
836 /* create a dummy wrapper data to work with */
837 dummychan.type = ANIMTYPE_SCENE;
838 dummychan.data = sce;
839 dummychan.id = &sce->id;
840 dummychan.adt = sce->adt;
843 ac.data = &dummychan;
844 ac.datatype = ANIMCONT_CHANNEL;
846 /* get F-Curves to take keyframes from */
847 filter = ANIMFILTER_DATA_VISIBLE; // curves only
848 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
850 /* loop through each F-Curve, grabbing the keyframes */
851 for (ale = anim_data.first; ale; ale = ale->next)
852 fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
854 ANIM_animdata_freelist(&anim_data);
857 void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *blocks)
859 bAnimContext ac = {NULL};
860 ListBase anim_data = {NULL, NULL};
864 bAnimListElem dummychan = {NULL};
865 Base dummybase = {NULL};
870 /* create a dummy wrapper data to work with */
871 dummybase.object = ob;
873 dummychan.type = ANIMTYPE_OBJECT;
874 dummychan.data = &dummybase;
875 dummychan.id = &ob->id;
876 dummychan.adt = ob->adt;
879 ac.data = &dummychan;
880 ac.datatype = ANIMCONT_CHANNEL;
882 /* get F-Curves to take keyframes from */
883 filter = ANIMFILTER_DATA_VISIBLE; // curves only
884 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
886 /* loop through each F-Curve, grabbing the keyframes */
887 for (ale = anim_data.first; ale; ale = ale->next)
888 fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
890 ANIM_animdata_freelist(&anim_data);
893 void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks)
898 if (fcu && fcu->totvert && fcu->bezt) {
899 /* apply NLA-mapping (if applicable) */
901 ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
903 /* loop through beztriples, making ActKeysColumns and ActKeyBlocks */
904 for (v = 0, bezt = fcu->bezt; v < fcu->totvert; v++, bezt++) {
905 add_bezt_to_keycolumns_list(keys, bezt);
906 if (blocks) add_bezt_to_keyblocks_list(blocks, fcu->bezt, bezt);
909 /* update the number of curves that elements have appeared in */
911 set_touched_actkeycolumn(keys->root);
913 set_touched_actkeyblock(blocks->root);
915 /* unapply NLA-mapping if applicable */
917 ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
921 void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, DLRBT_Tree *blocks)
926 /* loop through F-Curves */
927 for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
928 fcurve_to_keylist(adt, fcu, keys, blocks);
933 void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree *blocks)
938 /* loop through F-Curves */
939 for (fcu = act->curves.first; fcu; fcu = fcu->next) {
940 fcurve_to_keylist(adt, fcu, keys, blocks);
946 void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
951 /* for now, just aggregate out all the frames, but only for visible layers */
952 for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
953 if ((gpl->flag & GP_LAYER_HIDE) == 0) {
954 gpl_to_keylist(ads, gpl, keys);
960 void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
965 /* although the frames should already be in an ordered list, they are not suitable for displaying yet */
966 for (gpf = gpl->frames.first; gpf; gpf = gpf->next)
967 add_gpframe_to_keycolumns_list(keys, gpf);
971 void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
973 MaskLayerShape *masklay_shape;
975 if (masklay && keys) {
976 for (masklay_shape = masklay->splines_shapes.first;
978 masklay_shape = masklay_shape->next)
980 add_masklay_to_keycolumns_list(keys, masklay_shape);