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