Holiday coding log :)
[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_math.h"
46 #include "BLI_rand.h"
47 #include "BLI_dlrbTree.h"
48 #include "BLI_utildefines.h"
49
50 #include "BKE_fcurve.h"
51 #include "BKE_nla.h"
52 #include "BKE_context.h"
53 #include "BKE_screen.h"
54
55 #include "ED_anim_api.h"
56 #include "ED_keyframes_draw.h"
57
58 #include "BIF_gl.h"
59 #include "BIF_glutil.h"
60
61 #include "WM_types.h"
62
63 #include "UI_interface.h"
64 #include "UI_interface_icons.h"
65 #include "UI_resources.h"
66 #include "UI_view2d.h"
67
68
69 #include "nla_intern.h" /* own include */
70
71
72 /* *********************************************** */
73 /* Strips */
74
75 /* Action-Line ---------------------- */
76
77 /* get colors for drawing Action-Line 
78  * NOTE: color returned includes fine-tuned alpha!
79  */
80 static void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
81 {
82         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
83                 /* greenish color (same as tweaking strip) */
84                 UI_GetThemeColor4fv(TH_NLA_TWEAK, color);
85         }
86         else {
87                 if (act) {
88                         /* reddish color - same as dopesheet summary */
89                         UI_GetThemeColor4fv(TH_ANIM_ACTIVE, color);
90                 }
91                 else {
92                         /* grayish-red color */
93                         UI_GetThemeColor4fv(TH_ANIM_INACTIVE, color);
94                 }
95         }
96         
97         /* when an NLA track is tagged "solo", action doesn't contribute, so shouldn't be as prominent */
98         if (adt && (adt->flag & ADT_NLA_SOLO_TRACK))
99                 color[3] *= 0.15f;
100 }
101
102 /* draw the keyframes in the specified Action */
103 static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax)
104 {
105         DLRBT_Tree keys;
106         ActKeyColumn *ak;
107         float xscale, f1, f2;
108         float color[4];
109         
110         /* get a list of the keyframes with NLA-scaling applied */
111         BLI_dlrbTree_init(&keys);
112         action_to_keylist(adt, act, &keys, NULL);
113         BLI_dlrbTree_linkedlist_sync(&keys);
114         
115         if (ELEM(NULL, act, keys.first))
116                 return;
117         
118         /* draw a darkened region behind the strips 
119          *      - get and reset the background color, this time without the alpha to stand out better 
120          *        (amplified alpha is used instead)
121          */
122         nla_action_get_color(adt, act, color);
123         color[3] *= 2.5f;
124         
125         glColor4fv(color);
126         /*  - draw a rect from the first to the last frame (no extra overlaps for now)
127          *        that is slightly stumpier than the track background (hardcoded 2-units here)
128          */
129         f1 = ((ActKeyColumn *)keys.first)->cfra;
130         f2 = ((ActKeyColumn *)keys.last)->cfra;
131         
132         glRectf(f1, ymin + 2, f2, ymax - 2);
133         
134         
135         /* get View2D scaling factor */
136         UI_view2d_getscale(v2d, &xscale, NULL);
137         
138         /* for now, color is hardcoded to be black */
139         glColor3f(0.0f, 0.0f, 0.0f);
140         
141         /* just draw each keyframe as a simple dot (regardless of the selection status) 
142          *      - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction
143          */
144         for (ak = keys.first; ak; ak = ak->next)
145                 draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f);
146         
147         /* free icons */
148         BLI_dlrbTree_free(&keys);
149 }
150
151 /* Strips (Proper) ---------------------- */
152
153 /* get colors for drawing NLA-Strips */
154 static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float color[3])
155 {
156         if (strip->type == NLASTRIP_TYPE_TRANSITION) {
157                 /* Transition Clip */
158                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
159                         /* selected - use a bright blue color */
160                         UI_GetThemeColor3fv(TH_NLA_TRANSITION_SEL, color);
161                 }
162                 else {
163                         /* normal, unselected strip - use (hardly noticeable) blue tinge */
164                         UI_GetThemeColor3fv(TH_NLA_TRANSITION, color);
165                 }
166         }
167         else if (strip->type == NLASTRIP_TYPE_META) {
168                 /* Meta Clip */
169                 // TODO: should temporary metas get different colors too?
170                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
171                         /* selected - use a bold purple color */
172                         UI_GetThemeColor3fv(TH_NLA_META_SEL, color);
173                 }
174                 else {
175                         /* normal, unselected strip - use (hardly noticeable) dark purple tinge */
176                         UI_GetThemeColor3fv(TH_NLA_META, color);
177                 }
178         }
179         else if (strip->type == NLASTRIP_TYPE_SOUND) {
180                 /* Sound Clip */
181                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
182                         /* selected - use a bright teal color */
183                         UI_GetThemeColor3fv(TH_NLA_SOUND_SEL, color);
184                 }
185                 else {
186                         /* normal, unselected strip - use (hardly noticeable) teal tinge */
187                         UI_GetThemeColor3fv(TH_NLA_SOUND, color);
188                 }
189         }
190         else {
191                 /* Action Clip (default/normal type of strip) */
192                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) && (adt && (adt->flag & ADT_NLA_EDIT_ON))) {
193                         /* active strip should be drawn green when it is acting as the tweaking strip.
194                          * however, this case should be skipped for when not in EditMode...
195                          */
196                         UI_GetThemeColor3fv(TH_NLA_TWEAK, color);
197                 }
198                 else if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) {
199                         /* alert user that this strip is also used by the tweaking track (this is set when going into
200                          * 'editmode' for that strip), since the edits made here may not be what the user anticipated
201                          */
202                         UI_GetThemeColor3fv(TH_NLA_TWEAK_DUPLI, color);
203                 }
204                 else if (strip->flag & NLASTRIP_FLAG_SELECT) {
205                         /* selected strip - use theme color for selected */
206                         UI_GetThemeColor3fv(TH_STRIP_SELECT, color);
207                 }
208                 else {
209                         /* normal, unselected strip - use standard strip theme color */
210                         UI_GetThemeColor3fv(TH_STRIP, color);
211                 }
212         }
213 }
214
215 /* helper call for drawing influence/time control curves for a given NLA-strip */
216 static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
217 {
218         const float yheight = ymaxc - yminc;
219         
220         /* drawing color is simply a light-gray */
221         // TODO: is this color suitable?
222         // XXX nasty hacked color for now... which looks quite bad too...
223         glColor3f(0.7f, 0.7f, 0.7f);
224         
225         /* draw with AA'd line */
226         glEnable(GL_LINE_SMOOTH);
227         glEnable(GL_BLEND);
228         
229         /* influence -------------------------- */
230         if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
231                 FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
232                 float cfra;
233                 
234                 /* plot the curve (over the strip's main region) */
235                 glBegin(GL_LINE_STRIP);
236                 /* sample at 1 frame intervals, and draw
237                  *      - min y-val is yminc, max is y-maxc, so clamp in those regions
238                  */
239                 for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
240                         float y = evaluate_fcurve(fcu, cfra);    // assume this to be in 0-1 range
241                         glVertex2f(cfra, ((y * yheight) + yminc));
242                 }
243                 glEnd(); // GL_LINE_STRIP
244         }
245         else {
246                 /* use blend in/out values only if both aren't zero */
247                 if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
248                         glBegin(GL_LINE_STRIP);
249                         /* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */
250                         if (IS_EQF(strip->blendin, 0.0f) == 0) {
251                                 glVertex2f(strip->start,                    yminc);
252                                 glVertex2f(strip->start + strip->blendin,   ymaxc);
253                         }
254                         else
255                                 glVertex2f(strip->start, ymaxc);
256                                         
257                         /* end of strip */
258                         if (IS_EQF(strip->blendout, 0.0f) == 0) {
259                                 glVertex2f(strip->end - strip->blendout,    ymaxc);
260                                 glVertex2f(strip->end,                      yminc);
261                         }
262                         else
263                                 glVertex2f(strip->end, ymaxc);
264                         glEnd(); // GL_LINE_STRIP
265                 }
266         }
267         
268         /* time -------------------------- */
269         // XXX do we want to draw this curve? in a different color too?
270         
271         /* turn off AA'd lines */
272         glDisable(GL_LINE_SMOOTH);
273         glDisable(GL_BLEND);
274 }
275
276 /* main call for drawing a single NLA-strip */
277 static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
278 {
279         short nonSolo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
280         float color[3];
281         
282         /* get color of strip */
283         nla_strip_get_color_inside(adt, strip, color);
284         
285         /* draw extrapolation info first (as backdrop)
286          *      - but this should only be drawn if track has some contribution
287          */
288         if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (nonSolo == 0)) {
289                 /* enable transparency... */
290                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
291                 glEnable(GL_BLEND);
292                 
293                 switch (strip->extendmode) {
294                         /* since this does both sides, only do the 'before' side, and leave the rest to the next case */
295                         case NLASTRIP_EXTEND_HOLD: 
296                                 /* only need to draw here if there's no strip before since 
297                                  * it only applies in such a situation 
298                                  */
299                                 if (strip->prev == NULL) {
300                                         /* set the drawing color to the color of the strip, but with very faint alpha */
301                                         glColor4f(color[0], color[1], color[2], 0.15f);
302                                         
303                                         /* draw the rect to the edge of the screen */
304                                         glBegin(GL_QUADS);
305                                         glVertex2f(v2d->cur.xmin, yminc);
306                                         glVertex2f(v2d->cur.xmin, ymaxc);
307                                         glVertex2f(strip->start, ymaxc);
308                                         glVertex2f(strip->start, yminc);
309                                         glEnd();
310                                 }
311                         /* no break needed... */
312                                 
313                         /* this only draws after the strip */
314                         case NLASTRIP_EXTEND_HOLD_FORWARD: 
315                                 /* only need to try and draw if the next strip doesn't occur immediately after */
316                                 if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) {
317                                         /* set the drawing color to the color of the strip, but this time less faint */
318                                         glColor4f(color[0], color[1], color[2], 0.3f);
319                                         
320                                         /* draw the rect to the next strip or the edge of the screen */
321                                         glBegin(GL_QUADS);
322                                         glVertex2f(strip->end, yminc);
323                                         glVertex2f(strip->end, ymaxc);
324                                                 
325                                         if (strip->next) {
326                                                 glVertex2f(strip->next->start, ymaxc);
327                                                 glVertex2f(strip->next->start, yminc);
328                                         }
329                                         else {
330                                                 glVertex2f(v2d->cur.xmax, ymaxc);
331                                                 glVertex2f(v2d->cur.xmax, yminc);
332                                         }
333                                         glEnd();
334                                 }
335                                 break;
336                 }
337                 
338                 glDisable(GL_BLEND);
339         }
340         
341         
342         /* draw 'inside' of strip itself */
343         if (nonSolo == 0) {
344                 /* strip is in normal track */
345                 glColor3fv(color);
346                 uiSetRoundBox(UI_CNR_ALL); /* all corners rounded */
347                 
348                 uiDrawBoxShade(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
349         }
350         else {
351                 /* strip is in disabled track - make less visible */
352                 glColor4f(color[0], color[1], color[2], 0.1f);
353                 
354                 glEnable(GL_BLEND);
355                 glRectf(strip->start, yminc, strip->end, ymaxc);
356                 glDisable(GL_BLEND);
357         }
358         
359         
360         /* draw strip's control 'curves'
361          *      - only if user hasn't hidden them...
362          */
363         if ((snla->flag & SNLA_NOSTRIPCURVES) == 0)
364                 nla_draw_strip_curves(strip, yminc, ymaxc);
365         
366         
367         /* draw strip outline 
368          *      - color used here is to indicate active vs non-active
369          */
370         if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
371                 /* strip should appear 'sunken', so draw a light border around it */
372                 glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
373         }
374         else {
375                 /* strip should appear to stand out, so draw a dark border around it */
376                 glColor3f(0.0f, 0.0f, 0.0f);
377         }
378         
379         /* - line style: dotted for muted */
380         if (strip->flag & NLASTRIP_FLAG_MUTED)
381                 setlinestyle(4);
382                 
383         /* draw outline */
384         uiDrawBoxShade(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
385         
386         /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
387         if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) {
388                 float repeatLen = (strip->actend - strip->actstart) * strip->scale;
389                 int i;
390                 
391                 /* only draw lines for whole-numbered repeats, starting from the first full-repeat
392                  * up to the last full repeat (but not if it lies on the end of the strip)
393                  */
394                 for (i = 1; i < strip->repeat; i++) {
395                         float repeatPos = strip->start + (repeatLen * i);
396                         
397                         /* don't draw if line would end up on or after the end of the strip */
398                         if (repeatPos < strip->end)
399                                 fdrawline(repeatPos, yminc + 4, repeatPos, ymaxc - 4);
400                 }
401         }
402         /* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
403         else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
404                 NlaStrip *cs;
405                 float y = (ymaxc - yminc) / 2.0f + yminc;
406                 
407                 /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
408                 for (cs = strip->strips.first; cs; cs = cs->next) {
409                         /* draw start-line if not same as end of previous (and only if not the first strip) 
410                          *      - on upper half of strip
411                          */
412                         if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0)
413                                 fdrawline(cs->start, y, cs->start, ymaxc);
414                                 
415                         /* draw end-line if not the last strip
416                          *      - on lower half of strip
417                          */
418                         if (cs->next) 
419                                 fdrawline(cs->end, yminc, cs->end, y);
420                 }
421         }
422         
423         /* reset linestyle */
424         setlinestyle(0);
425
426
427 /* add the relevant text to the cache of text-strings to draw in pixelspace */
428 static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d, float yminc, float ymaxc)
429 {
430         short notSolo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
431         char str[256];
432         char col[4];
433         float xofs;
434         rctf rect;
435         
436         /* just print the name and the range */
437         if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
438                 BLI_snprintf(str, sizeof(str), "%d) Temp-Meta", index);
439         }
440         else {
441                 BLI_strncpy(str, strip->name, sizeof(str));
442         }
443         
444         /* set text color - if colors (see above) are light, draw black text, otherwise draw white */
445         if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_TWEAKUSER)) {
446                 col[0] = col[1] = col[2] = 0;
447         }
448         else {
449                 col[0] = col[1] = col[2] = 255;
450         }
451         
452         /* text opacity depends on whether if there's a solo'd track, this isn't it */
453         if (notSolo == 0)
454                 col[3] = 255;
455         else
456                 col[3] = 128;
457         
458         /* determine the amount of padding required - cannot be constant otherwise looks weird in some cases */
459         if ((strip->end - strip->start) <= 5.0f)
460                 xofs = 0.5f;
461         else
462                 xofs = 1.0f;
463         
464         /* set bounding-box for text 
465          *      - padding of 2 'units' on either side
466          */
467         // TODO: make this centered?
468         rect.xmin = strip->start + xofs;
469         rect.ymin = yminc;
470         rect.xmax = strip->end - xofs;
471         rect.ymax = ymaxc;
472         
473         /* add this string to the cache of texts to draw */
474         UI_view2d_text_cache_rectf(v2d, &rect, str, col);
475 }
476
477 /* add frame extents to cache of text-strings to draw in pixelspace
478  * for now, only used when transforming strips
479  */
480 static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float UNUSED(yminc), float ymaxc)
481 {
482         const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */
483         const char col[4] = {220, 220, 220, 255}; /* light gray */
484         char numstr[32] = "";
485         
486         
487         /* Always draw times above the strip, whereas sequencer drew below + above.
488          * However, we should be fine having everything on top, since these tend to be 
489          * quite spaced out. 
490          *      - 1 dp is compromise between lack of precision (ints only, as per sequencer)
491          *        while also preserving some accuracy, since we do use floats
492          */
493         /* start frame */
494         BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->start);
495         UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, col);
496         
497         /* end frame */
498         BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->end);
499         UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, col);
500 }
501
502 /* ---------------------- */
503
504 void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
505 {
506         ListBase anim_data = {NULL, NULL};
507         bAnimListElem *ale;
508         int filter;
509         
510         View2D *v2d = &ar->v2d;
511         float y = 0.0f;
512         size_t items;
513         int height;
514         
515         /* build list of channels to draw */
516         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
517         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
518         
519         /* Update max-extent of channels here (taking into account scrollers):
520          *  - this is done to allow the channel list to be scrollable, but must be done here
521          *    to avoid regenerating the list again and/or also because channels list is drawn first
522          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
523          *        start of list offset, and the second is as a correction for the scrollers.
524          */
525         height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
526         /* don't use totrect set, as the width stays the same 
527          * (NOTE: this is ok here, the configuration is pretty straightforward) 
528          */
529         v2d->tot.ymin = (float)(-height);
530         
531         /* loop through channels, and set up drawing depending on their type  */
532         y = (float)(-NLACHANNEL_HEIGHT(snla));
533         
534         for (ale = anim_data.first; ale; ale = ale->next) {
535                 const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
536                 const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
537                 
538                 /* check if visible */
539                 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
540                     IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
541                 {
542                         /* data to draw depends on the type of channel */
543                         switch (ale->type) {
544                                 case ANIMTYPE_NLATRACK:
545                                 {
546                                         AnimData *adt = ale->adt;
547                                         NlaTrack *nlt = (NlaTrack *)ale->data;
548                                         NlaStrip *strip;
549                                         int index;
550                                         
551                                         /* draw each strip in the track (if visible) */
552                                         for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
553                                                 if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
554                                                         /* draw the visualization of the strip */
555                                                         nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc);
556                                                         
557                                                         /* add the text for this strip to the cache */
558                                                         nla_draw_strip_text(adt, nlt, strip, index, v2d, yminc, ymaxc);
559                                                         
560                                                         /* if transforming strips (only real reason for temp-metas currently), 
561                                                          * add to the cache the frame numbers of the strip's extents
562                                                          */
563                                                         if (strip->flag & NLASTRIP_FLAG_TEMP_META)
564                                                                 nla_draw_strip_frames_text(nlt, strip, v2d, yminc, ymaxc);
565                                                 }
566                                         }
567                                 }
568                                 break;
569                                         
570                                 case ANIMTYPE_NLAACTION:
571                                 {
572                                         AnimData *adt = ale->adt;
573                                         float color[4];
574                                         
575                                         /* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
576                                          * and a second darker rect within which we draw keyframe indicator dots if there's data
577                                          */
578                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
579                                         glEnable(GL_BLEND);
580                                                 
581                                         /* get colors for drawing */
582                                         nla_action_get_color(adt, ale->data, color);
583                                         glColor4fv(color);
584                                         
585                                         /* draw slightly shifted up for greater separation from standard channels,
586                                          * but also slightly shorter for some more contrast when viewing the strips
587                                          */
588                                         glRectf(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
589                                         
590                                         /* draw keyframes in the action */
591                                         nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
592                                         
593                                         /* draw 'embossed' lines above and below the strip for effect */
594                                         /* white base-lines */
595                                         glLineWidth(2.0f);
596                                         glColor4f(1.0f, 1.0f, 1.0f, 0.3);
597                                         fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
598                                         fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
599                                         
600                                         /* black top-lines */
601                                         glLineWidth(1.0f);
602                                         glColor3f(0.0f, 0.0f, 0.0f);
603                                         fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
604                                         fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
605                                         
606                                         glDisable(GL_BLEND);
607                                 }
608                                 break;
609                         }
610                 }
611                 
612                 /* adjust y-position for next one */
613                 y -= NLACHANNEL_STEP(snla);
614         }
615         
616         /* free tempolary channels */
617         BLI_freelistN(&anim_data);
618 }
619
620 /* *********************************************** */
621 /* Channel List */
622
623 /* old code for drawing NLA channels using GL only */
624 // TODO: depreceate this code...
625 static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View2D *v2d, float y)
626 {
627         SpaceNla *snla = (SpaceNla *)ac->sl;
628         bAnimListElem *ale;
629         float x = 0.0f;
630         
631         /* loop through channels, and set up drawing depending on their type  */
632         for (ale = anim_data->first; ale; ale = ale->next) {
633                 const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
634                 const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
635                 const float ydatac = (float)(y - 0.35f * U.widget_unit);
636                 
637                 /* check if visible */
638                 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
639                     IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
640                 {
641                         AnimData *adt = ale->adt;
642                         
643                         short indent = 0, offset = 0, sel = 0, group = 0, nonSolo = 0;
644                         int expand = -1, protect = -1, special = -1, mute = -1;
645                         char name[128];
646                         short do_draw = FALSE;
647                         
648                         /* determine what needs to be drawn */
649                         switch (ale->type) {
650                                 case ANIMTYPE_NLATRACK: /* NLA Track */
651                                 {
652                                         NlaTrack *nlt = (NlaTrack *)ale->data;
653                                         
654                                         /* 'solo' as the 'special' button? */
655                                         if (nlt->flag & NLATRACK_SOLO)
656                                                 special = ICON_SOLO_ON;
657                                         else
658                                                 special = ICON_SOLO_OFF;
659                                                 
660                                         /* if this track is active and we're tweaking it, don't draw these toggles */
661                                         // TODO: need a special macro for this...
662                                         if (((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0) {
663                                                 if (nlt->flag & NLATRACK_MUTED)
664                                                         mute = ICON_MUTE_IPO_ON;
665                                                 else
666                                                         mute = ICON_MUTE_IPO_OFF;
667                                                         
668                                                 if (EDITABLE_NLT(nlt))
669                                                         protect = ICON_UNLOCKED;
670                                                 else
671                                                         protect = ICON_LOCKED;
672                                         }
673                                         
674                                         /* is track enabled for solo drawing? */
675                                         if ((adt) && (adt->flag & ADT_NLA_SOLO_TRACK)) {
676                                                 if ((nlt->flag & NLATRACK_SOLO) == 0) {
677                                                         /* tag for special non-solo handling; also hide the mute toggles */
678                                                         nonSolo = 1;
679                                                         mute = 0;
680                                                 }
681                                         }
682                                                 
683                                         sel = SEL_NLT(nlt);
684                                         BLI_strncpy(name, nlt->name, sizeof(name));
685                                         
686                                         /* draw manually still */
687                                         do_draw = TRUE;
688                                 }
689                                 break;
690                                 case ANIMTYPE_NLAACTION: /* NLA Action-Line */
691                                 {
692                                         bAction *act = (bAction *)ale->data;
693                                         
694                                         group = 5;
695                                         
696                                         special = ICON_ACTION;
697                                         
698                                         if (act)
699                                                 BLI_snprintf(name, sizeof(name), "%s", act->id.name + 2);
700                                         else
701                                                 BLI_strncpy(name, "<No Action>", sizeof(name));
702                                                 
703                                         /* draw manually still */
704                                         do_draw = TRUE;
705                                 }
706                                 break;
707                                         
708                                 default: /* handled by standard channel-drawing API */
709                                         // draw backdrops only...
710                                         ANIM_channel_draw(ac, ale, yminc, ymaxc);
711                                         break;
712                         }
713                         
714                         /* if special types, draw manually for now... */
715                         if (do_draw) {
716                                 if (ale->id) {
717                                         /* special exception for textures */
718                                         if (GS(ale->id->name) == ID_TE) {
719                                                 offset = 0.7f * U.widget_unit;
720                                                 indent = 1;
721                                         }
722                                         /* special exception for nodetrees */
723                                         else if (GS(ale->id->name) == ID_NT) {
724                                                 bNodeTree *ntree = (bNodeTree *)ale->id;
725                                                 
726                                                 switch (ntree->type) {
727                                                         case NTREE_SHADER:
728                                                         {
729                                                                 /* same as for textures */
730                                                                 offset = 0.7f * U.widget_unit;
731                                                                 indent = 1;
732                                                         }
733                                                         break;
734                                                                 
735                                                         case NTREE_TEXTURE:
736                                                         {
737                                                                 /* even more */
738                                                                 offset = U.widget_unit;
739                                                                 indent = 1;
740                                                         }
741                                                         break;
742                                                                 
743                                                         default:
744                                                                 /* normal will do */
745                                                                 offset = 0.7f * U.widget_unit;
746                                                                 break;
747                                                 }
748                                         }
749                                         else {
750                                                 offset = 0.7f * U.widget_unit;
751                                         }
752                                 }
753                                 else {
754                                         offset = 0;
755                                 }
756                                 
757                                 /* now, start drawing based on this information */
758                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
759                                 glEnable(GL_BLEND);
760                                 
761                                 /* draw backing strip behind channel name */
762                                 // FIXME: hardcoded colors!!!
763                                 if (group == 5) {
764                                         float color[4];
765                                         
766                                         /* Action Line
767                                          *   The alpha values action_get_color returns are only useful for drawing 
768                                          *   strips backgrounds but here we're doing channel list backgrounds instead
769                                          *   so we ignore that and use our own when needed
770                                          */
771                                         nla_action_get_color(adt, (bAction *)ale->data, color);
772                                         
773                                         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
774                                                 /* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */
775                                                 glColor3fv(color);
776                                         }
777                                         else {
778                                                 float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
779                                                 glColor4f(color[0], color[1], color[2], alpha);
780                                         }
781                                         
782                                         offset += 0.35f * U.widget_unit * indent;
783                                         
784                                         /* only on top two corners, to show that this channel sits on top of the preceding ones */
785                                         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
786                                         
787                                         /* draw slightly shifted up vertically to look like it has more separation from other channels,
788                                          * but we then need to slightly shorten it so that it doesn't look like it overlaps
789                                          */
790                                         uiDrawBox(GL_POLYGON, x + offset,  yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
791                                         
792                                         /* clear group value, otherwise we cause errors... */
793                                         group = 0;
794                                 }
795                                 else {
796                                         /* NLA tracks - darker color if not solo track when we're showing solo */
797                                         UI_ThemeColorShade(TH_HEADER, ((nonSolo == 0) ? 20 : -20));
798                                         
799                                         indent += group;
800                                         offset += 0.35f * U.widget_unit * indent;
801                                         glBegin(GL_QUADS);
802                                         glVertex2f(x + offset, yminc);
803                                         glVertex2f(x + offset, ymaxc);
804                                         glVertex2f((float)v2d->cur.xmax, ymaxc);
805                                         glVertex2f((float)v2d->cur.xmax, yminc);
806                                         glEnd();
807                                 }
808                                 
809                                 /* draw expand/collapse triangle */
810                                 if (expand > 0) {
811                                         UI_icon_draw(x + offset, ydatac, expand);
812                                         offset += 0.85f * U.widget_unit;
813                                 }
814                                 
815                                 /* draw special icon indicating certain data-types */
816                                 if (special > -1) {
817                                         /* for normal channels */
818                                         UI_icon_draw(x + offset, ydatac, special);
819                                         offset += 0.85f * U.widget_unit;
820                                 }
821                                 glDisable(GL_BLEND);
822                                 
823                                 /* draw name */
824                                 if (sel)
825                                         UI_ThemeColor(TH_TEXT_HI);
826                                 else
827                                         UI_ThemeColor(TH_TEXT);
828                                 offset += 3;
829                                 UI_DrawString(x + offset, y - 4, name);
830                                 
831                                 /* reset offset - for RHS of panel */
832                                 offset = 0;
833                                 
834                                 /* set blending again, as text drawing may clear it */
835                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
836                                 glEnable(GL_BLEND);
837                                 
838                                 /* draw protect 'lock' */
839                                 if (protect > -1) {
840                                         offset =  0.8f * U.widget_unit;
841                                         UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, protect);
842                                 }
843                                 
844                                 /* draw mute 'eye' */
845                                 if (mute > -1) {
846                                         offset += 0.8f * U.widget_unit;
847                                         UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, mute);
848                                 }
849                                 
850                                 /* draw NLA-action line 'status-icons' - only when there's an action */
851                                 if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) {
852                                         offset += 0.8f * U.widget_unit;
853                                         
854                                         /* now draw some indicator icons  */
855                                         if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
856                                                 /* toggle for tweaking with mapping/no-mapping (i.e. 'in place editing' toggle) */
857                                                 // for now, use pin icon to symbolise this
858                                                 if (adt->flag & ADT_NLA_EDIT_NOMAP)
859                                                         UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_PINNED);
860                                                 else
861                                                         UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_UNPINNED);
862                                                 
863                                                 fdrawline((float)(v2d->cur.xmax - offset), yminc,
864                                                           (float)(v2d->cur.xmax - offset), ymaxc);
865                                                 offset += 0.8f * U.widget_unit;
866                                                 
867                                                 /* 'tweaking action' indicator - not a button */
868                                                 UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_EDIT);
869                                         }
870                                         else {
871                                                 /* XXX firstly draw a little rect to help identify that it's different from the toggles */
872                                                 glBegin(GL_LINE_LOOP);
873                                                 glVertex2f((float)v2d->cur.xmax - offset - 1, y - 0.35f * U.widget_unit);
874                                                 glVertex2f((float)v2d->cur.xmax - offset - 1, y + 0.45 * U.widget_unit);
875                                                 glVertex2f((float)v2d->cur.xmax - 1, y +  0.45f * U.widget_unit);
876                                                 glVertex2f((float)v2d->cur.xmax - 1, y - 0.35f * U.widget_unit);
877                                                 glEnd(); // GL_LINES
878                                                 
879                                                 /* 'push down' icon for normal active-actions */
880                                                 UI_icon_draw((float)v2d->cur.xmax - offset, ydatac, ICON_FREEZE);
881                                         }
882                                 }
883                                 
884                                 glDisable(GL_BLEND);
885                         }
886                 }
887                 
888                 /* adjust y-position for next one */
889                 y -= NLACHANNEL_STEP(snla);
890         }
891 }
892
893 void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
894 {
895         ListBase anim_data = {NULL, NULL};
896         bAnimListElem *ale;
897         int filter;
898         
899         SpaceNla *snla = (SpaceNla *)ac->sl;
900         View2D *v2d = &ar->v2d;
901         float y = 0.0f;
902         size_t items;
903         int height;
904         
905         /* build list of channels to draw */
906         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
907         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
908         
909         /* Update max-extent of channels here (taking into account scrollers):
910          *  - this is done to allow the channel list to be scrollable, but must be done here
911          *    to avoid regenerating the list again and/or also because channels list is drawn first
912          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
913          *        start of list offset, and the second is as a correction for the scrollers.
914          */
915         height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
916         /* don't use totrect set, as the width stays the same 
917          * (NOTE: this is ok here, the configuration is pretty straightforward) 
918          */
919         v2d->tot.ymin = (float)(-height);
920         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
921         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
922         
923         /* draw channels */
924         {   /* first pass: backdrops + oldstyle drawing */
925                 y = (float)(-NLACHANNEL_HEIGHT(snla));
926                 
927                 draw_nla_channel_list_gl(ac, &anim_data, v2d, y);
928         }
929         {   /* second pass: UI widgets */
930                 uiBlock *block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
931                 size_t channel_index = 0;
932                 
933                 y = (float)(-NLACHANNEL_HEIGHT(snla));
934                 
935                 /* set blending again, as may not be set in previous step */
936                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
937                 glEnable(GL_BLEND);
938                 
939                 /* loop through channels, and set up drawing depending on their type  */
940                 for (ale = anim_data.first; ale; ale = ale->next) {
941                         const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
942                         const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
943                         
944                         /* check if visible */
945                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
946                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
947                         {
948                                 /* draw all channels using standard channel-drawing API */
949                                 ANIM_channel_draw_widgets(C, ac, ale, block, yminc, ymaxc, channel_index);
950                         }
951                         
952                         /* adjust y-position for next one */
953                         y -= NLACHANNEL_STEP(snla);
954                         channel_index++;
955                 }
956                 
957                 uiEndBlock(C, block);
958                 uiDrawBlock(C, block);
959                 
960                 glDisable(GL_BLEND);
961         }
962         
963         /* free tempolary channels */
964         BLI_freelistN(&anim_data);
965 }
966
967 /* *********************************************** */