2.5 - IPO Editor
[blender.git] / source / blender / editors / space_ipo / ipo_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_action_types.h"
47 #include "DNA_curve_types.h"
48 #include "DNA_ipo_types.h"
49 #include "DNA_key_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_screen_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_sequence_types.h"
55 #include "DNA_userdef_types.h"
56 #include "DNA_view2d_types.h"
57 #include "DNA_windowmanager_types.h"
58
59 #include "BKE_curve.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_ipo.h"
62 #include "BKE_key.h"
63 #include "BKE_object.h"
64 #include "BKE_utildefines.h"
65
66 #include "BIF_gl.h"
67 #include "BIF_glutil.h"
68
69 #include "ED_anim_api.h"
70 #include "ED_util.h"
71
72 #include "UI_resources.h"
73 #include "UI_view2d.h"
74
75 /* **************************** */
76 // XXX stubs to remove!
77
78 // NOTE: the code in this file has yet to be rewritten to get rid of the editipo system which is past its use-by-date - Aligorith
79
80 typedef struct EditIpo {
81         IpoCurve *icu;
82         short disptype;
83         short flag;
84         unsigned int col;
85 } EditIpo;
86
87 #define ISPOIN(a, b, c)                       ( (a->b) && (a->c) )  
88 #define ISPOIN3(a, b, c, d)           ( (a->b) && (a->c) && (a->d) )
89 #define ISPOIN4(a, b, c, d, e)        ( (a->b) && (a->c) && (a->d) && (a->e) )
90
91 /* *************************** */
92
93 /* helper func - draw keyframe vertices only for an IPO-curve */
94 static void draw_ipovertices_keyframes(IpoCurve *icu, View2D *v2d, short disptype, short edit, short sel)
95 {
96         BezTriple *bezt= icu->bezt;
97         float v1[2];
98         int a, b;
99         
100         bglBegin(GL_POINTS);
101         
102         for (a = 0; a < icu->totvert; a++, bezt++) {
103                 /* IPO_DISPBITS is used for displaying curves for bitflag variables */
104                 if (disptype == IPO_DISPBITS) {
105                         /*if (v2d->cur.xmin < bezt->vec[1][0] < v2d->cur.xmax) {*/
106                         short ok= 0;
107                         
108                         if (edit) {
109                                 if ((bezt->f2 & SELECT) == sel) 
110                                         ok= 1;
111                         }
112                         else ok= 1;
113                         
114                         if (ok) {
115                                 int val= (int)bezt->vec[1][1];
116                                 v1[0]= bezt->vec[1][0];
117                                 
118                                 for (b= 0; b < 31; b++) {
119                                         if (val & (1<<b)) {     
120                                                 v1[1]= b + 1;
121                                                 bglVertex3fv(v1);
122                                         }
123                                 }
124                         }
125                         /*}*/
126                 } 
127                 else { /* normal (non bit) curves */
128                         if (edit) {
129                                 /* Only the vertex of the line, the
130                                  * handler are drawn later
131                                  */
132                                 if ((bezt->f2 & SELECT) == sel) /* && G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/
133                                         bglVertex3fv(bezt->vec[1]);
134                         }
135                         else {
136                                 /* draw only if in bounds */
137                                 /*if (G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/
138                                 bglVertex3fv(bezt->vec[1]);
139                         }
140                 }
141         }
142         bglEnd();
143 }
144
145 /* helper func - draw handle vertex for an IPO-Curve as a round unfilled circle */
146 static void draw_ipohandle_control(float x, float y, float xscale, float yscale, float hsize)
147 {
148         static GLuint displist=0;
149         
150         /* initialise round circle shape */
151         if (displist == 0) {
152                 GLUquadricObj *qobj;
153                 
154                 displist= glGenLists(1);
155                 glNewList(displist, GL_COMPILE_AND_EXECUTE);
156                 
157                 qobj    = gluNewQuadric(); 
158                 gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
159                 gluDisk(qobj, 0.07,  0.8, 12, 1);
160                 gluDeleteQuadric(qobj);  
161                 
162                 glEndList();
163         }
164         
165         /* adjust view transform before starting */
166         glTranslatef(x, y, 0.0f);
167         glScalef(1.0/xscale*hsize, 1.0/yscale*hsize, 1.0);
168         
169         /* draw! */
170         glCallList(displist);
171         
172         /* restore view transform */
173         glScalef(xscale/hsize, yscale/hsize, 1.0);
174         glTranslatef(-x, -y, 0.0f);
175 }
176
177 /* helper func - draw handle vertices only for an IPO-curve (if it is in EditMode) */
178 static void draw_ipovertices_handles(IpoCurve *icu, View2D *v2d, short disptype, short sel)
179 {
180         BezTriple *bezt= icu->bezt;
181         BezTriple *prevbezt = NULL;
182         float hsize, xscale, yscale;
183         int a;
184         
185         /* get view settings */
186         hsize= UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE);
187         UI_view2d_getscale(v2d, &xscale, &yscale);
188         
189         /* set handle color */
190         if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
191         else UI_ThemeColor(TH_HANDLE_VERTEX);
192         
193         for (a= 0; a < icu->totvert; a++, prevbezt=bezt, bezt++) {
194                 if (disptype != IPO_DISPBITS) {
195                         if (ELEM(icu->ipo, IPO_BEZ, IPO_MIXED)) {
196                                 /* Draw the editmode handels for a bezier curve (others don't have handles) 
197                                  * if their selection status matches the selection status we're drawing for
198                                  *      - first handle only if previous beztriple was bezier-mode
199                                  *      - second handle only if current beztriple is bezier-mode
200                                  */
201                                 if ( (!prevbezt && (bezt->ipo==IPO_BEZ)) || (prevbezt && (prevbezt->ipo==IPO_BEZ)) ) {
202                                         if ((bezt->f1 & SELECT) == sel)/* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/
203                                                 draw_ipohandle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize);
204                                 }
205                                 
206                                 if (bezt->ipo==IPO_BEZ) {
207                                         if ((bezt->f3 & SELECT) == sel)/* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/
208                                                 draw_ipohandle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize);
209                                 }
210                         }
211                 }
212         }
213 }
214
215 static void draw_ipovertices(SpaceIpo *sipo, ARegion *ar, int sel)
216 {
217         View2D *v2d= &ar->v2d;
218         EditIpo *ei= sipo->editipo;
219         int nr, val = 0;
220         
221         /* this shouldn't get called while drawing in selection-buffer anyway */
222         //if (G.f & G_PICKSEL) return;
223         
224         glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
225         
226         for (nr=0; nr<sipo->totipo; nr++, ei++) {
227                 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
228                         /* select colors to use to draw keyframes */
229                         if (sipo->showkey) {
230                                 if (sel) UI_ThemeColor(TH_TEXT_HI);
231                                 else UI_ThemeColor(TH_TEXT);
232                         } 
233                         else if (ei->flag & IPO_EDIT) {
234                                 if (sel) UI_ThemeColor(TH_VERTEX_SELECT); 
235                                 else UI_ThemeColor(TH_VERTEX);
236                         } 
237                         else {
238                                 if (sel) UI_ThemeColor(TH_TEXT_HI);
239                                 else UI_ThemeColor(TH_TEXT);
240                                 
241                                 val= (ei->icu->flag & IPO_SELECT)!=0;
242                                 if (sel != val) continue;
243                         }
244                         
245                         /* We can't change the color in the middle of
246                          * GL_POINTS because then Blender will segfault
247                          * on TNT2 / Linux with NVidia's drivers
248                          * (at least up to ver. 4349) 
249                          */             
250                         
251                         /* draw keyframes, then the handles (if in editmode) */
252                         draw_ipovertices_keyframes(ei->icu, v2d, ei->disptype, (ei->flag & IPO_EDIT), sel);
253                         
254                         /* Now draw the two vertex of the handles,
255                          * This needs to be done after the keyframes, 
256                          * because we can't call glPointSize
257                          * in the middle of a glBegin/glEnd also the
258                          * bug comment before.
259                          */
260                         if ((ei->flag & IPO_EDIT) && (sipo->flag & SIPO_NOHANDLES)==0)
261                                 draw_ipovertices_handles(ei->icu, v2d, ei->disptype, sel);
262                 }
263         }
264         
265         glPointSize(1.0);
266 }
267
268 /* draw lines for IPO-curve handles only (this is only done in EditMode) */
269 static void draw_ipohandles(SpaceIpo *sipo, ARegion *ar, int sel)
270 {
271         EditIpo *ei;
272         extern unsigned int nurbcol[];
273         unsigned int *col;
274         int a, b;
275         
276         /* don't draw handle lines if handles are not shown */
277         if (sipo->flag & SIPO_NOHANDLES)
278                 return;
279         
280         if (sel) col= nurbcol+4;
281         else col= nurbcol;
282         
283         ei= sipo->editipo;
284         for (a=0; a<sipo->totipo; a++, ei++) {
285                 if ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, disptype!=IPO_DISPBITS) {
286                         if (ELEM(ei->icu->ipo, IPO_BEZ, IPO_MIXED)) {
287                                 BezTriple *bezt=ei->icu->bezt, *prevbezt=NULL;
288                                 float *fp;
289                                 
290                                 for (b= 0; b < ei->icu->totvert; b++, prevbezt=bezt, bezt++) {
291                                         if ((bezt->f2 & SELECT)==sel) {
292                                                 fp= bezt->vec[0];
293                                                 
294                                                 /* only draw first handle if previous segment had handles */
295                                                 if ( (!prevbezt && (bezt->ipo==IPO_BEZ)) || (prevbezt && (prevbezt->ipo==IPO_BEZ)) ) 
296                                                 {
297                                                         cpack(col[bezt->h1]);
298                                                         glBegin(GL_LINE_STRIP); 
299                                                         glVertex2fv(fp); glVertex2fv(fp+3); 
300                                                         glEnd();
301                                                         
302                                                 }
303                                                 
304                                                 /* only draw second handle if this segment is bezier */
305                                                 if (bezt->ipo == IPO_BEZ) 
306                                                 {
307                                                         cpack(col[bezt->h2]);
308                                                         glBegin(GL_LINE_STRIP); 
309                                                         glVertex2fv(fp+3); glVertex2fv(fp+6); 
310                                                         glEnd();
311                                                 }
312                                         }
313                                         else {
314                                                 /* only draw first handle if previous segment was had handles, and selection is ok */
315                                                 if ( ((bezt->f1 & SELECT)==sel) && 
316                                                          ( (!prevbezt && (bezt->ipo==IPO_BEZ)) || (prevbezt && (prevbezt->ipo==IPO_BEZ)) ) ) 
317                                                 {
318                                                         fp= bezt->vec[0];
319                                                         cpack(col[bezt->h1]);
320                                                         
321                                                         glBegin(GL_LINE_STRIP); 
322                                                         glVertex2fv(fp); glVertex2fv(fp+3); 
323                                                         glEnd();
324                                                 }
325                                                 
326                                                 /* only draw second handle if this segment is bezier, and selection is ok */
327                                                 if ( ((bezt->f3 & SELECT)==sel) &&
328                                                          (bezt->ipo == IPO_BEZ) )
329                                                 {
330                                                         fp= bezt->vec[1];
331                                                         cpack(col[bezt->h2]);
332                                                         
333                                                         glBegin(GL_LINE_STRIP); 
334                                                         glVertex2fv(fp); glVertex2fv(fp+3); 
335                                                         glEnd();
336                                                 }
337                                         }
338                                 }
339                         }
340                 }
341         }
342 }
343
344 /* helper func - draw one repeat of an ipo-curve: bitflag curve only (this is evil stuff to expose to user like this) */
345 static void draw_ipocurve_repeat_bits (IpoCurve *icu, View2D *v2d, float cycxofs)
346 {
347         BezTriple *bezt= icu->bezt;
348         int a;
349         
350         /* loop over each keyframe, drawing a line extending from that point */
351         for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) {
352                 int val= (int)bezt->vec[1][1];
353                 int b= 0;
354                 
355                 /* for each bit in the int, draw a line if the keyframe incorporates it */
356                 for (b = 0; b < 31; b++) {
357                         if (val & (1<<b)) {
358                                 float v1[2];
359                                 
360                                 /* value stays constant */
361                                 v1[1]= b+1;
362                                 
363                                 glBegin(GL_LINE_STRIP);
364                                         /* extend left too if first keyframe, and not cyclic extrapolation */
365                                         if ((a == 0) && !(icu->extrap & IPO_CYCL)) {
366                                                 v1[0]= v2d->cur.xmin+cycxofs;
367                                                 glVertex2fv(v1);
368                                         }
369                                         
370                                         /* must pass through current keyframe */
371                                         v1[0]= bezt->vec[1][0] + cycxofs;
372                                         glVertex2fv(v1); 
373                                         
374                                         /* 1. if there is a next keyframe, extend until then OR
375                                          * 2. extend until 'infinity' if not cyclic extrapolation
376                                          */
377                                         if ((a+1) < icu->totvert) v1[0]= (bezt+1)->vec[1][0]+cycxofs;
378                                         else if ((icu->extrap & IPO_CYCL)==0) v1[0]= v2d->cur.xmax+cycxofs;
379                                         
380                                         glVertex2fv(v1);
381                                 glEnd();
382                         }
383                 }
384         }
385 }
386
387 /* helper func - draw one repeat of an ipo-curve: normal curve */
388 static void draw_ipocurve_repeat_normal (IpoCurve *icu, View2D *v2d, float cycxofs, float cycyofs, float *facp)
389 {
390         BezTriple *prevbezt= icu->bezt;
391         BezTriple *bezt= prevbezt+1;
392         float v1[2], v2[2], v3[2], v4[2];
393         float *fp, data[120];
394         float fac= *(facp);
395         int b= icu->totvert-1;
396         int resol;
397         
398         glBegin(GL_LINE_STRIP);
399         
400         /* extrapolate to left? */
401         if ((icu->extrap & IPO_CYCL)==0) {
402                 /* left-side of view comes before first keyframe, so need to extend as not cyclic */
403                 if (prevbezt->vec[1][0] > v2d->cur.xmin) {
404                         v1[0]= v2d->cur.xmin;
405                         
406                         /* y-value depends on the interpolation */
407                         if ((icu->extrap==IPO_HORIZ) || (prevbezt->ipo==IPO_CONST) || (icu->totvert==1)) {
408                                 /* just extend across the first keyframe's value */
409                                 v1[1]= prevbezt->vec[1][1];
410                         } 
411                         else if (prevbezt->ipo==IPO_LIN) {
412                                 /* extrapolate linear dosnt use the handle, use the next points center instead */
413                                 fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
414                                 if (fac) fac= 1.0f/fac;
415                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
416                         } 
417                         else {
418                                 /* based on angle of handle 1 (relative to keyframe) */
419                                 fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
420                                 if (fac) fac= 1.0f/fac;
421                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]);
422                         }
423                         
424                         glVertex2fv(v1);
425                 }
426         }
427         
428         /* if only one keyframe, add it now */
429         if (icu->totvert == 1) {
430                 v1[0]= prevbezt->vec[1][0] + cycxofs;
431                 v1[1]= prevbezt->vec[1][1] + cycyofs;
432                 glVertex2fv(v1);
433         }
434         
435         /* draw curve between first and last keyframe (if there are enough to do so) */
436         while (b--) {
437                 if (prevbezt->ipo==IPO_CONST) {
438                         /* Constant-Interpolation: draw segment between previous keyframe and next, but holding same value */
439                         v1[0]= prevbezt->vec[1][0]+cycxofs;
440                         v1[1]= prevbezt->vec[1][1]+cycyofs;
441                         glVertex2fv(v1);
442                         
443                         v1[0]= bezt->vec[1][0]+cycxofs;
444                         v1[1]= prevbezt->vec[1][1]+cycyofs;
445                         glVertex2fv(v1);
446                 }
447                 else if (prevbezt->ipo==IPO_LIN) {
448                         /* Linear interpolation: just add one point (which should add a new line segment) */
449                         v1[0]= prevbezt->vec[1][0]+cycxofs;
450                         v1[1]= prevbezt->vec[1][1]+cycyofs;
451                         glVertex2fv(v1);
452                 }
453                 else {
454                         /* Bezier-Interpolation: draw curve as series of segments between keyframes 
455                          *      - resol determines number of points to sample in between keyframes
456                          */
457                         
458                         /* resol not depending on horizontal resolution anymore, drivers for example... */
459                         if (icu->driver) 
460                                 resol= 32;
461                         else 
462                                 resol= 3.0*sqrt(bezt->vec[1][0] - prevbezt->vec[1][0]);
463                         
464                         if (resol < 2) {
465                                 /* only draw one */
466                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
467                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
468                                 glVertex2fv(v1);
469                         }
470                         else {
471                                 /* clamp resolution to max of 32 */
472                                 if (resol > 32) resol= 32;
473                                 
474                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
475                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
476                                 v2[0]= prevbezt->vec[2][0]+cycxofs;
477                                 v2[1]= prevbezt->vec[2][1]+cycyofs;
478                                 
479                                 v3[0]= bezt->vec[0][0]+cycxofs;
480                                 v3[1]= bezt->vec[0][1]+cycyofs;
481                                 v4[0]= bezt->vec[1][0]+cycxofs;
482                                 v4[1]= bezt->vec[1][1]+cycyofs;
483                                 
484                                 correct_bezpart(v1, v2, v3, v4);
485                                 
486                                 forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, 3);
487                                 forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data+1, resol, 3);
488                                 
489                                 for (fp= data; resol; resol--, fp+= 3)
490                                         glVertex2fv(fp);
491                         }
492                 }
493                 
494                 /* get next pointers */
495                 prevbezt= bezt; 
496                 bezt++;
497                 
498                 /* last point? */
499                 if (b == 0) {
500                         v1[0]= prevbezt->vec[1][0]+cycxofs;
501                         v1[1]= prevbezt->vec[1][1]+cycyofs;
502                         glVertex2fv(v1);
503                 }
504         }
505         
506         /* extrapolate to right? (see code for left-extrapolation above too) */
507         if ((icu->extrap & IPO_CYCL)==0) {
508                 if (prevbezt->vec[1][0] < v2d->cur.xmax) {
509                         v1[0]= v2d->cur.xmax;
510                         
511                         /* y-value depends on the interpolation */
512                         if ((icu->extrap==IPO_HORIZ) || (prevbezt->ipo==IPO_CONST) || (icu->totvert==1)) {
513                                 /* based on last keyframe's value */
514                                 v1[1]= prevbezt->vec[1][1];
515                         } 
516                         else if (prevbezt->ipo==IPO_LIN) {
517                                 /* extrapolate linear dosnt use the handle, use the previous points center instead */
518                                 bezt = prevbezt-1;
519                                 fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
520                                 if (fac) fac= 1.0f/fac;
521                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
522                         } 
523                         else {
524                                 /* based on angle of handle 1 (relative to keyframe) */
525                                 fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
526                                 if (fac) fac= 1.0f/fac;
527                                 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]);
528                         }
529                         
530                         glVertex2fv(v1);
531                 }
532         }
533         
534         glEnd();
535         
536         /* return fac, as we alter it */
537         *(facp) = fac;
538
539
540 /* draw all ipo-curves */
541 static void draw_ipocurves(SpaceIpo *sipo, ARegion *ar, int sel)
542 {
543         View2D *v2d= &ar->v2d;
544         EditIpo *ei;
545         int nr, val/*, pickselcode=0*/;
546         
547         /* if we're drawing for GL_SELECT, reset pickselcode first 
548          *      - there's only one place that will do this, so it should be fine
549          */
550         //if (G.f & G_PICKSEL)
551         //      pickselcode= 1;
552         
553         ei= sipo->editipo;
554         for (nr=0; nr<sipo->totipo; nr++, ei++) {
555                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
556                         /* val is used to indicate if curve can be edited */
557                         //if (G.f & G_PICKSEL) {
558                         //      /* when using OpenGL to select stuff (on mouseclick) */
559                         //      glLoadName(pickselcode++);
560                         //      val= 1;
561                         //}
562                         //else {
563                                 /* filter to only draw those that are selected or unselected (based on drawing mode */
564                                 val= (ei->flag & (IPO_SELECT+IPO_EDIT)) != 0;
565                                 val= (val==sel);
566                         //}
567                         
568                         /* only draw those curves that we can draw */
569                         if (val) {
570                                 IpoCurve *icu= ei->icu;
571                                 float cycdx=0.0f, cycdy=0.0f, cycxofs=0.0f, cycyofs=0.0f;
572                                 const int lastindex= (icu->totvert-1);
573                                 float fac= 0.0f;
574                                 int cycount=1;
575                                 
576                                 /* set color for curve curve:
577                                  *      - bitflag curves (evil) must always be drawn coloured as they cannot work with IPO-Keys
578                                  *      - when IPO-Keys are shown, individual curves are not editable, so we show by drawing them all black
579                                  */
580                                 if ((sipo->showkey) && (ei->disptype!=IPO_DISPBITS)) UI_ThemeColor(TH_TEXT); 
581                                 else cpack(ei->col);
582                                 
583                                 /* cyclic curves - get offset and number of repeats to display */
584                                 if (icu->extrap & IPO_CYCL) {
585                                         BezTriple *bezt= icu->bezt;
586                                         BezTriple *lastbezt= bezt + lastindex;
587                                         
588                                         /* calculate cycle length and amplitude  */
589                                         cycdx= lastbezt->vec[1][0] - bezt->vec[1][0];
590                                         cycdy= lastbezt->vec[1][1] - bezt->vec[1][1];
591                                         
592                                         /* check that the cycle does have some length */
593                                         if (cycdx > 0.01f) {
594                                                 /* count cycles before first frame  */
595                                                 while (icu->bezt->vec[1][0]+cycxofs > v2d->cur.xmin) {
596                                                         cycxofs -= cycdx;
597                                                         if (icu->extrap & IPO_DIR) cycyofs-= cycdy;
598                                                         cycount++;
599                                                 }
600                                                 
601                                                 /* count cycles after last frame (and adjust offset) */
602                                                 fac= 0.0f;
603                                                 while (lastbezt->vec[1][0]+fac < v2d->cur.xmax) {
604                                                         cycount++;
605                                                         fac += cycdx;
606                                                 }
607                                         }
608                                 }
609                                 
610                                 /* repeat process for each repeat */
611                                 while (cycount--) {
612                                         /* bitflag curves are drawn differently to normal curves */
613                                         if (ei->disptype==IPO_DISPBITS)
614                                                 draw_ipocurve_repeat_bits(icu, v2d, cycxofs);
615                                         else
616                                                 draw_ipocurve_repeat_normal(icu, v2d, cycxofs, cycyofs, &fac);
617                                         
618                                         /* prepare for next cycle by adjusing offsets */
619                                         cycxofs += cycdx;
620                                         if (icu->extrap & IPO_DIR) cycyofs += cycdy;
621                                 }
622                                 
623                                 /* vertical line that indicates the end of a speed curve */
624                                 if ((sipo->blocktype==ID_CU) && (icu->adrcode==CU_SPEED)) {
625                                         int b= icu->totvert-1;
626                                         
627                                         if (b) {
628                                                 BezTriple *bezt= icu->bezt+b;
629                                                 
630                                                 glColor3ub(0, 0, 0);
631                                                 
632                                                 glBegin(GL_LINES);
633                                                         glVertex2f(bezt->vec[1][0], 0.0f);
634                                                         glVertex2f(bezt->vec[1][0], bezt->vec[1][1]);
635                                                 glEnd();
636                                         }
637                                 }
638                         }
639                 }
640         }
641 }
642
643 #if 0
644 static void draw_ipokey(SpaceIpo *sipo, ARegion *ar)
645 {
646         View2D *v2d= &ar->v2d;
647         IpoKey *ik;
648         
649         glBegin(GL_LINES);
650         for (ik= sipo->ipokey.first; ik; ik= ik->next) {
651                 if (ik->flag & SELECT) glColor3ub(0xFF, 0xFF, 0x99);
652                 else glColor3ub(0xAA, 0xAA, 0x55);
653                 
654                 glVertex2f(ik->val, v2d->cur.ymin);
655                 glVertex2f(ik->val, v2d->cur.ymax);
656         }
657         glEnd();
658 }
659 #endif
660
661 void drawipospace(ScrArea *sa, ARegion *ar)
662 {
663         SpaceIpo *sipo= sa->spacedata.first;
664         //View2D *v2d= &ar->v2d;
665         EditIpo *ei;
666
667         
668         if(sipo->editipo) {
669                 
670                 /* correct scale for degrees? */
671                 // XXX this should be calculated elsewhere
672 #if 0
673                 disptype= -1;
674                 ei= sipo->editipo;
675                 for(a=0; a<sipo->totipo; a++, ei++) {
676                         if(ei->flag & IPO_VISIBLE) {
677                                 if(disptype== -1) disptype= ei->disptype;
678                                 else if(disptype!=ei->disptype) disptype= 0;
679                         }
680                 }
681 #endif
682                 // now set grid size (done elsehwere now)
683                 
684                 /* ipokeys */
685 #if 0
686                 if(sipo->showkey) {
687                         //if(sipo->ipokey.first==0) make_ipokey();
688                         //else update_ipokey_val();
689                         make_ipokey();
690                         draw_ipokey(sipo);
691                 }
692 #endif
693                 
694                 /* map ipo-points for drawing if scaled ipo */
695                 //if (NLA_IPO_SCALED)
696                 //      ANIM_nla_mapping_apply_ipo(OBACT, sipo->ipo, 0, 0);
697
698                 /* draw deselect */
699                 draw_ipocurves(sipo, ar, 0);
700                 draw_ipohandles(sipo, ar, 0);
701                 draw_ipovertices(sipo, ar, 0);
702                 
703                 /* draw select */
704                 draw_ipocurves(sipo, ar, 1);
705                 draw_ipohandles(sipo, ar, 1);
706                 draw_ipovertices(sipo, ar, 1);
707                 
708                 /* undo mapping of ipo-points for drawing if scaled ipo */
709                 //if (NLA_IPO_SCALED)
710                 //      ANIM_nla_mapping_apply_ipo(OBACT, sipo->ipo, 1, 0);
711                 
712         }
713 }