1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edanimation
22  */
23 
24 /* System includes ----------------------------------------------------- */
25 
26 #include <float.h>
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_dlrbTree.h"
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36 #include "BLI_rect.h"
37 #include "BLI_utildefines.h"
38 
39 #include "DNA_anim_types.h"
40 #include "DNA_brush_types.h"
41 #include "DNA_cachefile_types.h"
42 #include "DNA_gpencil_types.h"
43 #include "DNA_mask_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 
47 #include "BKE_fcurve.h"
48 
49 #include "GPU_immediate.h"
50 #include "GPU_state.h"
51 
52 #include "UI_resources.h"
53 #include "UI_view2d.h"
54 
55 #include "ED_anim_api.h"
56 #include "ED_keyframes_draw.h"
57 
58 /* *************************** Keyframe Processing *************************** */
59 
60 /* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
61 
is_cfra_eq(float a,float b)62 BLI_INLINE bool is_cfra_eq(float a, float b)
63 {
64   return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
65 }
66 
is_cfra_lt(float a,float b)67 BLI_INLINE bool is_cfra_lt(float a, float b)
68 {
69   return (b - a) > BEZT_BINARYSEARCH_THRESH;
70 }
71 
72 /* Comparator callback used for ActKeyColumns and cframe float-value pointer */
73 /* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
compare_ak_cfraPtr(void * node,void * data)74 short compare_ak_cfraPtr(void *node, void *data)
75 {
76   ActKeyColumn *ak = (ActKeyColumn *)node;
77   const float *cframe = data;
78   float val = *cframe;
79 
80   if (is_cfra_eq(val, ak->cfra)) {
81     return 0;
82   }
83 
84   if (val < ak->cfra) {
85     return -1;
86   }
87   return 1;
88 }
89 
90 /* --------------- */
91 
92 /* Set of references to three logically adjacent keys. */
93 typedef struct BezTripleChain {
94   /* Current keyframe. */
95   BezTriple *cur;
96 
97   /* Logical neighbors. May be NULL. */
98   BezTriple *prev, *next;
99 } BezTripleChain;
100 
101 /* Categorize the interpolation & handle type of the keyframe. */
bezt_handle_type(BezTriple * bezt)102 static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt)
103 {
104   if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
105     return KEYFRAME_HANDLE_AUTO_CLAMP;
106   }
107   if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
108     return KEYFRAME_HANDLE_AUTO;
109   }
110   if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
111     return KEYFRAME_HANDLE_VECTOR;
112   }
113   if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
114     return KEYFRAME_HANDLE_FREE;
115   }
116   return KEYFRAME_HANDLE_ALIGNED;
117 }
118 
119 /* Determine if the keyframe is an extreme by comparing with neighbors.
120  * Ends of fixed-value sections and of the whole curve are also marked.
121  */
bezt_extreme_type(BezTripleChain * chain)122 static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain)
123 {
124   if (chain->prev == NULL && chain->next == NULL) {
125     return KEYFRAME_EXTREME_NONE;
126   }
127 
128   /* Keyframe values for the current one and neighbors. */
129   float cur_y = chain->cur->vec[1][1];
130   float prev_y = cur_y, next_y = cur_y;
131 
132   if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
133     prev_y = chain->prev->vec[1][1];
134   }
135   if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
136     next_y = chain->next->vec[1][1];
137   }
138 
139   /* Static hold. */
140   if (prev_y == cur_y && next_y == cur_y) {
141     return KEYFRAME_EXTREME_FLAT;
142   }
143 
144   /* Middle of an incline. */
145   if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
146     return KEYFRAME_EXTREME_NONE;
147   }
148 
149   /* Bezier handle values for the overshoot check. */
150   bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
151   bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
152   float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
153   float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
154 
155   /* Detect extremes. One of the neighbors is allowed to be equal to current. */
156   if (prev_y < cur_y || next_y < cur_y) {
157     bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
158 
159     return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
160   }
161 
162   if (prev_y > cur_y || next_y > cur_y) {
163     bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
164 
165     return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
166   }
167 
168   return KEYFRAME_EXTREME_NONE;
169 }
170 
171 /* Comparator callback used for ActKeyColumns and BezTripleChain */
compare_ak_bezt(void * node,void * data)172 static short compare_ak_bezt(void *node, void *data)
173 {
174   BezTripleChain *chain = data;
175 
176   return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
177 }
178 
179 /* New node callback used for building ActKeyColumns from BezTripleChain */
nalloc_ak_bezt(void * data)180 static DLRBT_Node *nalloc_ak_bezt(void *data)
181 {
182   ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
183   BezTripleChain *chain = data;
184   BezTriple *bezt = chain->cur;
185 
186   /* store settings based on state of BezTriple */
187   ak->cfra = bezt->vec[1][0];
188   ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
189   ak->key_type = BEZKEYTYPE(bezt);
190   ak->handle_type = bezt_handle_type(bezt);
191   ak->extreme_type = bezt_extreme_type(chain);
192 
193   /* count keyframes in this column */
194   ak->totkey = 1;
195 
196   return (DLRBT_Node *)ak;
197 }
198 
199 /* Node updater callback used for building ActKeyColumns from BezTripleChain */
nupdate_ak_bezt(void * node,void * data)200 static void nupdate_ak_bezt(void *node, void *data)
201 {
202   ActKeyColumn *ak = node;
203   BezTripleChain *chain = data;
204   BezTriple *bezt = chain->cur;
205 
206   /* set selection status and 'touched' status */
207   if (BEZT_ISSEL_ANY(bezt)) {
208     ak->sel = SELECT;
209   }
210 
211   /* count keyframes in this column */
212   ak->totkey++;
213 
214   /* For keyframe type, 'proper' keyframes have priority over breakdowns
215    * (and other types for now). */
216   if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) {
217     ak->key_type = BEZT_KEYTYPE_KEYFRAME;
218   }
219 
220   /* For interpolation type, select the highest value (enum is sorted). */
221   ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
222 
223   /* For extremes, detect when combining different states. */
224   char new_extreme = bezt_extreme_type(chain);
225 
226   if (new_extreme != ak->extreme_type) {
227     /* Replace the flat status without adding mixed. */
228     if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
229       ak->extreme_type = new_extreme;
230     }
231     else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
232       ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
233     }
234   }
235 }
236 
237 /* ......... */
238 
239 /* Comparator callback used for ActKeyColumns and GPencil frame */
compare_ak_gpframe(void * node,void * data)240 static short compare_ak_gpframe(void *node, void *data)
241 {
242   bGPDframe *gpf = (bGPDframe *)data;
243 
244   float frame = gpf->framenum;
245   return compare_ak_cfraPtr(node, &frame);
246 }
247 
248 /* New node callback used for building ActKeyColumns from GPencil frames */
nalloc_ak_gpframe(void * data)249 static DLRBT_Node *nalloc_ak_gpframe(void *data)
250 {
251   ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
252   bGPDframe *gpf = (bGPDframe *)data;
253 
254   /* store settings based on state of BezTriple */
255   ak->cfra = gpf->framenum;
256   ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
257   ak->key_type = gpf->key_type;
258 
259   /* count keyframes in this column */
260   ak->totkey = 1;
261 
262   return (DLRBT_Node *)ak;
263 }
264 
265 /* Node updater callback used for building ActKeyColumns from GPencil frames */
nupdate_ak_gpframe(void * node,void * data)266 static void nupdate_ak_gpframe(void *node, void *data)
267 {
268   ActKeyColumn *ak = (ActKeyColumn *)node;
269   bGPDframe *gpf = (bGPDframe *)data;
270 
271   /* set selection status and 'touched' status */
272   if (gpf->flag & GP_FRAME_SELECT) {
273     ak->sel = SELECT;
274   }
275 
276   /* count keyframes in this column */
277   ak->totkey++;
278 
279   /* for keyframe type, 'proper' keyframes have priority over breakdowns
280    * (and other types for now). */
281   if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) {
282     ak->key_type = BEZT_KEYTYPE_KEYFRAME;
283   }
284 }
285 
286 /* ......... */
287 
288 /* Comparator callback used for ActKeyColumns and GPencil frame */
compare_ak_masklayshape(void * node,void * data)289 static short compare_ak_masklayshape(void *node, void *data)
290 {
291   MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
292 
293   float frame = masklay_shape->frame;
294   return compare_ak_cfraPtr(node, &frame);
295 }
296 
297 /* New node callback used for building ActKeyColumns from GPencil frames */
nalloc_ak_masklayshape(void * data)298 static DLRBT_Node *nalloc_ak_masklayshape(void *data)
299 {
300   ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF");
301   MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
302 
303   /* store settings based on state of BezTriple */
304   ak->cfra = masklay_shape->frame;
305   ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
306 
307   /* count keyframes in this column */
308   ak->totkey = 1;
309 
310   return (DLRBT_Node *)ak;
311 }
312 
313 /* Node updater callback used for building ActKeyColumns from GPencil frames */
nupdate_ak_masklayshape(void * node,void * data)314 static void nupdate_ak_masklayshape(void *node, void *data)
315 {
316   ActKeyColumn *ak = (ActKeyColumn *)node;
317   MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
318 
319   /* set selection status and 'touched' status */
320   if (masklay_shape->flag & MASK_SHAPE_SELECT) {
321     ak->sel = SELECT;
322   }
323 
324   /* count keyframes in this column */
325   ak->totkey++;
326 }
327 
328 /* --------------- */
329 
330 /* Add the given BezTriple to the given 'list' of Keyframes */
add_bezt_to_keycolumns_list(DLRBT_Tree * keys,BezTripleChain * bezt)331 static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
332 {
333   if (ELEM(NULL, keys, bezt)) {
334     return;
335   }
336 
337   BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
338 }
339 
340 /* Add the given GPencil Frame to the given 'list' of Keyframes */
add_gpframe_to_keycolumns_list(DLRBT_Tree * keys,bGPDframe * gpf)341 static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf)
342 {
343   if (ELEM(NULL, keys, gpf)) {
344     return;
345   }
346 
347   BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
348 }
349 
350 /* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
add_masklay_to_keycolumns_list(DLRBT_Tree * keys,MaskLayerShape * masklay_shape)351 static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape)
352 {
353   if (ELEM(NULL, keys, masklay_shape)) {
354     return;
355   }
356 
357   BLI_dlrbTree_add(keys,
358                    compare_ak_masklayshape,
359                    nalloc_ak_masklayshape,
360                    nupdate_ak_masklayshape,
361                    masklay_shape);
362 }
363 
364 /* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
365 
366 static const ActKeyBlockInfo dummy_keyblock = {0};
367 
compute_keyblock_data(ActKeyBlockInfo * info,BezTriple * prev,BezTriple * beztn)368 static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
369 {
370   memset(info, 0, sizeof(ActKeyBlockInfo));
371 
372   if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
373     /* Animator tagged a "moving hold"
374      *   - Previous key must also be tagged as a moving hold, otherwise
375      *     we're just dealing with the first of a pair, and we don't
376      *     want to be creating any phantom holds...
377      */
378     if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
379       info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
380     }
381   }
382 
383   /* Check for same values...
384    *  - Handles must have same central value as each other
385    *  - Handles which control that section of the curve must be constant
386    */
387   if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
388     bool hold;
389 
390     /* Only check handles in case of actual bezier interpolation. */
391     if (prev->ipo == BEZT_IPO_BEZ) {
392       hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
393              IS_EQF(prev->vec[1][1], prev->vec[2][1]);
394     }
395     /* This interpolation type induces movement even between identical keys. */
396     else {
397       hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
398     }
399 
400     if (hold) {
401       info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
402     }
403   }
404 
405   /* Remember non-bezier interpolation info. */
406   if (prev->ipo != BEZT_IPO_BEZ) {
407     info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
408   }
409 
410   info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
411 }
412 
add_keyblock_info(ActKeyColumn * col,const ActKeyBlockInfo * block)413 static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
414 {
415   /* New curve and block. */
416   if (col->totcurve <= 1 && col->totblock == 0) {
417     memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
418   }
419   /* Existing curve. */
420   else {
421     col->block.conflict |= (col->block.flag ^ block->flag);
422     col->block.flag |= block->flag;
423     col->block.sel |= block->sel;
424   }
425 
426   if (block->flag) {
427     col->totblock++;
428   }
429 }
430 
add_bezt_to_keyblocks_list(DLRBT_Tree * keys,BezTriple * bezt,int bezt_len)431 static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
432 {
433   ActKeyColumn *col = keys->first;
434 
435   if (bezt && bezt_len >= 2) {
436     ActKeyBlockInfo block;
437 
438     /* Find the first key column while inserting dummy blocks. */
439     for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
440       add_keyblock_info(col, &dummy_keyblock);
441     }
442 
443     BLI_assert(col != NULL);
444 
445     /* Insert real blocks. */
446     for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
447       /* Wrong order of bezier keys: resync position. */
448       if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
449         /* Backtrack to find the right location. */
450         if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
451           ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
452               keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
453 
454           if (newcol != NULL) {
455             col = newcol;
456 
457             /* The previous keyblock is garbage too. */
458             if (col->prev != NULL) {
459               add_keyblock_info(col->prev, &dummy_keyblock);
460             }
461           }
462           else {
463             BLI_assert(false);
464           }
465         }
466 
467         continue;
468       }
469 
470       /* Normal sequence */
471       BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
472 
473       compute_keyblock_data(&block, bezt, bezt + 1);
474 
475       for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
476         add_keyblock_info(col, &block);
477       }
478 
479       BLI_assert(col != NULL);
480     }
481   }
482 
483   /* Insert dummy blocks at the end. */
484   for (; col != NULL; col = col->next) {
485     add_keyblock_info(col, &dummy_keyblock);
486   }
487 }
488 
489 /* Walk through columns and propagate blocks and totcurve.
490  *
491  * This must be called even by animation sources that don't generate
492  * keyblocks to keep the data structure consistent after adding columns.
493  */
update_keyblocks(DLRBT_Tree * keys,BezTriple * bezt,int bezt_len)494 static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
495 {
496   /* Recompute the prev/next linked list. */
497   BLI_dlrbTree_linkedlist_sync(keys);
498 
499   /* Find the curve count */
500   int max_curve = 0;
501 
502   LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
503     max_curve = MAX2(max_curve, col->totcurve);
504   }
505 
506   /* Propagate blocks to inserted keys */
507   ActKeyColumn *prev_ready = NULL;
508 
509   LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
510     /* Pre-existing column. */
511     if (col->totcurve > 0) {
512       prev_ready = col;
513     }
514     /* Newly inserted column, so copy block data from previous. */
515     else if (prev_ready != NULL) {
516       col->totblock = prev_ready->totblock;
517       memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
518     }
519 
520     col->totcurve = max_curve + 1;
521   }
522 
523   /* Add blocks on top */
524   add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
525 }
526 
527 /* --------- */
528 
actkeyblock_is_valid(ActKeyColumn * ac)529 bool actkeyblock_is_valid(ActKeyColumn *ac)
530 {
531   return ac != NULL && ac->next != NULL && ac->totblock > 0;
532 }
533 
534 /* Checks if ActKeyBlock should exist... */
actkeyblock_get_valid_hold(ActKeyColumn * ac)535 int actkeyblock_get_valid_hold(ActKeyColumn *ac)
536 {
537   /* check that block is valid */
538   if (!actkeyblock_is_valid(ac)) {
539     return 0;
540   }
541 
542   const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
543   return (ac->block.flag & ~ac->block.conflict) & hold_mask;
544 }
545 
546 /* *************************** Keyframe Drawing *************************** */
547 
draw_keyframe_shape(float x,float y,float size,bool sel,short key_type,short mode,float alpha,uint pos_id,uint size_id,uint color_id,uint outline_color_id,uint flags_id,short handle_type,short extreme_type)548 void draw_keyframe_shape(float x,
549                          float y,
550                          float size,
551                          bool sel,
552                          short key_type,
553                          short mode,
554                          float alpha,
555                          uint pos_id,
556                          uint size_id,
557                          uint color_id,
558                          uint outline_color_id,
559                          uint flags_id,
560                          short handle_type,
561                          short extreme_type)
562 {
563   bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH);
564   bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH);
565 
566   BLI_assert(draw_fill || draw_outline);
567 
568   /* tweak size of keyframe shape according to type of keyframe
569    * - 'proper' keyframes have key_type = 0, so get drawn at full size
570    */
571   switch (key_type) {
572     case BEZT_KEYTYPE_KEYFRAME: /* must be full size */
573       break;
574 
575     case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
576       size *= 0.85f;
577       break;
578 
579     case BEZT_KEYTYPE_MOVEHOLD: /* Slightly smaller than normal keyframes
580                                  * (but by less than for breakdowns). */
581       size *= 0.925f;
582       break;
583 
584     case BEZT_KEYTYPE_EXTREME: /* slightly larger */
585       size *= 1.2f;
586       break;
587 
588     default:
589       size -= 0.8f * key_type;
590   }
591 
592   uchar fill_col[4];
593   uchar outline_col[4];
594   uint flags = 0;
595 
596   /* draw! */
597   if (draw_fill) {
598     /* get interior colors from theme (for selected and unselected only) */
599     switch (key_type) {
600       case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */
601         UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col);
602         break;
603       case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */
604         UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col);
605         break;
606       case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */
607         UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col);
608         break;
609       case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
610         UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_MOVEHOLD_SELECT : TH_KEYTYPE_MOVEHOLD, fill_col);
611         break;
612       case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
613       default:
614         UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col);
615     }
616 
617     /* NOTE: we don't use the straight alpha from the theme, or else effects such as
618      * graying out protected/muted channels doesn't work correctly!
619      */
620     fill_col[3] *= alpha;
621 
622     if (!draw_outline) {
623       /* force outline color to match */
624       outline_col[0] = fill_col[0];
625       outline_col[1] = fill_col[1];
626       outline_col[2] = fill_col[2];
627       outline_col[3] = fill_col[3];
628     }
629   }
630 
631   if (draw_outline) {
632     /* exterior - black frame */
633     UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col);
634     outline_col[3] *= alpha;
635 
636     if (!draw_fill) {
637       /* fill color needs to be (outline.rgb, 0) */
638       fill_col[0] = outline_col[0];
639       fill_col[1] = outline_col[1];
640       fill_col[2] = outline_col[2];
641       fill_col[3] = 0;
642     }
643 
644     /* Handle type to outline shape. */
645     switch (handle_type) {
646       case KEYFRAME_HANDLE_AUTO_CLAMP:
647         flags = 0x2;
648         break; /* circle */
649       case KEYFRAME_HANDLE_AUTO:
650         flags = 0x12;
651         break; /* circle with dot */
652       case KEYFRAME_HANDLE_VECTOR:
653         flags = 0xC;
654         break; /* square */
655       case KEYFRAME_HANDLE_ALIGNED:
656         flags = 0x5;
657         break; /* clipped diamond */
658 
659       case KEYFRAME_HANDLE_FREE:
660       default:
661         flags = 1; /* diamond */
662     }
663 
664     /* Extreme type to arrow-like shading. */
665     if (extreme_type & KEYFRAME_EXTREME_MAX) {
666       flags |= 0x100;
667     }
668     if (extreme_type & KEYFRAME_EXTREME_MIN) {
669       flags |= 0x200;
670     }
671     if (extreme_type & KEYFRAME_EXTREME_MIXED) {
672       flags |= 0x400;
673     }
674   }
675 
676   immAttr1f(size_id, size);
677   immAttr4ubv(color_id, fill_col);
678   immAttr4ubv(outline_color_id, outline_col);
679   immAttr1u(flags_id, flags);
680   immVertex2f(pos_id, x, y);
681 }
682 
draw_keylist(View2D * v2d,DLRBT_Tree * keys,float ypos,float yscale_fac,bool channelLocked,int saction_flag)683 static void draw_keylist(View2D *v2d,
684                          DLRBT_Tree *keys,
685                          float ypos,
686                          float yscale_fac,
687                          bool channelLocked,
688                          int saction_flag)
689 {
690   const float icon_sz = U.widget_unit * 0.5f * yscale_fac;
691   const float half_icon_sz = 0.5f * icon_sz;
692   const float smaller_sz = 0.35f * icon_sz;
693   const float ipo_sz = 0.1f * icon_sz;
694 
695   GPU_blend(GPU_BLEND_ALPHA);
696 
697   /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */
698   /* TODO: allow this opacity factor to be themed? */
699   float alpha = channelLocked ? 0.25f : 1.0f;
700 
701   /* Show interpolation and handle type? */
702   bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0;
703 
704   /* draw keyblocks */
705   if (keys) {
706     float sel_color[4], unsel_color[4];
707     float sel_mhcol[4], unsel_mhcol[4];
708     float ipo_color[4], ipo_color_mix[4];
709 
710     /* cache colors first */
711     UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
712     UI_GetThemeColor4fv(TH_STRIP, unsel_color);
713     UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color);
714 
715     sel_color[3] *= alpha;
716     unsel_color[3] *= alpha;
717     ipo_color[3] *= alpha;
718 
719     copy_v4_v4(sel_mhcol, sel_color);
720     sel_mhcol[3] *= 0.8f;
721     copy_v4_v4(unsel_mhcol, unsel_color);
722     unsel_mhcol[3] *= 0.8f;
723     copy_v4_v4(ipo_color_mix, ipo_color);
724     ipo_color_mix[3] *= 0.5f;
725 
726     uint block_len = 0;
727     LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
728       if (actkeyblock_get_valid_hold(ab)) {
729         block_len++;
730       }
731       if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
732         block_len++;
733       }
734     }
735 
736     if (block_len > 0) {
737       GPUVertFormat *format = immVertexFormat();
738       uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
739       uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
740       immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
741 
742       immBegin(GPU_PRIM_TRIS, 6 * block_len);
743       LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
744         int valid_hold = actkeyblock_get_valid_hold(ab);
745         if (valid_hold != 0) {
746           if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
747             /* draw "moving hold" long-keyframe block - slightly smaller */
748             immRectf_fast_with_color(pos_id,
749                                      color_id,
750                                      ab->cfra,
751                                      ypos - smaller_sz,
752                                      ab->next->cfra,
753                                      ypos + smaller_sz,
754                                      (ab->block.sel) ? sel_mhcol : unsel_mhcol);
755           }
756           else {
757             /* draw standard long-keyframe block */
758             immRectf_fast_with_color(pos_id,
759                                      color_id,
760                                      ab->cfra,
761                                      ypos - half_icon_sz,
762                                      ab->next->cfra,
763                                      ypos + half_icon_sz,
764                                      (ab->block.sel) ? sel_color : unsel_color);
765           }
766         }
767         if (show_ipo && actkeyblock_is_valid(ab) &&
768             (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
769           /* draw an interpolation line */
770           immRectf_fast_with_color(
771               pos_id,
772               color_id,
773               ab->cfra,
774               ypos - ipo_sz,
775               ab->next->cfra,
776               ypos + ipo_sz,
777               (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color);
778         }
779       }
780       immEnd();
781       immUnbindProgram();
782     }
783   }
784 
785   if (keys) {
786     /* count keys */
787     uint key_len = 0;
788     LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
789       /* Optimization: if keyframe doesn't appear within 5 units (screenspace)
790        * in visible area, don't draw.
791        * This might give some improvements,
792        * since we current have to flip between view/region matrices.
793        */
794       if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
795         key_len++;
796       }
797     }
798 
799     if (key_len > 0) {
800       /* draw keys */
801       GPUVertFormat *format = immVertexFormat();
802       uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
803       uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
804       uint color_id = GPU_vertformat_attr_add(
805           format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
806       uint outline_color_id = GPU_vertformat_attr_add(
807           format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
808       uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
809 
810       GPU_program_point_size(true);
811       immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
812       immUniform1f("outline_scale", 1.0f);
813       immUniform2f(
814           "ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
815       immBegin(GPU_PRIM_POINTS, key_len);
816 
817       short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
818 
819       LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
820         if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
821           if (show_ipo) {
822             handle_type = ak->handle_type;
823           }
824           if (saction_flag & SACTION_SHOW_EXTREMES) {
825             extreme_type = ak->extreme_type;
826           }
827 
828           draw_keyframe_shape(ak->cfra,
829                               ypos,
830                               icon_sz,
831                               (ak->sel & SELECT),
832                               ak->key_type,
833                               KEYFRAME_SHAPE_BOTH,
834                               alpha,
835                               pos_id,
836                               size_id,
837                               color_id,
838                               outline_color_id,
839                               flags_id,
840                               handle_type,
841                               extreme_type);
842         }
843       }
844 
845       immEnd();
846       GPU_program_point_size(false);
847       immUnbindProgram();
848     }
849   }
850 
851   GPU_blend(GPU_BLEND_NONE);
852 }
853 
854 /* *************************** Channel Drawing Funcs *************************** */
855 
draw_summary_channel(View2D * v2d,bAnimContext * ac,float ypos,float yscale_fac,int saction_flag)856 void draw_summary_channel(
857     View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag)
858 {
859   DLRBT_Tree keys;
860 
861   saction_flag &= ~SACTION_SHOW_EXTREMES;
862 
863   BLI_dlrbTree_init(&keys);
864 
865   summary_to_keylist(ac, &keys, saction_flag);
866 
867   draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
868 
869   BLI_dlrbTree_free(&keys);
870 }
871 
draw_scene_channel(View2D * v2d,bDopeSheet * ads,Scene * sce,float ypos,float yscale_fac,int saction_flag)872 void draw_scene_channel(
873     View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag)
874 {
875   DLRBT_Tree keys;
876 
877   saction_flag &= ~SACTION_SHOW_EXTREMES;
878 
879   BLI_dlrbTree_init(&keys);
880 
881   scene_to_keylist(ads, sce, &keys, saction_flag);
882 
883   draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
884 
885   BLI_dlrbTree_free(&keys);
886 }
887 
draw_object_channel(View2D * v2d,bDopeSheet * ads,Object * ob,float ypos,float yscale_fac,int saction_flag)888 void draw_object_channel(
889     View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag)
890 {
891   DLRBT_Tree keys;
892 
893   saction_flag &= ~SACTION_SHOW_EXTREMES;
894 
895   BLI_dlrbTree_init(&keys);
896 
897   ob_to_keylist(ads, ob, &keys, saction_flag);
898 
899   draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
900 
901   BLI_dlrbTree_free(&keys);
902 }
903 
draw_fcurve_channel(View2D * v2d,AnimData * adt,FCurve * fcu,float ypos,float yscale_fac,int saction_flag)904 void draw_fcurve_channel(
905     View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac, int saction_flag)
906 {
907   DLRBT_Tree keys;
908 
909   bool locked = (fcu->flag & FCURVE_PROTECTED) ||
910                 ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
911                 ((adt && adt->action) && ID_IS_LINKED(adt->action));
912 
913   BLI_dlrbTree_init(&keys);
914 
915   fcurve_to_keylist(adt, fcu, &keys, saction_flag);
916 
917   draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
918 
919   BLI_dlrbTree_free(&keys);
920 }
921 
draw_agroup_channel(View2D * v2d,AnimData * adt,bActionGroup * agrp,float ypos,float yscale_fac,int saction_flag)922 void draw_agroup_channel(
923     View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag)
924 {
925   DLRBT_Tree keys;
926 
927   bool locked = (agrp->flag & AGRP_PROTECTED) ||
928                 ((adt && adt->action) && ID_IS_LINKED(adt->action));
929 
930   BLI_dlrbTree_init(&keys);
931 
932   agroup_to_keylist(adt, agrp, &keys, saction_flag);
933 
934   draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
935 
936   BLI_dlrbTree_free(&keys);
937 }
938 
draw_action_channel(View2D * v2d,AnimData * adt,bAction * act,float ypos,float yscale_fac,int saction_flag)939 void draw_action_channel(
940     View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac, int saction_flag)
941 {
942   DLRBT_Tree keys;
943 
944   bool locked = (act && ID_IS_LINKED(act));
945 
946   saction_flag &= ~SACTION_SHOW_EXTREMES;
947 
948   BLI_dlrbTree_init(&keys);
949 
950   action_to_keylist(adt, act, &keys, saction_flag);
951 
952   draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
953 
954   BLI_dlrbTree_free(&keys);
955 }
956 
draw_gpencil_channel(View2D * v2d,bDopeSheet * ads,bGPdata * gpd,float ypos,float yscale_fac,int saction_flag)957 void draw_gpencil_channel(
958     View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac, int saction_flag)
959 {
960   DLRBT_Tree keys;
961 
962   saction_flag &= ~SACTION_SHOW_EXTREMES;
963 
964   BLI_dlrbTree_init(&keys);
965 
966   gpencil_to_keylist(ads, gpd, &keys, false);
967 
968   draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
969 
970   BLI_dlrbTree_free(&keys);
971 }
972 
draw_gpl_channel(View2D * v2d,bDopeSheet * ads,bGPDlayer * gpl,float ypos,float yscale_fac,int saction_flag)973 void draw_gpl_channel(
974     View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag)
975 {
976   DLRBT_Tree keys;
977 
978   bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0;
979 
980   BLI_dlrbTree_init(&keys);
981 
982   gpl_to_keylist(ads, gpl, &keys);
983 
984   draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
985 
986   BLI_dlrbTree_free(&keys);
987 }
988 
draw_masklay_channel(View2D * v2d,bDopeSheet * ads,MaskLayer * masklay,float ypos,float yscale_fac,int saction_flag)989 void draw_masklay_channel(View2D *v2d,
990                           bDopeSheet *ads,
991                           MaskLayer *masklay,
992                           float ypos,
993                           float yscale_fac,
994                           int saction_flag)
995 {
996   DLRBT_Tree keys;
997 
998   bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0;
999 
1000   BLI_dlrbTree_init(&keys);
1001 
1002   mask_to_keylist(ads, masklay, &keys);
1003 
1004   draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
1005 
1006   BLI_dlrbTree_free(&keys);
1007 }
1008 
1009 /* *************************** Keyframe List Conversions *************************** */
1010 
summary_to_keylist(bAnimContext * ac,DLRBT_Tree * keys,int saction_flag)1011 void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
1012 {
1013   if (ac) {
1014     ListBase anim_data = {NULL, NULL};
1015     bAnimListElem *ale;
1016     int filter;
1017 
1018     /* get F-Curves to take keyframes from */
1019     filter = ANIMFILTER_DATA_VISIBLE;
1020     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1021 
1022     /* loop through each F-Curve, grabbing the keyframes */
1023     for (ale = anim_data.first; ale; ale = ale->next) {
1024       /* Why not use all #eAnim_KeyType here?
1025        * All of the other key types are actually "summaries" themselves,
1026        * and will just end up duplicating stuff that comes up through
1027        * standard filtering of just F-Curves. Given the way that these work,
1028        * there isn't really any benefit at all from including them. - Aligorith */
1029 
1030       switch (ale->datatype) {
1031         case ALE_FCURVE:
1032           fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
1033           break;
1034         case ALE_MASKLAY:
1035           mask_to_keylist(ac->ads, ale->data, keys);
1036           break;
1037         case ALE_GPFRAME:
1038           gpl_to_keylist(ac->ads, ale->data, keys);
1039           break;
1040         default:
1041           // printf("%s: datatype %d unhandled\n", __func__, ale->datatype);
1042           break;
1043       }
1044     }
1045 
1046     ANIM_animdata_freelist(&anim_data);
1047   }
1048 }
1049 
scene_to_keylist(bDopeSheet * ads,Scene * sce,DLRBT_Tree * keys,int saction_flag)1050 void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
1051 {
1052   bAnimContext ac = {NULL};
1053   ListBase anim_data = {NULL, NULL};
1054   bAnimListElem *ale;
1055   int filter;
1056 
1057   bAnimListElem dummychan = {NULL};
1058 
1059   if (sce == NULL) {
1060     return;
1061   }
1062 
1063   /* create a dummy wrapper data to work with */
1064   dummychan.type = ANIMTYPE_SCENE;
1065   dummychan.data = sce;
1066   dummychan.id = &sce->id;
1067   dummychan.adt = sce->adt;
1068 
1069   ac.ads = ads;
1070   ac.data = &dummychan;
1071   ac.datatype = ANIMCONT_CHANNEL;
1072 
1073   /* get F-Curves to take keyframes from */
1074   filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
1075   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1076 
1077   /* loop through each F-Curve, grabbing the keyframes */
1078   for (ale = anim_data.first; ale; ale = ale->next) {
1079     fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
1080   }
1081 
1082   ANIM_animdata_freelist(&anim_data);
1083 }
1084 
ob_to_keylist(bDopeSheet * ads,Object * ob,DLRBT_Tree * keys,int saction_flag)1085 void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
1086 {
1087   bAnimContext ac = {NULL};
1088   ListBase anim_data = {NULL, NULL};
1089   bAnimListElem *ale;
1090   int filter;
1091 
1092   bAnimListElem dummychan = {NULL};
1093   Base dummybase = {NULL};
1094 
1095   if (ob == NULL) {
1096     return;
1097   }
1098 
1099   /* create a dummy wrapper data to work with */
1100   dummybase.object = ob;
1101 
1102   dummychan.type = ANIMTYPE_OBJECT;
1103   dummychan.data = &dummybase;
1104   dummychan.id = &ob->id;
1105   dummychan.adt = ob->adt;
1106 
1107   ac.ads = ads;
1108   ac.data = &dummychan;
1109   ac.datatype = ANIMCONT_CHANNEL;
1110 
1111   /* get F-Curves to take keyframes from */
1112   filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
1113   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1114 
1115   /* loop through each F-Curve, grabbing the keyframes */
1116   for (ale = anim_data.first; ale; ale = ale->next) {
1117     fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
1118   }
1119 
1120   ANIM_animdata_freelist(&anim_data);
1121 }
1122 
cachefile_to_keylist(bDopeSheet * ads,CacheFile * cache_file,DLRBT_Tree * keys,int saction_flag)1123 void cachefile_to_keylist(bDopeSheet *ads,
1124                           CacheFile *cache_file,
1125                           DLRBT_Tree *keys,
1126                           int saction_flag)
1127 {
1128   if (cache_file == NULL) {
1129     return;
1130   }
1131 
1132   /* create a dummy wrapper data to work with */
1133   bAnimListElem dummychan = {NULL};
1134   dummychan.type = ANIMTYPE_DSCACHEFILE;
1135   dummychan.data = cache_file;
1136   dummychan.id = &cache_file->id;
1137   dummychan.adt = cache_file->adt;
1138 
1139   bAnimContext ac = {NULL};
1140   ac.ads = ads;
1141   ac.data = &dummychan;
1142   ac.datatype = ANIMCONT_CHANNEL;
1143 
1144   /* get F-Curves to take keyframes from */
1145   ListBase anim_data = {NULL, NULL};
1146   int filter = ANIMFILTER_DATA_VISIBLE; /* curves only */
1147   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1148 
1149   /* loop through each F-Curve, grabbing the keyframes */
1150   LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1151     fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
1152   }
1153 
1154   ANIM_animdata_freelist(&anim_data);
1155 }
1156 
fcurve_to_keylist(AnimData * adt,FCurve * fcu,DLRBT_Tree * keys,int saction_flag)1157 void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
1158 {
1159   if (fcu && fcu->totvert && fcu->bezt) {
1160     /* apply NLA-mapping (if applicable) */
1161     if (adt) {
1162       ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
1163     }
1164 
1165     /* Check if the curve is cyclic. */
1166     bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
1167     bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
1168 
1169     /* loop through beztriples, making ActKeysColumns */
1170     BezTripleChain chain = {0};
1171 
1172     for (int v = 0; v < fcu->totvert; v++) {
1173       chain.cur = &fcu->bezt[v];
1174 
1175       /* Neighbor keys, accounting for being cyclic. */
1176       if (do_extremes) {
1177         chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
1178         chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
1179       }
1180 
1181       add_bezt_to_keycolumns_list(keys, &chain);
1182     }
1183 
1184     /* Update keyblocks. */
1185     update_keyblocks(keys, fcu->bezt, fcu->totvert);
1186 
1187     /* unapply NLA-mapping if applicable */
1188     if (adt) {
1189       ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
1190     }
1191   }
1192 }
1193 
agroup_to_keylist(AnimData * adt,bActionGroup * agrp,DLRBT_Tree * keys,int saction_flag)1194 void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag)
1195 {
1196   FCurve *fcu;
1197 
1198   if (agrp) {
1199     /* loop through F-Curves */
1200     for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
1201       fcurve_to_keylist(adt, fcu, keys, saction_flag);
1202     }
1203   }
1204 }
1205 
action_to_keylist(AnimData * adt,bAction * act,DLRBT_Tree * keys,int saction_flag)1206 void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag)
1207 {
1208   FCurve *fcu;
1209 
1210   if (act) {
1211     /* loop through F-Curves */
1212     for (fcu = act->curves.first; fcu; fcu = fcu->next) {
1213       fcurve_to_keylist(adt, fcu, keys, saction_flag);
1214     }
1215   }
1216 }
1217 
gpencil_to_keylist(bDopeSheet * ads,bGPdata * gpd,DLRBT_Tree * keys,const bool active)1218 void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
1219 {
1220   bGPDlayer *gpl;
1221 
1222   if (gpd && keys) {
1223     /* for now, just aggregate out all the frames, but only for visible layers */
1224     for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
1225       if ((gpl->flag & GP_LAYER_HIDE) == 0) {
1226         if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
1227           gpl_to_keylist(ads, gpl, keys);
1228         }
1229       }
1230     }
1231   }
1232 }
1233 
gpl_to_keylist(bDopeSheet * UNUSED (ads),bGPDlayer * gpl,DLRBT_Tree * keys)1234 void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
1235 {
1236   bGPDframe *gpf;
1237 
1238   if (gpl && keys) {
1239     /* Although the frames should already be in an ordered list,
1240      * they are not suitable for displaying yet. */
1241     for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
1242       add_gpframe_to_keycolumns_list(keys, gpf);
1243     }
1244 
1245     update_keyblocks(keys, NULL, 0);
1246   }
1247 }
1248 
mask_to_keylist(bDopeSheet * UNUSED (ads),MaskLayer * masklay,DLRBT_Tree * keys)1249 void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys)
1250 {
1251   MaskLayerShape *masklay_shape;
1252 
1253   if (masklay && keys) {
1254     for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
1255          masklay_shape = masklay_shape->next) {
1256       add_masklay_to_keycolumns_list(keys, masklay_shape);
1257     }
1258 
1259     update_keyblocks(keys, NULL, 0);
1260   }
1261 }
1262