2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Joshua Leung
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/space_action/action_draw.c
33 /* System includes ----------------------------------------------------- */
40 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
43 /* Types --------------------------------------------------------------- */
45 #include "DNA_anim_types.h"
46 #include "DNA_screen_types.h"
48 #include "BKE_action.h"
49 #include "BKE_context.h"
52 /* Everything from source (BIF, BDR, BSE) ------------------------------ */
56 #include "UI_interface.h"
57 #include "UI_resources.h"
58 #include "UI_view2d.h"
60 #include "ED_anim_api.h"
61 #include "ED_keyframes_draw.h"
63 #include "action_intern.h"
64 #include "GPU_immediate.h"
66 /* ************************************************************************* */
70 void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
72 ListBase anim_data = {NULL, NULL};
76 View2D *v2d = &ar->v2d;
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);
85 height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
86 if (height > BLI_rcti_size_y(&v2d->mask)) {
87 /* don't use totrect set, as the width stays the same
88 * (NOTE: this is ok here, the configuration is pretty straightforward)
90 v2d->tot.ymin = (float)(-height);
92 /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
93 UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
95 /* loop through channels, and set up drawing depending on their type */
96 { /* first pass: just the standard GL-drawing for backdrop + text */
97 size_t channel_index = 0;
99 y = (float)ACHANNEL_FIRST(ac);
101 for (ale = anim_data.first; ale; ale = ale->next) {
102 float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
103 float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
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) )
109 /* draw all channels using standard channel-drawing API */
110 ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
113 /* adjust y-position for next one */
114 y -= ACHANNEL_STEP(ac);
118 { /* second pass: widgets */
119 uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
120 size_t channel_index = 0;
122 y = (float)ACHANNEL_FIRST(ac);
124 for (ale = anim_data.first; ale; ale = ale->next) {
125 float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
126 float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
128 /* check if visible */
129 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
130 IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
132 /* draw all channels using standard channel-drawing API */
133 ANIM_channel_draw_widgets(C, ac, ale, block, yminc, ymaxc, channel_index);
136 /* adjust y-position for next one */
137 y -= ACHANNEL_STEP(ac);
141 UI_block_end(C, block);
142 UI_block_draw(C, block);
145 /* free tempolary channels */
146 ANIM_animdata_freelist(&anim_data);
149 /* ************************************************************************* */
152 /* extra padding for lengths (to go under scrollers) */
153 #define EXTRA_SCROLL_PAD 100.0f
155 /* draw keyframes in each channel */
156 void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
158 ListBase anim_data = {NULL, NULL};
162 View2D *v2d = &ar->v2d;
163 bDopeSheet *ads = &saction->ads;
164 AnimData *adt = NULL;
166 float act_start, act_end, y;
170 unsigned char col1[3], col2[3];
171 unsigned char col1a[3], col2a[3];
172 unsigned char col1b[3], col2b[3];
174 const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
177 /* get theme colors */
178 UI_GetThemeColor3ubv(TH_BACK, col2);
179 UI_GetThemeColor3ubv(TH_HILITE, col1);
181 UI_GetThemeColor3ubv(TH_GROUP, col2a);
182 UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
184 UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
185 UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
187 /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
189 /* if in NLA there's a strip active, map the view */
190 if (ac->datatype == ANIMCONT_ACTION) {
191 /* adt = ANIM_nla_mapping_get(ac, NULL); */ /* UNUSED */
193 /* start and end of action itself */
194 calc_action_range(ac->data, &act_start, &act_end, 0);
197 /* build list of channels to draw */
198 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
199 items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
201 height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
202 /* don't use totrect set, as the width stays the same
203 * (NOTE: this is ok here, the configuration is pretty straightforward)
205 v2d->tot.ymin = (float)(-height);
207 /* first backdrop strips */
208 y = (float)(-ACHANNEL_HEIGHT(ac));
210 VertexFormat* format = immVertexFormat();
211 unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT);
213 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
217 for (ale = anim_data.first; ale; ale = ale->next) {
218 const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
219 const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
221 /* check if visible */
222 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
223 IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
225 const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
228 /* determine if any need to draw channel */
229 if (ale->datatype != ALE_NONE) {
230 /* determine if channel is selected */
231 if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
232 sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
234 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
236 case ANIMTYPE_SUMMARY:
238 /* reddish color from NLA */
239 UI_ThemeColor4(TH_ANIM_ACTIVE);
243 case ANIMTYPE_OBJECT:
245 if (sel) immUniformColor4ub(col1b[0], col1b[1], col1b[2], 0x45);
246 else immUniformColor4ub(col1b[0], col1b[1], col1b[2], 0x22);
249 case ANIMTYPE_FILLACTD:
250 case ANIMTYPE_DSSKEY:
253 if (sel) immUniformColor4ub(col2b[0], col2b[1], col2b[2], 0x45);
254 else immUniformColor4ub(col2b[0], col2b[1], col2b[2], 0x22);
259 bActionGroup *agrp = ale->data;
260 if (show_group_colors && agrp->customCol) {
262 unsigned char *cp = agrp->cs.select;
263 immUniformColor4ub(cp[0], cp[1], cp[2], 0x45);
266 unsigned char *cp = agrp->cs.solid;
267 immUniformColor4ub(cp[0], cp[1], cp[2], 0x1D);
271 if (sel) immUniformColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
272 else immUniformColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
276 case ANIMTYPE_FCURVE:
278 FCurve *fcu = ale->data;
279 if (show_group_colors && fcu->grp && fcu->grp->customCol) {
280 unsigned char *cp = fcu->grp->cs.active;
282 if (sel) immUniformColor4ub(cp[0], cp[1], cp[2], 0x65);
283 else immUniformColor4ub(cp[0], cp[1], cp[2], 0x0B);
286 if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22);
287 else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22);
293 if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22);
294 else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22);
299 /* draw region twice: firstly backdrop, then the current range */
300 immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
302 if (ac->datatype == ANIMCONT_ACTION)
303 immRectf(pos, act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac));
305 else if (ac->datatype == ANIMCONT_GPENCIL) {
306 /* frames less than one get less saturated background */
307 if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22);
308 else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22);
309 immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
311 /* frames one and higher get a saturated background */
312 if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x44);
313 else immUniformColor4ub(col2[0], col2[1], col2[2], 0x44);
314 immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
316 else if (ac->datatype == ANIMCONT_MASK) {
317 /* TODO --- this is a copy of gpencil */
318 /* frames less than one get less saturated background */
319 if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22);
320 else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22);
321 immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
323 /* frames one and higher get a saturated background */
324 if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x44);
325 else immUniformColor4ub(col2[0], col2[1], col2[2], 0x44);
326 immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
331 /* Increment the step */
332 y -= ACHANNEL_STEP(ac);
337 * 1) Only channels that are visible in the Action Editor get drawn/evaluated.
338 * This is to try to optimize this for heavier data sets
339 * 2) Keyframes which are out of view horizontally are disregarded
341 y = (float)(-ACHANNEL_HEIGHT(ac));
343 for (ale = anim_data.first; ale; ale = ale->next) {
344 const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
345 const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
347 /* check if visible */
348 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
349 IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
351 /* check if anything to show for this channel */
352 if (ale->datatype != ALE_NONE) {
353 adt = ANIM_nla_mapping_get(ac, ale);
355 /* draw 'keyframes' for each specific datatype */
356 switch (ale->datatype) {
358 draw_summary_channel(v2d, ale->data, y, ac->yscale_fac);
361 draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
364 draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
367 draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
370 draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac);
373 draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
376 draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac);
379 draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac);
385 y -= ACHANNEL_STEP(ac);
388 /* free tempolary channels used for drawing */
389 ANIM_animdata_freelist(&anim_data);
391 /* black line marking 'current frame' for Time-Slide transform mode */
392 if (saction->flag & SACTION_MOVING) {
393 immUniformColor3f(0.0f, 0.0f, 0.0f);
395 immBegin(GL_LINES, 2);
396 immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
397 immVertex2f(pos, saction->timeslide, v2d->cur.ymax);