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