Blender V4.3
anim_motion_paths.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include <cstdlib>
12
13#include "BLI_dlrbTree.h"
14#include "BLI_listbase.h"
15#include "BLI_math_matrix.h"
16#include "BLI_math_matrix.hh"
17
18#include "DNA_anim_types.h"
19#include "DNA_armature_types.h"
20#include "DNA_scene_types.h"
21
22#include "BKE_action.hh"
23#include "BKE_anim_data.hh"
24#include "BKE_main.hh"
25#include "BKE_scene.hh"
26
27#include "DEG_depsgraph.hh"
30
31#include "GPU_batch.hh"
32#include "GPU_vertex_buffer.hh"
33
34#include "ED_anim_api.hh"
36
37#include "ANIM_action_legacy.hh"
39
40#include "CLG_log.h"
41
42static CLG_LogRef LOG = {"ed.anim.motion_paths"};
43
44/* Motion path needing to be baked (mpt) */
47
48 bMotionPath *mpath; /* motion path in question */
49
50 AnimKeylist *keylist; /* temp, to know where the keyframes are */
51
52 /* Original (Source Objects) */
53 Object *ob; /* source object */
54 bPoseChannel *pchan; /* source posechannel (if applicable) */
55
56 /* "Evaluated" Copies (these come from the background evaluated copy
57 * that provide all the coordinates we want to save off). */
58 Object *ob_eval; /* evaluated object */
59};
60
61/* ........ */
62
63/* update scene for current frame */
68
69Depsgraph *animviz_depsgraph_build(Main *bmain,
70 Scene *scene,
71 ViewLayer *view_layer,
72 ListBase *targets)
73{
74 /* Allocate dependency graph. */
75 Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
76
77 /* Make a flat array of IDs for the DEG API. */
78 const int num_ids = BLI_listbase_count(targets);
79 blender::Array<ID *> ids(num_ids);
80 int current_id_index = 0;
81 for (MPathTarget *mpt = static_cast<MPathTarget *>(targets->first); mpt != nullptr;
82 mpt = mpt->next)
83 {
84 ids[current_id_index++] = &mpt->ob->id;
85 }
86
87 /* Build graph from all requested IDs. */
89
90 /* Update once so we can access pointers of evaluated animation data. */
92 return depsgraph;
93}
94
96{
97 /* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
98
99 MPathTarget *mpt;
100
101 /* object itself first */
102 if ((ob->avs.recalc & ANIMVIZ_RECALC_PATHS) && (ob->mpath)) {
103 /* new target for object */
104 mpt = static_cast<MPathTarget *>(MEM_callocN(sizeof(MPathTarget), "MPathTarget Ob"));
105 BLI_addtail(targets, mpt);
106
107 mpt->mpath = ob->mpath;
108 mpt->ob = ob;
109 }
110
111 /* bones */
112 if ((ob->pose) && (ob->pose->avs.recalc & ANIMVIZ_RECALC_PATHS)) {
113 bArmature *arm = static_cast<bArmature *>(ob->data);
114 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
115 if ((pchan->bone) && ANIM_bonecoll_is_visible_pchan(arm, pchan) && (pchan->mpath)) {
116 /* new target for bone */
117 mpt = static_cast<MPathTarget *>(MEM_callocN(sizeof(MPathTarget), "MPathTarget PoseBone"));
118 BLI_addtail(targets, mpt);
119
120 mpt->mpath = pchan->mpath;
121 mpt->ob = ob;
122 mpt->pchan = pchan;
123 }
124 }
125 }
126}
127
128/* ........ */
129
130/* perform baking for the targets on the current frame */
132 int cframe,
133 Depsgraph *depsgraph,
134 Object *camera)
135{
136 using namespace blender;
137 /* for each target, check if it can be baked on the current frame */
138 LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
139 bMotionPath *mpath = mpt->mpath;
140
141 /* current frame must be within the range the cache works for
142 * - is inclusive of the first frame, but not the last otherwise we get buffer overruns
143 */
144 if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame)) {
145 continue;
146 }
147
148 /* get the relevant cache vert to write to */
149 bMotionPathVert *mpv = mpath->points + (cframe - mpath->start_frame);
150
151 Object *ob_eval = mpt->ob_eval;
152
153 /* Lookup evaluated pose channel, here because the depsgraph
154 * evaluation can change them so they are not cached in mpt. */
155 bPoseChannel *pchan_eval = nullptr;
156 if (mpt->pchan) {
157 pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name);
158 }
159
160 /* pose-channel or object path baking? */
161 if (pchan_eval) {
162 /* heads or tails */
163 if (mpath->flag & MOTIONPATH_FLAG_BHEAD) {
164 copy_v3_v3(mpv->co, pchan_eval->pose_head);
165 }
166 else {
167 copy_v3_v3(mpv->co, pchan_eval->pose_tail);
168 }
169
170 /* Result must be in world-space. */
171 mul_m4_v3(ob_eval->object_to_world().ptr(), mpv->co);
172 }
173 else {
174 /* World-space object location. */
175 copy_v3_v3(mpv->co, ob_eval->object_to_world().location());
176 }
177
178 if (mpath->flag & MOTIONPATH_FLAG_BAKE_CAMERA && camera) {
179 Object *cam_eval = DEG_get_evaluated_object(depsgraph, camera);
180 /* Convert point to camera space. */
181 float3 co_camera_space = math::transform_point(cam_eval->world_to_object(), float3(mpv->co));
182 copy_v3_v3(mpv->co, co_camera_space);
183 }
184
185 float mframe = float(cframe);
186
187 /* Tag if it's a keyframe */
188 if (ED_keylist_find_exact(mpt->keylist, mframe)) {
190 }
191 else {
192 mpv->flag &= ~MOTIONPATH_VERT_KEY;
193 }
194
195 /* Incremental update on evaluated object if possible, for fast updating
196 * while dragging in transform. */
197 bMotionPath *mpath_eval = nullptr;
198 if (mpt->pchan) {
199 mpath_eval = (pchan_eval) ? pchan_eval->mpath : nullptr;
200 }
201 else {
202 mpath_eval = ob_eval->mpath;
203 }
204
205 if (mpath_eval && mpath_eval->length == mpath->length) {
206 bMotionPathVert *mpv_eval = mpath_eval->points + (cframe - mpath_eval->start_frame);
207 *mpv_eval = *mpv;
208
212 }
213 }
214}
215
216/* Get pointer to animviz settings for the given target. */
218{
219 if (mpt->pchan != nullptr) {
220 return &mpt->ob->pose->avs;
221 }
222 return &mpt->ob->avs;
223}
224
225static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra)
226{
227 *r_sfra = INT_MAX;
228 *r_efra = INT_MIN;
229 LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
230 *r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
231 *r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
232 }
233}
234
235/* TODO(jbakker): Remove complexity, keylists are ordered. */
236static int motionpath_get_prev_keyframe(MPathTarget *mpt, AnimKeylist *keylist, int current_frame)
237{
238 if (current_frame <= mpt->mpath->start_frame) {
239 return mpt->mpath->start_frame;
240 }
241
242 float current_frame_float = current_frame;
243 const ActKeyColumn *ak = ED_keylist_find_prev(keylist, current_frame_float);
244 if (ak == nullptr) {
245 return mpt->mpath->start_frame;
246 }
247
248 return ak->cfra;
249}
250
252 AnimKeylist *keylist,
253 int current_frame)
254{
255 int frame = motionpath_get_prev_keyframe(mpt, keylist, current_frame);
256 return motionpath_get_prev_keyframe(mpt, keylist, frame);
257}
258
259static int motionpath_get_next_keyframe(MPathTarget *mpt, AnimKeylist *keylist, int current_frame)
260{
261 if (current_frame >= mpt->mpath->end_frame) {
262 return mpt->mpath->end_frame;
263 }
264
265 float current_frame_float = current_frame;
266 const ActKeyColumn *ak = ED_keylist_find_next(keylist, current_frame_float);
267 if (ak == nullptr) {
268 return mpt->mpath->end_frame;
269 }
270
271 return ak->cfra;
272}
273
275 AnimKeylist *keylist,
276 int current_frame)
277{
278 int frame = motionpath_get_next_keyframe(mpt, keylist, current_frame);
279 return motionpath_get_next_keyframe(mpt, keylist, frame);
280}
281
283 AnimData *adt,
284 ListBase *fcurve_list)
285{
286 if (adt == nullptr || fcurve_list == nullptr) {
287 return false;
288 }
289 /* NOTE: We might needed to do a full frame range update if there is a specific setup of NLA
290 * or drivers or modifiers on the f-curves. */
291 return true;
292}
293
295 AnimData *adt,
296 ListBase *fcurve_list,
297 int current_frame,
298 int *r_sfra,
299 int *r_efra)
300{
301 *r_sfra = INT_MAX;
302 *r_efra = INT_MIN;
303
304 /* If the current frame is outside of the configured motion path range we ignore update of this
305 * motion path by using invalid frame range where start frame is above the end frame. */
306 if (current_frame < mpt->mpath->start_frame || current_frame > mpt->mpath->end_frame) {
307 return;
308 }
309
310 /* Similar to the case when there is only a single keyframe: need to update en entire range to
311 * a constant value. */
312 if (!motionpath_check_can_use_keyframe_range(mpt, adt, fcurve_list)) {
313 *r_sfra = mpt->mpath->start_frame;
314 *r_efra = mpt->mpath->end_frame;
315 return;
316 }
317
318 /* NOTE: Iterate over individual f-curves, and check their keyframes individually and pick a
319 * widest range from them. This is because it's possible to have more narrow keyframe on a
320 * channel which wasn't edited.
321 * Could be optimized further by storing some flags about which channels has been modified so
322 * we ignore all others (which can potentially make an update range unnecessary wide). */
323 for (FCurve *fcu = static_cast<FCurve *>(fcurve_list->first); fcu != nullptr; fcu = fcu->next) {
324 AnimKeylist *keylist = ED_keylist_create();
325 fcurve_to_keylist(adt, fcu, keylist, 0, {-FLT_MAX, FLT_MAX});
327
328 int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, keylist, current_frame);
329 int fcu_efra = motionpath_get_next_next_keyframe(mpt, keylist, current_frame);
330
331 /* Extend range further, since acceleration compensation propagates even further away. */
332 if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
333 fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, keylist, fcu_sfra);
334 fcu_efra = motionpath_get_next_next_keyframe(mpt, keylist, fcu_efra);
335 }
336
337 if (fcu_sfra <= fcu_efra) {
338 *r_sfra = min_ii(*r_sfra, fcu_sfra);
339 *r_efra = max_ii(*r_efra, fcu_efra);
340 }
341
342 ED_keylist_free(keylist);
343 }
344}
345
347{
348 LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
349 ED_keylist_free(mpt->keylist);
350 }
351}
352
354{
355 bAnimVizSettings *avs = ob->mode == OB_MODE_POSE ? &ob->pose->avs : &ob->avs;
356
358 /* Don't touch manually-determined ranges. */
359 return;
360 }
361
362 const bool has_action = ob->adt && ob->adt->action;
363 if (avs->path_range == MOTIONPATH_RANGE_SCENE || !has_action ||
365 {
366 /* Default to the scene (preview) range if there is no animation data to
367 * find selected keys in. */
368 avs->path_sf = PSFRA;
369 avs->path_ef = PEFRA;
370 return;
371 }
372
373 AnimKeylist *keylist = ED_keylist_create();
375 fcurve_to_keylist(ob->adt, fcu, keylist, 0, {-FLT_MAX, FLT_MAX});
376 }
377
378 Range2f frame_range;
379 switch (avs->path_range) {
381 if (ED_keylist_selected_keys_frame_range(keylist, &frame_range)) {
382 break;
383 }
384 ATTR_FALLTHROUGH; /* Fall through if there were no selected keys found. */
386 ED_keylist_all_keys_frame_range(keylist, &frame_range);
387 break;
390 BLI_assert_msg(false, "This should not happen, function should have exited earlier.");
391 };
392
393 avs->path_sf = frame_range.min;
394 avs->path_ef = frame_range.max;
395
396 ED_keylist_free(keylist);
397}
398
400 Main *bmain,
401 Scene *scene,
402 ListBase *targets,
403 eAnimvizCalcRange range,
404 bool restore)
405{
406 /* TODO: include reports pointer? */
407
408 /* Sanity check. */
409 if (ELEM(nullptr, targets, targets->first)) {
410 return;
411 }
412
413 const int cfra = scene->r.cfra;
414 int sfra = INT_MAX, efra = INT_MIN;
415 switch (range) {
417 motionpath_get_global_framerange(targets, &sfra, &efra);
418 if (sfra > efra) {
419 return;
420 }
421 if (cfra < sfra || cfra > efra) {
422 return;
423 }
424 sfra = efra = cfra;
425 break;
427 /* Nothing to do here, will be handled later when iterating through the targets. */
428 break;
430 motionpath_get_global_framerange(targets, &sfra, &efra);
431 if (sfra > efra) {
432 return;
433 }
434 break;
435 }
436
437 /* get copies of objects/bones to get the calculated results from
438 * (for copy-on-evaluation), so that we actually get some results
439 */
440
441 /* TODO: Create a copy of background depsgraph that only contain these entities,
442 * and only evaluates them.
443 *
444 * For until that is done we force dependency graph to not be active, so we don't lose unkeyed
445 * changes during updating the motion path.
446 * This still doesn't include unkeyed changes to the path itself, but allows to have updates in
447 * an environment when auto-keying and pose paste is used. */
448
449 const bool is_active_depsgraph = DEG_is_active(depsgraph);
450 if (is_active_depsgraph) {
452 }
453
454 LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
455 mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
456
457 AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
458
459 /* build list of all keyframes in active action for object or pchan */
460 mpt->keylist = ED_keylist_create();
461
462 ListBase *fcurve_list = nullptr;
463 if (adt) {
464 /* get pointer to animviz settings for each target */
466
467 /* it is assumed that keyframes for bones are all grouped in a single group
468 * unless an option is set to always use the whole action
469 */
470 if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
471 bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
472
473 if (agrp) {
474 fcurve_list = &agrp->channels;
475 action_group_to_keylist(adt, agrp, mpt->keylist, 0, {-FLT_MAX, FLT_MAX});
476 }
477 }
478 else {
479 fcurve_list = &adt->action->curves;
480 action_to_keylist(adt, adt->action, mpt->keylist, 0, {-FLT_MAX, FLT_MAX});
481 }
482 }
484
485 if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
486 int mpt_sfra, mpt_efra;
487 motionpath_calculate_update_range(mpt, adt, fcurve_list, cfra, &mpt_sfra, &mpt_efra);
488 if (mpt_sfra <= mpt_efra) {
489 sfra = min_ii(sfra, mpt_sfra);
490 efra = max_ii(efra, mpt_efra);
491 }
492 }
493 }
494
495 if (sfra > efra) {
497 return;
498 }
499
500 /* calculate path over requested range */
501 CLOG_INFO(&LOG,
502 1,
503 "Calculating MotionPaths between frames %d - %d (%d frames)",
504 sfra,
505 efra,
506 efra - sfra + 1);
507 for (scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
509 /* For current frame, only update tagged. */
511 }
512 else {
513 /* Update relevant data for new frame. */
515 }
516
517 /* perform baking for targets */
518 motionpaths_calc_bake_targets(targets, scene->r.cfra, depsgraph, scene->camera);
519 }
520
521 /* reset original environment */
522 /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph
523 * may be a temporary one that works on a subset of the data.
524 * We always have to restore the current frame though. */
525 scene->r.cfra = cfra;
526 if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
528 }
529
530 if (is_active_depsgraph) {
532 }
533
534 /* clear recalc flags from targets */
535 LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
536 bMotionPath *mpath = mpt->mpath;
537
538 /* get pointer to animviz settings for each target */
540
541 /* clear the flag requesting recalculation of targets */
542 avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
543
544 /* Clean temp data */
545 ED_keylist_free(mpt->keylist);
546
547 /* Free previous batches to force update. */
551 }
552}
Functions for backward compatibility with the legacy Action API.
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
bool ANIM_bonecoll_is_visible_pchan(const bArmature *armature, const bPoseChannel *pchan)
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
bActionGroup * BKE_action_group_find_name(bAction *act, const char name[])
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2568
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2647
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void mul_m4_v3(const float M[4][4], float r[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
@ DAG_EVAL_VIEWPORT
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:273
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
void DEG_make_inactive(Depsgraph *depsgraph)
Definition depsgraph.cc:338
void DEG_make_active(Depsgraph *depsgraph)
Definition depsgraph.cc:331
void DEG_graph_build_from_ids(Depsgraph *graph, blender::Span< ID * > ids)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ MOTIONPATH_VERT_KEY
@ MOTIONPATH_VIEW_KFACT
@ MOTIONPATH_RANGE_KEYS_ALL
@ MOTIONPATH_RANGE_KEYS_SELECTED
@ MOTIONPATH_RANGE_SCENE
@ MOTIONPATH_RANGE_MANUAL
@ ANIMVIZ_RECALC_PATHS
@ MOTIONPATH_FLAG_BAKE_CAMERA
@ MOTIONPATH_FLAG_BHEAD
@ FCURVE_SMOOTH_NONE
@ OB_MODE_POSE
#define PSFRA
#define PEFRA
eAnimvizCalcRange
@ ANIMVIZ_CALC_RANGE_FULL
@ ANIMVIZ_CALC_RANGE_CURRENT_FRAME
@ ANIMVIZ_CALC_RANGE_CHANGED
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:205
#define GPU_VERTBUF_DISCARD_SAFE(verts)
Read Guarded memory(de)allocation.
static void motionpaths_calc_bake_targets(ListBase *targets, int cframe, Depsgraph *depsgraph, Object *camera)
static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra)
static bool motionpath_check_can_use_keyframe_range(MPathTarget *, AnimData *adt, ListBase *fcurve_list)
void animviz_calc_motionpaths(Depsgraph *depsgraph, Main *bmain, Scene *scene, ListBase *targets, eAnimvizCalcRange range, bool restore)
void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
static int motionpath_get_prev_prev_keyframe(MPathTarget *mpt, AnimKeylist *keylist, int current_frame)
static int motionpath_get_prev_keyframe(MPathTarget *mpt, AnimKeylist *keylist, int current_frame)
static int motionpath_get_next_next_keyframe(MPathTarget *mpt, AnimKeylist *keylist, int current_frame)
void animviz_motionpath_compute_range(Object *ob, Scene *scene)
static bAnimVizSettings * animviz_target_settings_get(MPathTarget *mpt)
static void motionpaths_calc_update_scene(Depsgraph *depsgraph)
static int motionpath_get_next_keyframe(MPathTarget *mpt, AnimKeylist *keylist, int current_frame)
static void motionpath_calculate_update_range(MPathTarget *mpt, AnimData *adt, ListBase *fcurve_list, int current_frame, int *r_sfra, int *r_efra)
static CLG_LogRef LOG
Depsgraph * animviz_depsgraph_build(Main *bmain, Scene *scene, ViewLayer *view_layer, ListBase *targets)
static void motionpath_free_free_tree_data(ListBase *targets)
const Depsgraph * depsgraph
draw_view in_light_buf[] float
const ActKeyColumn * ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
bool ED_keylist_selected_keys_frame_range(const AnimKeylist *keylist, Range2f *r_frame_range)
void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
bool ED_keylist_all_keys_frame_range(const AnimKeylist *keylist, Range2f *r_frame_range)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
const ActKeyColumn * ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
const ActKeyColumn * ED_keylist_find_exact(const AnimKeylist *keylist, const float cfra)
void action_to_keylist(AnimData *adt, bAction *dna_action, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void action_group_to_keylist(AnimData *adt, bActionGroup *agrp, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
#define FLT_MAX
Definition stdcycles.h:14
bAction * action
void * first
AnimKeylist * keylist
bPoseChannel * pchan
MPathTarget * next
MPathTarget * prev
bMotionPath * mpath
struct bPose * pose
bMotionPath * mpath
struct AnimData * adt
bAnimVizSettings avs
float min
Definition BLI_range.h:16
float max
Definition BLI_range.h:17
ListBase curves
GPUBatchHandle * batch_line
bMotionPathVert * points
GPUVertBufHandle * points_vbo
GPUBatchHandle * batch_points
bMotionPath * mpath
ListBase chanbase
bAnimVizSettings avs