Dope Sheet: remove many hard-coded color and alpha constants.
[blender.git] / source / blender / editors / animation / keyframes_draw.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung (full recode)
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/animation/keyframes_draw.c
29  *  \ingroup edanimation
30  */
31
32
33 /* System includes ----------------------------------------------------- */
34
35 #include <math.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <float.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_dlrbTree.h"
43 #include "BLI_math.h"
44 #include "BLI_utildefines.h"
45
46 #include "DNA_anim_types.h"
47 #include "DNA_cachefile_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_gpencil_types.h"
51 #include "DNA_brush_types.h"
52 #include "DNA_mask_types.h"
53
54 #include "BKE_fcurve.h"
55
56 #include "GPU_draw.h"
57 #include "GPU_immediate.h"
58 #include "GPU_state.h"
59
60 #include "UI_resources.h"
61 #include "UI_view2d.h"
62
63 #include "ED_anim_api.h"
64 #include "ED_keyframes_draw.h"
65
66 /* *************************** Keyframe Processing *************************** */
67
68 /* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
69
70 BLI_INLINE bool is_cfra_eq(float a, float b)
71 {
72         return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
73 }
74
75 BLI_INLINE bool is_cfra_lt(float a, float b)
76 {
77         return (b - a) > BEZT_BINARYSEARCH_THRESH;
78 }
79
80 /* Comparator callback used for ActKeyColumns and cframe float-value pointer */
81 /* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
82 short compare_ak_cfraPtr(void *node, void *data)
83 {
84         ActKeyColumn *ak = (ActKeyColumn *)node;
85         const float *cframe = data;
86         float val = *cframe;
87
88         if (is_cfra_eq(val, ak->cfra))
89                 return 0;
90
91         if (val < ak->cfra)
92                 return -1;
93         else
94                 return 1;
95 }
96
97 /* --------------- */
98
99 /* Comparator callback used for ActKeyColumns and BezTriple */
100 static short compare_ak_bezt(void *node, void *data)
101 {
102         BezTriple *bezt = (BezTriple *)data;
103
104         return compare_ak_cfraPtr(node, &bezt->vec[1][0]);
105 }
106
107 /* New node callback used for building ActKeyColumns from BezTriples */
108 static DLRBT_Node *nalloc_ak_bezt(void *data)
109 {
110         ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
111         BezTriple *bezt = (BezTriple *)data;
112
113         /* store settings based on state of BezTriple */
114         ak->cfra = bezt->vec[1][0];
115         ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
116         ak->key_type = BEZKEYTYPE(bezt);
117
118         /* count keyframes in this column */
119         ak->totkey = 1;
120
121         return (DLRBT_Node *)ak;
122 }
123
124 /* Node updater callback used for building ActKeyColumns from BezTriples */
125 static void nupdate_ak_bezt(void *node, void *data)
126 {
127         ActKeyColumn *ak = (ActKeyColumn *)node;
128         BezTriple *bezt = (BezTriple *)data;
129
130         /* set selection status and 'touched' status */
131         if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
132
133         /* count keyframes in this column */
134         ak->totkey++;
135
136         /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
137         if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME)
138                 ak->key_type = BEZT_KEYTYPE_KEYFRAME;
139 }
140
141 /* ......... */
142
143 /* Comparator callback used for ActKeyColumns and GPencil frame */
144 static short compare_ak_gpframe(void *node, void *data)
145 {
146         bGPDframe *gpf = (bGPDframe *)data;
147
148         return compare_ak_cfraPtr(node, &gpf->framenum);
149 }
150
151 /* New node callback used for building ActKeyColumns from GPencil frames */
152 static DLRBT_Node *nalloc_ak_gpframe(void *data)
153 {
154         ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
155         bGPDframe *gpf = (bGPDframe *)data;
156
157         /* store settings based on state of BezTriple */
158         ak->cfra = gpf->framenum;
159         ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
160         ak->key_type = gpf->key_type;
161
162         /* count keyframes in this column */
163         ak->totkey = 1;
164
165         return (DLRBT_Node *)ak;
166 }
167
168 /* Node updater callback used for building ActKeyColumns from GPencil frames */
169 static void nupdate_ak_gpframe(void *node, void *data)
170 {
171         ActKeyColumn *ak = (ActKeyColumn *)node;
172         bGPDframe *gpf = (bGPDframe *)data;
173
174         /* set selection status and 'touched' status */
175         if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT;
176
177         /* count keyframes in this column */
178         ak->totkey++;
179
180         /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
181         if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME)
182                 ak->key_type = BEZT_KEYTYPE_KEYFRAME;
183 }
184
185 /* ......... */
186
187 /* Comparator callback used for ActKeyColumns and GPencil frame */
188 static short compare_ak_masklayshape(void *node, void *data)
189 {
190         MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
191
192         return compare_ak_cfraPtr(node, &masklay_shape->frame);
193 }
194
195 /* New node callback used for building ActKeyColumns from GPencil frames */
196 static DLRBT_Node *nalloc_ak_masklayshape(void *data)
197 {
198         ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
199         MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
200
201         /* store settings based on state of BezTriple */
202         ak->cfra = masklay_shape->frame;
203         ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
204
205         /* count keyframes in this column */
206         ak->totkey = 1;
207
208         return (DLRBT_Node *)ak;
209 }
210
211 /* Node updater callback used for building ActKeyColumns from GPencil frames */
212 static void nupdate_ak_masklayshape(void *node, void *data)
213 {
214         ActKeyColumn *ak = (ActKeyColumn *)node;
215         MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
216
217         /* set selection status and 'touched' status */
218         if (masklay_shape->flag & MASK_SHAPE_SELECT) ak->sel = SELECT;
219
220         /* count keyframes in this column */
221         ak->totkey++;
222 }
223
224
225 /* --------------- */
226
227 /* Add the given BezTriple to the given 'list' of Keyframes */
228 static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt)
229 {
230         if (ELEM(NULL, keys, bezt))
231                 return;
232         else
233                 BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
234 }
235
236 /* Add the given GPencil Frame to the given 'list' of Keyframes */
237 static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
238 {
239         if (ELEM(NULL, keys, gpf))
240                 return;
241         else
242                 BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
243 }
244
245 /* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
246 static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
247 {
248         if (ELEM(NULL, keys, masklay_shape))
249                 return;
250         else
251                 BLI_dlrbTree_add(keys, compare_ak_masklayshape, nalloc_ak_masklayshape, nupdate_ak_masklayshape, masklay_shape);
252 }
253
254 /* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
255
256 static const ActKeyBlockInfo dummy_keyblock = { 0 };
257
258 static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
259 {
260         memset(info, 0, sizeof(ActKeyBlockInfo));
261
262         if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
263                 /* Animator tagged a "moving hold"
264                  *   - Previous key must also be tagged as a moving hold, otherwise
265                  *     we're just dealing with the first of a pair, and we don't
266                  *     want to be creating any phantom holds...
267                  */
268                 if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
269                         info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
270                 }
271         }
272
273         /* Check for same values...
274          *  - Handles must have same central value as each other
275          *  - Handles which control that section of the curve must be constant
276          */
277         if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
278                 bool hold;
279
280                 /* Only check handles in case of actual bezier interpolation. */
281                 if (prev->ipo == BEZT_IPO_BEZ) {
282                         hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && IS_EQF(prev->vec[1][1], prev->vec[2][1]);
283                 }
284                 /* This interpolation type induces movement even between identical keys. */
285                 else {
286                         hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
287                 }
288
289                 if (hold) {
290                         info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
291                 }
292         }
293
294         info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
295 }
296
297 static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
298 {
299         /* New curve and block. */
300         if (col->totcurve <= 1 && col->totblock == 0) {
301                 memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
302         }
303         /* Existing curve. */
304         else {
305                 col->block.conflict |= (col->block.flag ^ block->flag);
306                 col->block.flag |= block->flag;
307                 col->block.sel |= block->sel;
308         }
309
310         if (block->flag) {
311                 col->totblock++;
312         }
313 }
314
315 static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
316 {
317         ActKeyColumn *col = keys->first;
318
319         if (bezt && bezt_len >= 2) {
320                 ActKeyBlockInfo block;
321
322                 /* Find the first key column while inserting dummy blocks. */
323                 for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
324                         add_keyblock_info(col, &dummy_keyblock);
325                 }
326
327                 BLI_assert(col != NULL);
328
329                 /* Insert real blocks. */
330                 for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
331                         /* Wrong order of bezier keys: resync position. */
332                         if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
333                                 /* Backtrack to find the right location. */
334                                 if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
335                                         ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
336                                                 keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
337
338                                         if (newcol != NULL) {
339                                                 col = newcol;
340
341                                                 /* The previous keyblock is garbage too. */
342                                                 if (col->prev != NULL) {
343                                                         add_keyblock_info(col->prev, &dummy_keyblock);
344                                                 }
345                                         }
346                                         else {
347                                                 BLI_assert(false);
348                                         }
349                                 }
350
351                                 continue;
352                         }
353
354                         /* Normal sequence */
355                         BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
356
357                         compute_keyblock_data(&block, bezt, bezt + 1);
358
359                         for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
360                                 add_keyblock_info(col, &block);
361                         }
362
363                         BLI_assert(col != NULL);
364                 }
365         }
366
367         /* Insert dummy blocks at the end. */
368         for (; col != NULL; col = col->next) {
369                 add_keyblock_info(col, &dummy_keyblock);
370         }
371 }
372
373 /* Walk through columns and propagate blocks and totcurve.
374  *
375  * This must be called even by animation sources that don't generate
376  * keyblocks to keep the data structure consistent after adding columns.
377  */
378 static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
379 {
380         /* Recompute the prev/next linked list. */
381         BLI_dlrbTree_linkedlist_sync(keys);
382
383         /* Find the curve count */
384         int max_curve = 0;
385
386         for (ActKeyColumn *col = keys->first; col; col = col->next) {
387                 max_curve = MAX2(max_curve, col->totcurve);
388         }
389
390         /* Propagate blocks to inserted keys */
391         ActKeyColumn *prev_ready = NULL;
392
393         for (ActKeyColumn *col = keys->first; col; col = col->next) {
394                 /* Pre-existing column. */
395                 if (col->totcurve > 0) {
396                         prev_ready = col;
397                 }
398                 /* Newly inserted column, so copy block data from previous. */
399                 else if (prev_ready != NULL) {
400                         col->totblock = prev_ready->totblock;
401                         memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
402                 }
403
404                 col->totcurve = max_curve + 1;
405         }
406
407         /* Add blocks on top */
408         add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
409 }
410
411 /* --------- */
412
413 /* Checks if ActKeyBlock should exist... */
414 int actkeyblock_get_valid_hold(ActKeyColumn *ac)
415 {
416         /* check that block is valid */
417         if (ac == NULL || ac->next == NULL || ac->totblock == 0)
418                 return 0;
419
420         const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD);
421         return (ac->block.flag & ~ac->block.conflict) & hold_mask;
422 }
423
424 /* *************************** Keyframe Drawing *************************** */
425
426 void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha,
427                          unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id)
428 {
429         bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH);
430         bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH);
431
432         BLI_assert(draw_fill || draw_outline);
433
434         /* tweak size of keyframe shape according to type of keyframe
435          * - 'proper' keyframes have key_type = 0, so get drawn at full size
436          */
437         switch (key_type) {
438                 case BEZT_KEYTYPE_KEYFRAME:  /* must be full size */
439                         break;
440
441                 case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
442                         size *= 0.85f;
443                         break;
444
445                 case BEZT_KEYTYPE_MOVEHOLD:  /* slightly smaller than normal keyframes (but by less than for breakdowns) */
446                         size *= 0.925f;
447                         break;
448
449                 case BEZT_KEYTYPE_EXTREME:   /* slightly larger */
450                         size *= 1.2f;
451                         break;
452
453                 default:
454                         size -= 0.8f * key_type;
455         }
456
457         unsigned char fill_col[4];
458         unsigned char outline_col[4];
459
460         /* draw! */
461         if (draw_fill) {
462                 /* get interior colors from theme (for selected and unselected only) */
463                 switch (key_type) {
464                         case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */
465                                 UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col);
466                                 break;
467                         case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */
468                                 UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col);
469                                 break;
470                         case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */
471                                 UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col);
472                                 break;
473                         case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
474                                 UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_MOVEHOLD_SELECT : TH_KEYTYPE_MOVEHOLD, fill_col);
475                                 break;
476                         case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
477                         default:
478                                 UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col);
479                 }
480
481                 /* NOTE: we don't use the straight alpha from the theme, or else effects such as
482                  * graying out protected/muted channels doesn't work correctly!
483                  */
484                 fill_col[3] *= alpha;
485
486                 if (!draw_outline) {
487                         /* force outline color to match */
488                         outline_col[0] = fill_col[0];
489                         outline_col[1] = fill_col[1];
490                         outline_col[2] = fill_col[2];
491                         outline_col[3] = fill_col[3];
492                 }
493         }
494
495         if (draw_outline) {
496                 /* exterior - black frame */
497                 UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col);
498                 outline_col[3] *= alpha;
499
500                 if (!draw_fill) {
501                         /* fill color needs to be (outline.rgb, 0) */
502                         fill_col[0] = outline_col[0];
503                         fill_col[1] = outline_col[1];
504                         fill_col[2] = outline_col[2];
505                         fill_col[3] = 0;
506                 }
507         }
508
509         immAttr1f(size_id, size);
510         immAttr4ubv(color_id, fill_col);
511         immAttr4ubv(outline_color_id, outline_col);
512         immVertex2f(pos_id, x, y);
513 }
514
515 static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale_fac, bool channelLocked)
516 {
517         const float icon_sz = U.widget_unit * 0.5f * yscale_fac;
518         const float half_icon_sz = 0.5f * icon_sz;
519         const float smaller_sz = 0.35f * icon_sz;
520
521         GPU_blend(true);
522
523         /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */
524         /* TODO: allow this opacity factor to be themed? */
525         float alpha = channelLocked ? 0.25f : 1.0f;
526
527         /* draw keyblocks */
528         if (keys) {
529                 float sel_color[4], unsel_color[4];
530                 float sel_mhcol[4], unsel_mhcol[4];
531
532                 /* cache colours first */
533                 UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
534                 UI_GetThemeColor4fv(TH_STRIP, unsel_color);
535
536                 sel_color[3]   *= alpha;
537                 unsel_color[3] *= alpha;
538
539                 copy_v4_v4(sel_mhcol, sel_color);
540                 sel_mhcol[3]   *= 0.8f;
541                 copy_v4_v4(unsel_mhcol, unsel_color);
542                 unsel_mhcol[3] *= 0.8f;
543
544                 uint block_len = 0;
545                 for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
546                         if (actkeyblock_get_valid_hold(ab)) {
547                                 block_len++;
548                         }
549                 }
550
551                 if (block_len > 0) {
552                         GPUVertFormat *format = immVertexFormat();
553                         uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
554                         uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
555                         immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
556
557                         immBegin(GPU_PRIM_TRIS, 6 * block_len);
558                         for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
559                                 int valid_hold = actkeyblock_get_valid_hold(ab);
560                                 if (valid_hold != 0) {
561                                         if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
562                                                 /* draw "moving hold" long-keyframe block - slightly smaller */
563                                                 immRectf_fast_with_color(pos_id, color_id,
564                                                                          ab->cfra, ypos - smaller_sz, ab->next->cfra, ypos + smaller_sz,
565                                                                          (ab->block.sel) ? sel_mhcol : unsel_mhcol);
566                                         }
567                                         else {
568                                                 /* draw standard long-keyframe block */
569                                                 immRectf_fast_with_color(pos_id, color_id,
570                                                                          ab->cfra, ypos - half_icon_sz, ab->next->cfra, ypos + half_icon_sz,
571                                                                          (ab->block.sel) ? sel_color : unsel_color);
572                                         }
573                                 }
574                         }
575                         immEnd();
576                         immUnbindProgram();
577                 }
578         }
579
580         if (keys) {
581                 /* count keys */
582                 uint key_len = 0;
583                 for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
584                         /* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw
585                          *      - this might give some improvements, since we current have to flip between view/region matrices
586                          */
587                         if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax))
588                                 key_len++;
589                 }
590
591                 if (key_len > 0) {
592                         /* draw keys */
593                         GPUVertFormat *format = immVertexFormat();
594                         uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
595                         uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
596                         uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
597                         uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
598                         immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
599                         GPU_enable_program_point_size();
600                         immBegin(GPU_PRIM_POINTS, key_len);
601
602                         for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
603                                 if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
604                                         draw_keyframe_shape(ak->cfra, ypos, icon_sz, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha,
605                                                             pos_id, size_id, color_id, outline_color_id);
606                                 }
607                         }
608
609                         immEnd();
610                         GPU_disable_program_point_size();
611                         immUnbindProgram();
612                 }
613         }
614
615         GPU_blend(false);
616 }
617
618 /* *************************** Channel Drawing Funcs *************************** */
619
620 void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac)
621 {
622         DLRBT_Tree keys;
623
624         BLI_dlrbTree_init(&keys);
625
626         summary_to_keylist(ac, &keys);
627
628         draw_keylist(v2d, &keys, ypos, yscale_fac, false);
629
630         BLI_dlrbTree_free(&keys);
631 }
632
633 void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac)
634 {
635         DLRBT_Tree keys;
636
637         BLI_dlrbTree_init(&keys);
638
639         scene_to_keylist(ads, sce, &keys);
640
641         draw_keylist(v2d, &keys, ypos, yscale_fac, false);
642
643         BLI_dlrbTree_free(&keys);
644 }
645
646 void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac)
647 {
648         DLRBT_Tree keys;
649
650         BLI_dlrbTree_init(&keys);
651
652         ob_to_keylist(ads, ob, &keys);
653
654         draw_keylist(v2d, &keys, ypos, yscale_fac, false);
655
656         BLI_dlrbTree_free(&keys);
657 }
658
659 void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac)
660 {
661         DLRBT_Tree keys;
662
663         bool locked = (fcu->flag & FCURVE_PROTECTED) ||
664                       ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
665                       ((adt && adt->action) && ID_IS_LINKED(adt->action));
666
667         BLI_dlrbTree_init(&keys);
668
669         fcurve_to_keylist(adt, fcu, &keys);
670
671         draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
672
673         BLI_dlrbTree_free(&keys);
674 }
675
676 void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac)
677 {
678         DLRBT_Tree keys;
679
680         bool locked = (agrp->flag & AGRP_PROTECTED) ||
681                       ((adt && adt->action) && ID_IS_LINKED(adt->action));
682
683         BLI_dlrbTree_init(&keys);
684
685         agroup_to_keylist(adt, agrp, &keys);
686
687         draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
688
689         BLI_dlrbTree_free(&keys);
690 }
691
692 void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac)
693 {
694         DLRBT_Tree keys;
695
696         bool locked = (act && ID_IS_LINKED(act));
697
698         BLI_dlrbTree_init(&keys);
699
700         action_to_keylist(adt, act, &keys);
701
702         draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
703
704         BLI_dlrbTree_free(&keys);
705 }
706
707 void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac)
708 {
709         DLRBT_Tree keys;
710
711         BLI_dlrbTree_init(&keys);
712
713         gpencil_to_keylist(ads, gpd, &keys, false);
714
715         draw_keylist(v2d, &keys, ypos, yscale_fac, false);
716
717         BLI_dlrbTree_free(&keys);
718 }
719
720 void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac)
721 {
722         DLRBT_Tree keys;
723
724         bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0;
725
726         BLI_dlrbTree_init(&keys);
727
728         gpl_to_keylist(ads, gpl, &keys);
729
730         draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
731
732         BLI_dlrbTree_free(&keys);
733 }
734
735 void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac)
736 {
737         DLRBT_Tree keys;
738
739         bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0;
740
741         BLI_dlrbTree_init(&keys);
742
743         mask_to_keylist(ads, masklay, &keys);
744
745         draw_keylist(v2d, &keys, ypos, yscale_fac, locked);
746
747         BLI_dlrbTree_free(&keys);
748 }
749
750 /* *************************** Keyframe List Conversions *************************** */
751
752 void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys)
753 {
754         if (ac) {
755                 ListBase anim_data = {NULL, NULL};
756                 bAnimListElem *ale;
757                 int filter;
758
759                 /* get F-Curves to take keyframes from */
760                 filter = ANIMFILTER_DATA_VISIBLE;
761                 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
762
763                 /* loop through each F-Curve, grabbing the keyframes */
764                 for (ale = anim_data.first; ale; ale = ale->next) {
765                         /* Why not use all #eAnim_KeyType here?
766                          * All of the other key types are actually "summaries" themselves, and will just end up duplicating stuff
767                          * that comes up through standard filtering of just F-Curves.
768                          * Given the way that these work, there isn't really any benefit at all from including them. - Aligorith */
769
770                         switch (ale->datatype) {
771                                 case ALE_FCURVE:
772                                         fcurve_to_keylist(ale->adt, ale->data, keys);
773                                         break;
774                                 case ALE_MASKLAY:
775                                         mask_to_keylist(ac->ads, ale->data, keys);
776                                         break;
777                                 case ALE_GPFRAME:
778                                         gpl_to_keylist(ac->ads, ale->data, keys);
779                                         break;
780                                 default:
781                                         // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
782                                         break;
783                         }
784                 }
785
786                 ANIM_animdata_freelist(&anim_data);
787         }
788 }
789
790 void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys)
791 {
792         bAnimContext ac = {NULL};
793         ListBase anim_data = {NULL, NULL};
794         bAnimListElem *ale;
795         int filter;
796
797         bAnimListElem dummychan = {NULL};
798
799         if (sce == NULL)
800                 return;
801
802         /* create a dummy wrapper data to work with */
803         dummychan.type = ANIMTYPE_SCENE;
804         dummychan.data = sce;
805         dummychan.id = &sce->id;
806         dummychan.adt = sce->adt;
807
808         ac.ads = ads;
809         ac.data = &dummychan;
810         ac.datatype = ANIMCONT_CHANNEL;
811
812         /* get F-Curves to take keyframes from */
813         filter = ANIMFILTER_DATA_VISIBLE; // curves only
814         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
815
816         /* loop through each F-Curve, grabbing the keyframes */
817         for (ale = anim_data.first; ale; ale = ale->next)
818                 fcurve_to_keylist(ale->adt, ale->data, keys);
819
820         ANIM_animdata_freelist(&anim_data);
821 }
822
823 void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys)
824 {
825         bAnimContext ac = {NULL};
826         ListBase anim_data = {NULL, NULL};
827         bAnimListElem *ale;
828         int filter;
829
830         bAnimListElem dummychan = {NULL};
831         Base dummybase = {NULL};
832
833         if (ob == NULL)
834                 return;
835
836         /* create a dummy wrapper data to work with */
837         dummybase.object = ob;
838
839         dummychan.type = ANIMTYPE_OBJECT;
840         dummychan.data = &dummybase;
841         dummychan.id = &ob->id;
842         dummychan.adt = ob->adt;
843
844         ac.ads = ads;
845         ac.data = &dummychan;
846         ac.datatype = ANIMCONT_CHANNEL;
847
848         /* get F-Curves to take keyframes from */
849         filter = ANIMFILTER_DATA_VISIBLE; // curves only
850         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
851
852         /* loop through each F-Curve, grabbing the keyframes */
853         for (ale = anim_data.first; ale; ale = ale->next)
854                 fcurve_to_keylist(ale->adt, ale->data, keys);
855
856         ANIM_animdata_freelist(&anim_data);
857 }
858
859 void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys)
860 {
861         if (cache_file == NULL) {
862                 return;
863         }
864
865         /* create a dummy wrapper data to work with */
866         bAnimListElem dummychan = {NULL};
867         dummychan.type = ANIMTYPE_DSCACHEFILE;
868         dummychan.data = cache_file;
869         dummychan.id = &cache_file->id;
870         dummychan.adt = cache_file->adt;
871
872         bAnimContext ac = {NULL};
873         ac.ads = ads;
874         ac.data = &dummychan;
875         ac.datatype = ANIMCONT_CHANNEL;
876
877         /* get F-Curves to take keyframes from */
878         ListBase anim_data = { NULL, NULL };
879         int filter = ANIMFILTER_DATA_VISIBLE; // curves only
880         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
881
882         /* loop through each F-Curve, grabbing the keyframes */
883         for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
884                 fcurve_to_keylist(ale->adt, ale->data, keys);
885         }
886
887         ANIM_animdata_freelist(&anim_data);
888 }
889
890 void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys)
891 {
892         BezTriple *bezt;
893         unsigned int v;
894
895         if (fcu && fcu->totvert && fcu->bezt) {
896                 /* apply NLA-mapping (if applicable) */
897                 if (adt)
898                         ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
899
900                 /* loop through beztriples, making ActKeysColumns */
901                 for (v = 0, bezt = fcu->bezt; v < fcu->totvert; v++, bezt++) {
902                         add_bezt_to_keycolumns_list(keys, bezt);
903                 }
904
905                 /* Update keyblocks. */
906                 update_keyblocks(keys, fcu->bezt, fcu->totvert);
907
908                 /* unapply NLA-mapping if applicable */
909                 if (adt)
910                         ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
911         }
912 }
913
914 void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys)
915 {
916         FCurve *fcu;
917
918         if (agrp) {
919                 /* loop through F-Curves */
920                 for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
921                         fcurve_to_keylist(adt, fcu, keys);
922                 }
923         }
924 }
925
926 void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys)
927 {
928         FCurve *fcu;
929
930         if (act) {
931                 /* loop through F-Curves */
932                 for (fcu = act->curves.first; fcu; fcu = fcu->next) {
933                         fcurve_to_keylist(adt, fcu, keys);
934                 }
935         }
936 }
937
938
939 void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
940 {
941         bGPDlayer *gpl;
942
943         if (gpd && keys) {
944                 /* for now, just aggregate out all the frames, but only for visible layers */
945                 for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
946                         if ((gpl->flag & GP_LAYER_HIDE) == 0) {
947                                 if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
948                                         gpl_to_keylist(ads, gpl, keys);
949                                 }
950                         }
951                 }
952         }
953 }
954
955 void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
956 {
957         bGPDframe *gpf;
958
959         if (gpl && keys) {
960                 /* although the frames should already be in an ordered list, they are not suitable for displaying yet */
961                 for (gpf = gpl->frames.first; gpf; gpf = gpf->next)
962                         add_gpframe_to_keycolumns_list(keys, gpf);
963
964                 update_keyblocks(keys, NULL, 0);
965         }
966 }
967
968 void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
969 {
970         MaskLayerShape *masklay_shape;
971
972         if (masklay && keys) {
973                 for (masklay_shape = masklay->splines_shapes.first;
974                      masklay_shape;
975                      masklay_shape = masklay_shape->next)
976                 {
977                         add_masklay_to_keycolumns_list(keys, masklay_shape);
978                 }
979
980                 update_keyblocks(keys, NULL, 0);
981         }
982 }