Files
test2/source/blender/draw/engines/overlay/overlay_next_motion_path.hh
Clément Foucault f8195e0bb4 Fix: Overlay: Broken shader compilation
Caused by the changes in UBO members.
This removes the duplicated lib used by overlay
and reuse the same side clip plane UBO mechanism
as workbench.
2025-02-19 17:46:47 +01:00

283 lines
9.5 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "BLI_string.h"
#include "DEG_depsgraph_query.hh"
#include "draw_manager_text.hh"
#include "overlay_next_armature.hh"
#include "overlay_next_base.hh"
namespace blender::draw::overlay {
/**
* Display object and armature motion path.
* Motion paths can be found in (Object > Motion Paths) or (Data > Motion Paths) for armatures.
*/
class MotionPath : Overlay {
private:
PassSimple motion_path_ps_ = {"motion_path_ps_"};
PassSimple::Sub *line_ps_ = nullptr;
PassSimple::Sub *vert_ps_ = nullptr;
public:
void begin_sync(Resources &res, const State &state) final
{
enabled_ = state.v3d && state.show_motion_paths() && !res.is_selection();
if (!enabled_) {
/* Not used. But release the data. */
motion_path_ps_.init();
return;
}
{
PassSimple &pass = motion_path_ps_;
pass.init();
pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
pass.state_set(DRW_STATE_WRITE_COLOR, state.clipping_plane_count);
{
PassSimple::Sub &sub = pass.sub("Lines");
sub.shader_set(res.shaders.motion_path_line.get());
line_ps_ = ⊂
}
{
PassSimple::Sub &sub = pass.sub("Points");
sub.shader_set(res.shaders.motion_path_vert.get());
vert_ps_ = ⊂
}
}
}
void object_sync(Manager & /*manager*/,
const ObjectRef &ob_ref,
Resources & /*res*/,
const State &state) final
{
if (!enabled_) {
return;
}
const Object *object = ob_ref.object;
if (object->type == OB_ARMATURE) {
if (Armatures::is_pose_mode(object, state)) {
for (bPoseChannel *pchan : ListBaseWrapper<bPoseChannel>(&object->pose->chanbase)) {
if (pchan->mpath) {
motion_path_sync(state, object, pchan, object->pose->avs, pchan->mpath);
}
}
}
}
if (object->mpath) {
motion_path_sync(state, object, nullptr, object->avs, object->mpath);
}
}
void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view) final
{
if (!enabled_) {
return;
}
GPU_framebuffer_bind(framebuffer);
manager.submit(motion_path_ps_, view);
}
private:
void motion_path_sync(const State &state,
const Object *ob,
const bPoseChannel *pchan,
const bAnimVizSettings &avs,
bMotionPath *mpath)
{
/* Avoid 0 size allocations. Current code to calculate motion paths should
* sanitize this already [see animviz_verify_motionpaths()], we might however
* encounter an older file where this was still possible. */
if (mpath->length == 0) {
return;
}
const bool show_keyframes = (avs.path_viewflag & MOTIONPATH_VIEW_KFRAS);
const bool show_keyframes_number = (avs.path_viewflag & MOTIONPATH_VIEW_KFNOS);
const bool show_frame_number = (avs.path_viewflag & MOTIONPATH_VIEW_FNUMS);
const bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES);
const bool custom_color = (mpath->flag & MOTIONPATH_FLAG_CUSTOM);
const bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) :
(ob->base_flag & BASE_SELECTED);
const float3 color_pre = custom_color ? float3(mpath->color) : float3(-1.0f);
const float3 color_post = custom_color ? float3(mpath->color_post) : float3(-1.0f);
int stride = max_ii(avs.path_step, 1);
int current_frame = state.cfra;
IndexRange frame_range;
{
int start, end;
if (avs.path_type == MOTIONPATH_TYPE_ACFRA) {
start = current_frame - avs.path_bc;
end = current_frame + avs.path_ac;
}
else {
start = avs.path_sf;
end = avs.path_ef;
}
if (start > end) {
std::swap(start, end);
}
start = math::clamp(start, mpath->start_frame, mpath->end_frame);
end = math::clamp(end, mpath->start_frame, mpath->end_frame);
frame_range = IndexRange::from_begin_end_inclusive(start, end);
}
if (frame_range.is_empty()) {
return;
}
int start_index = frame_range.start() - mpath->start_frame;
Object *camera_eval = nullptr;
if ((eMotionPath_BakeFlag(avs.path_bakeflag) & MOTIONPATH_BAKE_CAMERA_SPACE) &&
state.v3d->camera)
{
camera_eval = DEG_get_evaluated_object(state.depsgraph, state.v3d->camera);
}
/* Draw curve-line of path. */
if (show_lines) {
const int4 motion_path_settings(
current_frame, int(frame_range.start()), int(frame_range.last()), mpath->start_frame);
auto &sub = *line_ps_;
sub.push_constant("mpathLineSettings", motion_path_settings);
sub.push_constant("lineThickness", mpath->line_thickness);
sub.push_constant("selected", selected);
sub.push_constant("customColorPre", color_pre);
sub.push_constant("customColorPost", color_post);
sub.push_constant("camera_space_matrix",
camera_eval ? camera_eval->object_to_world() : float4x4::identity());
gpu::Batch *geom = mpath_batch_points_get(mpath);
/* Only draw the required range. */
sub.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, frame_range.size() - 1, start_index);
}
/* Draw points. */
{
int pt_size = max_ii(mpath->line_thickness - 1, 1);
const int4 motion_path_settings = {pt_size, current_frame, mpath->start_frame, stride};
auto &sub = *vert_ps_;
sub.push_constant("mpathPointSettings", motion_path_settings);
sub.push_constant("showKeyFrames", show_keyframes);
sub.push_constant("customColorPre", color_pre);
sub.push_constant("customColorPost", color_post);
sub.push_constant("camera_space_matrix",
camera_eval ? camera_eval->object_to_world() : float4x4::identity());
gpu::Batch *geom = mpath_batch_points_get(mpath);
/* Only draw the required range. */
sub.draw(geom, 1, frame_range.size(), start_index);
}
/* Draw frame numbers at each frame-step value. */
if (show_frame_number || (show_keyframes_number && show_keyframes)) {
uchar4 col, col_kf;
/* Color Management: Exception here as texts are drawn in sRGB space directly. */
UI_GetThemeColor3ubv(TH_TEXT_HI, col);
UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
col.w = col_kf.w = 255;
Span<bMotionPathVert> mpv(mpath->points, mpath->length);
for (int i = 0; i < frame_range.size(); i += stride) {
const bMotionPathVert &mpv_curr = mpv[start_index + i];
int frame = frame_range.start() + i;
bool is_keyframe = (mpv_curr.flag & MOTIONPATH_VERT_KEY) != 0;
float3 vert_coordinate(mpv_curr.co);
if (camera_eval) {
/* Projecting the point into world space from the camera's POV. */
vert_coordinate = math::transform_point(camera_eval->object_to_world(), vert_coordinate);
}
if ((show_keyframes && show_keyframes_number && is_keyframe) ||
(show_frame_number && (i == 0)))
{
char numstr[32];
size_t numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
DRW_text_cache_add(state.dt,
vert_coordinate,
numstr,
numstr_len,
0,
0,
DRW_TEXT_CACHE_GLOBALSPACE,
(is_keyframe) ? col_kf : col);
}
else if (show_frame_number) {
const bMotionPathVert &mpv_prev = mpv[start_index + i - stride];
const bMotionPathVert &mpv_next = mpv[start_index + i + stride];
/* Only draw frame number if several consecutive highlighted points
* don't occur on same point. */
if (!math::is_equal(float3(mpv_curr.co), float3(mpv_prev.co)) ||
!math::is_equal(float3(mpv_curr.co), float3(mpv_next.co)))
{
char numstr[32];
size_t numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
DRW_text_cache_add(state.dt,
vert_coordinate,
numstr,
numstr_len,
0,
0,
DRW_TEXT_CACHE_GLOBALSPACE,
col);
}
}
}
}
}
/* Just convert the CPU cache to GPU cache. */
/* TODO(fclem) This should go into a draw_cache_impl_motionpath. */
blender::gpu::VertBuf *mpath_vbo_get(bMotionPath *mpath)
{
if (!mpath->points_vbo) {
GPUVertFormat format = {0};
/* Match structure of #bMotionPathVert. */
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
mpath->points_vbo = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(*mpath->points_vbo, mpath->length);
/* meh... a useless `memcpy`. */
mpath->points_vbo->data<bMotionPathVert>().copy_from({mpath->points, mpath->length});
}
return mpath->points_vbo;
}
blender::gpu::Batch *mpath_batch_points_get(bMotionPath *mpath)
{
if (!mpath->batch_points) {
mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), nullptr);
}
return mpath->batch_points;
}
};
} // namespace blender::draw::overlay