Blender V4.3
overlay_next_motion_path.hh
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#pragma once
10
11#include "BKE_paint.hh"
12
14
15#include "draw_manager_text.hh"
16
19
20namespace blender::draw::overlay {
21
23
24 private:
25 PassSimple motion_path_ps_ = {"motion_path_ps_"};
26
27 PassSimple::Sub *line_ps_ = nullptr;
28 PassSimple::Sub *vert_ps_ = nullptr;
29
30 bool enabled = false;
31
32 public:
33 void begin_sync(Resources &res, const State &state)
34 {
35 enabled = state.v3d && !(state.overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) &&
36 (res.selection_type == SelectionType::DISABLED);
37 if (!enabled) {
38 /* Not used. But release the data. */
39 motion_path_ps_.init();
40 return;
41 }
42
43 {
44 PassSimple &pass = motion_path_ps_;
45 pass.init();
46 pass.state_set(DRW_STATE_WRITE_COLOR, state.clipping_plane_count);
47 {
48 PassSimple::Sub &sub = pass.sub("Lines");
49 sub.shader_set(res.shaders.motion_path_line.get());
50 sub.bind_ubo("globalsBlock", &res.globals_buf);
51 line_ps_ = ⊂
52 }
53 {
54 PassSimple::Sub &sub = pass.sub("Points");
55 sub.shader_set(res.shaders.motion_path_vert.get());
56 sub.bind_ubo("globalsBlock", &res.globals_buf);
57 vert_ps_ = ⊂
58 }
59 }
60 }
61
62 void object_sync(const ObjectRef &ob_ref, Resources & /*res*/, const State &state)
63 {
64 if (!enabled) {
65 return;
66 }
67
68 const Object *object = ob_ref.object;
69
70 if (object->type == OB_ARMATURE) {
71 if (Armatures::is_pose_mode(object, state)) {
72 for (bPoseChannel *pchan : ListBaseWrapper<bPoseChannel>(&object->pose->chanbase)) {
73 if (pchan->mpath) {
74 motion_path_sync(state, object, pchan, object->pose->avs, pchan->mpath);
75 }
76 }
77 }
78 }
79
80 if (object->mpath) {
81 motion_path_sync(state, object, nullptr, object->avs, object->mpath);
82 }
83 }
84
85 void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view)
86 {
87 if (!enabled) {
88 return;
89 }
90 GPU_framebuffer_bind(framebuffer);
91 manager.submit(motion_path_ps_, view);
92 }
93
94 private:
95 void motion_path_sync(const State &state,
96 const Object *ob,
97 const bPoseChannel *pchan,
98 const bAnimVizSettings &avs,
99 bMotionPath *mpath)
100 {
101 /* Avoid 0 size allocations. Current code to calculate motion paths should
102 * sanitize this already [see animviz_verify_motionpaths()], we might however
103 * encounter an older file where this was still possible. */
104 if (mpath->length == 0) {
105 return;
106 }
107
108 const bool show_keyframes = (avs.path_viewflag & MOTIONPATH_VIEW_KFRAS);
109 const bool show_keyframes_number = (avs.path_viewflag & MOTIONPATH_VIEW_KFNOS);
110 const bool show_frame_number = (avs.path_viewflag & MOTIONPATH_VIEW_FNUMS);
111 const bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES);
112 const bool custom_color = (mpath->flag & MOTIONPATH_FLAG_CUSTOM);
113 const bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) :
114 (ob->base_flag & BASE_SELECTED);
115
116 const float3 color_pre = custom_color ? float3(mpath->color) : float3(-1.0f);
117 const float3 color_post = custom_color ? float3(mpath->color_post) : float3(-1.0f);
118
119 int stride = max_ii(avs.path_step, 1);
120 int current_frame = state.cfra;
121
122 IndexRange frame_range;
123 {
124 int start, end;
125 if (avs.path_type == MOTIONPATH_TYPE_ACFRA) {
126 start = current_frame - avs.path_bc;
127 end = current_frame + avs.path_ac;
128 }
129 else {
130 start = avs.path_sf;
131 end = avs.path_ef;
132 }
133
134 if (start > end) {
135 std::swap(start, end);
136 }
137 start = math::clamp(start, mpath->start_frame, mpath->end_frame);
138 end = math::clamp(end, mpath->start_frame, mpath->end_frame);
139
140 frame_range = IndexRange::from_begin_end_inclusive(start, end);
141 }
142
143 if (frame_range.is_empty()) {
144 return;
145 }
146
147 int start_index = frame_range.start() - mpath->start_frame;
148
149 Object *camera_eval = nullptr;
151 state.v3d->camera)
152 {
153 camera_eval = DEG_get_evaluated_object(state.depsgraph, state.v3d->camera);
154 }
155
156 /* Draw curve-line of path. */
157 if (show_lines) {
158 const int4 motion_path_settings(
159 current_frame, int(frame_range.start()), int(frame_range.last()), mpath->start_frame);
160
161 auto &sub = *line_ps_;
162 sub.push_constant("mpathLineSettings", motion_path_settings);
163 sub.push_constant("lineThickness", mpath->line_thickness);
164 sub.push_constant("selected", selected);
165 sub.push_constant("customColorPre", color_pre);
166 sub.push_constant("customColorPost", color_post);
167 sub.push_constant("camera_space_matrix",
168 camera_eval ? camera_eval->object_to_world() : float4x4::identity());
169
170 gpu::Batch *geom = mpath_batch_points_get(mpath);
171 /* Only draw the required range. */
172 sub.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, frame_range.size() - 1, start_index);
173 }
174
175 /* Draw points. */
176 {
177 int pt_size = max_ii(mpath->line_thickness - 1, 1);
178 const int4 motion_path_settings = {pt_size, current_frame, mpath->start_frame, stride};
179
180 auto &sub = *vert_ps_;
181 sub.push_constant("mpathPointSettings", motion_path_settings);
182 sub.push_constant("showKeyFrames", show_keyframes);
183 sub.push_constant("customColorPre", color_pre);
184 sub.push_constant("customColorPost", color_post);
185 sub.push_constant("camera_space_matrix",
186 camera_eval ? camera_eval->object_to_world() : float4x4::identity());
187
188 gpu::Batch *geom = mpath_batch_points_get(mpath);
189 /* Only draw the required range. */
190 sub.draw(geom, 1, frame_range.size(), start_index);
191 }
192
193 /* Draw frame numbers at each frame-step value. */
194 if (show_frame_number || (show_keyframes_number && show_keyframes)) {
195 uchar4 col, col_kf;
196 /* Color Management: Exception here as texts are drawn in sRGB space directly. */
199 col.w = col_kf.w = 255;
200
201 Span<bMotionPathVert> mpv(mpath->points, mpath->length);
202 for (int i = 0; i < frame_range.size(); i += stride) {
203 const bMotionPathVert &mpv_curr = mpv[start_index + i];
204
205 int frame = frame_range.start() + i;
206 bool is_keyframe = (mpv_curr.flag & MOTIONPATH_VERT_KEY) != 0;
207
208 float3 vert_coordinate(mpv_curr.co);
209 if (camera_eval) {
210 /* Projecting the point into world space from the camera's POV. */
211 vert_coordinate = math::transform_point(camera_eval->object_to_world(), vert_coordinate);
212 }
213
214 if ((show_keyframes && show_keyframes_number && is_keyframe) ||
215 (show_frame_number && (i == 0)))
216 {
217 char numstr[32];
218 size_t numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
220 vert_coordinate,
221 numstr,
222 numstr_len,
223 0,
224 0,
226 (is_keyframe) ? col_kf : col);
227 }
228 else if (show_frame_number) {
229 const bMotionPathVert &mpv_prev = mpv[start_index + i - stride];
230 const bMotionPathVert &mpv_next = mpv[start_index + i + stride];
231 /* Only draw frame number if several consecutive highlighted points
232 * don't occur on same point. */
233 if (!math::is_equal(float3(mpv_curr.co), float3(mpv_prev.co)) ||
234 !math::is_equal(float3(mpv_curr.co), float3(mpv_next.co)))
235 {
236 char numstr[32];
237 size_t numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
239 vert_coordinate,
240 numstr,
241 numstr_len,
242 0,
243 0,
245 col);
246 }
247 }
248 }
249 }
250 }
251
252 /* Just convert the CPU cache to GPU cache. */
253 /* TODO(fclem) This should go into a draw_cache_impl_motionpath. */
254 blender::gpu::VertBuf *mpath_vbo_get(bMotionPath *mpath)
255 {
256 if (!mpath->points_vbo) {
257 GPUVertFormat format = {0};
258 /* Match structure of #bMotionPathVert. */
263 /* meh... a useless `memcpy`. */
264 mpath->points_vbo->data<bMotionPathVert>().copy_from({mpath->points, mpath->length});
265 }
266 return mpath->points_vbo;
267 }
268
269 blender::gpu::Batch *mpath_batch_points_get(bMotionPath *mpath)
270 {
271 if (!mpath->batch_points) {
272 mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), nullptr);
273 }
274 return mpath->batch_points;
275 }
276};
277
278} // namespace blender::draw::overlay
MINLINE int max_ii(int a, int b)
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:598
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)
@ V3D_OVERLAY_HIDE_MOTION_PATHS
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:149
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRIS
#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])
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr int64_t start() const
static constexpr IndexRange from_begin_end_inclusive(const int64_t begin, const int64_t last)
void submit(PassSimple &pass, View &view)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void push_constant(const char *name, const float &data)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
static bool is_pose_mode(const Object *armature_ob, const State &state)
void begin_sync(Resources &res, const State &state)
void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view)
void object_sync(const ObjectRef &ob_ref, Resources &, const State &state)
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
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
uint col
format
static ulong state[N]
T clamp(const T &a, const T &min, const T &max)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
VecBase< float, 3 > float3
short base_flag
bMotionPathVert * points
float color_post[3]
GPUVertBufHandle * points_vbo
GPUBatchHandle * batch_points
struct Bone * bone
uchar w