Blender V4.3
overlay_motion_path.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "DRW_render.hh"
10
11#include "BLI_listbase.h"
12#include "BLI_math_matrix.hh"
13#include "BLI_string.h"
14
15#include "DNA_armature_types.h"
16
18
19#include "GPU_batch.hh"
20
21#include "UI_resources.hh"
22
23#include "draw_manager_text.hh"
24
25#include "overlay_private.hh"
26
45
46/* Just convert the CPU cache to GPU cache. */
47/* T0D0(fclem) This should go into a draw_cache_impl_motionpath. */
49{
50 if (!mpath->points_vbo) {
52 /* Match structure of #bMotionPathVert. */
57 /* meh... a useless `memcpy`. */
58 mpath->points_vbo->data<bMotionPathVert>().copy_from({mpath->points, mpath->length});
59 }
60 return mpath->points_vbo;
61}
62
63static blender::gpu::Batch *mpath_batch_line_get(bMotionPath *mpath)
64{
65 if (!mpath->batch_line) {
67 }
68 return mpath->batch_line;
69}
70
71static blender::gpu::Batch *mpath_batch_points_get(bMotionPath *mpath)
72{
73 if (!mpath->batch_points) {
75 }
76 return mpath->batch_points;
77}
78
80 bMotionPath *mpath,
81 int current_frame,
82 int *r_start,
83 int *r_end,
84 int *r_step)
85{
86 int start, end;
87
88 if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
89 start = current_frame - avs->path_bc;
90 end = current_frame + avs->path_ac + 1;
91 }
92 else {
93 start = avs->path_sf;
94 end = avs->path_ef + 1;
95 }
96
97 if (start > end) {
98 std::swap(start, end);
99 }
100
101 CLAMP(start, mpath->start_frame, mpath->end_frame);
102 CLAMP(end, mpath->start_frame, mpath->end_frame);
103
104 *r_start = start;
105 *r_end = end;
106 *r_step = max_ii(avs->path_step, 1);
107}
108
110 const eMotionPath_BakeFlag bake_flag)
111{
112 if ((bake_flag & MOTIONPATH_BAKE_CAMERA_SPACE) == 0) {
113 return nullptr;
114 }
115 return draw_context->v3d->camera;
116}
117
118static void motion_path_cache(OVERLAY_Data *vedata,
119 Object *ob,
120 bPoseChannel *pchan,
121 bAnimVizSettings *avs,
122 bMotionPath *mpath)
123{
124 using namespace blender;
125 OVERLAY_PrivateData *pd = vedata->stl->pd;
126 const DRWContextState *draw_ctx = DRW_context_state_get();
128 int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE;
129 int cfra = int(DEG_get_ctime(draw_ctx->depsgraph));
130 bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->base_flag & BASE_SELECTED);
131 bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
132 bool show_keyframes_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
133 bool show_frame_no = (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) != 0;
134 bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES) != 0;
135 float no_custom_col[3] = {-1.0f, -1.0f, -1.0f};
136 const bool use_custom_color = mpath->flag & MOTIONPATH_FLAG_CUSTOM;
137 const float *color_pre = use_custom_color ? mpath->color : no_custom_col;
138 const float *color_post = use_custom_color ? mpath->color_post : no_custom_col;
139
140 int sfra, efra, stepsize;
141 motion_path_get_frame_range_to_draw(avs, mpath, cfra, &sfra, &efra, &stepsize);
142
143 int len = efra - sfra;
144 if (len == 0) {
145 return;
146 }
147
148 /* Avoid 0 size allocations. Current code to calculate motion paths should
149 * sanitize this already [see animviz_verify_motionpaths()], we might however
150 * encounter an older file where this was still possible. */
151 if (mpath->length == 0) {
152 return;
153 }
154
155 int start_index = sfra - mpath->start_frame;
156
157 float camera_matrix[4][4];
158 Object *motion_path_camera = get_camera_for_motion_path(
159 draw_ctx, eMotionPath_BakeFlag(avs->path_bakeflag));
160 if (motion_path_camera) {
161 copy_m4_m4(camera_matrix, motion_path_camera->object_to_world().ptr());
162 }
163 else {
164 unit_m4(camera_matrix);
165 }
166
167 /* Draw curve-line of path. */
168 if (show_lines) {
169 const int motion_path_settings[4] = {cfra, sfra, efra, mpath->start_frame};
171 DRW_shgroup_uniform_ivec4_copy(grp, "mpathLineSettings", motion_path_settings);
172 DRW_shgroup_uniform_int_copy(grp, "lineThickness", mpath->line_thickness);
173 DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
174 DRW_shgroup_uniform_vec3_copy(grp, "customColorPre", color_pre);
175 DRW_shgroup_uniform_vec3_copy(grp, "customColorPost", color_post);
176 DRW_shgroup_uniform_mat4_copy(grp, "camera_space_matrix", camera_matrix);
177 /* Only draw the required range. */
178 DRW_shgroup_call_range(grp, nullptr, mpath_batch_line_get(mpath), start_index, len);
179 }
180
181 /* Draw points. */
182 {
183 int pt_size = max_ii(mpath->line_thickness - 1, 1);
184 const int motion_path_settings[4] = {pt_size, cfra, mpath->start_frame, stepsize};
186 DRW_shgroup_uniform_ivec4_copy(grp, "mpathPointSettings", motion_path_settings);
187 DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
188 DRW_shgroup_uniform_vec3_copy(grp, "customColorPre", color_pre);
189 DRW_shgroup_uniform_vec3_copy(grp, "customColorPost", color_post);
190 DRW_shgroup_uniform_mat4_copy(grp, "camera_space_matrix", camera_matrix);
191 /* Only draw the required range. */
192 DRW_shgroup_call_range(grp, nullptr, mpath_batch_points_get(mpath), start_index, len);
193 }
194
195 /* Draw frame numbers at each frame-step value. */
196 if (show_frame_no || (show_keyframes_no && show_keyframes)) {
197 int i;
198 uchar col[4], col_kf[4];
199 /* Color Management: Exception here as texts are drawn in sRGB space directly. */
202 col[3] = col_kf[3] = 255;
203
204 Object *cam_eval = nullptr;
205 if (motion_path_camera) {
206 cam_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, motion_path_camera);
207 }
208
209 bMotionPathVert *mpv = mpath->points + start_index;
210 for (i = 0; i < len; i += stepsize, mpv += stepsize) {
211 int frame = sfra + i;
212 char numstr[32];
213 size_t numstr_len;
214 bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
215 float3 vert_coordinate;
216 copy_v3_v3(vert_coordinate, mpv->co);
217 if (cam_eval) {
218 /* Projecting the point into world space from the camera's POV. */
219 vert_coordinate = math::transform_point(cam_eval->object_to_world(), vert_coordinate);
220 }
221
222 if ((show_keyframes && show_keyframes_no && is_keyframe) || (show_frame_no && (i == 0))) {
223 numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
225 dt, vert_coordinate, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
226 }
227 else if (show_frame_no) {
228 bMotionPathVert *mpvP = (mpv - stepsize);
229 bMotionPathVert *mpvN = (mpv + stepsize);
230 /* Only draw frame number if several consecutive highlighted points
231 * don't occur on same point. */
232 if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
233 numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
234 DRW_text_cache_add(dt, vert_coordinate, numstr, numstr_len, 0, 0, txt_flag, col);
235 }
236 }
237 }
238 }
239}
240
242{
243 const DRWContextState *draw_ctx = DRW_context_state_get();
244
245 if (ob->type == OB_ARMATURE) {
246 if (OVERLAY_armature_is_pose_mode(ob, draw_ctx)) {
247 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
248 if (pchan->mpath) {
249 motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath);
250 }
251 }
252 }
253 }
254
255 if (ob->mpath) {
256 motion_path_cache(vedata, ob, nullptr, &ob->avs, ob->mpath);
257 }
258}
259
261{
262 OVERLAY_PassList *psl = vedata->psl;
263
265}
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
void unit_m4(float m[4][4])
Definition rct.c:1127
void copy_m4_m4(float m1[4][4], const float m2[4][4])
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:598
unsigned char uchar
#define CLAMP(a, b, c)
float DEG_get_ctime(const Depsgraph *graph)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ MOTIONPATH_BAKE_CAMERA_SPACE
@ MOTIONPATH_TYPE_ACFRA
@ MOTIONPATH_VERT_KEY
@ MOTIONPATH_VIEW_KFNOS
@ MOTIONPATH_VIEW_FNUMS
@ MOTIONPATH_VIEW_KFRAS
@ MOTIONPATH_FLAG_LINES
@ MOTIONPATH_FLAG_CUSTOM
enum eMotionPaths_BakeFlag eMotionPath_BakeFlag
@ BONE_SELECTED
@ OB_ARMATURE
#define BASE_SELECTED(v3d, base)
#define DRW_PASS_CREATE(pass, state)
#define DRW_shgroup_uniform_block(shgroup, name, ubo)
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:149
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
@ TH_VERTEX_SELECT
@ TH_TEXT_HI
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
struct GPUShader GPUShader
DRW_Global G_draw
DRWTextStore * DRW_text_cache_ensure()
const DRWContextState * DRW_context_state_get()
int len
DRWShadingGroup * DRW_shgroup_create(GPUShader *shader, DRWPass *pass)
void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value)
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
void DRW_shgroup_call_range(DRWShadingGroup *shgroup, const Object *ob, blender::gpu::Batch *geom, uint v_sta, uint v_num)
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
void DRW_shgroup_uniform_mat4_copy(DRWShadingGroup *shgroup, const char *name, const float(*value)[4])
void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value)
void DRW_draw_pass(DRWPass *pass)
void DRW_text_cache_add(DRWTextStore *dt, const float co[3], const char *str, const int str_len, short xoffs, short yoffs, short flag, const uchar col[4], const bool shadow, const bool align_center)
@ DRW_TEXT_CACHE_GLOBALSPACE
DRWState
Definition draw_state.hh:25
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
format
static ulong state[N]
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob)
static blender::gpu::Batch * mpath_batch_points_get(bMotionPath *mpath)
static Object * get_camera_for_motion_path(const DRWContextState *draw_context, const eMotionPath_BakeFlag bake_flag)
void OVERLAY_motion_path_draw(OVERLAY_Data *vedata)
void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata)
static void motion_path_cache(OVERLAY_Data *vedata, Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath)
static blender::gpu::VertBuf * mpath_vbo_get(bMotionPath *mpath)
static void motion_path_get_frame_range_to_draw(bAnimVizSettings *avs, bMotionPath *mpath, int current_frame, int *r_start, int *r_end, int *r_step)
static blender::gpu::Batch * mpath_batch_line_get(bMotionPath *mpath)
GPUShader * OVERLAY_shader_motion_path_vert()
GPUShader * OVERLAY_shader_motion_path_line()
Depsgraph * depsgraph
GPUUniformBuf * block_ubo
OVERLAY_PassList * psl
OVERLAY_StorageList * stl
DRWShadingGroup * motion_path_points_grp
DRWShadingGroup * motion_path_lines_grp
OVERLAY_PrivateData * pd
short base_flag
struct bPose * pose
bMotionPath * mpath
bAnimVizSettings avs
struct Object * camera
GPUBatchHandle * batch_line
bMotionPathVert * points
float color_post[3]
GPUVertBufHandle * points_vbo
GPUBatchHandle * batch_points
struct Bone * bone
ListBase chanbase
bAnimVizSettings avs