4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): Joshua Leung
27 * ***** END GPL LICENSE BLOCK *****
30 /** \file blender/editors/space_action/action_draw.c
35 /* System includes ----------------------------------------------------- */
42 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
46 /* Types --------------------------------------------------------------- */
48 #include "DNA_anim_types.h"
49 #include "DNA_screen_types.h"
51 #include "BKE_action.h"
52 #include "BKE_context.h"
55 /* Everything from source (BIF, BDR, BSE) ------------------------------ */
59 #include "UI_interface.h"
60 #include "UI_resources.h"
61 #include "UI_view2d.h"
63 #include "ED_anim_api.h"
64 #include "ED_keyframes_draw.h"
66 #include "action_intern.h"
68 /* ************************************************************************* */
72 void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
74 ListBase anim_data = {NULL, NULL};
78 View2D *v2d= &ar->v2d;
82 /* build list of channels to draw */
83 filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
84 items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
86 /* Update max-extent of channels here (taking into account scrollers):
87 * - this is done to allow the channel list to be scrollable, but must be done here
88 * to avoid regenerating the list again and/or also because channels list is drawn first
89 * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
90 * start of list offset, and the second is as a correction for the scrollers.
92 height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
93 if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
94 /* don't use totrect set, as the width stays the same
95 * (NOTE: this is ok here, the configuration is pretty straightforward)
97 v2d->tot.ymin= (float)(-height);
99 /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
100 UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
102 /* loop through channels, and set up drawing depending on their type */
103 { /* first pass: just the standard GL-drawing for backdrop + text */
104 y= (float)ACHANNEL_FIRST;
106 for (ale= anim_data.first; ale; ale= ale->next) {
107 float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
108 float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
110 /* check if visible */
111 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
112 IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
114 /* draw all channels using standard channel-drawing API */
115 ANIM_channel_draw(ac, ale, yminc, ymaxc);
118 /* adjust y-position for next one */
122 { /* second pass: widgets */
123 uiBlock *block= uiBeginBlock(C, ar, "dopesheet channel buttons", UI_EMBOSS);
125 y= (float)ACHANNEL_FIRST;
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);
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) )
135 /* draw all channels using standard channel-drawing API */
136 ANIM_channel_draw_widgets(ac, ale, block, yminc, ymaxc);
139 /* adjust y-position for next one */
143 uiEndBlock(C, block);
144 uiDrawBlock(C, block);
147 /* free tempolary channels */
148 BLI_freelistN(&anim_data);
151 /* ************************************************************************* */
154 /* extra padding for lengths (to go under scrollers) */
155 #define EXTRA_SCROLL_PAD 100.0f
157 /* draw keyframes in each channel */
158 void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
160 ListBase anim_data = {NULL, NULL};
164 View2D *v2d= &ar->v2d;
165 bDopeSheet *ads= &saction->ads;
168 float act_start, act_end, y;
171 unsigned char col1[3], col2[3];
172 unsigned char col1a[3], col2a[3];
173 unsigned char col1b[3], col2b[3];
176 /* get theme colors */
177 UI_GetThemeColor3ubv(TH_BACK, col2);
178 UI_GetThemeColor3ubv(TH_HILITE, col1);
180 UI_GetThemeColor3ubv(TH_GROUP, col2a);
181 UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
183 UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
184 UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
186 /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
188 /* if in NLA there's a strip active, map the view */
189 if (ac->datatype == ANIMCONT_ACTION) {
190 adt= ANIM_nla_mapping_get(ac, NULL);
192 /* start and end of action itself */
193 calc_action_range(ac->data, &act_start, &act_end, 0);
196 /* build list of channels to draw */
197 filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
198 items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
200 /* Update max-extent of channels here (taking into account scrollers):
201 * - this is done to allow the channel list to be scrollable, but must be done here
202 * to avoid regenerating the list again and/or also because channels list is drawn first
203 * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
204 * start of list offset, and the second is as a correction for the scrollers.
206 height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
207 /* don't use totrect set, as the width stays the same
208 * (NOTE: this is ok here, the configuration is pretty straightforward)
210 v2d->tot.ymin= (float)(-height);
212 /* first backdrop strips */
213 y= (float)(-ACHANNEL_HEIGHT);
216 for (ale= anim_data.first; ale; ale= ale->next) {
217 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
218 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
220 /* check if visible */
221 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
222 IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
224 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
227 /* determine if any need to draw channel */
228 if (ale->datatype != ALE_NONE) {
229 /* determine if channel is selected */
230 if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
231 sel= ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
233 if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
235 case ANIMTYPE_SUMMARY:
237 // FIXME: hardcoded colors - reddish color from NLA
238 glColor4f(0.8f, 0.2f, 0.0f, 0.4f);
243 case ANIMTYPE_OBJECT:
245 if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45);
246 else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22);
250 case ANIMTYPE_FILLACTD:
251 case ANIMTYPE_FILLMATD:
252 case ANIMTYPE_FILLPARTD:
253 case ANIMTYPE_DSSKEY:
256 if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45);
257 else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22);
263 if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
264 else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
270 if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
271 else glColor4ub(col2[0], col2[1], col2[2], 0x22);
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);
279 if (ac->datatype == ANIMCONT_ACTION)
280 glRectf(act_start, (float)y-ACHANNEL_HEIGHT_HALF, act_end, (float)y+ACHANNEL_HEIGHT_HALF);
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);
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);
296 /* Increment the step */
302 * 1) Only channels that are visible in the Action Editor get drawn/evaluated.
303 * This is to try to optimise this for heavier data sets
304 * 2) Keyframes which are out of view horizontally are disregarded
306 y= (float)(-ACHANNEL_HEIGHT);
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);
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) )
316 /* check if anything to show for this channel */
317 if (ale->datatype != ALE_NONE) {
318 adt= ANIM_nla_mapping_get(ac, ale);
320 /* draw 'keyframes' for each specific datatype */
321 switch (ale->datatype) {
323 draw_summary_channel(v2d, ale->data, y);
326 draw_scene_channel(v2d, ads, ale->key_data, y);
329 draw_object_channel(v2d, ads, ale->key_data, y);
332 draw_action_channel(v2d, adt, ale->key_data, y);
335 draw_agroup_channel(v2d, adt, ale->data, y);
338 draw_fcurve_channel(v2d, adt, ale->key_data, y);
341 draw_gpl_channel(v2d, ads, ale->data, y);
350 /* free tempolary channels used for drawing */
351 BLI_freelistN(&anim_data);
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);
358 glVertex2f(saction->timeslide, v2d->cur.ymin-EXTRA_SCROLL_PAD);
359 glVertex2f(saction->timeslide, v2d->cur.ymax);