Geometry Nodes: add simulation support #104924

Closed
Hans Goudey wants to merge 211 commits from geometry-nodes-simulation into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
45 changed files with 489 additions and 610 deletions
Showing only changes of commit 8ed250c35d - Show all commits

View File

@ -449,6 +449,9 @@ void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
#ifdef __cplusplus
/**
* Should only be called once.
* Beware, this modifies ref_vec and other_vec in place!
@ -459,7 +462,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
float vec_other[3],
struct BLI_Stack *edge_vectors);
blender::Span<blender::float3> edge_vectors);
#endif
/**
* Add a new given loop to given lnor_space.
* Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct

View File

@ -281,7 +281,7 @@ void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType
}
}
/* A potential performance optimization is only counting the changed indices. */
this->curve_types_for_write().fill_indices(selection, type);
this->curve_types_for_write().fill_indices(selection.indices(), type);
this->update_curve_types();
this->tag_topology_changed();
}

View File

@ -19,13 +19,10 @@
#include "BLI_array_utils.hh"
#include "BLI_bit_vector.hh"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_math_vector.hh"
#include "BLI_memarena.h"
#include "BLI_span.hh"
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_timeit.hh"
#include "BLI_utildefines.h"
@ -474,7 +471,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
float vec_other[3],
BLI_Stack *edge_vectors)
const blender::Span<blender::float3> edge_vectors)
{
const float pi2 = float(M_PI) * 2.0f;
float tvec[3], dtp;
@ -486,31 +483,24 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
/* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
* tag it as invalid and abort. */
lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
if (edge_vectors) {
BLI_stack_clear(edge_vectors);
}
return;
}
copy_v3_v3(lnor_space->vec_lnor, lnor);
/* Compute ref alpha, average angle of all available edge vectors to lnor. */
if (edge_vectors) {
if (!edge_vectors.is_empty()) {
float alpha = 0.0f;
int count = 0;
while (!BLI_stack_is_empty(edge_vectors)) {
const float *vec = (const float *)BLI_stack_peek(edge_vectors);
for (const blender::float3 &vec : edge_vectors) {
alpha += saacosf(dot_v3v3(vec, lnor));
BLI_stack_discard(edge_vectors);
count++;
}
/* This piece of code shall only be called for more than one loop. */
/* NOTE: In theory, this could be `count > 2`,
* but there is one case where we only have two edges for two loops:
* a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.).
*/
BLI_assert(count >= 2); /* This piece of code shall only be called for more than one loop. */
lnor_space->ref_alpha = alpha / float(count);
BLI_assert(edge_vectors.size() >= 2);
lnor_space->ref_alpha = alpha / float(edge_vectors.size());
}
else {
lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) +
@ -666,23 +656,6 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space,
namespace blender::bke::mesh {
#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024
struct LoopSplitTaskData {
enum class Type : int8_t {
BlockEnd = 0, /* Set implicitly by calloc. */
Fan = 1,
Single = 2,
};
/** We have to create those outside of tasks, since #MemArena is not thread-safe. */
MLoopNorSpace *lnor_space;
int ml_curr_index;
int poly_index;
Type flag;
};
struct LoopSplitTaskDataCommon {
/* Read/write.
* Note we do not need to protect it, though, since two different tasks will *always* affect
@ -855,54 +828,39 @@ static void loop_manifold_fan_around_vert_next(const Span<int> corner_verts,
}
}
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data,
const int ml_curr_index,
MLoopNorSpace *lnor_space)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
const Span<short2> clnors_data = common_data->clnors_data;
const Span<float3> positions = common_data->positions;
const Span<int2> edges = common_data->edges;
const OffsetIndices polys = common_data->polys;
const Span<int> corner_verts = common_data->corner_verts;
const Span<int> corner_edges = common_data->corner_edges;
const Span<int> loop_to_poly = common_data->loop_to_poly;
const Span<float3> poly_normals = common_data->poly_normals;
MutableSpan<float3> loop_normals = common_data->loop_normals;
MLoopNorSpace *lnor_space = data->lnor_space;
const int ml_curr_index = data->ml_curr_index;
const int poly_index = data->poly_index;
loop_normals[ml_curr_index] = poly_normals[loop_to_poly[ml_curr_index]];
/* Simple case (both edges around that vertex are sharp in current polygon),
* this loop just takes its poly normal.
*/
loop_normals[ml_curr_index] = poly_normals[poly_index];
if (MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr) {
const Span<float3> positions = common_data->positions;
const Span<int2> edges = common_data->edges;
const OffsetIndices polys = common_data->polys;
const Span<int> corner_verts = common_data->corner_verts;
const Span<int> corner_edges = common_data->corner_edges;
const Span<short2> clnors_data = common_data->clnors_data;
#if 0
printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n",
ml_curr_index,
loops[ml_curr_index].e,
loops[ml_curr_index].v,
poly_index);
#endif
/* If needed, generate this (simple!) lnor space. */
if (lnors_spacearr) {
float vec_curr[3], vec_prev[3];
const int poly_index = loop_to_poly[ml_curr_index];
const int ml_prev_index = mesh::poly_corner_prev(polys[poly_index], ml_curr_index);
/* The vertex we are "fanning" around. */
const int vert_pivot = corner_verts[ml_curr_index];
const int2 &edge = edges[corner_edges[ml_curr_index]];
const int vert_2 = edge_other_vert(edge, vert_pivot);
const int2 &edge_prev = edges[corner_edges[ml_prev_index]];
const int vert_3 = edge_other_vert(edge_prev, vert_pivot);
const int vert_2 = edge_other_vert(edges[corner_edges[ml_curr_index]], vert_pivot);
const int vert_3 = edge_other_vert(edges[corner_edges[ml_prev_index]], vert_pivot);
sub_v3_v3v3(vec_curr, positions[vert_2], positions[vert_pivot]);
normalize_v3(vec_curr);
sub_v3_v3v3(vec_prev, positions[vert_3], positions[vert_pivot]);
normalize_v3(vec_prev);
BKE_lnor_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, nullptr);
BKE_lnor_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {});
/* We know there is only one loop in this space, no need to create a link-list in this case. */
BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true);
@ -914,8 +872,9 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
}
static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
LoopSplitTaskData *data,
BLI_Stack *edge_vectors)
const int ml_curr_index,
MLoopNorSpace *lnor_space,
Vector<float3> *edge_vectors)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
MutableSpan<float3> loop_normals = common_data->loop_normals;
@ -930,12 +889,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
const Span<int> loop_to_poly = common_data->loop_to_poly;
const Span<float3> poly_normals = common_data->poly_normals;
MLoopNorSpace *lnor_space = data->lnor_space;
#if 0 /* Not needed for 'fan' loops. */
float(*lnor)[3] = data->lnor;
#endif
const int ml_curr_index = data->ml_curr_index;
const int poly_index = data->poly_index;
const int poly_index = loop_to_poly[ml_curr_index];
const int ml_prev_index = poly_corner_prev(polys[poly_index], ml_curr_index);
/* Sigh! we have to fan around current vertex, until we find the other non-smooth edge,
@ -950,7 +904,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
const int2 &edge_orig = edges[corner_edges[ml_curr_index]];
float vec_curr[3], vec_prev[3], vec_org[3];
float lnor[3] = {0.0f, 0.0f, 0.0f};
float3 lnor(0.0f);
/* We validate clnors data on the fly - cheapest way to do! */
int clnors_avg[2] = {0, 0};
@ -958,10 +912,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
int clnors_count = 0;
bool clnors_invalid = false;
/* Temp loop normal stack. */
BLI_SMALLSTACK_DECLARE(normal, float *);
/* Temp clnors stack. */
BLI_SMALLSTACK_DECLARE(clnors, short *);
Vector<int, 8> processed_corners;
/* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
*/
@ -981,7 +932,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
copy_v3_v3(vec_prev, vec_org);
if (lnors_spacearr) {
BLI_stack_push(edge_vectors, vec_org);
edge_vectors->append(vec_org);
}
}
@ -1021,20 +972,17 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
clnors_avg[0] += (*clnor)[0];
clnors_avg[1] += (*clnor)[1];
clnors_count++;
/* We store here a pointer to all custom loop_normals processed. */
BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
}
}
/* We store here a pointer to all loop-normals processed. */
BLI_SMALLSTACK_PUSH(normal, (float *)(loop_normals[mlfan_vert_index]));
processed_corners.append(mlfan_vert_index);
if (lnors_spacearr) {
/* Assign current lnor space to current 'vertex' loop. */
BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, nullptr, false);
if (edge != edge_orig) {
/* We store here all edges-normalized vectors processed. */
BLI_stack_push(edge_vectors, vec_curr);
edge_vectors->append(vec_curr);
}
}
@ -1071,23 +1019,19 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
lnor_len = 1.0f;
}
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors);
edge_vectors->clear();
if (!clnors_data.is_empty()) {
if (clnors_invalid) {
short *clnor;
clnors_avg[0] /= clnors_count;
clnors_avg[1] /= clnors_count;
/* Fix/update all clnors of this fan with computed average value. */
if (G.debug & G_DEBUG) {
printf("Invalid clnors in this fan!\n");
}
while ((clnor = (short *)BLI_SMALLSTACK_POP(clnors))) {
// print_v2("org clnor", clnor);
clnor[0] = short(clnors_avg[0]);
clnor[1] = short(clnors_avg[1]);
}
clnors_data.fill_indices(processed_corners.as_span(),
short2(clnors_avg[0], clnors_avg[1]));
// print_v2("new clnors", clnors_avg);
}
/* Extra bonus: since small-stack is local to this function,
@ -1100,50 +1044,8 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
/* In case we get a zero normal here, just use vertex normal already set! */
if (LIKELY(lnor_len != 0.0f)) {
/* Copy back the final computed normal into all related loop-normals. */
float *nor;
while ((nor = (float *)BLI_SMALLSTACK_POP(normal))) {
copy_v3_v3(nor, lnor);
}
loop_normals.fill_indices(processed_corners.as_span(), lnor);
}
/* Extra bonus: since small-stack is local to this function,
* no more need to empty it at all cost! */
}
}
static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data,
LoopSplitTaskData *data,
BLI_Stack *edge_vectors)
{
if (data->flag == LoopSplitTaskData::Type::Fan) {
BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors));
split_loop_nor_fan_do(common_data, data, edge_vectors);
}
else {
/* No need for edge_vectors for 'single' case! */
split_loop_nor_single_do(common_data, data);
}
}
static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
{
LoopSplitTaskDataCommon *common_data = (LoopSplitTaskDataCommon *)BLI_task_pool_user_data(pool);
LoopSplitTaskData *data = (LoopSplitTaskData *)taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
BLI_Stack *edge_vectors = common_data->lnors_spacearr ?
BLI_stack_new(sizeof(float[3]), __func__) :
nullptr;
for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
if (data->flag == LoopSplitTaskData::Type::BlockEnd) {
break;
}
loop_split_worker_do(common_data, data, edge_vectors);
}
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
}
@ -1218,10 +1120,10 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const Span<int> corner_
}
}
static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
static void loop_split_generator(LoopSplitTaskDataCommon *common_data,
Vector<int> &r_single_corners,
Vector<int> &r_fan_corners)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
const Span<int> corner_verts = common_data->corner_verts;
const Span<int> corner_edges = common_data->corner_edges;
const OffsetIndices polys = common_data->polys;
@ -1230,23 +1132,10 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
BitVector<> skip_loops(corner_verts.size(), false);
LoopSplitTaskData *data_buff = nullptr;
int data_idx = 0;
/* Temp edge vectors stack, only used when computing lnor spacearr
* (and we are not multi-threading). */
BLI_Stack *edge_vectors = nullptr;
#ifdef DEBUG_TIME
SCOPED_TIMER_AVERAGED(__func__);
#endif
if (!pool) {
if (lnors_spacearr) {
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
}
}
/* We now know edges that can be smoothed (with their vector, and their two loops),
* and edges that will be hard! Now, time to generate the normals.
*/
@ -1290,30 +1179,11 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
// printf("SKIPPING!\n");
}
else {
LoopSplitTaskData *data, data_local;
// printf("PROCESSING!\n");
if (pool) {
if (data_idx == 0) {
data_buff = (LoopSplitTaskData *)MEM_calloc_arrayN(
LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
}
data = &data_buff[data_idx];
}
else {
data = &data_local;
memset(data, 0, sizeof(*data));
}
if (IS_EDGE_SHARP(edge_to_loops[corner_edges[ml_curr_index]]) &&
IS_EDGE_SHARP(edge_to_loops[corner_edges[ml_prev_index]])) {
data->ml_curr_index = ml_curr_index;
data->flag = LoopSplitTaskData::Type::Single;
data->poly_index = poly_index;
if (lnors_spacearr) {
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
}
/* Simple case (both edges around that vertex are sharp in current polygon),
* this corner just takes its poly normal. */
r_single_corners.append(ml_curr_index);
}
else {
/* We do not need to check/tag loops as already computed. Due to the fact that a loop
@ -1323,35 +1193,11 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
* current edge, smooth previous edge), and not the alternative (smooth current edge,
* sharp previous edge). All this due/thanks to the link between normals and loop
* ordering (i.e. winding). */
data->ml_curr_index = ml_curr_index;
data->flag = LoopSplitTaskData::Type::Fan;
data->poly_index = poly_index;
if (lnors_spacearr) {
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
}
}
if (pool) {
data_idx++;
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr);
data_idx = 0;
}
}
else {
loop_split_worker_do(common_data, data, edge_vectors);
r_fan_corners.append(ml_curr_index);
}
}
}
}
if (pool && data_idx) {
BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr);
}
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
}
void normals_calc_loop(const Span<float3> vert_positions,
@ -1472,19 +1318,34 @@ void normals_calc_loop(const Span<float3> vert_positions,
edge_to_loops,
{});
if (corner_verts.size() < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead. */
loop_split_generator(nullptr, &common_data);
Vector<int> single_corners;
Vector<int> fan_corners;
loop_split_generator(&common_data, single_corners, fan_corners);
MLoopNorSpace *lnor_spaces = nullptr;
if (r_lnors_spacearr) {
r_lnors_spacearr->spaces_num = single_corners.size() + fan_corners.size();
lnor_spaces = static_cast<MLoopNorSpace *>(BLI_memarena_calloc(
r_lnors_spacearr->mem, sizeof(MLoopNorSpace) * r_lnors_spacearr->spaces_num));
}
else {
TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH);
loop_split_generator(task_pool, &common_data);
threading::parallel_for(single_corners.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
const int corner = single_corners[i];
lnor_space_for_single_fan(&common_data, corner, lnor_spaces ? &lnor_spaces[i] : nullptr);
}
});
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
}
threading::parallel_for(fan_corners.index_range(), 1024, [&](const IndexRange range) {
Vector<float3> edge_vectors;
for (const int i : range) {
const int corner = fan_corners[i];
split_loop_nor_fan_do(&common_data,
corner,
lnor_spaces ? &lnor_spaces[single_corners.size() + i] : nullptr,
&edge_vectors);
}
});
if (r_lnors_spacearr) {
if (r_lnors_spacearr == &_lnors_spacearr) {
@ -1534,7 +1395,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
const bool use_split_normals = true;
const float split_angle = float(M_PI);
BLI_SMALLSTACK_DECLARE(clnors_data, short *);
Vector<short *> clnors_data;
/* Compute current lnor spacearr. */
normals_calc_loop(positions,
@ -1708,7 +1569,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
else {
int avg_nor_count = 0;
float avg_nor[3];
short clnor_data_tmp[2], *clnor_data;
short clnor_data_tmp[2];
zero_v3(avg_nor);
while (loop_link) {
@ -1718,7 +1579,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
avg_nor_count++;
add_v3_v3(avg_nor, nor);
BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
clnors_data.append(r_clnors_data[lidx]);
loop_link = loop_link->next;
done_loops[lidx].reset();
@ -1727,7 +1588,8 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count));
BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
while ((clnor_data = (short *)BLI_SMALLSTACK_POP(clnors_data))) {
while (!clnors_data.is_empty()) {
short *clnor_data = clnors_data.pop_last();
clnor_data[0] = clnor_data_tmp[0];
clnor_data[1] = clnor_data_tmp[1];
}

View File

@ -551,9 +551,10 @@ template<typename T> class MutableSpan {
* Replace a subset of all elements with the given value. This invokes undefined behavior when
* one of the indices is out of bounds.
*/
constexpr void fill_indices(Span<int64_t> indices, const T &value)
template<typename IndexT> constexpr void fill_indices(Span<IndexT> indices, const T &value)
{
for (int64_t i : indices) {
static_assert(std::is_integral_v<IndexT>);
for (IndexT i : indices) {
BLI_assert(i < size_);
data_[i] = value;
}

View File

@ -225,7 +225,7 @@ TEST(span, FillIndices)
{
std::array<int, 5> a = {0, 0, 0, 0, 0};
MutableSpan<int> a_span(a);
a_span.fill_indices({0, 2, 3}, 1);
a_span.fill_indices(Span({0, 2, 3}), 1);
EXPECT_EQ(a[0], 1);
EXPECT_EQ(a[1], 0);
EXPECT_EQ(a[2], 1);

View File

@ -15,9 +15,9 @@
#include "BLI_bitmap.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@ -470,7 +470,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
const int cd_loop_clnors_offset,
const bool has_clnors,
/* Cache. */
BLI_Stack *edge_vectors,
blender::Vector<blender::float3, 16> *edge_vectors,
/* Iterate. */
BMLoop *l_curr,
/* Result. */
@ -534,7 +534,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
normalize_v3(vec_prev);
}
BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, nullptr);
BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, {});
/* We know there is only one loop in this space,
* no need to create a linklist in this case... */
BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true);
@ -586,7 +586,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) :
nullptr;
BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors));
BLI_assert((edge_vectors == nullptr) || edge_vectors->is_empty());
lfan_pivot = l_curr;
lfan_pivot_index = BM_elem_index_get(lfan_pivot);
@ -605,7 +605,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
copy_v3_v3(vec_curr, vec_org);
if (r_lnors_spacearr) {
BLI_stack_push(edge_vectors, vec_org);
edge_vectors->append(vec_org);
}
}
@ -671,7 +671,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false);
if (e_next != e_org) {
/* We store here all edges-normalized vectors processed. */
BLI_stack_push(edge_vectors, vec_next);
edge_vectors->append(vec_next);
}
}
@ -700,7 +700,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
lnor_len = 1.0f;
}
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors);
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, *edge_vectors);
if (has_clnors) {
if (clnors_invalid) {
@ -863,19 +863,20 @@ static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
* operating on vertices this is needed for multi-threading
* so there is a guarantee that each thread has isolated loops.
*/
static void bm_mesh_loops_calc_normals_for_vert_with_clnors(BMesh *bm,
const float (*vcos)[3],
const float (*fnos)[3],
float (*r_lnos)[3],
const short (*clnors_data)[2],
const int cd_loop_clnors_offset,
const bool do_rebuild,
const float split_angle_cos,
/* TLS */
MLoopNorSpaceArray *r_lnors_spacearr,
BLI_Stack *edge_vectors,
/* Iterate over. */
BMVert *v)
static void bm_mesh_loops_calc_normals_for_vert_with_clnors(
BMesh *bm,
const float (*vcos)[3],
const float (*fnos)[3],
float (*r_lnos)[3],
const short (*clnors_data)[2],
const int cd_loop_clnors_offset,
const bool do_rebuild,
const float split_angle_cos,
/* TLS */
MLoopNorSpaceArray *r_lnors_spacearr,
blender::Vector<blender::float3, 16> *edge_vectors,
/* Iterate over. */
BMVert *v)
{
/* Respecting face order is necessary so the initial starting loop is consistent
* with looping over loops of all faces.
@ -992,7 +993,7 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors(
const float split_angle_cos,
/* TLS */
MLoopNorSpaceArray *r_lnors_spacearr,
BLI_Stack *edge_vectors,
blender::Vector<blender::float3, 16> *edge_vectors,
/* Iterate over. */
BMVert *v)
{
@ -1078,7 +1079,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
MLoopNorSpaceArray _lnors_spacearr = {nullptr};
BLI_Stack *edge_vectors = nullptr;
std::unique_ptr<blender::Vector<blender::float3, 16>> edge_vectors = nullptr;
{
char htype = 0;
@ -1095,7 +1096,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
}
if (r_lnors_spacearr) {
BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
edge_vectors = std::make_unique<blender::Vector<blender::float3, 16>>();
}
/* Clear all loops' tags (means none are to be skipped for now). */
@ -1138,7 +1139,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
clnors_data,
cd_loop_clnors_offset,
has_clnors,
edge_vectors,
edge_vectors.get(),
l_curr,
r_lnos,
r_lnors_spacearr);
@ -1146,7 +1147,6 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
}
if (r_lnors_spacearr) {
BLI_stack_free(edge_vectors);
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
}
@ -1169,7 +1169,7 @@ typedef struct BMLoopsCalcNormalsWithCoordsData {
} BMLoopsCalcNormalsWithCoordsData;
typedef struct BMLoopsCalcNormalsWithCoords_TLS {
BLI_Stack *edge_vectors;
blender::Vector<blender::float3, 16> *edge_vectors;
/** Copied from #BMLoopsCalcNormalsWithCoordsData.r_lnors_spacearr when it's not nullptr. */
MLoopNorSpaceArray *lnors_spacearr;
@ -1182,7 +1182,7 @@ static void bm_mesh_loops_calc_normals_for_vert_init_fn(const void *__restrict u
auto *data = static_cast<const BMLoopsCalcNormalsWithCoordsData *>(userdata);
auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk);
if (data->r_lnors_spacearr) {
tls_data->edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
tls_data->edge_vectors = MEM_new<blender::Vector<blender::float3, 16>>(__func__);
BKE_lnor_spacearr_tls_init(data->r_lnors_spacearr, &tls_data->lnors_spacearr_buf);
tls_data->lnors_spacearr = &tls_data->lnors_spacearr_buf;
}
@ -1210,7 +1210,7 @@ static void bm_mesh_loops_calc_normals_for_vert_free_fn(const void *__restrict u
auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk);
if (data->r_lnors_spacearr) {
BLI_stack_free(tls_data->edge_vectors);
MEM_delete(tls_data->edge_vectors);
}
}

View File

@ -129,6 +129,7 @@ set(GLSL_SRC
shaders/compositor_morphological_step.glsl
shaders/compositor_normalize.glsl
shaders/compositor_parallel_reduction.glsl
shaders/compositor_plane_deform.glsl
shaders/compositor_projector_lens_distortion.glsl
shaders/compositor_read_pass.glsl
shaders/compositor_realize_on_domain.glsl
@ -227,6 +228,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_morphological_step_info.hh
shaders/infos/compositor_normalize_info.hh
shaders/infos/compositor_parallel_reduction_info.hh
shaders/infos/compositor_plane_deform_info.hh
shaders/infos/compositor_projector_lens_distortion_info.hh
shaders/infos/compositor_read_pass_info.hh
shaders/infos/compositor_realize_on_domain_info.hh

View File

@ -0,0 +1,24 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
/* Add 0.5 to evaluate the input sampler at the center of the pixel and divide by the image size
* to get the coordinates into the sampler's expected [0, 1] range. */
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(texture_size(input_tx));
vec3 transformed_coordinates = mat3(homography_matrix) * vec3(coordinates, 1.0);
vec2 projected_coordinates = transformed_coordinates.xy / transformed_coordinates.z;
/* The derivatives of the projected coordinates with respect to x and y are the first and
* second columns respectively, divided by the z projection factor as can be shown by
* differentiating the above matrix multiplication with respect to x and y. */
vec2 x_gradient = homography_matrix[0].xy / transformed_coordinates.z;
vec2 y_gradient = homography_matrix[1].xy / transformed_coordinates.z;
vec4 sampled_color = textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
imageStore(output_img, texel, sampled_color);
imageStore(mask_img, texel, sampled_color.aaaa);
}

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_plane_deform)
.local_group_size(16, 16)
.push_constant(Type::MAT4, "homography_matrix")
.sampler(0, ImageType::FLOAT_2D, "input_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
.image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "mask_img")
.compute_source("compositor_plane_deform.glsl")
.do_static_compilation(true);

View File

@ -504,10 +504,10 @@ struct AddOperationExecutor {
{
if (self_->curve_roots_kdtree_ == nullptr) {
self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_orig_->curves_num());
const Span<int> offsets = curves_orig_->offsets();
const Span<float3> positions = curves_orig_->positions();
for (const int curve_i : curves_orig_->curves_range()) {
const int root_point_i = curves_orig_->offsets()[curve_i];
const float3 &root_pos_cu = curves_orig_->positions()[root_point_i];
BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu);
BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, positions[offsets[curve_i]]);
}
BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
}

View File

@ -854,13 +854,13 @@ static void action_space_subtype_item_extend(bContext * /*C*/,
RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
}
static void action_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
static void action_space_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
{
SpaceAction *saction = (SpaceAction *)sl;
memset(&saction->runtime, 0x0, sizeof(saction->runtime));
}
static void action_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void action_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceAction *saction = (SpaceAction *)sl;
bDopeSheet *ads = &saction->ads;
@ -873,7 +873,7 @@ static void action_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
BLO_read_id_address(reader, parent_id->lib, &saction->action);
}
static void action_blend_write(BlendWriter *writer, SpaceLink *sl)
static void action_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceAction, sl);
}
@ -905,9 +905,9 @@ void ED_spacetype_action(void)
st->space_subtype_item_extend = action_space_subtype_item_extend;
st->space_subtype_get = action_space_subtype_get;
st->space_subtype_set = action_space_subtype_set;
st->blend_read_data = action_blend_read_data;
st->blend_read_lib = action_blend_read_lib;
st->blend_write = action_blend_write;
st->blend_read_data = action_space_blend_read_data;
st->blend_read_lib = action_space_blend_read_lib;
st->blend_write = action_space_blend_write;
/* regions: main window */
art = MEM_cnew<ARegionType>("spacetype action region");

View File

@ -907,7 +907,7 @@ static void buttons_id_remap(ScrArea *UNUSED(area),
}
}
static void buttons_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
static void buttons_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
{
SpaceProperties *sbuts = (SpaceProperties *)sl;
@ -918,7 +918,7 @@ static void buttons_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *
sbuts->runtime = NULL;
}
static void buttons_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void buttons_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceProperties *sbuts = (SpaceProperties *)sl;
BLO_read_id_address(reader, parent_id->lib, &sbuts->pinid);
@ -927,7 +927,7 @@ static void buttons_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceL
}
}
static void buttons_blend_write(BlendWriter *writer, SpaceLink *sl)
static void buttons_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceProperties, sl);
}
@ -955,9 +955,9 @@ void ED_spacetype_buttons(void)
st->listener = buttons_area_listener;
st->context = buttons_context;
st->id_remap = buttons_id_remap;
st->blend_read_data = buttons_blend_read_data;
st->blend_read_lib = buttons_blend_read_lib;
st->blend_write = buttons_blend_write;
st->blend_read_data = buttons_space_blend_read_data;
st->blend_read_lib = buttons_space_blend_read_lib;
st->blend_write = buttons_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");

View File

@ -1121,7 +1121,7 @@ static void clip_id_remap(ScrArea * /*area*/, SpaceLink *slink, const struct IDR
BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
static void clip_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
static void clip_space_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
{
SpaceClip *sclip = (SpaceClip *)sl;
@ -1130,14 +1130,14 @@ static void clip_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
sclip->scopes.ok = 0;
}
static void clip_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void clip_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceClip *sclip = (SpaceClip *)sl;
BLO_read_id_address(reader, parent_id->lib, &sclip->clip);
BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask);
}
static void clip_blend_write(BlendWriter *writer, SpaceLink *sl)
static void clip_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceClip, sl);
}
@ -1162,9 +1162,9 @@ void ED_spacetype_clip(void)
st->dropboxes = clip_dropboxes;
st->refresh = clip_refresh;
st->id_remap = clip_id_remap;
st->blend_read_data = clip_blend_read_data;
st->blend_read_lib = clip_blend_read_lib;
st->blend_write = clip_blend_write;
st->blend_read_data = clip_space_blend_read_data;
st->blend_read_lib = clip_space_blend_read_lib;
st->blend_write = clip_space_blend_write;
/* regions: main window */
art = MEM_cnew<ARegionType>("spacetype clip region");

View File

@ -307,7 +307,7 @@ static void console_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
}
}
static void console_blend_write(BlendWriter *writer, SpaceLink *sl)
static void console_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceConsole *con = (SpaceConsole *)sl;
@ -335,7 +335,7 @@ void ED_spacetype_console(void)
st->keymap = console_keymap;
st->dropboxes = console_dropboxes;
st->blend_read_data = console_blend_read_data;
st->blend_write = console_blend_write;
st->blend_write = console_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype console region");

View File

@ -926,7 +926,7 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper
file_reset_filelist_showing_main_data(area, sfile);
}
static void file_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void file_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
SpaceFile *sfile = (SpaceFile *)sl;
@ -951,15 +951,15 @@ static void file_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
}
}
static void file_blend_read_lib(BlendLibReader *UNUSED(reader),
ID *UNUSED(parent_id),
SpaceLink *sl)
static void file_space_blend_read_lib(BlendLibReader *UNUSED(reader),
ID *UNUSED(parent_id),
SpaceLink *sl)
{
SpaceFile *sfile = (SpaceFile *)sl;
sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES;
}
static void file_blend_write(BlendWriter *writer, SpaceLink *sl)
static void file_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceFile *sfile = (SpaceFile *)sl;
@ -995,9 +995,9 @@ void ED_spacetype_file(void)
st->space_subtype_set = file_space_subtype_set;
st->context = file_context;
st->id_remap = file_id_remap;
st->blend_read_data = file_blend_read_data;
st->blend_read_lib = file_blend_read_lib;
st->blend_write = file_blend_write;
st->blend_read_data = file_space_blend_read_data;
st->blend_read_lib = file_space_blend_read_lib;
st->blend_write = file_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");

View File

@ -87,6 +87,59 @@ typedef struct tBeztCopyData {
/** \name Utility Functions
* \{ */
/**
* Helper function that iterates over all FCurves and selected segments and applies the given
* function.
*/
static void apply_fcu_segment_function(bAnimContext *ac,
const float factor,
void (*segment_function)(FCurve *fcu,
FCurveSegment *segment,
const float factor))
{
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
FCurve *fcu = (FCurve *)ale->key_data;
ListBase segments = find_fcurve_segments(fcu);
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
segment_function(fcu, segment, factor);
}
ale->update |= ANIM_UPDATE_DEFAULT;
BLI_freelistN(&segments);
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
static void common_draw_status_header(bContext *C, tGraphSliderOp *gso, const char *operator_name)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
char slider_string[UI_MAX_DRAW_STR];
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_(operator_name));
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
ED_workspace_status_text(C, status_str);
}
/**
* Construct a list with the original bezt arrays so we can restore them during modal operation.
* The data is stored on the struct that is passed.
@ -558,58 +611,16 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
/** \name Blend to Neighbor Operator
* \{ */
static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
static void blend_to_neighbor_graph_keys(bAnimContext *ac, const float factor)
{
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
bAnimListElem *ale;
/* Loop through filtered data and blend keys. */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
ListBase segments = find_fcurve_segments(fcu);
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
blend_to_neighbor_fcurve_segment(fcu, segment, factor);
}
BLI_freelistN(&segments);
ale->update |= ANIM_UPDATE_DEFAULT;
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
char slider_string[UI_MAX_DRAW_STR];
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Blend to Neighbor"));
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
ED_workspace_status_text(C, status_str);
apply_fcu_segment_function(ac, factor, blend_to_neighbor_fcurve_segment);
}
static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
blend_to_neighbor_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Blend to Neighbor");
/* Reset keyframe data to the state at invoke. */
reset_bezts(gso);
@ -631,7 +642,7 @@ static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *
tGraphSliderOp *gso = op->customdata;
gso->modal_update = blend_to_neighbor_modal_update;
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
blend_to_neighbor_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Blend to Neighbor");
return invoke_result;
}
@ -689,54 +700,14 @@ void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
static void breakdown_graph_keys(bAnimContext *ac, float factor)
{
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
bAnimListElem *ale;
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
ListBase segments = find_fcurve_segments(fcu);
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
breakdown_fcurve_segment(fcu, segment, factor);
}
BLI_freelistN(&segments);
ale->update |= ANIM_UPDATE_DEFAULT;
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
char slider_string[UI_MAX_DRAW_STR];
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Breakdown"));
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
ED_workspace_status_text(C, status_str);
apply_fcu_segment_function(ac, factor, breakdown_fcurve_segment);
}
static void breakdown_modal_update(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
breakdown_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Breakdown");
/* Reset keyframe data to the state at invoke. */
reset_bezts(gso);
@ -756,7 +727,7 @@ static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
tGraphSliderOp *gso = op->customdata;
gso->modal_update = breakdown_modal_update;
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
breakdown_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Breakdown");
return invoke_result;
}
@ -836,35 +807,11 @@ static void blend_to_default_graph_keys(bAnimContext *ac, const float factor)
ANIM_animdata_freelist(&anim_data);
}
static void blend_to_default_draw_status_header(bContext *C, tGraphSliderOp *gso)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
char slider_string[UI_MAX_DRAW_STR];
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Blend to Default Value"));
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
ED_workspace_status_text(C, status_str);
}
static void blend_to_default_modal_update(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
blend_to_default_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Blend to Default Value");
/* Set notifier that keyframes have changed. */
reset_bezts(gso);
@ -885,7 +832,7 @@ static int blend_to_default_invoke(bContext *C, wmOperator *op, const wmEvent *e
tGraphSliderOp *gso = op->customdata;
gso->modal_update = blend_to_default_modal_update;
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
blend_to_default_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Blend to Default Value");
return invoke_result;
}
@ -942,54 +889,14 @@ void GRAPH_OT_blend_to_default(wmOperatorType *ot)
static void ease_graph_keys(bAnimContext *ac, const float factor)
{
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
FCurve *fcu = (FCurve *)ale->key_data;
ListBase segments = find_fcurve_segments(fcu);
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
ease_fcurve_segment(fcu, segment, factor);
}
ale->update |= ANIM_UPDATE_DEFAULT;
BLI_freelistN(&segments);
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
static void ease_draw_status_header(bContext *C, tGraphSliderOp *gso)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
char slider_string[UI_MAX_DRAW_STR];
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Ease Keys"));
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
ED_workspace_status_text(C, status_str);
apply_fcu_segment_function(ac, factor, ease_fcurve_segment);
}
static void ease_modal_update(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
ease_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Ease Keys");
/* Reset keyframes to the state at invoke. */
reset_bezts(gso);
@ -1009,7 +916,7 @@ static int ease_invoke(bContext *C, wmOperator *op, const wmEvent *event)
tGraphSliderOp *gso = op->customdata;
gso->modal_update = ease_modal_update;
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
ease_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Ease Keys");
return invoke_result;
}
@ -1133,29 +1040,6 @@ static void gaussian_smooth_free_operator_data(void *operator_data)
MEM_freeN(gauss_data);
}
static void gaussian_smooth_draw_status_header(bContext *C, tGraphSliderOp *gso)
{
char status_str[UI_MAX_DRAW_STR];
char slider_string[UI_MAX_DRAW_STR];
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
const char *mode_str = TIP_("Gaussian Smooth");
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
ED_workspace_status_text(C, status_str);
}
static void gaussian_smooth_modal_update(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
@ -1166,7 +1050,7 @@ static void gaussian_smooth_modal_update(bContext *C, wmOperator *op)
return;
}
gaussian_smooth_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Gaussian Smooth");
const float factor = slider_factor_get_and_remember(op);
tGaussOperatorData *operator_data = (tGaussOperatorData *)gso->operator_data;
@ -1209,7 +1093,7 @@ static int gaussian_smooth_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_slider_allow_overshoot_set(gso->slider, false);
ED_slider_factor_set(gso->slider, 0.0f);
gaussian_smooth_draw_status_header(C, gso);
common_draw_status_header(C, gso, "Gaussian Smooth");
return invoke_result;
}

View File

@ -833,7 +833,7 @@ static void graph_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items);
}
static void graph_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void graph_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
SpaceGraph *sipo = (SpaceGraph *)sl;
@ -841,7 +841,7 @@ static void graph_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
memset(&sipo->runtime, 0x0, sizeof(sipo->runtime));
}
static void graph_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void graph_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceGraph *sipo = (SpaceGraph *)sl;
bDopeSheet *ads = sipo->ads;
@ -852,7 +852,7 @@ static void graph_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLin
}
}
static void graph_blend_write(BlendWriter *writer, SpaceLink *sl)
static void graph_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceGraph *sipo = (SpaceGraph *)sl;
ListBase tmpGhosts = sipo->runtime.ghost_curves;
@ -889,9 +889,9 @@ void ED_spacetype_ipo(void)
st->space_subtype_item_extend = graph_space_subtype_item_extend;
st->space_subtype_get = graph_space_subtype_get;
st->space_subtype_set = graph_space_subtype_set;
st->blend_read_data = graph_blend_read_data;
st->blend_read_lib = graph_blend_read_lib;
st->blend_write = graph_blend_write;
st->blend_read_data = graph_space_blend_read_data;
st->blend_read_lib = graph_space_blend_read_lib;
st->blend_write = graph_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");

View File

@ -1038,7 +1038,7 @@ static void image_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_image_mode_items);
}
static void image_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
static void image_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
{
SpaceImage *sima = (SpaceImage *)sl;
@ -1060,7 +1060,7 @@ static void image_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl
#endif
}
static void image_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void image_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceImage *sima = (SpaceImage *)sl;
@ -1073,7 +1073,7 @@ static void image_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLin
BLO_read_id_address(reader, parent_id->lib, &sima->gpd);
}
static void image_blend_write(BlendWriter *writer, SpaceLink *sl)
static void image_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceImage, sl);
}
@ -1103,9 +1103,9 @@ void ED_spacetype_image(void)
st->space_subtype_item_extend = image_space_subtype_item_extend;
st->space_subtype_get = image_space_subtype_get;
st->space_subtype_set = image_space_subtype_set;
st->blend_read_data = image_blend_read_data;
st->blend_read_lib = image_blend_read_lib;
st->blend_write = image_blend_write;
st->blend_read_data = image_space_blend_read_data;
st->blend_read_lib = image_space_blend_read_lib;
st->blend_write = image_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");

View File

@ -248,7 +248,7 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
static void info_blend_write(BlendWriter *writer, SpaceLink *sl)
static void info_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceInfo, sl);
}
@ -267,7 +267,7 @@ void ED_spacetype_info(void)
st->duplicate = info_duplicate;
st->operatortypes = info_operatortypes;
st->keymap = info_keymap;
st->blend_write = info_blend_write;
st->blend_write = info_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype info region");

View File

@ -565,13 +565,13 @@ static void nla_id_remap(ScrArea *UNUSED(area),
BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT);
}
static void nla_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void nla_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
SpaceNla *snla = (SpaceNla *)sl;
BLO_read_data_address(reader, &snla->ads);
}
static void nla_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void nla_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceNla *snla = (SpaceNla *)sl;
bDopeSheet *ads = snla->ads;
@ -582,7 +582,7 @@ static void nla_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink
}
}
static void nla_blend_write(BlendWriter *writer, SpaceLink *sl)
static void nla_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceNla *snla = (SpaceNla *)sl;
@ -608,9 +608,9 @@ void ED_spacetype_nla(void)
st->listener = nla_listener;
st->keymap = nla_keymap;
st->id_remap = nla_id_remap;
st->blend_read_data = nla_blend_read_data;
st->blend_read_lib = nla_blend_read_lib;
st->blend_write = nla_blend_write;
st->blend_read_data = nla_space_blend_read_data;
st->blend_read_lib = nla_space_blend_read_lib;
st->blend_write = nla_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");

View File

@ -1037,7 +1037,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
}
}
static void node_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void node_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
SpaceNode *snode = (SpaceNode *)sl;
@ -1051,7 +1051,7 @@ static void node_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
snode->runtime = nullptr;
}
static void node_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void node_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceNode *snode = (SpaceNode *)sl;
@ -1102,7 +1102,7 @@ static void node_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink
}
}
static void node_blend_write(BlendWriter *writer, SpaceLink *sl)
static void node_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceNode *snode = (SpaceNode *)sl;
BLO_write_struct(writer, SpaceNode, snode);
@ -1139,9 +1139,9 @@ void ED_spacetype_node()
st->space_subtype_item_extend = node_space_subtype_item_extend;
st->space_subtype_get = node_space_subtype_get;
st->space_subtype_set = node_space_subtype_set;
st->blend_read_data = node_blend_read_data;
st->blend_read_lib = node_blend_read_lib;
st->blend_write = node_blend_write;
st->blend_read_data = node_space_blend_read_data;
st->blend_read_lib = node_space_blend_read_lib;
st->blend_write = node_space_blend_write;
/* regions: main window */
art = MEM_cnew<ARegionType>("spacetype node region");

View File

@ -447,7 +447,7 @@ static void outliner_deactivate(struct ScrArea *area)
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
static void outliner_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void outliner_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
@ -478,7 +478,9 @@ static void outliner_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
space_outliner->runtime = nullptr;
}
static void outliner_blend_read_lib(BlendLibReader *reader, ID * /*parent_id*/, SpaceLink *sl)
static void outliner_space_blend_read_lib(BlendLibReader *reader,
ID * /*parent_id*/,
SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
@ -552,7 +554,7 @@ static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space
}
}
static void outliner_blend_write(BlendWriter *writer, SpaceLink *sl)
static void outliner_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
write_space_outliner(writer, space_outliner);
@ -580,9 +582,9 @@ void ED_spacetype_outliner(void)
st->id_remap = outliner_id_remap;
st->deactivate = outliner_deactivate;
st->context = outliner_context;
st->blend_read_data = outliner_blend_read_data;
st->blend_read_lib = outliner_blend_read_lib;
st->blend_write = outliner_blend_write;
st->blend_read_data = outliner_space_blend_read_data;
st->blend_read_lib = outliner_space_blend_read_lib;
st->blend_write = outliner_space_blend_write;
/* regions: main window */
art = MEM_cnew<ARegionType>("spacetype outliner region");

View File

@ -146,7 +146,7 @@ static void script_main_region_listener(const wmRegionListenerParams *UNUSED(par
#endif
}
static void script_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void script_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceScript *scpt = (SpaceScript *)sl;
/*scpt->script = NULL; - 2.45 set to null, better re-run the script */
@ -158,7 +158,7 @@ static void script_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
}
}
static void script_blend_write(BlendWriter *writer, SpaceLink *sl)
static void script_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
SpaceScript *scr = (SpaceScript *)sl;
scr->but_refs = NULL;
@ -179,8 +179,8 @@ void ED_spacetype_script(void)
st->duplicate = script_duplicate;
st->operatortypes = script_operatortypes;
st->keymap = script_keymap;
st->blend_read_lib = script_blend_read_lib;
st->blend_write = script_blend_write;
st->blend_read_lib = script_space_blend_read_lib;
st->blend_write = script_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype script region");

View File

@ -952,7 +952,7 @@ static void sequencer_channel_region_draw(const bContext *C, ARegion *region)
draw_channels(C, region);
}
static void sequencer_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
static void sequencer_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
{
SpaceSeq *sseq = (SpaceSeq *)sl;
@ -978,7 +978,7 @@ static void sequencer_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink
memset(&sseq->runtime, 0x0, sizeof(sseq->runtime));
}
static void sequencer_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void sequencer_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceSeq *sseq = (SpaceSeq *)sl;
@ -988,7 +988,7 @@ static void sequencer_blend_read_lib(BlendLibReader *reader, ID *parent_id, Spac
BLO_read_id_address(reader, parent_id->lib, &sseq->gpd);
}
static void sequencer_blend_write(BlendWriter *writer, SpaceLink *sl)
static void sequencer_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceSeq, sl);
}
@ -1013,9 +1013,9 @@ void ED_spacetype_sequencer(void)
st->refresh = sequencer_refresh;
st->listener = sequencer_listener;
st->id_remap = sequencer_id_remap;
st->blend_read_data = sequencer_blend_read_data;
st->blend_read_lib = sequencer_blend_read_lib;
st->blend_write = sequencer_blend_write;
st->blend_read_data = sequencer_space_blend_read_data;
st->blend_read_lib = sequencer_space_blend_read_lib;
st->blend_write = sequencer_space_blend_write;
/* Create regions: */
/* Main window. */

View File

@ -124,7 +124,7 @@ static void statusbar_header_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
static void statusbar_blend_write(BlendWriter *writer, SpaceLink *sl)
static void statusbar_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceStatusBar, sl);
}
@ -143,7 +143,7 @@ void ED_spacetype_statusbar(void)
st->duplicate = statusbar_duplicate;
st->operatortypes = statusbar_operatortypes;
st->keymap = statusbar_keymap;
st->blend_write = statusbar_blend_write;
st->blend_write = statusbar_space_blend_write;
/* regions: header window */
art = MEM_callocN(sizeof(*art), "spacetype statusbar header region");

View File

@ -395,19 +395,19 @@ static void text_id_remap(ScrArea *UNUSED(area),
BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
}
static void text_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
static void text_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
{
SpaceText *st = (SpaceText *)sl;
memset(&st->runtime, 0x0, sizeof(st->runtime));
}
static void text_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void text_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceText *st = (SpaceText *)sl;
BLO_read_id_address(reader, parent_id->lib, &st->text);
}
static void text_blend_write(BlendWriter *writer, SpaceLink *sl)
static void text_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceText, sl);
}
@ -432,9 +432,9 @@ void ED_spacetype_text(void)
st->context = text_context;
st->dropboxes = text_dropboxes;
st->id_remap = text_id_remap;
st->blend_read_data = text_blend_read_data;
st->blend_read_lib = text_blend_read_lib;
st->blend_write = text_blend_write;
st->blend_read_data = text_space_blend_read_data;
st->blend_read_lib = text_space_blend_read_lib;
st->blend_write = text_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype text region");

View File

@ -276,7 +276,7 @@ static void undo_history_menu_register(void)
WM_menutype_add(mt);
}
static void topbar_blend_write(BlendWriter *writer, SpaceLink *sl)
static void topbar_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceTopBar, sl);
}
@ -295,7 +295,7 @@ void ED_spacetype_topbar(void)
st->duplicate = topbar_duplicate;
st->operatortypes = topbar_operatortypes;
st->keymap = topbar_keymap;
st->blend_write = topbar_blend_write;
st->blend_write = topbar_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype topbar main region");

View File

@ -177,7 +177,7 @@ static void userpref_navigation_region_listener(const wmRegionListenerParams *UN
static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSED(params)) {}
static void userpref_blend_write(BlendWriter *writer, SpaceLink *sl)
static void userpref_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
BLO_write_struct(writer, SpaceUserPref, sl);
}
@ -196,7 +196,7 @@ void ED_spacetype_userpref(void)
st->duplicate = userpref_duplicate;
st->operatortypes = userpref_operatortypes;
st->keymap = userpref_keymap;
st->blend_write = userpref_blend_write;
st->blend_write = userpref_space_blend_write;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");

View File

@ -2053,7 +2053,7 @@ static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRema
BKE_viewer_path_id_remap(&view3d->viewer_path, mappings);
}
static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void view3d_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
{
View3D *v3d = (View3D *)sl;
@ -2078,7 +2078,7 @@ static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
BKE_viewer_path_blend_read_data(reader, &v3d->viewer_path);
}
static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
static void view3d_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
View3D *v3d = (View3D *)sl;
@ -2092,7 +2092,7 @@ static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
BKE_viewer_path_blend_read_lib(reader, parent_id->lib, &v3d->viewer_path);
}
static void view3d_blend_write(BlendWriter *writer, SpaceLink *sl)
static void view3d_space_blend_write(BlendWriter *writer, SpaceLink *sl)
{
View3D *v3d = (View3D *)sl;
BLO_write_struct(writer, View3D, v3d);
@ -2127,9 +2127,9 @@ void ED_spacetype_view3d()
st->gizmos = view3d_widgets;
st->context = view3d_context;
st->id_remap = view3d_id_remap;
st->blend_read_data = view3d_blend_read_data;
st->blend_read_lib = view3d_blend_read_lib;
st->blend_write = view3d_blend_write;
st->blend_read_data = view3d_space_blend_read_data;
st->blend_read_lib = view3d_space_blend_read_lib;
st->blend_write = view3d_space_blend_write;
/* regions: main window */
art = MEM_cnew<ARegionType>("spacetype view3d main region");

View File

@ -178,7 +178,7 @@ class OptionalOutputsFunction : public MultiFunction {
{
if (params.single_output_is_required(0, "Out 1")) {
MutableSpan<int> values = params.uninitialized_single_output<int>(0, "Out 1");
values.fill_indices(mask, 5);
values.fill_indices(mask.indices(), 5);
}
MutableSpan<std::string> values = params.uninitialized_single_output<std::string>(1, "Out 2");
for (const int i : mask) {

View File

@ -518,8 +518,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
};
auto catmull_rom_to_nurbs = [&](IndexMask selection) {
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
dst_curves.nurbs_orders_for_write().fill_indices(selection.indices(), 4);
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection.indices(),
NURBS_KNOT_MODE_BEZIER);
fill_weights_if_necessary(selection);
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
@ -544,7 +545,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
};
auto poly_to_nurbs = [&](IndexMask selection) {
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
dst_curves.nurbs_orders_for_write().fill_indices(selection.indices(), 4);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
fill_weights_if_necessary(selection);
@ -553,7 +554,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
* start/end. */
if (src_cyclic.is_single()) {
dst_curves.nurbs_knots_modes_for_write().fill_indices(
selection,
selection.indices(),
src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT);
}
else {
@ -576,8 +577,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
const Span<float3> src_handles_l = src_curves.handle_positions_left();
const Span<float3> src_handles_r = src_curves.handle_positions_right();
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
dst_curves.nurbs_orders_for_write().fill_indices(selection.indices(), 4);
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection.indices(),
NURBS_KNOT_MODE_BEZIER);
fill_weights_if_necessary(selection);
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {

View File

@ -1065,7 +1065,7 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
else {
/* Only trimmed curves are no longer cyclic. */
if (bke::SpanAttributeWriter cyclic = dst_attributes.lookup_for_write_span<bool>("cyclic")) {
cyclic.span.fill_indices(selection, false);
cyclic.span.fill_indices(selection.indices(), false);
cyclic.finish();
}

View File

@ -962,16 +962,18 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
/**
* Pack islands using a mix of other strategies.
* \param islands: The islands to be packed. Will be modified with results.
* \param islands: The islands to be packed.
* \param scale: Scale islands by `scale` before packing.
* \param margin: Add `margin` units around islands before packing.
* \param params: Additional parameters. Scale and margin information is ignored.
* \param r_phis: Island layout information will be written here.
* \return Size of square covering the resulting packed UVs. The maximum `u` or `v` co-ordinate.
*/
static float pack_islands_scale_margin(const Span<PackIsland *> islands,
const float scale,
const float margin,
const UVPackIsland_Params &params)
const UVPackIsland_Params &params,
MutableSpan<uv_phi> r_phis)
{
/* #BLI_box_pack_2d produces layouts with high packing efficiency, but has `O(n^3)`
* time complexity, causing poor performance if there are lots of islands. See: #102843.
@ -988,8 +990,6 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
* - Call #pack_islands_alpaca_* on the remaining islands.
*/
blender::Array<uv_phi> phis(islands.size());
/* First, copy information from our input into the AABB structure. */
Array<UVAABBIsland *> aabbs(islands.size());
for (const int64_t i : islands.index_range()) {
@ -1056,7 +1056,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
scale,
margin,
params,
phis.as_mutable_span(),
r_phis,
&max_u,
&max_v);
break;
@ -1066,7 +1066,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
scale,
margin,
params.target_aspect_y,
phis.as_mutable_span(),
r_phis,
&max_u,
&max_v);
break;
@ -1076,25 +1076,11 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
/* Call Alpaca. */
if (params.rotate) {
pack_islands_alpaca_rotate(max_box_pack,
aabbs.as_mutable_span(),
params.target_aspect_y,
phis.as_mutable_span(),
&max_u,
&max_v);
pack_islands_alpaca_rotate(
max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
}
else {
pack_islands_alpaca_turbo(max_box_pack,
aabbs.as_mutable_span(),
params.target_aspect_y,
phis.as_mutable_span(),
&max_u,
&max_v);
}
/* Write back UVs. */
for (int64_t i = 0; i < aabbs.size(); i++) {
islands[i]->place_(scale, phis[i]);
pack_islands_alpaca_turbo(max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
}
return std::max(max_u / params.target_aspect_y, max_v);
@ -1103,7 +1089,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
/** Find the optimal scale to pack islands into the unit square.
* returns largest scale that will pack `islands` into the unit square.
*/
static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vector,
static float pack_islands_margin_fraction(const Span<PackIsland *> &islands,
const float margin_fraction,
const UVPackIsland_Params &params)
{
@ -1118,7 +1104,10 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
float value_low = 0.0f;
float scale_high = 0.0f;
float value_high = 0.0f;
float scale_last = 0.0f;
blender::Array<uv_phi> phis_a(islands.size());
blender::Array<uv_phi> phis_b(islands.size());
blender::Array<uv_phi> *phis_low = nullptr;
/* Scaling smaller than `min_scale_roundoff` is unlikely to fit and
* will destroy information in existing UVs. */
@ -1166,19 +1155,23 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
/* Modified binary-search to improve robustness. */
scale = sqrtf(scale * sqrtf(scale_low * scale_high));
}
BLI_assert(scale_low < scale);
BLI_assert(scale < scale_high);
}
scale = std::max(scale, min_scale_roundoff);
/* Evaluate our `f`. */
scale_last = scale;
blender::Array<uv_phi> *phis_target = (phis_low == &phis_a) ? &phis_b : &phis_a;
const float max_uv = pack_islands_scale_margin(
island_vector, scale_last, margin_fraction, params);
islands, scale, margin_fraction, params, *phis_target);
const float value = sqrtf(max_uv) - 1.0f;
if (value <= 0.0f) {
scale_low = scale;
value_low = value;
phis_low = phis_target;
}
else {
scale_high = scale;
@ -1188,28 +1181,25 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
scale_low = scale;
break;
}
if (!phis_low) {
phis_low = phis_target; /* May as well do "something", even if it's wrong. */
}
}
}
const bool flush = true;
if (flush) {
if (phis_low) {
/* Write back best pack as a side-effect. */
if (scale_last != scale_low) {
scale_last = scale_low;
const float max_uv = pack_islands_scale_margin(
island_vector, scale_last, margin_fraction, params);
BLI_assert(max_uv == value_low);
UNUSED_VARS(max_uv);
/* TODO (?): `if (max_uv < 1.0f) { scale_last /= max_uv; }` */
for (const int64_t i : islands.index_range()) {
islands[i]->place_(scale_low, (*phis_low)[i]);
}
}
return scale_last;
return scale_low;
}
static float calc_margin_from_aabb_length_sum(const Span<PackIsland *> &island_vector,
const UVPackIsland_Params &params)
{
/* Logic matches behavior from #geometry::uv_parametrizer_pack.
/* Logic matches previous behavior from #geometry::uv_parametrizer_pack.
* Attempt to give predictable results not dependent on current UV scale by using
* `aabb_length_sum` (was "`area`") to multiply the margin by the length (was "area"). */
double aabb_length_sum = 0.0f;
@ -1361,21 +1351,22 @@ void pack_islands(const Span<PackIsland *> &islands,
const UVPackIsland_Params &params,
float r_scale[2])
{
BLI_assert(0.0f <= params.margin);
BLI_assert(0.0f <= params.target_aspect_y);
if (islands.size() == 0) {
r_scale[0] = 1.0f;
r_scale[1] = 1.0f;
return; /* Nothing to do, just create a safe default. */
}
if (params.merge_overlap) {
return OverlapMerger::pack_islands_overlap(islands, params, r_scale);
}
finalize_geometry(islands, params);
if (params.margin == 0.0f) {
/* Special case for zero margin. Margin_method is ignored as all formulas give same result. */
const float max_uv = pack_islands_scale_margin(islands, 1.0f, 0.0f, params);
r_scale[0] = 1.0f / max_uv;
r_scale[1] = r_scale[0];
return;
}
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION) {
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION && params.margin > 0.0f) {
/* Uses a line search on scale. ~10x slower than other method. */
const float scale = pack_islands_margin_fraction(islands, params.margin, params);
r_scale[0] = scale;
@ -1390,14 +1381,20 @@ void pack_islands(const Span<PackIsland *> &islands,
case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */
margin = calc_margin_from_aabb_length_sum(islands, params);
break;
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
BLI_assert_unreachable(); /* Handled above. */
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
BLI_assert(params.margin == 0.0f); /* Other (slower) cases are handled above. */
break;
default:
BLI_assert_unreachable();
}
const float max_uv = pack_islands_scale_margin(islands, 1.0f, margin, params);
blender::Array<uv_phi> phis(islands.size());
const float scale = 1.0f;
const float max_uv = pack_islands_scale_margin(islands, scale, margin, params, phis);
for (const int64_t i : islands.index_range()) {
islands[i]->place_(scale, phis[i]);
}
r_scale[0] = 1.0f / max_uv;
r_scale[1] = r_scale[0];
}

View File

@ -158,6 +158,18 @@ if(WITH_IMAGE_WEBP)
add_definitions(-DWITH_WEBP)
endif()
if(WITH_TBB)
add_definitions(-DWITH_TBB)
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
)
list(APPEND LIB
${TBB_LIBRARIES}
)
endif()
list(APPEND INC
../../../intern/opencolorio
)

View File

@ -5,9 +5,19 @@
* \ingroup cmpnodes
*/
#include "BLI_math_geom.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
#include "BLT_translation.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "BKE_tracking.h"
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
#include "node_composite_util.hh"
@ -15,23 +25,29 @@ namespace blender::nodes::node_composite_cornerpin_cc {
static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Color>(N_("Image"))
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
.compositor_domain_priority(0);
b.add_input<decl::Vector>(N_("Upper Left"))
.default_value({0.0f, 1.0f, 0.0f})
.min(0.0f)
.max(1.0f);
.max(1.0f)
.compositor_expects_single_value();
b.add_input<decl::Vector>(N_("Upper Right"))
.default_value({1.0f, 1.0f, 0.0f})
.min(0.0f)
.max(1.0f);
.max(1.0f)
.compositor_expects_single_value();
b.add_input<decl::Vector>(N_("Lower Left"))
.default_value({0.0f, 0.0f, 0.0f})
.min(0.0f)
.max(1.0f);
.max(1.0f)
.compositor_expects_single_value();
b.add_input<decl::Vector>(N_("Lower Right"))
.default_value({1.0f, 0.0f, 0.0f})
.min(0.0f)
.max(1.0f);
.max(1.0f)
.compositor_expects_single_value();
b.add_output<decl::Color>(N_("Image"));
b.add_output<decl::Float>(N_("Plane"));
}
@ -44,9 +60,70 @@ class CornerPinOperation : public NodeOperation {
void execute() override
{
get_input("Image").pass_through(get_result("Image"));
get_result("Plane").allocate_invalid();
context().set_info_message("Viewport compositor setup not fully supported");
const float3x3 homography_matrix = compute_homography_matrix();
Result &input_image = get_input("Image");
Result &output_image = get_result("Image");
Result &output_mask = get_result("Plane");
if (input_image.is_single_value() || homography_matrix == float3x3::identity()) {
if (output_image.should_compute()) {
input_image.pass_through(output_image);
}
if (output_mask.should_compute()) {
output_mask.allocate_single_value();
output_mask.set_float_value(1.0f);
}
return;
}
GPUShader *shader = shader_manager().get("compositor_plane_deform");
GPU_shader_bind(shader);
GPU_shader_uniform_mat3_as_mat4(shader, "homography_matrix", homography_matrix.ptr());
GPU_texture_mipmap_mode(input_image.texture(), true, true);
GPU_texture_anisotropic_filter(input_image.texture(), true);
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
input_image.bind_as_texture(shader, "input_tx");
const Domain domain = compute_domain();
output_image.allocate_texture(domain);
output_image.bind_as_image(shader, "output_img");
output_mask.allocate_texture(domain);
output_mask.bind_as_image(shader, "mask_img");
compute_dispatch_threads_at_least(shader, domain.size);
input_image.unbind_as_texture();
output_image.unbind_as_image();
output_mask.unbind_as_image();
GPU_shader_unbind();
}
float3x3 compute_homography_matrix()
{
float2 lower_left = get_input("Lower Left").get_vector_value_default(float4(0.0f)).xy();
float2 lower_right = get_input("Lower Right").get_vector_value_default(float4(0.0f)).xy();
float2 upper_right = get_input("Upper Right").get_vector_value_default(float4(0.0f)).xy();
float2 upper_left = get_input("Upper Left").get_vector_value_default(float4(0.0f)).xy();
/* The inputs are invalid because the plane is not convex, fallback to an identity operation in
* that case. */
if (!is_quad_convex_v2(lower_left, lower_right, upper_right, upper_left)) {
return float3x3::identity();
}
/* Compute a 2D projection matrix that projects from the corners of the image in normalized
* coordinates into the corners of the input plane. */
float3x3 homography_matrix;
float corners[4][2] = {{lower_left.x, lower_left.y},
{lower_right.x, lower_right.y},
{upper_right.x, upper_right.y},
{upper_left.x, upper_left.y}};
float identity_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
BKE_tracking_homography_between_two_quads(corners, identity_corners, homography_matrix.ptr());
return homography_matrix;
}
};
@ -66,8 +143,6 @@ void register_node_type_cmp_cornerpin()
cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT);
ntype.declare = file_ns::cmp_node_cornerpin_declare;
ntype.get_compositor_operation = file_ns::get_compositor_operation;
ntype.realtime_compositor_unsupported_message = N_(
"Node not supported in the Viewport compositor");
nodeRegisterType(&ntype);
}

View File

@ -282,13 +282,13 @@ class SampleCurveFunction : public mf::MultiFunction {
auto return_default = [&]() {
if (!sampled_positions.is_empty()) {
sampled_positions.fill_indices(mask, {0, 0, 0});
sampled_positions.fill_indices(mask.indices(), {0, 0, 0});
}
if (!sampled_tangents.is_empty()) {
sampled_tangents.fill_indices(mask, {0, 0, 0});
sampled_tangents.fill_indices(mask.indices(), {0, 0, 0});
}
if (!sampled_normals.is_empty()) {
sampled_normals.fill_indices(mask, {0, 0, 0});
sampled_normals.fill_indices(mask.indices(), {0, 0, 0});
}
};
@ -325,18 +325,18 @@ class SampleCurveFunction : public mf::MultiFunction {
auto fill_invalid = [&](const IndexMask mask) {
if (!sampled_positions.is_empty()) {
sampled_positions.fill_indices(mask, float3(0));
sampled_positions.fill_indices(mask.indices(), float3(0));
}
if (!sampled_tangents.is_empty()) {
sampled_tangents.fill_indices(mask, float3(0));
sampled_tangents.fill_indices(mask.indices(), float3(0));
}
if (!sampled_normals.is_empty()) {
sampled_normals.fill_indices(mask, float3(0));
sampled_normals.fill_indices(mask.indices(), float3(0));
}
if (!sampled_values.is_empty()) {
attribute_math::convert_to_static_type(source_data_->type(), [&](auto dummy) {
using T = decltype(dummy);
sampled_values.typed<T>().fill_indices(mask, {});
sampled_values.typed<T>().fill_indices(mask.indices(), {});
});
}
};

View File

@ -63,10 +63,10 @@ static void set_handle_type(bke::CurvesGeometry &curves,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
curves.handle_types_left_for_write().fill_indices(selection, new_handle_type);
curves.handle_types_left_for_write().fill_indices(selection.indices(), new_handle_type);
}
if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
curves.handle_types_right_for_write().fill_indices(selection, new_handle_type);
curves.handle_types_right_for_write().fill_indices(selection.indices(), new_handle_type);
}
/* Eagerly calculate automatically derived handle positions if necessary. */

View File

@ -82,7 +82,7 @@ static void save_selection_as_attribute(Mesh &mesh,
attribute.span.slice(selection.as_range()).fill(true);
}
else {
attribute.span.fill_indices(selection, true);
attribute.span.fill_indices(selection.indices(), true);
}
attribute.finish();

View File

@ -64,7 +64,6 @@ class IndexOfNearestFieldInput final : public bke::GeometryFieldInput {
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
const IndexMask mask) const final
{
SCOPED_TIMER_AVERAGED(__func__);
if (!context.attributes()) {
return {};
}
@ -93,10 +92,11 @@ class IndexOfNearestFieldInput final : public bke::GeometryFieldInput {
group_indexing.add(group_id);
}
/* Each group id has two corresponding index masks. One that contains all the points in the
* group, one that contains all the points in the group that should be looked up (this is the
* intersection of the points in the group and `mask`). In many cases, both of these masks are
* the same or very similar, so there is no benefit two separate masks. */
/* Each group ID has two corresponding index masks. One that contains all the points
* in each group and one that contains all the points in the group that should be looked up
* (the intersection of the points in the group and `mask`). In many cases, both of these
* masks are the same or very similar, so there is not enough benefit for a separate mask
* for the lookups. */
const bool use_separate_lookup_indices = mask.size() < domain_size / 2;
Array<Vector<int64_t>> all_indices_by_group_id(group_indexing.size());

View File

@ -162,7 +162,7 @@ class ProximityFunction : public mf::MultiFunction {
* comparison per vertex, so it's likely not worth it. */
MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance");
distances.fill_indices(mask, FLT_MAX);
distances.fill_indices(mask.indices(), FLT_MAX);
bool success = false;
if (target_.has_mesh()) {
@ -177,10 +177,10 @@ class ProximityFunction : public mf::MultiFunction {
if (!success) {
if (!positions.is_empty()) {
positions.fill_indices(mask, float3(0));
positions.fill_indices(mask.indices(), float3(0));
}
if (!distances.is_empty()) {
distances.fill_indices(mask, 0.0f);
distances.fill_indices(mask.indices(), 0.0f);
}
return;
}

View File

@ -255,7 +255,7 @@ class SampleNearestFunction : public mf::MultiFunction {
const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
MutableSpan<int> indices = params.uninitialized_single_output<int>(1, "Index");
if (!src_component_) {
indices.fill_indices(mask, 0);
indices.fill_indices(mask.indices(), 0);
return;
}

View File

@ -35,7 +35,7 @@ static void set_normal_mode(bke::CurvesGeometry &curves,
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
curves.normal_mode_for_write().fill_indices(selection, mode);
curves.normal_mode_for_write().fill_indices(selection.indices(), mode);
curves.tag_normals_changed();
}

View File

@ -53,7 +53,7 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate
MutableAttributeAccessor attributes = mesh.attributes_for_write();
SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
"material_index", ATTR_DOMAIN_FACE);
material_indices.span.fill_indices(selection, new_material_index);
material_indices.span.fill_indices(selection.indices(), new_material_index);
material_indices.finish();
}

View File

@ -81,7 +81,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
const bke::MeshFieldContext context{mesh_in, ATTR_DOMAIN_FACE};
const bke::MeshFieldContext context{mesh_in, ATTR_DOMAIN_FACE};
FieldEvaluator evaluator{context, mesh_in.totpoly};
evaluator.add(selection_field);
evaluator.evaluate();

View File

@ -41,7 +41,7 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
const OffsetIndices polys = mesh.polys();
const Span<int> corner_verts = mesh.corner_verts();
const bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
const bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
FieldEvaluator face_evaluator{face_context, polys.size()};
face_evaluator.add(selection_field);
face_evaluator.evaluate();
@ -50,7 +50,7 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
return {};
}
const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER};
const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER};
FieldEvaluator evaluator{corner_context, mesh.totloop};
Array<float3> uv(mesh.totloop);
evaluator.add_with_destination(uv_field, uv.as_mutable_span());