WM: refactor gestures for use as tools
[blender.git] / source / blender / editors / space_view3d / drawanimviz.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) 2009 by the Blender Foundation.
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_view3d/drawanimviz.c
29  *  \ingroup spview3d
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #include "BLI_sys_types.h"
38
39 #include "DNA_anim_types.h"
40 #include "DNA_armature_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_screen_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_object_types.h"
45
46 #include "BLI_math.h"
47 #include "BLI_dlrbTree.h"
48
49 #include "BKE_animsys.h"
50 #include "BKE_action.h"
51
52 #include "BIF_gl.h"
53
54 #include "ED_keyframes_draw.h"
55
56
57 #include "UI_resources.h"
58
59 #include "view3d_intern.h"
60
61 /* ************************************ Motion Paths ************************************* */
62
63 /* TODO:
64  * - options to draw paths with lines
65  * - include support for editing the path verts */
66
67 /* Set up drawing environment for drawing motion paths */
68 void draw_motion_paths_init(View3D *v3d, ARegion *ar) 
69 {
70         RegionView3D *rv3d = ar->regiondata;
71         
72         if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
73         
74         glPushMatrix();
75         glLoadMatrixf(rv3d->viewmat);
76 }
77
78 /* set color
79 * - more intense for active/selected bones, less intense for unselected bones
80 * - black for before current frame, green for current frame, blue for after current frame
81 * - intensity decreases as distance from current frame increases
82 *
83 * If the user select custom color, the color is replaced for the color selected in UI panel
84 * - 75% Darker color is used for previous frames
85 * - 50% Darker color for current frame
86 * - User selected color for next frames
87 */
88 static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra,
89         float prev_color[3], float frame_color[3], float next_color[3])
90 {
91         int frame = sfra + i;
92         int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
93
94 #define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
95         float intensity;  /* how faint */
96
97         if (frame < CFRA) {
98                 if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
99                         /* Custom color: previous frames color is darker than current frame */
100                         glColor3fv(prev_color);  
101                 }
102                 else {
103                         /* black - before cfra */
104                         if (sel) {
105                                 /* intensity = 0.5f; */
106                                 intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f);
107                         }
108                         else {
109                                 /* intensity = 0.8f; */
110                                 intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f);
111                         }
112                         UI_ThemeColorBlend(TH_WIRE, blend_base, intensity);
113                 }
114         }
115         else if (frame > CFRA) {
116                 if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
117                         /* Custom color: next frames color is equal to user selected color */
118                         glColor3fv(next_color);  
119                 }
120                 else {
121                         /* blue - after cfra */
122                         if (sel) {
123                                 /* intensity = 0.5f; */
124                                 intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f);
125                         }
126                         else {
127                                 /* intensity = 0.8f; */
128                                 intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f);
129                         }
130                         UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity);
131                 }
132         }
133         else {
134                 if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
135                         /* Custom color: current frame color is slightly darker than user selected color */
136                         glColor3fv(frame_color);  
137                 }
138                 else {
139                         /* green - on cfra */
140                         if (sel) {
141                                 intensity = 0.5f;
142                         }
143                         else {
144                                 intensity = 0.99f;
145                         }
146                         UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
147                 }
148         }
149 #undef SET_INTENSITY
150 }
151
152 /* Draw the given motion path for an Object or a Bone 
153  *  - assumes that the viewport has already been initialized properly
154  *    i.e. draw_motion_paths_init() has been called
155  */
156 void draw_motion_path_instance(Scene *scene, 
157                                Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath)
158 {
159         //RegionView3D *rv3d = ar->regiondata;
160         bMotionPathVert *mpv, *mpv_start;
161         int i, stepsize = avs->path_step;
162         int sfra, efra, sind, len;
163         float prev_color[3];
164         float frame_color[3];
165         float next_color[3];
166
167         /* Custom color - Previous frames: color is darker than current frame */
168         prev_color[0] = mpath->color[0] * 0.25f;
169         prev_color[1] = mpath->color[1] * 0.25f;
170         prev_color[2] = mpath->color[2] * 0.25f;
171
172         /* Custom color - Current frame: color is slightly darker than user selected color */
173         frame_color[0] = mpath->color[0] * 0.50f;
174         frame_color[1] = mpath->color[1] * 0.50f;
175         frame_color[2] = mpath->color[2] * 0.50f;
176
177         /* Custom color - Next frames: color is equal to user selection */
178         next_color[0] = mpath->color[0];
179         next_color[1] = mpath->color[1];
180         next_color[2] = mpath->color[2];
181
182         /* Save old line width */
183         GLfloat old_width;
184         glGetFloatv(GL_LINE_WIDTH, &old_width);
185         
186         /* get frame ranges */
187         if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
188                 /* With "Around Current", we only choose frames from around 
189                  * the current frame to draw.
190                  */
191                 sfra = CFRA - avs->path_bc;
192                 efra = CFRA + avs->path_ac;
193         }
194         else {
195                 /* Use the current display range */
196                 sfra = avs->path_sf;
197                 efra = avs->path_ef;
198         }
199         
200         /* no matter what, we can only show what is in the cache and no more 
201          * - abort if whole range is past ends of path
202          * - otherwise clamp endpoints to extents of path
203          */
204         if (sfra < mpath->start_frame) {
205                 /* start clamp */
206                 sfra = mpath->start_frame;
207         }
208         if (efra > mpath->end_frame) {
209                 /* end clamp */
210                 efra = mpath->end_frame;
211         }
212         
213         if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) {
214                 /* whole path is out of bounds */
215                 return;
216         }
217         
218         len = efra - sfra;
219         
220         if ((len <= 0) || (mpath->points == NULL)) {
221                 return;
222         }
223         
224         /* get pointers to parts of path */
225         sind = sfra - mpath->start_frame;
226         mpv_start = (mpath->points + sind);
227         
228         /* draw curve-line of path */
229         /* Draw lines only if line drawing option is enabled */
230         if (mpath->flag & MOTIONPATH_FLAG_LINES) {
231                 /* set line thickness */
232                 glLineWidth(mpath->line_thickness);
233
234                 glBegin(GL_LINE_STRIP);
235                 for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
236                         short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
237                         /* Set color */
238                         set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color);
239                         /* draw a vertex with this color */
240                         glVertex3fv(mpv->co);
241                 }
242
243                 glEnd();
244                 /* back to old line thickness */
245                 glLineWidth(old_width);
246         }
247
248         /* Point must be bigger than line thickness */
249         glPointSize(mpath->line_thickness + 1.0);
250         
251         /* draw little black point at each frame
252          * NOTE: this is not really visible/noticeable
253          */
254         glBegin(GL_POINTS);
255         for (i = 0, mpv = mpv_start; i < len; i++, mpv++)
256                 glVertex3fv(mpv->co);
257         glEnd();
258         
259         /* Draw little white dots at each framestep value or replace with custom color */
260         if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
261                 glColor4fv(mpath->color);
262         }
263         else {
264                 UI_ThemeColor(TH_TEXT_HI);
265         }
266         glBegin(GL_POINTS);
267         for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize)
268                 glVertex3fv(mpv->co);
269         glEnd();
270         
271         /* Draw big green dot where the current frame is 
272          * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
273          */
274         if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) &&
275             (sfra < CFRA) && (CFRA <= efra)) 
276         {
277                 UI_ThemeColor(TH_CFRAME);
278                 
279                 glPointSize(mpath->line_thickness + 5.0);
280                 glBegin(GL_POINTS);
281                 mpv = mpv_start + (CFRA - sfra);
282                 glVertex3fv(mpv->co);
283                 glEnd();
284                 
285                 UI_ThemeColor(TH_TEXT_HI);
286         }
287         
288         /* XXX, this isn't up to date but probably should be kept so. */
289         invert_m4_m4(ob->imat, ob->obmat);
290         
291         /* Draw frame numbers at each framestep value */
292         if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) {
293                 unsigned char col[4];
294                 UI_GetThemeColor3ubv(TH_TEXT_HI, col);
295                 col[3] = 255;
296                 
297                 for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) {
298                         int frame = sfra + i;
299                         char numstr[32];
300                         size_t numstr_len;
301                         float co[3];
302                         
303                         /* only draw framenum if several consecutive highlighted points don't occur on same point */
304                         if (i == 0) {
305                                 numstr_len = sprintf(numstr, " %d", frame);
306                                 mul_v3_m4v3(co, ob->imat, mpv->co);
307                                 view3d_cached_text_draw_add(co, numstr, numstr_len,
308                                                             0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col);
309                         }
310                         else if ((i >= stepsize) && (i < len - stepsize)) {
311                                 bMotionPathVert *mpvP = (mpv - stepsize);
312                                 bMotionPathVert *mpvN = (mpv + stepsize);
313                                 
314                                 if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
315                                         numstr_len = sprintf(numstr, " %d", frame);
316                                         mul_v3_m4v3(co, ob->imat, mpv->co);
317                                         view3d_cached_text_draw_add(co, numstr, numstr_len,
318                                                                     0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col);
319                                 }
320                         }
321                 }
322         }
323         
324         /* Keyframes - dots and numbers */
325         if (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) {
326                 unsigned char col[4];
327                 
328                 AnimData *adt = BKE_animdata_from_id(&ob->id);
329                 DLRBT_Tree keys;
330                 
331                 /* build list of all keyframes in active action for object or pchan */
332                 BLI_dlrbTree_init(&keys);
333                 
334                 if (adt) {
335                         /* it is assumed that keyframes for bones are all grouped in a single group
336                          * unless an option is set to always use the whole action
337                          */
338                         if ((pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
339                                 bActionGroup *agrp = BKE_action_group_find_name(adt->action, pchan->name);
340                                 
341                                 if (agrp) {
342                                         agroup_to_keylist(adt, agrp, &keys, NULL);
343                                         BLI_dlrbTree_linkedlist_sync(&keys);
344                                 }
345                         }
346                         else {
347                                 action_to_keylist(adt, adt->action, &keys, NULL);
348                                 BLI_dlrbTree_linkedlist_sync(&keys);
349                         }
350                 }
351                 
352                 /* Draw slightly-larger yellow dots at each keyframe */
353                 UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
354                 col[3] = 255;
355                 
356                 /* if custom, point must be bigger than line */
357                 if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
358                         glPointSize(mpath->line_thickness + 3.0);
359                 }
360                 else {
361                         glPointSize(4.0f);
362                 }
363                 glColor3ubv(col);
364                 
365                 glBegin(GL_POINTS);
366                 for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
367                         int    frame = sfra + i; 
368                         float mframe = (float)(frame);
369                         
370                         if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe))
371                                 glVertex3fv(mpv->co);
372                 }
373                 glEnd();
374                 
375                 /* Draw frame numbers of keyframes  */
376                 if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) {
377                         float co[3];
378                         for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
379                                 float mframe = (float)(sfra + i);
380                                 
381                                 if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) {
382                                         char numstr[32];
383                                         size_t numstr_len;
384                                         
385                                         numstr_len = sprintf(numstr, " %d", (sfra + i));
386                                         mul_v3_m4v3(co, ob->imat, mpv->co);
387                                         view3d_cached_text_draw_add(co, numstr, numstr_len,
388                                                                     0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col);
389                                 }
390                         }
391                 }
392                 
393                 BLI_dlrbTree_free(&keys);
394         }
395 }
396
397 /* Clean up drawing environment after drawing motion paths */
398 void draw_motion_paths_cleanup(View3D *v3d)
399 {
400         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
401         glPopMatrix();
402 }