Graph Editor: Experimental variations of curve display
[blender.git] / source / blender / editors / space_graph / graph_draw.c
1 /**
2  * $Id: drawipo.c 17512 2008-11-20 05:55:42Z aligorith $
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
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #ifndef _WIN32
36 #include <unistd.h>
37 #else
38 #include <io.h>
39 #endif
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_arithb.h"
45
46 #include "DNA_anim_types.h"
47 #include "DNA_action_types.h"
48 #include "DNA_camera_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_key_types.h"
51 #include "DNA_lamp_types.h"
52 #include "DNA_material_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_scene_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_sequence_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view2d_types.h"
60 #include "DNA_windowmanager_types.h"
61
62 #include "BKE_animsys.h"
63 #include "BKE_context.h"
64 #include "BKE_curve.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_fcurve.h"
67 #include "BKE_global.h"
68 #include "BKE_key.h"
69 #include "BKE_object.h"
70 #include "BKE_screen.h"
71 #include "BKE_utildefines.h"
72
73 #include "BIF_gl.h"
74 #include "BIF_glutil.h"
75
76 #include "ED_anim_api.h"
77 #include "ED_util.h"
78
79 #include "graph_intern.h"
80
81 #include "UI_interface.h"
82 #include "UI_interface_icons.h"
83 #include "UI_resources.h"
84 #include "UI_view2d.h"
85 #include "UI_text.h"
86
87 /* XXX */
88 extern void ui_rasterpos_safe(float x, float y, float aspect);
89 extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad);
90
91 /* *************************** */
92 /* Curve Drawing */
93
94 /* Points ---------------- */
95
96 /* helper func - draw keyframe vertices only for an F-Curve */
97 static void draw_fcurve_vertices_keyframes (FCurve *fcu, View2D *v2d, short edit, short sel)
98 {
99         BezTriple *bezt= fcu->bezt;
100         const float fac= 0.05f * (v2d->cur.xmax - v2d->cur.xmin);
101         int i;
102         
103         /* we use bgl points not standard gl points, to workaround vertex 
104          * drawing bugs that some drivers have (probably legacy ones only though)
105          */
106         bglBegin(GL_POINTS);
107         
108         for (i = 0; i < fcu->totvert; i++, bezt++) {
109                 /* as an optimisation step, only draw those in view 
110                  *      - we apply a correction factor to ensure that points don't pop in/out due to slight twitches of view size
111                  */
112                 if IN_RANGE(bezt->vec[1][0], (v2d->cur.xmin - fac), (v2d->cur.xmax + fac)) {
113                         if (edit) {
114                                 /* 'Keyframe' vertex only, as handle lines and handles have already been drawn
115                                  *      - only draw those with correct selection state for the current drawing color
116                                  *      - 
117                                  */
118                                 if ((bezt->f2 & SELECT) == sel)
119                                         bglVertex3fv(bezt->vec[1]);
120                         }
121                         else {
122                                 /* no check for selection here, as curve is not editable... */
123                                 // XXX perhaps we don't want to even draw points?   maybe add an option for that later
124                                 bglVertex3fv(bezt->vec[1]);
125                         }
126                 }
127         }
128         
129         bglEnd();
130 }
131
132
133 /* helper func - draw handle vertex for an F-Curve as a round unfilled circle */
134 static void draw_fcurve_handle_control (float x, float y, float xscale, float yscale, float hsize)
135 {
136         static GLuint displist=0;
137         
138         /* initialise round circle shape */
139         if (displist == 0) {
140                 GLUquadricObj *qobj;
141                 
142                 displist= glGenLists(1);
143                 glNewList(displist, GL_COMPILE);
144                 
145                 qobj    = gluNewQuadric(); 
146                 gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
147                 gluDisk(qobj, 0,  0.7, 8, 1);
148                 gluDeleteQuadric(qobj);  
149                 
150                 glEndList();
151         }
152         
153         /* adjust view transform before starting */
154         glTranslatef(x, y, 0.0f);
155         glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f);
156         
157         /* anti-aliased lines for more consistent appearance */
158         glEnable(GL_LINE_SMOOTH);
159         glEnable(GL_BLEND);
160         
161         /* draw! */
162         glCallList(displist);
163         
164         glDisable(GL_LINE_SMOOTH);
165         glDisable(GL_BLEND);
166         
167         /* restore view transform */
168         glScalef(xscale/hsize, yscale/hsize, 1.0);
169         glTranslatef(-x, -y, 0.0f);
170 }
171
172 /* helper func - draw handle vertices only for an F-Curve (if it is not protected) */
173 static void draw_fcurve_vertices_handles (FCurve *fcu, View2D *v2d, short sel)
174 {
175         BezTriple *bezt= fcu->bezt;
176         BezTriple *prevbezt = NULL;
177         float hsize, xscale, yscale;
178         int i;
179         
180         /* get view settings */
181         hsize= UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE);
182         UI_view2d_getscale(v2d, &xscale, &yscale);
183         
184         /* set handle color */
185         if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
186         else UI_ThemeColor(TH_HANDLE_VERTEX);
187         
188         for (i=0; i < fcu->totvert; i++, prevbezt=bezt, bezt++) {
189                 /* Draw the editmode handels for a bezier curve (others don't have handles) 
190                  * if their selection status matches the selection status we're drawing for
191                  *      - first handle only if previous beztriple was bezier-mode
192                  *      - second handle only if current beztriple is bezier-mode
193                  */
194                 if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) {
195                         if ((bezt->f1 & SELECT) == sel)/* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/
196                                 draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize);
197                 }
198                 
199                 if (bezt->ipo==BEZT_IPO_BEZ) {
200                         if ((bezt->f3 & SELECT) == sel)/* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/
201                                 draw_fcurve_handle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize);
202                 }
203         }
204 }
205
206 /* helper func - set color to draw F-Curve data with */
207 static void set_fcurve_vertex_color (SpaceIpo *sipo, FCurve *fcu, short sel)
208 {
209 #if 0
210                 if (sipo->showkey) {
211                         if (sel) UI_ThemeColor(TH_TEXT_HI);
212                         else UI_ThemeColor(TH_TEXT);
213                 } 
214 #endif
215                 if ((fcu->flag & FCURVE_PROTECTED)==0) {
216                         /* Curve's points are being edited */
217                         if (sel) UI_ThemeColor(TH_VERTEX_SELECT); 
218                         else UI_ThemeColor(TH_VERTEX);
219                 } 
220                 else {
221                         /* Curve's points cannot be edited */
222                         if (sel) UI_ThemeColor(TH_TEXT_HI);
223                         else UI_ThemeColor(TH_TEXT);
224                 }
225 }
226
227
228 void draw_fcurve_vertices (SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
229 {
230         View2D *v2d= &ar->v2d;
231         
232         /* only draw points if curve is visible 
233          *      - draw unselected points before selected points as separate passes to minimise color-changing overhead
234          *         (XXX dunno if this is faster than drawing all in one pass though) 
235          *         and also to make sure in the case of overlapping points that the selected is always visible
236          *      - draw handles before keyframes, so that keyframes will overlap handles (keyframes are more important for users)
237          */
238         
239         glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
240         
241         /* draw the two handles first (if they're shown, and if curve is being edited) */
242         if ((fcu->flag & FCURVE_PROTECTED)==0 && (sipo->flag & SIPO_NOHANDLES)==0) {
243                 set_fcurve_vertex_color(sipo, fcu, 0);
244                 draw_fcurve_vertices_handles(fcu, v2d, 0);
245                 
246                 set_fcurve_vertex_color(sipo, fcu, 1);
247                 draw_fcurve_vertices_handles(fcu, v2d, 1);
248         }
249                 
250         /* draw keyframes over the handles */
251         set_fcurve_vertex_color(sipo, fcu, 0);
252         draw_fcurve_vertices_keyframes(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), 0);
253         
254         set_fcurve_vertex_color(sipo, fcu, 1);
255         draw_fcurve_vertices_keyframes(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), 1);
256         
257         glPointSize(1.0f);
258 }
259
260 /* Handles ---------------- */
261
262 /* draw lines for F-Curve handles only (this is only done in EditMode) */
263 static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
264 {
265         extern unsigned int nurbcol[];
266         unsigned int *col;
267         int sel, b;
268         
269         /* don't draw handle lines if handles are not shown */
270         if ((sipo->flag & SIPO_NOHANDLES) || (fcu->flag & FCURVE_PROTECTED))
271                 return;
272         
273         /* slightly hacky, but we want to draw unselected points before selected ones*/
274         for (sel= 0; sel < 2; sel++) {
275                 BezTriple *bezt=fcu->bezt, *prevbezt=NULL;
276                 float *fp;
277                 
278                 if (sel) col= nurbcol+4;
279                 else col= nurbcol;
280                         
281                 for (b= 0; b < fcu->totvert; b++, prevbezt=bezt, bezt++) {
282                         if ((bezt->f2 & SELECT)==sel) {
283                                 fp= bezt->vec[0];
284                                 
285                                 /* only draw first handle if previous segment had handles */
286                                 if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) 
287                                 {
288                                         cpack(col[(unsigned char)bezt->h1]);
289                                         glBegin(GL_LINE_STRIP); 
290                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
291                                         glEnd();
292                                         
293                                 }
294                                 
295                                 /* only draw second handle if this segment is bezier */
296                                 if (bezt->ipo == BEZT_IPO_BEZ) 
297                                 {
298                                         cpack(col[(unsigned char)bezt->h2]);
299                                         glBegin(GL_LINE_STRIP); 
300                                                 glVertex2fv(fp+3); glVertex2fv(fp+6); 
301                                         glEnd();
302                                 }
303                         }
304                         else {
305                                 /* only draw first handle if previous segment was had handles, and selection is ok */
306                                 if ( ((bezt->f1 & SELECT)==sel) && 
307                                          ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) ) 
308                                 {
309                                         fp= bezt->vec[0];
310                                         cpack(col[(unsigned char)bezt->h1]);
311                                         
312                                         glBegin(GL_LINE_STRIP); 
313                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
314                                         glEnd();
315                                 }
316                                 
317                                 /* only draw second handle if this segment is bezier, and selection is ok */
318                                 if ( ((bezt->f3 & SELECT)==sel) &&
319                                          (bezt->ipo == BEZT_IPO_BEZ) )
320                                 {
321                                         fp= bezt->vec[1];
322                                         cpack(col[(unsigned char)bezt->h2]);
323                                         
324                                         glBegin(GL_LINE_STRIP); 
325                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
326                                         glEnd();
327                                 }
328                         }
329                 }
330         }
331 }
332
333 /* Samples ---------------- */
334
335 /* helper func - draw sample-range marker for an F-Curve as a cross */
336 static void draw_fcurve_sample_control (float x, float y, float xscale, float yscale, float hsize)
337 {
338         static GLuint displist=0;
339         
340         /* initialise X shape */
341         if (displist == 0) {
342                 displist= glGenLists(1);
343                 glNewList(displist, GL_COMPILE);
344                 
345                 glBegin(GL_LINES);
346                         glVertex2f(-0.7f, -0.7f);
347                         glVertex2f(+0.7f, +0.7f);
348                         
349                         glVertex2f(-0.7f, +0.7f);
350                         glVertex2f(+0.7f, -0.7f);
351                 glEnd(); // GL_LINES
352                 
353                 glEndList();
354         }
355         
356         /* adjust view transform before starting */
357         glTranslatef(x, y, 0.0f);
358         glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f);
359         
360         /* anti-aliased lines for more consistent appearance */
361                 // XXX needed here?
362         glEnable(GL_LINE_SMOOTH);
363         glEnable(GL_BLEND);
364         
365         /* draw! */
366         glCallList(displist);
367         
368         glDisable(GL_BLEND);
369         glDisable(GL_LINE_SMOOTH);
370         
371         /* restore view transform */
372         glScalef(xscale/hsize, yscale/hsize, 1.0);
373         glTranslatef(-x, -y, 0.0f);
374 }
375
376 /* helper func - draw keyframe vertices only for an F-Curve */
377 static void draw_fcurve_samples (SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
378 {
379         FPoint *first, *last;
380         float hsize, xscale, yscale;
381         
382         /* get view settings */
383         hsize= UI_GetThemeValuef(TH_VERTEX_SIZE);
384         UI_view2d_getscale(&ar->v2d, &xscale, &yscale);
385         
386         /* set vertex color */
387         if (fcu->flag & (FCURVE_ACTIVE|FCURVE_SELECTED)) UI_ThemeColor(TH_TEXT_HI);
388         else UI_ThemeColor(TH_TEXT);
389         
390         /* get verts */
391         first= fcu->fpt;
392         last= (first) ? (first + fcu->totvert) : (NULL);
393         
394         /* draw */
395         if (first && last) {
396                 draw_fcurve_sample_control(first->vec[0], first->vec[1], xscale, yscale, hsize);
397                 draw_fcurve_sample_control(last->vec[0], last->vec[1], xscale, yscale, hsize);
398         }
399 }
400
401 /* Curve ---------------- */
402
403 /* helper func - draw one repeat of an F-Curve */
404 static void draw_fcurve_repeat (FCurve *fcu, View2D *v2d, float cycxofs, float cycyofs, float *facp)
405 {
406         BezTriple *prevbezt= fcu->bezt;
407         BezTriple *bezt= prevbezt+1;
408         float v1[2], v2[2], v3[2], v4[2];
409         float *fp, data[120];
410         float fac= *(facp);
411         int b= fcu->totvert-1;
412         int resol;
413         
414         glBegin(GL_LINE_STRIP);
415         
416         /* extrapolate to left? */
417         if ( (fcu->modifiers.first == NULL)/* || ( ((FModifier *)fcu->modifiers.first)->type != FMODIFIER_TYPE_CYCLES) */) {
418                 /* left-side of view comes before first keyframe, so need to extend as not cyclic */
419                 if (prevbezt->vec[1][0] > v2d->cur.xmin) {
420                         v1[0]= v2d->cur.xmin;
421                         
422                         /* y-value depends on the interpolation */
423                         if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) {
424                                 /* just extend across the first keyframe's value */
425                                 v1[1]= prevbezt->vec[1][1];
426                         } 
427                         else if (prevbezt->ipo==BEZT_IPO_LIN) {
428                                 /* extrapolate linear dosnt use the handle, use the next points center instead */
429                                 fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
430                                 if (fac) fac= 1.0f/fac;
431                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
432                         } 
433                         else {
434                                 /* based on angle of handle 1 (relative to keyframe) */
435                                 fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
436                                 if (fac) fac= 1.0f/fac;
437                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]);
438                         }
439                         
440                         glVertex2fv(v1);
441                 }
442         }
443         
444         /* if only one keyframe, add it now */
445         if (fcu->totvert == 1) {
446                 v1[0]= prevbezt->vec[1][0] + cycxofs;
447                 v1[1]= prevbezt->vec[1][1] + cycyofs;
448                 glVertex2fv(v1);
449         }
450         
451         /* draw curve between first and last keyframe (if there are enough to do so) */
452         // XXX this doesn't take into account modifiers, or sample data
453         while (b--) {
454                 if (prevbezt->ipo==BEZT_IPO_CONST) {
455                         /* Constant-Interpolation: draw segment between previous keyframe and next, but holding same value */
456                         v1[0]= prevbezt->vec[1][0]+cycxofs;
457                         v1[1]= prevbezt->vec[1][1]+cycyofs;
458                         glVertex2fv(v1);
459                         
460                         v1[0]= bezt->vec[1][0]+cycxofs;
461                         v1[1]= prevbezt->vec[1][1]+cycyofs;
462                         glVertex2fv(v1);
463                 }
464                 else if (prevbezt->ipo==BEZT_IPO_LIN) {
465                         /* Linear interpolation: just add one point (which should add a new line segment) */
466                         v1[0]= prevbezt->vec[1][0]+cycxofs;
467                         v1[1]= prevbezt->vec[1][1]+cycyofs;
468                         glVertex2fv(v1);
469                 }
470                 else {
471                         /* Bezier-Interpolation: draw curve as series of segments between keyframes 
472                          *      - resol determines number of points to sample in between keyframes
473                          */
474                         
475                         /* resol not depending on horizontal resolution anymore, drivers for example... */
476                         // XXX need to take into account the scale
477                         if (fcu->driver) 
478                                 resol= 32;
479                         else 
480                                 resol= (int)(3.0*sqrt(bezt->vec[1][0] - prevbezt->vec[1][0]));
481                         
482                         if (resol < 2) {
483                                 /* only draw one */
484                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
485                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
486                                 glVertex2fv(v1);
487                         }
488                         else {
489                                 /* clamp resolution to max of 32 */
490                                 if (resol > 32) resol= 32;
491                                 
492                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
493                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
494                                 v2[0]= prevbezt->vec[2][0]+cycxofs;
495                                 v2[1]= prevbezt->vec[2][1]+cycyofs;
496                                 
497                                 v3[0]= bezt->vec[0][0]+cycxofs;
498                                 v3[1]= bezt->vec[0][1]+cycyofs;
499                                 v4[0]= bezt->vec[1][0]+cycxofs;
500                                 v4[1]= bezt->vec[1][1]+cycyofs;
501                                 
502                                 correct_bezpart(v1, v2, v3, v4);
503                                 
504                                 forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, 3);
505                                 forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data+1, resol, 3);
506                                 
507                                 for (fp= data; resol; resol--, fp+= 3)
508                                         glVertex2fv(fp);
509                         }
510                 }
511                 
512                 /* get next pointers */
513                 prevbezt= bezt; 
514                 bezt++;
515                 
516                 /* last point? */
517                 if (b == 0) {
518                         v1[0]= prevbezt->vec[1][0]+cycxofs;
519                         v1[1]= prevbezt->vec[1][1]+cycyofs;
520                         glVertex2fv(v1);
521                 }
522         }
523         
524         /* extrapolate to right? (see code for left-extrapolation above too) */
525         if ( (fcu->modifiers.first == NULL)/* || ( ((FModifier *)fcu->modifiers.first)->type != FMODIFIER_TYPE_CYCLES) */) {
526                 if (prevbezt->vec[1][0] < v2d->cur.xmax) {
527                         v1[0]= v2d->cur.xmax;
528                         
529                         /* y-value depends on the interpolation */
530                         if ((fcu->extend==FCURVE_EXTRAPOLATE_CONSTANT) || (prevbezt->ipo==BEZT_IPO_CONST) || (fcu->totvert==1)) {
531                                 /* based on last keyframe's value */
532                                 v1[1]= prevbezt->vec[1][1];
533                         } 
534                         else if (prevbezt->ipo==BEZT_IPO_LIN) {
535                                 /* extrapolate linear dosnt use the handle, use the previous points center instead */
536                                 bezt = prevbezt-1;
537                                 fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
538                                 if (fac) fac= 1.0f/fac;
539                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
540                         } 
541                         else {
542                                 /* based on angle of handle 1 (relative to keyframe) */
543                                 fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
544                                 if (fac) fac= 1.0f/fac;
545                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]);
546                         }
547                         
548                         glVertex2fv(v1);
549                 }
550         }
551         
552         glEnd();
553         
554         /* return fac, as we alter it */
555         *(facp) = fac;
556
557
558 #if 0 // XXX old animation system unconverted code!
559
560 /* draw all ipo-curves */
561 static void draw_ipocurves(SpaceIpo *sipo, ARegion *ar, int sel)
562 {
563         View2D *v2d= &ar->v2d;
564         EditIpo *ei;
565         int nr, val/*, pickselcode=0*/;
566         
567         /* if we're drawing for GL_SELECT, reset pickselcode first 
568          *      - there's only one place that will do this, so it should be fine
569          */
570         //if (G.f & G_PICKSEL)
571         //      pickselcode= 1;
572         
573         ei= sipo->editipo;
574         for (nr=0; nr<sipo->totipo; nr++, ei++) {
575                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
576                         /* val is used to indicate if curve can be edited */
577                         //if (G.f & G_PICKSEL) {
578                         //      /* when using OpenGL to select stuff (on mouseclick) */
579                         //      glLoadName(pickselcode++);
580                         //      val= 1;
581                         //}
582                         //else {
583                                 /* filter to only draw those that are selected or unselected (based on drawing mode */
584                                 val= (ei->flag & (IPO_SELECT+IPO_EDIT)) != 0;
585                                 val= (val==sel);
586                         //}
587                         
588                         /* only draw those curves that we can draw */
589                         if (val) {
590                                 IpoCurve *icu= ei->icu;
591                                 float cycdx=0.0f, cycdy=0.0f, cycxofs=0.0f, cycyofs=0.0f;
592                                 const int lastindex= (icu->totvert-1);
593                                 float fac= 0.0f;
594                                 int cycount=1;
595                                 
596                                 /* set color for curve curve:
597                                  *      - bitflag curves (evil) must always be drawn coloured as they cannot work with IPO-Keys
598                                  *      - when IPO-Keys are shown, individual curves are not editable, so we show by drawing them all black
599                                  */
600                                 if ((sipo->showkey) && (ei->disptype!=IPO_DISPBITS)) UI_ThemeColor(TH_TEXT); 
601                                 else cpack(ei->col);
602                                 
603                                 /* cyclic curves - get offset and number of repeats to display */
604                                 if (icu->extrap & IPO_CYCL) {
605                                         BezTriple *bezt= icu->bezt;
606                                         BezTriple *lastbezt= bezt + lastindex;
607                                         
608                                         /* calculate cycle length and amplitude  */
609                                         cycdx= lastbezt->vec[1][0] - bezt->vec[1][0];
610                                         cycdy= lastbezt->vec[1][1] - bezt->vec[1][1];
611                                         
612                                         /* check that the cycle does have some length */
613                                         if (cycdx > 0.01f) {
614                                                 /* count cycles before first frame  */
615                                                 while (icu->bezt->vec[1][0]+cycxofs > v2d->cur.xmin) {
616                                                         cycxofs -= cycdx;
617                                                         if (icu->extrap & IPO_DIR) cycyofs-= cycdy;
618                                                         cycount++;
619                                                 }
620                                                 
621                                                 /* count cycles after last frame (and adjust offset) */
622                                                 fac= 0.0f;
623                                                 while (lastbezt->vec[1][0]+fac < v2d->cur.xmax) {
624                                                         cycount++;
625                                                         fac += cycdx;
626                                                 }
627                                         }
628                                 }
629                                 
630                                 /* repeat process for each repeat */
631                                 while (cycount--) {
632                                         /* bitflag curves are drawn differently to normal curves */
633                                         if (ei->disptype==IPO_DISPBITS)
634                                                 draw_ipocurve_repeat_bits(icu, v2d, cycxofs);
635                                         else
636                                                 draw_ipocurve_repeat_normal(icu, v2d, cycxofs, cycyofs, &fac);
637                                         
638                                         /* prepare for next cycle by adjusing offsets */
639                                         cycxofs += cycdx;
640                                         if (icu->extrap & IPO_DIR) cycyofs += cycdy;
641                                 }
642                                 
643                                 /* vertical line that indicates the end of a speed curve */
644                                 if ((sipo->blocktype==ID_CU) && (icu->adrcode==CU_SPEED)) {
645                                         int b= icu->totvert-1;
646                                         
647                                         if (b) {
648                                                 BezTriple *bezt= icu->bezt+b;
649                                                 
650                                                 glColor3ub(0, 0, 0);
651                                                 
652                                                 glBegin(GL_LINES);
653                                                         glVertex2f(bezt->vec[1][0], 0.0f);
654                                                         glVertex2f(bezt->vec[1][0], bezt->vec[1][1]);
655                                                 glEnd();
656                                         }
657                                 }
658                         }
659                 }
660         }
661 }
662 #endif // XXX old animation system unconverted code
663
664 #if 0
665 static void draw_ipokey(SpaceIpo *sipo, ARegion *ar)
666 {
667         View2D *v2d= &ar->v2d;
668         IpoKey *ik;
669         
670         glBegin(GL_LINES);
671         for (ik= sipo->ipokey.first; ik; ik= ik->next) {
672                 if (ik->flag & SELECT) glColor3ub(0xFF, 0xFF, 0x99);
673                 else glColor3ub(0xAA, 0xAA, 0x55);
674                 
675                 glVertex2f(ik->val, v2d->cur.ymin);
676                 glVertex2f(ik->val, v2d->cur.ymax);
677         }
678         glEnd();
679 }
680 #endif
681
682 void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
683 {
684         ListBase anim_data = {NULL, NULL};
685         bAnimListElem *ale;
686         int filter;
687         
688         unsigned int col;
689         int items, i;
690         
691         /* build list of curves to draw */
692         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY|ANIMFILTER_CURVEVISIBLE);
693         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
694                 
695         /* for each curve:
696          *      draw curve, then handle-lines, and finally vertices in this order so that 
697          *      the data will be layered correctly
698          */
699         for (ale=anim_data.first, i=0; ale; ale=ale->next, i++) {
700                 FCurve *fcu= (FCurve *)ale->key_data;
701                 Object *nob= ANIM_nla_mapping_get(ac, ale);
702                 float fac=0.0f; // dummy var
703                 
704                 /* map keyframes for drawing if scaled F-Curve */
705                 if (nob)
706                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 0); 
707                 
708                 /* draw curve - we currently calculate colour on the fly, but that should probably be done in advance instead */
709                 if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { 
710                         /* set color/drawing style for curve itself */
711                         if (fcu->flag & FCURVE_PROTECTED) {
712                                 /* protected curves (non editable) are drawn with dotted lines */
713                                 setlinestyle(2);
714                         }
715                         if (fcu->flag & FCURVE_MUTED) {
716                                 /* muted curves are drawn in a greyish hue */
717                                 // XXX should we have some variations?
718                                 UI_ThemeColorShade(TH_HEADER, 50);
719                         }
720                         else {
721                                 // XXX color calculation here really needs to be done in advance instead
722                                 col= ipo_rainbow(i, items);
723                                 cpack(col);
724                         }
725                         
726                         /* draw F-Curve */
727                         draw_fcurve_repeat(fcu, &ar->v2d, 0, 0, &fac); // XXX this call still needs a lot more work
728                         
729                         /* restore settings */
730                         setlinestyle(0);
731                         
732                         
733                         /* draw handles and vertices as appropriate */
734                         if (fcu->bezt) {
735                                 /* only draw handles/vertices on keyframes */
736                                 draw_fcurve_handles(sipo, ar, fcu);
737                                 draw_fcurve_vertices(sipo, ar, fcu);
738                         }
739                         else {
740                                 /* samples: should we only draw two indicators at either end as indicators? */
741                                 draw_fcurve_samples(sipo, ar, fcu);
742                         }
743                 }
744                 
745                 /* undo mapping of keyframes for drawing if scaled F-Curve */
746                 if (nob)
747                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 0); 
748         }
749         
750         /* free list of curves */
751         BLI_freelistN(&anim_data);
752 }
753
754 /* ************************************************************************* */
755 /* Channel List */
756
757 // XXX quite a few of these need to be kept in sync with their counterparts in Action Editor
758 // as they're the same. We have 2 separate copies of this for now to make it easier to develop
759 // the diffences between the two editors, but one day these should be merged!
760
761 /* left hand part */
762 void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) 
763 {
764         ListBase anim_data = {NULL, NULL};
765         bAnimListElem *ale;
766         int filter;
767         
768         View2D *v2d= &ar->v2d;
769         float x= 0.0f, y= 0.0f, height;
770         int items;
771         
772         /* build list of channels to draw */
773         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
774         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
775         
776         /* Update max-extent of channels here (taking into account scrollers):
777          *      - this is done to allow the channel list to be scrollable, but must be done here
778          *        to avoid regenerating the list again and/or also because channels list is drawn first
779          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
780          *        start of list offset, and the second is as a correction for the scrollers.
781          */
782         height= (float)((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
783         
784         if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
785                 /* don't use totrect set, as the width stays the same 
786                  * (NOTE: this is ok here, the configuration is pretty straightforward) 
787                  */
788                 v2d->tot.ymin= (float)(-height);
789         }
790         
791         /* XXX I would call the below line! (ton) */
792         /* UI_view2d_totRect_set(v2d, ar->type->minsizex, height); */
793         
794         /* loop through channels, and set up drawing depending on their type  */        
795         y= (float)ACHANNEL_FIRST;
796         
797         for (ale= anim_data.first; ale; ale= ale->next) {
798                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
799                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
800                 
801                 /* check if visible */
802                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
803                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
804                 {
805                         bActionGroup *grp = NULL;
806                         short indent= 0, offset= 0, sel= 0, group= 0;
807                         int expand= -1, protect = -1, special= -1, mute = -1;
808                         char name[128];
809                         
810                         /* determine what needs to be drawn */
811                         switch (ale->type) {
812                                 case ANIMTYPE_OBJECT: /* object */
813                                 {
814                                         Base *base= (Base *)ale->data;
815                                         Object *ob= base->object;
816                                         
817                                         group= 4;
818                                         indent= 0;
819                                         
820                                         /* icon depends on object-type */
821                                         if (ob->type == OB_ARMATURE)
822                                                 special= ICON_ARMATURE;
823                                         else    
824                                                 special= ICON_OBJECT;
825                                                 
826                                         /* only show expand if there are any channels */
827                                         if (EXPANDED_OBJC(ob))
828                                                 expand= ICON_TRIA_DOWN;
829                                         else
830                                                 expand= ICON_TRIA_RIGHT;
831                                         
832                                         sel = SEL_OBJC(base);
833                                         strcpy(name, ob->id.name+2);
834                                 }
835                                         break;
836                                 case ANIMTYPE_FILLACTD: /* action widget */
837                                 {
838                                         bAction *act= (bAction *)ale->data;
839                                         
840                                         group = 4;
841                                         indent= 1;
842                                         special= ICON_ACTION;
843                                         
844                                         if (EXPANDED_ACTC(act))
845                                                 expand= ICON_TRIA_DOWN;
846                                         else
847                                                 expand= ICON_TRIA_RIGHT;
848                                         
849                                         sel = SEL_ACTC(act);
850                                         strcpy(name, "Action");
851                                 }
852                                         break;
853                                 case ANIMTYPE_FILLDRIVERS: /* drivers widget */
854                                 {
855                                         AnimData *adt= (AnimData *)ale->data;
856                                         
857                                         group = 4;
858                                         indent= 1;
859                                         special= ICON_IPO_DEHLT;
860                                         
861                                         if (EXPANDED_DRVD(adt))
862                                                 expand= ICON_TRIA_DOWN;
863                                         else
864                                                 expand= ICON_TRIA_RIGHT;
865                                         
866                                         strcpy(name, "Drivers");
867                                 }
868                                         break;
869                                 case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */
870                                 {
871                                         Object *ob = (Object *)ale->data;
872                                         
873                                         group = 4;
874                                         indent = 1;
875                                         special = ICON_MATERIAL;
876                                         
877                                         if (FILTER_MAT_OBJC(ob))
878                                                 expand = ICON_TRIA_DOWN;
879                                         else
880                                                 expand = ICON_TRIA_RIGHT;
881                                                 
882                                         strcpy(name, "Materials");
883                                 }
884                                         break;
885                                 
886                                 
887                                 case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */
888                                 {
889                                         Material *ma = (Material *)ale->data;
890                                         
891                                         group = 0;
892                                         indent = 0;
893                                         special = ICON_MATERIAL;
894                                         offset = 21;
895                                         
896                                         if (FILTER_MAT_OBJD(ma))
897                                                 expand = ICON_TRIA_DOWN;
898                                         else
899                                                 expand = ICON_TRIA_RIGHT;
900                                         
901                                         strcpy(name, ma->id.name+2);
902                                 }
903                                         break;
904                                 case ANIMTYPE_DSLAM: /* lamp (dopesheet) expand widget */
905                                 {
906                                         Lamp *la = (Lamp *)ale->data;
907                                         
908                                         group = 4;
909                                         indent = 1;
910                                         special = ICON_LAMP;
911                                         
912                                         if (FILTER_LAM_OBJD(la))
913                                                 expand = ICON_TRIA_DOWN;
914                                         else
915                                                 expand = ICON_TRIA_RIGHT;
916                                         
917                                         strcpy(name, la->id.name+2);
918                                 }
919                                         break;
920                                 case ANIMTYPE_DSCAM: /* camera (dopesheet) expand widget */
921                                 {
922                                         Camera *ca = (Camera *)ale->data;
923                                         
924                                         group = 4;
925                                         indent = 1;
926                                         special = ICON_CAMERA;
927                                         
928                                         if (FILTER_CAM_OBJD(ca))
929                                                 expand = ICON_TRIA_DOWN;
930                                         else
931                                                 expand = ICON_TRIA_RIGHT;
932                                         
933                                         strcpy(name, ca->id.name+2);
934                                 }
935                                         break;
936                                 case ANIMTYPE_DSCUR: /* curve (dopesheet) expand widget */
937                                 {
938                                         Curve *cu = (Curve *)ale->data;
939                                         
940                                         group = 4;
941                                         indent = 1;
942                                         special = ICON_CURVE;
943                                         
944                                         if (FILTER_CUR_OBJD(cu))
945                                                 expand = ICON_TRIA_DOWN;
946                                         else
947                                                 expand = ICON_TRIA_RIGHT;
948                                         
949                                         strcpy(name, cu->id.name+2);
950                                 }
951                                         break;
952                                 case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */
953                                 {
954                                         Key *key= (Key *)ale->data;
955                                         
956                                         group = 4;
957                                         indent = 1;
958                                         special = ICON_EDIT;
959                                         
960                                         if (FILTER_SKE_OBJD(key))       
961                                                 expand = ICON_TRIA_DOWN;
962                                         else
963                                                 expand = ICON_TRIA_RIGHT;
964                                                 
965                                         //sel = SEL_OBJC(base);
966                                         strcpy(name, "Shape Keys");
967                                 }
968                                         break;
969                                         
970                                 
971                                 case ANIMTYPE_GROUP: /* action group */
972                                 {
973                                         bActionGroup *agrp= (bActionGroup *)ale->data;
974                                         
975                                         group= 2;
976                                         indent= 0;
977                                         special= -1;
978                                         
979                                         offset= (ale->id) ? 16 : 0;
980                                         
981                                         /* only show expand if there are any channels */
982                                         if (agrp->channels.first) {
983                                                 if (EXPANDED_AGRP(agrp))
984                                                         expand = ICON_TRIA_DOWN;
985                                                 else
986                                                         expand = ICON_TRIA_RIGHT;
987                                         }
988                                         
989                                         if (EDITABLE_AGRP(agrp))
990                                                 protect = ICON_UNLOCKED;
991                                         else
992                                                 protect = ICON_LOCKED;
993                                                 
994                                         sel = SEL_AGRP(agrp);
995                                         strcpy(name, agrp->name);
996                                 }
997                                         break;
998                                 case ANIMTYPE_FCURVE: /* F-Curve channel */
999                                 {
1000                                         FCurve *fcu = (FCurve *)ale->data;
1001                                         
1002                                         indent = 0;
1003                                         
1004                                         group= (fcu->grp) ? 1 : 0;
1005                                         grp= fcu->grp;
1006                                                                                 
1007                                         switch (ale->ownertype) {
1008                                                 case ANIMTYPE_NONE:     /* no owner */
1009                                                 case ANIMTYPE_FCURVE: 
1010                                                         offset= 0;
1011                                                         break;
1012                                                         
1013                                                 case ANIMTYPE_DSMAT: /* for now, this is special case for materials */
1014                                                         offset= 21;
1015                                                         indent= 1;
1016                                                         break;
1017                                                         
1018                                                 default:
1019                                                         offset= 14;
1020                                                         break;
1021                                         }
1022                                         
1023                                         /* for now, 'special' (i.e. in front of name) is used to show visibility status */
1024                                         // XXX these 'blank' icons are currently checkboxes
1025                                         if (fcu->flag & FCURVE_VISIBLE)
1026                                                 special= ICON_BLANK012;
1027                                         else
1028                                                 special= ICON_BLANK011;
1029                                         
1030                                         if (fcu->flag & FCURVE_MUTED)
1031                                                 mute = ICON_MUTE_IPO_ON;
1032                                         else    
1033                                                 mute = ICON_MUTE_IPO_OFF;
1034                                                 
1035                                         if (EDITABLE_FCU(fcu))
1036                                                 protect = ICON_UNLOCKED;
1037                                         else
1038                                                 protect = ICON_LOCKED;
1039                                         
1040                                         sel = SEL_FCU(fcu);
1041                                         
1042                                         getname_anim_fcurve(name, ale->id, fcu);
1043                                 }
1044                                         break;
1045                                         
1046                                 case ANIMTYPE_SHAPEKEY: /* shapekey channel */
1047                                 {
1048                                         KeyBlock *kb = (KeyBlock *)ale->data;
1049                                         
1050                                         indent = 0;
1051                                         special = -1;
1052                                         
1053                                         offset= (ale->id) ? 21 : 0;
1054                                         
1055                                         if (kb->name[0] == '\0')
1056                                                 sprintf(name, "Key %d", ale->index);
1057                                         else
1058                                                 strcpy(name, kb->name);
1059                                 }
1060                                         break;
1061                         }       
1062                         
1063                         /* now, start drawing based on this information */
1064                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1065                         glEnable(GL_BLEND);
1066                         
1067                         /* draw backing strip behind channel name */
1068                         if (group == 4) {
1069                                 /* only used in dopesheet... */
1070                                 if (ale->type == ANIMTYPE_OBJECT) {
1071                                         /* object channel - darker */
1072                                         UI_ThemeColor(TH_DOPESHEET_CHANNELOB);
1073                                         uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1074                                         gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1075                                 }
1076                                 else {
1077                                         /* sub-object folders - lighter */
1078                                         UI_ThemeColor(TH_DOPESHEET_CHANNELSUBOB);
1079                                         
1080                                         offset += 7 * indent;
1081                                         glBegin(GL_QUADS);
1082                                                 glVertex2f(x+offset, yminc);
1083                                                 glVertex2f(x+offset, ymaxc);
1084                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
1085                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
1086                                         glEnd();
1087                                         
1088                                         /* clear group value, otherwise we cause errors... */
1089                                         group = 0;
1090                                 }
1091                         }
1092                         else if (group == 3) {
1093                                 /* only for gp-data channels */
1094                                 UI_ThemeColorShade(TH_GROUP, 20);
1095                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1096                                 gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1097                         }
1098                         else if (group == 2) {
1099                                 /* only for action group channels */
1100                                 if (ale->flag & AGRP_ACTIVE)
1101                                         UI_ThemeColorShade(TH_GROUP_ACTIVE, 10);
1102                                 else
1103                                         UI_ThemeColorShade(TH_GROUP, 20);
1104                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1105                                 gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1106                         }
1107                         else {
1108                                 /* for normal channels 
1109                                  *      - use 3 shades of color group/standard color for 3 indention level
1110                                  *      - only use group colors if allowed to, and if actually feasible
1111                                  */
1112                                 if ((grp) && (grp->customCol)) 
1113                                 {
1114                                         char cp[3];
1115                                         
1116                                         if (indent == 2) {
1117                                                 VECCOPY(cp, grp->cs.solid);
1118                                         }
1119                                         else if (indent == 1) {
1120                                                 VECCOPY(cp, grp->cs.select);
1121                                         }
1122                                         else {
1123                                                 VECCOPY(cp, grp->cs.active);
1124                                         }
1125                                         
1126                                         glColor3ub(cp[0], cp[1], cp[2]);
1127                                 }
1128                                 else
1129                                         UI_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40));
1130                                 
1131                                 indent += group;
1132                                 offset += 7 * indent;
1133                                 glBegin(GL_QUADS);
1134                                         glVertex2f(x+offset, yminc);
1135                                         glVertex2f(x+offset, ymaxc);
1136                                         glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
1137                                         glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
1138                                 glEnd();
1139                         }
1140                         
1141                         /* draw expand/collapse triangle */
1142                         if (expand > 0) {
1143                                 UI_icon_draw(x+offset, yminc, expand);
1144                                 offset += 17;
1145                         }
1146                         
1147                         /* draw special icon indicating certain data-types */
1148                         if (special > -1) {
1149                                 if (ELEM(group, 3, 4)) {
1150                                         /* for gpdatablock channels */
1151                                         UI_icon_draw(x+offset, yminc, special);
1152                                         offset += 17;
1153                                 }
1154                                 else {
1155                                         /* for normal channels */
1156                                         UI_icon_draw(x+offset, yminc, special);
1157                                         offset += 17;
1158                                 }
1159                         }
1160                         glDisable(GL_BLEND);
1161                         
1162                         /* draw name */
1163                         if (sel)
1164                                 UI_ThemeColor(TH_TEXT_HI);
1165                         else
1166                                 UI_ThemeColor(TH_TEXT);
1167                         offset += 3;
1168                         ui_rasterpos_safe(x+offset, y-4, 1.0f);
1169                         UI_DrawString(G.font, name, 0);
1170                         
1171                         /* reset offset - for RHS of panel */
1172                         offset = 0;
1173                         
1174                         /* set blending again, as text drawing may clear it */
1175                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1176                         glEnable(GL_BLEND);
1177                         
1178                         /* draw protect 'lock' */
1179                         if (protect > -1) {
1180                                 offset = 16;
1181                                 UI_icon_draw((float)ACHANNEL_NAMEWIDTH-offset, yminc, protect);
1182                         }
1183                         
1184                         /* draw mute 'eye' */
1185                         if (mute > -1) {
1186                                 offset += 16;
1187                                 UI_icon_draw((float)(ACHANNEL_NAMEWIDTH-offset), yminc, mute);
1188                         }
1189                         glDisable(GL_BLEND);
1190                 }
1191                 
1192                 /* adjust y-position for next one */
1193                 y -= ACHANNEL_STEP;
1194         }
1195         
1196         /* free tempolary channels */
1197         BLI_freelistN(&anim_data);
1198 }