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