doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / space_action / action_draw.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /* System includes ----------------------------------------------------- */
31
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <float.h>
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_utildefines.h"
40
41 /* Types --------------------------------------------------------------- */
42
43 #include "DNA_anim_types.h"
44 #include "DNA_screen_types.h"
45
46 #include "BKE_action.h"
47 #include "BKE_context.h"
48
49
50 /* Everything from source (BIF, BDR, BSE) ------------------------------ */ 
51
52 #include "BIF_gl.h"
53
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
57
58 #include "ED_anim_api.h"
59 #include "ED_keyframes_draw.h"
60
61 #include "action_intern.h"
62
63 /* ************************************************************************* */
64 /* Channel List */
65
66 /* left hand part */
67 void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) 
68 {
69         ListBase anim_data = {NULL, NULL};
70         bAnimListElem *ale;
71         int filter;
72         
73         View2D *v2d= &ar->v2d;
74         float y= 0.0f;
75         int items, height;
76         
77         /* build list of channels to draw */
78         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
79         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
80         
81         /* Update max-extent of channels here (taking into account scrollers):
82          *      - this is done to allow the channel list to be scrollable, but must be done here
83          *        to avoid regenerating the list again and/or also because channels list is drawn first
84          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
85          *        start of list offset, and the second is as a correction for the scrollers.
86          */
87         height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
88         if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
89                 /* don't use totrect set, as the width stays the same 
90                  * (NOTE: this is ok here, the configuration is pretty straightforward) 
91                  */
92                 v2d->tot.ymin= (float)(-height);
93         }
94         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
95         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
96         
97         /* loop through channels, and set up drawing depending on their type  */        
98         {       /* first pass: just the standard GL-drawing for backdrop + text */
99                 y= (float)ACHANNEL_FIRST;
100                 
101                 for (ale= anim_data.first; ale; ale= ale->next) {
102                         float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
103                         float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
104                         
105                         /* check if visible */
106                         if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
107                                  IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
108                         {
109                                 /* draw all channels using standard channel-drawing API */
110                                 ANIM_channel_draw(ac, ale, yminc, ymaxc);
111                         }
112                         
113                         /* adjust y-position for next one */
114                         y -= ACHANNEL_STEP;
115                 }
116         }
117         {       /* second pass: widgets */
118                 uiBlock *block= uiBeginBlock(C, ar, "dopesheet channel buttons", UI_EMBOSS);
119                 
120                 y= (float)ACHANNEL_FIRST;
121                 
122                 for (ale= anim_data.first; ale; ale= ale->next) {
123                         float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
124                         float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
125                         
126                         /* check if visible */
127                         if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
128                                  IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
129                         {
130                                 /* draw all channels using standard channel-drawing API */
131                                 ANIM_channel_draw_widgets(ac, ale, block, yminc, ymaxc);
132                         }
133                         
134                         /* adjust y-position for next one */
135                         y -= ACHANNEL_STEP;
136                 }
137                 
138                 uiEndBlock(C, block);
139                 uiDrawBlock(C, block);
140         }
141         
142         /* free tempolary channels */
143         BLI_freelistN(&anim_data);
144 }
145
146 /* ************************************************************************* */
147 /* Keyframes */
148
149 /* extra padding for lengths (to go under scrollers) */
150 #define EXTRA_SCROLL_PAD        100.0f
151
152 /* draw keyframes in each channel */
153 void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
154 {
155         ListBase anim_data = {NULL, NULL};
156         bAnimListElem *ale;
157         int filter;
158         
159         View2D *v2d= &ar->v2d;
160         bDopeSheet *ads= &saction->ads;
161         AnimData *adt= NULL;
162         
163         float act_start, act_end, y;
164         int height, items;
165         
166         unsigned char col1[3], col2[3];
167         unsigned char col1a[3], col2a[3];
168         unsigned char col1b[3], col2b[3];
169         
170         
171         /* get theme colors */
172         UI_GetThemeColor3ubv(TH_BACK, col2);
173         UI_GetThemeColor3ubv(TH_HILITE, col1);
174         
175         UI_GetThemeColor3ubv(TH_GROUP, col2a);
176         UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
177         
178         UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
179         UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
180         
181         /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
182
183         /* if in NLA there's a strip active, map the view */
184         if (ac->datatype == ANIMCONT_ACTION) {
185                 adt= ANIM_nla_mapping_get(ac, NULL);
186                 
187                 /* start and end of action itself */
188                 calc_action_range(ac->data, &act_start, &act_end, 0);
189         }
190         
191         /* build list of channels to draw */
192         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
193         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
194         
195         /* Update max-extent of channels here (taking into account scrollers):
196          *      - this is done to allow the channel list to be scrollable, but must be done here
197          *        to avoid regenerating the list again and/or also because channels list is drawn first
198          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
199          *        start of list offset, and the second is as a correction for the scrollers.
200          */
201         height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
202         /* don't use totrect set, as the width stays the same 
203          * (NOTE: this is ok here, the configuration is pretty straightforward) 
204          */
205         v2d->tot.ymin= (float)(-height);
206         
207         /* first backdrop strips */
208         y= (float)(-ACHANNEL_HEIGHT);
209         glEnable(GL_BLEND);
210         
211         for (ale= anim_data.first; ale; ale= ale->next) {
212                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
213                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
214                 
215                 /* check if visible */
216                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
217                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
218                 {
219                         bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
220                         int sel=0;
221                         
222                         /* determine if any need to draw channel */
223                         if (ale->datatype != ALE_NONE) {
224                                 /* determine if channel is selected */
225                                 if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
226                                         sel= ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
227                                 
228                                 if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
229                                         switch (ale->type) {
230                                                 case ANIMTYPE_SUMMARY:
231                                                 {
232                                                         // FIXME: hardcoded colors - reddish color from NLA
233                                                         glColor4f(0.8f, 0.2f, 0.0f, 0.4f);
234                                                 }
235                                                         break;
236                                                 
237                                                 case ANIMTYPE_SCENE:
238                                                 case ANIMTYPE_OBJECT:
239                                                 {
240                                                         if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); 
241                                                         else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); 
242                                                 }
243                                                         break;
244                                                 
245                                                 case ANIMTYPE_FILLACTD:
246                                                 case ANIMTYPE_FILLMATD:
247                                                 case ANIMTYPE_FILLPARTD:
248                                                 case ANIMTYPE_DSSKEY:
249                                                 case ANIMTYPE_DSWOR:
250                                                 {
251                                                         if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); 
252                                                         else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); 
253                                                 }
254                                                         break;
255                                                 
256                                                 case ANIMTYPE_GROUP:
257                                                 {
258                                                         if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
259                                                         else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
260                                                 }
261                                                         break;
262                                                 
263                                                 default:
264                                                 {
265                                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
266                                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
267                                                 }
268                                                         break;
269                                         }
270                                         
271                                         /* draw region twice: firstly backdrop, then the current range */
272                                         glRectf(v2d->cur.xmin,  (float)y-ACHANNEL_HEIGHT_HALF,  v2d->cur.xmax+EXTRA_SCROLL_PAD,  (float)y+ACHANNEL_HEIGHT_HALF);
273                                         
274                                         if (ac->datatype == ANIMCONT_ACTION)
275                                                 glRectf(act_start,  (float)y-ACHANNEL_HEIGHT_HALF,  act_end,  (float)y+ACHANNEL_HEIGHT_HALF);
276                                 }
277                                 else if (ac->datatype == ANIMCONT_GPENCIL) {
278                                         /* frames less than one get less saturated background */
279                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
280                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
281                                         glRectf(0.0f, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y+ACHANNEL_HEIGHT_HALF);
282                                         
283                                         /* frames one and higher get a saturated background */
284                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
285                                         else glColor4ub(col2[0], col2[1], col2[2], 0x44);
286                                         glRectf(v2d->cur.xmin, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmax+EXTRA_SCROLL_PAD,  (float)y+ACHANNEL_HEIGHT_HALF);
287                                 }
288                         }
289                 }
290                 
291                 /*      Increment the step */
292                 y -= ACHANNEL_STEP;
293         }               
294         glDisable(GL_BLEND);
295         
296         /* Draw keyframes 
297          *      1) Only channels that are visible in the Action Editor get drawn/evaluated.
298          *         This is to try to optimise this for heavier data sets
299          *      2) Keyframes which are out of view horizontally are disregarded 
300          */
301         y= (float)(-ACHANNEL_HEIGHT);
302         
303         for (ale= anim_data.first; ale; ale= ale->next) {
304                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
305                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
306                 
307                 /* check if visible */
308                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
309                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
310                 {
311                         /* check if anything to show for this channel */
312                         if (ale->datatype != ALE_NONE) {
313                                 adt= ANIM_nla_mapping_get(ac, ale);
314                                 
315                                 /* draw 'keyframes' for each specific datatype */
316                                 switch (ale->datatype) {
317                                         case ALE_ALL:
318                                                 draw_summary_channel(v2d, ale->data, y);
319                                                 break;
320                                         case ALE_SCE:
321                                                 draw_scene_channel(v2d, ads, ale->key_data, y);
322                                                 break;
323                                         case ALE_OB:
324                                                 draw_object_channel(v2d, ads, ale->key_data, y);
325                                                 break;
326                                         case ALE_ACT:
327                                                 draw_action_channel(v2d, adt, ale->key_data, y);
328                                                 break;
329                                         case ALE_GROUP:
330                                                 draw_agroup_channel(v2d, adt, ale->data, y);
331                                                 break;
332                                         case ALE_FCURVE:
333                                                 draw_fcurve_channel(v2d, adt, ale->key_data, y);
334                                                 break;
335                                         case ALE_GPFRAME:
336                                                 draw_gpl_channel(v2d, ads, ale->data, y);
337                                                 break;
338                                 }
339                         }
340                 }
341                 
342                 y-= ACHANNEL_STEP;
343         }
344         
345         /* free tempolary channels used for drawing */
346         BLI_freelistN(&anim_data);
347
348         /* black line marking 'current frame' for Time-Slide transform mode */
349         if (saction->flag & SACTION_MOVING) {
350                 glColor3f(0.0f, 0.0f, 0.0f);
351                 
352                 glBegin(GL_LINES);
353                         glVertex2f(saction->timeslide, v2d->cur.ymin-EXTRA_SCROLL_PAD);
354                         glVertex2f(saction->timeslide, v2d->cur.ymax);
355                 glEnd();
356         }
357 }