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