256 lines
8.7 KiB
C++
256 lines
8.7 KiB
C++
/* SPDX-FileCopyrightText: 2019 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup draw_engine
|
|
*/
|
|
|
|
#include "DRW_render.hh"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_math_matrix.hh"
|
|
#include "BLI_string.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
|
|
#include "DEG_depsgraph_query.hh"
|
|
|
|
#include "GPU_batch.h"
|
|
|
|
#include "UI_resources.hh"
|
|
|
|
#include "draw_manager_text.hh"
|
|
|
|
#include "overlay_private.hh"
|
|
|
|
void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata)
|
|
{
|
|
OVERLAY_PassList *psl = vedata->psl;
|
|
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
|
DRWShadingGroup *grp;
|
|
GPUShader *sh;
|
|
|
|
DRWState state = DRW_STATE_WRITE_COLOR;
|
|
DRW_PASS_CREATE(psl->motion_paths_ps, state | pd->clipping_state);
|
|
|
|
sh = OVERLAY_shader_motion_path_line();
|
|
pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
|
|
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
|
|
|
sh = OVERLAY_shader_motion_path_vert();
|
|
pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
|
|
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
|
}
|
|
|
|
/* Just convert the CPU cache to GPU cache. */
|
|
/* T0D0(fclem) This should go into a draw_cache_impl_motionpath. */
|
|
static GPUVertBuf *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. */
|
|
memcpy(GPU_vertbuf_get_data(mpath->points_vbo),
|
|
mpath->points,
|
|
sizeof(bMotionPathVert) * mpath->length);
|
|
}
|
|
return mpath->points_vbo;
|
|
}
|
|
|
|
static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
|
|
{
|
|
if (!mpath->batch_line) {
|
|
mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), nullptr);
|
|
}
|
|
return mpath->batch_line;
|
|
}
|
|
|
|
static GPUBatch *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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int start, end;
|
|
|
|
if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
|
|
start = current_frame - avs->path_bc;
|
|
end = current_frame + avs->path_ac + 1;
|
|
}
|
|
else {
|
|
start = avs->path_sf;
|
|
end = avs->path_ef + 1;
|
|
}
|
|
|
|
if (start > end) {
|
|
std::swap(start, end);
|
|
}
|
|
|
|
CLAMP(start, mpath->start_frame, mpath->end_frame);
|
|
CLAMP(end, mpath->start_frame, mpath->end_frame);
|
|
|
|
*r_start = start;
|
|
*r_end = end;
|
|
*r_step = max_ii(avs->path_step, 1);
|
|
}
|
|
|
|
static Object *get_camera_for_motion_path(const DRWContextState *draw_context,
|
|
const eMotionPath_BakeFlag bake_flag)
|
|
{
|
|
if ((bake_flag & MOTIONPATH_BAKE_CAMERA_SPACE) == 0) {
|
|
return nullptr;
|
|
}
|
|
return draw_context->v3d->camera;
|
|
}
|
|
|
|
static void motion_path_cache(OVERLAY_Data *vedata,
|
|
Object *ob,
|
|
bPoseChannel *pchan,
|
|
bAnimVizSettings *avs,
|
|
bMotionPath *mpath)
|
|
{
|
|
using namespace blender;
|
|
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
DRWTextStore *dt = DRW_text_cache_ensure();
|
|
int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE;
|
|
int cfra = int(DEG_get_ctime(draw_ctx->depsgraph));
|
|
bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->base_flag & BASE_SELECTED);
|
|
bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
|
|
bool show_keyframes_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
|
|
bool show_frame_no = (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) != 0;
|
|
bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES) != 0;
|
|
float no_custom_col[3] = {-1.0f, -1.0f, -1.0f};
|
|
float *color = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) ? mpath->color : no_custom_col;
|
|
|
|
int sfra, efra, stepsize;
|
|
motion_path_get_frame_range_to_draw(avs, mpath, cfra, &sfra, &efra, &stepsize);
|
|
|
|
int len = efra - sfra;
|
|
if (len == 0) {
|
|
return;
|
|
}
|
|
int start_index = sfra - mpath->start_frame;
|
|
|
|
float camera_matrix[4][4];
|
|
Object *motion_path_camera = get_camera_for_motion_path(
|
|
draw_ctx, eMotionPath_BakeFlag(avs->path_bakeflag));
|
|
if (motion_path_camera) {
|
|
copy_m4_m4(camera_matrix, motion_path_camera->object_to_world().ptr());
|
|
}
|
|
else {
|
|
unit_m4(camera_matrix);
|
|
}
|
|
|
|
/* Draw curve-line of path. */
|
|
if (show_lines) {
|
|
const int motion_path_settings[4] = {cfra, sfra, efra, mpath->start_frame};
|
|
DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_lines_grp);
|
|
DRW_shgroup_uniform_ivec4_copy(grp, "mpathLineSettings", motion_path_settings);
|
|
DRW_shgroup_uniform_int_copy(grp, "lineThickness", mpath->line_thickness);
|
|
DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
|
|
DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
|
|
DRW_shgroup_uniform_mat4_copy(grp, "camera_space_matrix", camera_matrix);
|
|
/* Only draw the required range. */
|
|
DRW_shgroup_call_range(grp, nullptr, mpath_batch_line_get(mpath), start_index, len);
|
|
}
|
|
|
|
/* Draw points. */
|
|
{
|
|
int pt_size = max_ii(mpath->line_thickness - 1, 1);
|
|
const int motion_path_settings[4] = {pt_size, cfra, mpath->start_frame, stepsize};
|
|
DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_points_grp);
|
|
DRW_shgroup_uniform_ivec4_copy(grp, "mpathPointSettings", motion_path_settings);
|
|
DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
|
|
DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
|
|
DRW_shgroup_uniform_mat4_copy(grp, "camera_space_matrix", camera_matrix);
|
|
/* Only draw the required range. */
|
|
DRW_shgroup_call_range(grp, nullptr, mpath_batch_points_get(mpath), start_index, len);
|
|
}
|
|
|
|
/* Draw frame numbers at each frame-step value. */
|
|
if (show_frame_no || (show_keyframes_no && show_keyframes)) {
|
|
int i;
|
|
uchar col[4], col_kf[4];
|
|
/* 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[3] = col_kf[3] = 255;
|
|
|
|
Object *cam_eval = nullptr;
|
|
if (motion_path_camera) {
|
|
cam_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, motion_path_camera);
|
|
}
|
|
|
|
bMotionPathVert *mpv = mpath->points + start_index;
|
|
for (i = 0; i < len; i += stepsize, mpv += stepsize) {
|
|
int frame = sfra + i;
|
|
char numstr[32];
|
|
size_t numstr_len;
|
|
bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
|
|
float3 vert_coordinate;
|
|
copy_v3_v3(vert_coordinate, mpv->co);
|
|
if (cam_eval) {
|
|
/* Projecting the point into world space from the camera's POV. */
|
|
vert_coordinate = math::transform_point(cam_eval->object_to_world(), vert_coordinate);
|
|
}
|
|
|
|
if ((show_keyframes && show_keyframes_no && is_keyframe) || (show_frame_no && (i == 0))) {
|
|
numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
|
|
DRW_text_cache_add(
|
|
dt, vert_coordinate, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
|
|
}
|
|
else if (show_frame_no) {
|
|
bMotionPathVert *mpvP = (mpv - stepsize);
|
|
bMotionPathVert *mpvN = (mpv + stepsize);
|
|
/* Only draw frame number if several consecutive highlighted points
|
|
* don't occur on same point. */
|
|
if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
|
|
numstr_len = SNPRINTF_RLEN(numstr, " %d", frame);
|
|
DRW_text_cache_add(dt, vert_coordinate, numstr, numstr_len, 0, 0, txt_flag, col);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
|
{
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
|
|
if (ob->type == OB_ARMATURE) {
|
|
if (OVERLAY_armature_is_pose_mode(ob, draw_ctx)) {
|
|
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
|
if (pchan->mpath) {
|
|
motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ob->mpath) {
|
|
motion_path_cache(vedata, ob, nullptr, &ob->avs, ob->mpath);
|
|
}
|
|
}
|
|
|
|
void OVERLAY_motion_path_draw(OVERLAY_Data *vedata)
|
|
{
|
|
OVERLAY_PassList *psl = vedata->psl;
|
|
|
|
DRW_draw_pass(psl->motion_paths_ps);
|
|
}
|