CMake: Use GCC7's -Wimplicit-fallthrough=5
[blender.git] / source / blender / editors / space_nla / nla_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  * 
22  * Contributor(s): Joshua Leung (major recode)
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_nla/nla_draw.c
28  *  \ingroup spnla
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <float.h>
37
38 #include "DNA_anim_types.h"
39 #include "DNA_node_types.h"
40 #include "DNA_screen_types.h"
41 #include "DNA_space_types.h"
42 #include "DNA_windowmanager_types.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_dlrbTree.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_fcurve.h"
49 #include "BKE_nla.h"
50 #include "BKE_context.h"
51 #include "BKE_screen.h"
52
53 #include "ED_anim_api.h"
54 #include "ED_keyframes_draw.h"
55
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58
59 #include "WM_types.h"
60
61 #include "UI_interface.h"
62 #include "UI_resources.h"
63 #include "UI_view2d.h"
64
65 #include "nla_private.h"
66 #include "nla_intern.h" /* own include */
67
68
69 /* *********************************************** */
70 /* Strips */
71
72 /* Action-Line ---------------------- */
73
74 /* get colors for drawing Action-Line 
75  * NOTE: color returned includes fine-tuned alpha!
76  */
77 void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
78 {
79         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
80                 /* greenish color (same as tweaking strip) */
81                 UI_GetThemeColor4fv(TH_NLA_TWEAK, color);
82         }
83         else {
84                 if (act) {
85                         /* reddish color - same as dopesheet summary */
86                         UI_GetThemeColor4fv(TH_ANIM_ACTIVE, color);
87                 }
88                 else {
89                         /* grayish-red color */
90                         UI_GetThemeColor4fv(TH_ANIM_INACTIVE, color);
91                 }
92         }
93         
94         /* when an NLA track is tagged "solo", action doesn't contribute, so shouldn't be as prominent */
95         if (adt && (adt->flag & ADT_NLA_SOLO_TRACK))
96                 color[3] *= 0.15f;
97 }
98
99 /* draw the keyframes in the specified Action */
100 static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax)
101 {
102         DLRBT_Tree keys;
103         ActKeyColumn *ak;
104         float xscale, f1, f2;
105         float color[4];
106         
107         /* get a list of the keyframes with NLA-scaling applied */
108         BLI_dlrbTree_init(&keys);
109         action_to_keylist(adt, act, &keys, NULL);
110         BLI_dlrbTree_linkedlist_sync(&keys);
111         
112         if (ELEM(NULL, act, keys.first))
113                 return;
114         
115         /* draw a darkened region behind the strips 
116          *      - get and reset the background color, this time without the alpha to stand out better 
117          *        (amplified alpha is used instead)
118          */
119         nla_action_get_color(adt, act, color);
120         color[3] *= 2.5f;
121         
122         glColor4fv(color);
123         /*  - draw a rect from the first to the last frame (no extra overlaps for now)
124          *        that is slightly stumpier than the track background (hardcoded 2-units here)
125          */
126         f1 = ((ActKeyColumn *)keys.first)->cfra;
127         f2 = ((ActKeyColumn *)keys.last)->cfra;
128         
129         glRectf(f1, ymin + 2, f2, ymax - 2);
130         
131         
132         /* get View2D scaling factor */
133         UI_view2d_scale_get(v2d, &xscale, NULL);
134         
135         /* for now, color is hardcoded to be black */
136         glColor3f(0.0f, 0.0f, 0.0f);
137         
138         /* just draw each keyframe as a simple dot (regardless of the selection status) 
139          *      - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction
140          */
141         for (ak = keys.first; ak; ak = ak->next)
142                 draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f);
143         
144         /* free icons */
145         BLI_dlrbTree_free(&keys);
146 }
147
148 /* Strip Markers ------------------------ */
149
150 /* Markers inside an action strip */
151 static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
152 {
153         bAction *act = strip->act;
154         TimeMarker *marker;
155         
156         if (ELEM(NULL, strip->act, strip->act->markers.first))
157                 return;
158         
159         for (marker = act->markers.first; marker; marker = marker->next) {
160                 if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
161                         float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
162                         
163                         /* just a simple line for now */
164                         // XXX: draw a triangle instead...
165                         fdrawline(frame, yminc + 1, frame, ymaxc - 1);
166                 }
167         }
168 }
169
170 /* Markers inside a NLA-Strip */
171 static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
172 {
173         glLineWidth(2.0);
174         
175         if (strip->type == NLASTRIP_TYPE_CLIP) {
176                 /* try not to be too conspicuous, while being visible enough when transforming */
177                 if (strip->flag & NLASTRIP_FLAG_SELECT)
178                         UI_ThemeColorShade(TH_STRIP_SELECT, -60);
179                 else
180                         UI_ThemeColorShade(TH_STRIP_SELECT, -40);
181                 
182                 setlinestyle(3);
183                 
184                 /* just draw the markers in this clip */
185                 nla_actionclip_draw_markers(strip, yminc, ymaxc);
186                 
187                 setlinestyle(0);
188         }
189         else if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
190                 /* just a solid color, so that it is very easy to spot */
191                 UI_ThemeColorShade(TH_STRIP_SELECT, 20);
192                 
193                 /* draw the markers in the first level of strips only (if they are actions) */
194                 for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
195                         if (nls->type == NLASTRIP_TYPE_CLIP) {
196                                 nla_actionclip_draw_markers(nls, yminc, ymaxc);
197                         }
198                 }
199         }
200         
201         glLineWidth(1.0);
202 }
203
204 /* Strips (Proper) ---------------------- */
205
206 /* get colors for drawing NLA-Strips */
207 static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float color[3])
208 {
209         if (strip->type == NLASTRIP_TYPE_TRANSITION) {
210                 /* Transition Clip */
211                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
212                         /* selected - use a bright blue color */
213                         UI_GetThemeColor3fv(TH_NLA_TRANSITION_SEL, color);
214                 }
215                 else {
216                         /* normal, unselected strip - use (hardly noticeable) blue tinge */
217                         UI_GetThemeColor3fv(TH_NLA_TRANSITION, color);
218                 }
219         }
220         else if (strip->type == NLASTRIP_TYPE_META) {
221                 /* Meta Clip */
222                 // TODO: should temporary metas get different colors too?
223                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
224                         /* selected - use a bold purple color */
225                         UI_GetThemeColor3fv(TH_NLA_META_SEL, color);
226                 }
227                 else {
228                         /* normal, unselected strip - use (hardly noticeable) dark purple tinge */
229                         UI_GetThemeColor3fv(TH_NLA_META, color);
230                 }
231         }
232         else if (strip->type == NLASTRIP_TYPE_SOUND) {
233                 /* Sound Clip */
234                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
235                         /* selected - use a bright teal color */
236                         UI_GetThemeColor3fv(TH_NLA_SOUND_SEL, color);
237                 }
238                 else {
239                         /* normal, unselected strip - use (hardly noticeable) teal tinge */
240                         UI_GetThemeColor3fv(TH_NLA_SOUND, color);
241                 }
242         }
243         else {
244                 /* Action Clip (default/normal type of strip) */
245                 if (adt && (adt->flag & ADT_NLA_EDIT_ON) && (adt->actstrip == strip)) {
246                         /* active strip should be drawn green when it is acting as the tweaking strip.
247                          * however, this case should be skipped for when not in EditMode...
248                          */
249                         UI_GetThemeColor3fv(TH_NLA_TWEAK, color);
250                 }
251                 else if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) {
252                         /* alert user that this strip is also used by the tweaking track (this is set when going into
253                          * 'editmode' for that strip), since the edits made here may not be what the user anticipated
254                          */
255                         UI_GetThemeColor3fv(TH_NLA_TWEAK_DUPLI, color);
256                 }
257                 else if (strip->flag & NLASTRIP_FLAG_SELECT) {
258                         /* selected strip - use theme color for selected */
259                         UI_GetThemeColor3fv(TH_STRIP_SELECT, color);
260                 }
261                 else {
262                         /* normal, unselected strip - use standard strip theme color */
263                         UI_GetThemeColor3fv(TH_STRIP, color);
264                 }
265         }
266 }
267
268 /* helper call for drawing influence/time control curves for a given NLA-strip */
269 static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
270 {
271         const float yheight = ymaxc - yminc;
272         
273         /* drawing color is simply a light-gray */
274         // TODO: is this color suitable?
275         // XXX nasty hacked color for now... which looks quite bad too...
276         glColor3f(0.7f, 0.7f, 0.7f);
277         
278         /* draw with AA'd line */
279         glEnable(GL_LINE_SMOOTH);
280         glEnable(GL_BLEND);
281         
282         /* influence -------------------------- */
283         if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
284                 FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
285                 float cfra;
286                 
287                 /* plot the curve (over the strip's main region) */
288                 glBegin(GL_LINE_STRIP);
289                 /* sample at 1 frame intervals, and draw
290                  *      - min y-val is yminc, max is y-maxc, so clamp in those regions
291                  */
292                 for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
293                         float y = evaluate_fcurve(fcu, cfra);
294                         CLAMP(y, 0.0f, 1.0f);
295                         glVertex2f(cfra, ((y * yheight) + yminc));
296                 }
297                 glEnd(); // GL_LINE_STRIP
298         }
299         else {
300                 /* use blend in/out values only if both aren't zero */
301                 if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
302                         glBegin(GL_LINE_STRIP);
303                         /* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */
304                         if (IS_EQF(strip->blendin, 0.0f) == 0) {
305                                 glVertex2f(strip->start,                    yminc);
306                                 glVertex2f(strip->start + strip->blendin,   ymaxc);
307                         }
308                         else
309                                 glVertex2f(strip->start, ymaxc);
310                                         
311                         /* end of strip */
312                         if (IS_EQF(strip->blendout, 0.0f) == 0) {
313                                 glVertex2f(strip->end - strip->blendout,    ymaxc);
314                                 glVertex2f(strip->end,                      yminc);
315                         }
316                         else
317                                 glVertex2f(strip->end, ymaxc);
318                         glEnd(); // GL_LINE_STRIP
319                 }
320         }
321         
322         /* time -------------------------- */
323         // XXX do we want to draw this curve? in a different color too?
324         
325         /* turn off AA'd lines */
326         glDisable(GL_LINE_SMOOTH);
327         glDisable(GL_BLEND);
328 }
329
330 /* main call for drawing a single NLA-strip */
331 static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
332 {
333         const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
334         float color[3];
335         
336         /* get color of strip */
337         nla_strip_get_color_inside(adt, strip, color);
338         
339         /* draw extrapolation info first (as backdrop)
340          *      - but this should only be drawn if track has some contribution
341          */
342         if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) {
343                 /* enable transparency... */
344                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
345                 glEnable(GL_BLEND);
346                 
347                 switch (strip->extendmode) {
348                         /* since this does both sides, only do the 'before' side, and leave the rest to the next case */
349                         case NLASTRIP_EXTEND_HOLD: 
350                                 /* only need to draw here if there's no strip before since 
351                                  * it only applies in such a situation 
352                                  */
353                                 if (strip->prev == NULL) {
354                                         /* set the drawing color to the color of the strip, but with very faint alpha */
355                                         glColor4f(color[0], color[1], color[2], 0.15f);
356                                         
357                                         /* draw the rect to the edge of the screen */
358                                         glBegin(GL_QUADS);
359                                         glVertex2f(v2d->cur.xmin, yminc);
360                                         glVertex2f(v2d->cur.xmin, ymaxc);
361                                         glVertex2f(strip->start, ymaxc);
362                                         glVertex2f(strip->start, yminc);
363                                         glEnd();
364                                 }
365                                 ATTR_FALLTHROUGH;
366
367                         /* this only draws after the strip */
368                         case NLASTRIP_EXTEND_HOLD_FORWARD: 
369                                 /* only need to try and draw if the next strip doesn't occur immediately after */
370                                 if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) {
371                                         /* set the drawing color to the color of the strip, but this time less faint */
372                                         glColor4f(color[0], color[1], color[2], 0.3f);
373                                         
374                                         /* draw the rect to the next strip or the edge of the screen */
375                                         glBegin(GL_QUADS);
376                                         glVertex2f(strip->end, yminc);
377                                         glVertex2f(strip->end, ymaxc);
378                                                 
379                                         if (strip->next) {
380                                                 glVertex2f(strip->next->start, ymaxc);
381                                                 glVertex2f(strip->next->start, yminc);
382                                         }
383                                         else {
384                                                 glVertex2f(v2d->cur.xmax, ymaxc);
385                                                 glVertex2f(v2d->cur.xmax, yminc);
386                                         }
387                                         glEnd();
388                                 }
389                                 break;
390                 }
391                 
392                 glDisable(GL_BLEND);
393         }
394         
395         
396         /* draw 'inside' of strip itself */
397         if (non_solo == 0) {
398                 /* strip is in normal track */
399                 glColor3fv(color);
400                 UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
401                 
402                 UI_draw_roundbox_shade_x(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
403         }
404         else {
405                 /* strip is in disabled track - make less visible */
406                 glColor4f(color[0], color[1], color[2], 0.1f);
407                 
408                 glEnable(GL_BLEND);
409                 glRectf(strip->start, yminc, strip->end, ymaxc);
410                 glDisable(GL_BLEND);
411         }
412         
413         
414         /* draw strip's control 'curves'
415          *      - only if user hasn't hidden them...
416          */
417         if ((snla->flag & SNLA_NOSTRIPCURVES) == 0)
418                 nla_draw_strip_curves(strip, yminc, ymaxc);
419         
420         
421         /* draw markings indicating locations of local markers (useful for lining up different actions) */
422         if ((snla->flag & SNLA_NOLOCALMARKERS) == 0)
423                 nla_strip_draw_markers(strip, yminc, ymaxc);
424         
425         /* draw strip outline 
426          *      - color used here is to indicate active vs non-active
427          */
428         if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
429                 /* strip should appear 'sunken', so draw a light border around it */
430                 glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
431         }
432         else {
433                 /* strip should appear to stand out, so draw a dark border around it */
434                 glColor3f(0.0f, 0.0f, 0.0f);
435         }
436         
437         /* - line style: dotted for muted */
438         if ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED))
439                 setlinestyle(4);
440                 
441         /* draw outline */
442         UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
443         
444         /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
445         if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) {
446                 float repeatLen = (strip->actend - strip->actstart) * strip->scale;
447                 int i;
448                 
449                 /* only draw lines for whole-numbered repeats, starting from the first full-repeat
450                  * up to the last full repeat (but not if it lies on the end of the strip)
451                  */
452                 for (i = 1; i < strip->repeat; i++) {
453                         float repeatPos = strip->start + (repeatLen * i);
454                         
455                         /* don't draw if line would end up on or after the end of the strip */
456                         if (repeatPos < strip->end)
457                                 fdrawline(repeatPos, yminc + 4, repeatPos, ymaxc - 4);
458                 }
459         }
460         /* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
461         else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
462                 NlaStrip *cs;
463                 float y = (ymaxc - yminc) / 2.0f + yminc;
464                 
465                 /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
466                 for (cs = strip->strips.first; cs; cs = cs->next) {
467                         /* draw start-line if not same as end of previous (and only if not the first strip) 
468                          *      - on upper half of strip
469                          */
470                         if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0)
471                                 fdrawline(cs->start, y, cs->start, ymaxc);
472                                 
473                         /* draw end-line if not the last strip
474                          *      - on lower half of strip
475                          */
476                         if (cs->next) 
477                                 fdrawline(cs->end, yminc, cs->end, y);
478                 }
479         }
480         
481         /* reset linestyle */
482         setlinestyle(0);
483
484
485 /* add the relevant text to the cache of text-strings to draw in pixelspace */
486 static void nla_draw_strip_text(
487         AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d,
488         float xminc, float xmaxc, float yminc, float ymaxc)
489 {
490         const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
491         char str[256];
492         size_t str_len;
493         char col[4];
494         rctf rect;
495         
496         /* just print the name and the range */
497         if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
498                 str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
499         }
500         else {
501                 str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
502         }
503         
504         /* set text color - if colors (see above) are light, draw black text, otherwise draw white */
505         if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_TWEAKUSER)) {
506                 col[0] = col[1] = col[2] = 0;
507         }
508         else {
509                 col[0] = col[1] = col[2] = 255;
510         }
511         
512         /* text opacity depends on whether if there's a solo'd track, this isn't it */
513         if (non_solo == 0)
514                 col[3] = 255;
515         else
516                 col[3] = 128;
517
518         /* set bounding-box for text 
519          *      - padding of 2 'units' on either side
520          */
521         // TODO: make this centered?
522         rect.xmin = xminc;
523         rect.ymin = yminc;
524         rect.xmax = xmaxc;
525         rect.ymax = ymaxc;
526         
527         /* add this string to the cache of texts to draw */
528         UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
529 }
530
531 /* add frame extents to cache of text-strings to draw in pixelspace
532  * for now, only used when transforming strips
533  */
534 static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float UNUSED(yminc), float ymaxc)
535 {
536         const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */
537         const char col[4] = {220, 220, 220, 255}; /* light gray */
538         char numstr[32];
539         size_t numstr_len;
540         
541         
542         /* Always draw times above the strip, whereas sequencer drew below + above.
543          * However, we should be fine having everything on top, since these tend to be 
544          * quite spaced out. 
545          *      - 1 dp is compromise between lack of precision (ints only, as per sequencer)
546          *        while also preserving some accuracy, since we do use floats
547          */
548         /* start frame */
549         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
550         UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
551         
552         /* end frame */
553         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end);
554         UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
555 }
556
557 /* ---------------------- */
558
559 void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
560 {
561         ListBase anim_data = {NULL, NULL};
562         bAnimListElem *ale;
563         int filter;
564         
565         View2D *v2d = &ar->v2d;
566         float y = 0.0f;
567         size_t items;
568         int height;
569         const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
570         const float text_margin_x = (8 * UI_DPI_FAC) * pixelx;
571         
572         /* build list of channels to draw */
573         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
574         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
575         
576         /* Update max-extent of channels here (taking into account scrollers):
577          *  - this is done to allow the channel list to be scrollable, but must be done here
578          *    to avoid regenerating the list again and/or also because channels list is drawn first
579          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
580          *        start of list offset, and the second is as a correction for the scrollers.
581          */
582         height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
583         /* don't use totrect set, as the width stays the same 
584          * (NOTE: this is ok here, the configuration is pretty straightforward) 
585          */
586         v2d->tot.ymin = (float)(-height);
587         
588         /* loop through channels, and set up drawing depending on their type  */
589         y = (float)(-NLACHANNEL_HEIGHT(snla));
590         
591         for (ale = anim_data.first; ale; ale = ale->next) {
592                 const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
593                 const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
594                 
595                 /* check if visible */
596                 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
597                     IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
598                 {
599                         /* data to draw depends on the type of channel */
600                         switch (ale->type) {
601                                 case ANIMTYPE_NLATRACK:
602                                 {
603                                         AnimData *adt = ale->adt;
604                                         NlaTrack *nlt = (NlaTrack *)ale->data;
605                                         NlaStrip *strip;
606                                         int index;
607                                         
608                                         /* draw each strip in the track (if visible) */
609                                         for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
610                                                 if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
611                                                         const float xminc = strip->start + text_margin_x;
612                                                         const float xmaxc = strip->end + text_margin_x;
613
614                                                         /* draw the visualization of the strip */
615                                                         nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc);
616                                                         
617                                                         /* add the text for this strip to the cache */
618                                                         if (xminc < xmaxc) {
619                                                                 nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, yminc, ymaxc);
620                                                         }
621                                                         
622                                                         /* if transforming strips (only real reason for temp-metas currently), 
623                                                          * add to the cache the frame numbers of the strip's extents
624                                                          */
625                                                         if (strip->flag & NLASTRIP_FLAG_TEMP_META)
626                                                                 nla_draw_strip_frames_text(nlt, strip, v2d, yminc, ymaxc);
627                                                 }
628                                         }
629                                         break;
630                                 }
631                                 case ANIMTYPE_NLAACTION:
632                                 {
633                                         AnimData *adt = ale->adt;
634                                         float color[4];
635                                         
636                                         /* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
637                                          * and a second darker rect within which we draw keyframe indicator dots if there's data
638                                          */
639                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
640                                         glEnable(GL_BLEND);
641                                                 
642                                         /* get colors for drawing */
643                                         nla_action_get_color(adt, ale->data, color);
644                                         glColor4fv(color);
645                                         
646                                         /* draw slightly shifted up for greater separation from standard channels,
647                                          * but also slightly shorter for some more contrast when viewing the strips
648                                          */
649                                         glRectf(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
650                                         
651                                         /* draw keyframes in the action */
652                                         nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
653                                         
654                                         /* draw 'embossed' lines above and below the strip for effect */
655                                         /* white base-lines */
656                                         glLineWidth(2.0f);
657                                         glColor4f(1.0f, 1.0f, 1.0f, 0.3);
658                                         fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
659                                         fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
660                                         
661                                         /* black top-lines */
662                                         glLineWidth(1.0f);
663                                         glColor3f(0.0f, 0.0f, 0.0f);
664                                         fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
665                                         fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
666                                         
667                                         glDisable(GL_BLEND);
668                                         break;
669                                 }
670                         }
671                 }
672                 
673                 /* adjust y-position for next one */
674                 y -= NLACHANNEL_STEP(snla);
675         }
676         
677         /* free tempolary channels */
678         ANIM_animdata_freelist(&anim_data);
679 }
680
681 /* *********************************************** */
682 /* Channel List */
683
684 void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
685 {
686         ListBase anim_data = {NULL, NULL};
687         bAnimListElem *ale;
688         int filter;
689         
690         SpaceNla *snla = (SpaceNla *)ac->sl;
691         View2D *v2d = &ar->v2d;
692         float y = 0.0f;
693         size_t items;
694         int height;
695         
696         /* build list of channels to draw */
697         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
698         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
699         
700         /* Update max-extent of channels here (taking into account scrollers):
701          *  - this is done to allow the channel list to be scrollable, but must be done here
702          *    to avoid regenerating the list again and/or also because channels list is drawn first
703          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
704          *        start of list offset, and the second is as a correction for the scrollers.
705          */
706         height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
707         /* don't use totrect set, as the width stays the same 
708          * (NOTE: this is ok here, the configuration is pretty straightforward) 
709          */
710         v2d->tot.ymin = (float)(-height);
711         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
712         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
713         
714         /* draw channels */
715         {   /* first pass: just the standard GL-drawing for backdrop + text */
716                 size_t channel_index = 0;
717                 
718                 y = (float)(-NLACHANNEL_HEIGHT(snla));
719                 
720                 for (ale = anim_data.first; ale; ale = ale->next) {
721                         float yminc = (float)(y -  NLACHANNEL_HEIGHT_HALF(snla));
722                         float ymaxc = (float)(y +  NLACHANNEL_HEIGHT_HALF(snla));
723                         
724                         /* check if visible */
725                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
726                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
727                         {
728                                 /* draw all channels using standard channel-drawing API */
729                                 ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
730                         }
731                         
732                         /* adjust y-position for next one */
733                         y -= NLACHANNEL_STEP(snla);
734                         channel_index++;
735                 }
736         }
737         {   /* second pass: UI widgets */
738                 uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
739                 size_t channel_index = 0;
740                 
741                 y = (float)(-NLACHANNEL_HEIGHT(snla));
742                 
743                 /* set blending again, as may not be set in previous step */
744                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
745                 glEnable(GL_BLEND);
746                 
747                 /* loop through channels, and set up drawing depending on their type  */
748                 for (ale = anim_data.first; ale; ale = ale->next) {
749                         const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
750                         const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
751                         
752                         /* check if visible */
753                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
754                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
755                         {
756                                 /* draw all channels using standard channel-drawing API */
757                                 ANIM_channel_draw_widgets(C, ac, ale, block, yminc, ymaxc, channel_index);
758                         }
759                         
760                         /* adjust y-position for next one */
761                         y -= NLACHANNEL_STEP(snla);
762                         channel_index++;
763                 }
764                 
765                 UI_block_end(C, block);
766                 UI_block_draw(C, block);
767                 
768                 glDisable(GL_BLEND);
769         }
770         
771         /* free temporary channels */
772         ANIM_animdata_freelist(&anim_data);
773 }
774
775 /* *********************************************** */