Blender  V2.59
action_draw.c
Go to the documentation of this file.
00001 /*
00002  * $Id: action_draw.c 35242 2011-02-27 20:29:51Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Joshua Leung
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 /* System includes ----------------------------------------------------- */
00036 
00037 #include <math.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <float.h>
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_math.h"
00044 #include "BLI_utildefines.h"
00045 
00046 /* Types --------------------------------------------------------------- */
00047 
00048 #include "DNA_anim_types.h"
00049 #include "DNA_screen_types.h"
00050 
00051 #include "BKE_action.h"
00052 #include "BKE_context.h"
00053 
00054 
00055 /* Everything from source (BIF, BDR, BSE) ------------------------------ */ 
00056 
00057 #include "BIF_gl.h"
00058 
00059 #include "UI_interface.h"
00060 #include "UI_resources.h"
00061 #include "UI_view2d.h"
00062 
00063 #include "ED_anim_api.h"
00064 #include "ED_keyframes_draw.h"
00065 
00066 #include "action_intern.h"
00067 
00068 /* ************************************************************************* */
00069 /* Channel List */
00070 
00071 /* left hand part */
00072 void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) 
00073 {
00074         ListBase anim_data = {NULL, NULL};
00075         bAnimListElem *ale;
00076         int filter;
00077         
00078         View2D *v2d= &ar->v2d;
00079         float y= 0.0f;
00080         int items, height;
00081         
00082         /* build list of channels to draw */
00083         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
00084         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00085         
00086         /* Update max-extent of channels here (taking into account scrollers):
00087          *      - this is done to allow the channel list to be scrollable, but must be done here
00088          *        to avoid regenerating the list again and/or also because channels list is drawn first
00089          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
00090          *        start of list offset, and the second is as a correction for the scrollers.
00091          */
00092         height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
00093         if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
00094                 /* don't use totrect set, as the width stays the same 
00095                  * (NOTE: this is ok here, the configuration is pretty straightforward) 
00096                  */
00097                 v2d->tot.ymin= (float)(-height);
00098         }
00099         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
00100         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
00101         
00102         /* loop through channels, and set up drawing depending on their type  */        
00103         {       /* first pass: just the standard GL-drawing for backdrop + text */
00104                 y= (float)ACHANNEL_FIRST;
00105                 
00106                 for (ale= anim_data.first; ale; ale= ale->next) {
00107                         float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
00108                         float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
00109                         
00110                         /* check if visible */
00111                         if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
00112                                  IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
00113                         {
00114                                 /* draw all channels using standard channel-drawing API */
00115                                 ANIM_channel_draw(ac, ale, yminc, ymaxc);
00116                         }
00117                         
00118                         /* adjust y-position for next one */
00119                         y -= ACHANNEL_STEP;
00120                 }
00121         }
00122         {       /* second pass: widgets */
00123                 uiBlock *block= uiBeginBlock(C, ar, "dopesheet channel buttons", UI_EMBOSS);
00124                 
00125                 y= (float)ACHANNEL_FIRST;
00126                 
00127                 for (ale= anim_data.first; ale; ale= ale->next) {
00128                         float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
00129                         float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
00130                         
00131                         /* check if visible */
00132                         if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
00133                                  IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
00134                         {
00135                                 /* draw all channels using standard channel-drawing API */
00136                                 ANIM_channel_draw_widgets(ac, ale, block, yminc, ymaxc);
00137                         }
00138                         
00139                         /* adjust y-position for next one */
00140                         y -= ACHANNEL_STEP;
00141                 }
00142                 
00143                 uiEndBlock(C, block);
00144                 uiDrawBlock(C, block);
00145         }
00146         
00147         /* free tempolary channels */
00148         BLI_freelistN(&anim_data);
00149 }
00150 
00151 /* ************************************************************************* */
00152 /* Keyframes */
00153 
00154 /* extra padding for lengths (to go under scrollers) */
00155 #define EXTRA_SCROLL_PAD        100.0f
00156 
00157 /* draw keyframes in each channel */
00158 void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
00159 {
00160         ListBase anim_data = {NULL, NULL};
00161         bAnimListElem *ale;
00162         int filter;
00163         
00164         View2D *v2d= &ar->v2d;
00165         bDopeSheet *ads= &saction->ads;
00166         AnimData *adt= NULL;
00167         
00168         float act_start, act_end, y;
00169         int height, items;
00170         
00171         unsigned char col1[3], col2[3];
00172         unsigned char col1a[3], col2a[3];
00173         unsigned char col1b[3], col2b[3];
00174         
00175         
00176         /* get theme colors */
00177         UI_GetThemeColor3ubv(TH_BACK, col2);
00178         UI_GetThemeColor3ubv(TH_HILITE, col1);
00179         
00180         UI_GetThemeColor3ubv(TH_GROUP, col2a);
00181         UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
00182         
00183         UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
00184         UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
00185         
00186         /* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
00187 
00188         /* if in NLA there's a strip active, map the view */
00189         if (ac->datatype == ANIMCONT_ACTION) {
00190                 adt= ANIM_nla_mapping_get(ac, NULL);
00191                 
00192                 /* start and end of action itself */
00193                 calc_action_range(ac->data, &act_start, &act_end, 0);
00194         }
00195         
00196         /* build list of channels to draw */
00197         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
00198         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00199         
00200         /* Update max-extent of channels here (taking into account scrollers):
00201          *      - this is done to allow the channel list to be scrollable, but must be done here
00202          *        to avoid regenerating the list again and/or also because channels list is drawn first
00203          *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
00204          *        start of list offset, and the second is as a correction for the scrollers.
00205          */
00206         height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
00207         /* don't use totrect set, as the width stays the same 
00208          * (NOTE: this is ok here, the configuration is pretty straightforward) 
00209          */
00210         v2d->tot.ymin= (float)(-height);
00211         
00212         /* first backdrop strips */
00213         y= (float)(-ACHANNEL_HEIGHT);
00214         glEnable(GL_BLEND);
00215         
00216         for (ale= anim_data.first; ale; ale= ale->next) {
00217                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
00218                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
00219                 
00220                 /* check if visible */
00221                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
00222                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
00223                 {
00224                         bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
00225                         int sel=0;
00226                         
00227                         /* determine if any need to draw channel */
00228                         if (ale->datatype != ALE_NONE) {
00229                                 /* determine if channel is selected */
00230                                 if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
00231                                         sel= ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
00232                                 
00233                                 if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
00234                                         switch (ale->type) {
00235                                                 case ANIMTYPE_SUMMARY:
00236                                                 {
00237                                                         // FIXME: hardcoded colors - reddish color from NLA
00238                                                         glColor4f(0.8f, 0.2f, 0.0f, 0.4f);
00239                                                 }
00240                                                         break;
00241                                                 
00242                                                 case ANIMTYPE_SCENE:
00243                                                 case ANIMTYPE_OBJECT:
00244                                                 {
00245                                                         if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); 
00246                                                         else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); 
00247                                                 }
00248                                                         break;
00249                                                 
00250                                                 case ANIMTYPE_FILLACTD:
00251                                                 case ANIMTYPE_FILLMATD:
00252                                                 case ANIMTYPE_FILLPARTD:
00253                                                 case ANIMTYPE_DSSKEY:
00254                                                 case ANIMTYPE_DSWOR:
00255                                                 {
00256                                                         if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); 
00257                                                         else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); 
00258                                                 }
00259                                                         break;
00260                                                 
00261                                                 case ANIMTYPE_GROUP:
00262                                                 {
00263                                                         if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
00264                                                         else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
00265                                                 }
00266                                                         break;
00267                                                 
00268                                                 default:
00269                                                 {
00270                                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
00271                                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
00272                                                 }
00273                                                         break;
00274                                         }
00275                                         
00276                                         /* draw region twice: firstly backdrop, then the current range */
00277                                         glRectf(v2d->cur.xmin,  (float)y-ACHANNEL_HEIGHT_HALF,  v2d->cur.xmax+EXTRA_SCROLL_PAD,  (float)y+ACHANNEL_HEIGHT_HALF);
00278                                         
00279                                         if (ac->datatype == ANIMCONT_ACTION)
00280                                                 glRectf(act_start,  (float)y-ACHANNEL_HEIGHT_HALF,  act_end,  (float)y+ACHANNEL_HEIGHT_HALF);
00281                                 }
00282                                 else if (ac->datatype == ANIMCONT_GPENCIL) {
00283                                         /* frames less than one get less saturated background */
00284                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
00285                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
00286                                         glRectf(0.0f, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y+ACHANNEL_HEIGHT_HALF);
00287                                         
00288                                         /* frames one and higher get a saturated background */
00289                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
00290                                         else glColor4ub(col2[0], col2[1], col2[2], 0x44);
00291                                         glRectf(v2d->cur.xmin, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmax+EXTRA_SCROLL_PAD,  (float)y+ACHANNEL_HEIGHT_HALF);
00292                                 }
00293                         }
00294                 }
00295                 
00296                 /*      Increment the step */
00297                 y -= ACHANNEL_STEP;
00298         }               
00299         glDisable(GL_BLEND);
00300         
00301         /* Draw keyframes 
00302          *      1) Only channels that are visible in the Action Editor get drawn/evaluated.
00303          *         This is to try to optimise this for heavier data sets
00304          *      2) Keyframes which are out of view horizontally are disregarded 
00305          */
00306         y= (float)(-ACHANNEL_HEIGHT);
00307         
00308         for (ale= anim_data.first; ale; ale= ale->next) {
00309                 const float yminc= (float)(y - ACHANNEL_HEIGHT_HALF);
00310                 const float ymaxc= (float)(y + ACHANNEL_HEIGHT_HALF);
00311                 
00312                 /* check if visible */
00313                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
00314                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
00315                 {
00316                         /* check if anything to show for this channel */
00317                         if (ale->datatype != ALE_NONE) {
00318                                 adt= ANIM_nla_mapping_get(ac, ale);
00319                                 
00320                                 /* draw 'keyframes' for each specific datatype */
00321                                 switch (ale->datatype) {
00322                                         case ALE_ALL:
00323                                                 draw_summary_channel(v2d, ale->data, y);
00324                                                 break;
00325                                         case ALE_SCE:
00326                                                 draw_scene_channel(v2d, ads, ale->key_data, y);
00327                                                 break;
00328                                         case ALE_OB:
00329                                                 draw_object_channel(v2d, ads, ale->key_data, y);
00330                                                 break;
00331                                         case ALE_ACT:
00332                                                 draw_action_channel(v2d, adt, ale->key_data, y);
00333                                                 break;
00334                                         case ALE_GROUP:
00335                                                 draw_agroup_channel(v2d, adt, ale->data, y);
00336                                                 break;
00337                                         case ALE_FCURVE:
00338                                                 draw_fcurve_channel(v2d, adt, ale->key_data, y);
00339                                                 break;
00340                                         case ALE_GPFRAME:
00341                                                 draw_gpl_channel(v2d, ads, ale->data, y);
00342                                                 break;
00343                                 }
00344                         }
00345                 }
00346                 
00347                 y-= ACHANNEL_STEP;
00348         }
00349         
00350         /* free tempolary channels used for drawing */
00351         BLI_freelistN(&anim_data);
00352 
00353         /* black line marking 'current frame' for Time-Slide transform mode */
00354         if (saction->flag & SACTION_MOVING) {
00355                 glColor3f(0.0f, 0.0f, 0.0f);
00356                 
00357                 glBegin(GL_LINES);
00358                         glVertex2f(saction->timeslide, v2d->cur.ymin-EXTRA_SCROLL_PAD);
00359                         glVertex2f(saction->timeslide, v2d->cur.ymax);
00360                 glEnd();
00361         }
00362 }