Cleanup: Don't do recursion where possible in node.cc #105394

Merged
Hans Goudey merged 25 commits from mod_moder/blender:cleanup_bke_nodes_unwrap_recursion into main 2023-03-06 18:39:30 +01:00
52 changed files with 1075 additions and 1026 deletions
Showing only changes of commit 97cc782cbc - Show all commits

View File

@ -182,7 +182,7 @@ class Device {
{
}
/* Return true if device is ready for rendering, or report status if not. */
/* Report status and return true if device is ready for rendering. */
virtual bool is_ready(string & /*status*/) const
{
return true;

View File

@ -490,6 +490,9 @@ bool MetalDevice::make_source_and_check_if_compile_needed(MetalPipelineType pso_
MD5Hash md5;
md5.append(constant_values);
md5.append(source[pso_type]);
if (use_metalrt) {
md5.append(string_printf("metalrt_features=%d", kernel_features & METALRT_FEATURE_MASK));
}
kernels_md5[pso_type] = md5.get_hex();
return MetalDeviceKernels::should_load_kernels(this, pso_type);
@ -934,6 +937,17 @@ bool MetalDevice::is_ready(string &status) const
DEVICE_KERNEL_NUM);
return false;
}
if (int num_requests = MetalDeviceKernels::num_incomplete_specialization_requests()) {
status = string_printf("%d kernels to optimize", num_requests);
}
else if (kernel_specialization_level == PSO_SPECIALIZED_INTERSECT) {
status = "Using optimized intersection kernels";
}
else if (kernel_specialization_level == PSO_SPECIALIZED_SHADE) {
status = "Using optimized kernels";
}
metal_printf("MetalDevice::is_ready(...) --> true\n");
return true;
}
@ -970,7 +984,7 @@ void MetalDevice::optimize_for_scene(Scene *scene)
}
if (specialize_in_background) {
if (!MetalDeviceKernels::any_specialization_happening_now()) {
if (MetalDeviceKernels::num_incomplete_specialization_requests() == 0) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
specialize_kernels_fn);
}

View File

@ -63,8 +63,7 @@ enum MetalPipelineType {
};
# define METALRT_FEATURE_MASK \
(KERNEL_FEATURE_HAIR | KERNEL_FEATURE_HAIR_THICK | KERNEL_FEATURE_POINTCLOUD | \
KERNEL_FEATURE_OBJECT_MOTION)
(KERNEL_FEATURE_HAIR | KERNEL_FEATURE_HAIR_THICK | KERNEL_FEATURE_POINTCLOUD)
const char *kernel_type_as_string(MetalPipelineType pso_type);
@ -81,7 +80,7 @@ struct MetalKernelPipeline {
KernelData kernel_data_;
bool use_metalrt;
uint32_t metalrt_features = 0;
uint32_t kernel_features = 0;
int threads_per_threadgroup;
@ -104,7 +103,7 @@ struct MetalKernelPipeline {
/* Cache of Metal kernels for each DeviceKernel. */
namespace MetalDeviceKernels {
bool any_specialization_happening_now();
int num_incomplete_specialization_requests();
int get_loaded_kernel_count(MetalDevice const *device, MetalPipelineType pso_type);
bool should_load_kernels(MetalDevice const *device, MetalPipelineType pso_type);
bool load(MetalDevice *device, MetalPipelineType pso_type);

View File

@ -344,9 +344,7 @@ void ShaderCache::load_kernel(DeviceKernel device_kernel,
/* metalrt options */
pipeline->use_metalrt = device->use_metalrt;
pipeline->metalrt_features = device->use_metalrt ?
(device->kernel_features & METALRT_FEATURE_MASK) :
0;
pipeline->kernel_features = device->kernel_features;
{
thread_scoped_lock lock(cache_mutex);
@ -357,65 +355,36 @@ void ShaderCache::load_kernel(DeviceKernel device_kernel,
MetalKernelPipeline *ShaderCache::get_best_pipeline(DeviceKernel kernel, const MetalDevice *device)
{
/* metalrt options */
bool use_metalrt = device->use_metalrt;
bool device_metalrt_hair = use_metalrt && device->kernel_features & KERNEL_FEATURE_HAIR;
bool device_metalrt_hair_thick = use_metalrt &&
device->kernel_features & KERNEL_FEATURE_HAIR_THICK;
bool device_metalrt_pointcloud = use_metalrt &&
device->kernel_features & KERNEL_FEATURE_POINTCLOUD;
bool device_metalrt_motion = use_metalrt &&
device->kernel_features & KERNEL_FEATURE_OBJECT_MOTION;
MetalKernelPipeline *best_pipeline = nullptr;
while (!best_pipeline) {
while (running) {
/* Search all loaded pipelines with matching kernels_md5 checksums. */
MetalKernelPipeline *best_match = nullptr;
{
thread_scoped_lock lock(cache_mutex);
for (auto &pipeline : pipelines[kernel]) {
if (!pipeline->loaded) {
/* still loading - ignore */
continue;
}
bool pipeline_metalrt_hair = pipeline->metalrt_features & KERNEL_FEATURE_HAIR;
bool pipeline_metalrt_hair_thick = pipeline->metalrt_features & KERNEL_FEATURE_HAIR_THICK;
bool pipeline_metalrt_pointcloud = pipeline->metalrt_features & KERNEL_FEATURE_POINTCLOUD;
bool pipeline_metalrt_motion = use_metalrt &&
pipeline->metalrt_features & KERNEL_FEATURE_OBJECT_MOTION;
if (pipeline->use_metalrt != use_metalrt || pipeline_metalrt_hair != device_metalrt_hair ||
pipeline_metalrt_hair_thick != device_metalrt_hair_thick ||
pipeline_metalrt_pointcloud != device_metalrt_pointcloud ||
pipeline_metalrt_motion != device_metalrt_motion) {
/* wrong combination of metalrt options */
continue;
}
if (pipeline->pso_type != PSO_GENERIC) {
if (pipeline->kernels_md5 == device->kernels_md5[PSO_SPECIALIZED_INTERSECT] ||
pipeline->kernels_md5 == device->kernels_md5[PSO_SPECIALIZED_SHADE]) {
best_pipeline = pipeline.get();
for (auto &candidate : pipelines[kernel]) {
if (candidate->loaded &&
candidate->kernels_md5 == device->kernels_md5[candidate->pso_type]) {
/* Replace existing match if candidate is more specialized. */
if (!best_match || candidate->pso_type > best_match->pso_type) {
best_match = candidate.get();
}
}
else if (!best_pipeline) {
best_pipeline = pipeline.get();
}
}
}
if (!best_pipeline) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (best_match) {
if (best_match->usage_count == 0 && best_match->pso_type != PSO_GENERIC) {
metal_printf("Swapping in %s version of %s\n",
kernel_type_as_string(best_match->pso_type),
device_kernel_as_string(kernel));
}
best_match->usage_count += 1;
return best_match;
}
}
if (best_pipeline->usage_count == 0 && best_pipeline->pso_type != PSO_GENERIC) {
metal_printf("Swapping in %s version of %s\n",
kernel_type_as_string(best_pipeline->pso_type),
device_kernel_as_string(kernel));
/* Spin until a matching kernel is loaded, or we're shutting down. */
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
best_pipeline->usage_count += 1;
return best_pipeline;
return nullptr;
}
bool MetalKernelPipeline::should_use_binary_archive() const
@ -570,18 +539,14 @@ void MetalKernelPipeline::compile()
NSArray *table_functions[METALRT_TABLE_NUM] = {nil};
NSArray *linked_functions = nil;
bool metalrt_hair = use_metalrt && (metalrt_features & KERNEL_FEATURE_HAIR);
bool metalrt_hair_thick = use_metalrt && (metalrt_features & KERNEL_FEATURE_HAIR_THICK);
bool metalrt_pointcloud = use_metalrt && (metalrt_features & KERNEL_FEATURE_POINTCLOUD);
if (use_metalrt) {
id<MTLFunction> curve_intersect_default = nil;
id<MTLFunction> curve_intersect_shadow = nil;
id<MTLFunction> point_intersect_default = nil;
id<MTLFunction> point_intersect_shadow = nil;
if (metalrt_hair) {
if (kernel_features & KERNEL_FEATURE_HAIR) {
/* Add curve intersection programs. */
if (metalrt_hair_thick) {
if (kernel_features & KERNEL_FEATURE_HAIR_THICK) {
/* Slower programs for thick hair since that also slows down ribbons.
* Ideally this should not be needed. */
curve_intersect_default = rt_intersection_function[METALRT_FUNC_CURVE_ALL];
@ -592,7 +557,7 @@ void MetalKernelPipeline::compile()
curve_intersect_shadow = rt_intersection_function[METALRT_FUNC_CURVE_RIBBON_SHADOW];
}
}
if (metalrt_pointcloud) {
if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
point_intersect_default = rt_intersection_function[METALRT_FUNC_POINT];
point_intersect_shadow = rt_intersection_function[METALRT_FUNC_POINT_SHADOW];
}
@ -682,15 +647,6 @@ void MetalKernelPipeline::compile()
local_md5.append((uint8_t *)&this->threads_per_threadgroup,
sizeof(this->threads_per_threadgroup));
string options;
if (use_metalrt && kernel_has_intersection(device_kernel)) {
/* incorporate any MetalRT specializations into the archive name */
options += string_printf(".hair_%d.hair_thick_%d.pointcloud_%d",
metalrt_hair ? 1 : 0,
metalrt_hair_thick ? 1 : 0,
metalrt_pointcloud ? 1 : 0);
}
/* Replace non-alphanumerical characters with underscores. */
string device_name = [mtlDevice.name UTF8String];
for (char &c : device_name) {
@ -702,7 +658,7 @@ void MetalKernelPipeline::compile()
metalbin_name = device_name;
metalbin_name = path_join(metalbin_name, device_kernel_as_string(device_kernel));
metalbin_name = path_join(metalbin_name, kernel_type_as_string(pso_type));
metalbin_name = path_join(metalbin_name, local_md5.get_hex() + options + ".bin");
metalbin_name = path_join(metalbin_name, local_md5.get_hex() + ".bin");
metalbin_path = path_cache_get(path_join("kernels", metalbin_name));
path_create_directories(metalbin_path);
@ -860,16 +816,15 @@ void MetalDeviceKernels::wait_for_all()
}
}
bool MetalDeviceKernels::any_specialization_happening_now()
int MetalDeviceKernels::num_incomplete_specialization_requests()
{
/* Return true if any ShaderCaches have ongoing specialization requests (typically there will be
* only 1). */
int total = 0;
for (int i = 0; i < g_shaderCacheCount; i++) {
if (g_shaderCache[i].second->incomplete_specialization_requests > 0) {
return true;
}
total += g_shaderCache[i].second->incomplete_specialization_requests;
}
return false;
return total;
}
int MetalDeviceKernels::get_loaded_kernel_count(MetalDevice const *device,

View File

@ -706,6 +706,12 @@ void Session::update_status_time(bool show_pause, bool show_done)
string_printf("Sample %d/%d", current_sample, num_samples));
}
/* Append any device-specific status (such as background kernel optimization) */
string device_status;
if (device->is_ready(device_status) && !device_status.empty()) {
substatus += string_printf(" (%s)", device_status.c_str());
}
/* TODO(sergey): Denoising status from the path trace. */
if (show_pause) {

View File

@ -6,6 +6,7 @@
#include <mutex>
#include "BLI_cache_mutex.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_resource_scope.hh"
#include "BLI_utility_mixins.hh"
@ -150,6 +151,13 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
Vector<bNode *> root_frames;
Vector<bNodeSocket *> interface_inputs;
Vector<bNodeSocket *> interface_outputs;
/**
* The location of all sockets in the tree, calculated while drawing the nodes.
* Indexed with #bNodeSocket::index_in_tree(). In the node tree's "world space"
* (the same as #bNode::runtime::totr).
*/
Vector<float2> all_socket_locations;
};
/**

View File

@ -580,7 +580,7 @@ static void bvhtree_from_mesh_setup_data(BVHTree *tree,
const MEdge *edge,
const MFace *face,
const MLoop *loop,
const MLoopTri *looptri,
const Span<MLoopTri> looptris,
BVHTreeFromMesh *r_data)
{
memset(r_data, 0, sizeof(*r_data));
@ -591,7 +591,7 @@ static void bvhtree_from_mesh_setup_data(BVHTree *tree,
r_data->edge = edge;
r_data->face = face;
r_data->loop = loop;
r_data->looptri = looptri;
r_data->looptri = looptris.data();
switch (bvh_cache_type) {
case BVHTREE_FROM_VERTS:
@ -779,7 +779,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
if (data) {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_setup_data(
tree, BVHTREE_FROM_VERTS, vert_positions, nullptr, nullptr, nullptr, nullptr, data);
tree, BVHTREE_FROM_VERTS, vert_positions, nullptr, nullptr, nullptr, {}, data);
}
return tree;
@ -914,7 +914,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
if (data) {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_setup_data(
tree, BVHTREE_FROM_EDGES, vert_positions, edge, nullptr, nullptr, nullptr, data);
tree, BVHTREE_FROM_EDGES, vert_positions, edge, nullptr, nullptr, {}, data);
}
return tree;
@ -1037,16 +1037,15 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
int axis,
const float (*positions)[3],
const MLoop *mloop,
const MLoopTri *looptri,
const int looptri_num,
const Span<MLoopTri> looptris,
const BitSpan looptri_mask,
int looptri_num_active)
{
if (!looptri_mask.is_empty()) {
BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptris.size()));
}
else {
looptri_num_active = looptri_num;
looptri_num_active = looptris.size();
}
if (looptri_num_active == 0) {
return nullptr;
@ -1059,16 +1058,16 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
return nullptr;
}
if (positions && looptri) {
for (int i = 0; i < looptri_num; i++) {
if (positions && !looptris.is_empty()) {
for (const int i : looptris.index_range()) {
float co[3][3];
if (!looptri_mask.is_empty() && !looptri_mask[i]) {
continue;
}
copy_v3_v3(co[0], positions[mloop[looptri[i].tri[0]].v]);
copy_v3_v3(co[1], positions[mloop[looptri[i].tri[1]].v]);
copy_v3_v3(co[2], positions[mloop[looptri[i].tri[2]].v]);
copy_v3_v3(co[0], positions[mloop[looptris[i].tri[0]].v]);
copy_v3_v3(co[1], positions[mloop[looptris[i].tri[1]].v]);
copy_v3_v3(co[2], positions[mloop[looptris[i].tri[2]].v]);
BLI_bvhtree_insert(tree, i, co[0], 3);
}
@ -1121,8 +1120,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
axis,
vert_positions,
mloop,
looptri,
looptri_num,
{looptri, looptri_num},
looptri_mask,
looptri_num_active);
@ -1130,8 +1128,14 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
if (data) {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_setup_data(
tree, BVHTREE_FROM_LOOPTRI, vert_positions, nullptr, nullptr, mloop, looptri, data);
bvhtree_from_mesh_setup_data(tree,
BVHTREE_FROM_LOOPTRI,
vert_positions,
nullptr,
nullptr,
mloop,
{looptri, looptri_num},
data);
}
return tree;
@ -1208,11 +1212,9 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
{
BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime->bvh_cache;
const MLoopTri *looptri = nullptr;
int looptri_len = 0;
Span<MLoopTri> looptris;
if (ELEM(bvh_cache_type, BVHTREE_FROM_LOOPTRI, BVHTREE_FROM_LOOPTRI_NO_HIDDEN)) {
looptri = BKE_mesh_runtime_looptri_ensure(mesh);
looptri_len = BKE_mesh_runtime_looptri_len(mesh);
looptris = mesh->looptris();
}
const float(*positions)[3] = reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data());
const Span<MEdge> edges = mesh->edges();
@ -1225,7 +1227,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
edges.data(),
(const MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE),
loops.data(),
looptri,
looptris,
data);
bool lock_started = false;
@ -1278,20 +1280,13 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
mask = looptri_no_hidden_map_get(
mesh->polys(),
attributes.lookup_or_default(".hide_poly", ATTR_DOMAIN_FACE, false),
looptri_len,
looptris.size(),
&mask_bits_act_len);
ATTR_FALLTHROUGH;
}
case BVHTREE_FROM_LOOPTRI:
data->tree = bvhtree_from_mesh_looptri_create_tree(0.0f,
tree_type,
6,
positions,
loops.data(),
looptri,
looptri_len,
mask,
mask_bits_act_len);
data->tree = bvhtree_from_mesh_looptri_create_tree(
0.0f, tree_type, 6, positions, loops.data(), looptris, mask, mask_bits_act_len);
break;
case BVHTREE_FROM_EM_VERTS:
case BVHTREE_FROM_EM_EDGES:

View File

@ -836,9 +836,8 @@ static bool cloth_from_object(
static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mesh)
{
const blender::Span<MLoop> loops = mesh->loops();
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
const blender::Span<MLoopTri> looptris = mesh->looptris();
const uint mvert_num = mesh->totvert;
const uint looptri_num = BKE_mesh_runtime_looptri_len(mesh);
/* Allocate our vertices. */
clmd->clothObject->mvert_num = mvert_num;
@ -853,14 +852,14 @@ static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mes
/* save face information */
if (clmd->hairdata == nullptr) {
clmd->clothObject->primitive_num = looptri_num;
clmd->clothObject->primitive_num = looptris.size();
}
else {
clmd->clothObject->primitive_num = mesh->totedge;
}
clmd->clothObject->tri = static_cast<MVertTri *>(
MEM_malloc_arrayN(looptri_num, sizeof(MVertTri), __func__));
MEM_malloc_arrayN(looptris.size(), sizeof(MVertTri), __func__));
if (clmd->clothObject->tri == nullptr) {
cloth_free_modifier(clmd);
BKE_modifier_set_error(
@ -869,7 +868,7 @@ static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mes
return;
}
BKE_mesh_runtime_verttri_from_looptri(
clmd->clothObject->tri, loops.data(), looptri, looptri_num);
clmd->clothObject->tri, loops.data(), looptris.data(), looptris.size());
clmd->clothObject->edges = mesh->edges().data();

View File

@ -1481,7 +1481,7 @@ struct DynamicPaintSetInitColorData {
blender::Span<MLoop> loops;
const float (*mloopuv)[2];
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
const MLoopCol *mloopcol;
ImagePool *pool;
@ -1498,7 +1498,7 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdat
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
const blender::Span<MLoop> loops = data->loops;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const float(*mloopuv)[2] = data->mloopuv;
ImagePool *pool = data->pool;
Tex *tex = data->surface->init_texture;
@ -1509,11 +1509,11 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdat
for (int j = 3; j--;) {
TexResult texres = {0};
const uint vert = loops[mlooptri[i].tri[j]].v;
const uint vert = loops[looptris[i].tri[j]].v;
/* remap to [-1.0, 1.0] */
uv[0] = mloopuv[mlooptri[i].tri[j]][0] * 2.0f - 1.0f;
uv[1] = mloopuv[mlooptri[i].tri[j]][1] * 2.0f - 1.0f;
uv[0] = mloopuv[looptris[i].tri[j]][0] * 2.0f - 1.0f;
uv[1] = mloopuv[looptris[i].tri[j]][1] * 2.0f - 1.0f;
multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
@ -1533,7 +1533,7 @@ static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *__restrict userda
const PaintSurfaceData *sData = data->surface->data;
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const float(*mloopuv)[2] = data->mloopuv;
Tex *tex = data->surface->init_texture;
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
@ -1548,7 +1548,7 @@ static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *__restrict userda
/* collect all uvs */
for (int j = 3; j--;) {
copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]]);
copy_v2_v2(&uv[j * 3], mloopuv[looptris[f_data->uv_p[i].tri_index].tri[j]]);
}
/* interpolate final uv pos */
@ -1572,7 +1572,7 @@ static void dynamic_paint_set_init_color_vcol_to_imseq_cb(
const PaintSurfaceData *sData = data->surface->data;
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const MLoopCol *mloopcol = data->mloopcol;
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
@ -1583,7 +1583,7 @@ static void dynamic_paint_set_init_color_vcol_to_imseq_cb(
/* collect color values */
for (int j = 3; j--;) {
rgba_uchar_to_float(colors[j], (const uchar *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
rgba_uchar_to_float(colors[j], (const uchar *)&mloopcol[looptris[tri_idx].tri[j]].r);
}
/* interpolate final color */
@ -1619,8 +1619,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
Tex *tex = surface->init_texture;
const blender::Span<MLoop> loops = mesh->loops();
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
const int tottri = BKE_mesh_runtime_looptri_len(mesh);
const blender::Span<MLoopTri> looptris = mesh->looptris();
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@ -1645,22 +1644,22 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
DynamicPaintSetInitColorData data{};
data.surface = surface;
data.loops = loops;
data.mlooptri = mlooptri;
data.looptris = looptris;
data.mloopuv = mloopuv;
data.pool = pool;
data.scene_color_manage = scene_color_manage;
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (tottri > 1000);
settings.use_threading = (looptris.size() > 1000);
BLI_task_parallel_range(
0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
0, looptris.size(), &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
BKE_image_pool_free(pool);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
DynamicPaintSetInitColorData data{};
data.surface = surface;
data.mlooptri = mlooptri;
data.looptris = looptris;
data.mloopuv = mloopuv;
data.scene_color_manage = scene_color_manage;
@ -1688,7 +1687,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
const blender::Span<MLoopTri> looptris = mesh->looptris();
const MLoopCol *col = static_cast<const MLoopCol *>(
CustomData_get_layer_named(&mesh->ldata, CD_PROP_BYTE_COLOR, surface->init_layername));
if (!col) {
@ -1697,7 +1696,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
DynamicPaintSetInitColorData data{};
data.surface = surface;
data.mlooptri = mlooptri;
data.looptris = looptris;
data.mloopcol = col;
TaskParallelSettings settings;
@ -2192,10 +2191,9 @@ struct DynamicPaintCreateUVSurfaceData {
PaintUVPoint *tempPoints;
Vec3f *tempWeights;
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
const float (*mloopuv)[2];
blender::Span<MLoop> loops;
int tottri;
const Bounds2D *faceBB;
uint32_t *active_points;
@ -2212,10 +2210,9 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
PaintUVPoint *tempPoints = data->tempPoints;
Vec3f *tempWeights = data->tempWeights;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const float(*mloopuv)[2] = data->mloopuv;
const blender::Span<MLoop> loops = data->loops;
const int tottri = data->tottri;
const Bounds2D *faceBB = data->faceBB;
@ -2259,16 +2256,16 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
/* Loop through every face in the mesh */
/* XXX TODO: This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here!
*/
for (int i = 0; i < tottri; i++) {
for (const int i : looptris.index_range()) {
/* Check uv bb */
if ((faceBB[i].min[0] > point[sample][0]) || (faceBB[i].min[1] > point[sample][1]) ||
(faceBB[i].max[0] < point[sample][0]) || (faceBB[i].max[1] < point[sample][1])) {
continue;
}
const float *uv1 = mloopuv[mlooptri[i].tri[0]];
const float *uv2 = mloopuv[mlooptri[i].tri[1]];
const float *uv3 = mloopuv[mlooptri[i].tri[2]];
const float *uv1 = mloopuv[looptris[i].tri[0]];
const float *uv2 = mloopuv[looptris[i].tri[1]];
const float *uv3 = mloopuv[looptris[i].tri[2]];
/* If point is inside the face */
if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
@ -2286,9 +2283,9 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
tPoint->tri_index = i;
/* save vertex indexes */
tPoint->v1 = loops[mlooptri[i].tri[0]].v;
tPoint->v2 = loops[mlooptri[i].tri[1]].v;
tPoint->v3 = loops[mlooptri[i].tri[2]].v;
tPoint->v1 = loops[looptris[i].tri[0]].v;
tPoint->v2 = loops[looptris[i].tri[1]].v;
tPoint->v3 = loops[looptris[i].tri[2]].v;
sample = 5; /* make sure we exit sample loop as well */
break;
@ -2309,7 +2306,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
PaintUVPoint *tempPoints = data->tempPoints;
Vec3f *tempWeights = data->tempWeights;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const float(*mloopuv)[2] = data->mloopuv;
const blender::Span<MLoop> loops = data->loops;
@ -2351,9 +2348,9 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
if (tempPoints[ind].neighbor_pixel == -1 && tempPoints[ind].tri_index != -1) {
float uv[2];
const int i = tempPoints[ind].tri_index;
const float *uv1 = mloopuv[mlooptri[i].tri[0]];
const float *uv2 = mloopuv[mlooptri[i].tri[1]];
const float *uv3 = mloopuv[mlooptri[i].tri[2]];
const float *uv1 = mloopuv[looptris[i].tri[0]];
const float *uv2 = mloopuv[looptris[i].tri[1]];
const float *uv3 = mloopuv[looptris[i].tri[2]];
/* tri index */
/* There is a low possibility of actually having a neighbor point which tri is
@ -2376,9 +2373,9 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
}
/* save vertex indexes */
tPoint->v1 = loops[mlooptri[i].tri[0]].v;
tPoint->v2 = loops[mlooptri[i].tri[1]].v;
tPoint->v3 = loops[mlooptri[i].tri[2]].v;
tPoint->v1 = loops[looptris[i].tri[0]].v;
tPoint->v2 = loops[looptris[i].tri[1]].v;
tPoint->v3 = loops[looptris[i].tri[2]].v;
break;
}
@ -2396,7 +2393,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
#undef JITTER_SAMPLES
static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
static float dist_squared_to_looptri_uv_edges(const blender::Span<MLoopTri> looptris,
const float (*mloopuv)[2],
int tri_index,
const float point[2])
@ -2408,8 +2405,8 @@ static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
for (int i = 0; i < 3; i++) {
const float dist_squared = dist_squared_to_line_segment_v2(
point,
mloopuv[mlooptri[tri_index].tri[(i + 0)]],
mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]]);
mloopuv[looptris[tri_index].tri[(i + 0)]],
mloopuv[looptris[tri_index].tri[(i + 1) % 3]]);
if (dist_squared < min_distance) {
min_distance = dist_squared;
@ -2520,10 +2517,10 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
int depth)
{
const blender::Span<MLoop> loops = data->loops;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const float(*mloopuv)[2] = data->mloopuv;
const uint *loop_idx = mlooptri[tri_index].tri;
const uint *loop_idx = looptris[tri_index].tri;
/* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
@ -2577,7 +2574,7 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
continue;
}
const uint *other_loop_idx = mlooptri[lt_index].tri;
const uint *other_loop_idx = looptris[lt_index].tri;
/* Check edges for match, looping in the same order as the outer loop. */
for (int j = 0; j < 3; j++) {
@ -2680,7 +2677,7 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
const float threshold = square_f(0.7f) / (w * h);
if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, final_tri_index, final_pt) >
if (dist_squared_to_looptri_uv_edges(looptris, mloopuv, final_tri_index, final_pt) >
threshold) {
continue;
}
@ -2818,7 +2815,6 @@ int dynamicPaint_createUVSurface(Scene *scene,
PaintUVPoint *tempPoints = nullptr;
Vec3f *tempWeights = nullptr;
const MLoopTri *mlooptri = nullptr;
const float(*mloopuv)[2] = nullptr;
Bounds2D *faceBB = nullptr;
@ -2835,8 +2831,7 @@ int dynamicPaint_createUVSurface(Scene *scene,
}
const blender::Span<MLoop> loops = mesh->loops();
mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
const int tottri = BKE_mesh_runtime_looptri_len(mesh);
const blender::Span<MLoopTri> looptris = mesh->looptris();
/* get uv map */
if (CustomData_has_layer(&mesh->ldata, CD_PROP_FLOAT2)) {
@ -2859,7 +2854,8 @@ int dynamicPaint_createUVSurface(Scene *scene,
/*
* Start generating the surface
*/
CLOG_INFO(&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, tottri);
CLOG_INFO(
&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, int(looptris.size()));
/* Init data struct */
if (surface->data) {
@ -2893,7 +2889,8 @@ int dynamicPaint_createUVSurface(Scene *scene,
* the pixel-inside-a-face search.
*/
if (!error) {
faceBB = static_cast<Bounds2D *>(MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB"));
faceBB = static_cast<Bounds2D *>(
MEM_malloc_arrayN(looptris.size(), sizeof(*faceBB), "MPCanvasFaceBB"));
if (!faceBB) {
error = true;
}
@ -2903,12 +2900,12 @@ int dynamicPaint_createUVSurface(Scene *scene,
*do_update = true;
if (!error) {
for (int i = 0; i < tottri; i++) {
copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]]);
copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]]);
for (const int i : looptris.index_range()) {
copy_v2_v2(faceBB[i].min, mloopuv[looptris[i].tri[0]]);
copy_v2_v2(faceBB[i].max, mloopuv[looptris[i].tri[0]]);
for (int j = 1; j < 3; j++) {
minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]]);
minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[looptris[i].tri[j]]);
}
}
@ -2920,16 +2917,15 @@ int dynamicPaint_createUVSurface(Scene *scene,
data.surface = surface;
data.tempPoints = tempPoints;
data.tempWeights = tempWeights;
data.mlooptri = mlooptri;
data.looptris = looptris;
data.mloopuv = mloopuv;
data.loops = loops;
data.tottri = tottri;
data.faceBB = faceBB;
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (h > 64 || tottri > 1000);
settings.use_threading = (h > 64 || looptris.size() > 1000);
BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, &settings);
}
@ -2979,8 +2975,8 @@ int dynamicPaint_createUVSurface(Scene *scene,
BKE_mesh_vert_looptri_map_create(&vert_to_looptri_map,
&vert_to_looptri_map_mem,
mesh->totvert,
mlooptri,
tottri,
looptris.data(),
looptris.size(),
loops.data(),
mesh->totloop);
@ -3439,15 +3435,15 @@ static void mesh_tris_spherecast_dp(void *userdata,
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const float(*positions)[3] = data->vert_positions;
const MLoopTri *mlooptri = data->looptri;
const MLoopTri *looptris = data->looptri;
const MLoop *loops = data->loop;
const float *t0, *t1, *t2;
float dist;
t0 = positions[loops[mlooptri[index].tri[0]].v];
t1 = positions[loops[mlooptri[index].tri[1]].v];
t2 = positions[loops[mlooptri[index].tri[2]].v];
t0 = positions[loops[looptris[index].tri[0]].v];
t1 = positions[loops[looptris[index].tri[1]].v];
t2 = positions[loops[looptris[index].tri[2]].v];
dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
@ -3471,14 +3467,14 @@ static void mesh_tris_nearest_point_dp(void *userdata,
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const float(*positions)[3] = data->vert_positions;
const MLoopTri *mlooptri = data->looptri;
const MLoopTri *looptris = data->looptri;
const MLoop *loops = data->loop;
float nearest_tmp[3], dist_sq;
const float *t0, *t1, *t2;
t0 = positions[loops[mlooptri[index].tri[0]].v];
t1 = positions[loops[mlooptri[index].tri[1]].v];
t2 = positions[loops[mlooptri[index].tri[2]].v];
t0 = positions[loops[looptris[index].tri[0]].v];
t1 = positions[loops[looptris[index].tri[1]].v];
t2 = positions[loops[looptris[index].tri[2]].v];
closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
dist_sq = len_squared_v3v3(co, nearest_tmp);
@ -3912,7 +3908,7 @@ struct DynamicPaintPaintData {
Mesh *mesh;
const float (*positions)[3];
blender::Span<MLoop> loops;
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
float brush_radius;
const float *avg_brushNor;
const Vec3f *brushVelocity;
@ -3946,7 +3942,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata,
const float(*positions)[3] = data->positions;
const blender::Span<MLoop> loops = data->loops;
const MLoopTri *mlooptri = data->mlooptri;
const blender::Span<MLoopTri> looptris = data->looptris;
const float brush_radius = data->brush_radius;
const float *avg_brushNor = data->avg_brushNor;
const Vec3f *brushVelocity = data->brushVelocity;
@ -4019,9 +4015,9 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata,
/* For optimization sake, hit point normal isn't calculated in ray cast loop */
const int vtri[3] = {
int(loops[mlooptri[hit.index].tri[0]].v),
int(loops[mlooptri[hit.index].tri[1]].v),
int(loops[mlooptri[hit.index].tri[2]].v),
int(loops[looptris[hit.index].tri[0]].v),
int(loops[looptris[hit.index].tri[1]].v),
int(loops[looptris[hit.index].tri[2]].v),
};
float dot;
@ -4169,9 +4165,9 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata,
float brushPointVelocity[3];
float velocity[3];
const int v1 = loops[mlooptri[hitTri].tri[0]].v;
const int v2 = loops[mlooptri[hitTri].tri[1]].v;
const int v3 = loops[mlooptri[hitTri].tri[2]].v;
const int v1 = loops[looptris[hitTri].tri[0]].v;
const int v2 = loops[looptris[hitTri].tri[1]].v;
const int v3 = loops[looptris[hitTri].tri[2]].v;
/* calculate barycentric weights for hit point */
interp_weights_tri_v3(weights, positions[v1], positions[v2], positions[v3], hitCoord);
@ -4270,7 +4266,6 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
PaintBakeData *bData = sData->bData;
Mesh *mesh = nullptr;
Vec3f *brushVelocity = nullptr;
const MLoopTri *mlooptri = nullptr;
if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
dynamicPaint_brushMeshCalculateVelocity(
@ -4294,7 +4289,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
float(*positions)[3] = BKE_mesh_vert_positions_for_write(mesh);
const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh);
mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<MLoop> loops = mesh->loops();
numOfVerts = mesh->totvert;
@ -4350,7 +4345,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
data.mesh = mesh;
data.positions = positions;
data.loops = loops;
data.mlooptri = mlooptri;
data.looptris = looptris;
data.brush_radius = brush_radius;
data.avg_brushNor = avg_brushNor;
data.brushVelocity = brushVelocity;

View File

@ -939,7 +939,7 @@ struct ObstaclesFromDMData {
const float (*vert_positions)[3];
const MLoop *mloop;
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
BVHTreeFromMesh *tree;
FluidObjectBB *bb;
@ -974,7 +974,7 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata,
update_velocities(data->fes,
data->vert_positions,
data->mloop,
data->mlooptri,
data->looptris.data(),
bb->velocity,
index,
data->tree,
@ -997,7 +997,6 @@ static void obstacles_from_mesh(Object *coll_ob,
float dt)
{
if (fes->mesh) {
const MLoopTri *looptri;
BVHTreeFromMesh tree_data = {nullptr};
int numverts, i;
@ -1010,7 +1009,7 @@ static void obstacles_from_mesh(Object *coll_ob,
int min[3], max[3], res[3];
const MLoop *mloop = BKE_mesh_loops(me);
looptri = BKE_mesh_runtime_looptri_ensure(me);
const blender::Span<MLoopTri> looptris = me->looptris();
numverts = me->totvert;
/* TODO(sebbas): Make initialization of vertex velocities optional? */
@ -1074,7 +1073,7 @@ static void obstacles_from_mesh(Object *coll_ob,
data.fes = fes;
data.vert_positions = positions;
data.mloop = mloop;
data.mlooptri = looptri;
data.looptris = looptris;
data.tree = &tree_data;
data.bb = bb;
data.has_velocity = has_velocity;
@ -1983,7 +1982,7 @@ struct EmitFromDMData {
const float (*vert_positions)[3];
const float (*vert_normals)[3];
const MLoop *mloop;
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
const float (*mloopuv)[2];
const MDeformVert *dvert;
int defgrp_index;
@ -2017,7 +2016,7 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
data->vert_positions,
data->vert_normals,
data->mloop,
data->mlooptri,
data->looptris.data(),
data->mloopuv,
bb->influence,
bb->velocity,
@ -2067,7 +2066,7 @@ static void emit_from_mesh(
float(*positions)[3] = BKE_mesh_vert_positions_for_write(me);
const MLoop *mloop = BKE_mesh_loops(me);
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
const blender::Span<MLoopTri> looptris = me->looptris();
const int numverts = me->totvert;
const MDeformVert *dvert = BKE_mesh_deform_verts(me);
const float(*mloopuv)[2] = static_cast<const float(*)[2]>(
@ -2144,7 +2143,7 @@ static void emit_from_mesh(
data.vert_positions = positions;
data.vert_normals = vert_normals;
data.mloop = mloop;
data.mlooptri = mlooptri;
data.looptris = looptris;
data.mloopuv = mloopuv;
data.dvert = dvert;
data.defgrp_index = defgrp_index;

View File

@ -493,7 +493,13 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
copy_v3_v3(&pt2->x, last_coord);
new_pt[i].pressure = pt[0].pressure;
new_pt[i].strength = pt[0].strength;
memcpy(new_pt[i].vert_color, pt[0].vert_color, sizeof(float[4]));
copy_v3_v3(&pt2->x, last_coord);
new_pt[i].pressure = pt[0].pressure;
new_pt[i].strength = pt[0].strength;
new_pt[i].uv_fac = pt[0].uv_fac;
new_pt[i].uv_rot = pt[0].uv_rot;
copy_v2_v2(new_pt[i].uv_fill, pt[0].uv_fill);
copy_v4_v4(new_pt[i].vert_color, pt[0].vert_color);
if (select) {
new_pt[i].flag |= GP_SPOINT_SELECT;
}

View File

@ -1252,8 +1252,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
int i;
BLI_assert(mode & MREMAP_MODE_LOOP);
BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f));
@ -1262,7 +1260,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (mode == MREMAP_MODE_TOPOLOGY) {
/* In topology mapping, we assume meshes are identical, islands included! */
BLI_assert(numloops_dst == me_src->totloop);
for (i = 0; i < numloops_dst; i++) {
for (int i = 0; i < numloops_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
}
@ -1311,8 +1309,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const blender::Span<MEdge> edges_src = me_src->edges();
const blender::Span<MPoly> polys_src = me_src->polys();
const blender::Span<MLoop> loops_src = me_src->loops();
const MLoopTri *looptri_src = nullptr;
int num_looptri_src = 0;
blender::Span<MLoopTri> looptris_src;
size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE;
float(*vcos_interp)[3] = nullptr;
@ -1506,7 +1503,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
MeshElemMap *isld = island_store.islands[tindex];
int num_verts_active = 0;
verts_active.fill(false);
for (i = 0; i < isld->count; i++) {
for (int i = 0; i < isld->count; i++) {
const MPoly &poly = polys_src[isld->indices[i]];
for (lidx_src = poly.loopstart; lidx_src < poly.loopstart + poly.totloop; lidx_src++) {
const uint vidx_src = loops_src[lidx_src].v;
@ -1533,16 +1530,14 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
else { /* We use polygons. */
if (use_islands) {
/* bvhtree here uses looptri faces... */
looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
num_looptri_src = BKE_mesh_runtime_looptri_len(me_src);
blender::BitVector<> looptri_active(num_looptri_src);
looptris_src = me_src->looptris();
blender::BitVector<> looptri_active(looptris_src.size());
for (tindex = 0; tindex < num_trees; tindex++) {
int num_looptri_active = 0;
looptri_active.fill(false);
for (i = 0; i < num_looptri_src; i++) {
const MPoly &poly = polys_src[looptri_src[i].poly];
for (const int64_t i : looptris_src.index_range()) {
const MPoly &poly = polys_src[looptris_src[i].poly];
if (island_store.items_to_islands[poly.loopstart] == tindex) {
looptri_active[i].set();
num_looptri_active++;
@ -1551,8 +1546,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
bvhtree_from_mesh_looptri_ex(&treedata[tindex],
positions_src,
loops_src.data(),
looptri_src,
num_looptri_src,
looptris_src.data(),
int(looptris_src.size()),
looptri_active,
num_looptri_active,
0.0,
@ -1636,7 +1631,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
vert_to_refelem_map_src = vert_to_poly_map_src;
}
for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
for (int i = vert_to_refelem_map_src[nearest.index].count; i--;) {
const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
BLI_assert(index_src != -1);
const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
@ -1881,7 +1876,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
*/
int last_valid_pidx_isld_src = -1;
/* Note we go backward here, from dest to src poly. */
for (i = as_solution.steps - 1; i--;) {
for (int i = as_solution.steps - 1; i--;) {
BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
const int eidx = POINTER_AS_INT(as_link->custom_data);
pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
@ -1973,7 +1968,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
*/
int last_valid_pidx_isld_src = -1;
/* Note we go backward here, from dest to src poly. */
for (i = as_solution.steps - 1; i--;) {
for (int i = as_solution.steps - 1; i--;) {
BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
int eidx = POINTER_AS_INT(as_link->custom_data);
@ -2008,14 +2003,14 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
&poly_to_looptri_map_src_buff,
polys_src.data(),
int(polys_src.size()),
looptri_src,
num_looptri_src);
looptris_src.data(),
int(looptris_src.size()));
}
for (j = poly_to_looptri_map_src[pidx_src].count; j--;) {
float h[3];
const MLoopTri *lt =
&looptri_src[poly_to_looptri_map_src[pidx_src].indices[j]];
&looptris_src[poly_to_looptri_map_src[pidx_src].indices[j]];
float dist_sq;
closest_on_tri_to_point_v3(h,

View File

@ -65,15 +65,14 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
{
const Span<float3> input_positions = input_mesh->vert_positions();
const Span<MLoop> input_loops = input_mesh->loops();
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
const Span<MLoopTri> looptris = input_mesh->looptris();
/* Gather the required data for export to the internal quadriflow mesh format. */
MVertTri *verttri = (MVertTri *)MEM_callocN(
sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh), "remesh_looptri");
Array<MVertTri> verttri(looptris.size());
BKE_mesh_runtime_verttri_from_looptri(
verttri, input_loops.data(), looptri, BKE_mesh_runtime_looptri_len(input_mesh));
verttri.data(), input_loops.data(), looptris.data(), looptris.size());
const int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
const int totfaces = looptris.size();
const int totverts = input_mesh->totvert;
Array<int> faces(totfaces * 3);
@ -105,8 +104,6 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
/* Run the remesher */
QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data);
MEM_freeN(verttri);
if (qrd.out_faces == nullptr) {
/* The remeshing was canceled */
return nullptr;
@ -335,7 +332,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
const VArraySpan<int> src(src_face_sets);
MutableSpan<int> dst = dst_face_sets.span;
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source);
const blender::Span<MLoopTri> looptris = source->looptris();
BVHTreeFromMesh bvhtree = {nullptr};
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_LOOPTRI, 2);
@ -353,7 +350,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
BLI_bvhtree_find_nearest(
bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index != -1) {
dst[i] = src[looptri[nearest.index].poly];
dst[i] = src[looptris[nearest.index].poly];
}
else {
dst[i] = 1;

View File

@ -574,14 +574,15 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
int tangent_names_len)
{
/* TODO(@ideasman42): store in Mesh.runtime to avoid recalculation. */
const blender::Span<MLoopTri> looptris = me_eval->looptris();
short tangent_mask = 0;
BKE_mesh_calc_loop_tangent_ex(
BKE_mesh_vert_positions(me_eval),
me_eval->polys().data(),
uint(me_eval->totpoly),
me_eval->loops().data(),
BKE_mesh_runtime_looptri_ensure(me_eval),
uint(BKE_mesh_runtime_looptri_len(me_eval)),
looptris.data(),
uint(looptris.size()),
&me_eval->ldata,
calc_active_tangent,
tangent_names,

View File

@ -231,15 +231,14 @@ static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(Mesh *mesh)
data->edge_is_boundary = edge_is_boundary;
/* Build the boundary looptri bitmask. */
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
int totlooptri = BKE_mesh_runtime_looptri_len(mesh);
const blender::Span<MLoopTri> looptris = mesh->looptris();
BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri,
BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(looptris.size(),
"ShrinkwrapBoundaryData::looptri_is_boundary");
for (int i = 0; i < totlooptri; i++) {
for (const int64_t i : looptris.index_range()) {
int real_edges[3];
BKE_mesh_looptri_get_real_edges(edges.data(), loops.data(), &mlooptri[i], real_edges);
BKE_mesh_looptri_get_real_edges(edges.data(), loops.data(), &looptris[i], real_edges);
for (int j = 0; j < 3; j++) {
if (real_edges[j] >= 0 && edge_mode[real_edges[j]]) {

View File

@ -387,7 +387,7 @@ BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr,
int stop;
switch (iter_type) {
case MR_ITER_LOOPTRI:
range_data.elems = is_mesh ? mr->mlooptri : (void *)mr->edit_bmesh->looptris;
range_data.elems = is_mesh ? mr->looptris.data() : (void *)mr->edit_bmesh->looptris;
func = is_mesh ? extract_range_iter_looptri_mesh : extract_range_iter_looptri_bm;
stop = mr->tri_len;
break;

View File

@ -339,7 +339,7 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
mr->mlooptri = BKE_mesh_runtime_looptri_ensure(mr->me);
mr->looptris = mr->me->looptris();
}
}
else {

View File

@ -83,7 +83,7 @@ struct MeshRenderData {
BMFace *efa_act;
BMFace *efa_act_uv;
/* The triangulation of #Mesh polygons, owned by the mesh. */
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
const int *material_indices;
const float (*vert_normals)[3];
const float (*poly_normals)[3];

View File

@ -74,7 +74,7 @@ static void extract_tris_iter_poly_mesh(const MeshRenderData *mr,
int tri_len = mp->totloop - 2;
for (int offs = 0; offs < tri_len; offs++) {
const MLoopTri *mlt = &mr->mlooptri[tri_first_index_real + offs];
const MLoopTri *mlt = &mr->looptris[tri_first_index_real + offs];
int tri_index = tri_first_index + offs;
GPU_indexbuf_set_tri_verts(elb, tri_index, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
}

View File

@ -214,12 +214,12 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
BVHTreeFromMesh treeData = {nullptr};
BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4);
const MLoopTri *mlooptri = mr->mlooptri;
for (int i = 0; i < mr->tri_len; i++, mlooptri++) {
const int index = mlooptri->poly;
const float *cos[3] = {mr->vert_positions[mr->mloop[mlooptri->tri[0]].v],
mr->vert_positions[mr->mloop[mlooptri->tri[1]].v],
mr->vert_positions[mr->mloop[mlooptri->tri[2]].v]};
const Span<MLoopTri> looptris = mr->looptris;
for (const int i : looptris.index_range()) {
const int index = looptris[i].poly;
const float *cos[3] = {mr->vert_positions[mr->mloop[looptris[i].tri[0]].v],
mr->vert_positions[mr->mloop[looptris[i].tri[1]].v],
mr->vert_positions[mr->mloop[looptris[i].tri[2]].v]};
float ray_co[3];
float ray_no[3];
@ -261,7 +261,7 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
struct BVHTree_OverlapData {
const float3 *positions;
const MLoop *loops;
const MLoopTri *mlooptri;
Span<MLoopTri> looptris;
float epsilon;
};
@ -269,8 +269,8 @@ static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int /*threa
{
struct BVHTree_OverlapData *data = static_cast<struct BVHTree_OverlapData *>(userdata);
const MLoopTri *tri_a = &data->mlooptri[index_a];
const MLoopTri *tri_b = &data->mlooptri[index_b];
const MLoopTri *tri_a = &data->looptris[index_a];
const MLoopTri *tri_b = &data->looptris[index_b];
if (UNLIKELY(tri_a->poly == tri_b->poly)) {
return false;
@ -344,15 +344,15 @@ static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect)
struct BVHTree_OverlapData data = {nullptr};
data.positions = mr->vert_positions;
data.loops = mr->mloop;
data.mlooptri = mr->mlooptri;
data.looptris = mr->looptris;
data.epsilon = BLI_bvhtree_get_epsilon(tree);
BVHTreeOverlap *overlap = BLI_bvhtree_overlap_self(tree, &overlap_len, bvh_overlap_cb, &data);
if (overlap) {
for (int i = 0; i < overlap_len; i++) {
const MPoly *f_hit_pair[2] = {
&mr->mpoly[mr->mlooptri[overlap[i].indexA].poly],
&mr->mpoly[mr->mlooptri[overlap[i].indexB].poly],
&mr->mpoly[mr->looptris[overlap[i].indexA].poly],
&mr->mpoly[mr->looptris[overlap[i].indexB].poly],
};
for (int j = 0; j < 2; j++) {
const MPoly *f_hit = f_hit_pair[j];

View File

@ -118,7 +118,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
mr->mpoly,
mr->poly_len,
mr->mloop,
mr->mlooptri,
mr->looptris.data(),
mr->tri_len,
cd_ldata,
calc_active_tangent,

View File

@ -928,7 +928,7 @@ typedef struct MeshDeformBind {
struct {
blender::Span<MPoly> polys;
blender::Span<MLoop> loops;
const MLoopTri *looptri;
blender::Span<MLoopTri> looptris;
const float (*poly_nors)[3];
} cagemesh_cache;
} MeshDeformBind;
@ -959,13 +959,12 @@ static void harmonic_ray_callback(void *userdata,
MeshRayCallbackData *data = static_cast<MeshRayCallbackData *>(userdata);
MeshDeformBind *mdb = data->mdb;
const blender::Span<MLoop> loops = mdb->cagemesh_cache.loops;
const MLoopTri *looptri = mdb->cagemesh_cache.looptri, *lt;
const float(*poly_nors)[3] = mdb->cagemesh_cache.poly_nors;
MeshDeformIsect *isec = data->isec;
float no[3], co[3], dist;
float *face[3];
lt = &looptri[index];
const MLoopTri *lt = &mdb->cagemesh_cache.looptris[index];
face[0] = mdb->cagecos[loops[lt->tri[0]].v];
face[1] = mdb->cagecos[loops[lt->tri[1]].v];
@ -1034,7 +1033,7 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb,
&data,
BVH_RAYCAST_WATERTIGHT) != -1) {
const blender::Span<MLoop> loops = mdb->cagemesh_cache.loops;
const MLoopTri *lt = &mdb->cagemesh_cache.looptri[hit.index];
const MLoopTri *lt = &mdb->cagemesh_cache.looptris[hit.index];
const MPoly *mp = &mdb->cagemesh_cache.polys[lt->poly];
const float(*cagecos)[3] = mdb->cagecos;
const float len = isect_mdef.lambda;
@ -1632,7 +1631,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
Mesh *me = mdb->cagemesh;
mdb->cagemesh_cache.polys = me->polys();
mdb->cagemesh_cache.loops = me->loops();
mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
mdb->cagemesh_cache.looptris = me->looptris();
mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me);
}

View File

@ -1174,21 +1174,30 @@ static int gizmo_cage2d_modal(bContext *C,
}
}
float scale[2] = {1.0f, 1.0f};
for (int i = 0; i < 2; i++) {
if (size_orig[i] == 0) {
size_orig[i] = 1.0f;
gz->matrix_offset[i][i] = 1.0f;
}
scale[i] = size_new[i] / size_orig[i];
}
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM) {
if (constrain_axis[0] == false && constrain_axis[1] == false) {
if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
/* So that the cursor lies on the circle. */
size_new[1] = size_new[0] = len_v2(size_new);
scale[1] = scale[0] = len_v2(scale);
}
else {
size_new[1] = size_new[0] = (size_new[1] + size_new[0]) / 2.0f;
scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
}
}
else if (constrain_axis[0] == false) {
size_new[1] = size_new[0];
scale[1] = scale[0];
}
else if (constrain_axis[1] == false) {
size_new[0] = size_new[1];
scale[0] = scale[1];
}
else {
BLI_assert(0);
@ -1196,18 +1205,11 @@ static int gizmo_cage2d_modal(bContext *C,
}
/* Scale around pivot. */
float scale[2];
float matrix_scale[4][4];
unit_m4(matrix_scale);
for (int i = 0; i < 2; i++) {
if (size_orig[i] == 0) {
size_orig[i] = 1.0f;
gz->matrix_offset[i][i] = 1.0f;
}
scale[i] = size_new[i] / size_orig[i];
mul_v3_fl(matrix_scale[i], scale[i]);
}
mul_v3_fl(matrix_scale[0], scale[0]);
mul_v3_fl(matrix_scale[1], scale[1]);
transform_pivot_set_m4(matrix_scale, (const float[3]){UNPACK2(pivot), 0.0f});
mul_m4_m4_post(gz->matrix_offset, matrix_scale);

View File

@ -419,7 +419,7 @@ struct ProjPaintState {
blender::Span<MLoop> loops_eval;
const bool *select_poly_eval;
const int *material_indices;
const MLoopTri *mlooptri_eval;
blender::Span<MLoopTri> looptris_eval;
const float (*mloopuv_stencil_eval)[2];
@ -551,7 +551,7 @@ static Material *tex_get_material(const ProjPaintState *ps, int poly_i)
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const int poly_i = ps->mlooptri_eval[tri_index].poly;
const int poly_i = ps->looptris_eval[tri_index].poly;
Material *ma = tex_get_material(ps, poly_i);
return ma ? ma->texpaintslot + ma->paint_active_slot : nullptr;
}
@ -562,7 +562,7 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
return ps->stencil_ima;
}
const int poly_i = ps->mlooptri_eval[tri_index].poly;
const int poly_i = ps->looptris_eval[tri_index].poly;
Material *ma = tex_get_material(ps, poly_i);
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : nullptr;
return slot ? slot->ima : ps->canvas_ima;
@ -570,14 +570,14 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{
const int poly_i = ps->mlooptri_eval[tri_index].poly;
const int poly_i = ps->looptris_eval[tri_index].poly;
Material *ma = tex_get_material(ps, poly_i);
return ma ? ma->texpaintslot + ma->paint_clone_slot : nullptr;
}
static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{
const int poly_i = ps->mlooptri_eval[tri_index].poly;
const int poly_i = ps->looptris_eval[tri_index].poly;
Material *ma = tex_get_material(ps, poly_i);
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : nullptr;
return slot ? slot->ima : ps->clone_ima;
@ -673,7 +673,7 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
const int tri_index = POINTER_AS_INT(node->link);
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const float *vtri_ss[3] = {
ps->screenCoords[ps->loops_eval[lt->tri[0]].v],
ps->screenCoords[ps->loops_eval[lt->tri[1]].v],
@ -737,7 +737,7 @@ static bool project_paint_PickColor(
return false;
}
lt = &ps->mlooptri_eval[tri_index];
lt = &ps->looptris_eval[tri_index];
PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->poly_to_loop_uv, lt);
interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
@ -915,7 +915,7 @@ static bool project_bucket_point_occluded(const ProjPaintState *ps,
const int tri_index = POINTER_AS_INT(bucketFace->link);
if (orig_face != tri_index) {
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const float *vtri_ss[3] = {
ps->screenCoords[ps->loops_eval[lt->tri[0]].v],
ps->screenCoords[ps->loops_eval[lt->tri[1]].v],
@ -1121,7 +1121,7 @@ static bool pixel_bounds_array(
static void project_face_winding_init(const ProjPaintState *ps, const int tri_index)
{
/* detect the winding of faces in uv space */
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
@ -1141,7 +1141,7 @@ static bool check_seam(const ProjPaintState *ps,
int *other_face,
int *orig_fidx)
{
const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
const MLoopTri *orig_lt = &ps->looptris_eval[orig_face];
const float *orig_lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt)};
/* vert indices from face vert order indices */
const uint i1 = ps->loops_eval[orig_lt->tri[orig_i1_fidx]].v;
@ -1154,7 +1154,7 @@ static bool check_seam(const ProjPaintState *ps,
const int tri_index = POINTER_AS_INT(node->link);
if (tri_index != orig_face) {
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
/* could check if the 2 faces images match here,
* but then there wouldn't be a way to return the opposite face's info */
@ -1303,7 +1303,7 @@ static void uv_image_outset(const ProjPaintState *ps,
int fidx[2];
uint loop_index;
uint vert[2];
const MLoopTri *ltri = &ps->mlooptri_eval[tri_index];
const MLoopTri *ltri = &ps->looptris_eval[tri_index];
float ibuf_inv[2];
@ -1386,7 +1386,7 @@ static void insert_seam_vert_array(const ProjPaintState *ps,
const int ibuf_x,
const int ibuf_y)
{
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
const int fidx[2] = {fidx1, ((fidx1 + 1) % 3)};
float vec[2];
@ -1446,7 +1446,7 @@ static void project_face_seams_init(const ProjPaintState *ps,
int other_face, other_fidx;
/* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
int fidx[2] = {2, 0};
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
LinkNode *node;
/* initialize face winding if needed */
@ -1665,7 +1665,7 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
Image *other_tpage = ps->stencil_ima;
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, nullptr, nullptr))) {
const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt_other = &ps->looptris_eval[tri_index];
const float *lt_other_tri_uv[3] = {ps->mloopuv_stencil_eval[lt_other->tri[0]],
ps->mloopuv_stencil_eval[lt_other->tri[1]],
ps->mloopuv_stencil_eval[lt_other->tri[2]]};
@ -1704,7 +1704,7 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
}
if (ps->do_mask_cavity) {
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
float ca1, ca2, ca3, ca_mask;
ca1 = ps->cavities[lt_vtri[0]];
@ -1719,7 +1719,7 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
/* calculate mask */
if (ps->do_mask_normal) {
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const MPoly *mp = &ps->polys_eval[lt->poly];
float no[3], angle_cos;
@ -1959,7 +1959,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, nullptr, nullptr))) {
const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt_other = &ps->looptris_eval[tri_index];
const float *lt_other_tri_uv[3] = {
PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, lt_other)};
@ -2996,7 +2996,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
ps->projImages + image_index,
};
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
@ -3287,7 +3287,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
bucket_clip_edges[1])) {
/* Avoid div by zero. */
if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) {
uint loop_idx = ps->mlooptri_eval[tri_index].tri[fidx1];
uint loop_idx = ps->looptris_eval[tri_index].tri[fidx1];
LoopSeamData *seam_data = &ps->loopSeamData[loop_idx];
float(*seam_uvs)[2] = seam_data->seam_uvs;
@ -3525,7 +3525,7 @@ static void project_bucket_init(const ProjPaintState *ps,
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
tri_index = POINTER_AS_INT(node->link);
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
/* Image context switching */
@ -4085,8 +4085,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->totpoly_eval = ps->me_eval->totpoly;
ps->totloop_eval = ps->me_eval->totloop;
ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval);
ps->totlooptri_eval = BKE_mesh_runtime_looptri_len(ps->me_eval);
ps->looptris_eval = ps->me_eval->looptris();
ps->poly_to_loop_uv = static_cast<const float(**)[2]>(
MEM_mallocN(ps->totpoly_eval * sizeof(float(*)[2]), "proj_paint_mtfaces"));
@ -4159,7 +4158,7 @@ static bool project_paint_clone_face_skip(ProjPaintState *ps,
}
/* will set multiple times for 4+ sided poly */
ps->poly_to_loop_uv_clone[ps->mlooptri_eval[tri_index].poly] = lc->mloopuv_clone_base;
ps->poly_to_loop_uv_clone[ps->looptris_eval[tri_index].poly] = lc->mloopuv_clone_base;
}
return false;
}
@ -4304,17 +4303,17 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
TexPaintSlot *slot_last = nullptr;
TexPaintSlot *slot = nullptr;
int tile_last = -1, tile;
const MLoopTri *lt;
int image_index = -1, tri_index;
int prev_poly = -1;
const blender::Span<MLoopTri> looptris = ps->looptris_eval;
BLI_assert(ps->image_tot == 0);
for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
for (tri_index = 0; tri_index < ps->totlooptri_eval; tri_index++) {
bool is_face_sel;
bool skip_tri = false;
is_face_sel = project_paint_check_face_sel(ps, face_lookup, lt);
is_face_sel = project_paint_check_face_sel(ps, face_lookup, &looptris[tri_index]);
if (!ps->do_stencil_brush) {
slot = project_paint_face_paint_slot(ps, tri_index);
@ -4353,12 +4352,12 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
tpage = ps->stencil_ima;
}
ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
ps->poly_to_loop_uv[looptris[tri_index].poly] = mloopuv_base;
tile = project_paint_face_paint_tile(tpage, mloopuv_base[lt->tri[0]]);
tile = project_paint_face_paint_tile(tpage, mloopuv_base[looptris[tri_index].tri[0]]);
#ifndef PROJ_DEBUG_NOSEAMBLEED
project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
project_paint_bleed_add_face_user(ps, arena, &looptris[tri_index], tri_index);
#endif
if (skip_tri || project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
@ -4369,7 +4368,7 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
if (is_face_sel && tpage) {
ProjPaintFaceCoSS coSS;
proj_paint_face_coSS_init(ps, lt, &coSS);
proj_paint_face_coSS_init(ps, &looptris[tri_index], &coSS);
if (is_multi_view == false) {
if (project_paint_flt_max_cull(ps, &coSS)) {
@ -4386,12 +4385,12 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
/* Back-face culls individual triangles but mask normal will use polygon. */
if (ps->do_backfacecull) {
if (ps->do_mask_normal) {
if (prev_poly != lt->poly) {
if (prev_poly != looptris[tri_index].poly) {
int iloop;
bool culled = true;
const MPoly *poly = &ps->polys_eval[lt->poly];
const MPoly *poly = &ps->polys_eval[looptris[tri_index].poly];
int poly_loops = poly->totloop;
prev_poly = lt->poly;
prev_poly = looptris[tri_index].poly;
for (iloop = 0; iloop < poly_loops; iloop++) {
if (!(ps->vertFlags[ps->loops_eval[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
culled = false;
@ -4404,7 +4403,6 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
* but counter gets incremented when continuing, so decrease by 3 */
int poly_tri = poly_loops - 3;
tri_index += poly_tri;
lt += poly_tri;
continue;
}
}
@ -4451,7 +4449,7 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
if (image_index != -1) {
/* Initialize the faces screen pixels */
/* Add this to a list to initialize later */
project_paint_delayed_face_init(ps, lt, tri_index);
project_paint_delayed_face_init(ps, &looptris[tri_index], tri_index);
}
}
}
@ -5703,7 +5701,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
tri_index = project_paint_PickFace(ps, pos, w);
if (tri_index != -1) {
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
float world[3];
UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;

View File

@ -902,7 +902,7 @@ void file_draw_list(const bContext *C, ARegion *region)
int numfiles;
int numfiles_layout;
int offset;
int textwidth, textheight;
int column_width, textheight;
int i;
bool is_icon;
eFontStyle_Align align;
@ -936,9 +936,9 @@ void file_draw_list(const bContext *C, ARegion *region)
filelist_file_cache_slidingwindow_set(files, numfiles_layout);
textwidth = (FILE_IMGDISPLAY == params->display) ?
layout->tile_w :
round_fl_to_int(layout->attribute_columns[COLUMN_NAME].width);
column_width = (FILE_IMGDISPLAY == params->display) ?
layout->tile_w :
round_fl_to_int(layout->attribute_columns[COLUMN_NAME].width);
textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5);
align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT;
@ -1053,7 +1053,7 @@ void file_draw_list(const bContext *C, ARegion *region)
if (file_selflag & FILE_SEL_EDITING) {
const short width = (params->display == FILE_IMGDISPLAY) ?
textwidth :
column_width :
layout->attribute_columns[COLUMN_NAME].width -
ATTRIBUTE_COLUMN_PADDING;
@ -1099,8 +1099,8 @@ void file_draw_list(const bContext *C, ARegion *region)
tile_draw_rect.ymin + layout->tile_border_y + layout->textheight :
tile_draw_rect.ymax - layout->tile_border_y;
const int twidth = (params->display == FILE_IMGDISPLAY) ?
textwidth :
textwidth - 1 - icon_ofs - padx - layout->tile_border_x;
column_width :
column_width - 1 - icon_ofs - padx - layout->tile_border_x;
file_draw_string(txpos, typos, file->name, (float)twidth, textheight, align, text_col);
}

View File

@ -2039,9 +2039,11 @@ static NodeLinkDrawConfig nodelink_get_draw_config(const bContext &C,
draw_config.th_col2 = th_col2;
draw_config.th_col3 = th_col3;
const bNodeTree &node_tree = *snode.edittree;
draw_config.dim_factor = selected ? 1.0f :
node_link_dim_factor(
snode.runtime->all_socket_locations, v2d, link);
node_tree.runtime->all_socket_locations, v2d, link);
bTheme *btheme = UI_GetTheme();
draw_config.dash_alpha = btheme->space_node.dash_alpha;
@ -2063,24 +2065,21 @@ static NodeLinkDrawConfig nodelink_get_draw_config(const bContext &C,
if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
PointerRNA from_node_ptr, to_node_ptr;
RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
RNA_pointer_create((ID *)&node_tree, &RNA_Node, link.fromnode, &from_node_ptr);
RNA_pointer_create((ID *)&node_tree, &RNA_Node, link.tonode, &to_node_ptr);
if (link.fromsock) {
node_socket_color_get(
C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.start_color);
node_socket_color_get(C, node_tree, from_node_ptr, *link.fromsock, draw_config.start_color);
}
else {
node_socket_color_get(
C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.start_color);
node_socket_color_get(C, node_tree, to_node_ptr, *link.tosock, draw_config.start_color);
}
if (link.tosock) {
node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.end_color);
node_socket_color_get(C, node_tree, to_node_ptr, *link.tosock, draw_config.end_color);
}
else {
node_socket_color_get(
C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.end_color);
node_socket_color_get(C, node_tree, from_node_ptr, *link.fromsock, draw_config.end_color);
}
}
else {
@ -2167,8 +2166,9 @@ void node_draw_link_bezier(const bContext &C,
const int th_col3,
const bool selected)
{
const std::array<float2, 4> points = node_link_bezier_points(snode.runtime->all_socket_locations,
link);
const bNodeTree &node_tree = *snode.edittree;
const std::array<float2, 4> points = node_link_bezier_points(
node_tree.runtime->all_socket_locations, link);
if (!node_link_draw_is_visible(v2d, points)) {
return;
}
@ -2227,15 +2227,18 @@ void node_draw_link(const bContext &C,
static std::array<float2, 4> node_link_bezier_points_dragged(const SpaceNode &snode,
const bNodeLink &link)
{
const bNodeTree &node_tree = *snode.edittree;
const float2 cursor = snode.runtime->cursor * UI_DPI_FAC;
std::array<float2, 4> points;
points[0] = link.fromsock ?
socket_link_connection_location(
snode.runtime->all_socket_locations, *link.fromnode, *link.fromsock, link) :
socket_link_connection_location(node_tree.runtime->all_socket_locations,
*link.fromnode,
*link.fromsock,
link) :
cursor;
points[3] = link.tosock ?
socket_link_connection_location(
snode.runtime->all_socket_locations, *link.tonode, *link.tosock, link) :
node_tree.runtime->all_socket_locations, *link.tonode, *link.tosock, link) :
cursor;
calculate_inner_link_bezier_points(points);
return points;

View File

@ -138,7 +138,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
const ARegion &region = *CTX_wm_region(C);
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
const Span<float2> socket_locations = ntree.runtime->all_socket_locations;
Vector<float2> path;
RNA_BEGIN (op->ptr, itemptr, "path") {

View File

@ -268,6 +268,9 @@ void node_sort(bNodeTree &ntree)
ntree.runtime->nodes_by_id.add_new(sort_nodes[i]);
sort_nodes[i]->runtime->index_in_tree = i;
}
/* Nodes have been reordered; the socket locations are invalid until the node tree is redrawn. */
ntree.runtime->all_socket_locations.clear();
}
static Array<uiBlock *> node_uiblocks_init(const bContext &C, const Span<bNode *> nodes)
@ -3178,16 +3181,16 @@ static void draw_nodetree(const bContext &C,
else if (ntree.type == NTREE_COMPOSIT) {
tree_draw_ctx.used_by_realtime_compositor = realtime_compositor_is_in_use(C);
}
snode->runtime->all_socket_locations.reinitialize(ntree.all_sockets().size());
ntree.runtime->all_socket_locations.reinitialize(ntree.all_sockets().size());
node_update_nodetree(
C, tree_draw_ctx, ntree, nodes, blocks, snode->runtime->all_socket_locations);
C, tree_draw_ctx, ntree, nodes, blocks, ntree.runtime->all_socket_locations);
node_draw_nodetree(C,
tree_draw_ctx,
region,
*snode,
ntree,
snode->runtime->all_socket_locations,
ntree.runtime->all_socket_locations,
nodes,
blocks,
parent_key);

View File

@ -1129,13 +1129,14 @@ bNodeSocket *node_find_indicated_socket(SpaceNode &snode,
rctf rect;
const float size_sock_padded = NODE_SOCKSIZE + 4;
snode.edittree->ensure_topology_cache();
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
if (socket_locations.size() != snode.edittree->all_sockets().size()) {
bNodeTree &node_tree = *snode.edittree;
node_tree.ensure_topology_cache();
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
if (socket_locations.size() != node_tree.all_sockets().size()) {
/* Sockets haven't been drawn yet, e.g. when the file is currently opening. */
return nullptr;
}
const Span<bNode *> nodes = snode.edittree->all_nodes();
const Span<bNode *> nodes = node_tree.all_nodes();
if (nodes.is_empty()) {
return nullptr;
}

View File

@ -79,12 +79,6 @@ struct bNodeLinkDrag {
};
struct SpaceNode_Runtime {
/**
* The location of all sockets in the tree, calculated while drawing the nodes.
* To be indexed with #bNodeSocket::index_in_tree().
*/
Vector<float2> all_socket_locations;
float aspect;
/** Mouse position for drawing socket-less links and adding nodes. */

View File

@ -121,7 +121,11 @@ static void pick_input_link_by_link_intersect(const bContext &C,
const float2 &cursor)
{
SpaceNode *snode = CTX_wm_space_node(&C);
const Span<float2> socket_locations = snode->runtime->all_socket_locations;
bNodeTree &node_tree = *snode->edittree;
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
if (socket_locations.is_empty()) {
return;
}
float2 drag_start;
RNA_float_get_array(op.ptr, "drag_start", drag_start);
@ -132,7 +136,7 @@ static void pick_input_link_by_link_intersect(const bContext &C,
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
bNodeLink *link_to_pick = nullptr;
clear_picking_highlight(&snode->edittree->links);
clear_picking_highlight(&node_tree.links);
for (bNodeLink *link : socket->directly_linked_links()) {
/* Test if the cursor is near a link. */
std::array<float2, NODE_LINK_RESOL + 1> coords;
@ -643,7 +647,7 @@ static int view_socket(const bContext &C,
}
if (viewer_node == nullptr) {
const float2 socket_location =
snode.runtime->all_socket_locations[bsocket_to_view.index_in_tree()];
btree.runtime->all_socket_locations[bsocket_to_view.index_in_tree()];
const int viewer_type = get_default_viewer_type(&C);
const float2 location{socket_location.x / UI_DPI_FAC + 100, socket_location.y / UI_DPI_FAC};
viewer_node = add_static_node(C, viewer_type, location);
@ -1072,7 +1076,12 @@ static void node_link_cancel(bContext *C, wmOperator *op)
static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree &node_tree = *snode.edittree;
bNodeLinkDrag &nldrag = *static_cast<bNodeLinkDrag *>(op.customdata);
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
if (socket_locations.is_empty()) {
return;
}
if (nldrag.in_out == SOCK_OUT) {
if (bNodeSocket *tsock = node_find_indicated_socket(snode, cursor, SOCK_IN)) {
@ -1103,8 +1112,7 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
continue;
}
if (tsock && tsock->is_multi_input()) {
sort_multi_input_socket_links_with_drag(
snode.runtime->all_socket_locations, *tsock, link, cursor);
sort_multi_input_socket_links_with_drag(socket_locations, *tsock, link, cursor);
}
}
}
@ -1477,7 +1485,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
bNodeTree &node_tree = *snode.edittree;
node_tree.ensure_topology_cache();
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
Set<bNodeLink *> links_to_remove;
LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
@ -1563,7 +1571,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
SpaceNode &snode = *CTX_wm_space_node(C);
const ARegion &region = *CTX_wm_region(C);
bNodeTree &ntree = *snode.edittree;
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
const Span<float2> socket_locations = ntree.runtime->all_socket_locations;
Vector<float2> path;
RNA_BEGIN (op->ptr, itemptr, "path") {
@ -2046,7 +2054,10 @@ void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion &region)
{
bNodeTree &node_tree = *snode.edittree;
node_tree.ensure_topology_cache();
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
if (socket_locations.is_empty()) {
return;
}
node_insert_on_link_flags_clear(node_tree);

View File

@ -72,6 +72,7 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
const float(*positions)[3] = BKE_mesh_vert_positions(me);
const blender::Span<MPoly> polys = me->polys();
const blender::Span<MLoop> loops = me->loops();
const blender::Span<MLoopTri> looptris = me->looptris();
facemap_data = static_cast<const int *>(CustomData_get_layer(&me->pdata, CD_FACEMAP));
@ -90,46 +91,23 @@ void ED_draw_object_facemap(Depsgraph *depsgraph,
GPUVertBufRaw pos_step;
GPU_vertbuf_attr_get_raw_data(vbo_pos, pos_id, &pos_step);
if (BKE_mesh_runtime_looptri_ensure(me)) {
const MLoopTri *mlt = BKE_mesh_runtime_looptri_ensure(me);
for (const int i : polys.index_range()) {
const MPoly &poly = polys[i];
if (facemap_data[i] == facemap) {
for (int j = 2; j < poly.totloop; j++) {
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[loops[mlt->tri[0]].v]);
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[loops[mlt->tri[1]].v]);
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[loops[mlt->tri[2]].v]);
vbo_len_used += 3;
mlt++;
}
}
else {
mlt += poly.totloop - 2;
int tri_index = 0;
for (const int i : polys.index_range()) {
const MPoly &poly = polys[i];
if (facemap_data[i] == facemap) {
for (int j = 2; j < poly.totloop; j++) {
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[loops[looptris[tri_index].tri[0]].v]);
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[loops[looptris[tri_index].tri[1]].v]);
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[loops[looptris[tri_index].tri[2]].v]);
vbo_len_used += 3;
tri_index++;
}
}
}
else {
/* No tessellation data, fan-fill. */
for (const int i : polys.index_range()) {
const MPoly &poly = polys[i];
if (facemap_data[i] == facemap) {
const MLoop *ml_start = &loops[poly.loopstart];
const MLoop *ml_a = ml_start + 1;
const MLoop *ml_b = ml_start + 2;
for (int j = 2; j < poly.totloop; j++) {
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)),
positions[ml_start->v]);
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)), positions[ml_a->v]);
copy_v3_v3(static_cast<float *>(GPU_vertbuf_raw_step(&pos_step)), positions[ml_b->v]);
vbo_len_used += 3;
ml_a++;
ml_b++;
}
}
else {
tri_index += poly.totloop - 2;
}
}

View File

@ -55,6 +55,8 @@ set(SRC
transform_generics.c
transform_gizmo_2d.c
transform_gizmo_3d.cc
transform_gizmo_3d_cage.cc
transform_gizmo_3d_shear.cc
transform_gizmo_extrude_3d.c
transform_input.c
transform_mode.c
@ -99,6 +101,7 @@ set(SRC
transform_convert.h
transform_data.h
transform_draw_cursors.h
transform_gizmo.h
transform_mode.h
transform_orientations.h
transform_snap.h

View File

@ -52,6 +52,7 @@
#include "transform_constraints.h"
#include "transform_convert.h"
#include "transform_draw_cursors.h"
#include "transform_gizmo.h"
#include "transform_mode.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -728,40 +728,6 @@ void transform_final_value_get(const TransInfo *t, float *value, int value_num);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Gizmo
* \{ */
/* transform_gizmo.c */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
/**
* Set the #T_NO_GIZMO flag.
*
* \note This maintains the conventional behavior of not displaying the gizmo if the operator has
* been triggered by shortcuts.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t);
/**
* Change the gizmo and its orientation to match the transform state.
*
* \note This used while the modal operator is running so changes to the constraint or mode show
* the gizmo associated with that state, as if it had been the initial gizmo dragged.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t);
/**
* Restores the non-modal state of the gizmo.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t);
/** \} */
/* -------------------------------------------------------------------- */
/** \name TransData Creation and General Handling
* \{ */

View File

@ -34,6 +34,7 @@
#include "UI_resources.h"
#include "transform.h"
#include "transform_gizmo.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -35,6 +35,7 @@
#include "RNA_prototypes.h"
#include "transform.h"
#include "transform_orientations.h"
#include "transform_snap.h"
/* Own include. */

View File

@ -49,6 +49,7 @@
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_mode.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup edtransform
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name Types/
* \{ */
struct ARegion;
struct bContext;
struct bScreen;
struct RegionView3D;
struct Scene;
struct ScrArea;
struct TransformBounds;
struct TransInfo;
struct wmGizmoGroup;
struct wmGizmoGroupType;
struct wmMsgBus;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Gizmo
* \{ */
/* transform_gizmo_3d.c */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
void gizmo_prepare_mat(const struct bContext *C,
struct RegionView3D *rv3d,
const struct TransformBounds *tbounds);
void gizmo_xform_message_subscribe(struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
struct Scene *scene,
struct bScreen *screen,
struct ScrArea *area,
struct ARegion *region,
void (*type_fn)(struct wmGizmoGroupType *));
/**
* Set the #T_NO_GIZMO flag.
*
* \note This maintains the conventional behavior of not displaying the gizmo if the operator has
* been triggered by shortcuts.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t);
/**
* Change the gizmo and its orientation to match the transform state.
*
* \note This used while the modal operator is running so changes to the constraint or mode show
* the gizmo associated with that state, as if it had been the initial gizmo dragged.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t);
/**
* Restores the non-modal state of the gizmo.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t);
/** \} */
#ifdef __cplusplus
}
#endif

View File

@ -42,7 +42,8 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
#include "transform.h" /* own include */
#include "transform.h"
#include "transform_gizmo.h"
/* -------------------------------------------------------------------- */
/** \name Shared Callback's

View File

@ -8,31 +8,15 @@
* Used for 3D View
*/
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "BLI_array_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_crazyspace.hh"
#include "BKE_curve.h"
#include "BKE_curves.hh"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@ -41,12 +25,10 @@
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#include "BLI_array_utils.h"
#include "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
#include "ED_armature.h"
#include "ED_curves.h"
@ -56,9 +38,7 @@
#include "ED_object.h"
#include "ED_particle.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
@ -67,12 +47,9 @@
/* local module include */
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_snap.h"
#include "MEM_guardedalloc.h"
#include "GPU_state.h"
static wmGizmoGroupType *g_GGT_xform_gizmo = nullptr;
static wmGizmoGroupType *g_GGT_xform_gizmo_context = nullptr;
@ -527,101 +504,6 @@ static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *e
}
}
/* could move into BLI_math however this is only useful for display/editing purposes */
static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
{
/* X/Y are arbitrary axes, most importantly Z is the axis of rotation. */
float cross_vec[3];
float quat[4];
/* this is an un-scientific method to get a vector to cross with
* XYZ intentionally YZX */
cross_vec[0] = axis[1];
cross_vec[1] = axis[2];
cross_vec[2] = axis[0];
/* X-axis */
cross_v3_v3v3(gmat[0], cross_vec, axis);
normalize_v3(gmat[0]);
axis_angle_to_quat(quat, axis, angle);
mul_qt_v3(quat, gmat[0]);
/* Y-axis */
axis_angle_to_quat(quat, axis, M_PI_2);
copy_v3_v3(gmat[1], gmat[0]);
mul_qt_v3(quat, gmat[1]);
/* Z-axis */
copy_v3_v3(gmat[2], axis);
normalize_m3(gmat);
}
static bool test_rotmode_euler(short rotmode)
{
return ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT) ? 0 : 1;
}
bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3])
{
float mat[3][3], tmat[3][3], obmat[3][3];
if (test_rotmode_euler(pchan->rotmode)) {
eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
}
else { /* quat */
return 0;
}
/* apply bone transformation */
mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
if (pchan->parent) {
float parent_mat[3][3];
copy_m3_m4(parent_mat,
(pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat :
pchan->parent->pose_mat);
mul_m3_m3m3(mat, parent_mat, tmat);
/* needed if object transformation isn't identity */
copy_m3_m4(obmat, ob->object_to_world);
mul_m3_m3m3(gmat, obmat, mat);
}
else {
/* needed if object transformation isn't identity */
copy_m3_m4(obmat, ob->object_to_world);
mul_m3_m3m3(gmat, obmat, tmat);
}
normalize_m3(gmat);
return true;
}
bool gimbal_axis_object(Object *ob, float gmat[3][3])
{
if (test_rotmode_euler(ob->rotmode)) {
eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
}
else { /* quat */
return 0;
}
if (ob->parent) {
float parent_mat[3][3];
copy_m3_m4(parent_mat, ob->parent->object_to_world);
normalize_m3(parent_mat);
mul_m3_m3m3(gmat, parent_mat, gmat);
}
return 1;
}
int ED_transform_calc_gizmo_stats(const bContext *C,
const TransformCalcParams *params,
TransformBounds *tbounds)
@ -1117,9 +999,7 @@ static void gizmo_get_idot(const RegionView3D *rv3d, float r_idot[3])
}
}
static void gizmo_prepare_mat(const bContext *C,
RegionView3D *rv3d,
const TransformBounds *tbounds)
void gizmo_prepare_mat(const bContext *C, RegionView3D *rv3d, const TransformBounds *tbounds)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@ -1197,13 +1077,13 @@ static void gizmo_line_range(const int twtype, const short axis_type, float *r_s
}
}
static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
ScrArea *area,
ARegion *region,
void (*type_fn)(wmGizmoGroupType *))
void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
ScrArea *area,
ARegion *region,
void (*type_fn)(wmGizmoGroupType *))
{
/* Subscribe to view properties */
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh{};
@ -2337,437 +2217,6 @@ void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Scale Cage Gizmo
* \{ */
struct XFormCageWidgetGroup {
wmGizmo *gizmo;
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_cage_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(
MEM_mallocN(sizeof(XFormCageWidgetGroup), __func__));
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true);
xgzgroup->gizmo = WM_gizmo_new_ptr(gzt_cage, gzgroup, nullptr);
wmGizmo *gz = xgzgroup->gizmo;
RNA_enum_set(
gz->ptr, "transform", ED_GIZMO_CAGE_XFORM_FLAG_SCALE | ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE);
gz->color[0] = 1;
gz->color_hi[0] = 1;
gzgroup->customdata = xgzgroup;
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
PointerRNA *ptr;
/* assign operator */
PropertyRNA *prop_release_confirm = nullptr;
PropertyRNA *prop_constraint_axis = nullptr;
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
for (int z = 0; z < 3; z++) {
const bool constraint[3] = {x != 1, y != 1, z != 1};
ptr = WM_gizmo_operator_set(gz, i, ot_resize, nullptr);
if (prop_release_confirm == nullptr) {
prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
}
RNA_property_boolean_set(ptr, prop_release_confirm, true);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
i++;
}
}
}
}
}
static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
Scene *scene = CTX_data_scene(C);
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
wmGizmo *gz = xgzgroup->gizmo;
TransformBounds tbounds;
const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, SCE_ORIENT_SCALE);
TransformCalcParams calc_params{};
calc_params.use_local_axis = true;
calc_params.orientation_index = orient_index + 1;
if ((ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0) ||
equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) {
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
if (tbounds.use_matrix_space) {
copy_m4_m4(gz->matrix_space, tbounds.matrix_space);
}
else {
unit_m4(gz->matrix_space);
}
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
float dims[3];
sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
RNA_float_set_array(gz->ptr, "dimensions", dims);
mul_v3_fl(dims, 0.5f);
copy_m4_m3(gz->matrix_offset, rv3d->tw_axis_matrix);
mid_v3_v3v3(gz->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
mul_m3_v3(rv3d->tw_axis_matrix, gz->matrix_offset[3]);
float matrix_offset_global[4][4];
mul_m4_m4m4(matrix_offset_global, gz->matrix_space, gz->matrix_offset);
PropertyRNA *prop_center_override = nullptr;
float center[3];
float center_global[3];
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
center[0] = float(1 - x) * dims[0];
for (int y = 0; y < 3; y++) {
center[1] = float(1 - y) * dims[1];
for (int z = 0; z < 3; z++) {
center[2] = float(1 - z) * dims[2];
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, i);
if (prop_center_override == nullptr) {
prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
}
mul_v3_m4v3(center_global, matrix_offset_global, center);
RNA_property_float_set_array(&gzop->ptr, prop_center_override, center_global);
i++;
}
}
}
}
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
}
static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_SCALE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_cage_refresh(C, gzgroup);
}
break;
}
}
}
}
void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_cage_poll;
gzgt->setup = WIDGETGROUP_xform_cage_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_cage_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform Shear Gizmo
* \{ */
struct XFormShearWidgetGroup {
wmGizmo *gizmo[3][2];
/** View aligned gizmos. */
wmGizmo *gizmo_view[4];
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_shear_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_shear_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(
MEM_mallocN(sizeof(XFormShearWidgetGroup), __func__));
const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
wmOperatorType *ot_shear = WM_operatortype_find("TRANSFORM_OT_shear", true);
float axis_color[3][3];
for (int i = 0; i < 3; i++) {
UI_GetThemeColor3fv(TH_AXIS_X + i, axis_color[i]);
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
gz->color[3] = 0.5f;
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo[i][j] = gz;
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
RNA_enum_set(gz->ptr, "draw_options", 0); /* No stem. */
copy_v3_fl(gz->color, 1.0f);
gz->color[3] = 0.5f;
WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo_view[i] = gz;
/* Unlike the other gizmos, this never changes so can be set on setup. */
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
RNA_enum_set(&gzop->ptr, "orient_type", V3D_ORIENT_VIEW);
RNA_enum_set(&gzop->ptr, "orient_axis", 2);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", ((i % 2) ? 0 : 1));
}
gzgroup->customdata = xgzgroup;
}
static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
TransformBounds tbounds;
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag(
scene, SCE_ORIENT_ROTATE);
const int orient_index = BKE_scene_orientation_slot_get_index(orient_slot);
TransformCalcParams calc_params{};
calc_params.use_local_axis = false;
calc_params.orientation_index = orient_index + 1;
if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
else {
gizmo_prepare_mat(C, rv3d, &tbounds);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
WM_gizmo_set_matrix_rotation_from_yz_axis(gz, rv3d->twmat[i_ortho_a], rv3d->twmat[i]);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
RNA_float_set_array(&gzop->ptr, "orient_matrix", &tbounds.axis[0][0]);
RNA_enum_set(&gzop->ptr, "orient_type", orient_slot->type);
RNA_enum_set(&gzop->ptr, "orient_axis", i_ortho_b);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", i_ortho_a);
mul_v3_fl(gz->matrix_basis[0], 0.5f);
mul_v3_fl(gz->matrix_basis[1], 6.0f);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
}
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(
gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
/* Shear is like rotate, use the rotate setting. */
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(
scene, SCE_ORIENT_ROTATE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_shear_refresh(C, gzgroup);
}
break;
}
}
}
for (int i = 0; i < 4; i++) {
const float outer_thin = 0.3f;
const float outer_offset = 1.0f / 0.3f;
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_matrix_rotation_from_yz_axis(
gz, rv3d->viewinv[(i + 1) % 2], rv3d->viewinv[i % 2]);
if (i >= 2) {
negate_v3(gz->matrix_basis[1]);
negate_v3(gz->matrix_basis[2]);
}
/* No need for depth with view aligned gizmos. */
mul_v3_fl(gz->matrix_basis[0], 0.0f);
mul_v3_fl(gz->matrix_basis[1], 20.0f + ((1.0f / outer_thin) * 1.8f));
mul_v3_fl(gz->matrix_basis[2], outer_thin);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
gz->matrix_offset[3][2] = outer_offset;
}
/* Basic ordering for drawing only. */
{
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
/* Since we have two pairs of each axis,
* bias the values so gizmos that are orthogonal to the view get priority.
* This means we never default to shearing along
* the view axis in the case of an overlap. */
float axis_order[3], axis_bias[3];
copy_v3_v3(axis_order, gz->matrix_basis[2]);
copy_v3_v3(axis_bias, gz->matrix_basis[1]);
if (dot_v3v3(axis_bias, rv3d->viewinv[2]) < 0.0f) {
negate_v3(axis_bias);
}
madd_v3_v3fl(axis_order, axis_bias, 0.01f);
gz->temp.f = dot_v3v3(rv3d->viewinv[2], axis_order);
}
BLI_listbase_sort(&gzgroup->gizmos, WM_gizmo_cmp_temp_fl_reverse);
}
}
void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_shear_poll;
gzgt->setup = WIDGETGROUP_xform_shear_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_shear_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_shear_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_shear_draw_prepare;
}
/** \} */
static wmGizmoGroup *gizmogroup_xform_find(TransInfo *t)
{
wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(t->region->gizmo_map);

View File

@ -0,0 +1,223 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edtransform
*
* \name 3D Transform Gizmo
*
* Used for 3D View
*/
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_scene.h"
#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "RNA_access.h"
/* local module include */
#include "transform.h"
#include "transform_gizmo.h"
/* -------------------------------------------------------------------- */
/** \name Scale Cage Gizmo
* \{ */
struct XFormCageWidgetGroup {
wmGizmo *gizmo;
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_cage_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(
MEM_mallocN(sizeof(XFormCageWidgetGroup), __func__));
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true);
xgzgroup->gizmo = WM_gizmo_new_ptr(gzt_cage, gzgroup, nullptr);
wmGizmo *gz = xgzgroup->gizmo;
RNA_enum_set(
gz->ptr, "transform", ED_GIZMO_CAGE_XFORM_FLAG_SCALE | ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE);
gz->color[0] = 1;
gz->color_hi[0] = 1;
gzgroup->customdata = xgzgroup;
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
PointerRNA *ptr;
/* assign operator */
PropertyRNA *prop_release_confirm = nullptr;
PropertyRNA *prop_constraint_axis = nullptr;
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
for (int z = 0; z < 3; z++) {
const bool constraint[3] = {x != 1, y != 1, z != 1};
ptr = WM_gizmo_operator_set(gz, i, ot_resize, nullptr);
if (prop_release_confirm == nullptr) {
prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
}
RNA_property_boolean_set(ptr, prop_release_confirm, true);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
i++;
}
}
}
}
}
static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
Scene *scene = CTX_data_scene(C);
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
wmGizmo *gz = xgzgroup->gizmo;
TransformBounds tbounds;
const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, SCE_ORIENT_SCALE);
TransformCalcParams calc_params{};
calc_params.use_local_axis = true;
calc_params.orientation_index = orient_index + 1;
if ((ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0) ||
equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) {
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
if (tbounds.use_matrix_space) {
copy_m4_m4(gz->matrix_space, tbounds.matrix_space);
}
else {
unit_m4(gz->matrix_space);
}
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
float dims[3];
sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
RNA_float_set_array(gz->ptr, "dimensions", dims);
mul_v3_fl(dims, 0.5f);
copy_m4_m3(gz->matrix_offset, rv3d->tw_axis_matrix);
mid_v3_v3v3(gz->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
mul_m3_v3(rv3d->tw_axis_matrix, gz->matrix_offset[3]);
float matrix_offset_global[4][4];
mul_m4_m4m4(matrix_offset_global, gz->matrix_space, gz->matrix_offset);
PropertyRNA *prop_center_override = nullptr;
float center[3];
float center_global[3];
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
center[0] = float(1 - x) * dims[0];
for (int y = 0; y < 3; y++) {
center[1] = float(1 - y) * dims[1];
for (int z = 0; z < 3; z++) {
center[2] = float(1 - z) * dims[2];
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, i);
if (prop_center_override == nullptr) {
prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
}
mul_v3_m4v3(center_global, matrix_offset_global, center);
RNA_property_float_set_array(&gzop->ptr, prop_center_override, center_global);
i++;
}
}
}
}
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
}
static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_SCALE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_cage_refresh(C, gzgroup);
}
break;
}
}
}
}
void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_cage_poll;
gzgt->setup = WIDGETGROUP_xform_cage_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_cage_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
}
/** \} */

View File

@ -0,0 +1,261 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edtransform
*
* \name 3D Transform Gizmo
*
* Used for 3D View
*/
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_scene.h"
#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "UI_resources.h"
#include "RNA_access.h"
/* local module include */
#include "transform.h"
#include "transform_gizmo.h"
/* -------------------------------------------------------------------- */
/** \name Transform Shear Gizmo
* \{ */
struct XFormShearWidgetGroup {
wmGizmo *gizmo[3][2];
/** View aligned gizmos. */
wmGizmo *gizmo_view[4];
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_shear_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_shear_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(
MEM_mallocN(sizeof(XFormShearWidgetGroup), __func__));
const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
wmOperatorType *ot_shear = WM_operatortype_find("TRANSFORM_OT_shear", true);
float axis_color[3][3];
for (int i = 0; i < 3; i++) {
UI_GetThemeColor3fv(TH_AXIS_X + i, axis_color[i]);
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
gz->color[3] = 0.5f;
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo[i][j] = gz;
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
RNA_enum_set(gz->ptr, "draw_options", 0); /* No stem. */
copy_v3_fl(gz->color, 1.0f);
gz->color[3] = 0.5f;
WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo_view[i] = gz;
/* Unlike the other gizmos, this never changes so can be set on setup. */
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
RNA_enum_set(&gzop->ptr, "orient_type", V3D_ORIENT_VIEW);
RNA_enum_set(&gzop->ptr, "orient_axis", 2);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", ((i % 2) ? 0 : 1));
}
gzgroup->customdata = xgzgroup;
}
static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
TransformBounds tbounds;
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag(
scene, SCE_ORIENT_ROTATE);
const int orient_index = BKE_scene_orientation_slot_get_index(orient_slot);
TransformCalcParams calc_params{};
calc_params.use_local_axis = false;
calc_params.orientation_index = orient_index + 1;
if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
else {
gizmo_prepare_mat(C, rv3d, &tbounds);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
WM_gizmo_set_matrix_rotation_from_yz_axis(gz, rv3d->twmat[i_ortho_a], rv3d->twmat[i]);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
RNA_float_set_array(&gzop->ptr, "orient_matrix", &tbounds.axis[0][0]);
RNA_enum_set(&gzop->ptr, "orient_type", orient_slot->type);
RNA_enum_set(&gzop->ptr, "orient_axis", i_ortho_b);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", i_ortho_a);
mul_v3_fl(gz->matrix_basis[0], 0.5f);
mul_v3_fl(gz->matrix_basis[1], 6.0f);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
}
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(
gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
/* Shear is like rotate, use the rotate setting. */
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(
scene, SCE_ORIENT_ROTATE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_shear_refresh(C, gzgroup);
}
break;
}
}
}
for (int i = 0; i < 4; i++) {
const float outer_thin = 0.3f;
const float outer_offset = 1.0f / 0.3f;
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_matrix_rotation_from_yz_axis(
gz, rv3d->viewinv[(i + 1) % 2], rv3d->viewinv[i % 2]);
if (i >= 2) {
negate_v3(gz->matrix_basis[1]);
negate_v3(gz->matrix_basis[2]);
}
/* No need for depth with view aligned gizmos. */
mul_v3_fl(gz->matrix_basis[0], 0.0f);
mul_v3_fl(gz->matrix_basis[1], 20.0f + ((1.0f / outer_thin) * 1.8f));
mul_v3_fl(gz->matrix_basis[2], outer_thin);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
gz->matrix_offset[3][2] = outer_offset;
}
/* Basic ordering for drawing only. */
{
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
/* Since we have two pairs of each axis,
* bias the values so gizmos that are orthogonal to the view get priority.
* This means we never default to shearing along
* the view axis in the case of an overlap. */
float axis_order[3], axis_bias[3];
copy_v3_v3(axis_order, gz->matrix_basis[2]);
copy_v3_v3(axis_bias, gz->matrix_basis[1]);
if (dot_v3v3(axis_bias, rv3d->viewinv[2]) < 0.0f) {
negate_v3(axis_bias);
}
madd_v3_v3fl(axis_order, axis_bias, 0.01f);
gz->temp.f = dot_v3v3(rv3d->viewinv[2], axis_order);
}
BLI_listbase_sort(&gzgroup->gizmos, WM_gizmo_cmp_temp_fl_reverse);
}
}
void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_shear_poll;
gzgt->setup = WIDGETGROUP_xform_shear_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_shear_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_shear_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_shear_draw_prepare;
}
/** \} */

View File

@ -29,6 +29,7 @@
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -230,6 +230,101 @@ static TransformOrientation *createMeshSpace(bContext *C,
return addMatrixSpace(C, mat, name, overwrite);
}
static bool test_rotmode_euler(short rotmode)
{
return ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT) ? 0 : 1;
}
/* could move into BLI_math however this is only useful for display/editing purposes */
static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
{
/* X/Y are arbitrary axes, most importantly Z is the axis of rotation. */
float cross_vec[3];
float quat[4];
/* this is an un-scientific method to get a vector to cross with
* XYZ intentionally YZX */
cross_vec[0] = axis[1];
cross_vec[1] = axis[2];
cross_vec[2] = axis[0];
/* X-axis */
cross_v3_v3v3(gmat[0], cross_vec, axis);
normalize_v3(gmat[0]);
axis_angle_to_quat(quat, axis, angle);
mul_qt_v3(quat, gmat[0]);
/* Y-axis */
axis_angle_to_quat(quat, axis, M_PI_2);
copy_v3_v3(gmat[1], gmat[0]);
mul_qt_v3(quat, gmat[1]);
/* Z-axis */
copy_v3_v3(gmat[2], axis);
normalize_m3(gmat);
}
bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3])
{
float mat[3][3], tmat[3][3], obmat[3][3];
if (test_rotmode_euler(pchan->rotmode)) {
eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
}
else { /* quat */
return 0;
}
/* apply bone transformation */
mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
if (pchan->parent) {
float parent_mat[3][3];
copy_m3_m4(parent_mat,
(pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat :
pchan->parent->pose_mat);
mul_m3_m3m3(mat, parent_mat, tmat);
/* needed if object transformation isn't identity */
copy_m3_m4(obmat, ob->object_to_world);
mul_m3_m3m3(gmat, obmat, mat);
}
else {
/* needed if object transformation isn't identity */
copy_m3_m4(obmat, ob->object_to_world);
mul_m3_m3m3(gmat, obmat, tmat);
}
normalize_m3(gmat);
return true;
}
bool gimbal_axis_object(Object *ob, float gmat[3][3])
{
if (test_rotmode_euler(ob->rotmode)) {
eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
}
else { /* quat */
return 0;
}
if (ob->parent) {
float parent_mat[3][3];
copy_m3_m4(parent_mat, ob->parent->object_to_world);
normalize_m3(parent_mat);
mul_m3_m3m3(gmat, parent_mat, gmat);
}
return 1;
}
bool transform_orientations_create_from_axis(float mat[3][3],
const float x[3],
const float y[3],

View File

@ -9,8 +9,13 @@
#include "RE_engine.h"
struct bPoseChannel;
struct Object;
struct TransInfo;
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
/**
* Sets the matrix of the specified space orientation.
* If the matrix cannot be obtained, an orientation different from the one informed is returned.

View File

@ -1430,7 +1430,7 @@ struct Nearest2dUserData {
const float (*vert_normals)[3];
const MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
const MLoop *loop;
const MLoopTri *looptri;
const MLoopTri *looptris;
};
};
@ -1481,7 +1481,7 @@ static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data
{
const MEdge *medge = data->edge;
const MLoop *mloop = data->loop;
const MLoopTri *lt = &data->looptri[index];
const MLoopTri *lt = &data->looptris[index];
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
const MEdge *ed = &medge[mloop[lt->tri[j]].e];
const uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
@ -1498,7 +1498,7 @@ static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data
static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
const MLoop *loop = data->loop;
const MLoopTri *looptri = &data->looptri[index];
const MLoopTri *looptri = &data->looptris[index];
r_v_index[0] = loop[looptri->tri[0]].v;
r_v_index[1] = loop[looptri->tri[1]].v;
@ -1719,7 +1719,7 @@ static void nearest2d_data_init_mesh(const Mesh *mesh,
r_nearest2d->vert_normals = BKE_mesh_vert_normals_ensure(mesh);
r_nearest2d->edge = mesh->edges().data();
r_nearest2d->loop = mesh->loops().data();
r_nearest2d->looptri = BKE_mesh_runtime_looptri_ensure(mesh);
r_nearest2d->looptris = mesh->looptris().data();
r_nearest2d->is_persp = is_persp;
r_nearest2d->use_backface_culling = use_backface_culling;

View File

@ -1474,11 +1474,11 @@ struct EdgeFeatData {
LineartData *ld;
Mesh *me;
Object *ob_eval; /* For evaluated materials. */
const MLoopTri *mlooptri;
const int *material_indices;
blender::Span<MEdge> edges;
blender::Span<MLoop> loops;
blender::Span<MPoly> polys;
blender::Span<MLoop> loops;
blender::Span<MLoopTri> looptris;
LineartTriangle *tri_array;
blender::VArray<bool> sharp_edges;
LineartVert *v_array;
@ -1514,7 +1514,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
const int *material_indices = e_feat_data->material_indices;
Object *ob_eval = e_feat_data->ob_eval;
LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
const MLoopTri *mlooptri = e_feat_data->mlooptri;
const blender::Span<MLoopTri> looptris = e_feat_data->looptris;
uint16_t edge_flag_result = 0;
@ -1532,10 +1532,10 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
FreestyleFace *ff1, *ff2;
int index = e_feat_data->freestyle_face_index;
if (index > -1) {
ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly];
ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[looptris[i / 3].poly];
}
if (edge_nabr[i].e > -1) {
ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly];
ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[looptris[edge_nabr[i].e / 3].poly];
}
else {
/* Handle mesh boundary cases: We want mesh boundaries to respect
@ -1648,8 +1648,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
if (ld->conf.use_crease) {
bool do_crease = true;
if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth &&
(e_feat_data->polys[mlooptri[f1].poly].flag & ME_SMOOTH) &&
(e_feat_data->polys[mlooptri[f2].poly].flag & ME_SMOOTH)) {
(e_feat_data->polys[looptris[f1].poly].flag & ME_SMOOTH) &&
(e_feat_data->polys[looptris[f2].poly].flag & ME_SMOOTH)) {
do_crease = false;
}
if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) {
@ -1657,8 +1657,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
}
}
int mat1 = material_indices ? material_indices[mlooptri[f1].poly] : 0;
int mat2 = material_indices ? material_indices[mlooptri[f2].poly] : 0;
int mat1 = material_indices ? material_indices[looptris[f1].poly] : 0;
int mat2 = material_indices ? material_indices[looptris[f2].poly] : 0;
if (mat1 != mat2) {
Material *m1 = BKE_object_material_get_eval(ob_eval, mat1 + 1);
@ -1683,7 +1683,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
int real_edges[3];
BKE_mesh_looptri_get_real_edges(
e_feat_data->edges.data(), e_feat_data->loops.data(), &mlooptri[i / 3], real_edges);
e_feat_data->edges.data(), e_feat_data->loops.data(), &looptris[i / 3], real_edges);
if (real_edges[i % 3] >= 0) {
if (ld->conf.use_crease && ld->conf.sharp_as_crease &&
@ -1789,7 +1789,7 @@ struct TriData {
LineartObjectInfo *ob_info;
blender::Span<blender::float3> positions;
blender::Span<MLoop> loops;
const MLoopTri *mlooptri;
blender::Span<MLoopTri> looptris;
const int *material_indices;
LineartVert *vert_arr;
LineartTriangle *tri_arr;
@ -1805,16 +1805,16 @@ static void lineart_load_tri_task(void *__restrict userdata,
LineartObjectInfo *ob_info = tri_task_data->ob_info;
const blender::Span<blender::float3> positions = tri_task_data->positions;
const blender::Span<MLoop> loops = tri_task_data->loops;
const MLoopTri *mlooptri = &tri_task_data->mlooptri[i];
const MLoopTri *looptri = &tri_task_data->looptris[i];
const int *material_indices = tri_task_data->material_indices;
LineartVert *vert_arr = tri_task_data->vert_arr;
LineartTriangle *tri = tri_task_data->tri_arr;
tri = (LineartTriangle *)(((uchar *)tri) + tri_task_data->lineart_triangle_size * i);
int v1 = loops[mlooptri->tri[0]].v;
int v2 = loops[mlooptri->tri[1]].v;
int v3 = loops[mlooptri->tri[2]].v;
int v1 = loops[looptri->tri[0]].v;
int v2 = loops[looptri->tri[1]].v;
int v3 = loops[looptri->tri[2]].v;
tri->v[0] = &vert_arr[v1];
tri->v[1] = &vert_arr[v2];
@ -1822,7 +1822,7 @@ static void lineart_load_tri_task(void *__restrict userdata,
/* Material mask bits and occlusion effectiveness assignment. */
Material *mat = BKE_object_material_get(
ob_info->original_ob_eval, material_indices ? material_indices[mlooptri->poly] + 1 : 1);
ob_info->original_ob_eval, material_indices ? material_indices[looptri->poly] + 1 : 1);
tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
mat->lineart.material_mask_bits :
0);
@ -1862,8 +1862,8 @@ static void lineart_load_tri_task(void *__restrict userdata,
struct EdgeNeighborData {
LineartEdgeNeighbor *edge_nabr;
LineartAdjacentEdge *adj_e;
const MLoopTri *mlooptri;
blender::Span<MLoop> loops;
blender::Span<MLoopTri> looptris;
};
static void lineart_edge_neighbor_init_task(void *__restrict userdata,
@ -1872,7 +1872,7 @@ static void lineart_edge_neighbor_init_task(void *__restrict userdata,
{
EdgeNeighborData *en_data = (EdgeNeighborData *)userdata;
LineartAdjacentEdge *adj_e = &en_data->adj_e[i];
const MLoopTri *looptri = &en_data->mlooptri[i / 3];
const MLoopTri *looptri = &en_data->looptris[i / 3];
LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i];
const blender::Span<MLoop> loops = en_data->loops;
@ -1924,8 +1924,8 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge
EdgeNeighborData en_data;
en_data.adj_e = adj_e;
en_data.edge_nabr = edge_nabr;
en_data.mlooptri = BKE_mesh_runtime_looptri_ensure(me);
en_data.loops = me->loops();
en_data.looptris = me->looptris();
BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings);
@ -1954,8 +1954,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
}
/* Triangulate. */
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
const int tot_tri = BKE_mesh_runtime_looptri_len(me);
const blender::Span<MLoopTri> looptris = me->looptris();
const int *material_indices = (const int *)CustomData_get_layer_named(
&me->pdata, CD_PROP_INT32, "material_index");
@ -1978,8 +1977,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
* chains containing the same edge. */
LineartVert *la_v_arr = static_cast<LineartVert *>(
lineart_mem_acquire_thread(&la_data->render_data_pool, sizeof(LineartVert) * me->totvert));
LineartTriangle *la_tri_arr = static_cast<LineartTriangle *>(
lineart_mem_acquire_thread(&la_data->render_data_pool, tot_tri * la_data->sizeof_triangle));
LineartTriangle *la_tri_arr = static_cast<LineartTriangle *>(lineart_mem_acquire_thread(
&la_data->render_data_pool, looptris.size() * la_data->sizeof_triangle));
Object *orig_ob = ob_info->original_ob;
@ -2025,7 +2024,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
int usage = ob_info->usage;
elem_link_node->element_count = tot_tri;
elem_link_node->element_count = looptris.size();
elem_link_node->object_ref = orig_ob;
elem_link_node->flags = eLineArtElementNodeFlag(
elem_link_node->flags |
@ -2033,7 +2032,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
/* Note this memory is not from pool, will be deleted after culling. */
LineartTriangleAdjacent *tri_adj = static_cast<LineartTriangleAdjacent *>(
MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri, "LineartTriangleAdjacent"));
MEM_callocN(sizeof(LineartTriangleAdjacent) * looptris.size(), "LineartTriangleAdjacent"));
/* Link is minimal so we use pool anyway. */
BLI_spin_lock(&la_data->lock_task);
lineart_list_append_pointer_pool_thread(
@ -2065,7 +2064,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
TriData tri_data;
tri_data.ob_info = ob_info;
tri_data.positions = me->vert_positions();
tri_data.mlooptri = mlooptri;
tri_data.looptris = looptris;
tri_data.loops = me->loops();
tri_data.material_indices = material_indices;
tri_data.vert_arr = la_v_arr;
@ -2073,9 +2072,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
tri_data.lineart_triangle_size = la_data->sizeof_triangle;
tri_data.tri_adj = tri_adj;
uint32_t total_edges = tot_tri * 3;
uint32_t total_edges = looptris.size() * 3;
BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
BLI_task_parallel_range(0, looptris.size(), &tri_data, lineart_load_tri_task, &tri_settings);
/* Check for contour lines in the mesh.
* IE check if the triangle edges lies in area where the triangles go from front facing to back
@ -2098,11 +2097,11 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
edge_feat_data.ld = la_data;
edge_feat_data.me = me;
edge_feat_data.ob_eval = ob_info->original_ob_eval;
edge_feat_data.mlooptri = mlooptri;
edge_feat_data.material_indices = material_indices;
edge_feat_data.edges = me->edges();
edge_feat_data.polys = me->polys();
edge_feat_data.loops = me->loops();
edge_feat_data.looptris = looptris;
edge_feat_data.sharp_edges = sharp_edges;
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
edge_feat_data.tri_array = la_tri_arr;

View File

@ -66,7 +66,7 @@ static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
input->mloop = (DualConLoop)mesh->loops().data();
input->loop_stride = sizeof(MLoop);
input->looptri = (DualConTri)BKE_mesh_runtime_looptri_ensure(mesh);
input->looptri = (DualConTri)mesh->looptris().data();
input->tri_stride = sizeof(MLoopTri);
input->tottri = BKE_mesh_runtime_looptri_len(mesh);

View File

@ -68,10 +68,10 @@ struct SDefBindCalcData {
const SDefAdjacencyArray *vert_edges;
const SDefEdgePolys *edge_polys;
SDefVert *bind_verts;
const MLoopTri *looptri;
blender::Span<MEdge> edges;
blender::Span<MPoly> polys;
blender::Span<MLoop> loops;
blender::Span<MLoopTri> looptris;
/** Coordinates to bind to, transformed into local space (compatible with `vertexCos`). */
float (*targetCos)[3];
@ -396,7 +396,7 @@ BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3
BLI_bvhtree_find_nearest(
data->treeData->tree, t_point, &nearest, data->treeData->nearest_callback, data->treeData);
poly = &data->polys[data->looptri[nearest.index].poly];
poly = &data->polys[data->looptris[nearest.index].poly];
loop = &data->loops[poly->loopstart];
for (int i = 0; i < poly->totloop; i++, loop++) {
@ -1266,7 +1266,7 @@ static bool surfacedeformBind(Object *ob,
data.polys = polys;
data.edges = edges;
data.loops = loops;
data.looptri = BKE_mesh_runtime_looptri_ensure(target);
data.looptris = target->looptris();
data.targetCos = static_cast<float(*)[3]>(
MEM_malloc_arrayN(target_verts_num, sizeof(float[3]), "SDefTargetBindVertArray"));
data.bind_verts = smd_orig->verts;

View File

@ -597,7 +597,6 @@ bool RE_bake_pixels_populate_from_objects(Mesh *me_low,
tris_high[i] = mesh_calc_tri_tessface(highpoly[i].me, false, nullptr);
me_highpoly[i] = highpoly[i].me;
BKE_mesh_runtime_looptri_ensure(me_highpoly[i]);
if (BKE_mesh_runtime_looptri_len(me_highpoly[i]) != 0) {
/* Create a BVH-tree for each `highpoly` object. */

View File

@ -501,6 +501,14 @@ void WM_check(bContext *C)
/* Case: no open windows at all, for old file reads. */
wm_window_ghostwindows_ensure(wm);
/* It possible for a pre-250 file to have window but none set active. See #104726. */
if (wm->winactive == NULL) {
wm->winactive = (wmWindow *)wm->windows.first;
if (wm->winactive != NULL) {
wm->winactive->active = true;
}
}
}
/* Case: file-read. */