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

This commit is contained in:
Hans Goudey 2023-01-02 13:52:04 -05:00
commit 06265a6a06
29 changed files with 452 additions and 113 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

@ -1462,7 +1462,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2);
mesh->totvert = (int)process.curvertex;
mesh->totvert = int(process.curvertex);
CustomData_add_layer_named(
&mesh->vdata, CD_PROP_FLOAT3, CD_ASSIGN, process.co, mesh->totvert, "position");
process.co = nullptr;

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

@ -1675,8 +1675,11 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
continue;
}
OperationCode target_op = driver_targets_bbone ? OperationCode::BONE_SEGMENTS :
OperationCode::BONE_LOCAL;
OperationCode target_op = OperationCode::BONE_LOCAL;
if (driver_targets_bbone) {
target_op = check_pchan_has_bbone_segments(object, pchan) ? OperationCode::BONE_SEGMENTS :
OperationCode::BONE_DONE;
}
OperationKey bone_key(&object->id, NodeType::BONE, pchan->name, target_op);
add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone");
}

View File

@ -105,8 +105,7 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod
* times.
* This is a thread-safe modification as the node's flags are only read for a non-scheduled nodes
* and this node has been scheduled. */
operation_node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE |
DEPSOP_FLAG_USER_MODIFIED);
operation_node->flag &= ~DEPSOP_FLAG_CLEAR_ON_EVAL;
}
void deg_task_run_func(TaskPool *pool, void *taskdata)
@ -270,6 +269,10 @@ void schedule_node(DepsgraphEvalState *state,
bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, uint8_t(true));
if (!is_scheduled) {
if (node->is_noop()) {
/* Clear flags to avoid affecting subsequent update propagation.
* For normal nodes these are cleared when it is evaluated. */
node->flag &= ~DEPSOP_FLAG_CLEAR_ON_EVAL;
/* skip NOOP node, schedule children right away */
schedule_children(state, node, schedule_fn);
}

View File

@ -224,6 +224,10 @@ enum OperationFlag {
/* Set of flags which gets flushed along the relations. */
DEPSOP_FLAG_FLUSH = (DEPSOP_FLAG_USER_MODIFIED),
/* Set of flags which get cleared upon evaluation. */
DEPSOP_FLAG_CLEAR_ON_EVAL = (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE |
DEPSOP_FLAG_USER_MODIFIED),
};
/* Atomic Operation - Base type for all operations */

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"
@ -83,10 +83,12 @@ typedef struct PoseBlendData {
char headerstr[UI_MAX_DRAW_STR];
} PoseBlendData;
static void poselib_blend_flip_pose(bContext *C, wmOperator *op);
/* 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 +127,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 +154,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. */
@ -178,7 +180,7 @@ static void poselib_blend_set_factor(PoseBlendData *pbd, const float new_factor)
}
/* Return operator return value. */
static int poselib_blend_handle_event(bContext *UNUSED(C), wmOperator *op, const wmEvent *event)
static int poselib_blend_handle_event(bContext *C, wmOperator *op, const wmEvent *event)
{
PoseBlendData *pbd = op->customdata;
@ -225,7 +227,9 @@ static int poselib_blend_handle_event(bContext *UNUSED(C), wmOperator *op, const
pbd->needs_redraw = true;
break;
/* TODO(Sybren): use better UI for slider. */
case EVT_FKEY:
poselib_blend_flip_pose(C, op);
break;
}
return OPERATOR_RUNNING_MODAL;
@ -276,6 +280,30 @@ static bAction *flip_pose(bContext *C, Object *ob, bAction *action)
return action_copy;
}
/* Flip the target pose the interactive blend operator is currently using. */
static void poselib_blend_flip_pose(bContext *C, wmOperator *op)
{
PoseBlendData *pbd = op->customdata;
bAction *old_action = pbd->act;
bAction *new_action = flip_pose(C, pbd->ob, old_action);
/* Before flipping over to the other side, this side needs to be restored. */
BKE_pose_backup_restore(pbd->pose_backup);
BKE_pose_backup_free(pbd->pose_backup);
pbd->pose_backup = NULL;
if (pbd->free_action) {
BKE_id_free(NULL, old_action);
}
pbd->free_action = true;
pbd->act = new_action;
pbd->needs_redraw = true;
/* Refresh the pose backup to use the flipped bones. */
poselib_backup_posecopy(pbd);
}
/* Return true on success, false if the context isn't suitable. */
static bool poselib_blend_init_data(bContext *C, wmOperator *op, const wmEvent *event)
{
@ -381,7 +409,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 +434,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);
@ -461,7 +489,11 @@ static int poselib_blend_modal(bContext *C, wmOperator *op, const wmEvent *event
strcpy(tab_string, TIP_("[Tab] - Show blended pose"));
}
BLI_snprintf(status_string, sizeof(status_string), "%s | %s", tab_string, slider_string);
BLI_snprintf(status_string,
sizeof(status_string),
"[F] - Flip pose | %s | %s",
tab_string,
slider_string);
ED_workspace_status_text(C, status_string);
poselib_blend_apply(C, op);

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

@ -75,10 +75,13 @@ typedef struct tSlider {
/** Last mouse cursor position used for mouse movement delta calculation. */
float last_cursor[2];
/** Enable range beyond 0-100%. */
/** Enable range beyond 0-100%.
* This is set by the code that uses the slider, as not all operations support
* extrapolation. */
bool allow_overshoot;
/** Allow overshoot or clamp between 0% and 100%. */
/** Allow overshoot or clamp between 0% and 100%.
* This is set by the artist while using the slider. */
bool overshoot;
/** Move factor in 10% steps. */

View File

@ -355,7 +355,7 @@ class Executor {
this->ensure_thread_locals();
/* Construct all node states in parallel. */
threading::parallel_for(nodes.index_range(), 256, [&](const IndexRange range) {
LinearAllocator<> &allocator = this->get_main_or_local_allocator();
LinearAllocator<> &allocator = thread_locals_->local().allocator;
construct_node_range(range, allocator);
});
}

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

@ -6,11 +6,10 @@
*/
/* Screw modifier: revolves the edges about an axis */
#include <limits.h>
#include <climits>
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
@ -53,7 +52,7 @@ static void initData(ModifierData *md)
}
/** Used for gathering edge connectivity. */
typedef struct ScrewVertConnect {
struct ScrewVertConnect {
/** Distance from the center axis. */
float dist_sq;
/** Location relative to the transformed axis. */
@ -63,14 +62,14 @@ typedef struct ScrewVertConnect {
/** Edges on either side, a bit of a waste since each edge ref's 2 edges. */
MEdge *e[2];
char flag;
} ScrewVertConnect;
};
typedef struct ScrewVertIter {
struct ScrewVertIter {
ScrewVertConnect *v_array;
ScrewVertConnect *v_poin;
uint v, v_other;
MEdge *e;
} ScrewVertIter;
};
#define SV_UNUSED (UINT_MAX)
#define SV_INVALID ((UINT_MAX)-1)
@ -336,9 +335,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
/* apply the multiplier */
angle *= (float)ltmd->iter;
screw_ofs *= (float)ltmd->iter;
uv_u_scale = 1.0f / (float)(step_tot);
angle *= float(ltmd->iter);
screw_ofs *= float(ltmd->iter);
uv_u_scale = 1.0f / float(step_tot);
/* multiplying the steps is a bit tricky, this works best */
step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);
@ -473,22 +472,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* Sort edge verts for correct face flipping
* NOT REALLY NEEDED but face flipping is nice. */
/* Notice!
*
* Since we are only ordering the edges here it can avoid mallocing the
* extra space by abusing the vert array before its filled with new verts.
* The new array for vert_connect must be at least `sizeof(ScrewVertConnect) * totvert`
* and the size of our resulting meshes array is `sizeof(MVert) * totvert * 3`
* so its safe to use the second 2 thirds of #MVert the array for vert_connect,
* just make sure #ScrewVertConnect struct is no more than twice as big as #MVert,
* at the moment there is no chance of that being a problem,
* unless #MVert becomes half its current size.
*
* once the edges are ordered, vert_connect is not needed and it can be used for verts
*
* This makes the modifier faster with one less allocate.
*/
vert_connect = static_cast<ScrewVertConnect *>(
MEM_malloc_arrayN(totvert, sizeof(ScrewVertConnect), __func__));
/* skip the first slice of verts. */

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,