Merge branch 'master' into refactor-mesh-position-generic

This commit is contained in:
Hans Goudey 2023-01-02 12:07:18 -05:00
commit f2d1e38289
22 changed files with 388 additions and 77 deletions

View File

@ -1532,7 +1532,7 @@ ccl_device_extern void osl_texture_set_missingcolor_alpha(ccl_private OSLTexture
ccl_device_extern bool osl_texture(ccl_private ShaderGlobals *sg,
DeviceString filename,
ccl_private void *texture_handle,
OSLTextureOptions *opt,
ccl_private OSLTextureOptions *opt,
float s,
float t,
float dsdx,
@ -1557,13 +1557,14 @@ ccl_device_extern bool osl_texture(ccl_private ShaderGlobals *sg,
const float4 rgba = kernel_tex_image_interp(nullptr, id, s, 1.0f - t);
result[0] = rgba.x;
if (nchannels > 0)
result[0] = rgba.x;
if (nchannels > 1)
result[1] = rgba.y;
if (nchannels > 2)
result[2] = rgba.z;
if (nchannels > 3)
result[3] = rgba.w;
if (alpha)
*alpha = rgba.w;
return true;
}
@ -1571,7 +1572,7 @@ ccl_device_extern bool osl_texture(ccl_private ShaderGlobals *sg,
ccl_device_extern bool osl_texture3d(ccl_private ShaderGlobals *sg,
DeviceString filename,
ccl_private void *texture_handle,
OSLTextureOptions *opt,
ccl_private OSLTextureOptions *opt,
ccl_private const float3 *P,
ccl_private const float3 *dPdx,
ccl_private const float3 *dPdy,
@ -1594,13 +1595,14 @@ ccl_device_extern bool osl_texture3d(ccl_private ShaderGlobals *sg,
const float4 rgba = kernel_tex_image_interp_3d(nullptr, id, *P, INTERPOLATION_NONE);
result[0] = rgba.x;
if (nchannels > 0)
result[0] = rgba.x;
if (nchannels > 1)
result[1] = rgba.y;
if (nchannels > 2)
result[2] = rgba.z;
if (nchannels > 3)
result[3] = rgba.w;
if (alpha)
*alpha = rgba.w;
return true;
}
@ -1608,7 +1610,7 @@ ccl_device_extern bool osl_texture3d(ccl_private ShaderGlobals *sg,
ccl_device_extern bool osl_environment(ccl_private ShaderGlobals *sg,
DeviceString filename,
ccl_private void *texture_handle,
OSLTextureOptions *opt,
ccl_private OSLTextureOptions *opt,
ccl_private const float3 *R,
ccl_private const float3 *dRdx,
ccl_private const float3 *dRdy,
@ -1621,13 +1623,14 @@ ccl_device_extern bool osl_environment(ccl_private ShaderGlobals *sg,
ccl_private float *dalphay,
ccl_private void *errormessage)
{
result[0] = 1.0f;
if (nchannels > 0)
result[0] = 1.0f;
if (nchannels > 1)
result[1] = 0.0f;
if (nchannels > 2)
result[2] = 1.0f;
if (nchannels > 3)
result[3] = 1.0f;
if (alpha)
*alpha = 1.0f;
return false;
}

View File

@ -540,7 +540,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
sc = context.space_data
if sc and sc.type == 'CLIP_EDITOR':
clip = sc.clip
if clip and clip.tracking.reconstruction.is_valid:
if clip and clip.tracking.objects.active.reconstruction.is_valid:
return True
return False

View File

@ -0,0 +1,66 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*
* Pose Backups can be created from the current pose, and later restored. The
* backup is restricted to those bones animated by a given Action, so that
* operations are as fast as possible.
*/
#pragma once
#include <stdbool.h>
#include "BLI_listbase.h"
#ifdef __cplusplus
extern "C" {
#endif
struct PoseBackup;
/**
* Create a backup of those bones that are selected AND animated in the given action.
*
* The backup is owned by the caller, and should be freed with `BKE_pose_backup_free()`.
*/
struct PoseBackup *BKE_pose_backup_create_selected_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
/**
* Create a backup of those bones that are animated in the given action.
*
* The backup is owned by the caller, and should be freed with `BKE_pose_backup_free()`.
*/
struct PoseBackup *BKE_pose_backup_create_all_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
bool BKE_pose_backup_is_selection_relevant(const struct PoseBackup *pose_backup);
void BKE_pose_backup_restore(const struct PoseBackup *pbd);
void BKE_pose_backup_free(struct PoseBackup *pbd);
/**
* Create a backup of those bones that are animated in the given action.
*
* The backup is owned by the Object, and there can be only one backup at a time.
* It should be freed with `BKE_pose_backup_clear(ob)`.
*/
void BKE_pose_backup_create_on_object(struct Object *ob, const struct bAction *action);
/**
* Restore the pose backup owned by this OBject.
*
* \return true on success, false if there was no pose backup to restore.
*
* \see #BKE_pose_backup_create_on_object
*/
bool BKE_pose_backup_restore_on_object(struct Object *ob);
/**
* Free the pose backup that was stored on this object's runtime data.
*/
void BKE_pose_backup_clear(struct Object *ob);
#ifdef __cplusplus
}
#endif

View File

@ -254,6 +254,7 @@ set(SRC
intern/pbvh_uv_islands.cc
intern/pointcache.c
intern/pointcloud.cc
intern/pose_backup.cc
intern/preferences.c
intern/report.c
intern/rigidbody.c

View File

@ -3558,8 +3558,6 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
node->flag |= flags_to_set;
}
void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
{
const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0;

View File

@ -117,6 +117,7 @@
#include "BKE_pbvh.h"
#include "BKE_pointcache.h"
#include "BKE_pointcloud.h"
#include "BKE_pose_backup.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_shader_fx.h"
@ -1814,6 +1815,7 @@ void BKE_object_free_derived_caches(Object *ob)
}
BKE_object_to_mesh_clear(ob);
BKE_pose_backup_clear(ob);
BKE_object_to_curve_clear(ob);
BKE_object_free_curve_cache(ob);
@ -5132,6 +5134,7 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int /*flag*/)
runtime->mesh_deform_eval = nullptr;
runtime->curve_cache = nullptr;
runtime->object_as_temp_mesh = nullptr;
runtime->pose_backup = nullptr;
runtime->object_as_temp_curve = nullptr;
runtime->geometry_set_eval = nullptr;

View File

@ -1,10 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edarmature
* \ingroup bke
*/
#include "ED_armature.h"
#include "BKE_pose_backup.h"
#include <cstring>
@ -38,6 +38,14 @@ struct PoseBackup {
ListBase /* PoseChannelBackup* */ backups;
};
/**
* Create a backup of the pose, for only those bones that are animated in the
* given Action. If `selected_bone_names` is not empty, the set of bones to back
* up is intersected with these bone names such that only the selected subset is
* backed up.
*
* The returned pointer is owned by the caller.
*/
static PoseBackup *pose_backup_create(const Object *ob,
const bAction *action,
const BoneNameSet &selected_bone_names)
@ -86,24 +94,24 @@ static PoseBackup *pose_backup_create(const Object *ob,
return pose_backup;
}
PoseBackup *ED_pose_backup_create_all_bones(const Object *ob, const bAction *action)
PoseBackup *BKE_pose_backup_create_all_bones(const Object *ob, const bAction *action)
{
return pose_backup_create(ob, action, BoneNameSet());
}
PoseBackup *ED_pose_backup_create_selected_bones(const Object *ob, const bAction *action)
PoseBackup *BKE_pose_backup_create_selected_bones(const Object *ob, const bAction *action)
{
const bArmature *armature = static_cast<const bArmature *>(ob->data);
const BoneNameSet selected_bone_names = BKE_armature_find_selected_bone_names(armature);
return pose_backup_create(ob, action, selected_bone_names);
}
bool ED_pose_backup_is_selection_relevant(const struct PoseBackup *pose_backup)
bool BKE_pose_backup_is_selection_relevant(const struct PoseBackup *pose_backup)
{
return pose_backup->is_bone_selection_relevant;
}
void ED_pose_backup_restore(const PoseBackup *pbd)
void BKE_pose_backup_restore(const PoseBackup *pbd)
{
LISTBASE_FOREACH (PoseChannelBackup *, chan_bak, &pbd->backups) {
memcpy(chan_bak->pchan, &chan_bak->olddata, sizeof(chan_bak->olddata));
@ -117,7 +125,7 @@ void ED_pose_backup_restore(const PoseBackup *pbd)
}
}
void ED_pose_backup_free(PoseBackup *pbd)
void BKE_pose_backup_free(PoseBackup *pbd)
{
LISTBASE_FOREACH_MUTABLE (PoseChannelBackup *, chan_bak, &pbd->backups) {
if (chan_bak->oldprops) {
@ -127,3 +135,29 @@ void ED_pose_backup_free(PoseBackup *pbd)
}
MEM_freeN(pbd);
}
void BKE_pose_backup_create_on_object(Object *ob, const bAction *action)
{
BKE_pose_backup_clear(ob);
PoseBackup *pose_backup = BKE_pose_backup_create_all_bones(ob, action);
ob->runtime.pose_backup = pose_backup;
}
bool BKE_pose_backup_restore_on_object(struct Object *ob)
{
if (ob->runtime.pose_backup == nullptr) {
return false;
}
BKE_pose_backup_restore(ob->runtime.pose_backup);
return true;
}
void BKE_pose_backup_clear(Object *ob)
{
if (ob->runtime.pose_backup == nullptr) {
return;
}
BKE_pose_backup_free(ob->runtime.pose_backup);
ob->runtime.pose_backup = nullptr;
}

View File

@ -88,8 +88,8 @@ struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree
const char *name);
/**
* The versioning code generally expects `SOCK_IS_LINKED` to be set correctly. This function updates
* the flag on all sockets after changes to the node tree.
* The versioning code generally expects `SOCK_IS_LINKED` to be set correctly. This function
* updates the flag on all sockets after changes to the node tree.
*/
void version_socket_update_is_used(bNodeTree *ntree);
ARegion *do_versions_add_region(int regiontype, const char *name);

View File

@ -30,7 +30,6 @@ set(SRC
armature_utils.c
editarmature_undo.c
meshlaplacian.c
pose_backup.cc
pose_edit.c
pose_group.c
pose_lib_2.c

View File

@ -24,6 +24,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_object.h"
#include "BKE_pose_backup.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@ -37,7 +38,6 @@
#include "UI_interface.h"
#include "ED_armature.h"
#include "ED_asset.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
@ -86,7 +86,7 @@ typedef struct PoseBlendData {
/* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */
static void poselib_backup_posecopy(PoseBlendData *pbd)
{
pbd->pose_backup = ED_pose_backup_create_selected_bones(pbd->ob, pbd->act);
pbd->pose_backup = BKE_pose_backup_create_selected_bones(pbd->ob, pbd->act);
if (pbd->state == POSE_BLEND_INIT) {
/* Ready for blending now. */
@ -125,7 +125,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd)
continue;
}
if (ED_pose_backup_is_selection_relevant(pbd->pose_backup) &&
if (BKE_pose_backup_is_selection_relevant(pbd->pose_backup) &&
!PBONE_SELECTED(armature, pchan->bone)) {
continue;
}
@ -152,7 +152,7 @@ static void poselib_blend_apply(bContext *C, wmOperator *op)
}
pbd->needs_redraw = false;
ED_pose_backup_restore(pbd->pose_backup);
BKE_pose_backup_restore(pbd->pose_backup);
/* The pose needs updating, whether it's for restoring the original pose or for showing the
* result of the blend. */
@ -381,7 +381,7 @@ static void poselib_blend_cleanup(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Internal pose library error, canceling operator");
ATTR_FALLTHROUGH;
case POSE_BLEND_CANCEL:
ED_pose_backup_restore(pbd->pose_backup);
BKE_pose_backup_restore(pbd->pose_backup);
break;
}
@ -406,7 +406,7 @@ static void poselib_blend_free(wmOperator *op)
poselib_tempload_exit(pbd);
/* Free temp data for operator */
ED_pose_backup_free(pbd->pose_backup);
BKE_pose_backup_free(pbd->pose_backup);
pbd->pose_backup = NULL;
MEM_SAFE_FREE(op->customdata);

View File

@ -3356,7 +3356,7 @@ void ED_gpencil_layer_merge(bGPdata *gpd,
}
}
void gpencil_layer_new_name_get(bGPdata *gpd, char *rname)
static void gpencil_layer_new_name_get(bGPdata *gpd, char *rname)
{
int index = 0;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {

View File

@ -369,19 +369,6 @@ void ED_mesh_deform_bind_callback(struct Object *object,
int verts_num,
float cagemat[4][4]);
/* Pose backups, pose_backup.c */
struct PoseBackup;
/**
* Create a backup of those bones that are animated in the given action.
*/
struct PoseBackup *ED_pose_backup_create_selected_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
struct PoseBackup *ED_pose_backup_create_all_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
bool ED_pose_backup_is_selection_relevant(const struct PoseBackup *pose_backup);
void ED_pose_backup_restore(const struct PoseBackup *pbd);
void ED_pose_backup_free(struct PoseBackup *pbd);
#ifdef __cplusplus
}
#endif

View File

@ -19,6 +19,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "BLI_array.hh"
@ -44,6 +45,7 @@
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@ -639,6 +641,17 @@ static bool apply_objects_internal_need_single_user(bContext *C)
return (ID_REAL_USERS(ob->data) > CTX_DATA_COUNT(C, selected_editable_objects));
}
static void transform_positions(blender::MutableSpan<blender::float3> positions,
const blender::float4x4 &matrix)
{
using namespace blender;
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = matrix * position;
}
});
}
static int apply_objects_internal(bContext *C,
ReportList *reports,
bool apply_loc,
@ -647,6 +660,7 @@ static int apply_objects_internal(bContext *C,
bool do_props,
bool do_single_user)
{
using namespace blender;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@ -696,7 +710,8 @@ static int apply_objects_internal(bContext *C,
OB_SURF,
OB_FONT,
OB_GPENCIL,
OB_CURVES)) {
OB_CURVES,
OB_POINTCLOUD)) {
ID *obdata = static_cast<ID *>(ob->data);
if (!do_multi_user && ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports,
@ -932,6 +947,14 @@ static int apply_objects_internal(bContext *C,
blender::bke::CurvesGeometry::wrap(curves.geometry).transform(mat);
blender::bke::CurvesGeometry::wrap(curves.geometry).calculate_bezier_auto_handles();
}
else if (ob->type == OB_POINTCLOUD) {
PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
bke::SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", ATTR_DOMAIN_POINT);
transform_positions(position.span, float4x4(mat));
position.finish();
}
else if (ob->type == OB_CAMERA) {
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
@ -1230,8 +1253,29 @@ enum {
ORIGIN_TO_CENTER_OF_MASS_VOLUME,
};
static float3 calculate_mean(const blender::Span<blender::float3> values)
{
if (values.is_empty()) {
return float3(0);
}
/* TODO: Use a method that avoids overflow. */
return std::accumulate(values.begin(), values.end(), float3(0)) / values.size();
}
static void translate_positions(blender::MutableSpan<blender::float3> positions,
const blender::float3 &translation)
{
using namespace blender;
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
}
});
}
static int object_origin_set_exec(bContext *C, wmOperator *op)
{
using namespace blender;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
@ -1653,9 +1697,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
else if (around == V3D_AROUND_CENTER_MEDIAN) {
Span<float3> positions = curves.positions();
cent = std::accumulate(positions.begin(), positions.end(), float3(0)) /
curves.points_num();
cent = calculate_mean(curves.positions());
}
tot_change++;
@ -1663,6 +1705,39 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
curves_id.id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
else if (ob->type == OB_POINTCLOUD) {
PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
bke::SpanAttributeWriter positions = attributes.lookup_or_add_for_write_span<float3>(
"position", ATTR_DOMAIN_POINT);
if (ELEM(centermode, ORIGIN_TO_CENTER_OF_MASS_SURFACE, ORIGIN_TO_CENTER_OF_MASS_VOLUME) ||
!ELEM(around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN)) {
BKE_report(op->reports,
RPT_WARNING,
"Point cloud object does not support this set origin operation");
continue;
}
if (centermode == ORIGIN_TO_CURSOR) {
/* Done. */
}
else if (around == V3D_AROUND_CENTER_BOUNDS) {
float3 min(std::numeric_limits<float>::max());
float3 max(-std::numeric_limits<float>::max());
if (pointcloud.bounds_min_max(min, max)) {
cent = math::midpoint(min, max);
}
}
else if (around == V3D_AROUND_CENTER_MEDIAN) {
cent = calculate_mean(positions.span);
}
tot_change++;
translate_positions(positions.span, -cent);
positions.finish();
pointcloud.id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
/* offset other selected objects */
if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {

View File

@ -57,6 +57,7 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_pose_backup.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_texture.h"
@ -81,7 +82,6 @@
#include "WM_api.h"
#include "WM_types.h"
#include "ED_armature.h"
#include "ED_datafiles.h"
#include "ED_render.h"
#include "ED_screen.h"
@ -955,7 +955,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
/* Create a backup of the current pose. */
struct bAction *action = (struct bAction *)preview->id;
struct PoseBackup *pose_backup = ED_pose_backup_create_all_bones(object, action);
struct PoseBackup *pose_backup = BKE_pose_backup_create_all_bones(object, action);
/* Apply the Action as pose, so that it can be rendered. This assumes the Action represents a
* single pose, and that thus the evaluation time doesn't matter. */
@ -974,8 +974,8 @@ static void action_preview_render_cleanup(IconPreview *preview, struct PoseBacku
if (pose_backup == nullptr) {
return;
}
ED_pose_backup_restore(pose_backup);
ED_pose_backup_free(pose_backup);
BKE_pose_backup_restore(pose_backup);
BKE_pose_backup_free(pose_backup);
DEG_id_tag_update(&preview->active_object->id, ID_RECALC_GEOMETRY);
}

View File

@ -2144,11 +2144,9 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &nodes_num);
for (int i = 0; i < nodes_num; i++) {
PBVHVertexIter vd;
bool update = false;
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[i], vd, PBVH_ITER_UNIQUE) {
*vd.mask = 1.0f;
update = true;
}
BKE_pbvh_vertex_iter_end;

View File

@ -1293,7 +1293,8 @@ static void std_node_socket_draw(
return;
}
if ((sock->in_out == SOCK_OUT) || (sock->flag & SOCK_IS_LINKED) || (sock->flag & SOCK_HIDE_VALUE)) {
if ((sock->in_out == SOCK_OUT) || (sock->flag & SOCK_IS_LINKED) ||
(sock->flag & SOCK_HIDE_VALUE)) {
node_socket_button_label(C, layout, ptr, node_ptr, text);
return;
}

View File

@ -337,6 +337,9 @@ void OBJWriter::write_poly_elements(FormatHandler &fh,
const int tot_polygons = obj_mesh_data.tot_polygons();
const int tot_deform_groups = obj_mesh_data.tot_deform_groups();
threading::EnumerableThreadSpecific<Vector<float>> group_weights;
const bke::AttributeAccessor attributes = obj_mesh_data.get_mesh()->attributes();
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler &buf, int idx) {
/* Polygon order for writing into the file is not necessarily the same
@ -372,10 +375,6 @@ void OBJWriter::write_poly_elements(FormatHandler &fh,
}
}
const bke::AttributeAccessor attributes = obj_mesh_data.get_mesh()->attributes();
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
/* Write material name and material group if different from previous. */
if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) {
const int16_t prev_mat = idx == 0 ? NEGATIVE_INIT : std::max(0, material_indices[prev_i]);
@ -392,7 +391,7 @@ void OBJWriter::write_poly_elements(FormatHandler &fh,
if (export_params_.export_material_groups) {
std::string object_name = obj_mesh_data.get_object_name();
spaces_to_underscores(object_name);
fh.write_obj_group(object_name + "_" + mat_name);
buf.write_obj_group(object_name + "_" + mat_name);
}
buf.write_obj_usemtl(mat_name);
}

View File

@ -192,6 +192,14 @@ typedef struct Object_Runtime {
*/
struct Mesh *object_as_temp_mesh;
/**
* Backup of the object's pose (might be a subset, i.e. not contain all bones).
*
* Created by `BKE_pose_backup_create_on_object()`. This memory is owned by the Object.
* It is freed along with the object, or when `BKE_pose_backup_clear()` is called.
*/
struct PoseBackup *pose_backup;
/**
* This is a curve representation of corresponding object.
* It created when Python calls `object.to_curve()`.
@ -200,6 +208,7 @@ typedef struct Object_Runtime {
/** Runtime evaluated curve-specific data, not stored in the file. */
struct CurveCache *curve_cache;
void *_pad4;
unsigned short local_collections_bits;
short _pad2[3];

View File

@ -712,9 +712,9 @@ static void rna_AttributeGroup_active_color_name_set(PointerRNA *ptr, const char
ID *id = ptr->owner_id;
if (GS(id->name) == ID_ME) {
Mesh *mesh = (Mesh *)id;
MEM_SAFE_FREE(mesh->default_color_attribute);
MEM_SAFE_FREE(mesh->active_color_attribute);
if (value[0]) {
mesh->default_color_attribute = BLI_strdup(value);
mesh->active_color_attribute = BLI_strdup(value);
}
}
}

View File

@ -25,6 +25,7 @@
# include "BKE_animsys.h"
# include "BKE_armature.h"
# include "BKE_context.h"
# include "BKE_pose_backup.h"
# include "DNA_action_types.h"
# include "DNA_anim_types.h"
@ -108,6 +109,56 @@ static void rna_Pose_apply_pose_from_action(ID *pose_owner,
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner);
}
static void rna_Pose_blend_pose_from_action(ID *pose_owner,
bContext *C,
bAction *action,
const float blend_factor,
const float evaluation_time)
{
BLI_assert(GS(pose_owner->name) == ID_OB);
Object *pose_owner_ob = (Object *)pose_owner;
AnimationEvalContext anim_eval_context = {CTX_data_depsgraph_pointer(C), evaluation_time};
BKE_pose_apply_action_blend(pose_owner_ob, action, &anim_eval_context, blend_factor);
/* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */
DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner);
}
static void rna_Pose_backup_create(ID *pose_owner, bAction *action)
{
BLI_assert(GS(pose_owner->name) == ID_OB);
Object *pose_owner_ob = (Object *)pose_owner;
BKE_pose_backup_create_on_object(pose_owner_ob, action);
}
static bool rna_Pose_backup_restore(ID *pose_owner, bContext *C)
{
BLI_assert(GS(pose_owner->name) == ID_OB);
Object *pose_owner_ob = (Object *)pose_owner;
const bool success = BKE_pose_backup_restore_on_object(pose_owner_ob);
if (!success) {
return false;
}
/* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */
DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner);
return true;
}
static void rna_Pose_backup_clear(ID *pose_owner)
{
BLI_assert(GS(pose_owner->name) == ID_OB);
Object *pose_owner_ob = (Object *)pose_owner;
BKE_pose_backup_clear(pose_owner_ob);
}
#else
void RNA_api_pose(StructRNA *srna)
@ -121,10 +172,8 @@ void RNA_api_pose(StructRNA *srna)
func,
"Apply the given action to this pose by evaluating it at a specific time. Only updates the "
"pose of selected bones, or all bones if none are selected.");
parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func,
"evaluation_time",
0.0f,
@ -134,6 +183,67 @@ void RNA_api_pose(StructRNA *srna)
"Time at which the given action is evaluated to obtain the pose",
-FLT_MAX,
FLT_MAX);
func = RNA_def_function(srna, "blend_pose_from_action", "rna_Pose_blend_pose_from_action");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func,
"Blend the given action into this pose by evaluating it at a "
"specific time. Only updates the "
"pose of selected bones, or all bones if none are selected.");
parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func,
"blend_factor",
1.0f,
0.0f,
1.0f,
"Blend Factor",
"How much the given Action affects the final pose",
0.0f,
1.0f);
parm = RNA_def_float(func,
"evaluation_time",
0.0f,
-FLT_MAX,
FLT_MAX,
"Evaluation Time",
"Time at which the given action is evaluated to obtain the pose",
-FLT_MAX,
FLT_MAX);
func = RNA_def_function(srna, "backup_create", "rna_Pose_backup_create");
RNA_def_function_ui_description(
func,
"Create a backup of the current pose. Only those bones that are animated in the Action are "
"backed up. The object owns the backup, and each object can have only one backup at a time. "
"When you no longer need it, it must be freed use `backup_clear()`.");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF);
parm = RNA_def_pointer(func,
"action",
"Action",
"Action",
"An Action with animation data for the bones. Only the animated bones "
"will be included in the backup.");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "backup_restore", "rna_Pose_backup_restore");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func,
"Restore the previously made pose backup. This can be called "
"multiple times. See `Pose.backup_create()` for more info.");
/* return value */
parm = RNA_def_boolean(
func,
"success",
false,
"",
"`True` when the backup was restored, `False` if there was no backup to restore.");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "backup_clear", "rna_Pose_backup_clear");
RNA_def_function_ui_description(
func, "Free a previously made pose backup. See `Pose.backup_create()` for more info.");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF);
}
void RNA_api_pose_channel(StructRNA *srna)

View File

@ -101,6 +101,15 @@ static void rna_trackingPlaneTracks_begin(CollectionPropertyIterator *iter, Poin
rna_iterator_listbase_begin(iter, &tracking_camera_object->plane_tracks, NULL);
}
static PointerRNA rna_trackingReconstruction_get(PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
MovieTrackingObject *tracking_camera_object = BKE_tracking_object_get_camera(&clip->tracking);
return rna_pointer_inherit_refine(
ptr, &RNA_MovieTrackingReconstruction, &tracking_camera_object->reconstruction);
}
static void rna_trackingObjects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
@ -2609,6 +2618,7 @@ static void rna_def_tracking(BlenderRNA *brna)
/* reconstruction */
prop = RNA_def_property(srna, "reconstruction", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "reconstruction_legacy");
RNA_def_property_pointer_funcs(prop, "rna_trackingReconstruction_get", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MovieTrackingReconstruction");
/* objects */

View File

@ -34,6 +34,24 @@ static bool use_translate(const float3 rotation, const float3 scale)
return true;
}
static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
{
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
}
});
}
static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
{
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = matrix * position;
}
});
}
static void translate_mesh(Mesh &mesh, const float3 translation)
{
if (!math::is_zero(translation)) {
@ -51,9 +69,7 @@ static void translate_pointcloud(PointCloud &pointcloud, const float3 translatio
MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", ATTR_DOMAIN_POINT);
for (const int i : position.span.index_range()) {
position.span[i] += translation;
}
translate_positions(position.span, translation);
position.finish();
}
@ -62,26 +78,28 @@ static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transfo
MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", ATTR_DOMAIN_POINT);
for (const int i : position.span.index_range()) {
position.span[i] = transform * position.span[i];
}
transform_positions(position.span, transform);
position.finish();
}
static void translate_instances(bke::Instances &instances, const float3 translation)
{
MutableSpan<float4x4> transforms = instances.transforms();
for (float4x4 &transform : transforms) {
add_v3_v3(transform.ptr()[3], translation);
}
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
add_v3_v3(instance_transform.ptr()[3], translation);
}
});
}
static void transform_instances(bke::Instances &instances, const float4x4 &transform)
{
MutableSpan<float4x4> transforms = instances.transforms();
for (float4x4 &instance_transform : transforms) {
instance_transform = transform * instance_transform;
}
threading::parallel_for(transforms.index_range(), 1024, [&](const IndexRange range) {
for (float4x4 &instance_transform : transforms.slice(range)) {
instance_transform = transform * instance_transform;
}
});
}
static void transform_volume(GeoNodeExecParams &params,