Merge with 2.5 -r 21788:22040.
[blender-staging.git] / source / blender / editors / space_graph / graph_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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) Blender Foundation
21  *
22  * Contributor(s): Joshua Leung (2009 Recode)
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <stdio.h>
28 #include <math.h>
29 #include <string.h>
30 #include <float.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #ifndef _WIN32
37 #include <unistd.h>
38 #else
39 #include <io.h>
40 #endif
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 #include "DNA_anim_types.h"
48 #include "DNA_action_types.h"
49 #include "DNA_camera_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_key_types.h"
52 #include "DNA_lamp_types.h"
53 #include "DNA_material_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_particle_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_space_types.h"
59 #include "DNA_sequence_types.h"
60 #include "DNA_userdef_types.h"
61 #include "DNA_view2d_types.h"
62 #include "DNA_windowmanager_types.h"
63 #include "DNA_world_types.h"
64
65 #include "BKE_animsys.h"
66 #include "BKE_context.h"
67 #include "BKE_curve.h"
68 #include "BKE_depsgraph.h"
69 #include "BKE_fcurve.h"
70 #include "BKE_global.h"
71 #include "BKE_key.h"
72 #include "BKE_object.h"
73 #include "BKE_screen.h"
74 #include "BKE_utildefines.h"
75
76 #include "BIF_gl.h"
77 #include "BIF_glutil.h"
78
79 #include "ED_anim_api.h"
80 #include "ED_util.h"
81
82 #include "graph_intern.h"
83
84 #include "UI_interface.h"
85 #include "UI_interface_icons.h"
86 #include "UI_resources.h"
87 #include "UI_view2d.h"
88
89 /* XXX */
90 extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad);
91
92 /* *************************** */
93 /* F-Curve Modifier Drawing */
94
95 /* Envelope -------------- */
96
97 // TODO: draw a shaded poly showing the region of influence too!!!
98 static void draw_fcurve_modifier_controls_envelope (FCurve *fcu, FModifier *fcm, View2D *v2d)
99 {
100         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
101         FCM_EnvelopeData *fed;
102         const float fac= 0.05f * (v2d->cur.xmax - v2d->cur.xmin);
103         int i;
104         
105         /* draw two black lines showing the standard reference levels */
106         glColor3f(0.0f, 0.0f, 0.0f);
107         setlinestyle(5);
108         
109         glBegin(GL_LINES);
110                 glVertex2f(v2d->cur.xmin, env->midval+env->min);
111                 glVertex2f(v2d->cur.xmax, env->midval+env->min);
112                 
113                 glVertex2f(v2d->cur.xmin, env->midval+env->max);
114                 glVertex2f(v2d->cur.xmax, env->midval+env->max);
115         glEnd(); // GL_LINES
116         setlinestyle(0);
117         
118         /* set size of vertices (non-adjustable for now) */
119         glPointSize(2.0f);
120         
121         // for now, point color is fixed, and is white
122         glColor3f(1.0f, 1.0f, 1.0f);
123         
124         /* we use bgl points not standard gl points, to workaround vertex 
125          * drawing bugs that some drivers have (probably legacy ones only though)
126          */
127         bglBegin(GL_POINTS);
128         for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
129                 /* only draw if visible
130                  *      - min/max here are fixed, not relative
131                  */
132                 if IN_RANGE(fed->time, (v2d->cur.xmin - fac), (v2d->cur.xmax + fac)) {
133                         glVertex2f(fed->time, fed->min);
134                         glVertex2f(fed->time, fed->max);
135                 }
136         }
137         bglEnd();
138         
139         glPointSize(1.0f);
140 }
141
142 /* *************************** */
143 /* F-Curve Drawing */
144
145 /* Points ---------------- */
146
147 /* helper func - draw keyframe vertices only for an F-Curve */
148 static void draw_fcurve_vertices_keyframes (FCurve *fcu, View2D *v2d, short edit, short sel)
149 {
150         BezTriple *bezt= fcu->bezt;
151         const float fac= 0.05f * (v2d->cur.xmax - v2d->cur.xmin);
152         int i;
153         
154         /* we use bgl points not standard gl points, to workaround vertex 
155          * drawing bugs that some drivers have (probably legacy ones only though)
156          */
157         bglBegin(GL_POINTS);
158         
159         for (i = 0; i < fcu->totvert; i++, bezt++) {
160                 /* as an optimisation step, only draw those in view 
161                  *      - we apply a correction factor to ensure that points don't pop in/out due to slight twitches of view size
162                  */
163                 if IN_RANGE(bezt->vec[1][0], (v2d->cur.xmin - fac), (v2d->cur.xmax + fac)) {
164                         if (edit) {
165                                 /* 'Keyframe' vertex only, as handle lines and handles have already been drawn
166                                  *      - only draw those with correct selection state for the current drawing color
167                                  *      - 
168                                  */
169                                 if ((bezt->f2 & SELECT) == sel)
170                                         bglVertex3fv(bezt->vec[1]);
171                         }
172                         else {
173                                 /* no check for selection here, as curve is not editable... */
174                                 // XXX perhaps we don't want to even draw points?   maybe add an option for that later
175                                 bglVertex3fv(bezt->vec[1]);
176                         }
177                 }
178         }
179         
180         bglEnd();
181 }
182
183
184 /* helper func - draw handle vertex for an F-Curve as a round unfilled circle */
185 static void draw_fcurve_handle_control (float x, float y, float xscale, float yscale, float hsize)
186 {
187         static GLuint displist=0;
188         
189         /* initialise round circle shape */
190         if (displist == 0) {
191                 GLUquadricObj *qobj;
192                 
193                 displist= glGenLists(1);
194                 glNewList(displist, GL_COMPILE);
195                 
196                 qobj    = gluNewQuadric(); 
197                 gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
198                 gluDisk(qobj, 0,  0.7, 8, 1);
199                 gluDeleteQuadric(qobj);  
200                 
201                 glEndList();
202         }
203         
204         /* adjust view transform before starting */
205         glTranslatef(x, y, 0.0f);
206         glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f);
207         
208         /* anti-aliased lines for more consistent appearance */
209         glEnable(GL_LINE_SMOOTH);
210         glEnable(GL_BLEND);
211         
212         /* draw! */
213         glCallList(displist);
214         
215         glDisable(GL_LINE_SMOOTH);
216         glDisable(GL_BLEND);
217         
218         /* restore view transform */
219         glScalef(xscale/hsize, yscale/hsize, 1.0);
220         glTranslatef(-x, -y, 0.0f);
221 }
222
223 /* helper func - draw handle vertices only for an F-Curve (if it is not protected) */
224 static void draw_fcurve_vertices_handles (FCurve *fcu, View2D *v2d, short sel)
225 {
226         BezTriple *bezt= fcu->bezt;
227         BezTriple *prevbezt = NULL;
228         float hsize, xscale, yscale;
229         int i;
230         
231         /* get view settings */
232         hsize= UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE);
233         UI_view2d_getscale(v2d, &xscale, &yscale);
234         
235         /* set handle color */
236         if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
237         else UI_ThemeColor(TH_HANDLE_VERTEX);
238         
239         for (i=0; i < fcu->totvert; i++, prevbezt=bezt, bezt++) {
240                 /* Draw the editmode handels for a bezier curve (others don't have handles) 
241                  * if their selection status matches the selection status we're drawing for
242                  *      - first handle only if previous beztriple was bezier-mode
243                  *      - second handle only if current beztriple is bezier-mode
244                  */
245                 if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) {
246                         if ((bezt->f1 & SELECT) == sel)/* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/
247                                 draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize);
248                 }
249                 
250                 if (bezt->ipo==BEZT_IPO_BEZ) {
251                         if ((bezt->f3 & SELECT) == sel)/* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/
252                                 draw_fcurve_handle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize);
253                 }
254         }
255 }
256
257 /* helper func - set color to draw F-Curve data with */
258 static void set_fcurve_vertex_color (SpaceIpo *sipo, FCurve *fcu, short sel)
259 {
260 #if 0
261                 if (sipo->showkey) {
262                         if (sel) UI_ThemeColor(TH_TEXT_HI);
263                         else UI_ThemeColor(TH_TEXT);
264                 } 
265 #endif
266                 if ((fcu->flag & FCURVE_PROTECTED)==0) {
267                         /* Curve's points are being edited */
268                         if (sel) UI_ThemeColor(TH_VERTEX_SELECT); 
269                         else UI_ThemeColor(TH_VERTEX);
270                 } 
271                 else {
272                         /* Curve's points cannot be edited */
273                         if (sel) UI_ThemeColor(TH_TEXT_HI);
274                         else UI_ThemeColor(TH_TEXT);
275                 }
276 }
277
278
279 void draw_fcurve_vertices (SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
280 {
281         View2D *v2d= &ar->v2d;
282         
283         /* only draw points if curve is visible 
284          *      - draw unselected points before selected points as separate passes to minimise color-changing overhead
285          *         (XXX dunno if this is faster than drawing all in one pass though) 
286          *         and also to make sure in the case of overlapping points that the selected is always visible
287          *      - draw handles before keyframes, so that keyframes will overlap handles (keyframes are more important for users)
288          */
289         
290         glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
291         
292         /* draw the two handles first (if they're shown, and if curve is being edited) */
293         if ((fcu->flag & FCURVE_PROTECTED)==0 && (fcu->flag & FCURVE_INT_VALUES)==0 && (sipo->flag & SIPO_NOHANDLES)==0) {
294                 set_fcurve_vertex_color(sipo, fcu, 0);
295                 draw_fcurve_vertices_handles(fcu, v2d, 0);
296                 
297                 set_fcurve_vertex_color(sipo, fcu, 1);
298                 draw_fcurve_vertices_handles(fcu, v2d, 1);
299         }
300                 
301         /* draw keyframes over the handles */
302         set_fcurve_vertex_color(sipo, fcu, 0);
303         draw_fcurve_vertices_keyframes(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), 0);
304         
305         set_fcurve_vertex_color(sipo, fcu, 1);
306         draw_fcurve_vertices_keyframes(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), 1);
307         
308         glPointSize(1.0f);
309 }
310
311 /* Handles ---------------- */
312
313 /* draw lines for F-Curve handles only (this is only done in EditMode) */
314 static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
315 {
316         extern unsigned int nurbcol[];
317         unsigned int *col;
318         int sel, b;
319         
320         /* don't draw handle lines if handles are not shown */
321         if ((sipo->flag & SIPO_NOHANDLES) || (fcu->flag & FCURVE_PROTECTED) || (fcu->flag & FCURVE_INT_VALUES))
322                 return;
323         
324         /* slightly hacky, but we want to draw unselected points before selected ones*/
325         for (sel= 0; sel < 2; sel++) {
326                 BezTriple *bezt=fcu->bezt, *prevbezt=NULL;
327                 float *fp;
328                 
329                 if (sel) col= nurbcol+4;
330                 else col= nurbcol;
331                         
332                 for (b= 0; b < fcu->totvert; b++, prevbezt=bezt, bezt++) {
333                         if ((bezt->f2 & SELECT)==sel) {
334                                 fp= bezt->vec[0];
335                                 
336                                 /* only draw first handle if previous segment had handles */
337                                 if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) 
338                                 {
339                                         cpack(col[(unsigned char)bezt->h1]);
340                                         glBegin(GL_LINE_STRIP); 
341                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
342                                         glEnd();
343                                         
344                                 }
345                                 
346                                 /* only draw second handle if this segment is bezier */
347                                 if (bezt->ipo == BEZT_IPO_BEZ) 
348                                 {
349                                         cpack(col[(unsigned char)bezt->h2]);
350                                         glBegin(GL_LINE_STRIP); 
351                                                 glVertex2fv(fp+3); glVertex2fv(fp+6); 
352                                         glEnd();
353                                 }
354                         }
355                         else {
356                                 /* only draw first handle if previous segment was had handles, and selection is ok */
357                                 if ( ((bezt->f1 & SELECT)==sel) && 
358                                          ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) ) 
359                                 {
360                                         fp= bezt->vec[0];
361                                         cpack(col[(unsigned char)bezt->h1]);
362                                         
363                                         glBegin(GL_LINE_STRIP); 
364                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
365                                         glEnd();
366                                 }
367                                 
368                                 /* only draw second handle if this segment is bezier, and selection is ok */
369                                 if ( ((bezt->f3 & SELECT)==sel) &&
370                                          (bezt->ipo == BEZT_IPO_BEZ) )
371                                 {
372                                         fp= bezt->vec[1];
373                                         cpack(col[(unsigned char)bezt->h2]);
374                                         
375                                         glBegin(GL_LINE_STRIP); 
376                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
377                                         glEnd();
378                                 }
379                         }
380                 }
381         }
382 }
383
384 /* Samples ---------------- */
385
386 /* helper func - draw sample-range marker for an F-Curve as a cross */
387 static void draw_fcurve_sample_control (float x, float y, float xscale, float yscale, float hsize)
388 {
389         static GLuint displist=0;
390         
391         /* initialise X shape */
392         if (displist == 0) {
393                 displist= glGenLists(1);
394                 glNewList(displist, GL_COMPILE);
395                 
396                 glBegin(GL_LINES);
397                         glVertex2f(-0.7f, -0.7f);
398                         glVertex2f(+0.7f, +0.7f);
399                         
400                         glVertex2f(-0.7f, +0.7f);
401                         glVertex2f(+0.7f, -0.7f);
402                 glEnd(); // GL_LINES
403                 
404                 glEndList();
405         }
406         
407         /* adjust view transform before starting */
408         glTranslatef(x, y, 0.0f);
409         glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f);
410         
411         /* anti-aliased lines for more consistent appearance */
412                 // XXX needed here?
413         glEnable(GL_LINE_SMOOTH);
414         glEnable(GL_BLEND);
415         
416         /* draw! */
417         glCallList(displist);
418         
419         glDisable(GL_BLEND);
420         glDisable(GL_LINE_SMOOTH);
421         
422         /* restore view transform */
423         glScalef(xscale/hsize, yscale/hsize, 1.0);
424         glTranslatef(-x, -y, 0.0f);
425 }
426
427 /* helper func - draw keyframe vertices only for an F-Curve */
428 static void draw_fcurve_samples (SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
429 {
430         FPoint *first, *last;
431         float hsize, xscale, yscale;
432         
433         /* get view settings */
434         hsize= UI_GetThemeValuef(TH_VERTEX_SIZE);
435         UI_view2d_getscale(&ar->v2d, &xscale, &yscale);
436         
437         /* set vertex color */
438         if (fcu->flag & (FCURVE_ACTIVE|FCURVE_SELECTED)) UI_ThemeColor(TH_TEXT_HI);
439         else UI_ThemeColor(TH_TEXT);
440         
441         /* get verts */
442         first= fcu->fpt;
443         last= (first) ? (first + (fcu->totvert-1)) : (NULL);
444         
445         /* draw */
446         if (first && last) {
447                 draw_fcurve_sample_control(first->vec[0], first->vec[1], xscale, yscale, hsize);
448                 draw_fcurve_sample_control(last->vec[0], last->vec[1], xscale, yscale, hsize);
449         }
450 }
451
452 /* Curve ---------------- */
453
454 /* minimum pixels per gridstep 
455  * XXX: defined in view2d.c - must keep these in sync or relocate to View2D header!
456  */
457 #define MINGRIDSTEP     35
458
459 /* helper func - just draw the F-Curve by sampling the visible region (for drawing curves with modifiers) */
460 static void draw_fcurve_curve (FCurve *fcu, SpaceIpo *sipo, View2D *v2d, View2DGrid *grid)
461 {
462         ChannelDriver *driver;
463         float samplefreq, ctime;
464         float stime, etime;
465         
466         /* disable any drivers temporarily */
467         driver= fcu->driver;
468         fcu->driver= NULL;
469         
470         
471         /* Note about sampling frequency:
472          *      Ideally, this is chosen such that we have 1-2 pixels = 1 segment
473          *      which means that our curves can be as smooth as possible. However,
474          *      this does mean that curves may not be fully accurate (i.e. if they have
475          *      sudden spikes which happen at the sampling point, we may have problems).
476          *      Also, this may introduce lower performance on less densely detailed curves,'
477          *      though it is impossible to predict this from the modifiers!
478          *
479          *      If the automatically determined sampling frequency is likely to cause an infinite
480          *      loop (i.e. too close to FLT_EPSILON), fall back to default of 0.001
481          */
482                 /* grid->dx is the first float in View2DGrid struct, so just cast to float pointer, and use it
483                  * It represents the number of 'frames' between gridlines, but we divide by MINGRIDSTEP to get pixels-steps
484                  */
485                 // TODO: perhaps we should have 1.0 frames as upper limit so that curves don't get too distorted?
486         samplefreq= *((float *)grid) / MINGRIDSTEP;
487         if (IS_EQ(samplefreq, 0)) samplefreq= 0.001f;
488         
489         
490         /* the start/end times are simply the horizontal extents of the 'cur' rect */
491         stime= v2d->cur.xmin;
492         etime= v2d->cur.xmax;
493         
494         
495         /* at each sampling interval, add a new vertex */
496         glBegin(GL_LINE_STRIP);
497         
498         for (ctime= stime; ctime <= etime; ctime += samplefreq)
499                 glVertex2f( ctime, evaluate_fcurve(fcu, ctime) );
500         
501         glEnd();
502         
503         /* restore driver */
504         fcu->driver= driver;
505 }
506
507 /* helper func - draw a samples-based F-Curve */
508 // TODO: add offset stuff...
509 static void draw_fcurve_curve_samples (FCurve *fcu, View2D *v2d)
510 {
511         FPoint *prevfpt= fcu->fpt;
512         FPoint *fpt= prevfpt + 1;
513         float fac, v[2];
514         int b= fcu->totvert-1;
515         
516         glBegin(GL_LINE_STRIP);
517         
518         /* extrapolate to left? - left-side of view comes before first keyframe? */
519         if (prevfpt->vec[0] > v2d->cur.xmin) {
520                 v[0]= v2d->cur.xmin;
521                 
522                 /* y-value depends on the interpolation */
523                 if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (fcu->totvert==1)) {
524                         /* just extend across the first keyframe's value */
525                         v[1]= prevfpt->vec[1];
526                 } 
527                 else {
528                         /* extrapolate linear dosnt use the handle, use the next points center instead */
529                         fac= (prevfpt->vec[0]-fpt->vec[0])/(prevfpt->vec[0]-v[0]);
530                         if (fac) fac= 1.0f/fac;
531                         v[1]= prevfpt->vec[1]-fac*(prevfpt->vec[1]-fpt->vec[1]);
532                 }
533                 
534                 glVertex2fv(v);
535         }
536         
537         /* if only one sample, add it now */
538         if (fcu->totvert == 1)
539                 glVertex2fv(prevfpt->vec);
540         
541         /* loop over samples, drawing segments */
542         /* draw curve between first and last keyframe (if there are enough to do so) */
543         while (b--) {
544                 /* Linear interpolation: just add one point (which should add a new line segment) */
545                 glVertex2fv(prevfpt->vec);
546                 
547                 /* get next pointers */
548                 prevfpt= fpt; 
549                 fpt++;
550                 
551                 /* last point? */
552                 if (b == 0)
553                         glVertex2fv(prevfpt->vec);
554         }
555         
556         /* extrapolate to right? (see code for left-extrapolation above too) */
557         if (prevfpt->vec[0] < v2d->cur.xmax) {
558                 v[0]= v2d->cur.xmax;
559                 
560                 /* y-value depends on the interpolation */
561                 if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (fcu->totvert==1)) {
562                         /* based on last keyframe's value */
563                         v[1]= prevfpt->vec[1];
564                 } 
565                 else {
566                         /* extrapolate linear dosnt use the handle, use the previous points center instead */
567                         fpt = prevfpt-1;
568                         fac= (prevfpt->vec[0]-fpt->vec[0])/(prevfpt->vec[0]-v[0]);
569                         if (fac) fac= 1.0f/fac;
570                         v[1]= prevfpt->vec[1]-fac*(prevfpt->vec[1]-fpt->vec[1]);
571                 }
572                 
573                 glVertex2fv(v);
574         }
575         
576         glEnd();
577 }
578
579 /* helper func - draw one repeat of an F-Curve */
580 static void draw_fcurve_curve_bezts (FCurve *fcu, View2D *v2d, View2DGrid *grid)
581 {
582         BezTriple *prevbezt= fcu->bezt;
583         BezTriple *bezt= prevbezt+1;
584         float v1[2], v2[2], v3[2], v4[2];
585         float *fp, data[120];
586         float fac= 0.0f;
587         int b= fcu->totvert-1;
588         int resol;
589         
590         glBegin(GL_LINE_STRIP);
591         
592         /* extrapolate to left? */
593         if (prevbezt->vec[1][0] > v2d->cur.xmin) {
594                 /* left-side of view comes before first keyframe, so need to extend as not cyclic */
595                 v1[0]= v2d->cur.xmin;
596                 
597                 /* y-value depends on the interpolation */
598                 if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) {
599                         /* just extend across the first keyframe's value */
600                         v1[1]= prevbezt->vec[1][1];
601                 } 
602                 else if (prevbezt->ipo==BEZT_IPO_LIN) {
603                         /* extrapolate linear dosnt use the handle, use the next points center instead */
604                         fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
605                         if (fac) fac= 1.0f/fac;
606                         v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
607                 } 
608                 else {
609                         /* based on angle of handle 1 (relative to keyframe) */
610                         fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
611                         if (fac) fac= 1.0f/fac;
612                         v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]);
613                 }
614                 
615                 glVertex2fv(v1);
616         }
617         
618         /* if only one keyframe, add it now */
619         if (fcu->totvert == 1) {
620                 v1[0]= prevbezt->vec[1][0];
621                 v1[1]= prevbezt->vec[1][1];
622                 glVertex2fv(v1);
623         }
624         
625         /* draw curve between first and last keyframe (if there are enough to do so) */
626         while (b--) {
627                 if (prevbezt->ipo==BEZT_IPO_CONST) {
628                         /* Constant-Interpolation: draw segment between previous keyframe and next, but holding same value */
629                         v1[0]= prevbezt->vec[1][0];
630                         v1[1]= prevbezt->vec[1][1];
631                         glVertex2fv(v1);
632                         
633                         v1[0]= bezt->vec[1][0];
634                         v1[1]= prevbezt->vec[1][1];
635                         glVertex2fv(v1);
636                 }
637                 else if (prevbezt->ipo==BEZT_IPO_LIN) {
638                         /* Linear interpolation: just add one point (which should add a new line segment) */
639                         v1[0]= prevbezt->vec[1][0];
640                         v1[1]= prevbezt->vec[1][1];
641                         glVertex2fv(v1);
642                 }
643                 else {
644                         /* Bezier-Interpolation: draw curve as series of segments between keyframes 
645                          *      - resol determines number of points to sample in between keyframes
646                          */
647                         
648                         /* resol not depending on horizontal resolution anymore, drivers for example... */
649                         // XXX need to take into account the scale
650                         if (fcu->driver) 
651                                 resol= 32;
652                         else 
653                                 resol= (int)(3.0*sqrt(bezt->vec[1][0] - prevbezt->vec[1][0]));
654                         
655                         if (resol < 2) {
656                                 /* only draw one */
657                                 v1[0]= prevbezt->vec[1][0];
658                                 v1[1]= prevbezt->vec[1][1];
659                                 glVertex2fv(v1);
660                         }
661                         else {
662                                 /* clamp resolution to max of 32 */
663                                 if (resol > 32) resol= 32;
664                                 
665                                 v1[0]= prevbezt->vec[1][0];
666                                 v1[1]= prevbezt->vec[1][1];
667                                 v2[0]= prevbezt->vec[2][0];
668                                 v2[1]= prevbezt->vec[2][1];
669                                 
670                                 v3[0]= bezt->vec[0][0];
671                                 v3[1]= bezt->vec[0][1];
672                                 v4[0]= bezt->vec[1][0];
673                                 v4[1]= bezt->vec[1][1];
674                                 
675                                 correct_bezpart(v1, v2, v3, v4);
676                                 
677                                 forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, 3);
678                                 forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data+1, resol, 3);
679                                 
680                                 for (fp= data; resol; resol--, fp+= 3)
681                                         glVertex2fv(fp);
682                         }
683                 }
684                 
685                 /* get next pointers */
686                 prevbezt= bezt; 
687                 bezt++;
688                 
689                 /* last point? */
690                 if (b == 0) {
691                         v1[0]= prevbezt->vec[1][0];
692                         v1[1]= prevbezt->vec[1][1];
693                         glVertex2fv(v1);
694                 }
695         }
696         
697         /* extrapolate to right? (see code for left-extrapolation above too) */
698         if (prevbezt->vec[1][0] < v2d->cur.xmax) {
699                 v1[0]= v2d->cur.xmax;
700                 
701                 /* y-value depends on the interpolation */
702                 if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) {
703                         /* based on last keyframe's value */
704                         v1[1]= prevbezt->vec[1][1];
705                 } 
706                 else if (prevbezt->ipo==BEZT_IPO_LIN) {
707                         /* extrapolate linear dosnt use the handle, use the previous points center instead */
708                         bezt = prevbezt-1;
709                         fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
710                         if (fac) fac= 1.0f/fac;
711                         v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
712                 } 
713                 else {
714                         /* based on angle of handle 1 (relative to keyframe) */
715                         fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
716                         if (fac) fac= 1.0f/fac;
717                         v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]);
718                 }
719                 
720                 glVertex2fv(v1);
721         }
722         
723         glEnd();
724
725
726 /* Public Curve-Drawing API  ---------------- */
727
728 /* Draw the 'ghost' F-Curves (i.e. snapshots of the curve) */
729 void graph_draw_ghost_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid *grid)
730 {
731         FCurve *fcu;
732         
733         /* draw with thick dotted lines */
734         setlinestyle(10);
735         glLineWidth(3.0f);
736         
737         /* anti-aliased lines for less jagged appearance */
738         glEnable(GL_LINE_SMOOTH);
739         glEnable(GL_BLEND);
740         
741         /* the ghost curves are simply sampled F-Curves stored in sipo->ghostCurves */
742         for (fcu= sipo->ghostCurves.first; fcu; fcu= fcu->next) {
743                 /* set whatever color the curve has set 
744                  *      - this is set by the function which creates these
745                  *      - draw with a fixed opacity of 2
746                  */
747                 glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], 0.5f);
748                 
749                 /* simply draw the stored samples */
750                 draw_fcurve_curve_samples(fcu, &ar->v2d);
751         }
752         
753         /* restore settings */
754         setlinestyle(0);
755         glLineWidth(1.0f);
756         
757         glDisable(GL_LINE_SMOOTH);
758         glDisable(GL_BLEND);
759 }
760
761 /* This is called twice from space_graph.c -> graph_main_area_draw()
762  * Unselected then selected F-Curves are drawn so that they do not occlude each other.
763  */
764 void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid *grid, short sel)
765 {
766         ListBase anim_data = {NULL, NULL};
767         bAnimListElem *ale;
768         int filter;
769         
770         /* build list of curves to draw */
771         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY|ANIMFILTER_CURVEVISIBLE);
772         filter |= ((sel) ? (ANIMFILTER_SEL) : (ANIMFILTER_UNSEL));
773         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
774                 
775         /* for each curve:
776          *      draw curve, then handle-lines, and finally vertices in this order so that 
777          *      the data will be layered correctly
778          */
779         for (ale=anim_data.first; ale; ale=ale->next) {
780                 FCurve *fcu= (FCurve *)ale->key_data;
781                 FModifier *fcm= find_active_fmodifier(&fcu->modifiers);
782                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
783                 
784                 /* map keyframes for drawing if scaled F-Curve */
785                 if (adt)
786                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); 
787                 
788                 /* draw curve:
789                  *      - curve line may be result of one or more destructive modifiers or just the raw data,
790                  *        so we need to check which method should be used
791                  *      - controls from active modifier take precidence over keyframes
792                  *        (XXX! editing tools need to take this into account!)
793                  */
794                  
795                 /* 1) draw curve line */
796                 {
797                         /* set color/drawing style for curve itself */
798                         if ( ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || (fcu->flag & FCURVE_PROTECTED) ) {
799                                 /* protected curves (non editable) are drawn with dotted lines */
800                                 setlinestyle(2);
801                         }
802                         if (fcu->flag & FCURVE_MUTED) {
803                                 /* muted curves are drawn in a greyish hue */
804                                 // XXX should we have some variations?
805                                 UI_ThemeColorShade(TH_HEADER, 50);
806                         }
807                         else {
808                                 /* set whatever color the curve has set 
809                                  *      - unselected curves draw less opaque to help distinguish the selected ones
810                                  */
811                                 glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], ((sel) ? 1.0f : 0.5f));
812                         }
813                         
814                         /* anti-aliased lines for less jagged appearance */
815                         glEnable(GL_LINE_SMOOTH);
816                         glEnable(GL_BLEND);
817                         
818                         /* draw F-Curve */
819                         if ((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) {
820                                 /* draw a curve affected by modifiers or only allowed to have integer values 
821                                  * by sampling it at various small-intervals over the visible region 
822                                  */
823                                 draw_fcurve_curve(fcu, sipo, &ar->v2d, grid);
824                         }
825                         else if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { 
826                                 /* just draw curve based on defined data (i.e. no modifiers) */
827                                 if (fcu->bezt)
828                                         draw_fcurve_curve_bezts(fcu, &ar->v2d, grid);
829                                 else if (fcu->fpt)
830                                         draw_fcurve_curve_samples(fcu, &ar->v2d);
831                         }
832                         
833                         /* restore settings */
834                         setlinestyle(0);
835                         
836                         glDisable(GL_LINE_SMOOTH);
837                         glDisable(GL_BLEND);
838                 }
839                 
840                 /* 2) draw handles and vertices as appropriate based on active 
841                  *      - if the option to only show controls if the F-Curve is selected is enabled, we must obey this
842                  */
843                 if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) {
844                         if (fcurve_needs_draw_fmodifier_controls(fcu, fcm)) {
845                                 /* only draw controls if this is the active modifier */
846                                 if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) {
847                                         switch (fcm->type) {
848                                                 case FMODIFIER_TYPE_ENVELOPE: /* envelope */
849                                                         draw_fcurve_modifier_controls_envelope(fcu, fcm, &ar->v2d);
850                                                         break;
851                                         }
852                                 }
853                         }
854                         else if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { 
855                                 if (fcu->bezt) {
856                                         /* only draw handles/vertices on keyframes */
857                                         draw_fcurve_handles(sipo, ar, fcu);
858                                         draw_fcurve_vertices(sipo, ar, fcu);
859                                 }
860                                 else {
861                                         /* samples: should we only draw two indicators at either end as indicators? */
862                                         draw_fcurve_samples(sipo, ar, fcu);
863                                 }
864                         }
865                 }
866                 
867                 /* undo mapping of keyframes for drawing if scaled F-Curve */
868                 if (adt)
869                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); 
870         }
871         
872         /* free list of curves */
873         BLI_freelistN(&anim_data);
874 }
875
876 /* ************************************************************************* */
877 /* Channel List */
878
879 // XXX quite a few of these need to be kept in sync with their counterparts in Action Editor
880 // as they're the same. We have 2 separate copies of this for now to make it easier to develop
881 // the diffences between the two editors, but one day these should be merged!
882
883 /* left hand part */
884 void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) 
885 {
886         ListBase anim_data = {NULL, NULL};
887         bAnimListElem *ale;
888         int filter;
889         
890         View2D *v2d= &ar->v2d;
891         float x= 0.0f, y= 0.0f, height;
892         int items, i=0;
893         
894         /* build list of channels to draw */
895         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
896         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
897         
898         /* Update max-extent of channels here (taking into account scrollers):
899          *      - this is done to allow the channel list to be scrollable, but must be done here
900          *        to avoid regenerating the list again and/or also because channels list is drawn first
901          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
902          *        start of list offset, and the second is as a correction for the scrollers.
903          */
904         height= (float)((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
905         
906 #if 0
907         if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
908                 /* don't use totrect set, as the width stays the same 
909                  * (NOTE: this is ok here, the configuration is pretty straightforward) 
910                  */
911                 v2d->tot.ymin= (float)(-height);
912         }
913         
914         /* XXX I would call the below line! (ton) */
915 #endif
916         UI_view2d_totRect_set(v2d, ar->winx, height);
917         
918         /* loop through channels, and set up drawing depending on their type  */        
919         y= (float)ACHANNEL_FIRST;
920         
921         for (ale= anim_data.first, i=0; ale; ale= ale->next, i++) {
922                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
923                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
924                 
925                 /* check if visible */
926                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
927                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
928                 {
929                         bActionGroup *grp = NULL;
930                         short indent= 0, offset= 0, sel= 0, group= 0;
931                         int expand= -1, protect = -1, special= -1, mute = -1;
932                         char name[128];
933                         
934                         /* determine what needs to be drawn */
935                         switch (ale->type) {
936                                 case ANIMTYPE_SCENE: /* scene */
937                                 {
938                                         Scene *sce= (Scene *)ale->data;
939                                         
940                                         group= 4;
941                                         indent= 0;
942                                         
943                                         special= ICON_SCENE_DATA;
944                                         
945                                         /* only show expand if there are any channels */
946                                         if (EXPANDED_SCEC(sce))
947                                                 expand= ICON_TRIA_DOWN;
948                                         else
949                                                 expand= ICON_TRIA_RIGHT;
950                                         
951                                         sel = SEL_SCEC(sce);
952                                         strcpy(name, sce->id.name+2);
953                                 }
954                                         break;
955                                 case ANIMTYPE_OBJECT: /* object */
956                                 {
957                                         Base *base= (Base *)ale->data;
958                                         Object *ob= base->object;
959                                         
960                                         group= 4;
961                                         indent= 0;
962                                         
963                                         /* icon depends on object-type */
964                                         if (ob->type == OB_ARMATURE)
965                                                 special= ICON_ARMATURE_DATA;
966                                         else    
967                                                 special= ICON_OBJECT_DATA;
968                                                 
969                                         /* only show expand if there are any channels */
970                                         if (EXPANDED_OBJC(ob))
971                                                 expand= ICON_TRIA_DOWN;
972                                         else
973                                                 expand= ICON_TRIA_RIGHT;
974                                         
975                                         sel = SEL_OBJC(base);
976                                         strcpy(name, ob->id.name+2);
977                                 }
978                                         break;
979                                 case ANIMTYPE_FILLACTD: /* action widget */
980                                 {
981                                         bAction *act= (bAction *)ale->data;
982                                         
983                                         group = 4;
984                                         indent= 1;
985                                         special= ICON_ACTION;
986                                         
987                                         if (EXPANDED_ACTC(act))
988                                                 expand= ICON_TRIA_DOWN;
989                                         else
990                                                 expand= ICON_TRIA_RIGHT;
991                                         
992                                         sel = SEL_ACTC(act);
993                                         strcpy(name, act->id.name+2);
994                                 }
995                                         break;
996                                 case ANIMTYPE_FILLDRIVERS: /* drivers widget */
997                                 {
998                                         AnimData *adt= (AnimData *)ale->data;
999                                         
1000                                         group = 4;
1001                                         indent= 1;
1002                                         special= ICON_ANIM_DATA;
1003                                         
1004                                         if (EXPANDED_DRVD(adt))
1005                                                 expand= ICON_TRIA_DOWN;
1006                                         else
1007                                                 expand= ICON_TRIA_RIGHT;
1008                                         
1009                                         strcpy(name, "Drivers");
1010                                 }
1011                                         break;
1012                                 case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */
1013                                 {
1014                                         Object *ob = (Object *)ale->data;
1015                                         
1016                                         group = 4;
1017                                         indent = 1;
1018                                         special = ICON_MATERIAL_DATA;
1019                                         
1020                                         if (FILTER_MAT_OBJC(ob))
1021                                                 expand = ICON_TRIA_DOWN;
1022                                         else
1023                                                 expand = ICON_TRIA_RIGHT;
1024                                                 
1025                                         strcpy(name, "Materials");
1026                                 }
1027                                         break;
1028                                 case ANIMTYPE_FILLPARTD: /* object particles (dopesheet) expand widget */
1029                                 {
1030                                         Object *ob = (Object *)ale->data;
1031                                         
1032                                         group = 4;
1033                                         indent = 1;
1034                                         special = ICON_PARTICLE_DATA;
1035                                         
1036                                         if (FILTER_PART_OBJC(ob))
1037                                                 expand = ICON_TRIA_DOWN;
1038                                         else
1039                                                 expand = ICON_TRIA_RIGHT;
1040                                                 
1041                                         strcpy(name, "Particles");
1042                                 }
1043                                         break;
1044                                 
1045                                 
1046                                 case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */
1047                                 {
1048                                         Material *ma = (Material *)ale->data;
1049                                         
1050                                         group = 0;
1051                                         indent = 0;
1052                                         special = ICON_MATERIAL_DATA;
1053                                         offset = 21;
1054                                         
1055                                         if (FILTER_MAT_OBJD(ma))
1056                                                 expand = ICON_TRIA_DOWN;
1057                                         else
1058                                                 expand = ICON_TRIA_RIGHT;
1059                                         
1060                                         strcpy(name, ma->id.name+2);
1061                                 }
1062                                         break;
1063                                 case ANIMTYPE_DSLAM: /* lamp (dopesheet) expand widget */
1064                                 {
1065                                         Lamp *la = (Lamp *)ale->data;
1066                                         
1067                                         group = 4;
1068                                         indent = 1;
1069                                         special = ICON_LAMP_DATA;
1070                                         
1071                                         if (FILTER_LAM_OBJD(la))
1072                                                 expand = ICON_TRIA_DOWN;
1073                                         else
1074                                                 expand = ICON_TRIA_RIGHT;
1075                                         
1076                                         strcpy(name, la->id.name+2);
1077                                 }
1078                                         break;
1079                                 case ANIMTYPE_DSCAM: /* camera (dopesheet) expand widget */
1080                                 {
1081                                         Camera *ca = (Camera *)ale->data;
1082                                         
1083                                         group = 4;
1084                                         indent = 1;
1085                                         special = ICON_CAMERA_DATA;
1086                                         
1087                                         if (FILTER_CAM_OBJD(ca))
1088                                                 expand = ICON_TRIA_DOWN;
1089                                         else
1090                                                 expand = ICON_TRIA_RIGHT;
1091                                         
1092                                         strcpy(name, ca->id.name+2);
1093                                 }
1094                                         break;
1095                                 case ANIMTYPE_DSCUR: /* curve (dopesheet) expand widget */
1096                                 {
1097                                         Curve *cu = (Curve *)ale->data;
1098                                         
1099                                         group = 4;
1100                                         indent = 1;
1101                                         special = ICON_CURVE_DATA;
1102                                         
1103                                         if (FILTER_CUR_OBJD(cu))
1104                                                 expand = ICON_TRIA_DOWN;
1105                                         else
1106                                                 expand = ICON_TRIA_RIGHT;
1107                                         
1108                                         strcpy(name, cu->id.name+2);
1109                                 }
1110                                         break;
1111                                 case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */
1112                                 {
1113                                         Key *key= (Key *)ale->data;
1114                                         
1115                                         group = 4;
1116                                         indent = 1;
1117                                         special = ICON_SHAPEKEY_DATA;
1118                                         
1119                                         if (FILTER_SKE_OBJD(key))       
1120                                                 expand = ICON_TRIA_DOWN;
1121                                         else
1122                                                 expand = ICON_TRIA_RIGHT;
1123                                                 
1124                                         //sel = SEL_OBJC(base);
1125                                         strcpy(name, "Shape Keys");
1126                                 }
1127                                         break;
1128                                 case ANIMTYPE_DSWOR: /* world (dopesheet) expand widget */
1129                                 {
1130                                         World *wo= (World *)ale->data;
1131                                         
1132                                         group = 4;
1133                                         indent = 1;
1134                                         special = ICON_WORLD_DATA;
1135                                         
1136                                         if (FILTER_WOR_SCED(wo))        
1137                                                 expand = ICON_TRIA_DOWN;
1138                                         else
1139                                                 expand = ICON_TRIA_RIGHT;
1140                                         
1141                                         strcpy(name, wo->id.name+2);
1142                                 }
1143                                         break;
1144                                 case ANIMTYPE_DSPART: /* particle (dopesheet) expand widget */
1145                                 {
1146                                         ParticleSettings *part= (ParticleSettings*)ale->data;
1147                                         
1148                                         group = 0;
1149                                         indent = 0;
1150                                         special = ICON_PARTICLE_DATA;
1151                                         offset = 21;
1152                                         
1153                                         if (FILTER_PART_OBJD(part))     
1154                                                 expand = ICON_TRIA_DOWN;
1155                                         else
1156                                                 expand = ICON_TRIA_RIGHT;
1157                                         
1158                                         strcpy(name, part->id.name+2);
1159                                 }
1160                                         break;
1161                                 
1162                                 
1163                                 case ANIMTYPE_GROUP: /* action group */
1164                                 {
1165                                         bActionGroup *agrp= (bActionGroup *)ale->data;
1166                                         
1167                                         group= 2;
1168                                         indent= 0;
1169                                         special= -1;
1170                                         
1171                                         if (ale->id) {
1172                                                 /* special exception for materials */
1173                                                 if (GS(ale->id->name) == ID_MA) 
1174                                                         offset= 25;
1175                                                 else
1176                                                         offset= 14;
1177                                         }
1178                                         else
1179                                                 offset= 0;
1180                                         
1181                                         /* only show expand if there are any channels */
1182                                         if (agrp->channels.first) {
1183                                                 if (EXPANDED_AGRP(agrp))
1184                                                         expand = ICON_TRIA_DOWN;
1185                                                 else
1186                                                         expand = ICON_TRIA_RIGHT;
1187                                         }
1188                                         
1189                                         /* for now, 'special' (i.e. in front of name) is used to show visibility status */
1190                                         if (agrp->flag & AGRP_NOTVISIBLE)
1191                                                 special= ICON_CHECKBOX_DEHLT;
1192                                         else
1193                                                 special= ICON_CHECKBOX_HLT;
1194                                         
1195                                         if (agrp->flag & AGRP_MUTED)
1196                                                 mute = ICON_MUTE_IPO_ON;
1197                                         else    
1198                                                 mute = ICON_MUTE_IPO_OFF;
1199                                         
1200                                         if (EDITABLE_AGRP(agrp))
1201                                                 protect = ICON_UNLOCKED;
1202                                         else
1203                                                 protect = ICON_LOCKED;
1204                                                 
1205                                         sel = SEL_AGRP(agrp);
1206                                         strcpy(name, agrp->name);
1207                                 }
1208                                         break;
1209                                 case ANIMTYPE_FCURVE: /* F-Curve channel */
1210                                 {
1211                                         FCurve *fcu = (FCurve *)ale->data;
1212                                         
1213                                         indent = 0;
1214                                         
1215                                         group= (fcu->grp) ? 1 : 0;
1216                                         grp= fcu->grp;
1217                                         
1218                                         if (ale->id) {
1219                                                 /* special exception for materials and particles */
1220                                                 if (ELEM(GS(ale->id->name),ID_MA,ID_PA)) {
1221                                                         offset= 21;
1222                                                         indent= 1;
1223                                                 }
1224                                                 else
1225                                                         offset= 14;
1226                                         }
1227                                         else
1228                                                 offset= 0;
1229                                         
1230                                         /* for now, 'special' (i.e. in front of name) is used to show visibility status */
1231                                         if (fcu->flag & FCURVE_VISIBLE)
1232                                                 special= ICON_CHECKBOX_HLT;
1233                                         else
1234                                                 special= ICON_CHECKBOX_DEHLT;
1235                                         
1236                                         if (fcu->flag & FCURVE_MUTED)
1237                                                 mute = ICON_MUTE_IPO_ON;
1238                                         else    
1239                                                 mute = ICON_MUTE_IPO_OFF;
1240                                                 
1241                                         if (fcu->bezt) {
1242                                                 if (EDITABLE_FCU(fcu))
1243                                                         protect = ICON_UNLOCKED;
1244                                                 else
1245                                                         protect = ICON_LOCKED;
1246                                         }
1247                                         else
1248                                                 protect = ICON_ZOOMOUT; // XXX editability is irrelevant here, but this icon is temp...
1249                                         
1250                                         sel = SEL_FCU(fcu);
1251                                         
1252                                         getname_anim_fcurve(name, ale->id, fcu);
1253                                 }
1254                                         break;
1255                                         
1256                                 case ANIMTYPE_SHAPEKEY: /* shapekey channel */
1257                                 {
1258                                         KeyBlock *kb = (KeyBlock *)ale->data;
1259                                         
1260                                         indent = 0;
1261                                         special = -1;
1262                                         
1263                                         offset= (ale->id) ? 21 : 0;
1264                                         
1265                                         if (kb->name[0] == '\0')
1266                                                 sprintf(name, "Key %d", ale->index);
1267                                         else
1268                                                 strcpy(name, kb->name);
1269                                 }
1270                                         break;
1271                         }       
1272                         
1273                         /* now, start drawing based on this information */
1274                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1275                         glEnable(GL_BLEND);
1276                         
1277                         /* draw backing strip behind channel name */
1278                         if (group == 4) {
1279                                 /* only used in dopesheet... */
1280                                 if (ELEM(ale->type, ANIMTYPE_SCENE, ANIMTYPE_OBJECT)) {
1281                                         /* object channel - darker */
1282                                         UI_ThemeColor(TH_DOPESHEET_CHANNELOB);
1283                                         uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1284                                         gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1285                                 }
1286                                 else {
1287                                         /* sub-object folders - lighter */
1288                                         UI_ThemeColor(TH_DOPESHEET_CHANNELSUBOB);
1289                                         
1290                                         offset += 7 * indent;
1291                                         glBegin(GL_QUADS);
1292                                                 glVertex2f(x+offset, yminc);
1293                                                 glVertex2f(x+offset, ymaxc);
1294                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
1295                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
1296                                         glEnd();
1297                                         
1298                                         /* clear group value, otherwise we cause errors... */
1299                                         group = 0;
1300                                 }
1301                         }
1302                         else if (group == 3) {
1303                                 /* only for gp-data channels */
1304                                 UI_ThemeColorShade(TH_GROUP, 20);
1305                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1306                                 gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1307                         }
1308                         else if (group == 2) {
1309                                 /* only for action group channels */
1310                                 if (ale->flag & AGRP_ACTIVE)
1311                                         UI_ThemeColorShade(TH_GROUP_ACTIVE, 10);
1312                                 else
1313                                         UI_ThemeColorShade(TH_GROUP, 20);
1314                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1315                                 gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1316                         }
1317                         else {
1318                                 short shadefac= ((indent==0)?20: (indent==1)?-20: -40);
1319                                 
1320                                 indent += group;
1321                                 offset += 7 * indent;
1322                                 
1323                                 /* draw channel backdrop */
1324                                 UI_ThemeColorShade(TH_HEADER, shadefac);
1325                                 
1326                                 glBegin(GL_QUADS);
1327                                         glVertex2f(x+offset, yminc);
1328                                         glVertex2f(x+offset, ymaxc);
1329                                         glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
1330                                         glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
1331                                 glEnd();
1332                                 
1333                                 /* most of the time, only F-Curves are going to be drawn here */
1334                                 if (ale->type == ANIMTYPE_FCURVE) {
1335                                         /* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever 
1336                                          * color the curve has stored 
1337                                          */
1338                                         FCurve *fcu= (FCurve *)ale->data;
1339                                         glColor3fv(fcu->color);
1340                                         
1341                                         // NOTE: only enable the following line for the fading-out gradient
1342                                         //glShadeModel(GL_SMOOTH);
1343                                         
1344                                         glBegin(GL_QUADS);
1345                                                 /* solid color for the area around the checkbox */
1346                                                 glVertex2f(x+offset, yminc);
1347                                                 glVertex2f(x+offset, ymaxc);
1348                                                 glVertex2f(x+offset+18, ymaxc);
1349                                                 glVertex2f(x+offset+18, yminc);
1350                                                 
1351 #if 0 // fading out gradient
1352                                                 /* fading out gradient for the rest of the box */
1353                                                 glVertex2f(x+offset+18, yminc);
1354                                                 glVertex2f(x+offset+18, ymaxc);
1355                                                 
1356                                                 UI_ThemeColorShade(TH_HEADER, shadefac); // XXX does this cause any problems on some cards?
1357                                                 
1358                                                 glVertex2f(x+offset+20, ymaxc);
1359                                                 glVertex2f(x+offset+20, yminc);
1360 #endif // fading out gradient
1361                                         glEnd();
1362                                         
1363                                         // NOTE: only enable the following line for the fading-out gradient
1364                                         //glShadeModel(GL_FLAT);
1365                                 }
1366                         }
1367                         
1368                         /* draw expand/collapse triangle */
1369                         if (expand > 0) {
1370                                 UI_icon_draw(x+offset, yminc, expand);
1371                                 offset += 17;
1372                         }
1373                         
1374                         /* draw special icon indicating certain data-types */
1375                         if (special > -1) {
1376                                 if (ELEM(group, 3, 4)) {
1377                                         /* for gpdatablock channels */
1378                                         UI_icon_draw(x+offset, yminc, special);
1379                                         offset += 17;
1380                                 }
1381                                 else {
1382                                         /* for normal channels */
1383                                         UI_icon_draw(x+offset, yminc, special);
1384                                         offset += 17;
1385                                 }
1386                         }
1387                         glDisable(GL_BLEND);
1388                         
1389                         /* draw name */
1390                         if (sel)
1391                                 UI_ThemeColor(TH_TEXT_HI);
1392                         else
1393                                 UI_ThemeColor(TH_TEXT);
1394                         offset += 3;
1395                         UI_DrawString(x+offset, y-4, name);
1396                         
1397                         /* reset offset - for RHS of panel */
1398                         offset = 0;
1399                         
1400                         /* set blending again, as text drawing may clear it */
1401                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1402                         glEnable(GL_BLEND);
1403                         
1404                         /* draw protect 'lock' */
1405                         if (protect > -1) {
1406                                 offset = 16;
1407                                 UI_icon_draw((float)ACHANNEL_NAMEWIDTH-offset, yminc, protect);
1408                         }
1409                         
1410                         /* draw mute 'eye' */
1411                         if (mute > -1) {
1412                                 offset += 16;
1413                                 UI_icon_draw((float)(ACHANNEL_NAMEWIDTH-offset), yminc, mute);
1414                         }
1415                         glDisable(GL_BLEND);
1416                 }
1417                 
1418                 /* adjust y-position for next one */
1419                 y -= ACHANNEL_STEP;
1420         }
1421         
1422         /* free tempolary channels */
1423         BLI_freelistN(&anim_data);
1424 }