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