Transform: support multi-threading for most modes
Multi-threading support for transform modes: bevel-weight, crease, push-pull, rotate, shear, shrink-fatten, skin-resize, to-sphere, trackball & translate. This is done using a parallel loop over transform data. From testing a 1.5million polygon mesh on a 32 core system the overall performance gains were between ~20-28% To ensure the code is thread-safe arguments to shared data are const. Reviewed By: mano-wii
This commit is contained in:
parent
501d2443d0
commit
2d4ec90497
Notes:
blender-bot
2023-02-14 07:31:32 +01:00
Referenced by commit cdc1c60f5b
, Fix T102466: push/pull doesn't work if applied to many vertices
Referenced by issue #88550, Mesh Optimization Project Progress
Referenced by issue #87228, Apply random selection factor precisely for all operators
|
@ -149,6 +149,8 @@ typedef struct TransData {
|
|||
short protectflag;
|
||||
} TransData;
|
||||
|
||||
#define TRANSDATA_THREAD_LIMIT 1024
|
||||
|
||||
/** #TransData.flag */
|
||||
enum {
|
||||
TD_SELECTED = 1 << 0,
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -39,6 +40,50 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Bevel Weight) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_BevelWeight {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float weight;
|
||||
};
|
||||
|
||||
static void transdata_elem_bevel_weight(const TransInfo *UNUSED(t),
|
||||
const TransDataContainer *UNUSED(tc),
|
||||
TransData *td,
|
||||
const float weight)
|
||||
{
|
||||
if (td->val == NULL) {
|
||||
return;
|
||||
}
|
||||
*td->val = td->ival + weight * td->factor;
|
||||
if (*td->val < 0.0f) {
|
||||
*td->val = 0.0f;
|
||||
}
|
||||
if (*td->val > 1.0f) {
|
||||
*td->val = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void transdata_elem_bevel_weight_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_BevelWeight *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_bevel_weight(data->t, data->tc, td, data->weight);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Bevel Weight)
|
||||
* \{ */
|
||||
|
@ -83,18 +128,25 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
|
|||
}
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->val) {
|
||||
*td->val = td->ival + weight * td->factor;
|
||||
if (*td->val < 0.0f) {
|
||||
*td->val = 0.0f;
|
||||
}
|
||||
if (*td->val > 1.0f) {
|
||||
*td->val = 1.0f;
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_bevel_weight(t, tc, td, weight);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_BevelWeight data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.weight = weight,
|
||||
};
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_bevel_weight_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
recalcData(t);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -39,6 +40,51 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Crease) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_Crease {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float crease;
|
||||
};
|
||||
|
||||
static void transdata_elem_crease(const TransInfo *UNUSED(t),
|
||||
const TransDataContainer *UNUSED(tc),
|
||||
TransData *td,
|
||||
const float crease)
|
||||
{
|
||||
if (td->val == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
*td->val = td->ival + crease * td->factor;
|
||||
if (*td->val < 0.0f) {
|
||||
*td->val = 0.0f;
|
||||
}
|
||||
if (*td->val > 1.0f) {
|
||||
*td->val = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void transdata_elem_crease_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_Crease *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_crease(data->t, data->tc, td, data->crease);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Crease)
|
||||
* \{ */
|
||||
|
@ -83,22 +129,25 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
|
|||
}
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (td->val) {
|
||||
*td->val = td->ival + crease * td->factor;
|
||||
if (*td->val < 0.0f) {
|
||||
*td->val = 0.0f;
|
||||
}
|
||||
if (*td->val > 1.0f) {
|
||||
*td->val = 1.0f;
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_crease(t, tc, td, crease);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_Crease data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.crease = crease,
|
||||
};
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_crease_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
recalcData(t);
|
||||
|
@ -124,4 +173,5 @@ void initCrease(TransInfo *t)
|
|||
|
||||
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -40,13 +41,76 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Push/Pull) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_PushPull {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
|
||||
float distance;
|
||||
const float axis_global[3];
|
||||
bool is_data_space;
|
||||
};
|
||||
|
||||
static void transdata_elem_push_pull(const TransInfo *t,
|
||||
const TransDataContainer *tc,
|
||||
TransData *td,
|
||||
const float distance,
|
||||
const float axis_global[3],
|
||||
const bool is_data_space)
|
||||
{
|
||||
float vec[3];
|
||||
sub_v3_v3v3(vec, tc->center_local, td->center);
|
||||
if (t->con.applyRot && t->con.mode & CON_APPLY) {
|
||||
float axis[3];
|
||||
copy_v3_v3(axis, axis_global);
|
||||
t->con.applyRot(t, tc, td, axis, NULL);
|
||||
|
||||
mul_m3_v3(td->smtx, axis);
|
||||
if (isLockConstraint(t)) {
|
||||
float dvec[3];
|
||||
project_v3_v3v3(dvec, vec, axis);
|
||||
sub_v3_v3(vec, dvec);
|
||||
}
|
||||
else {
|
||||
project_v3_v3v3(vec, vec, axis);
|
||||
}
|
||||
}
|
||||
normalize_v3_length(vec, distance * td->factor);
|
||||
if (is_data_space) {
|
||||
mul_m3_v3(td->smtx, vec);
|
||||
}
|
||||
|
||||
add_v3_v3v3(td->loc, td->iloc, vec);
|
||||
}
|
||||
|
||||
static void transdata_elem_push_pull_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_PushPull *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_push_pull(
|
||||
data->t, data->tc, td, data->distance, data->axis_global, data->is_data_space);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Push/Pull)
|
||||
* \{ */
|
||||
|
||||
static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
|
||||
{
|
||||
float vec[3], axis_global[3];
|
||||
float axis_global[3];
|
||||
float distance;
|
||||
int i;
|
||||
char str[UI_MAX_DRAW_STR];
|
||||
|
@ -80,34 +144,26 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
|
|||
const bool is_data_space = (t->options & CTX_POSE_BONE) != 0;
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_v3_v3v3(vec, tc->center_local, td->center);
|
||||
if (t->con.applyRot && t->con.mode & CON_APPLY) {
|
||||
float axis[3];
|
||||
copy_v3_v3(axis, axis_global);
|
||||
t->con.applyRot(t, tc, td, axis, NULL);
|
||||
|
||||
mul_m3_v3(td->smtx, axis);
|
||||
if (isLockConstraint(t)) {
|
||||
float dvec[3];
|
||||
project_v3_v3v3(dvec, vec, axis);
|
||||
sub_v3_v3(vec, dvec);
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
project_v3_v3v3(vec, vec, axis);
|
||||
}
|
||||
}
|
||||
normalize_v3_length(vec, distance * td->factor);
|
||||
if (is_data_space) {
|
||||
mul_m3_v3(td->smtx, vec);
|
||||
}
|
||||
|
||||
add_v3_v3v3(td->loc, td->iloc, vec);
|
||||
transdata_elem_push_pull(t, tc, td, distance, axis_global, is_data_space);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_PushPull data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.axis_global = {UNPACK3(axis_global)},
|
||||
.is_data_space = is_data_space,
|
||||
};
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_push_pull_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -38,6 +39,30 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Resize) Element
|
||||
* \{ */
|
||||
|
||||
struct ElemResizeData {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float mat[3][3];
|
||||
};
|
||||
|
||||
static void element_resize_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct ElemResizeData *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
ElementResize(data->t, data->tc, td, data->mat);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Resize)
|
||||
* \{ */
|
||||
|
@ -123,13 +148,27 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
|
|||
copy_m3_m3(t->mat, mat); /* used in gizmo */
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ElementResize(t, tc, td, mat);
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ElementResize(t, tc, td, mat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct ElemResizeData data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
};
|
||||
copy_m3_m3(data.mat, mat);
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, element_resize_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -36,6 +37,140 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Rotation) Matrix Cache
|
||||
* \{ */
|
||||
|
||||
struct RotateMatrixCache {
|
||||
/**
|
||||
* Counter for needed updates (when we need to update to non-default matrix,
|
||||
* we also need another update on next iteration to go back to default matrix,
|
||||
* hence the '2' value used here, instead of a mere boolean).
|
||||
*/
|
||||
short do_update_matrix;
|
||||
float mat[3][3];
|
||||
};
|
||||
|
||||
static void rmat_cache_init(struct RotateMatrixCache *rmc, const float angle, const float axis[3])
|
||||
{
|
||||
axis_angle_normalized_to_mat3(rmc->mat, axis, angle);
|
||||
rmc->do_update_matrix = 0;
|
||||
}
|
||||
|
||||
static void rmat_cache_reset(struct RotateMatrixCache *rmc)
|
||||
{
|
||||
rmc->do_update_matrix = 2;
|
||||
}
|
||||
|
||||
static void rmat_cache_update(struct RotateMatrixCache *rmc,
|
||||
const float axis[3],
|
||||
const float angle)
|
||||
{
|
||||
if (rmc->do_update_matrix > 0) {
|
||||
axis_angle_normalized_to_mat3(rmc->mat, axis, angle);
|
||||
rmc->do_update_matrix--;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Rotation) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_Rotate {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
const float axis[3];
|
||||
float angle;
|
||||
float angle_step;
|
||||
bool is_large_rotation;
|
||||
};
|
||||
|
||||
struct TransDataArgs_RotateTLS {
|
||||
struct RotateMatrixCache rmc;
|
||||
};
|
||||
|
||||
static void transdata_elem_rotate(const TransInfo *t,
|
||||
const TransDataContainer *tc,
|
||||
TransData *td,
|
||||
const float axis[3],
|
||||
const float angle,
|
||||
const float angle_step,
|
||||
const bool is_large_rotation,
|
||||
struct RotateMatrixCache *rmc)
|
||||
{
|
||||
float axis_buffer[3];
|
||||
const float *axis_final = axis;
|
||||
|
||||
float angle_final = angle;
|
||||
if (t->con.applyRot) {
|
||||
copy_v3_v3(axis_buffer, axis);
|
||||
axis_final = axis_buffer;
|
||||
t->con.applyRot(t, tc, td, axis_buffer, NULL);
|
||||
angle_final = angle * td->factor;
|
||||
/* Even though final angle might be identical to orig value,
|
||||
* we have to update the rotation matrix in that case... */
|
||||
rmat_cache_reset(rmc);
|
||||
}
|
||||
else if (t->flag & T_PROP_EDIT) {
|
||||
angle_final = angle * td->factor;
|
||||
}
|
||||
|
||||
/* Rotation is very likely to be above 180°, we need to do rotation by steps.
|
||||
* Note that this is only needed when doing 'absolute' rotation
|
||||
* (i.e. from initial rotation again, typically when using numinput).
|
||||
* regular incremental rotation (from mouse/widget/...) will be called often enough,
|
||||
* hence steps are small enough to be properly handled without that complicated trick.
|
||||
* Note that we can only do that kind of stepped rotation if we have initial rotation values
|
||||
* (and access to some actual rotation value storage).
|
||||
* Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing).
|
||||
* Also need to be in Euler rotation mode, the others never allow more than one turn anyway.
|
||||
*/
|
||||
if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) {
|
||||
copy_v3_v3(td->ext->rot, td->ext->irot);
|
||||
for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final);
|
||||
angle_progress += angle_step) {
|
||||
axis_angle_normalized_to_mat3(rmc->mat, axis_final, angle_progress);
|
||||
ElementRotation(t, tc, td, rmc->mat, t->around);
|
||||
}
|
||||
rmat_cache_reset(rmc);
|
||||
}
|
||||
else if (angle_final != angle) {
|
||||
rmat_cache_reset(rmc);
|
||||
}
|
||||
|
||||
rmat_cache_update(rmc, axis_final, angle_final);
|
||||
|
||||
ElementRotation(t, tc, td, rmc->mat, t->around);
|
||||
}
|
||||
|
||||
static void transdata_elem_rotate_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
struct TransDataArgs_Rotate *data = iter_data_v;
|
||||
struct TransDataArgs_RotateTLS *tls_data = tls->userdata_chunk;
|
||||
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_rotate(data->t,
|
||||
data->tc,
|
||||
td,
|
||||
data->axis,
|
||||
data->angle,
|
||||
data->angle_step,
|
||||
data->is_large_rotation,
|
||||
&tls_data->rmc);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Rotation)
|
||||
* \{ */
|
||||
|
@ -115,12 +250,9 @@ static float large_rotation_limit(float angle)
|
|||
|
||||
static void applyRotationValue(TransInfo *t,
|
||||
float angle,
|
||||
float axis[3],
|
||||
const float axis[3],
|
||||
const bool is_large_rotation)
|
||||
{
|
||||
float mat[3][3];
|
||||
int i;
|
||||
|
||||
const float angle_sign = angle < 0.0f ? -1.0f : 1.0f;
|
||||
/* We cannot use something too close to 180°, or 'continuous' rotation may fail
|
||||
* due to computing error... */
|
||||
|
@ -132,60 +264,37 @@ static void applyRotationValue(TransInfo *t,
|
|||
angle = large_rotation_limit(angle);
|
||||
}
|
||||
|
||||
axis_angle_normalized_to_mat3(mat, axis, angle);
|
||||
/* Counter for needed updates (when we need to update to non-default matrix,
|
||||
* we also need another update on next iteration to go back to default matrix,
|
||||
* hence the '2' value used here, instead of a mere boolean). */
|
||||
short do_update_matrix = 0;
|
||||
struct RotateMatrixCache rmc = {0};
|
||||
rmat_cache_init(&rmc, angle, axis);
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float angle_final = angle;
|
||||
if (t->con.applyRot) {
|
||||
t->con.applyRot(t, tc, td, axis, NULL);
|
||||
angle_final = angle * td->factor;
|
||||
/* Even though final angle might be identical to orig value,
|
||||
* we have to update the rotation matrix in that case... */
|
||||
do_update_matrix = 2;
|
||||
}
|
||||
else if (t->flag & T_PROP_EDIT) {
|
||||
angle_final = angle * td->factor;
|
||||
}
|
||||
|
||||
/* Rotation is very likely to be above 180°, we need to do rotation by steps.
|
||||
* Note that this is only needed when doing 'absolute' rotation
|
||||
* (i.e. from initial rotation again, typically when using numinput).
|
||||
* regular incremental rotation (from mouse/widget/...) will be called often enough,
|
||||
* hence steps are small enough to be properly handled without that complicated trick.
|
||||
* Note that we can only do that kind of stepped rotation if we have initial rotation values
|
||||
* (and access to some actual rotation value storage).
|
||||
* Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing).
|
||||
* Also need to be in Euler rotation mode, the others never allow more than one turn anyway.
|
||||
*/
|
||||
if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) {
|
||||
copy_v3_v3(td->ext->rot, td->ext->irot);
|
||||
for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final);
|
||||
angle_progress += angle_step) {
|
||||
axis_angle_normalized_to_mat3(mat, axis, angle_progress);
|
||||
ElementRotation(t, tc, td, mat, t->around);
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
do_update_matrix = 2;
|
||||
}
|
||||
else if (angle_final != angle) {
|
||||
do_update_matrix = 2;
|
||||
transdata_elem_rotate(t, tc, td, axis, angle, angle_step, is_large_rotation, &rmc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_Rotate data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.axis = {UNPACK3(axis)},
|
||||
.angle = angle,
|
||||
.angle_step = angle_step,
|
||||
.is_large_rotation = is_large_rotation,
|
||||
};
|
||||
struct TransDataArgs_RotateTLS tls_data = {
|
||||
.rmc = rmc,
|
||||
};
|
||||
|
||||
if (do_update_matrix > 0) {
|
||||
axis_angle_normalized_to_mat3(mat, axis, angle_final);
|
||||
do_update_matrix--;
|
||||
}
|
||||
|
||||
ElementRotation(t, tc, td, mat, t->around);
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.userdata_chunk = &tls_data;
|
||||
settings.userdata_chunk_size = sizeof(tls_data);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_rotate_fn, &settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -43,6 +44,79 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Shear) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_Shear {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float totmat[3][3];
|
||||
bool is_local_center;
|
||||
};
|
||||
|
||||
static void transdata_elem_shear(const TransInfo *t,
|
||||
const TransDataContainer *tc,
|
||||
TransData *td,
|
||||
const float totmat[3][3],
|
||||
const bool is_local_center)
|
||||
{
|
||||
float tmat[3][3];
|
||||
const float *center;
|
||||
if (t->flag & T_EDIT) {
|
||||
mul_m3_series(tmat, td->smtx, totmat, td->mtx);
|
||||
}
|
||||
else {
|
||||
copy_m3_m3(tmat, totmat);
|
||||
}
|
||||
|
||||
if (is_local_center) {
|
||||
center = td->center;
|
||||
}
|
||||
else {
|
||||
center = tc->center_local;
|
||||
}
|
||||
|
||||
float vec[3];
|
||||
sub_v3_v3v3(vec, td->iloc, center);
|
||||
mul_m3_v3(tmat, vec);
|
||||
add_v3_v3(vec, center);
|
||||
sub_v3_v3(vec, td->iloc);
|
||||
|
||||
if (t->options & CTX_GPENCIL_STROKES) {
|
||||
/* Grease pencil multi-frame falloff. */
|
||||
bGPDstroke *gps = (bGPDstroke *)td->extra;
|
||||
if (gps != NULL) {
|
||||
mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, td->factor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, td->factor);
|
||||
}
|
||||
|
||||
add_v3_v3v3(td->loc, td->iloc, vec);
|
||||
}
|
||||
|
||||
static void transdata_elem_shear_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_Shear *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_shear(data->t, data->tc, td, data->totmat, data->is_local_center);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Shear)
|
||||
* \{ */
|
||||
|
@ -117,8 +191,7 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
|
|||
|
||||
static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
|
||||
{
|
||||
float vec[3];
|
||||
float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3];
|
||||
float smat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3];
|
||||
float value;
|
||||
int i;
|
||||
char str[UI_MAX_DRAW_STR];
|
||||
|
@ -160,47 +233,26 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
|
|||
mul_m3_series(totmat, axismat_inv, smat, axismat);
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
const float *center;
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->flag & T_EDIT) {
|
||||
mul_m3_series(tmat, td->smtx, totmat, td->mtx);
|
||||
}
|
||||
else {
|
||||
copy_m3_m3(tmat, totmat);
|
||||
}
|
||||
|
||||
if (is_local_center) {
|
||||
center = td->center;
|
||||
}
|
||||
else {
|
||||
center = tc->center_local;
|
||||
}
|
||||
|
||||
sub_v3_v3v3(vec, td->iloc, center);
|
||||
mul_m3_v3(tmat, vec);
|
||||
add_v3_v3(vec, center);
|
||||
sub_v3_v3(vec, td->iloc);
|
||||
|
||||
if (t->options & CTX_GPENCIL_STROKES) {
|
||||
/* grease pencil multiframe falloff */
|
||||
bGPDstroke *gps = (bGPDstroke *)td->extra;
|
||||
if (gps != NULL) {
|
||||
mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, td->factor);
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_shear(t, tc, td, totmat, is_local_center);
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, td->factor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_Shear data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.is_local_center = is_local_center,
|
||||
};
|
||||
copy_m3_m3(data.totmat, totmat);
|
||||
|
||||
add_v3_v3v3(td->loc, td->iloc, vec);
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_shear_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -42,6 +43,47 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Shrink-Fatten) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_ShrinkFatten {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float distance;
|
||||
};
|
||||
|
||||
static void transdata_elem_shrink_fatten(const TransInfo *t,
|
||||
const TransDataContainer *UNUSED(tc),
|
||||
TransData *td,
|
||||
const float distance)
|
||||
{
|
||||
/* Get the final offset. */
|
||||
float tdistance = distance * td->factor;
|
||||
if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) {
|
||||
tdistance *= td->ext->isize[0]; /* shell factor */
|
||||
}
|
||||
|
||||
madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
|
||||
}
|
||||
|
||||
static void transdata_elem_shrink_fatten_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_ShrinkFatten *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_shrink_fatten(data->t, data->tc, td, data->distance);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Shrink-Fatten)
|
||||
* \{ */
|
||||
|
@ -114,20 +156,24 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
|
|||
/* done with header string */
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
float tdistance; /* temp dist */
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_shrink_fatten(t, tc, td, distance);
|
||||
}
|
||||
|
||||
/* get the final offset */
|
||||
tdistance = distance * td->factor;
|
||||
if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) {
|
||||
tdistance *= td->ext->isize[0]; /* shell factor */
|
||||
}
|
||||
|
||||
madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_ShrinkFatten data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.distance = distance,
|
||||
};
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_shrink_fatten_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -37,6 +38,58 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Skin) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_SkinResize {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float mat[3][3];
|
||||
};
|
||||
|
||||
static void transdata_elem_skin_resize(const TransInfo *t,
|
||||
const TransDataContainer *UNUSED(tc),
|
||||
TransData *td,
|
||||
const float mat[3][3])
|
||||
{
|
||||
float tmat[3][3], smat[3][3];
|
||||
float fsize[3];
|
||||
|
||||
if (t->flag & T_EDIT) {
|
||||
mul_m3_m3m3(smat, mat, td->mtx);
|
||||
mul_m3_m3m3(tmat, td->smtx, smat);
|
||||
}
|
||||
else {
|
||||
copy_m3_m3(tmat, mat);
|
||||
}
|
||||
|
||||
if (t->con.applySize) {
|
||||
t->con.applySize(t, NULL, NULL, tmat);
|
||||
}
|
||||
|
||||
mat3_to_size(fsize, tmat);
|
||||
td->loc[0] = td->iloc[0] * (1 + (fsize[0] - 1) * td->factor);
|
||||
td->loc[1] = td->iloc[1] * (1 + (fsize[1] - 1) * td->factor);
|
||||
}
|
||||
|
||||
static void transdata_elem_skin_resize_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_SkinResize *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_skin_resize(data->t, data->tc, td, data->mat);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Skin)
|
||||
* \{ */
|
||||
|
@ -67,29 +120,24 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
|
|||
headerResize(t, t->values_final, str, sizeof(str));
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
float tmat[3][3], smat[3][3];
|
||||
float fsize[3];
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_skin_resize(t, tc, td, mat);
|
||||
}
|
||||
|
||||
if (t->flag & T_EDIT) {
|
||||
mul_m3_m3m3(smat, mat, td->mtx);
|
||||
mul_m3_m3m3(tmat, td->smtx, smat);
|
||||
}
|
||||
else {
|
||||
copy_m3_m3(tmat, mat);
|
||||
}
|
||||
|
||||
if (t->con.applySize) {
|
||||
t->con.applySize(t, NULL, NULL, tmat);
|
||||
}
|
||||
|
||||
mat3_to_size(fsize, tmat);
|
||||
td->loc[0] = td->iloc[0] * (1 + (fsize[0] - 1) * td->factor);
|
||||
td->loc[1] = td->iloc[1] * (1 + (fsize[1] - 1) * td->factor);
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_SkinResize data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
};
|
||||
copy_m3_m3(data.mat, mat);
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_skin_resize_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
|
@ -110,6 +111,74 @@ static void to_sphere_radius_update(TransInfo *t)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (ToSphere) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_ToSphere {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
float ratio;
|
||||
const struct ToSphereInfo to_sphere_info;
|
||||
bool is_local_center;
|
||||
bool is_data_space;
|
||||
};
|
||||
|
||||
static void transdata_elem_to_sphere(const TransInfo *UNUSED(t),
|
||||
const TransDataContainer *tc,
|
||||
TransData *td,
|
||||
const float ratio,
|
||||
const struct ToSphereInfo *to_sphere_info,
|
||||
const bool is_local_center,
|
||||
const bool is_data_space)
|
||||
{
|
||||
float vec[3];
|
||||
const float *center = is_local_center ? td->center : tc->center_local;
|
||||
if (is_data_space) {
|
||||
copy_v3_v3(vec, td->center);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(vec, td->iloc);
|
||||
}
|
||||
|
||||
sub_v3_v3(vec, center);
|
||||
const float radius = normalize_v3(vec);
|
||||
const float tratio = ratio * td->factor;
|
||||
mul_v3_fl(vec, radius * (1.0f - tratio) + to_sphere_info->radius * tratio);
|
||||
add_v3_v3(vec, center);
|
||||
|
||||
if (is_data_space) {
|
||||
sub_v3_v3(vec, td->center);
|
||||
mul_m3_v3(td->smtx, vec);
|
||||
add_v3_v3(vec, td->iloc);
|
||||
}
|
||||
|
||||
copy_v3_v3(td->loc, vec);
|
||||
}
|
||||
|
||||
static void transdata_elem_to_sphere_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_ToSphere *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_to_sphere(data->t,
|
||||
data->tc,
|
||||
td,
|
||||
data->ratio,
|
||||
&data->to_sphere_info,
|
||||
data->is_local_center,
|
||||
data->is_data_space);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (ToSphere)
|
||||
* \{ */
|
||||
|
@ -119,8 +188,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
|
|||
const bool is_local_center = transdata_check_local_center(t, t->around);
|
||||
const bool is_data_space = (t->options & CTX_POSE_BONE) != 0;
|
||||
|
||||
float vec[3];
|
||||
float ratio, radius;
|
||||
float ratio;
|
||||
int i;
|
||||
char str[UI_MAX_DRAW_STR];
|
||||
|
||||
|
@ -147,40 +215,33 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
|
|||
BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext);
|
||||
}
|
||||
|
||||
const struct ToSphereInfo *data = t->custom.mode.data;
|
||||
if (data->prop_size_prev != t->prop_size) {
|
||||
const struct ToSphereInfo *to_sphere_info = t->custom.mode.data;
|
||||
if (to_sphere_info->prop_size_prev != t->prop_size) {
|
||||
to_sphere_radius_update(t);
|
||||
}
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
float tratio;
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_to_sphere(t, tc, td, ratio, to_sphere_info, is_local_center, is_data_space);
|
||||
}
|
||||
|
||||
const float *center = is_local_center ? td->center : tc->center_local;
|
||||
if (is_data_space) {
|
||||
copy_v3_v3(vec, td->center);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(vec, td->iloc);
|
||||
}
|
||||
|
||||
sub_v3_v3(vec, center);
|
||||
radius = normalize_v3(vec);
|
||||
tratio = ratio * td->factor;
|
||||
mul_v3_fl(vec, radius * (1.0f - tratio) + data->radius * tratio);
|
||||
add_v3_v3(vec, center);
|
||||
|
||||
if (is_data_space) {
|
||||
sub_v3_v3(vec, td->center);
|
||||
mul_m3_v3(td->smtx, vec);
|
||||
add_v3_v3(vec, td->iloc);
|
||||
}
|
||||
|
||||
copy_v3_v3(td->loc, vec);
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_ToSphere data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.ratio = ratio,
|
||||
.to_sphere_info = *to_sphere_info,
|
||||
.is_local_center = is_local_center,
|
||||
.is_data_space = is_data_space,
|
||||
};
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_to_sphere_fn, &settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
@ -39,6 +40,51 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Rotation - Trackball) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_Trackball {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
const float axis[3];
|
||||
const float angle;
|
||||
float mat[3][3];
|
||||
};
|
||||
|
||||
static void transdata_elem_trackball(const TransInfo *t,
|
||||
const TransDataContainer *tc,
|
||||
TransData *td,
|
||||
const float axis[3],
|
||||
const float angle,
|
||||
const float mat[3][3])
|
||||
{
|
||||
float mat_buf[3][3];
|
||||
const float(*mat_final)[3] = mat;
|
||||
if (t->flag & T_PROP_EDIT) {
|
||||
axis_angle_normalized_to_mat3(mat_buf, axis, td->factor * angle);
|
||||
mat_final = mat_buf;
|
||||
}
|
||||
ElementRotation(t, tc, td, mat_final, t->around);
|
||||
}
|
||||
|
||||
static void transdata_elem_trackball_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_Trackball *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_trackball(data->t, data->tc, td, data->axis, data->angle, data->mat);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Rotation - Trackball)
|
||||
* \{ */
|
||||
|
@ -59,17 +105,27 @@ static void applyTrackballValue(TransInfo *t,
|
|||
axis_angle_normalized_to_mat3(mat, axis, angle);
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_trackball(t, tc, td, axis, angle, mat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_Trackball data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.axis = {UNPACK3(axis)},
|
||||
.angle = angle,
|
||||
};
|
||||
copy_m3_m3(data.mat, mat);
|
||||
|
||||
if (t->flag & T_PROP_EDIT) {
|
||||
axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
|
||||
}
|
||||
|
||||
ElementRotation(t, tc, td, mat, t->around);
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_trackball_fn, &settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
|
@ -48,6 +49,121 @@
|
|||
#include "transform_mode.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Translation) Element
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \note Small arrays / data-structures should be stored copied for faster memory access.
|
||||
*/
|
||||
struct TransDataArgs_Translate {
|
||||
const TransInfo *t;
|
||||
const TransDataContainer *tc;
|
||||
const float tc_pivot[3];
|
||||
const float vec[3];
|
||||
bool apply_snap_align_rotation;
|
||||
bool is_valid_snapping_normal;
|
||||
};
|
||||
|
||||
static void transdata_elem_translate(const TransInfo *t,
|
||||
const TransDataContainer *tc,
|
||||
TransData *td,
|
||||
const float pivot[3],
|
||||
const float vec[3],
|
||||
const bool apply_snap_align_rotation,
|
||||
const bool is_valid_snapping_normal)
|
||||
{
|
||||
float rotate_offset[3] = {0};
|
||||
bool use_rotate_offset = false;
|
||||
|
||||
/* Handle snapping rotation before doing the translation. */
|
||||
if (apply_snap_align_rotation) {
|
||||
float mat[3][3];
|
||||
|
||||
if (is_valid_snapping_normal) {
|
||||
const float *original_normal;
|
||||
|
||||
/* In pose mode, we want to align normals with Y axis of bones. */
|
||||
if (t->options & CTX_POSE_BONE) {
|
||||
original_normal = td->axismtx[1];
|
||||
}
|
||||
else {
|
||||
original_normal = td->axismtx[2];
|
||||
}
|
||||
|
||||
rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
|
||||
}
|
||||
else {
|
||||
unit_m3(mat);
|
||||
}
|
||||
|
||||
ElementRotation_ex(t, tc, td, mat, pivot);
|
||||
|
||||
if (td->loc) {
|
||||
use_rotate_offset = true;
|
||||
sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
|
||||
}
|
||||
}
|
||||
|
||||
float tvec[3];
|
||||
|
||||
if (t->con.applyVec) {
|
||||
t->con.applyVec(t, tc, td, vec, tvec);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(tvec, vec);
|
||||
}
|
||||
|
||||
mul_m3_v3(td->smtx, tvec);
|
||||
|
||||
if (use_rotate_offset) {
|
||||
add_v3_v3(tvec, rotate_offset);
|
||||
}
|
||||
|
||||
if (t->options & CTX_GPENCIL_STROKES) {
|
||||
/* Grease pencil multi-frame falloff. */
|
||||
bGPDstroke *gps = (bGPDstroke *)td->extra;
|
||||
if (gps != NULL) {
|
||||
mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff);
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(tvec, td->factor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Proportional editing falloff. */
|
||||
mul_v3_fl(tvec, td->factor);
|
||||
}
|
||||
|
||||
protectedTransBits(td->protectflag, tvec);
|
||||
|
||||
if (td->loc) {
|
||||
add_v3_v3v3(td->loc, td->iloc, tvec);
|
||||
}
|
||||
|
||||
constraintTransLim(t, td);
|
||||
}
|
||||
|
||||
static void transdata_elem_translate_fn(void *__restrict iter_data_v,
|
||||
const int iter,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
struct TransDataArgs_Translate *data = iter_data_v;
|
||||
TransData *td = &data->tc->data[iter];
|
||||
if (td->flag & TD_SKIP) {
|
||||
return;
|
||||
}
|
||||
transdata_elem_translate(data->t,
|
||||
data->tc,
|
||||
td,
|
||||
data->tc_pivot,
|
||||
data->vec,
|
||||
data->apply_snap_align_rotation,
|
||||
data->is_valid_snapping_normal);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Translation)
|
||||
* \{ */
|
||||
|
@ -242,14 +358,13 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
|
|||
static void applyTranslationValue(TransInfo *t, const float vec[3])
|
||||
{
|
||||
const bool apply_snap_align_rotation = usingSnappingNormal(t);
|
||||
float tvec[3];
|
||||
const bool is_valid_snapping_normal = apply_snap_align_rotation && validSnappingNormal(t);
|
||||
|
||||
/* Ideally "apply_snap_align_rotation" would only be used when a snap point is found:
|
||||
* `t->tsnap.status & POINT_INIT` - perhaps this function isn't the best place to apply rotation.
|
||||
* However snapping rotation needs to be handled before doing the translation
|
||||
* (unless the pivot is also translated). */
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
|
||||
float pivot[3];
|
||||
if (apply_snap_align_rotation) {
|
||||
copy_v3_v3(pivot, t->tsnap.snapTarget);
|
||||
|
@ -259,79 +374,28 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
|
|||
}
|
||||
}
|
||||
|
||||
TransData *td = tc->data;
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float rotate_offset[3] = {0};
|
||||
bool use_rotate_offset = false;
|
||||
|
||||
/* Handle snapping rotation before doing the translation. */
|
||||
if (apply_snap_align_rotation) {
|
||||
float mat[3][3];
|
||||
|
||||
if (validSnappingNormal(t)) {
|
||||
const float *original_normal;
|
||||
|
||||
/* In pose mode, we want to align normals with Y axis of bones. */
|
||||
if (t->options & CTX_POSE_BONE) {
|
||||
original_normal = td->axismtx[1];
|
||||
}
|
||||
else {
|
||||
original_normal = td->axismtx[2];
|
||||
}
|
||||
|
||||
rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
|
||||
}
|
||||
else {
|
||||
unit_m3(mat);
|
||||
}
|
||||
|
||||
ElementRotation_ex(t, tc, td, mat, pivot);
|
||||
|
||||
if (td->loc) {
|
||||
use_rotate_offset = true;
|
||||
sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
transdata_elem_translate(
|
||||
t, tc, td, pivot, vec, apply_snap_align_rotation, is_valid_snapping_normal);
|
||||
}
|
||||
|
||||
if (t->con.applyVec) {
|
||||
t->con.applyVec(t, tc, td, vec, tvec);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(tvec, vec);
|
||||
}
|
||||
|
||||
mul_m3_v3(td->smtx, tvec);
|
||||
|
||||
if (use_rotate_offset) {
|
||||
add_v3_v3(tvec, rotate_offset);
|
||||
}
|
||||
|
||||
if (t->options & CTX_GPENCIL_STROKES) {
|
||||
/* Grease pencil multi-frame falloff. */
|
||||
bGPDstroke *gps = (bGPDstroke *)td->extra;
|
||||
if (gps != NULL) {
|
||||
mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff);
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(tvec, td->factor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Proportional editing falloff. */
|
||||
mul_v3_fl(tvec, td->factor);
|
||||
}
|
||||
|
||||
protectedTransBits(td->protectflag, tvec);
|
||||
|
||||
if (td->loc) {
|
||||
add_v3_v3v3(td->loc, td->iloc, tvec);
|
||||
}
|
||||
|
||||
constraintTransLim(t, td);
|
||||
}
|
||||
else {
|
||||
struct TransDataArgs_Translate data = {
|
||||
.t = t,
|
||||
.tc = tc,
|
||||
.tc_pivot = {UNPACK3(pivot)},
|
||||
.vec = {UNPACK3(vec)},
|
||||
.apply_snap_align_rotation = apply_snap_align_rotation,
|
||||
.is_valid_snapping_normal = is_valid_snapping_normal,
|
||||
};
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_translate_fn, &settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue