Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / space_action / action_draw.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spaction
22  */
23
24 /* System includes ----------------------------------------------------- */
25
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <float.h>
30
31 #include "BLI_blenlib.h"
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34
35 /* Types --------------------------------------------------------------- */
36
37 #include "DNA_anim_types.h"
38 #include "DNA_cachefile_types.h"
39 #include "DNA_gpencil_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_scene_types.h"
43
44 #include "BKE_action.h"
45 #include "BKE_context.h"
46 #include "BKE_pointcache.h"
47
48 /* Everything from source (BIF, BDR, BSE) ------------------------------ */
49
50 #include "GPU_immediate.h"
51 #include "GPU_matrix.h"
52 #include "GPU_state.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   size_t items;
76   int height;
77
78   /* build list of channels to draw */
79   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
80   items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
81
82   height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
83   if (height > BLI_rcti_size_y(&v2d->mask)) {
84     /* don't use totrect set, as the width stays the same
85      * (NOTE: this is ok here, the configuration is pretty straightforward)
86      */
87     v2d->tot.ymin = (float)(-height);
88   }
89   /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
90   UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
91
92   /* loop through channels, and set up drawing depending on their type  */
93   { /* first pass: just the standard GL-drawing for backdrop + text */
94     size_t channel_index = 0;
95
96     y = (float)ACHANNEL_FIRST(ac);
97
98     for (ale = anim_data.first; ale; ale = ale->next) {
99       float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
100       float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
101
102       /* check if visible */
103       if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
104           IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) {
105         /* draw all channels using standard channel-drawing API */
106         ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
107       }
108
109       /* adjust y-position for next one */
110       y -= ACHANNEL_STEP(ac);
111       channel_index++;
112     }
113   }
114   { /* second pass: widgets */
115     uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
116     size_t channel_index = 0;
117
118     y = (float)ACHANNEL_FIRST(ac);
119
120     for (ale = anim_data.first; ale; ale = ale->next) {
121       float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
122       float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
123
124       /* check if visible */
125       if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
126           IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) {
127         /* draw all channels using standard channel-drawing API */
128         rctf channel_rect;
129         BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc);
130         ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index);
131       }
132
133       /* adjust y-position for next one */
134       y -= ACHANNEL_STEP(ac);
135       channel_index++;
136     }
137
138     UI_block_end(C, block);
139     UI_block_draw(C, block);
140   }
141
142   /* free tempolary channels */
143   ANIM_animdata_freelist(&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
158   View2D *v2d = &ar->v2d;
159   bDopeSheet *ads = &saction->ads;
160   AnimData *adt = NULL;
161
162   float y;
163
164   unsigned char col1[4], col2[4];
165   unsigned char col1a[4], col2a[4];
166   unsigned char col1b[4], col2b[4];
167
168   const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
169
170   /* get theme colors */
171   UI_GetThemeColor4ubv(TH_SHADE2, col2);
172   UI_GetThemeColor4ubv(TH_HILITE, col1);
173
174   UI_GetThemeColor4ubv(TH_GROUP, col2a);
175   UI_GetThemeColor4ubv(TH_GROUP_ACTIVE, col1a);
176
177   UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELOB, col1b);
178   UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
179
180   /* build list of channels to draw */
181   int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
182   size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
183
184   int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
185   /* don't use totrect set, as the width stays the same
186    * (NOTE: this is ok here, the configuration is pretty straightforward)
187    */
188   v2d->tot.ymin = (float)(-height);
189
190   /* first backdrop strips */
191   y = (float)(-ACHANNEL_HEIGHT(ac));
192
193   GPUVertFormat *format = immVertexFormat();
194   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
195
196   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
197
198   GPU_blend(true);
199
200   for (ale = anim_data.first; ale; ale = ale->next) {
201     const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
202     const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
203
204     /* check if visible */
205     if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
206         IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) {
207       const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
208       int sel = 0;
209
210       /* determine if any need to draw channel */
211       if (ale->datatype != ALE_NONE) {
212         /* determine if channel is selected */
213         if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) {
214           sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
215         }
216
217         if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
218           switch (ale->type) {
219             case ANIMTYPE_SUMMARY: {
220               /* reddish color from NLA */
221               immUniformThemeColor(TH_ANIM_ACTIVE);
222               break;
223             }
224             case ANIMTYPE_SCENE:
225             case ANIMTYPE_OBJECT: {
226               immUniformColor3ubvAlpha(col1b, sel ? col1[3] : col1b[3]);
227               break;
228             }
229             case ANIMTYPE_FILLACTD:
230             case ANIMTYPE_DSSKEY:
231             case ANIMTYPE_DSWOR: {
232               immUniformColor3ubvAlpha(col2b, sel ? col1[3] : col2b[3]);
233               break;
234             }
235             case ANIMTYPE_GROUP: {
236               bActionGroup *agrp = ale->data;
237               if (show_group_colors && agrp->customCol) {
238                 if (sel) {
239                   immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, col1a[3]);
240                 }
241                 else {
242                   immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, col2a[3]);
243                 }
244               }
245               else {
246                 immUniformColor4ubv(sel ? col1a : col2a);
247               }
248               break;
249             }
250             case ANIMTYPE_FCURVE: {
251               FCurve *fcu = ale->data;
252               if (show_group_colors && fcu->grp && fcu->grp->customCol) {
253                 immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active,
254                                          sel ? col1[3] : col2[3]);
255               }
256               else {
257                 immUniformColor4ubv(sel ? col1 : col2);
258               }
259               break;
260             }
261             default: {
262               immUniformColor4ubv(sel ? col1 : col2);
263             }
264           }
265
266           /* draw region twice: firstly backdrop, then the current range */
267           immRectf(pos,
268                    v2d->cur.xmin,
269                    (float)y - ACHANNEL_HEIGHT_HALF(ac),
270                    v2d->cur.xmax + EXTRA_SCROLL_PAD,
271                    (float)y + ACHANNEL_HEIGHT_HALF(ac));
272         }
273         else if (ac->datatype == ANIMCONT_GPENCIL) {
274           unsigned char *color;
275           unsigned char gpl_col[4];
276           if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) {
277             bGPDlayer *gpl = (bGPDlayer *)ale->data;
278             rgb_float_to_uchar(gpl_col, gpl->color);
279             gpl_col[3] = col1[3];
280
281             color = sel ? col1 : gpl_col;
282           }
283           else {
284             color = sel ? col1 : col2;
285           }
286           /* frames less than one get less saturated background */
287           immUniformColor4ubv(color);
288           immRectf(pos,
289                    0.0f,
290                    (float)y - ACHANNEL_HEIGHT_HALF(ac),
291                    v2d->cur.xmin,
292                    (float)y + ACHANNEL_HEIGHT_HALF(ac));
293
294           /* frames one and higher get a saturated background */
295           immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2));
296           immRectf(pos,
297                    v2d->cur.xmin,
298                    (float)y - ACHANNEL_HEIGHT_HALF(ac),
299                    v2d->cur.xmax + EXTRA_SCROLL_PAD,
300                    (float)y + ACHANNEL_HEIGHT_HALF(ac));
301         }
302         else if (ac->datatype == ANIMCONT_MASK) {
303           /* TODO --- this is a copy of gpencil */
304           /* frames less than one get less saturated background */
305           unsigned char *color = sel ? col1 : col2;
306           immUniformColor4ubv(color);
307           immRectf(pos,
308                    0.0f,
309                    (float)y - ACHANNEL_HEIGHT_HALF(ac),
310                    v2d->cur.xmin,
311                    (float)y + ACHANNEL_HEIGHT_HALF(ac));
312
313           /* frames one and higher get a saturated background */
314           immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2));
315           immRectf(pos,
316                    v2d->cur.xmin,
317                    (float)y - ACHANNEL_HEIGHT_HALF(ac),
318                    v2d->cur.xmax + EXTRA_SCROLL_PAD,
319                    (float)y + ACHANNEL_HEIGHT_HALF(ac));
320         }
321       }
322     }
323
324     /* Increment the step */
325     y -= ACHANNEL_STEP(ac);
326   }
327   GPU_blend(false);
328
329   /* black line marking 'current frame' for Time-Slide transform mode */
330   if (saction->flag & SACTION_MOVING) {
331     immUniformColor3f(0.0f, 0.0f, 0.0f);
332
333     immBegin(GPU_PRIM_LINES, 2);
334     immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
335     immVertex2f(pos, saction->timeslide, v2d->cur.ymax);
336     immEnd();
337   }
338   immUnbindProgram();
339
340   /* Draw keyframes
341    * 1) Only channels that are visible in the Action Editor get drawn/evaluated.
342    *    This is to try to optimize this for heavier data sets
343    * 2) Keyframes which are out of view horizontally are disregarded
344    */
345   y = (float)(-ACHANNEL_HEIGHT(ac));
346
347   int action_flag = saction->flag;
348
349   if (saction->mode == SACTCONT_TIMELINE) {
350     action_flag &= ~(SACTION_SHOW_INTERPOLATION | SACTION_SHOW_EXTREMES);
351   }
352
353   for (ale = anim_data.first; ale; ale = ale->next) {
354     const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
355     const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
356
357     /* check if visible */
358     if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
359         IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) {
360       /* check if anything to show for this channel */
361       if (ale->datatype != ALE_NONE) {
362         adt = ANIM_nla_mapping_get(ac, ale);
363
364         /* draw 'keyframes' for each specific datatype */
365         switch (ale->datatype) {
366           case ALE_ALL:
367             draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, action_flag);
368             break;
369           case ALE_SCE:
370             draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag);
371             break;
372           case ALE_OB:
373             draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag);
374             break;
375           case ALE_ACT:
376             draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag);
377             break;
378           case ALE_GROUP:
379             draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, action_flag);
380             break;
381           case ALE_FCURVE:
382             draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag);
383             break;
384           case ALE_GPFRAME:
385             draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag);
386             break;
387           case ALE_MASKLAY:
388             draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag);
389             break;
390         }
391       }
392     }
393
394     y -= ACHANNEL_STEP(ac);
395   }
396
397   /* free temporary channels used for drawing */
398   ANIM_animdata_freelist(&anim_data);
399 }
400
401 /* ************************************************************************* */
402 /* Timeline - Caches */
403
404 void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene)
405 {
406   PTCacheID *pid;
407   ListBase pidlist;
408   const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
409   float yoffs = 0.f;
410
411   if (!(saction->cache_display & TIME_CACHE_DISPLAY) || (!ob)) {
412     return;
413   }
414
415   BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
416
417   uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
418   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
419
420   /* iterate over pointcaches on the active object, and draw each one's range */
421   for (pid = pidlist.first; pid; pid = pid->next) {
422     float col[4];
423
424     switch (pid->type) {
425       case PTCACHE_TYPE_SOFTBODY:
426         if (!(saction->cache_display & TIME_CACHE_SOFTBODY)) {
427           continue;
428         }
429         break;
430       case PTCACHE_TYPE_PARTICLES:
431         if (!(saction->cache_display & TIME_CACHE_PARTICLES)) {
432           continue;
433         }
434         break;
435       case PTCACHE_TYPE_CLOTH:
436         if (!(saction->cache_display & TIME_CACHE_CLOTH)) {
437           continue;
438         }
439         break;
440       case PTCACHE_TYPE_SMOKE_DOMAIN:
441       case PTCACHE_TYPE_SMOKE_HIGHRES:
442         if (!(saction->cache_display & TIME_CACHE_SMOKE)) {
443           continue;
444         }
445         break;
446       case PTCACHE_TYPE_DYNAMICPAINT:
447         if (!(saction->cache_display & TIME_CACHE_DYNAMICPAINT)) {
448           continue;
449         }
450         break;
451       case PTCACHE_TYPE_RIGIDBODY:
452         if (!(saction->cache_display & TIME_CACHE_RIGIDBODY)) {
453           continue;
454         }
455         break;
456     }
457
458     if (pid->cache->cached_frames == NULL) {
459       continue;
460     }
461
462     GPU_matrix_push();
463     GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_TEXT + yoffs);
464     GPU_matrix_scale_2f(1.0, cache_draw_height);
465
466     switch (pid->type) {
467       case PTCACHE_TYPE_SOFTBODY:
468         col[0] = 1.0;
469         col[1] = 0.4;
470         col[2] = 0.02;
471         col[3] = 0.1;
472         break;
473       case PTCACHE_TYPE_PARTICLES:
474         col[0] = 1.0;
475         col[1] = 0.1;
476         col[2] = 0.02;
477         col[3] = 0.1;
478         break;
479       case PTCACHE_TYPE_CLOTH:
480         col[0] = 0.1;
481         col[1] = 0.1;
482         col[2] = 0.75;
483         col[3] = 0.1;
484         break;
485       case PTCACHE_TYPE_SMOKE_DOMAIN:
486       case PTCACHE_TYPE_SMOKE_HIGHRES:
487         col[0] = 0.2;
488         col[1] = 0.2;
489         col[2] = 0.2;
490         col[3] = 0.1;
491         break;
492       case PTCACHE_TYPE_DYNAMICPAINT:
493         col[0] = 1.0;
494         col[1] = 0.1;
495         col[2] = 0.75;
496         col[3] = 0.1;
497         break;
498       case PTCACHE_TYPE_RIGIDBODY:
499         col[0] = 1.0;
500         col[1] = 0.6;
501         col[2] = 0.0;
502         col[3] = 0.1;
503         break;
504       default:
505         col[0] = 1.0;
506         col[1] = 0.0;
507         col[2] = 1.0;
508         col[3] = 0.1;
509         BLI_assert(0);
510         break;
511     }
512
513     const int sta = pid->cache->startframe, end = pid->cache->endframe;
514
515     GPU_blend(true);
516
517     immUniformColor4fv(col);
518     immRectf(pos, (float)sta, 0.0, (float)end, 1.0);
519
520     col[3] = 0.4f;
521     if (pid->cache->flag & PTCACHE_BAKED) {
522       col[0] -= 0.4f;
523       col[1] -= 0.4f;
524       col[2] -= 0.4f;
525     }
526     else if (pid->cache->flag & PTCACHE_OUTDATED) {
527       col[0] += 0.4f;
528       col[1] += 0.4f;
529       col[2] += 0.4f;
530     }
531
532     immUniformColor4fv(col);
533
534     {
535       /* draw a quad for each chunk of consecutive cached frames */
536       const int chunk_tot = 32;
537       int chunk_len = 0;
538       int ista = 0, iend = -1;
539
540       for (int i = sta; i <= end; i++) {
541         if (pid->cache->cached_frames[i - sta]) {
542           if (chunk_len == 0) {
543             immBeginAtMost(GPU_PRIM_TRIS, chunk_tot * 6);
544           }
545           if (ista > iend) {
546             chunk_len++;
547             ista = i;
548           }
549           iend = i;
550         }
551         else {
552           if (ista <= iend) {
553             immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f);
554             iend = ista - 1;
555           }
556           if (chunk_len >= chunk_tot) {
557             immEnd();
558             chunk_len = 0;
559           }
560         }
561       }
562       if (ista <= iend) {
563         immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f);
564       }
565       if (chunk_len != 0) {
566         immEnd();
567       }
568     }
569
570     GPU_blend(false);
571
572     GPU_matrix_pop();
573
574     yoffs += cache_draw_height;
575   }
576
577   immUnbindProgram();
578
579   BLI_freelistN(&pidlist);
580 }
581
582 /* ************************************************************************* */