Graph Editor: Visibility toggles
[blender-staging.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                 // XXX enable ANIMFILTER_CURVEVISIBLE when we have a method to set them
693         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY|ANIMFILTER_CURVEVISIBLE);
694         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
695                 
696         /* for each curve:
697          *      draw curve, then handle-lines, and finally vertices in this order so that 
698          *      the data will be layered correctly
699          */
700         for (ale=anim_data.first, i=0; ale; ale=ale->next, i++) {
701                 FCurve *fcu= (FCurve *)ale->key_data;
702                 Object *nob= ANIM_nla_mapping_get(ac, ale);
703                 float fac=0.0f; // dummy var
704                 
705                 /* map keyframes for drawing if scaled F-Curve */
706                 if (nob)
707                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 0); 
708                 
709                 /* draw curve - we currently calculate colour on the fly, but that should probably be done in advance instead */
710                 if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { 
711                         col= ipo_rainbow(i, items);
712                         cpack(col);
713                         
714                         draw_fcurve_repeat(fcu, &ar->v2d, 0, 0, &fac); // XXX this call still needs a lot more work
715                         
716                         /* draw handles and vertices as appropriate */
717                         if (fcu->bezt) {
718                                 /* only draw handles/vertices on keyframes */
719                                 draw_fcurve_handles(sipo, ar, fcu);
720                                 draw_fcurve_vertices(sipo, ar, fcu);
721                         }
722                         else {
723                                 /* samples: should we only draw two indicators at either end as indicators? */
724                                 draw_fcurve_samples(sipo, ar, fcu);
725                         }
726                 }
727                 
728                 /* undo mapping of keyframes for drawing if scaled F-Curve */
729                 if (nob)
730                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 0); 
731         }
732         
733         /* free list of curves */
734         BLI_freelistN(&anim_data);
735 }
736
737 /* ************************************************************************* */
738 /* Channel List */
739
740 // XXX quite a few of these need to be kept in sync with their counterparts in Action Editor
741 // as they're the same. We have 2 separate copies of this for now to make it easier to develop
742 // the diffences between the two editors, but one day these should be merged!
743
744 /* left hand part */
745 void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) 
746 {
747         ListBase anim_data = {NULL, NULL};
748         bAnimListElem *ale;
749         int filter;
750         
751         View2D *v2d= &ar->v2d;
752         float x= 0.0f, y= 0.0f, height;
753         int items;
754         
755         /* build list of channels to draw */
756         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
757         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
758         
759         /* Update max-extent of channels here (taking into account scrollers):
760          *      - this is done to allow the channel list to be scrollable, but must be done here
761          *        to avoid regenerating the list again and/or also because channels list is drawn first
762          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
763          *        start of list offset, and the second is as a correction for the scrollers.
764          */
765         height= (float)((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
766         
767         if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
768                 /* don't use totrect set, as the width stays the same 
769                  * (NOTE: this is ok here, the configuration is pretty straightforward) 
770                  */
771                 v2d->tot.ymin= (float)(-height);
772         }
773         
774         /* XXX I would call the below line! (ton) */
775         /* UI_view2d_totRect_set(v2d, ar->type->minsizex, height); */
776         
777         /* loop through channels, and set up drawing depending on their type  */        
778         y= (float)ACHANNEL_FIRST;
779         
780         for (ale= anim_data.first; ale; ale= ale->next) {
781                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
782                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
783                 
784                 /* check if visible */
785                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
786                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
787                 {
788                         bActionGroup *grp = NULL;
789                         short indent= 0, offset= 0, sel= 0, group= 0;
790                         int expand= -1, protect = -1, special= -1, mute = -1;
791                         char name[128];
792                         
793                         /* determine what needs to be drawn */
794                         switch (ale->type) {
795                                 case ANIMTYPE_OBJECT: /* object */
796                                 {
797                                         Base *base= (Base *)ale->data;
798                                         Object *ob= base->object;
799                                         
800                                         group= 4;
801                                         indent= 0;
802                                         
803                                         /* icon depends on object-type */
804                                         if (ob->type == OB_ARMATURE)
805                                                 special= ICON_ARMATURE;
806                                         else    
807                                                 special= ICON_OBJECT;
808                                                 
809                                         /* only show expand if there are any channels */
810                                         if (EXPANDED_OBJC(ob))
811                                                 expand= ICON_TRIA_DOWN;
812                                         else
813                                                 expand= ICON_TRIA_RIGHT;
814                                         
815                                         sel = SEL_OBJC(base);
816                                         strcpy(name, ob->id.name+2);
817                                 }
818                                         break;
819                                 case ANIMTYPE_FILLACTD: /* action widget */
820                                 {
821                                         bAction *act= (bAction *)ale->data;
822                                         
823                                         group = 4;
824                                         indent= 1;
825                                         special= ICON_ACTION;
826                                         
827                                         if (EXPANDED_ACTC(act))
828                                                 expand= ICON_TRIA_DOWN;
829                                         else
830                                                 expand= ICON_TRIA_RIGHT;
831                                         
832                                         sel = SEL_ACTC(act);
833                                         strcpy(name, "Action");
834                                 }
835                                         break;
836                                 case ANIMTYPE_FILLDRIVERS: /* drivers widget */
837                                 {
838                                         AnimData *adt= (AnimData *)ale->data;
839                                         
840                                         group = 4;
841                                         indent= 1;
842                                         special= ICON_IPO_DEHLT;
843                                         
844                                         if (EXPANDED_DRVD(adt))
845                                                 expand= ICON_TRIA_DOWN;
846                                         else
847                                                 expand= ICON_TRIA_RIGHT;
848                                         
849                                         strcpy(name, "Drivers");
850                                 }
851                                         break;
852                                 case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */
853                                 {
854                                         Object *ob = (Object *)ale->data;
855                                         
856                                         group = 4;
857                                         indent = 1;
858                                         special = ICON_MATERIAL;
859                                         
860                                         if (FILTER_MAT_OBJC(ob))
861                                                 expand = ICON_TRIA_DOWN;
862                                         else
863                                                 expand = ICON_TRIA_RIGHT;
864                                                 
865                                         strcpy(name, "Materials");
866                                 }
867                                         break;
868                                 
869                                 
870                                 case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */
871                                 {
872                                         Material *ma = (Material *)ale->data;
873                                         
874                                         group = 0;
875                                         indent = 0;
876                                         special = ICON_MATERIAL;
877                                         offset = 21;
878                                         
879                                         if (FILTER_MAT_OBJD(ma))
880                                                 expand = ICON_TRIA_DOWN;
881                                         else
882                                                 expand = ICON_TRIA_RIGHT;
883                                         
884                                         strcpy(name, ma->id.name+2);
885                                 }
886                                         break;
887                                 case ANIMTYPE_DSLAM: /* lamp (dopesheet) expand widget */
888                                 {
889                                         Lamp *la = (Lamp *)ale->data;
890                                         
891                                         group = 4;
892                                         indent = 1;
893                                         special = ICON_LAMP;
894                                         
895                                         if (FILTER_LAM_OBJD(la))
896                                                 expand = ICON_TRIA_DOWN;
897                                         else
898                                                 expand = ICON_TRIA_RIGHT;
899                                         
900                                         strcpy(name, la->id.name+2);
901                                 }
902                                         break;
903                                 case ANIMTYPE_DSCAM: /* camera (dopesheet) expand widget */
904                                 {
905                                         Camera *ca = (Camera *)ale->data;
906                                         
907                                         group = 4;
908                                         indent = 1;
909                                         special = ICON_CAMERA;
910                                         
911                                         if (FILTER_CAM_OBJD(ca))
912                                                 expand = ICON_TRIA_DOWN;
913                                         else
914                                                 expand = ICON_TRIA_RIGHT;
915                                         
916                                         strcpy(name, ca->id.name+2);
917                                 }
918                                         break;
919                                 case ANIMTYPE_DSCUR: /* curve (dopesheet) expand widget */
920                                 {
921                                         Curve *cu = (Curve *)ale->data;
922                                         
923                                         group = 4;
924                                         indent = 1;
925                                         special = ICON_CURVE;
926                                         
927                                         if (FILTER_CUR_OBJD(cu))
928                                                 expand = ICON_TRIA_DOWN;
929                                         else
930                                                 expand = ICON_TRIA_RIGHT;
931                                         
932                                         strcpy(name, cu->id.name+2);
933                                 }
934                                         break;
935                                 case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */
936                                 {
937                                         Key *key= (Key *)ale->data;
938                                         
939                                         group = 4;
940                                         indent = 1;
941                                         special = ICON_EDIT;
942                                         
943                                         if (FILTER_SKE_OBJD(key))       
944                                                 expand = ICON_TRIA_DOWN;
945                                         else
946                                                 expand = ICON_TRIA_RIGHT;
947                                                 
948                                         //sel = SEL_OBJC(base);
949                                         strcpy(name, "Shape Keys");
950                                 }
951                                         break;
952                                         
953                                 
954                                 case ANIMTYPE_GROUP: /* action group */
955                                 {
956                                         bActionGroup *agrp= (bActionGroup *)ale->data;
957                                         
958                                         group= 2;
959                                         indent= 0;
960                                         special= -1;
961                                         
962                                         offset= (ale->id) ? 16 : 0;
963                                         
964                                         /* only show expand if there are any channels */
965                                         if (agrp->channels.first) {
966                                                 if (EXPANDED_AGRP(agrp))
967                                                         expand = ICON_TRIA_DOWN;
968                                                 else
969                                                         expand = ICON_TRIA_RIGHT;
970                                         }
971                                         
972                                         if (EDITABLE_AGRP(agrp))
973                                                 protect = ICON_UNLOCKED;
974                                         else
975                                                 protect = ICON_LOCKED;
976                                                 
977                                         sel = SEL_AGRP(agrp);
978                                         strcpy(name, agrp->name);
979                                 }
980                                         break;
981                                 case ANIMTYPE_FCURVE: /* F-Curve channel */
982                                 {
983                                         FCurve *fcu = (FCurve *)ale->data;
984                                         
985                                         indent = 0;
986                                         
987                                         group= (fcu->grp) ? 1 : 0;
988                                         grp= fcu->grp;
989                                                                                 
990                                         switch (ale->ownertype) {
991                                                 case ANIMTYPE_NONE:     /* no owner */
992                                                 case ANIMTYPE_FCURVE: 
993                                                         offset= 0;
994                                                         break;
995                                                         
996                                                 case ANIMTYPE_DSMAT: /* for now, this is special case for materials */
997                                                         offset= 21;
998                                                         indent= 1;
999                                                         break;
1000                                                         
1001                                                 default:
1002                                                         offset= 14;
1003                                                         break;
1004                                         }
1005                                         
1006                                         /* for now, 'special' (i.e. in front of name) is used to show visibility status */
1007                                         // XXX these 'blank' icons are currently checkboxes
1008                                         if (fcu->flag & FCURVE_VISIBLE)
1009                                                 special= ICON_BLANK012;
1010                                         else
1011                                                 special= ICON_BLANK011;
1012                                         
1013                                         if (fcu->flag & FCURVE_MUTED)
1014                                                 mute = ICON_MUTE_IPO_ON;
1015                                         else    
1016                                                 mute = ICON_MUTE_IPO_OFF;
1017                                                 
1018                                         if (EDITABLE_FCU(fcu))
1019                                                 protect = ICON_UNLOCKED;
1020                                         else
1021                                                 protect = ICON_LOCKED;
1022                                         
1023                                         sel = SEL_FCU(fcu);
1024                                         
1025                                         getname_anim_fcurve(name, ale->id, fcu);
1026                                 }
1027                                         break;
1028                                         
1029                                 case ANIMTYPE_SHAPEKEY: /* shapekey channel */
1030                                 {
1031                                         KeyBlock *kb = (KeyBlock *)ale->data;
1032                                         
1033                                         indent = 0;
1034                                         special = -1;
1035                                         
1036                                         offset= (ale->id) ? 21 : 0;
1037                                         
1038                                         if (kb->name[0] == '\0')
1039                                                 sprintf(name, "Key %d", ale->index);
1040                                         else
1041                                                 strcpy(name, kb->name);
1042                                 }
1043                                         break;
1044                         }       
1045                         
1046                         /* now, start drawing based on this information */
1047                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1048                         glEnable(GL_BLEND);
1049                         
1050                         /* draw backing strip behind channel name */
1051                         if (group == 4) {
1052                                 /* only used in dopesheet... */
1053                                 if (ale->type == ANIMTYPE_OBJECT) {
1054                                         /* object channel - darker */
1055                                         UI_ThemeColor(TH_DOPESHEET_CHANNELOB);
1056                                         uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1057                                         gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1058                                 }
1059                                 else {
1060                                         /* sub-object folders - lighter */
1061                                         UI_ThemeColor(TH_DOPESHEET_CHANNELSUBOB);
1062                                         
1063                                         offset += 7 * indent;
1064                                         glBegin(GL_QUADS);
1065                                                 glVertex2f(x+offset, yminc);
1066                                                 glVertex2f(x+offset, ymaxc);
1067                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
1068                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
1069                                         glEnd();
1070                                         
1071                                         /* clear group value, otherwise we cause errors... */
1072                                         group = 0;
1073                                 }
1074                         }
1075                         else if (group == 3) {
1076                                 /* only for gp-data channels */
1077                                 UI_ThemeColorShade(TH_GROUP, 20);
1078                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1079                                 gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1080                         }
1081                         else if (group == 2) {
1082                                 /* only for action group channels */
1083                                 if (ale->flag & AGRP_ACTIVE)
1084                                         UI_ThemeColorShade(TH_GROUP_ACTIVE, 10);
1085                                 else
1086                                         UI_ThemeColorShade(TH_GROUP, 20);
1087                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
1088                                 gl_round_box(GL_POLYGON, x+offset,  yminc, (float)ACHANNEL_NAMEWIDTH, ymaxc, 8);
1089                         }
1090                         else {
1091                                 /* for normal channels 
1092                                  *      - use 3 shades of color group/standard color for 3 indention level
1093                                  *      - only use group colors if allowed to, and if actually feasible
1094                                  */
1095                                 if ((grp) && (grp->customCol)) 
1096                                 {
1097                                         char cp[3];
1098                                         
1099                                         if (indent == 2) {
1100                                                 VECCOPY(cp, grp->cs.solid);
1101                                         }
1102                                         else if (indent == 1) {
1103                                                 VECCOPY(cp, grp->cs.select);
1104                                         }
1105                                         else {
1106                                                 VECCOPY(cp, grp->cs.active);
1107                                         }
1108                                         
1109                                         glColor3ub(cp[0], cp[1], cp[2]);
1110                                 }
1111                                 else
1112                                         UI_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40));
1113                                 
1114                                 indent += group;
1115                                 offset += 7 * indent;
1116                                 glBegin(GL_QUADS);
1117                                         glVertex2f(x+offset, yminc);
1118                                         glVertex2f(x+offset, ymaxc);
1119                                         glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
1120                                         glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
1121                                 glEnd();
1122                         }
1123                         
1124                         /* draw expand/collapse triangle */
1125                         if (expand > 0) {
1126                                 UI_icon_draw(x+offset, yminc, expand);
1127                                 offset += 17;
1128                         }
1129                         
1130                         /* draw special icon indicating certain data-types */
1131                         if (special > -1) {
1132                                 if (ELEM(group, 3, 4)) {
1133                                         /* for gpdatablock channels */
1134                                         UI_icon_draw(x+offset, yminc, special);
1135                                         offset += 17;
1136                                 }
1137                                 else {
1138                                         /* for ipo/constraint channels */
1139                                         UI_icon_draw(x+offset, yminc, special);
1140                                         offset += 17;
1141                                 }
1142                         }
1143                         glDisable(GL_BLEND);
1144                         
1145                         /* draw name */
1146                         if (sel)
1147                                 UI_ThemeColor(TH_TEXT_HI);
1148                         else
1149                                 UI_ThemeColor(TH_TEXT);
1150                         offset += 3;
1151                         ui_rasterpos_safe(x+offset, y-4, 1.0f);
1152                         UI_DrawString(G.font, name, 0);
1153                         
1154                         /* reset offset - for RHS of panel */
1155                         offset = 0;
1156                         
1157                         /* set blending again, as text drawing may clear it */
1158                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1159                         glEnable(GL_BLEND);
1160                         
1161                         /* draw protect 'lock' */
1162                         if (protect > -1) {
1163                                 offset = 16;
1164                                 UI_icon_draw((float)ACHANNEL_NAMEWIDTH-offset, yminc, protect);
1165                         }
1166                         
1167                         /* draw mute 'eye' */
1168                         if (mute > -1) {
1169                                 offset += 16;
1170                                 UI_icon_draw((float)(ACHANNEL_NAMEWIDTH-offset), yminc, mute);
1171                         }
1172                         glDisable(GL_BLEND);
1173                 }
1174                 
1175                 /* adjust y-position for next one */
1176                 y -= ACHANNEL_STEP;
1177         }
1178         
1179         /* free tempolary channels */
1180         BLI_freelistN(&anim_data);
1181 }