Mesh: Rename MLoopTri variable names, and functions

Make the naming consistent with the recent change from "loop" to
"corner". Avoid the need for a special type for these triangles by
conveying the semantics in the naming instead.

- `looptris` -> `corner_tris`
- `lt` -> `tri` (or `corner_tri` when there is less context)
- `looptri_index` -> `tri_index` (or `corner_tri_index`)
- `lt->tri[0]` -> `tri[0]`
- `Span<MLoopTri>` -> `Span<int3>`
- `looptri_faces` -> `tri_faces` (or `corner_tri_faces`)

If we followed the naming pattern of "corner_verts" and "edge_verts"
exactly, we'd probably use "tri_corners" instead. But that sounds much
worse and less intuitive to me.

I've found that by using standard vector types for this sort of data,
the commonalities with other areas become much clearer, and code ends
up being naturally more data oriented. Besides that, the consistency
is nice, and we get to mostly remove use of `DNA_meshdata_types.h`.

Pull Request: https://projects.blender.org/blender/blender/pulls/116238
This commit is contained in:
Hans Goudey 2023-12-19 14:57:49 +01:00 committed by Hans Goudey
parent 3f33b06dde
commit 7c69c8827b
115 changed files with 1993 additions and 1996 deletions

@ -269,11 +269,11 @@ static void attr_create_generic(Scene *scene,
const bool need_motion,
const float motion_scale)
{
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<blender::int3> corner_tris;
blender::Span<int> tri_faces;
if (!subdivision) {
looptris = b_mesh.looptris();
looptri_faces = b_mesh.looptri_faces();
corner_tris = b_mesh.corner_tris();
tri_faces = b_mesh.corner_tri_faces();
}
const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
@ -325,14 +325,14 @@ static void attr_create_generic(Scene *scene,
}
}
else {
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
data[i * 3 + 0] = make_uchar4(
src[lt.tri[0]][0], src[lt.tri[0]][1], src[lt.tri[0]][2], src[lt.tri[0]][3]);
src[tri[0]][0], src[tri[0]][1], src[tri[0]][2], src[tri[0]][3]);
data[i * 3 + 1] = make_uchar4(
src[lt.tri[1]][0], src[lt.tri[1]][1], src[lt.tri[1]][2], src[lt.tri[1]][3]);
src[tri[1]][0], src[tri[1]][1], src[tri[1]][2], src[tri[1]][3]);
data[i * 3 + 2] = make_uchar4(
src[lt.tri[2]][0], src[lt.tri[2]][1], src[lt.tri[2]][2], src[lt.tri[2]][3]);
src[tri[2]][0], src[tri[2]][1], src[tri[2]][2], src[tri[2]][3]);
}
}
return true;
@ -375,11 +375,11 @@ static void attr_create_generic(Scene *scene,
}
}
else {
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
data[i * 3 + 0] = Converter::convert(src[lt.tri[0]]);
data[i * 3 + 1] = Converter::convert(src[lt.tri[1]]);
data[i * 3 + 2] = Converter::convert(src[lt.tri[2]]);
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
data[i * 3 + 0] = Converter::convert(src[tri[0]]);
data[i * 3 + 1] = Converter::convert(src[tri[1]]);
data[i * 3 + 2] = Converter::convert(src[tri[2]]);
}
}
break;
@ -397,8 +397,8 @@ static void attr_create_generic(Scene *scene,
}
}
else {
for (const int i : looptris.index_range()) {
data[i] = Converter::convert(src[looptri_faces[i]]);
for (const int i : corner_tris.index_range()) {
data[i] = Converter::convert(src[tri_faces[i]]);
}
}
break;
@ -435,7 +435,7 @@ static void attr_create_uv_map(Scene *scene,
const ::Mesh &b_mesh,
const set<ustring> &blender_uv_names)
{
const blender::Span<MLoopTri> looptris = b_mesh.looptris();
const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
const ustring render_name(CustomData_get_render_layer_name(&b_mesh.loop_data, CD_PROP_FLOAT2));
if (!blender_uv_names.empty()) {
@ -468,11 +468,11 @@ static void attr_create_uv_map(Scene *scene,
const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
uv_name.c_str(), ATTR_DOMAIN_CORNER);
float2 *fdata = uv_attr->data_float2();
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
fdata[i * 3 + 0] = make_float2(b_uv_map[lt.tri[0]][0], b_uv_map[lt.tri[0]][1]);
fdata[i * 3 + 1] = make_float2(b_uv_map[lt.tri[1]][0], b_uv_map[lt.tri[1]][1]);
fdata[i * 3 + 2] = make_float2(b_uv_map[lt.tri[2]][0], b_uv_map[lt.tri[2]][1]);
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
fdata[i * 3 + 0] = make_float2(b_uv_map[tri[0]][0], b_uv_map[tri[0]][1]);
fdata[i * 3 + 1] = make_float2(b_uv_map[tri[1]][0], b_uv_map[tri[1]][1]);
fdata[i * 3 + 2] = make_float2(b_uv_map[tri[2]][0], b_uv_map[tri[2]][1]);
}
}
@ -782,10 +782,10 @@ static void attr_create_random_per_island(Scene *scene,
float *data = attribute->data_float();
if (!subdivision) {
const blender::Span<MLoopTri> looptris = b_mesh.looptris();
if (!looptris.is_empty()) {
for (const int i : looptris.index_range()) {
const int vert = corner_verts[looptris[i].tri[0]];
const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
if (!corner_tris.is_empty()) {
for (const int i : corner_tris.index_range()) {
const int vert = corner_verts[corner_tris[i][0]];
data[i] = hash_uint_to_float(vertices_sets.find(vert));
}
}
@ -817,7 +817,7 @@ static void create_mesh(Scene *scene,
const blender::Span<int> corner_verts = b_mesh.corner_verts();
const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
const blender::bke::MeshNormalDomain normals_domain = b_mesh.normals_domain();
int numfaces = (!subdivision) ? b_mesh.looptris().size() : faces.size();
int numfaces = (!subdivision) ? b_mesh.corner_tris().size() : faces.size();
bool use_loop_normals = normals_domain == blender::bke::MeshNormalDomain::Corner &&
(mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
@ -913,18 +913,18 @@ static void create_mesh(Scene *scene,
bool *smooth = mesh->get_smooth().data();
int *shader = mesh->get_shader().data();
const blender::Span<MLoopTri> looptris = b_mesh.looptris();
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
triangles[i * 3 + 0] = corner_verts[lt.tri[0]];
triangles[i * 3 + 1] = corner_verts[lt.tri[1]];
triangles[i * 3 + 2] = corner_verts[lt.tri[2]];
const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
triangles[i * 3 + 0] = corner_verts[tri[0]];
triangles[i * 3 + 1] = corner_verts[tri[1]];
triangles[i * 3 + 2] = corner_verts[tri[2]];
}
if (!material_indices.is_empty()) {
const blender::Span<int> looptri_faces = b_mesh.looptri_faces();
for (const int i : looptris.index_range()) {
shader[i] = clamp_material_index(material_indices[looptri_faces[i]]);
const blender::Span<int> tri_faces = b_mesh.corner_tri_faces();
for (const int i : corner_tris.index_range()) {
shader[i] = clamp_material_index(material_indices[tri_faces[i]]);
}
}
else {
@ -932,9 +932,9 @@ static void create_mesh(Scene *scene,
}
if (!sharp_faces.is_empty() && !(use_loop_normals && !corner_normals.is_empty())) {
const blender::Span<int> looptri_faces = b_mesh.looptri_faces();
for (const int i : looptris.index_range()) {
smooth[i] = !sharp_faces[looptri_faces[i]];
const blender::Span<int> tri_faces = b_mesh.corner_tri_faces();
for (const int i : corner_tris.index_range()) {
smooth[i] = !sharp_faces[tri_faces[i]];
}
}
else {
@ -943,10 +943,10 @@ static void create_mesh(Scene *scene,
}
if (use_loop_normals && !corner_normals.is_empty()) {
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
for (int i = 0; i < 3; i++) {
const int corner = lt.tri[i];
const int corner = tri[i];
const int vert = corner_verts[corner];
const float *normal = corner_normals[corner];
N[vert] = make_float3(normal[0], normal[1], normal[2]);

@ -26,7 +26,7 @@ typedef struct DualConInput {
int co_stride;
int totco;
DualConTri looptris;
DualConTri corner_tris;
int tri_stride;
int tottri;

@ -22,7 +22,7 @@ static void veccopy(float dst[3], const float src[3])
}
#define GET_TRI(_mesh, _n) \
(*(DualConTri)(((char *)(_mesh)->looptris) + ((_n) * (_mesh)->tri_stride)))
(*(DualConTri)(((char *)(_mesh)->corner_tris) + ((_n) * (_mesh)->tri_stride)))
#define GET_CO(_mesh, _n) (*(DualConCo)(((char *)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))

@ -21,7 +21,6 @@ struct BVHCache;
struct BVHTree;
struct MFace;
struct Mesh;
struct MLoopTri;
struct PointCloud;
struct vec2i;
@ -53,7 +52,7 @@ struct BVHTreeFromMesh {
blender::Span<blender::float3> vert_positions;
blender::Span<blender::int2> edges;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<blender::int3> corner_tris;
const MFace *face;
@ -65,8 +64,8 @@ enum BVHCacheType {
BVHTREE_FROM_VERTS,
BVHTREE_FROM_EDGES,
BVHTREE_FROM_FACES,
BVHTREE_FROM_LOOPTRIS,
BVHTREE_FROM_LOOPTRIS_NO_HIDDEN,
BVHTREE_FROM_CORNER_TRIS,
BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN,
BVHTREE_FROM_LOOSEVERTS,
BVHTREE_FROM_LOOSEEDGES,
@ -150,7 +149,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
int tree_type,
int axis);
BVHTree *bvhtree_from_editmesh_looptris(
BVHTree *bvhtree_from_editmesh_corner_tris(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis);
/**
@ -158,8 +157,8 @@ BVHTree *bvhtree_from_editmesh_looptris(
*/
BVHTree *bvhtree_from_editmesh_looptris_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
blender::BitSpan looptris_mask,
int looptris_num_active,
blender::BitSpan corner_tris_mask,
int corner_tris_num_active,
float epsilon,
int tree_type,
int axis);
@ -167,15 +166,15 @@ BVHTree *bvhtree_from_editmesh_looptris_ex(BVHTreeFromEditMesh *data,
/**
* Builds a BVH-tree where nodes are the triangle faces (#MLoopTri) of the given mesh.
*/
BVHTree *bvhtree_from_mesh_looptris_ex(BVHTreeFromMesh *data,
blender::Span<blender::float3> vert_positions,
blender::Span<int> corner_verts,
blender::Span<MLoopTri> looptris,
blender::BitSpan looptris_mask,
int looptris_num_active,
float epsilon,
int tree_type,
int axis);
BVHTree *bvhtree_from_mesh_corner_tris_ex(BVHTreeFromMesh *data,
blender::Span<blender::float3> vert_positions,
blender::Span<int> corner_verts,
blender::Span<blender::int3> corner_tris,
blender::BitSpan corner_tris_mask,
int corner_tris_num_active,
float epsilon,
int tree_type,
int axis);
/**
* Builds or queries a BVH-cache for the cache BVH-tree of the request type.

@ -12,7 +12,6 @@
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
struct BMesh;
struct BMeshCreateParams;
@ -27,7 +26,6 @@ struct ListBase;
struct MDeformVert;
struct MDisps;
struct MFace;
struct MLoopTri;
struct Main;
struct MemArena;
struct Mesh;
@ -410,8 +408,8 @@ bool BKE_mesh_center_of_volume(const struct Mesh *mesh, float r_cent[3]);
*/
void BKE_mesh_calc_volume(const float (*vert_positions)[3],
int mverts_num,
const struct MLoopTri *looptris,
int looptris_num,
const blender::int3 *corner_tris,
int corner_tris_num,
const int *corner_verts,
float *r_volume,
float r_center[3]);

@ -29,33 +29,31 @@ namespace mesh {
/** Calculate the up direction for the face, depending on its winding direction. */
float3 face_normal_calc(Span<float3> vert_positions, Span<int> face_verts);
void corner_tris_calc(Span<float3> vert_positions,
OffsetIndices<int> faces,
Span<int> corner_verts,
MutableSpan<int3> corner_tris);
/**
* Calculate tessellation into #MLoopTri which exist only for this purpose.
*/
void looptris_calc(Span<float3> vert_positions,
OffsetIndices<int> faces,
Span<int> corner_verts,
MutableSpan<MLoopTri> looptris);
/**
* A version of #looptris_calc which takes pre-calculated face normals
* A version of #corner_tris_calc which takes pre-calculated face normals
* (used to avoid having to calculate the face normal for NGON tessellation).
*
* \note Only use this function if normals have already been calculated, there is no need
* to calculate normals just to use this function.
*/
void looptris_calc_with_normals(Span<float3> vert_positions,
OffsetIndices<int> faces,
Span<int> corner_verts,
Span<float3> face_normals,
MutableSpan<MLoopTri> looptris);
void corner_tris_calc_with_normals(Span<float3> vert_positions,
OffsetIndices<int> faces,
Span<int> corner_verts,
Span<float3> face_normals,
MutableSpan<int3> corner_tris);
void looptris_calc_face_indices(OffsetIndices<int> faces, MutableSpan<int> looptri_faces);
void corner_tris_calc_face_indices(OffsetIndices<int> faces, MutableSpan<int> tri_faces);
/** Return the triangle's three edge indices they are real edges, otherwise -1. */
int3 looptri_get_real_edges(Span<int2> edges,
Span<int> corner_verts,
Span<int> corner_edges,
const MLoopTri &lt);
int3 corner_tri_get_real_edges(Span<int2> edges,
Span<int> corner_verts,
Span<int> corner_edges,
const int3 &corner_tri);
/** Calculate the average position of the vertices in the face. */
float3 face_center_calc(Span<float3> vert_positions, Span<int> face_verts);

@ -13,7 +13,6 @@
struct BMLoop;
struct MemArena;
struct MLoopTri;
/* UvVertMap */
#define STD_UV_CONNECT_LIMIT 0.0001f
@ -113,16 +112,16 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
/**
* Generates a map where the key is the edge and the value
* is a list of looptris that use that edge.
* is a list of corner_tris that use that edge.
* The lists are allocated from one memory pool.
*/
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
int totvert,
const MLoopTri *looptris,
int totlooptris,
const int *corner_verts,
int totloop);
void BKE_mesh_vert_corner_tri_map_create(MeshElemMap **r_map,
int **r_mem,
int totvert,
const blender::int3 *corner_tris,
int tottris,
const int *corner_verts,
int totloop);
/**
* This function creates a map so the source-data (vert/edge/loop/face)
* can loop over the destination data (using the destination arrays origindex).
@ -140,14 +139,14 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
void BKE_mesh_origindex_map_create(
MeshElemMap **r_map, int **r_mem, int totsource, const int *final_origindex, int totfinal);
/**
* A version of #BKE_mesh_origindex_map_create that takes a #MLoopTri array.
* Making a face -> #MLoopTri map.
* A version of #BKE_mesh_origindex_map_create that takes a corner tri array.
* Making a face -> corner tri map.
*/
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
blender::OffsetIndices<int> faces,
const int *looptri_faces,
int looptris_num);
void BKE_mesh_origindex_map_create_corner_tri(MeshElemMap **r_map,
int **r_mem,
blender::OffsetIndices<int> faces,
const int *corner_tri_faces,
int corner_tris_num);
/* islands */
@ -263,7 +262,7 @@ int *BKE_mesh_calc_smoothgroups(int edges_num,
int *r_totgroup,
bool use_bitflags);
/* Use on #MLoopTri vertex values. */
/* Use on corner_tri vertex values. */
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v) \
((CHECK_TYPE_ANY( \
_tri, unsigned int *, int *, int[3], const unsigned int *, const int *, const int[3]), \

@ -14,14 +14,13 @@
struct CustomData_MeshMasks;
struct Depsgraph;
struct KeyBlock;
struct MLoopTri;
struct MVertTri;
struct Mesh;
struct Object;
struct Scene;
/** Return the number of derived triangles (looptris). */
int BKE_mesh_runtime_looptris_len(const Mesh *mesh);
/** Return the number of derived triangles (corner_tris). */
int BKE_mesh_runtime_corner_tris_len(const Mesh *mesh);
void BKE_mesh_runtime_ensure_edit_data(Mesh *mesh);
@ -48,10 +47,10 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh);
/**
* Convert triangles encoded as face corner indices to triangles encoded as vertex indices.
*/
void BKE_mesh_runtime_verttris_from_looptris(MVertTri *r_verttri,
const int *corner_verts,
const MLoopTri *looptris,
int looptris_num);
void BKE_mesh_runtime_verttris_from_corner_tris(MVertTri *r_verttri,
const int *corner_verts,
const blender::int3 *corner_tris,
int corner_tris_num);
/* NOTE: the functions below are defined in DerivedMesh.cc, and are intended to be moved
* to a more suitable location when that file is removed.

@ -15,8 +15,6 @@
#include "FN_field.hh"
#include "FN_multi_function.hh"
#include "DNA_meshdata_types.h"
#include "BKE_attribute.h"
#include "BKE_geometry_fields.hh"
@ -30,37 +28,37 @@ class RandomNumberGenerator;
namespace blender::bke::mesh_surface_sample {
void sample_point_attribute(Span<int> corner_verts,
Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<int3> corner_tris,
Span<int> tri_indices,
Span<float3> bary_coords,
const GVArray &src,
const IndexMask &mask,
GMutableSpan dst);
void sample_point_normals(Span<int> corner_verts,
Span<MLoopTri> looptris,
Span<int> looptri_indices,
Span<int3> corner_tris,
Span<int> tri_indices,
Span<float3> bary_coords,
Span<float3> src,
IndexMask mask,
MutableSpan<float3> dst);
void sample_corner_attribute(Span<MLoopTri> looptris,
Span<int> looptri_indices,
void sample_corner_attribute(Span<int3> corner_tris,
Span<int> tri_indices,
Span<float3> bary_coords,
const GVArray &src,
const IndexMask &mask,
GMutableSpan dst);
void sample_corner_normals(Span<MLoopTri> looptris,
Span<int> looptri_indices,
void sample_corner_normals(Span<int3> corner_tris,
Span<int> tri_indices,
Span<float3> bary_coords,
Span<float3> src,
const IndexMask &mask,
MutableSpan<float3> dst);
void sample_face_attribute(Span<int> looptri_faces,
Span<int> looptri_indices,
void sample_face_attribute(Span<int> corner_tri_faces,
Span<int> tri_indices,
const GVArray &src,
const IndexMask &mask,
GMutableSpan dst);
@ -76,12 +74,12 @@ void sample_face_attribute(Span<int> looptri_faces,
*/
int sample_surface_points_spherical(RandomNumberGenerator &rng,
const Mesh &mesh,
Span<int> looptri_indices_to_sample,
Span<int> tris_to_sample,
const float3 &sample_pos,
float sample_radius,
float approximate_density,
Vector<float3> &r_bary_coords,
Vector<int> &r_looptri_indices,
Vector<int> &r_tri_indices,
Vector<float3> &r_positions);
/**
@ -109,34 +107,34 @@ int sample_surface_points_projected(
int tries_num,
int max_points,
Vector<float3> &r_bary_coords,
Vector<int> &r_looptri_indices,
Vector<int> &r_tri_indices,
Vector<float3> &r_positions);
float3 compute_bary_coord_in_triangle(Span<float3> vert_positions,
Span<int> corner_verts,
const MLoopTri &lt,
const int3 &corner_tri,
const float3 &position);
template<typename T>
inline T sample_corner_attribute_with_bary_coords(const float3 &bary_weights,
const MLoopTri &lt,
const int3 &corner_tri,
const Span<T> corner_attribute)
{
return attribute_math::mix3(bary_weights,
corner_attribute[lt.tri[0]],
corner_attribute[lt.tri[1]],
corner_attribute[lt.tri[2]]);
corner_attribute[corner_tri[0]],
corner_attribute[corner_tri[1]],
corner_attribute[corner_tri[2]]);
}
template<typename T>
inline T sample_corner_attribute_with_bary_coords(const float3 &bary_weights,
const MLoopTri &lt,
const int3 &corner_tri,
const VArray<T> &corner_attribute)
{
return attribute_math::mix3(bary_weights,
corner_attribute[lt.tri[0]],
corner_attribute[lt.tri[1]],
corner_attribute[lt.tri[2]]);
corner_attribute[corner_tri[0]],
corner_attribute[corner_tri[1]],
corner_attribute[corner_tri[2]]);
}
/**
@ -146,7 +144,7 @@ class BaryWeightFromPositionFn : public mf::MultiFunction {
GeometrySet source_;
Span<float3> vert_positions_;
Span<int> corner_verts_;
Span<MLoopTri> looptris_;
Span<int3> corner_tris_;
public:
BaryWeightFromPositionFn(GeometrySet geometry);
@ -161,7 +159,7 @@ class CornerBaryWeightFromPositionFn : public mf::MultiFunction {
GeometrySet source_;
Span<float3> vert_positions_;
Span<int> corner_verts_;
Span<MLoopTri> looptris_;
Span<int3> corner_tris_;
public:
CornerBaryWeightFromPositionFn(GeometrySet geometry);
@ -176,7 +174,7 @@ class BaryWeightSampleFn : public mf::MultiFunction {
mf::Signature signature_;
GeometrySet source_;
Span<MLoopTri> looptris_;
Span<int3> corner_tris_;
std::optional<bke::MeshFieldContext> source_context_;
std::unique_ptr<fn::FieldEvaluator> source_evaluator_;
const GVArray *source_data_;

@ -48,9 +48,9 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
blender::OffsetIndices<int> faces,
const int *corner_verts,
const MLoopTri *looptris,
const int *looptri_faces,
uint looptris_len,
const blender::int3 *corner_tris,
const int *corner_tri_faces,
uint corner_tris_len,
const blender::Span<bool> sharp_faces,
CustomData *loopdata,

@ -20,11 +20,9 @@
#include "BLI_vector.hh"
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
struct BVHCache;
struct Mesh;
struct MLoopTri;
struct ShrinkwrapBoundaryData;
struct SubdivCCG;
struct SubsurfRuntimeData;
@ -125,10 +123,10 @@ struct MeshRuntime {
*/
void *batch_cache = nullptr;
/** Cache for derived triangulation of the mesh, accessed with #Mesh::looptris(). */
SharedCache<Array<MLoopTri>> looptris_cache;
/** Cache for triangle to original face index map, accessed with #Mesh::looptri_faces(). */
SharedCache<Array<int>> looptri_faces_cache;
/** Cache for derived triangulation of the mesh, accessed with #Mesh::corner_tris(). */
SharedCache<Array<int3>> corner_tris_cache;
/** Cache for triangle to original face index map, accessed with #Mesh::corner_tri_faces(). */
SharedCache<Array<int>> corner_tri_faces_cache;
/** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
BVHCache *bvh_cache = nullptr;

@ -16,7 +16,6 @@ struct DerivedMesh;
struct MDisps;
struct Mesh;
struct ModifierData;
struct MLoopTri;
struct MultiresModifierData;
struct Object;
struct Scene;

@ -52,7 +52,6 @@ struct ImagePool;
struct ImageUser;
struct KeyBlock;
struct ListBase;
struct MLoopTri;
struct Main;
struct Mesh;
struct MDeformVert;

@ -11,7 +11,6 @@
#include "BLI_vector.hh"
#include "DNA_image_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_image.h"
#include "BKE_image_wrappers.hh"

@ -49,8 +49,8 @@ struct ShrinkwrapBoundaryVertData {
struct ShrinkwrapBoundaryData {
/* True if the edge belongs to exactly one face. */
blender::BitVector<> edge_is_boundary;
/* True if the looptri has any boundary edges. */
blender::BitVector<> looptri_has_boundary;
/* True if the triangle has any boundary edges. */
blender::BitVector<> tri_has_boundary;
/* Mapping from vertex index to boundary vertex index, or -1.
* Used for compact storage of data about boundary vertices. */
@ -173,7 +173,7 @@ void BKE_shrinkwrap_find_nearest_surface(ShrinkwrapTreeData *tree,
*/
void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
const SpaceTransform *transform,
int looptri_idx,
int tri_idx,
const float hit_co[3],
const float hit_no[3],
float r_no[3]);

@ -17,7 +17,6 @@
#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
#include "BLI_index_range.hh"

@ -13,7 +13,6 @@
#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
#include "BLI_array_utils.hh"

@ -36,6 +36,7 @@ using blender::BitSpan;
using blender::BitVector;
using blender::float3;
using blender::IndexRange;
using blender::int3;
using blender::Span;
using blender::VArray;
@ -269,17 +270,17 @@ static void mesh_faces_nearest_point(void *userdata,
} while (t2);
}
/* copy of function above */
static void mesh_looptris_nearest_point(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
static void mesh_corner_tris_nearest_point(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const MLoopTri *lt = &data->looptris[index];
const int3 &tri = data->corner_tris[index];
const float *vtri_co[3] = {
data->vert_positions[data->corner_verts[lt->tri[0]]],
data->vert_positions[data->corner_verts[lt->tri[1]]],
data->vert_positions[data->corner_verts[lt->tri[2]]],
data->vert_positions[data->corner_verts[tri[0]]],
data->vert_positions[data->corner_verts[tri[1]]],
data->vert_positions[data->corner_verts[tri[2]]],
};
float nearest_tmp[3], dist_sq;
@ -294,10 +295,10 @@ static void mesh_looptris_nearest_point(void *userdata,
}
}
/* Copy of function above (warning, should de-duplicate with `editmesh_bvh.cc`). */
static void editmesh_looptris_nearest_point(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
static void editmesh_corner_tris_nearest_point(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
{
BMEditMesh *em = static_cast<BMEditMesh *>(userdata);
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
@ -366,18 +367,18 @@ static void mesh_faces_spherecast(void *userdata,
} while (t2);
}
/* copy of function above */
static void mesh_looptris_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
static void mesh_corner_tris_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const Span<float3> positions = data->vert_positions;
const MLoopTri *lt = &data->looptris[index];
const int3 &tri = data->corner_tris[index];
const float *vtri_co[3] = {
positions[data->corner_verts[lt->tri[0]]],
positions[data->corner_verts[lt->tri[1]]],
positions[data->corner_verts[lt->tri[2]]],
positions[data->corner_verts[tri[0]]],
positions[data->corner_verts[tri[1]]],
positions[data->corner_verts[tri[2]]],
};
float dist;
@ -397,10 +398,10 @@ static void mesh_looptris_spherecast(void *userdata,
}
}
/* Copy of function above (warning, should de-duplicate with `editmesh_bvh.cc`). */
static void editmesh_looptris_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
static void editmesh_corner_tris_spherecast(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
BMEditMesh *em = static_cast<BMEditMesh *>(userdata);
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
@ -577,7 +578,7 @@ static void bvhtree_from_mesh_setup_data(BVHTree *tree,
const Span<float3> positions,
const Span<blender::int2> edges,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int3> corner_tris,
const MFace *face,
BVHTreeFromMesh *r_data)
{
@ -589,7 +590,7 @@ static void bvhtree_from_mesh_setup_data(BVHTree *tree,
r_data->edges = edges;
r_data->face = face;
r_data->corner_verts = corner_verts;
r_data->looptris = looptris;
r_data->corner_tris = corner_tris;
switch (bvh_cache_type) {
case BVHTREE_FROM_VERTS:
@ -609,10 +610,10 @@ static void bvhtree_from_mesh_setup_data(BVHTree *tree,
r_data->nearest_callback = mesh_faces_nearest_point;
r_data->raycast_callback = mesh_faces_spherecast;
break;
case BVHTREE_FROM_LOOPTRIS:
case BVHTREE_FROM_LOOPTRIS_NO_HIDDEN:
r_data->nearest_callback = mesh_looptris_nearest_point;
r_data->raycast_callback = mesh_looptris_spherecast;
case BVHTREE_FROM_CORNER_TRIS:
case BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN:
r_data->nearest_callback = mesh_corner_tris_nearest_point;
r_data->raycast_callback = mesh_corner_tris_spherecast;
break;
case BVHTREE_FROM_EM_LOOSEVERTS:
case BVHTREE_FROM_EM_EDGES:
@ -641,8 +642,8 @@ static void bvhtree_from_editmesh_setup_data(BVHTree *tree,
r_data->raycast_callback = nullptr; /* TODO */
break;
case BVHTREE_FROM_EM_LOOPTRIS:
r_data->nearest_callback = editmesh_looptris_nearest_point;
r_data->raycast_callback = editmesh_looptris_spherecast;
r_data->nearest_callback = editmesh_corner_tris_nearest_point;
r_data->raycast_callback = editmesh_corner_tris_spherecast;
break;
case BVHTREE_FROM_VERTS:
@ -650,8 +651,8 @@ static void bvhtree_from_editmesh_setup_data(BVHTree *tree,
case BVHTREE_FROM_EDGES:
case BVHTREE_FROM_LOOSEEDGES:
case BVHTREE_FROM_FACES:
case BVHTREE_FROM_LOOPTRIS:
case BVHTREE_FROM_LOOPTRIS_NO_HIDDEN:
case BVHTREE_FROM_CORNER_TRIS:
case BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN:
case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
@ -940,32 +941,33 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
/** \} */
/* -------------------------------------------------------------------- */
/** \name LoopTri Face Builder
/** \name corner_tri Face Builder
* \{ */
static BVHTree *bvhtree_from_editmesh_looptris_create_tree(float epsilon,
int tree_type,
int axis,
BMEditMesh *em,
const BitSpan looptris_mask,
int looptris_num_active)
static BVHTree *bvhtree_from_editmesh_corner_tris_create_tree(float epsilon,
int tree_type,
int axis,
BMEditMesh *em,
const BitSpan corner_tris_mask,
int corner_tris_num_active)
{
const int looptris_num = em->tottri;
const int corner_tris_num = em->tottri;
BVHTree *tree = bvhtree_new_common(epsilon, tree_type, axis, looptris_num, looptris_num_active);
BVHTree *tree = bvhtree_new_common(
epsilon, tree_type, axis, corner_tris_num, corner_tris_num_active);
if (!tree) {
return nullptr;
}
const BMLoop *(*looptris)[3] = (const BMLoop *(*)[3])em->looptris;
const BMLoop *(*corner_tris)[3] = (const BMLoop *(*)[3])em->looptris;
/* Insert BMesh-tessellation triangles into the BVH-tree, unless they are hidden
* and/or selected. Even if the faces themselves are not selected for the snapped
* transform, having a vertex selected means the face (and thus it's tessellated
* triangles) will be moving and will not be a good snap targets. */
for (int i = 0; i < looptris_num; i++) {
const BMLoop **ltri = looptris[i];
bool insert = !looptris_mask.is_empty() ? looptris_mask[i] : true;
for (int i = 0; i < corner_tris_num; i++) {
const BMLoop **ltri = corner_tris[i];
bool insert = !corner_tris_mask.is_empty() ? corner_tris_mask[i] : true;
if (insert) {
/* No reason found to block hit-testing the triangle for snap, so insert it now. */
@ -977,61 +979,61 @@ static BVHTree *bvhtree_from_editmesh_looptris_create_tree(float epsilon,
BLI_bvhtree_insert(tree, i, co[0], 3);
}
}
BLI_assert(BLI_bvhtree_get_len(tree) == looptris_num_active);
BLI_assert(BLI_bvhtree_get_len(tree) == corner_tris_num_active);
return tree;
}
static BVHTree *bvhtree_from_mesh_looptris_create_tree(float epsilon,
int tree_type,
int axis,
const Span<float3> positions,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const BitSpan looptris_mask,
int looptris_num_active)
static BVHTree *bvhtree_from_mesh_corner_tris_create_tree(float epsilon,
int tree_type,
int axis,
const Span<float3> positions,
const Span<int> corner_verts,
const Span<int3> corner_tris,
const BitSpan corner_tris_mask,
int corner_tris_num_active)
{
if (positions.is_empty()) {
return nullptr;
}
BVHTree *tree = bvhtree_new_common(
epsilon, tree_type, axis, looptris.size(), looptris_num_active);
epsilon, tree_type, axis, corner_tris.size(), corner_tris_num_active);
if (!tree) {
return nullptr;
}
for (const int i : looptris.index_range()) {
for (const int i : corner_tris.index_range()) {
float co[3][3];
if (!looptris_mask.is_empty() && !looptris_mask[i]) {
if (!corner_tris_mask.is_empty() && !corner_tris_mask[i]) {
continue;
}
copy_v3_v3(co[0], positions[corner_verts[looptris[i].tri[0]]]);
copy_v3_v3(co[1], positions[corner_verts[looptris[i].tri[1]]]);
copy_v3_v3(co[2], positions[corner_verts[looptris[i].tri[2]]]);
copy_v3_v3(co[0], positions[corner_verts[corner_tris[i][0]]]);
copy_v3_v3(co[1], positions[corner_verts[corner_tris[i][1]]]);
copy_v3_v3(co[2], positions[corner_verts[corner_tris[i][2]]]);
BLI_bvhtree_insert(tree, i, co[0], 3);
}
BLI_assert(BLI_bvhtree_get_len(tree) == looptris_num_active);
BLI_assert(BLI_bvhtree_get_len(tree) == corner_tris_num_active);
return tree;
}
BVHTree *bvhtree_from_editmesh_looptris_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BitSpan looptris_mask,
int looptris_num_active,
const BitSpan corner_tris_mask,
int corner_tris_num_active,
float epsilon,
int tree_type,
int axis)
{
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
BVHTree *tree = bvhtree_from_editmesh_looptris_create_tree(
epsilon, tree_type, axis, em, looptris_mask, looptris_num_active);
BVHTree *tree = bvhtree_from_editmesh_corner_tris_create_tree(
epsilon, tree_type, axis, em, corner_tris_mask, corner_tris_num_active);
bvhtree_balance(tree, false);
@ -1041,72 +1043,78 @@ BVHTree *bvhtree_from_editmesh_looptris_ex(BVHTreeFromEditMesh *data,
return tree;
}
BVHTree *bvhtree_from_editmesh_looptris(
BVHTree *bvhtree_from_editmesh_corner_tris(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_looptris_ex(data, em, {}, -1, epsilon, tree_type, axis);
}
BVHTree *bvhtree_from_mesh_looptris_ex(BVHTreeFromMesh *data,
const Span<float3> vert_positions,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const BitSpan looptris_mask,
int looptris_num_active,
float epsilon,
int tree_type,
int axis)
BVHTree *bvhtree_from_mesh_corner_tris_ex(BVHTreeFromMesh *data,
const Span<float3> vert_positions,
const Span<int> corner_verts,
const Span<int3> corner_tris,
const BitSpan corner_tris_mask,
int corner_tris_num_active,
float epsilon,
int tree_type,
int axis)
{
BVHTree *tree = bvhtree_from_mesh_looptris_create_tree(epsilon,
tree_type,
axis,
vert_positions,
corner_verts,
looptris,
looptris_mask,
looptris_num_active);
BVHTree *tree = bvhtree_from_mesh_corner_tris_create_tree(epsilon,
tree_type,
axis,
vert_positions,
corner_verts,
corner_tris,
corner_tris_mask,
corner_tris_num_active);
bvhtree_balance(tree, false);
if (data) {
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_setup_data(
tree, BVHTREE_FROM_LOOPTRIS, vert_positions, {}, corner_verts, looptris, nullptr, data);
bvhtree_from_mesh_setup_data(tree,
BVHTREE_FROM_CORNER_TRIS,
vert_positions,
{},
corner_verts,
corner_tris,
nullptr,
data);
}
return tree;
}
static BitVector<> looptris_no_hidden_map_get(const blender::OffsetIndices<int> faces,
const VArray<bool> &hide_poly,
const int looptris_len,
int *r_looptris_active_len)
static BitVector<> corner_tris_no_hidden_map_get(const blender::OffsetIndices<int> faces,
const VArray<bool> &hide_poly,
const int corner_tris_len,
int *r_corner_tris_active_len)
{
if (hide_poly.is_single() && !hide_poly.get_internal_single()) {
return {};
}
BitVector<> looptris_mask(looptris_len);
BitVector<> corner_tris_mask(corner_tris_len);
int looptris_no_hidden_len = 0;
int looptri_index = 0;
int corner_tris_no_hidden_len = 0;
int tri_index = 0;
for (const int64_t i : faces.index_range()) {
const int triangles_num = blender::bke::mesh::face_triangles_num(faces[i].size());
if (hide_poly[i]) {
looptri_index += triangles_num;
tri_index += triangles_num;
}
else {
for (const int i : IndexRange(triangles_num)) {
UNUSED_VARS(i);
looptris_mask[looptri_index].set();
looptri_index++;
looptris_no_hidden_len++;
corner_tris_mask[tri_index].set();
tri_index++;
corner_tris_no_hidden_len++;
}
}
}
*r_looptris_active_len = looptris_no_hidden_len;
*r_corner_tris_active_len = corner_tris_no_hidden_len;
return looptris_mask;
return corner_tris_mask;
}
BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
@ -1116,9 +1124,9 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
{
BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime->bvh_cache;
Span<MLoopTri> looptris;
if (ELEM(bvh_cache_type, BVHTREE_FROM_LOOPTRIS, BVHTREE_FROM_LOOPTRIS_NO_HIDDEN)) {
looptris = mesh->looptris();
Span<int3> corner_tris;
if (ELEM(bvh_cache_type, BVHTREE_FROM_CORNER_TRIS, BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN)) {
corner_tris = mesh->corner_tris();
}
const Span<float3> positions = mesh->vert_positions();
@ -1131,7 +1139,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
positions,
edges,
corner_verts,
looptris,
corner_tris,
(const MFace *)CustomData_get_layer(&mesh->fdata_legacy, CD_MFACE),
data);
@ -1183,21 +1191,21 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
-1);
break;
}
case BVHTREE_FROM_LOOPTRIS_NO_HIDDEN: {
case BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN: {
blender::bke::AttributeAccessor attributes = mesh->attributes();
int mask_bits_act_len = -1;
const BitVector<> mask = looptris_no_hidden_map_get(
const BitVector<> mask = corner_tris_no_hidden_map_get(
mesh->faces(),
*attributes.lookup_or_default(".hide_poly", ATTR_DOMAIN_FACE, false),
looptris.size(),
corner_tris.size(),
&mask_bits_act_len);
data->tree = bvhtree_from_mesh_looptris_create_tree(
0.0f, tree_type, 6, positions, corner_verts, looptris, mask, mask_bits_act_len);
data->tree = bvhtree_from_mesh_corner_tris_create_tree(
0.0f, tree_type, 6, positions, corner_verts, corner_tris, mask, mask_bits_act_len);
break;
}
case BVHTREE_FROM_LOOPTRIS: {
data->tree = bvhtree_from_mesh_looptris_create_tree(
0.0f, tree_type, 6, positions, corner_verts, looptris, {}, -1);
case BVHTREE_FROM_CORNER_TRIS: {
data->tree = bvhtree_from_mesh_corner_tris_create_tree(
0.0f, tree_type, 6, positions, corner_verts, corner_tris, {}, -1);
break;
}
case BVHTREE_FROM_EM_LOOSEVERTS:
@ -1282,13 +1290,13 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
data->tree = bvhtree_from_editmesh_edges_create_tree(0.0f, tree_type, 6, em, {}, -1);
break;
case BVHTREE_FROM_EM_LOOPTRIS:
data->tree = bvhtree_from_editmesh_looptris_create_tree(0.0f, tree_type, 6, em, {}, -1);
data->tree = bvhtree_from_editmesh_corner_tris_create_tree(0.0f, tree_type, 6, em, {}, -1);
break;
case BVHTREE_FROM_VERTS:
case BVHTREE_FROM_EDGES:
case BVHTREE_FROM_FACES:
case BVHTREE_FROM_LOOPTRIS:
case BVHTREE_FROM_LOOPTRIS_NO_HIDDEN:
case BVHTREE_FROM_CORNER_TRIS:
case BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN:
case BVHTREE_FROM_LOOSEVERTS:
case BVHTREE_FROM_LOOSEEDGES:
case BVHTREE_MAX_ITEM:

@ -28,7 +28,6 @@
#include "DNA_curve_types.h" /* for Curve */
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "MEM_guardedalloc.h"

@ -827,7 +827,7 @@ static bool cloth_from_object(
static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mesh)
{
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
const uint mvert_num = mesh->totvert;
/* Allocate our vertices. */
@ -841,21 +841,21 @@ static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mes
/* save face information */
if (clmd->hairdata == nullptr) {
clmd->clothObject->primitive_num = looptris.size();
clmd->clothObject->primitive_num = corner_tris.size();
}
else {
clmd->clothObject->primitive_num = mesh->totedge;
}
clmd->clothObject->tri = static_cast<MVertTri *>(
MEM_malloc_arrayN(looptris.size(), sizeof(MVertTri), __func__));
MEM_malloc_arrayN(corner_tris.size(), sizeof(MVertTri), __func__));
if (clmd->clothObject->tri == nullptr) {
cloth_free_modifier(clmd);
BKE_modifier_set_error(ob, &(clmd->modifier), "Out of memory on allocating triangles");
return;
}
BKE_mesh_runtime_verttris_from_looptris(
clmd->clothObject->tri, corner_verts.data(), looptris.data(), looptris.size());
BKE_mesh_runtime_verttris_from_corner_tris(
clmd->clothObject->tri, corner_verts.data(), corner_tris.data(), corner_tris.size());
clmd->clothObject->edges = mesh->edges().data();
@ -1417,7 +1417,6 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
int vert_idx = -1;
const int *corner_verts = treedata->corner_verts.data();
const MLoopTri *lt = nullptr;
if (rayhit.index != -1 && rayhit.dist <= max_length) {
if (check_normal && dot_v3v3(rayhit.no, no) < 0.0f) {
@ -1426,10 +1425,10 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
}
float min_len = FLT_MAX;
lt = &treedata->looptris[rayhit.index];
const blender::int3 &tri = treedata->corner_tris[rayhit.index];
for (int i = 0; i < 3; i++) {
int tmp_vert_idx = corner_verts[lt->tri[i]];
int tmp_vert_idx = corner_verts[tri[i]];
if (tmp_vert_idx == v_idx) {
/* We managed to hit ourselves. */
return false;
@ -1513,7 +1512,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
}
Set<OrderedEdge> existing_vert_pairs;
BKE_bvhtree_from_mesh_get(&treedata, tmp_mesh ? tmp_mesh : mesh, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&treedata, tmp_mesh ? tmp_mesh : mesh, BVHTREE_FROM_CORNER_TRIS, 2);
rng = BLI_rng_new_srandom(0);
const blender::Span<blender::float3> vert_normals = tmp_mesh ? tmp_mesh->vert_normals() :

@ -5077,7 +5077,7 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co
normalize_v3(ray_direction);
BVHTreeFromMesh tree_data = NULL_BVHTreeFromMesh;
BKE_bvhtree_from_mesh_get(&tree_data, depth_mesh, BVHTREE_FROM_LOOPTRIS, 4);
BKE_bvhtree_from_mesh_get(&tree_data, depth_mesh, BVHTREE_FROM_CORNER_TRIS, 4);
BVHTreeRayHit hit;
hit.dist = BVH_RAYCAST_DIST_MAX;

@ -9,7 +9,6 @@
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"

@ -75,6 +75,8 @@
#include "CLG_log.h"
using blender::int3;
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
//# pragma GCC diagnostic ignored "-Wdouble-promotion"
@ -1498,7 +1500,7 @@ struct DynamicPaintSetInitColorData {
blender::Span<int> corner_verts;
const float (*mloopuv)[2];
blender::Span<MLoopTri> looptris;
blender::Span<int3> corner_tris;
const MLoopCol *mloopcol;
ImagePool *pool;
};
@ -1513,7 +1515,7 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdat
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
const blender::Span<int> corner_verts = data->corner_verts;
const blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const float(*mloopuv)[2] = data->mloopuv;
ImagePool *pool = data->pool;
Tex *tex = data->surface->init_texture;
@ -1522,11 +1524,11 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdat
for (int j = 3; j--;) {
TexResult texres = {0};
const int vert = corner_verts[looptris[i].tri[j]];
const int vert = corner_verts[corner_tris[i][j]];
/* remap to [-1.0, 1.0] */
uv[0] = mloopuv[looptris[i].tri[j]][0] * 2.0f - 1.0f;
uv[1] = mloopuv[looptris[i].tri[j]][1] * 2.0f - 1.0f;
uv[0] = mloopuv[corner_tris[i][j]][0] * 2.0f - 1.0f;
uv[1] = mloopuv[corner_tris[i][j]][1] * 2.0f - 1.0f;
multitex_ext_safe(tex, uv, &texres, pool, true, false);
@ -1546,7 +1548,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 blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const float(*mloopuv)[2] = data->mloopuv;
Tex *tex = data->surface->init_texture;
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
@ -1559,7 +1561,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[looptris[f_data->uv_p[i].tri_index].tri[j]]);
copy_v2_v2(&uv[j * 3], mloopuv[corner_tris[f_data->uv_p[i].tri_index][j]]);
}
/* interpolate final uv pos */
@ -1583,7 +1585,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 blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const MLoopCol *mloopcol = data->mloopcol;
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
@ -1594,7 +1596,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[looptris[tri_idx].tri[j]].r);
rgba_uchar_to_float(colors[j], (const uchar *)&mloopcol[corner_tris[tri_idx][j]].r);
}
/* interpolate final color */
@ -1629,7 +1631,7 @@ static void dynamicPaint_setInitialColor(const Scene * /*scene*/, DynamicPaintSu
Tex *tex = surface->init_texture;
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<int3> corner_tris = mesh->corner_tris();
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@ -1647,7 +1649,7 @@ static void dynamicPaint_setInitialColor(const Scene * /*scene*/, DynamicPaintSu
return;
}
/* For vertex surface loop through `looptris` and find UV color
/* For vertex surface loop through `corner_tris` and find UV color
* that provides highest alpha. */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
ImagePool *pool = BKE_image_pool_new();
@ -1655,21 +1657,21 @@ static void dynamicPaint_setInitialColor(const Scene * /*scene*/, DynamicPaintSu
DynamicPaintSetInitColorData data{};
data.surface = surface;
data.corner_verts = corner_verts;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.mloopuv = mloopuv;
data.pool = pool;
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (looptris.size() > 1000);
settings.use_threading = (corner_tris.size() > 1000);
BLI_task_parallel_range(
0, looptris.size(), &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
0, corner_tris.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.looptris = looptris;
data.corner_tris = corner_tris;
data.mloopuv = mloopuv;
TaskParallelSettings settings;
@ -1696,7 +1698,7 @@ static void dynamicPaint_setInitialColor(const Scene * /*scene*/, DynamicPaintSu
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<int3> corner_tris = mesh->corner_tris();
const MLoopCol *col = static_cast<const MLoopCol *>(CustomData_get_layer_named(
&mesh->loop_data, CD_PROP_BYTE_COLOR, surface->init_layername));
if (!col) {
@ -1705,7 +1707,7 @@ static void dynamicPaint_setInitialColor(const Scene * /*scene*/, DynamicPaintSu
DynamicPaintSetInitColorData data{};
data.surface = surface;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.mloopcol = col;
TaskParallelSettings settings;
@ -2200,7 +2202,7 @@ struct DynamicPaintCreateUVSurfaceData {
PaintUVPoint *tempPoints;
Vec3f *tempWeights;
blender::Span<MLoopTri> looptris;
blender::Span<int3> corner_tris;
const float (*mloopuv)[2];
blender::Span<int> corner_verts;
@ -2219,7 +2221,7 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
PaintUVPoint *tempPoints = data->tempPoints;
Vec3f *tempWeights = data->tempWeights;
const blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const float(*mloopuv)[2] = data->mloopuv;
const blender::Span<int> corner_verts = data->corner_verts;
@ -2265,7 +2267,7 @@ 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 (const int i : looptris.index_range()) {
for (const int i : corner_tris.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]))
@ -2273,9 +2275,9 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
continue;
}
const float *uv1 = mloopuv[looptris[i].tri[0]];
const float *uv2 = mloopuv[looptris[i].tri[1]];
const float *uv3 = mloopuv[looptris[i].tri[2]];
const float *uv1 = mloopuv[corner_tris[i][0]];
const float *uv2 = mloopuv[corner_tris[i][1]];
const float *uv3 = mloopuv[corner_tris[i][2]];
/* If point is inside the face */
if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
@ -2293,9 +2295,9 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata,
tPoint->tri_index = i;
/* save vertex indexes */
tPoint->v1 = corner_verts[looptris[i].tri[0]];
tPoint->v2 = corner_verts[looptris[i].tri[1]];
tPoint->v3 = corner_verts[looptris[i].tri[2]];
tPoint->v1 = corner_verts[corner_tris[i][0]];
tPoint->v2 = corner_verts[corner_tris[i][1]];
tPoint->v3 = corner_verts[corner_tris[i][2]];
sample = 5; /* make sure we exit sample loop as well */
break;
@ -2316,7 +2318,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
PaintUVPoint *tempPoints = data->tempPoints;
Vec3f *tempWeights = data->tempWeights;
const blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const float(*mloopuv)[2] = data->mloopuv;
const blender::Span<int> corner_verts = data->corner_verts;
@ -2358,9 +2360,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[looptris[i].tri[0]];
const float *uv2 = mloopuv[looptris[i].tri[1]];
const float *uv3 = mloopuv[looptris[i].tri[2]];
const float *uv1 = mloopuv[corner_tris[i][0]];
const float *uv2 = mloopuv[corner_tris[i][1]];
const float *uv3 = mloopuv[corner_tris[i][2]];
/* tri index */
/* There is a low possibility of actually having a neighbor point which tri is
@ -2383,9 +2385,9 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
}
/* save vertex indexes */
tPoint->v1 = corner_verts[looptris[i].tri[0]];
tPoint->v2 = corner_verts[looptris[i].tri[1]];
tPoint->v3 = corner_verts[looptris[i].tri[2]];
tPoint->v1 = corner_verts[corner_tris[i][0]];
tPoint->v2 = corner_verts[corner_tris[i][1]];
tPoint->v3 = corner_verts[corner_tris[i][2]];
break;
}
@ -2403,10 +2405,10 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdat
#undef JITTER_SAMPLES
static float dist_squared_to_looptris_uv_edges(const blender::Span<MLoopTri> looptris,
const float (*mloopuv)[2],
int tri_index,
const float point[2])
static float dist_squared_to_corner_tris_uv_edges(const blender::Span<int3> corner_tris,
const float (*mloopuv)[2],
int tri_index,
const float point[2])
{
BLI_assert(tri_index >= 0);
@ -2415,8 +2417,8 @@ static float dist_squared_to_looptris_uv_edges(const blender::Span<MLoopTri> loo
for (int i = 0; i < 3; i++) {
const float dist_squared = dist_squared_to_line_segment_v2(
point,
mloopuv[looptris[tri_index].tri[(i + 0)]],
mloopuv[looptris[tri_index].tri[(i + 1) % 3]]);
mloopuv[corner_tris[tri_index][(i + 0)]],
mloopuv[corner_tris[tri_index][(i + 1) % 3]]);
if (dist_squared < min_distance) {
min_distance = dist_squared;
@ -2427,7 +2429,7 @@ static float dist_squared_to_looptris_uv_edges(const blender::Span<MLoopTri> loo
}
struct DynamicPaintFindIslandBorderData {
const MeshElemMap *vert_to_looptri_map;
const MeshElemMap *vert_to_tri_map;
int w, h, px, py;
int best_index;
@ -2448,7 +2450,7 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
* n_index : lookup direction index (use neighX, neighY to get final index)
*/
static int dynamic_paint_find_neighbor_pixel(const DynamicPaintCreateUVSurfaceData *data,
const MeshElemMap *vert_to_looptri_map,
const MeshElemMap *vert_to_tri_map,
const int w,
const int h,
const int px,
@ -2499,7 +2501,7 @@ static int dynamic_paint_find_neighbor_pixel(const DynamicPaintCreateUVSurfaceDa
*/
{
DynamicPaintFindIslandBorderData bdata{};
bdata.vert_to_looptri_map = vert_to_looptri_map;
bdata.vert_to_tri_map = vert_to_tri_map;
bdata.w = w;
bdata.h = h;
bdata.px = px;
@ -2527,10 +2529,10 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
int depth)
{
const blender::Span<int> corner_verts = data->corner_verts;
const blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const float(*mloopuv)[2] = data->mloopuv;
const uint *loop_idx = looptris[tri_index].tri;
const int3 loop_idx = corner_tris[tri_index];
/* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
@ -2567,9 +2569,9 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
const int vert0 = corner_verts[loop_idx[(edge_idx + 0)]];
const int vert1 = corner_verts[loop_idx[(edge_idx + 1) % 3]];
/* Use a pre-computed vert-to-looptri mapping,
* speeds up things a lot compared to looping over all looptris. */
const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
/* Use a pre-computed vert-to-corner_tri mapping,
* speeds up things a lot compared to looping over all corner_tris. */
const MeshElemMap *map = &bdata->vert_to_tri_map[vert0];
bool found_other = false;
int target_tri = -1;
@ -2578,33 +2580,33 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
float ouv0[2], ouv1[2];
for (int i = 0; i < map->count && !found_other; i++) {
const int lt_index = map->indices[i];
const int tri_other_index = map->indices[i];
if (lt_index == tri_index) {
if (tri_other_index == tri_index) {
continue;
}
const uint *other_loop_idx = looptris[lt_index].tri;
const int3 other_tri = corner_tris[tri_other_index];
/* Check edges for match, looping in the same order as the outer loop. */
for (int j = 0; j < 3; j++) {
const int overt0 = corner_verts[other_loop_idx[(j + 0)]];
const int overt1 = corner_verts[other_loop_idx[(j + 1) % 3]];
const int overt0 = corner_verts[other_tri[(j + 0)]];
const int overt1 = corner_verts[other_tri[(j + 1) % 3]];
/* Allow for swapped vertex order */
if (overt0 == vert0 && overt1 == vert1) {
found_other = true;
copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]]);
copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]]);
copy_v2_v2(ouv0, mloopuv[other_tri[(j + 0)]]);
copy_v2_v2(ouv1, mloopuv[other_tri[(j + 1) % 3]]);
}
else if (overt0 == vert1 && overt1 == vert0) {
found_other = true;
copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]]);
copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]]);
copy_v2_v2(ouv1, mloopuv[other_tri[(j + 0)]]);
copy_v2_v2(ouv0, mloopuv[other_tri[(j + 1) % 3]]);
}
if (found_other) {
target_tri = lt_index;
target_tri = tri_other_index;
target_edge = j;
break;
}
@ -2687,8 +2689,9 @@ 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_looptris_uv_edges(looptris, mloopuv, final_tri_index, final_pt) >
threshold) {
if (dist_squared_to_corner_tris_uv_edges(corner_tris, mloopuv, final_tri_index, final_pt) >
threshold)
{
continue;
}
}
@ -2841,7 +2844,7 @@ int dynamicPaint_createUVSurface(Scene *scene,
}
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<int3> corner_tris = mesh->corner_tris();
/* get uv map */
if (CustomData_has_layer(&mesh->loop_data, CD_PROP_FLOAT2)) {
@ -2866,7 +2869,7 @@ 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, int(looptris.size()));
&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, int(corner_tris.size()));
/* Init data struct */
if (surface->data) {
@ -2901,7 +2904,7 @@ int dynamicPaint_createUVSurface(Scene *scene,
*/
if (!error) {
faceBB = static_cast<Bounds2D *>(
MEM_malloc_arrayN(looptris.size(), sizeof(*faceBB), "MPCanvasFaceBB"));
MEM_malloc_arrayN(corner_tris.size(), sizeof(*faceBB), "MPCanvasFaceBB"));
if (!faceBB) {
error = true;
}
@ -2911,12 +2914,12 @@ int dynamicPaint_createUVSurface(Scene *scene,
*do_update = true;
if (!error) {
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 (const int i : corner_tris.index_range()) {
copy_v2_v2(faceBB[i].min, mloopuv[corner_tris[i][0]]);
copy_v2_v2(faceBB[i].max, mloopuv[corner_tris[i][0]]);
for (int j = 1; j < 3; j++) {
minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[looptris[i].tri[j]]);
minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[corner_tris[i][j]]);
}
}
@ -2928,7 +2931,7 @@ int dynamicPaint_createUVSurface(Scene *scene,
data.surface = surface;
data.tempPoints = tempPoints;
data.tempWeights = tempWeights;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.mloopuv = mloopuv;
data.corner_verts = corner_verts;
data.faceBB = faceBB;
@ -2936,7 +2939,7 @@ int dynamicPaint_createUVSurface(Scene *scene,
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (h > 64 || looptris.size() > 1000);
settings.use_threading = (h > 64 || corner_tris.size() > 1000);
BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, &settings);
}
@ -2980,16 +2983,16 @@ int dynamicPaint_createUVSurface(Scene *scene,
PaintAdjData *ed = sData->adj_data;
int n_pos = 0;
MeshElemMap *vert_to_looptri_map;
int *vert_to_looptri_map_mem;
MeshElemMap *vert_to_tri_map;
int *vert_to_tri_map_mem;
BKE_mesh_vert_looptri_map_create(&vert_to_looptri_map,
&vert_to_looptri_map_mem,
mesh->totvert,
looptris.data(),
looptris.size(),
corner_verts.data(),
mesh->totloop);
BKE_mesh_vert_corner_tri_map_create(&vert_to_tri_map,
&vert_to_tri_map_mem,
mesh->totvert,
corner_tris.data(),
corner_tris.size(),
corner_verts.data(),
mesh->totloop);
int total_border = 0;
@ -3010,7 +3013,7 @@ int dynamicPaint_createUVSurface(Scene *scene,
/* Try to find a neighboring pixel in defined direction.
* If not found, -1 is returned */
const int n_target = dynamic_paint_find_neighbor_pixel(
&data, vert_to_looptri_map, w, h, tx, ty, i);
&data, vert_to_tri_map, w, h, tx, ty, i);
if (n_target >= 0 && n_target != index) {
if (!dynamicPaint_pointHasNeighbor(
@ -3028,8 +3031,8 @@ int dynamicPaint_createUVSurface(Scene *scene,
}
}
MEM_freeN(vert_to_looptri_map);
MEM_freeN(vert_to_looptri_map_mem);
MEM_freeN(vert_to_tri_map);
MEM_freeN(vert_to_tri_map_mem);
/* Make neighbors symmetric */
if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
@ -3437,7 +3440,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,
/***************************** Ray / Nearest Point Utils ******************************/
/* A modified callback to bvh tree ray-cast.
* The tree must have been built using bvhtree_from_mesh_looptri.
* The tree must have been built using bvhtree_from_mesh_corner_tri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit coordinates or normal.
@ -3449,15 +3452,15 @@ static void mesh_tris_spherecast_dp(void *userdata,
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const blender::Span<blender::float3> positions = data->vert_positions;
const MLoopTri *looptris = data->looptris.data();
const int3 *corner_tris = data->corner_tris.data();
const int *corner_verts = data->corner_verts.data();
const float *t0, *t1, *t2;
float dist;
t0 = positions[corner_verts[looptris[index].tri[0]]];
t1 = positions[corner_verts[looptris[index].tri[1]]];
t2 = positions[corner_verts[looptris[index].tri[2]]];
t0 = positions[corner_verts[corner_tris[index][0]]];
t1 = positions[corner_verts[corner_tris[index][1]]];
t2 = positions[corner_verts[corner_tris[index][2]]];
dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
@ -3469,7 +3472,7 @@ static void mesh_tris_spherecast_dp(void *userdata,
}
/* A modified callback to bvh tree nearest point.
* The tree must have been built using bvhtree_from_mesh_looptri.
* The tree must have been built using bvhtree_from_mesh_corner_tri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit normal.
@ -3481,14 +3484,14 @@ static void mesh_tris_nearest_point_dp(void *userdata,
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const blender::Span<blender::float3> positions = data->vert_positions;
const MLoopTri *looptris = data->looptris.data();
const int3 *corner_tris = data->corner_tris.data();
const int *corner_verts = data->corner_verts.data();
float nearest_tmp[3], dist_sq;
const float *t0, *t1, *t2;
t0 = positions[corner_verts[looptris[index].tri[0]]];
t1 = positions[corner_verts[looptris[index].tri[1]]];
t2 = positions[corner_verts[looptris[index].tri[2]]];
t0 = positions[corner_verts[corner_tris[index][0]]];
t1 = positions[corner_verts[corner_tris[index][1]]];
t2 = positions[corner_verts[corner_tris[index][2]]];
closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
dist_sq = len_squared_v3v3(co, nearest_tmp);
@ -3925,7 +3928,7 @@ struct DynamicPaintPaintData {
Mesh *mesh;
blender::Span<blender::float3> positions;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<int3> corner_tris;
float brush_radius;
const float *avg_brushNor;
const Vec3f *brushVelocity;
@ -3959,7 +3962,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata,
const blender::Span<blender::float3> positions = data->positions;
const blender::Span<int> corner_verts = data->corner_verts;
const blender::Span<MLoopTri> looptris = data->looptris;
const blender::Span<int3> corner_tris = data->corner_tris;
const float brush_radius = data->brush_radius;
const float *avg_brushNor = data->avg_brushNor;
const Vec3f *brushVelocity = data->brushVelocity;
@ -4032,9 +4035,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] = {
corner_verts[looptris[hit.index].tri[0]],
corner_verts[looptris[hit.index].tri[1]],
corner_verts[looptris[hit.index].tri[2]],
corner_verts[corner_tris[hit.index][0]],
corner_verts[corner_tris[hit.index][1]],
corner_verts[corner_tris[hit.index][2]],
};
float dot;
@ -4184,9 +4187,9 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata,
float brushPointVelocity[3];
float velocity[3];
const int v1 = corner_verts[looptris[hitTri].tri[0]];
const int v2 = corner_verts[looptris[hitTri].tri[1]];
const int v3 = corner_verts[looptris[hitTri].tri[2]];
const int v1 = corner_verts[corner_tris[hitTri][0]];
const int v2 = corner_verts[corner_tris[hitTri][1]];
const int v3 = corner_verts[corner_tris[hitTri][2]];
/* calculate barycentric weights for hit point */
interp_weights_tri_v3(weights, positions[v1], positions[v2], positions[v3], hitCoord);
@ -4310,7 +4313,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
blender::MutableSpan<blender::float3> positions = mesh->vert_positions_for_write();
const blender::Span<blender::float3> vert_normals = mesh->vert_normals();
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<int3> corner_tris = mesh->corner_tris();
numOfVerts = mesh->totvert;
/* Transform collider vertices to global space
@ -4342,7 +4345,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
/* check bounding box collision */
if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
/* Build a bvh tree from transformed vertices */
if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRIS, 4)) {
if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_CORNER_TRIS, 4)) {
int c_index;
int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
@ -4366,7 +4369,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
data.mesh = mesh;
data.positions = positions;
data.corner_verts = corner_verts;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.brush_radius = brush_radius;
data.avg_brushNor = avg_brushNor;
data.brushVelocity = brushVelocity;

@ -671,11 +671,11 @@ bool closest_point_on_surface(SurfaceModifierData *surmd,
if (surface_vel) {
const int *corner_verts = bvhtree->corner_verts.data();
const MLoopTri *lt = &bvhtree->looptris[nearest.index];
const blender::int3 &tri = bvhtree->corner_tris[nearest.index];
copy_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[lt->tri[0]]]);
add_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[lt->tri[1]]]);
add_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[lt->tri[2]]]);
copy_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[tri[0]]]);
add_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[tri[1]]]);
add_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[tri[2]]]);
mul_v3_fl(surface_vel, (1.0f / 3.0f));
}

@ -852,7 +852,7 @@ BLI_INLINE void apply_effector_fields(FluidEffectorSettings * /*fes*/,
static void update_velocities(FluidEffectorSettings *fes,
const blender::Span<blender::float3> vert_positions,
const int *corner_verts,
const MLoopTri *looptris,
const blender::int3 *corner_tris,
float *velocity_map,
int index,
BVHTreeFromMesh *tree_data,
@ -876,12 +876,12 @@ static void update_velocities(FluidEffectorSettings *fes,
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1)
{
float weights[3];
int v1, v2, v3, lt_index = nearest.index;
int v1, v2, v3, tri_i = nearest.index;
/* Calculate barycentric weights for nearest point. */
v1 = corner_verts[looptris[lt_index].tri[0]];
v2 = corner_verts[looptris[lt_index].tri[1]];
v3 = corner_verts[looptris[lt_index].tri[2]];
v1 = corner_verts[corner_tris[tri_i][0]];
v2 = corner_verts[corner_tris[tri_i][1]];
v3 = corner_verts[corner_tris[tri_i][2]];
interp_weights_tri_v3(
weights, vert_positions[v1], vert_positions[v2], vert_positions[v3], nearest.co);
@ -952,7 +952,7 @@ struct ObstaclesFromDMData {
blender::Span<blender::float3> vert_positions;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<blender::int3> corner_tris;
BVHTreeFromMesh *tree;
FluidObjectBB *bb;
@ -987,7 +987,7 @@ static void obstacles_from_mesh_task_cb(void *__restrict userdata,
update_velocities(data->fes,
data->vert_positions,
data->corner_verts.data(),
data->looptris.data(),
data->corner_tris.data(),
bb->velocity,
index,
data->tree,
@ -1022,7 +1022,7 @@ static void obstacles_from_mesh(Object *coll_ob,
int min[3], max[3], res[3];
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
numverts = mesh->totvert;
/* TODO(sebbas): Make initialization of vertex velocities optional? */
@ -1080,13 +1080,13 @@ static void obstacles_from_mesh(Object *coll_ob,
/* Skip effector sampling loop if object has disabled effector. */
bool use_effector = fes->flags & FLUID_EFFECTOR_USE_EFFEC;
if (use_effector && BKE_bvhtree_from_mesh_get(&tree_data, mesh, BVHTREE_FROM_LOOPTRIS, 4)) {
if (use_effector && BKE_bvhtree_from_mesh_get(&tree_data, mesh, BVHTREE_FROM_CORNER_TRIS, 4)) {
ObstaclesFromDMData data{};
data.fes = fes;
data.vert_positions = positions;
data.corner_verts = corner_verts;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.tree = &tree_data;
data.bb = bb;
data.has_velocity = has_velocity;
@ -1801,7 +1801,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
blender::Span<blender::float3> vert_positions,
const blender::Span<blender::float3> vert_normals,
const int *corner_verts,
const MLoopTri *looptris,
const blender::int3 *corner_tris,
const float (*mloopuv)[2],
float *influence_map,
float *velocity_map,
@ -1882,13 +1882,13 @@ static void sample_mesh(FluidFlowSettings *ffs,
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1)
{
float weights[3];
int v1, v2, v3, lt_index = nearest.index;
int v1, v2, v3, tri_i = nearest.index;
float hit_normal[3];
/* Calculate barycentric weights for nearest point. */
v1 = corner_verts[looptris[lt_index].tri[0]];
v2 = corner_verts[looptris[lt_index].tri[1]];
v3 = corner_verts[looptris[lt_index].tri[2]];
v1 = corner_verts[corner_tris[tri_i][0]];
v2 = corner_verts[corner_tris[tri_i][1]];
v3 = corner_verts[corner_tris[tri_i][2]];
interp_weights_tri_v3(
weights, vert_positions[v1], vert_positions[v2], vert_positions[v3], nearest.co);
@ -1925,9 +1925,9 @@ static void sample_mesh(FluidFlowSettings *ffs,
}
else if (mloopuv) {
const float *uv[3];
uv[0] = mloopuv[looptris[lt_index].tri[0]];
uv[1] = mloopuv[looptris[lt_index].tri[1]];
uv[2] = mloopuv[looptris[lt_index].tri[2]];
uv[0] = mloopuv[corner_tris[tri_i][0]];
uv[1] = mloopuv[corner_tris[tri_i][1]];
uv[2] = mloopuv[corner_tris[tri_i][2]];
interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
@ -1999,7 +1999,7 @@ struct EmitFromDMData {
blender::Span<blender::float3> vert_positions;
blender::Span<blender::float3> vert_normals;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<blender::int3> corner_tris;
const float (*mloopuv)[2];
const MDeformVert *dvert;
int defgrp_index;
@ -2033,7 +2033,7 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
data->vert_positions,
data->vert_normals,
data->corner_verts.data(),
data->looptris.data(),
data->corner_tris.data(),
data->mloopuv,
bb->influence,
bb->velocity,
@ -2083,7 +2083,7 @@ static void emit_from_mesh(
blender::MutableSpan<blender::float3> positions = mesh->vert_positions_for_write();
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
const int numverts = mesh->totvert;
const MDeformVert *dvert = mesh->deform_verts().data();
const float(*mloopuv)[2] = static_cast<const float(*)[2]>(
@ -2146,7 +2146,7 @@ static void emit_from_mesh(
/* Skip flow sampling loop if object has disabled flow. */
bool use_flow = ffs->flags & FLUID_FLOW_USE_INFLOW;
if (use_flow && BKE_bvhtree_from_mesh_get(&tree_data, mesh, BVHTREE_FROM_LOOPTRIS, 4)) {
if (use_flow && BKE_bvhtree_from_mesh_get(&tree_data, mesh, BVHTREE_FROM_CORNER_TRIS, 4)) {
EmitFromDMData data{};
data.fds = fds;
@ -2154,7 +2154,7 @@ static void emit_from_mesh(
data.vert_positions = positions;
data.vert_normals = mesh->vert_normals();
data.corner_verts = corner_verts;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.mloopuv = mloopuv;
data.dvert = dvert;
data.defgrp_index = defgrp_index;

@ -140,8 +140,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_dst->runtime->loose_verts_cache = mesh_src->runtime->loose_verts_cache;
mesh_dst->runtime->verts_no_face_cache = mesh_src->runtime->verts_no_face_cache;
mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache;
mesh_dst->runtime->looptri_faces_cache = mesh_src->runtime->looptri_faces_cache;
mesh_dst->runtime->corner_tris_cache = mesh_src->runtime->corner_tris_cache;
mesh_dst->runtime->corner_tri_faces_cache = mesh_src->runtime->corner_tri_faces_cache;
mesh_dst->runtime->vert_to_face_offset_cache = mesh_src->runtime->vert_to_face_offset_cache;
mesh_dst->runtime->vert_to_face_map_cache = mesh_src->runtime->vert_to_face_map_cache;
mesh_dst->runtime->vert_to_corner_map_cache = mesh_src->runtime->vert_to_corner_map_cache;

@ -18,7 +18,6 @@
# include "MEM_guardedalloc.h"
# include "DNA_mesh_types.h"
# include "DNA_meshdata_types.h"
# include "DNA_object_types.h"
# include "BLI_utildefines.h"

@ -359,25 +359,24 @@ bool BKE_mesh_center_of_volume(const Mesh *mesh, float r_cent[3])
static bool mesh_calc_center_centroid_ex(const float (*positions)[3],
int /*mverts_num*/,
const MLoopTri *looptris,
int looptris_num,
const blender::int3 *corner_tris,
int corner_tris_num,
const int *corner_verts,
float r_center[3])
{
zero_v3(r_center);
if (looptris_num == 0) {
if (corner_tris_num == 0) {
return false;
}
float totweight = 0.0f;
const MLoopTri *lt;
int i;
for (i = 0, lt = looptris; i < looptris_num; i++, lt++) {
const float *v1 = positions[corner_verts[lt->tri[0]]];
const float *v2 = positions[corner_verts[lt->tri[1]]];
const float *v3 = positions[corner_verts[lt->tri[2]]];
for (i = 0; i < corner_tris_num; i++) {
const float *v1 = positions[corner_verts[corner_tris[i][0]]];
const float *v2 = positions[corner_verts[corner_tris[i][1]]];
const float *v3 = positions[corner_verts[corner_tris[i][2]]];
float area;
area = area_tri_v3(v1, v2, v3);
@ -397,13 +396,12 @@ static bool mesh_calc_center_centroid_ex(const float (*positions)[3],
void BKE_mesh_calc_volume(const float (*vert_positions)[3],
const int mverts_num,
const MLoopTri *looptris,
const int looptris_num,
const blender::int3 *corner_tris,
const int corner_tris_num,
const int *corner_verts,
float *r_volume,
float r_center[3])
{
const MLoopTri *lt;
float center[3];
float totvol;
int i;
@ -415,22 +413,22 @@ void BKE_mesh_calc_volume(const float (*vert_positions)[3],
zero_v3(r_center);
}
if (looptris_num == 0) {
if (corner_tris_num == 0) {
return;
}
if (!mesh_calc_center_centroid_ex(
vert_positions, mverts_num, looptris, looptris_num, corner_verts, center))
vert_positions, mverts_num, corner_tris, corner_tris_num, corner_verts, center))
{
return;
}
totvol = 0.0f;
for (i = 0, lt = looptris; i < looptris_num; i++, lt++) {
const float *v1 = vert_positions[corner_verts[lt->tri[0]]];
const float *v2 = vert_positions[corner_verts[lt->tri[1]]];
const float *v3 = vert_positions[corner_verts[lt->tri[2]]];
for (i = 0; i < corner_tris_num; i++) {
const float *v1 = vert_positions[corner_verts[corner_tris[i][0]]];
const float *v2 = vert_positions[corner_verts[corner_tris[i][1]]];
const float *v3 = vert_positions[corner_verts[corner_tris[i][2]]];
float vol;
vol = volume_tetrahedron_signed_v3(center, v1, v2, v3);

@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_task.hh"

@ -1008,7 +1008,7 @@ static int mesh_tessface_calc(Mesh &mesh,
/* We abuse #MFace.edcode to tag quad faces. See below for details. */
#define TESSFACE_IS_QUAD 1
const int looptris_num = poly_to_tri_count(faces_num, totloop);
const int corner_tris_num = poly_to_tri_count(faces_num, totloop);
MFace *mface, *mf;
MemArena *arena = nullptr;
@ -1028,9 +1028,9 @@ static int mesh_tessface_calc(Mesh &mesh,
* if all faces are triangles it will be correct, `quads == 2x` allocations. */
/* Take care since memory is _not_ zeroed so be sure to initialize each field. */
mface_to_poly_map = (int *)MEM_malloc_arrayN(
size_t(looptris_num), sizeof(*mface_to_poly_map), __func__);
mface = (MFace *)MEM_malloc_arrayN(size_t(looptris_num), sizeof(*mface), __func__);
lindices = (uint(*)[4])MEM_malloc_arrayN(size_t(looptris_num), sizeof(*lindices), __func__);
size_t(corner_tris_num), sizeof(*mface_to_poly_map), __func__);
mface = (MFace *)MEM_malloc_arrayN(size_t(corner_tris_num), sizeof(*mface), __func__);
lindices = (uint(*)[4])MEM_malloc_arrayN(size_t(corner_tris_num), sizeof(*lindices), __func__);
mface_index = 0;
for (poly_index = 0; poly_index < faces_num; poly_index++) {
@ -1187,10 +1187,10 @@ static int mesh_tessface_calc(Mesh &mesh,
CustomData_free(fdata_legacy, totface);
totface = mface_index;
BLI_assert(totface <= looptris_num);
BLI_assert(totface <= corner_tris_num);
/* Not essential but without this we store over-allocated memory in the #CustomData layers. */
if (LIKELY(looptris_num != totface)) {
if (LIKELY(corner_tris_num != totface)) {
mface = (MFace *)MEM_reallocN(mface, sizeof(*mface) * size_t(totface));
mface_to_poly_map = (int *)MEM_reallocN(mface_to_poly_map,
sizeof(*mface_to_poly_map) * size_t(totface));

@ -188,24 +188,23 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
}
}
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const int totvert,
const MLoopTri *looptris,
const int totlooptris,
const int *corner_verts,
const int /*totloop*/)
void BKE_mesh_vert_corner_tri_map_create(MeshElemMap **r_map,
int **r_mem,
const int totvert,
const blender::int3 *corner_tris,
const int tris_num,
const int *corner_verts,
const int /*totloop*/)
{
MeshElemMap *map = MEM_cnew_array<MeshElemMap>(size_t(totvert), __func__);
int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(totlooptris) * 3, __func__));
int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(tris_num) * 3, __func__));
int *index_step;
const MLoopTri *lt;
int i;
/* count face users */
for (i = 0, lt = looptris; i < totlooptris; lt++, i++) {
for (i = 0; i < tris_num; i++) {
for (int j = 3; j--;) {
map[corner_verts[lt->tri[j]]].count++;
map[corner_verts[corner_tris[i][j]]].count++;
}
}
@ -219,10 +218,10 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
map[i].count = 0;
}
/* assign looptri-edge users */
for (i = 0, lt = looptris; i < totlooptris; lt++, i++) {
/* assign corner_tri-edge users */
for (i = 0; i < tris_num; i++) {
for (int j = 3; j--;) {
MeshElemMap *map_ele = &map[corner_verts[lt->tri[j]]];
MeshElemMap *map_ele = &map[corner_verts[corner_tris[i][j]]];
map_ele->indices[map_ele->count++] = i;
}
}
@ -272,14 +271,14 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const blender::OffsetIndices<int> faces,
const int *looptri_faces,
const int looptris_num)
void BKE_mesh_origindex_map_create_corner_tri(MeshElemMap **r_map,
int **r_mem,
const blender::OffsetIndices<int> faces,
const int *corner_tri_faces,
const int corner_tris_num)
{
MeshElemMap *map = MEM_cnew_array<MeshElemMap>(size_t(faces.size()), __func__);
int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(looptris_num), __func__));
int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(corner_tris_num), __func__));
int *index_step;
/* create offsets */
@ -290,8 +289,8 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
}
/* Assign face-tessellation users. */
for (int i = 0; i < looptris_num; i++) {
MeshElemMap *map_ele = &map[looptri_faces[i]];
for (int i = 0; i < corner_tris_num; i++) {
MeshElemMap *map_ele = &map[corner_tri_faces[i]];
map_ele->indices[map_ele->count++] = i;
}

@ -559,7 +559,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
const blender::Span<int> corner_verts_src = me_src->corner_verts();
const blender::Span<blender::float3> positions_src = me_src->vert_positions();
const blender::Span<blender::float3> vert_normals_dst = me_dst->vert_normals();
const blender::Span<int> looptri_faces = me_src->looptri_faces();
const blender::Span<int> tri_faces = me_src->corner_tri_faces();
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float(*vcos)[3] = static_cast<float(*)[3]>(
@ -568,7 +568,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
float *weights = static_cast<float *>(
MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__));
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_CORNER_TRIS, 2);
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
@ -584,7 +584,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_raycast(
&treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist))
{
const int face_index = looptri_faces[rayhit.index];
const int face_index = tri_faces[rayhit.index];
const int sources_num = mesh_remap_interp_face_data_get(faces_src[face_index],
corner_verts_src,
positions_src,
@ -618,7 +618,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(
&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
const int face_index = looptri_faces[nearest.index];
const int face_index = tri_faces[nearest.index];
if (mode == MREMAP_MODE_VERT_FACE_NEAREST) {
int index;
@ -858,9 +858,9 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
const blender::OffsetIndices faces_src = me_src->faces();
const blender::Span<int> corner_edges_src = me_src->corner_edges();
const blender::Span<blender::float3> positions_src = me_src->vert_positions();
const blender::Span<int> looptri_faces = me_src->looptri_faces();
const blender::Span<int> tri_faces = me_src->corner_tri_faces();
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_CORNER_TRIS, 2);
for (i = 0; i < numedges_dst; i++) {
interp_v3_v3v3(tmp_co,
@ -875,7 +875,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
{
const int face_index = looptri_faces[nearest.index];
const int face_index = tri_faces[nearest.index];
const blender::IndexRange face_src = faces_src[face_index];
const int *corner_edge_src = &corner_edges_src[face_src.start()];
int nloops = int(face_src.size());
@ -1274,8 +1274,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
Array<int> edge_to_face_src_indices;
GroupedSpan<int> edge_to_face_map_src;
MeshElemMap *face_to_looptri_map_src = nullptr;
int *face_to_looptri_map_src_buff = nullptr;
MeshElemMap *face_to_corner_tri_map_src = nullptr;
int *face_to_corner_tri_map_src_buff = nullptr;
/* Unlike above, those are one-to-one mappings, simpler! */
blender::Span<int> loop_to_face_map_src;
@ -1286,8 +1286,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const blender::OffsetIndices faces_src = me_src->faces();
const blender::Span<int> corner_verts_src = me_src->corner_verts();
const blender::Span<int> corner_edges_src = me_src->corner_edges();
blender::Span<MLoopTri> looptris_src;
blender::Span<int> looptri_faces_src;
blender::Span<blender::int3> corner_tris_src;
blender::Span<int> tri_faces_src;
size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE;
float(*vcos_interp)[3] = nullptr;
@ -1442,34 +1442,34 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
else { /* We use faces. */
if (use_islands) {
looptris_src = me_src->looptris();
looptri_faces_src = me_src->looptri_faces();
blender::BitVector<> looptris_active(looptris_src.size());
corner_tris_src = me_src->corner_tris();
tri_faces_src = me_src->corner_tri_faces();
blender::BitVector<> corner_tris_active(corner_tris_src.size());
for (tindex = 0; tindex < num_trees; tindex++) {
int looptris_num_active = 0;
looptris_active.fill(false);
for (const int64_t i : looptris_src.index_range()) {
const blender::IndexRange face = faces_src[looptri_faces_src[i]];
int corner_tris_num_active = 0;
corner_tris_active.fill(false);
for (const int64_t i : corner_tris_src.index_range()) {
const blender::IndexRange face = faces_src[tri_faces_src[i]];
if (island_store.items_to_islands[face.start()] == tindex) {
looptris_active[i].set();
looptris_num_active++;
corner_tris_active[i].set();
corner_tris_num_active++;
}
}
bvhtree_from_mesh_looptris_ex(&treedata[tindex],
positions_src,
corner_verts_src,
looptris_src,
looptris_active,
looptris_num_active,
0.0,
2,
6);
bvhtree_from_mesh_corner_tris_ex(&treedata[tindex],
positions_src,
corner_verts_src,
corner_tris_src,
corner_tris_active,
corner_tris_num_active,
0.0,
2,
6);
}
}
else {
BLI_assert(num_trees == 1);
BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_CORNER_TRIS, 2);
}
}
@ -1480,7 +1480,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
islands_res[tindex] = static_cast<IslandResult *>(
MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__));
}
const blender::Span<int> looptri_faces = me_src->looptri_faces();
const blender::Span<int> tri_faces = me_src->corner_tri_faces();
for (pidx_dst = 0; pidx_dst < faces_dst.size(); pidx_dst++) {
const blender::IndexRange face_dst = faces_dst[pidx_dst];
@ -1636,7 +1636,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
{
islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w;
islands_res[tindex][plidx_dst].hit_dist = hit_dist;
islands_res[tindex][plidx_dst].index_src = looptri_faces[rayhit.index];
islands_res[tindex][plidx_dst].index_src = tri_faces[rayhit.index];
copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co);
break;
}
@ -1665,7 +1665,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(
tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
islands_res[tindex][plidx_dst].hit_dist = hit_dist;
islands_res[tindex][plidx_dst].index_src = looptri_faces[nearest.index];
islands_res[tindex][plidx_dst].index_src = tri_faces[nearest.index];
copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
}
else {
@ -1688,7 +1688,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
{
islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f;
islands_res[tindex][plidx_dst].hit_dist = hit_dist;
islands_res[tindex][plidx_dst].index_src = looptri_faces[nearest.index];
islands_res[tindex][plidx_dst].index_src = tri_faces[nearest.index];
copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
}
else {
@ -1909,25 +1909,25 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
last_valid_pidx_isld_src);
/* Create that one on demand. */
if (face_to_looptri_map_src == nullptr) {
BKE_mesh_origindex_map_create_looptri(&face_to_looptri_map_src,
&face_to_looptri_map_src_buff,
faces_src,
looptri_faces_src.data(),
int(looptri_faces_src.size()));
if (face_to_corner_tri_map_src == nullptr) {
BKE_mesh_origindex_map_create_corner_tri(&face_to_corner_tri_map_src,
&face_to_corner_tri_map_src_buff,
faces_src,
tri_faces_src.data(),
int(tri_faces_src.size()));
}
for (j = face_to_looptri_map_src[pidx_src].count; j--;) {
for (j = face_to_corner_tri_map_src[pidx_src].count; j--;) {
float h[3];
const MLoopTri *lt =
&looptris_src[face_to_looptri_map_src[pidx_src].indices[j]];
const blender::int3 &tri =
corner_tris_src[face_to_corner_tri_map_src[pidx_src].indices[j]];
float dist_sq;
closest_on_tri_to_point_v3(h,
tmp_co,
positions_src[corner_verts_src[lt->tri[0]]],
positions_src[corner_verts_src[lt->tri[1]]],
positions_src[corner_verts_src[lt->tri[2]]]);
positions_src[corner_verts_src[tri[0]]],
positions_src[corner_verts_src[tri[1]]],
positions_src[corner_verts_src[tri[2]]]);
dist_sq = len_squared_v3v3(tmp_co, h);
if (dist_sq < best_dist_sq) {
copy_v3_v3(hit_co, h);
@ -2012,11 +2012,11 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
BLI_astar_solution_free(&as_solution);
}
if (face_to_looptri_map_src) {
MEM_freeN(face_to_looptri_map_src);
if (face_to_corner_tri_map_src) {
MEM_freeN(face_to_corner_tri_map_src);
}
if (face_to_looptri_map_src_buff) {
MEM_freeN(face_to_looptri_map_src_buff);
if (face_to_corner_tri_map_src_buff) {
MEM_freeN(face_to_corner_tri_map_src_buff);
}
if (vcos_interp) {
MEM_freeN(vcos_interp);
@ -2067,9 +2067,9 @@ void BKE_mesh_remap_calc_faces_from_mesh(const int mode,
BVHTreeNearest nearest = {0};
BVHTreeRayHit rayhit = {0};
float hit_dist;
const blender::Span<int> looptri_faces = me_src->looptri_faces();
const blender::Span<int> tri_faces = me_src->corner_tri_faces();
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_CORNER_TRIS, 2);
if (mode == MREMAP_MODE_POLY_NEAREST) {
nearest.index = -1;
@ -2087,7 +2087,7 @@ void BKE_mesh_remap_calc_faces_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
{
const int face_index = looptri_faces[nearest.index];
const int face_index = tri_faces[nearest.index];
mesh_remap_item_define(r_map, int(i), hit_dist, 0, 1, &face_index, &full_weight);
}
else {
@ -2114,7 +2114,7 @@ void BKE_mesh_remap_calc_faces_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_raycast(
&treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist))
{
const int face_index = looptri_faces[rayhit.index];
const int face_index = tri_faces[rayhit.index];
mesh_remap_item_define(r_map, int(i), hit_dist, 0, 1, &face_index, &full_weight);
}
else {
@ -2267,7 +2267,7 @@ void BKE_mesh_remap_calc_faces_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_raycast(
&treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
{
const int face_index = looptri_faces[rayhit.index];
const int face_index = tri_faces[rayhit.index];
weights[face_index] += w;
totweights += w;
hit_dist_accum += hit_dist;

@ -54,6 +54,7 @@
using blender::Array;
using blender::float3;
using blender::IndexRange;
using blender::int3;
using blender::MutableSpan;
using blender::Span;
@ -69,14 +70,14 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
{
const Span<float3> input_positions = input_mesh->vert_positions();
const Span<int> input_corner_verts = input_mesh->corner_verts();
const Span<MLoopTri> looptris = input_mesh->looptris();
const Span<int3> corner_tris = input_mesh->corner_tris();
/* Gather the required data for export to the internal quadriflow mesh format. */
Array<MVertTri> verttri(looptris.size());
BKE_mesh_runtime_verttris_from_looptris(
verttri.data(), input_corner_verts.data(), looptris.data(), looptris.size());
Array<MVertTri> verttri(corner_tris.size());
BKE_mesh_runtime_verttris_from_corner_tris(
verttri.data(), input_corner_verts.data(), corner_tris.data(), corner_tris.size());
const int totfaces = looptris.size();
const int totfaces = corner_tris.size();
const int totverts = input_mesh->totvert;
Array<int> faces(totfaces * 3);
@ -188,20 +189,20 @@ static openvdb::FloatGrid::Ptr remesh_voxel_level_set_create(const Mesh *mesh,
{
const Span<float3> positions = mesh->vert_positions();
const Span<int> corner_verts = mesh->corner_verts();
const Span<MLoopTri> looptris = mesh->looptris();
const Span<int3> corner_tris = mesh->corner_tris();
std::vector<openvdb::Vec3s> points(mesh->totvert);
std::vector<openvdb::Vec3I> triangles(looptris.size());
std::vector<openvdb::Vec3I> triangles(corner_tris.size());
for (const int i : IndexRange(mesh->totvert)) {
const float3 &co = positions[i];
points[i] = openvdb::Vec3s(co.x, co.y, co.z);
}
for (const int i : IndexRange(looptris.size())) {
const MLoopTri &lt = looptris[i];
for (const int i : IndexRange(corner_tris.size())) {
const int3 &tri = corner_tris[i];
triangles[i] = openvdb::Vec3I(
corner_verts[lt.tri[0]], corner_verts[lt.tri[1]], corner_verts[lt.tri[2]]);
corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]);
}
openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(
@ -323,7 +324,7 @@ static void find_nearest_tris_parallel(const Span<float3> positions,
static void find_nearest_verts(const Span<float3> positions,
const Span<int> corner_verts,
const Span<MLoopTri> src_looptris,
const Span<int3> src_corner_tris,
const Span<float3> dst_positions,
const Span<int> nearest_vert_tris,
MutableSpan<int> nearest_verts)
@ -331,16 +332,16 @@ static void find_nearest_verts(const Span<float3> positions,
threading::parallel_for(dst_positions.index_range(), 512, [&](const IndexRange range) {
for (const int dst_vert : range) {
const float3 &dst_position = dst_positions[dst_vert];
const MLoopTri &src_lt = src_looptris[nearest_vert_tris[dst_vert]];
const int3 &src_tri = src_corner_tris[nearest_vert_tris[dst_vert]];
std::array<float, 3> distances;
for (const int i : IndexRange(3)) {
const int src_vert = corner_verts[src_lt.tri[i]];
const int src_vert = corner_verts[src_tri[i]];
distances[i] = math::distance_squared(positions[src_vert], dst_position);
}
const int min = std::min_element(distances.begin(), distances.end()) - distances.begin();
nearest_verts[dst_vert] = corner_verts[src_lt.tri[min]];
nearest_verts[dst_vert] = corner_verts[src_tri[min]];
}
});
}
@ -515,7 +516,7 @@ void mesh_remesh_reproject_attributes(const Mesh &src, Mesh &dst)
const Span<float3> src_positions = src.vert_positions();
const OffsetIndices src_faces = src.faces();
const Span<int> src_corner_verts = src.corner_verts();
const Span<MLoopTri> src_looptris = src.looptris();
const Span<int3> src_corner_tris = src.corner_tris();
/* The main idea in the following code is to trade some complexity in sampling for the benefit of
* only using and building a single BVH tree. Since sculpt mode doesn't generally deal with loose
@ -529,7 +530,7 @@ void mesh_remesh_reproject_attributes(const Mesh &src, Mesh &dst)
* possibly improved performance from lower cache usage in the "complex" sampling part of the
* algorithm and the copying itself. */
BVHTreeFromMesh bvhtree{};
BKE_bvhtree_from_mesh_get(&bvhtree, &src, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&bvhtree, &src, BVHTREE_FROM_CORNER_TRIS, 2);
const Span<float3> dst_positions = dst.vert_positions();
const OffsetIndices dst_faces = dst.faces();
@ -544,12 +545,12 @@ void mesh_remesh_reproject_attributes(const Mesh &src, Mesh &dst)
if (!point_ids.is_empty()) {
Array<int> map(dst.totvert);
find_nearest_verts(
src_positions, src_corner_verts, src_looptris, dst_positions, vert_nearest_tris, map);
src_positions, src_corner_verts, src_corner_tris, dst_positions, vert_nearest_tris, map);
gather_attributes(point_ids, src_attributes, ATTR_DOMAIN_POINT, map, dst_attributes);
}
if (!corner_ids.is_empty()) {
const Span<int> src_tri_faces = src.looptri_faces();
const Span<int> src_tri_faces = src.corner_tri_faces();
Array<int> map(dst.totloop);
find_nearest_corners(src_positions,
src_faces,
@ -566,7 +567,7 @@ void mesh_remesh_reproject_attributes(const Mesh &src, Mesh &dst)
if (!edge_ids.is_empty()) {
const Span<int2> src_edges = src.edges();
const Span<int> src_corner_edges = src.corner_edges();
const Span<int> src_tri_faces = src.looptri_faces();
const Span<int> src_tri_faces = src.corner_tri_faces();
const Span<int2> dst_edges = dst.edges();
Array<int> map(dst.totedge);
find_nearest_edges(src_positions,
@ -582,7 +583,7 @@ void mesh_remesh_reproject_attributes(const Mesh &src, Mesh &dst)
}
if (!face_ids.is_empty()) {
const Span<int> src_tri_faces = src.looptri_faces();
const Span<int> src_tri_faces = src.corner_tri_faces();
Array<int> map(dst.faces_num);
find_nearest_faces(src_tri_faces, dst_positions, dst_faces, dst_corner_verts, bvhtree, map);
gather_attributes(face_ids, src_attributes, ATTR_DOMAIN_FACE, map, dst_attributes);

@ -230,9 +230,9 @@ void Mesh::tag_overlapping_none()
this->flag |= ME_NO_OVERLAPPING_TOPOLOGY;
}
blender::Span<MLoopTri> Mesh::looptris() const
blender::Span<blender::int3> Mesh::corner_tris() const
{
this->runtime->looptris_cache.ensure([&](blender::Array<MLoopTri> &r_data) {
this->runtime->corner_tris_cache.ensure([&](blender::Array<blender::int3> &r_data) {
const Span<float3> positions = this->vert_positions();
const blender::OffsetIndices faces = this->faces();
const Span<int> corner_verts = this->corner_verts();
@ -240,43 +240,43 @@ blender::Span<MLoopTri> Mesh::looptris() const
r_data.reinitialize(poly_to_tri_count(faces.size(), corner_verts.size()));
if (BKE_mesh_face_normals_are_dirty(this)) {
blender::bke::mesh::looptris_calc(positions, faces, corner_verts, r_data);
blender::bke::mesh::corner_tris_calc(positions, faces, corner_verts, r_data);
}
else {
blender::bke::mesh::looptris_calc_with_normals(
blender::bke::mesh::corner_tris_calc_with_normals(
positions, faces, corner_verts, this->face_normals(), r_data);
}
});
return this->runtime->looptris_cache.data();
return this->runtime->corner_tris_cache.data();
}
blender::Span<int> Mesh::looptri_faces() const
blender::Span<int> Mesh::corner_tri_faces() const
{
using namespace blender;
this->runtime->looptri_faces_cache.ensure([&](blender::Array<int> &r_data) {
this->runtime->corner_tri_faces_cache.ensure([&](blender::Array<int> &r_data) {
const OffsetIndices faces = this->faces();
r_data.reinitialize(poly_to_tri_count(faces.size(), this->totloop));
bke::mesh::looptris_calc_face_indices(faces, r_data);
bke::mesh::corner_tris_calc_face_indices(faces, r_data);
});
return this->runtime->looptri_faces_cache.data();
return this->runtime->corner_tri_faces_cache.data();
}
int BKE_mesh_runtime_looptris_len(const Mesh *mesh)
int BKE_mesh_runtime_corner_tris_len(const Mesh *mesh)
{
/* Allow returning the size without calculating the cache. */
return poly_to_tri_count(mesh->faces_num, mesh->totloop);
}
void BKE_mesh_runtime_verttris_from_looptris(MVertTri *r_verttri,
const int *corner_verts,
const MLoopTri *looptris,
int looptris_num)
void BKE_mesh_runtime_verttris_from_corner_tris(MVertTri *r_verttri,
const int *corner_verts,
const blender::int3 *corner_tris,
int corner_tris_num)
{
for (int i = 0; i < looptris_num; i++) {
r_verttri[i].tri[0] = corner_verts[looptris[i].tri[0]];
r_verttri[i].tri[1] = corner_verts[looptris[i].tri[1]];
r_verttri[i].tri[2] = corner_verts[looptris[i].tri[2]];
for (int i = 0; i < corner_tris_num; i++) {
r_verttri[i].tri[0] = corner_verts[corner_tris[i][0]];
r_verttri[i].tri[1] = corner_verts[corner_tris[i][1]];
r_verttri[i].tri[2] = corner_verts[corner_tris[i][2]];
}
}
@ -311,8 +311,8 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
mesh->runtime->loose_edges_cache.tag_dirty();
mesh->runtime->loose_verts_cache.tag_dirty();
mesh->runtime->verts_no_face_cache.tag_dirty();
mesh->runtime->looptris_cache.tag_dirty();
mesh->runtime->looptri_faces_cache.tag_dirty();
mesh->runtime->corner_tris_cache.tag_dirty();
mesh->runtime->corner_tri_faces_cache.tag_dirty();
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
mesh->runtime->shrinkwrap_data.reset();
@ -372,7 +372,7 @@ void Mesh::tag_positions_changed()
void Mesh::tag_positions_changed_no_normals()
{
free_bvh_cache(*this->runtime);
this->runtime->looptris_cache.tag_dirty();
this->runtime->corner_tris_cache.tag_dirty();
this->runtime->bounds_cache.tag_dirty();
}

@ -19,43 +19,43 @@ namespace blender::bke::mesh_surface_sample {
template<typename T>
BLI_NOINLINE static void sample_point_attribute(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> bary_coords,
const VArray<T> &src,
const IndexMask &mask,
const MutableSpan<T> dst)
{
mask.foreach_index([&](const int i) {
const MLoopTri &lt = looptris[looptri_indices[i]];
const int3 &tri = corner_tris[tri_indices[i]];
dst[i] = attribute_math::mix3(bary_coords[i],
src[corner_verts[lt.tri[0]]],
src[corner_verts[lt.tri[1]]],
src[corner_verts[lt.tri[2]]]);
src[corner_verts[tri[0]]],
src[corner_verts[tri[1]]],
src[corner_verts[tri[2]]]);
});
}
void sample_point_normals(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> bary_coords,
const Span<float3> src,
const IndexMask mask,
const MutableSpan<float3> dst)
{
mask.foreach_index([&](const int i) {
const MLoopTri &lt = looptris[looptri_indices[i]];
const int3 &tri = corner_tris[tri_indices[i]];
const float3 value = attribute_math::mix3(bary_coords[i],
src[corner_verts[lt.tri[0]]],
src[corner_verts[lt.tri[1]]],
src[corner_verts[lt.tri[2]]]);
src[corner_verts[tri[0]]],
src[corner_verts[tri[1]]],
src[corner_verts[tri[2]]]);
dst[i] = math::normalize(value);
});
}
void sample_point_attribute(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> bary_coords,
const GVArray &src,
const IndexMask &mask,
@ -66,19 +66,14 @@ void sample_point_attribute(const Span<int> corner_verts,
const CPPType &type = src.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_point_attribute<T>(corner_verts,
looptris,
looptri_indices,
bary_coords,
src.typed<T>(),
mask,
dst.typed<T>());
sample_point_attribute<T>(
corner_verts, corner_tris, tri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>());
});
}
template<typename T, bool check_indices = false>
BLI_NOINLINE static void sample_corner_attribute(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
BLI_NOINLINE static void sample_corner_attribute(const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> bary_coords,
const VArray<T> &src,
const IndexMask &mask,
@ -86,32 +81,32 @@ BLI_NOINLINE static void sample_corner_attribute(const Span<MLoopTri> looptris,
{
mask.foreach_index([&](const int i) {
if constexpr (check_indices) {
if (looptri_indices[i] == -1) {
if (tri_indices[i] == -1) {
dst[i] = {};
return;
}
}
const MLoopTri &lt = looptris[looptri_indices[i]];
dst[i] = sample_corner_attribute_with_bary_coords(bary_coords[i], lt, src);
const int3 &tri = corner_tris[tri_indices[i]];
dst[i] = sample_corner_attribute_with_bary_coords(bary_coords[i], tri, src);
});
}
void sample_corner_normals(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
void sample_corner_normals(const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> bary_coords,
const Span<float3> src,
const IndexMask &mask,
const MutableSpan<float3> dst)
{
mask.foreach_index([&](const int i) {
const MLoopTri &lt = looptris[looptri_indices[i]];
const float3 value = sample_corner_attribute_with_bary_coords(bary_coords[i], lt, src);
const int3 &tri = corner_tris[tri_indices[i]];
const float3 value = sample_corner_attribute_with_bary_coords(bary_coords[i], tri, src);
dst[i] = math::normalize(value);
});
}
void sample_corner_attribute(const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
void sample_corner_attribute(const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> bary_coords,
const GVArray &src,
const IndexMask &mask,
@ -123,26 +118,26 @@ void sample_corner_attribute(const Span<MLoopTri> looptris,
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_corner_attribute<T>(
looptris, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>());
corner_tris, tri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>());
});
}
template<typename T>
void sample_face_attribute(const Span<int> looptri_faces,
const Span<int> looptri_indices,
void sample_face_attribute(const Span<int> tri_faces,
const Span<int> tri_indices,
const VArray<T> &src,
const IndexMask &mask,
const MutableSpan<T> dst)
{
mask.foreach_index([&](const int i) {
const int looptri_index = looptri_indices[i];
const int face_index = looptri_faces[looptri_index];
const int tri_index = tri_indices[i];
const int face_index = tri_faces[tri_index];
dst[i] = src[face_index];
});
}
void sample_face_attribute(const Span<int> looptri_faces,
const Span<int> looptri_indices,
void sample_face_attribute(const Span<int> corner_tri_faces,
const Span<int> tri_indices,
const GVArray &src,
const IndexMask &mask,
const GMutableSpan dst)
@ -152,53 +147,53 @@ void sample_face_attribute(const Span<int> looptri_faces,
const CPPType &type = src.type();
attribute_math::convert_to_static_type(type, [&](auto dummy) {
using T = decltype(dummy);
sample_face_attribute<T>(looptri_faces, looptri_indices, src.typed<T>(), mask, dst.typed<T>());
sample_face_attribute<T>(corner_tri_faces, tri_indices, src.typed<T>(), mask, dst.typed<T>());
});
}
template<bool check_indices = false>
static void sample_barycentric_weights(const Span<float3> vert_positions,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> sample_positions,
const IndexMask &mask,
MutableSpan<float3> bary_coords)
{
mask.foreach_index([&](const int i) {
if constexpr (check_indices) {
if (looptri_indices[i] == -1) {
if (tri_indices[i] == -1) {
bary_coords[i] = {};
return;
}
}
const MLoopTri &lt = looptris[looptri_indices[i]];
const int3 &tri = corner_tris[tri_indices[i]];
bary_coords[i] = compute_bary_coord_in_triangle(
vert_positions, corner_verts, lt, sample_positions[i]);
vert_positions, corner_verts, tri, sample_positions[i]);
});
}
template<bool check_indices = false>
static void sample_nearest_weights(const Span<float3> vert_positions,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_indices,
const Span<int3> corner_tris,
const Span<int> tri_indices,
const Span<float3> sample_positions,
const IndexMask &mask,
MutableSpan<float3> bary_coords)
{
mask.foreach_index([&](const int i) {
if constexpr (check_indices) {
if (looptri_indices[i] == -1) {
if (tri_indices[i] == -1) {
bary_coords[i] = {};
return;
}
}
const MLoopTri &lt = looptris[looptri_indices[i]];
const int3 &tri = corner_tris[tri_indices[i]];
bary_coords[i] = MIN3_PAIR(
math::distance_squared(sample_positions[i], vert_positions[corner_verts[lt.tri[0]]]),
math::distance_squared(sample_positions[i], vert_positions[corner_verts[lt.tri[1]]]),
math::distance_squared(sample_positions[i], vert_positions[corner_verts[lt.tri[2]]]),
math::distance_squared(sample_positions[i], vert_positions[corner_verts[tri[0]]]),
math::distance_squared(sample_positions[i], vert_positions[corner_verts[tri[1]]]),
math::distance_squared(sample_positions[i], vert_positions[corner_verts[tri[2]]]),
float3(1, 0, 0),
float3(0, 1, 0),
float3(0, 0, 1));
@ -207,17 +202,17 @@ static void sample_nearest_weights(const Span<float3> vert_positions,
int sample_surface_points_spherical(RandomNumberGenerator &rng,
const Mesh &mesh,
const Span<int> looptri_indices_to_sample,
const Span<int> tri_indices_to_sample,
const float3 &sample_pos,
const float sample_radius,
const float approximate_density,
Vector<float3> &r_bary_coords,
Vector<int> &r_looptri_indices,
Vector<int> &r_tri_indices,
Vector<float3> &r_positions)
{
const Span<float3> positions = mesh.vert_positions();
const Span<int> corner_verts = mesh.corner_verts();
const Span<MLoopTri> looptris = mesh.looptris();
const Span<int3> corner_tris = mesh.corner_tris();
const float sample_radius_sq = pow2f(sample_radius);
const float sample_plane_area = M_PI * sample_radius_sq;
@ -226,19 +221,19 @@ int sample_surface_points_spherical(RandomNumberGenerator &rng,
const int old_num = r_bary_coords.size();
for (const int looptri_index : looptri_indices_to_sample) {
const MLoopTri &lt = looptris[looptri_index];
for (const int tri_index : tri_indices_to_sample) {
const int3 &tri = corner_tris[tri_index];
const float3 &v0 = positions[corner_verts[lt.tri[0]]];
const float3 &v1 = positions[corner_verts[lt.tri[1]]];
const float3 &v2 = positions[corner_verts[lt.tri[2]]];
const float3 &v0 = positions[corner_verts[tri[0]]];
const float3 &v1 = positions[corner_verts[tri[1]]];
const float3 &v2 = positions[corner_verts[tri[2]]];
const float looptri_area = area_tri_v3(v0, v1, v2);
const float corner_tri_area = area_tri_v3(v0, v1, v2);
if (looptri_area < area_threshold) {
if (corner_tri_area < area_threshold) {
/* The triangle is small compared to the sample radius. Sample by generating random
* barycentric coordinates. */
const int amount = rng.round_probabilistic(approximate_density * looptri_area);
const int amount = rng.round_probabilistic(approximate_density * corner_tri_area);
for ([[maybe_unused]] const int i : IndexRange(amount)) {
const float3 bary_coord = rng.get_barycentric_coordinates();
const float3 point_pos = attribute_math::mix3(bary_coord, v0, v1, v2);
@ -248,7 +243,7 @@ int sample_surface_points_spherical(RandomNumberGenerator &rng,
}
r_bary_coords.append(bary_coord);
r_looptri_indices.append(looptri_index);
r_tri_indices.append(tri_index);
r_positions.append(point_pos);
}
}
@ -289,7 +284,7 @@ int sample_surface_points_spherical(RandomNumberGenerator &rng,
interp_weights_tri_v3(bary_coord, v0, v1, v2, point_pos);
r_bary_coords.append(bary_coord);
r_looptri_indices.append(looptri_index);
r_tri_indices.append(tri_index);
r_positions.append(point_pos);
}
}
@ -309,12 +304,12 @@ int sample_surface_points_projected(
const int tries_num,
const int max_points,
Vector<float3> &r_bary_coords,
Vector<int> &r_looptri_indices,
Vector<int> &r_tri_indices,
Vector<float3> &r_positions)
{
const Span<float3> positions = mesh.vert_positions();
const Span<int> corner_verts = mesh.corner_verts();
const Span<MLoopTri> looptris = mesh.looptris();
const Span<int3> corner_tris = mesh.corner_tris();
int point_count = 0;
for ([[maybe_unused]] const int _ : IndexRange(tries_num)) {
@ -351,15 +346,15 @@ int sample_surface_points_projected(
}
}
const int looptri_index = ray_hit.index;
const int tri_index = ray_hit.index;
const float3 pos = ray_hit.co;
const float3 bary_coords = compute_bary_coord_in_triangle(
positions, corner_verts, looptris[looptri_index], pos);
positions, corner_verts, corner_tris[tri_index], pos);
r_positions.append(pos);
r_bary_coords.append(bary_coords);
r_looptri_indices.append(looptri_index);
r_tri_indices.append(tri_index);
point_count++;
}
return point_count;
@ -367,12 +362,12 @@ int sample_surface_points_projected(
float3 compute_bary_coord_in_triangle(const Span<float3> vert_positions,
const Span<int> corner_verts,
const MLoopTri &lt,
const int3 &tri,
const float3 &position)
{
const float3 &v0 = vert_positions[corner_verts[lt.tri[0]]];
const float3 &v1 = vert_positions[corner_verts[lt.tri[1]]];
const float3 &v2 = vert_positions[corner_verts[lt.tri[2]]];
const float3 &v0 = vert_positions[corner_verts[tri[0]]];
const float3 &v1 = vert_positions[corner_verts[tri[1]]];
const float3 &v2 = vert_positions[corner_verts[tri[2]]];
float3 bary_coords;
interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
return bary_coords;
@ -394,7 +389,7 @@ BaryWeightFromPositionFn::BaryWeightFromPositionFn(GeometrySet geometry)
const Mesh &mesh = *source_.get_mesh();
vert_positions_ = mesh.vert_positions();
corner_verts_ = mesh.corner_verts();
looptris_ = mesh.looptris();
corner_tris_ = mesh.corner_tris();
}
void BaryWeightFromPositionFn::call(const IndexMask &mask,
@ -407,7 +402,7 @@ void BaryWeightFromPositionFn::call(const IndexMask &mask,
2, "Barycentric Weight");
sample_barycentric_weights<true>(vert_positions_,
corner_verts_,
looptris_,
corner_tris_,
triangle_indices,
sample_positions,
mask,
@ -430,7 +425,7 @@ CornerBaryWeightFromPositionFn::CornerBaryWeightFromPositionFn(GeometrySet geome
const Mesh &mesh = *source_.get_mesh();
vert_positions_ = mesh.vert_positions();
corner_verts_ = mesh.corner_verts();
looptris_ = mesh.looptris();
corner_tris_ = mesh.corner_tris();
}
void CornerBaryWeightFromPositionFn::call(const IndexMask &mask,
@ -443,7 +438,7 @@ void CornerBaryWeightFromPositionFn::call(const IndexMask &mask,
2, "Barycentric Weight");
sample_nearest_weights<true>(vert_positions_,
corner_verts_,
looptris_,
corner_tris_,
triangle_indices,
sample_positions,
mask,
@ -472,15 +467,19 @@ void BaryWeightSampleFn::call(const IndexMask &mask,
GMutableSpan dst = params.uninitialized_single_output(2, "Value");
attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
using T = decltype(dummy);
sample_corner_attribute<T, true>(
looptris_, triangle_indices, bary_weights, source_data_->typed<T>(), mask, dst.typed<T>());
sample_corner_attribute<T, true>(corner_tris_,
triangle_indices,
bary_weights,
source_data_->typed<T>(),
mask,
dst.typed<T>());
});
}
void BaryWeightSampleFn::evaluate_source(fn::GField src_field)
{
const Mesh &mesh = *source_.get_mesh();
looptris_ = mesh.looptris();
corner_tris_ = mesh.corner_tris();
/* Use the most complex domain for now, ensuring no information is lost. In the future, it should
* be possible to use the most complex domain required by the field inputs, to simplify sampling
* and avoid domain conversions. */

@ -156,13 +156,13 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
/** \name Mesh Tangent Calculations (All Layers)
* \{ */
/* Necessary complexity to handle looptris as quads for correct tangents. */
#define USE_LOOPTRI_DETECT_QUADS
/* Necessary complexity to handle corner_tris as quads for correct tangents. */
#define USE_TRI_DETECT_QUADS
struct SGLSLMeshToTangent {
uint GetNumFaces()
{
#ifdef USE_LOOPTRI_DETECT_QUADS
#ifdef USE_TRI_DETECT_QUADS
return uint(num_face_as_quad_map);
#else
return uint(numTessFaces);
@ -171,9 +171,9 @@ struct SGLSLMeshToTangent {
uint GetNumVerticesOfFace(const uint face_num)
{
#ifdef USE_LOOPTRI_DETECT_QUADS
#ifdef USE_TRI_DETECT_QUADS
if (face_as_quad_map) {
const int face_index = looptri_faces[face_as_quad_map[face_num]];
const int face_index = tri_faces[face_as_quad_map[face_num]];
if (faces[face_index].size() == 4) {
return 4;
}
@ -185,40 +185,40 @@ struct SGLSLMeshToTangent {
#endif
}
uint GetLoop(const uint face_num, const uint vert_num, MLoopTri &lt, int &face_index)
uint GetLoop(const uint face_num, const uint vert_num, blender::int3 &tri, int &face_index)
{
#ifdef USE_LOOPTRI_DETECT_QUADS
#ifdef USE_TRI_DETECT_QUADS
if (face_as_quad_map) {
lt = looptris[face_as_quad_map[face_num]];
face_index = looptri_faces[face_as_quad_map[face_num]];
tri = corner_tris[face_as_quad_map[face_num]];
face_index = tri_faces[face_as_quad_map[face_num]];
if (faces[face_index].size() == 4) {
return uint(faces[face_index][vert_num]);
}
/* fall through to regular triangle */
}
else {
lt = looptris[face_num];
face_index = looptri_faces[face_num];
tri = corner_tris[face_num];
face_index = tri_faces[face_num];
}
#else
lt = &looptris[face_num];
tri = &corner_tris[face_num];
#endif
return lt.tri[vert_num];
return uint(tri[int(vert_num)]);
}
mikk::float3 GetPosition(const uint face_num, const uint vert_num)
{
MLoopTri lt;
blender::int3 tri;
int face_index;
uint loop_index = GetLoop(face_num, vert_num, lt, face_index);
uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
return mikk::float3(positions[corner_verts[loop_index]]);
}
mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
{
MLoopTri lt;
blender::int3 tri;
int face_index;
uint loop_index = GetLoop(face_num, vert_num, lt, face_index);
uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
if (mloopuv != nullptr) {
const float2 &uv = mloopuv[loop_index];
return mikk::float3(uv[0], uv[1], 1.0f);
@ -231,9 +231,9 @@ struct SGLSLMeshToTangent {
mikk::float3 GetNormal(const uint face_num, const uint vert_num)
{
MLoopTri lt;
blender::int3 tri;
int face_index;
uint loop_index = GetLoop(face_num, vert_num, lt, face_index);
uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
if (precomputedLoopNormals) {
return mikk::float3(precomputedLoopNormals[loop_index]);
}
@ -241,7 +241,7 @@ struct SGLSLMeshToTangent {
if (precomputedFaceNormals) {
return mikk::float3(precomputedFaceNormals[face_index]);
}
#ifdef USE_LOOPTRI_DETECT_QUADS
#ifdef USE_TRI_DETECT_QUADS
const blender::IndexRange face = faces[face_index];
float normal[3];
if (face.size() == 4) {
@ -255,9 +255,9 @@ struct SGLSLMeshToTangent {
#endif
{
normal_tri_v3(normal,
positions[corner_verts[lt.tri[0]]],
positions[corner_verts[lt.tri[1]]],
positions[corner_verts[lt.tri[2]]]);
positions[corner_verts[tri[0]]],
positions[corner_verts[tri[1]]],
positions[corner_verts[tri[2]]]);
}
return mikk::float3(normal);
}
@ -266,17 +266,17 @@ struct SGLSLMeshToTangent {
void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
{
MLoopTri lt;
blender::int3 tri;
int face_index;
uint loop_index = GetLoop(face_num, vert_num, lt, face_index);
uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
copy_v4_fl4(tangent[loop_index], T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
const float (*precomputedFaceNormals)[3];
const float (*precomputedLoopNormals)[3];
const MLoopTri *looptris;
const int *looptri_faces;
const blender::int3 *corner_tris;
const int *tri_faces;
const float2 *mloopuv; /* texture coordinates */
blender::OffsetIndices<int> faces;
const int *corner_verts; /* indices */
@ -287,9 +287,9 @@ struct SGLSLMeshToTangent {
blender::Span<bool> sharp_faces;
int numTessFaces;
#ifdef USE_LOOPTRI_DETECT_QUADS
/* map from 'fake' face index to looptris,
* quads will point to the first looptris of the quad */
#ifdef USE_TRI_DETECT_QUADS
/* map from 'fake' face index to corner_tris,
* quads will point to the first corner_tris of the quad */
const int *face_as_quad_map;
int num_face_as_quad_map;
#endif
@ -394,9 +394,9 @@ void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
const blender::OffsetIndices<int> faces,
const int *corner_verts,
const MLoopTri *looptris,
const int *looptri_faces,
const uint looptris_len,
const blender::int3 *corner_tris,
const int *corner_tri_faces,
const uint corner_tris_len,
const blender::Span<bool> sharp_faces,
CustomData *loopdata,
@ -456,33 +456,33 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
loopdata, loopdata_out, int(loopdata_out_len), ren_uv_name);
}
#ifdef USE_LOOPTRI_DETECT_QUADS
#ifdef USE_TRI_DETECT_QUADS
int num_face_as_quad_map;
int *face_as_quad_map = nullptr;
/* map faces to quads */
if (looptris_len != uint(faces.size())) {
if (corner_tris_len != uint(faces.size())) {
/* Over allocate, since we don't know how many ngon or quads we have. */
/* Map fake face index to looptris. */
face_as_quad_map = static_cast<int *>(MEM_mallocN(sizeof(int) * looptris_len, __func__));
/* Map fake face index to corner_tris. */
face_as_quad_map = static_cast<int *>(MEM_mallocN(sizeof(int) * corner_tris_len, __func__));
int k, j;
for (k = 0, j = 0; j < int(looptris_len); k++, j++) {
for (k = 0, j = 0; j < int(corner_tris_len); k++, j++) {
face_as_quad_map[k] = j;
/* step over all quads */
if (faces[looptri_faces[j]].size() == 4) {
j++; /* Skips the next looptri. */
if (faces[corner_tri_faces[j]].size() == 4) {
j++; /* Skips the next corner_tri. */
}
}
num_face_as_quad_map = k;
}
else {
num_face_as_quad_map = int(looptris_len);
num_face_as_quad_map = int(corner_tris_len);
}
#endif
/* Calculation */
if (looptris_len != 0) {
if (corner_tris_len != 0) {
TaskPool *task_pool = BLI_task_pool_create(nullptr, TASK_PRIORITY_HIGH);
tangent_mask_curr = 0;
@ -493,8 +493,8 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
BLI_assert(n < MAX_MTFACE);
SGLSLMeshToTangent *mesh2tangent = &data_array[n];
mesh2tangent->numTessFaces = int(looptris_len);
#ifdef USE_LOOPTRI_DETECT_QUADS
mesh2tangent->numTessFaces = int(corner_tris_len);
#ifdef USE_TRI_DETECT_QUADS
mesh2tangent->face_as_quad_map = face_as_quad_map;
mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
@ -502,8 +502,8 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
mesh2tangent->vert_normals = vert_normals;
mesh2tangent->faces = faces;
mesh2tangent->corner_verts = corner_verts;
mesh2tangent->looptris = looptris;
mesh2tangent->looptri_faces = looptri_faces;
mesh2tangent->corner_tris = corner_tris;
mesh2tangent->tri_faces = corner_tri_faces;
mesh2tangent->sharp_faces = sharp_faces;
/* NOTE: we assume we do have tessellated loop normals at this point
* (in case it is object-enabled), have to check this is valid. */
@ -543,11 +543,11 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
else {
tangent_mask_curr = tangent_mask;
}
#ifdef USE_LOOPTRI_DETECT_QUADS
#ifdef USE_TRI_DETECT_QUADS
if (face_as_quad_map) {
MEM_freeN(face_as_quad_map);
}
# undef USE_LOOPTRI_DETECT_QUADS
# undef USE_TRI_DETECT_QUADS
#endif
@ -583,7 +583,7 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
/* TODO(@ideasman42): store in Mesh.runtime to avoid recalculation. */
using namespace blender;
using namespace blender::bke;
const blender::Span<MLoopTri> looptris = me_eval->looptris();
const blender::Span<int3> corner_tris = me_eval->corner_tris();
const bke::AttributeAccessor attributes = me_eval->attributes();
const VArraySpan sharp_face = *attributes.lookup<bool>("sharp_face", ATTR_DOMAIN_FACE);
short tangent_mask = 0;
@ -591,9 +591,9 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
reinterpret_cast<const float(*)[3]>(me_eval->vert_positions().data()),
me_eval->faces(),
me_eval->corner_verts().data(),
looptris.data(),
me_eval->looptri_faces().data(),
uint(looptris.size()),
corner_tris.data(),
me_eval->corner_tri_faces().data(),
uint(corner_tris.size()),
sharp_face,
&me_eval->loop_data,
calc_active_tangent,

@ -32,7 +32,7 @@ namespace blender::bke::mesh {
/* -------------------------------------------------------------------- */
/** \name Loop Tessellation
*
* Fill in #MLoopTri data-structure.
* Fill in Corner Triangle data-structure.
* \{ */
/**
@ -42,7 +42,7 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
const blender::OffsetIndices<int> faces,
const Span<float3> positions,
uint face_index,
MLoopTri *lt,
int3 *tri,
MemArena **pf_arena_p,
const bool face_normal,
const float normal_precalc[3])
@ -51,9 +51,9 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
const uint mp_totloop = uint(faces[face_index].size());
auto create_tri = [&](uint i1, uint i2, uint i3) {
lt->tri[0] = mp_loopstart + i1;
lt->tri[1] = mp_loopstart + i2;
lt->tri[2] = mp_loopstart + i3;
(*tri)[0] = int(mp_loopstart + i1);
(*tri)[1] = int(mp_loopstart + i2);
(*tri)[2] = int(mp_loopstart + i3);
};
switch (mp_totloop) {
@ -63,17 +63,17 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
}
case 4: {
create_tri(0, 1, 2);
MLoopTri *lt_a = lt++;
int3 *tri_a = tri++;
create_tri(0, 2, 3);
MLoopTri *lt_b = lt;
if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[lt_a->tri[0]]],
positions[corner_verts[lt_a->tri[1]]],
positions[corner_verts[lt_a->tri[2]]],
positions[corner_verts[lt_b->tri[2]]])))
int3 *tri_b = tri;
if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[(*tri_a)[0]]],
positions[corner_verts[(*tri_a)[1]]],
positions[corner_verts[(*tri_a)[2]]],
positions[corner_verts[(*tri_b)[2]]])))
{
/* Flip out of degenerate 0-2 state. */
lt_a->tri[2] = lt_b->tri[2];
lt_b->tri[0] = lt_a->tri[1];
(*tri_a)[2] = (*tri_b)[2];
(*tri_b)[0] = (*tri_a)[1];
}
break;
}
@ -122,9 +122,8 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, pf_arena);
/* Apply fill. */
for (uint j = 0; j < totfilltri; j++, lt++) {
const uint *tri = tris[j];
create_tri(tri[0], tri[1], tri[2]);
for (uint j = 0; j < totfilltri; j++, tri++) {
create_tri(tris[j][0], tris[j][1], tris[j][2]);
}
BLI_memarena_clear(pf_arena);
@ -139,33 +138,33 @@ static void mesh_calc_tessellation_for_face(const Span<int> corner_verts,
const blender::OffsetIndices<int> faces,
const Span<float3> positions,
uint face_index,
MLoopTri *lt,
int3 *tri,
MemArena **pf_arena_p)
{
mesh_calc_tessellation_for_face_impl(
corner_verts, faces, positions, face_index, lt, pf_arena_p, false, nullptr);
corner_verts, faces, positions, face_index, tri, pf_arena_p, false, nullptr);
}
static void mesh_calc_tessellation_for_face_with_normal(const Span<int> corner_verts,
const blender::OffsetIndices<int> faces,
const Span<float3> positions,
uint face_index,
MLoopTri *lt,
int3 *tri,
MemArena **pf_arena_p,
const float normal_precalc[3])
{
mesh_calc_tessellation_for_face_impl(
corner_verts, faces, positions, face_index, lt, pf_arena_p, true, normal_precalc);
corner_verts, faces, positions, face_index, tri, pf_arena_p, true, normal_precalc);
}
static void mesh_recalc_looptris__single_threaded(const Span<int> corner_verts,
const blender::OffsetIndices<int> faces,
const Span<float3> positions,
MLoopTri *looptris,
const float (*face_normals)[3])
static void mesh_recalc_corner_tris__single_threaded(const Span<int> corner_verts,
const blender::OffsetIndices<int> faces,
const Span<float3> positions,
int3 *corner_tris,
const float (*face_normals)[3])
{
MemArena *pf_arena = nullptr;
uint looptri_i = 0;
uint corner_tri_i = 0;
if (face_normals != nullptr) {
for (const int64_t i : faces.index_range()) {
@ -173,17 +172,17 @@ static void mesh_recalc_looptris__single_threaded(const Span<int> corner_verts,
faces,
positions,
uint(i),
&looptris[looptri_i],
&corner_tris[corner_tri_i],
&pf_arena,
face_normals[i]);
looptri_i += uint(faces[i].size() - 2);
corner_tri_i += uint(faces[i].size() - 2);
}
}
else {
for (const int64_t i : faces.index_range()) {
mesh_calc_tessellation_for_face(
corner_verts, faces, positions, uint(i), &looptris[looptri_i], &pf_arena);
looptri_i += uint(faces[i].size() - 2);
corner_verts, faces, positions, uint(i), &corner_tris[corner_tri_i], &pf_arena);
corner_tri_i += uint(faces[i].size() - 2);
}
}
@ -191,7 +190,7 @@ static void mesh_recalc_looptris__single_threaded(const Span<int> corner_verts,
BLI_memarena_free(pf_arena);
pf_arena = nullptr;
}
BLI_assert(looptri_i == uint(poly_to_tri_count(int(faces.size()), int(corner_verts.size()))));
BLI_assert(corner_tri_i == uint(poly_to_tri_count(int(faces.size()), int(corner_verts.size()))));
}
struct TessellationUserData {
@ -200,7 +199,7 @@ struct TessellationUserData {
Span<float3> positions;
/** Output array. */
MutableSpan<MLoopTri> looptris;
MutableSpan<int3> corner_tris;
/** Optional pre-calculated face normals array. */
const float (*face_normals)[3];
@ -216,12 +215,12 @@ static void mesh_calc_tessellation_for_face_fn(void *__restrict userdata,
{
const TessellationUserData *data = static_cast<const TessellationUserData *>(userdata);
TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
const int looptri_i = poly_to_tri_count(index, int(data->faces[index].start()));
const int corner_tri_i = poly_to_tri_count(index, int(data->faces[index].start()));
mesh_calc_tessellation_for_face_impl(data->corner_verts,
data->faces,
data->positions,
uint(index),
&data->looptris[looptri_i],
&data->corner_tris[corner_tri_i],
&tls_data->pf_arena,
false,
nullptr);
@ -233,12 +232,12 @@ static void mesh_calc_tessellation_for_face_with_normal_fn(void *__restrict user
{
const TessellationUserData *data = static_cast<const TessellationUserData *>(userdata);
TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
const int looptri_i = poly_to_tri_count(index, int(data->faces[index].start()));
const int corner_tri_i = poly_to_tri_count(index, int(data->faces[index].start()));
mesh_calc_tessellation_for_face_impl(data->corner_verts,
data->faces,
data->positions,
uint(index),
&data->looptris[looptri_i],
&data->corner_tris[corner_tri_i],
&tls_data->pf_arena,
true,
data->face_normals[index]);
@ -253,18 +252,18 @@ static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict /*use
}
}
static void looptris_calc_all(const Span<float3> positions,
const blender::OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<float3> face_normals,
MutableSpan<MLoopTri> looptris)
static void corner_tris_calc_all(const Span<float3> positions,
const blender::OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<float3> face_normals,
MutableSpan<int3> corner_tris)
{
if (corner_verts.size() < MESH_FACE_TESSELLATE_THREADED_LIMIT) {
mesh_recalc_looptris__single_threaded(
mesh_recalc_corner_tris__single_threaded(
corner_verts,
faces,
positions,
looptris.data(),
corner_tris.data(),
reinterpret_cast<const float(*)[3]>(face_normals.data()));
return;
}
@ -274,7 +273,7 @@ static void looptris_calc_all(const Span<float3> positions,
data.corner_verts = corner_verts;
data.faces = faces;
data.positions = positions;
data.looptris = looptris;
data.corner_tris = corner_tris;
data.face_normals = reinterpret_cast<const float(*)[3]>(face_normals.data());
TaskParallelSettings settings;
@ -293,47 +292,47 @@ static void looptris_calc_all(const Span<float3> positions,
&settings);
}
void looptris_calc(const Span<float3> vert_positions,
const OffsetIndices<int> faces,
const Span<int> corner_verts,
MutableSpan<MLoopTri> looptris)
void corner_tris_calc(const Span<float3> vert_positions,
const OffsetIndices<int> faces,
const Span<int> corner_verts,
MutableSpan<int3> corner_tris)
{
looptris_calc_all(vert_positions, faces, corner_verts, {}, looptris);
corner_tris_calc_all(vert_positions, faces, corner_verts, {}, corner_tris);
}
void looptris_calc_face_indices(const OffsetIndices<int> faces, MutableSpan<int> looptri_faces)
void corner_tris_calc_face_indices(const OffsetIndices<int> faces, MutableSpan<int> tri_faces)
{
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
for (const int64_t i : range) {
const IndexRange face = faces[i];
const int start = poly_to_tri_count(int(i), int(face.start()));
const int num = face_triangles_num(int(face.size()));
looptri_faces.slice(start, num).fill(int(i));
tri_faces.slice(start, num).fill(int(i));
}
});
}
void looptris_calc_with_normals(const Span<float3> vert_positions,
const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<float3> face_normals,
MutableSpan<MLoopTri> looptris)
void corner_tris_calc_with_normals(const Span<float3> vert_positions,
const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<float3> face_normals,
MutableSpan<int3> corner_tris)
{
BLI_assert(!face_normals.is_empty() || faces.is_empty());
looptris_calc_all(vert_positions, faces, corner_verts, face_normals, looptris);
corner_tris_calc_all(vert_positions, faces, corner_verts, face_normals, corner_tris);
}
/** \} */
int3 looptri_get_real_edges(const Span<int2> edges,
const Span<int> corner_verts,
const Span<int> corner_edges,
const MLoopTri &lt)
int3 corner_tri_get_real_edges(const Span<int2> edges,
const Span<int> corner_verts,
const Span<int> corner_edges,
const int3 &corner_tri)
{
int3 real_edges;
for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
const int corner_1 = int(lt.tri[i]);
const int corner_2 = int(lt.tri[i_next]);
const int corner_1 = int(corner_tri[i]);
const int corner_2 = int(corner_tri[i_next]);
const int vert_1 = corner_verts[corner_1];
const int vert_2 = corner_verts[corner_2];
const int edge_i = corner_edges[corner_1];

@ -252,8 +252,8 @@ static int map_insert_vert(Map<int, int> &map,
/* Find vertices used by the faces in this node and update the draw buffers */
static void build_mesh_leaf_node(const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_faces,
const Span<int3> corner_tris,
const Span<int> tri_faces,
const Span<bool> hide_poly,
MutableSpan<bool> vert_bitmap,
PBVHNode *node)
@ -268,10 +268,10 @@ static void build_mesh_leaf_node(const Span<int> corner_verts,
node->face_vert_indices.reinitialize(prim_indices.size());
for (const int i : prim_indices.index_range()) {
const MLoopTri &lt = looptris[prim_indices[i]];
const int3 &tri = corner_tris[prim_indices[i]];
for (int j = 0; j < 3; j++) {
node->face_vert_indices[i][j] = map_insert_vert(
map, vert_bitmap, &node->face_verts, &node->uniq_verts, corner_verts[lt.tri[j]]);
map, vert_bitmap, &node->face_verts, &node->uniq_verts, corner_verts[tri[j]]);
}
}
@ -296,10 +296,9 @@ static void build_mesh_leaf_node(const Span<int> corner_verts,
}
const bool fully_hidden = !hide_poly.is_empty() &&
std::all_of(
prim_indices.begin(), prim_indices.end(), [&](const int tri) {
return hide_poly[looptri_faces[tri]];
});
std::all_of(prim_indices.begin(),
prim_indices.end(),
[&](const int tri) { return hide_poly[tri_faces[tri]]; });
BKE_pbvh_node_fully_hidden_set(node, fully_hidden);
BKE_pbvh_node_mark_rebuild_draw(node);
}
@ -363,8 +362,8 @@ static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
static void build_leaf(PBVH *pbvh,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_faces,
const Span<int3> corner_tris,
const Span<int> tri_faces,
const Span<bool> hide_poly,
MutableSpan<bool> vert_bitmap,
int node_index,
@ -380,8 +379,8 @@ static void build_leaf(PBVH *pbvh,
/* Still need vb for searches */
update_vb(pbvh->prim_indices, &node, prim_bounds, offset, count);
if (!pbvh->looptris.is_empty()) {
build_mesh_leaf_node(corner_verts, looptris, looptri_faces, hide_poly, vert_bitmap, &node);
if (!pbvh->corner_tris.is_empty()) {
build_mesh_leaf_node(corner_verts, corner_tris, tri_faces, hide_poly, vert_bitmap, &node);
}
else {
build_grid_leaf_node(pbvh, &node);
@ -425,7 +424,7 @@ static void test_face_boundaries(PBVH *pbvh, const Mesh &mesh)
}
for (int j = 0; j < node->totprim; j++) {
int face_i = mesh.looptri_faces()[node->prim_indices[j]];
int face_i = mesh.corner_tri_faces()[node->prim_indices[j]];
if (node_map[face_i] >= 0 && node_map[face_i] != i) {
int old_i = node_map[face_i];
@ -459,8 +458,8 @@ static void test_face_boundaries(PBVH *pbvh, const Mesh &mesh)
static void build_sub(PBVH *pbvh,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_faces,
const Span<int3> corner_tris,
const Span<int> tri_faces,
const Span<bool> hide_poly,
const Span<int> material_indices,
const Span<bool> sharp_faces,
@ -474,7 +473,7 @@ static void build_sub(PBVH *pbvh,
int depth)
{
const Span<int> prim_to_face_map = pbvh->header.type == PBVH_FACES ?
looptri_faces :
tri_faces :
pbvh->subdiv_ccg->grid_to_face_map;
int end;
@ -490,8 +489,8 @@ static void build_sub(PBVH *pbvh,
{
build_leaf(pbvh,
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
hide_poly,
vert_bitmap,
node_index,
@ -551,8 +550,8 @@ static void build_sub(PBVH *pbvh,
/* Build children */
build_sub(pbvh,
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
hide_poly,
material_indices,
sharp_faces,
@ -566,8 +565,8 @@ static void build_sub(PBVH *pbvh,
depth + 1);
build_sub(pbvh,
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
hide_poly,
material_indices,
sharp_faces,
@ -587,8 +586,8 @@ static void build_sub(PBVH *pbvh,
static void pbvh_build(PBVH *pbvh,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_faces,
const Span<int3> corner_tris,
const Span<int> tri_faces,
const Span<bool> hide_poly,
const Span<int> material_indices,
const Span<bool> sharp_faces,
@ -609,8 +608,8 @@ static void pbvh_build(PBVH *pbvh,
build_sub(pbvh,
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
hide_poly,
material_indices,
sharp_faces,
@ -625,7 +624,7 @@ static void pbvh_build(PBVH *pbvh,
}
#ifdef VALIDATE_UNIQUE_NODE_FACES
static void pbvh_validate_node_prims(PBVH *pbvh, const Span<int> looptri_faces)
static void pbvh_validate_node_prims(PBVH *pbvh, const Span<int> tri_faces)
{
int totface = 0;
@ -644,7 +643,7 @@ static void pbvh_validate_node_prims(PBVH *pbvh, const Span<int> looptri_faces)
int face_i;
if (pbvh->header.type == PBVH_FACES) {
face_i = looptri_faces[node->prim_indices[j]];
face_i = tri_faces[node->prim_indices[j]];
}
else {
face_i = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
@ -671,7 +670,7 @@ static void pbvh_validate_node_prims(PBVH *pbvh, const Span<int> looptri_faces)
int face_i;
if (pbvh->header.type == PBVH_FACES) {
face_i = looptri_faces[node->prim_indices[j]];
face_i = tri_faces[node->prim_indices[j]];
}
else {
face_i = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
@ -696,7 +695,7 @@ void update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
BLI_assert(pbvh->header.type == PBVH_FACES);
pbvh->faces = mesh->faces();
pbvh->corner_verts = mesh->corner_verts();
pbvh->looptri_faces = mesh->looptri_faces();
pbvh->corner_tri_faces = mesh->corner_tri_faces();
if (!pbvh->deformed) {
/* Deformed data not matching the original mesh are owned directly by the PBVH, and are
* set separately by #BKE_pbvh_vert_coords_apply. */
@ -712,19 +711,19 @@ PBVH *build_mesh(Mesh *mesh)
pbvh->header.type = PBVH_FACES;
const int totvert = mesh->totvert;
const int looptris_num = poly_to_tri_count(mesh->faces_num, mesh->totloop);
const int corner_tris_num = poly_to_tri_count(mesh->faces_num, mesh->totloop);
MutableSpan<float3> vert_positions = mesh->vert_positions_for_write();
const OffsetIndices<int> faces = mesh->faces();
const Span<int> corner_verts = mesh->corner_verts();
pbvh->looptris.reinitialize(looptris_num);
mesh::looptris_calc(vert_positions, faces, corner_verts, pbvh->looptris);
const Span<MLoopTri> looptris = pbvh->looptris;
pbvh->corner_tris.reinitialize(corner_tris_num);
mesh::corner_tris_calc(vert_positions, faces, corner_verts, pbvh->corner_tris);
const Span<int3> corner_tris = pbvh->corner_tris;
pbvh->mesh = mesh;
update_mesh_pointers(pbvh.get(), mesh);
const Span<int> looptri_faces = pbvh->looptri_faces;
const Span<int> tri_faces = pbvh->corner_tri_faces;
pbvh->vert_bitmap = blender::Array<bool>(totvert, false);
pbvh->totvert = totvert;
@ -739,19 +738,19 @@ PBVH *build_mesh(Mesh *mesh)
#endif
/* For each face, store the AABB and the AABB centroid */
Array<Bounds<float3>> prim_bounds(looptris_num);
Array<Bounds<float3>> prim_bounds(corner_tris_num);
const Bounds<float3> cb = threading::parallel_reduce(
looptris.index_range(),
corner_tris.index_range(),
1024,
negative_bounds(),
[&](const IndexRange range, const Bounds<float3> &init) {
Bounds<float3> current = init;
for (const int i : range) {
const MLoopTri &lt = looptris[i];
const int3 &tri = corner_tris[i];
Bounds<float3> &bounds = prim_bounds[i];
bounds = {vert_positions[corner_verts[lt.tri[0]]]};
math::min_max(vert_positions[corner_verts[lt.tri[1]]], bounds.min, bounds.max);
math::min_max(vert_positions[corner_verts[lt.tri[2]]], bounds.min, bounds.max);
bounds = {vert_positions[corner_verts[tri[0]]]};
math::min_max(vert_positions[corner_verts[tri[1]]], bounds.min, bounds.max);
math::min_max(vert_positions[corner_verts[tri[2]]], bounds.min, bounds.max);
const float3 center = math::midpoint(prim_bounds[i].min, prim_bounds[i].max);
math::min_max(center, current.min, current.max);
}
@ -759,25 +758,25 @@ PBVH *build_mesh(Mesh *mesh)
},
[](const Bounds<float3> &a, const Bounds<float3> &b) { return bounds::merge(a, b); });
if (looptris_num) {
if (corner_tris_num) {
const AttributeAccessor attributes = mesh->attributes();
const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", ATTR_DOMAIN_FACE);
const VArraySpan material_index = *attributes.lookup<int>("material_index", ATTR_DOMAIN_FACE);
const VArraySpan sharp_face = *attributes.lookup<bool>("sharp_face", ATTR_DOMAIN_FACE);
pbvh_build(pbvh.get(),
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
hide_poly,
material_index,
sharp_face,
pbvh->vert_bitmap,
&cb,
prim_bounds,
looptris_num);
corner_tris_num);
#ifdef TEST_PBVH_FACE_SPLIT
test_face_boundaries(pbvh, looptri_faces);
test_face_boundaries(pbvh, tri_faces);
#endif
}
@ -1755,10 +1754,10 @@ namespace blender::bke::pbvh {
Span<int> node_face_indices_calc_mesh(const PBVH &pbvh, const PBVHNode &node, Vector<int> &faces)
{
faces.clear();
const Span<int> looptri_faces = pbvh.looptri_faces;
const Span<int> tri_faces = pbvh.corner_tri_faces;
int prev_face = -1;
for (const int tri : node.prim_indices) {
const int face = looptri_faces[tri];
const int face = tri_faces[tri];
if (face != prev_face) {
faces.append(face);
prev_face = face;
@ -2025,16 +2024,17 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
int *r_active_face_index,
float *r_face_normal)
{
using namespace blender;
const Span<float3> positions = pbvh->vert_positions;
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
for (const int i : node->prim_indices.index_range()) {
const int looptri_i = node->prim_indices[i];
const MLoopTri *lt = &pbvh->looptris[looptri_i];
const int tri_i = node->prim_indices[i];
const int3 &tri = pbvh->corner_tris[tri_i];
const int3 face_verts = node->face_vert_indices[i];
if (!hide_poly.is_empty() && hide_poly[pbvh->looptri_faces[looptri_i]]) {
if (!hide_poly.is_empty() && hide_poly[pbvh->corner_tri_faces[tri_i]]) {
continue;
}
@ -2047,9 +2047,9 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
}
else {
/* intersect with current coordinates */
co[0] = positions[corner_verts[lt->tri[0]]];
co[1] = positions[corner_verts[lt->tri[1]]];
co[2] = positions[corner_verts[lt->tri[2]]];
co[0] = positions[corner_verts[tri[0]]];
co[1] = positions[corner_verts[tri[1]]];
co[2] = positions[corner_verts[tri[2]]];
}
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
@ -2069,8 +2069,8 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
if (j == 0 ||
len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
r_active_vertex->i = corner_verts[lt->tri[j]];
*r_active_face_index = pbvh->looptri_faces[looptri_i];
r_active_vertex->i = corner_verts[tri[j]];
*r_active_face_index = pbvh->corner_tri_faces[tri_i];
}
}
}
@ -2376,15 +2376,16 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
float *depth,
float *dist_sq)
{
using namespace blender;
const Span<float3> positions = pbvh->vert_positions;
bool hit = false;
for (const int i : node->prim_indices.index_range()) {
const int looptri_i = node->prim_indices[i];
const MLoopTri *lt = &pbvh->looptris[looptri_i];
const int tri_i = node->prim_indices[i];
const int3 &corner_tri = pbvh->corner_tris[tri_i];
const int3 face_verts = node->face_vert_indices[i];
if (!hide_poly.is_empty() && hide_poly[pbvh->looptri_faces[looptri_i]]) {
if (!hide_poly.is_empty() && hide_poly[pbvh->corner_tri_faces[tri_i]]) {
continue;
}
@ -2402,9 +2403,9 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
/* intersect with current coordinates */
hit |= ray_face_nearest_tri(ray_start,
ray_normal,
positions[corner_verts[lt->tri[0]]],
positions[corner_verts[lt->tri[1]]],
positions[corner_verts[lt->tri[2]]],
positions[corner_verts[corner_tri[0]]],
positions[corner_verts[corner_tri[1]]],
positions[corner_verts[corner_tri[2]]],
depth,
dist_sq);
}
@ -2588,7 +2589,7 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh,
args.vert_positions = pbvh.vert_positions;
args.corner_verts = mesh.corner_verts();
args.corner_edges = mesh.corner_edges();
args.looptris = pbvh.looptris;
args.corner_tris = pbvh.corner_tris;
args.vert_normals = pbvh.vert_normals;
args.face_normals = pbvh.face_normals;
/* Retrieve data from the original mesh. Ideally that would be passed to this function to
@ -2596,7 +2597,7 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh,
args.hide_poly = *pbvh.mesh->attributes().lookup<bool>(".hide_poly", ATTR_DOMAIN_FACE);
args.prim_indices = node.prim_indices;
args.looptri_faces = mesh.looptri_faces();
args.tri_faces = mesh.corner_tri_faces();
break;
case PBVH_GRIDS:
args.vert_data = &pbvh.mesh->vert_data;
@ -3045,6 +3046,7 @@ void BKE_pbvh_pmap_set(PBVH *pbvh, const blender::GroupedSpan<int> pmap)
void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
{
using namespace blender;
BLI_assert(BKE_pbvh_type(pbvh) == PBVH_FACES);
int totloop = 0;
@ -3074,12 +3076,12 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
loop_indices.clear();
for (const int i : node.prim_indices) {
const MLoopTri &lt = pbvh->looptris[i];
const int3 &tri = pbvh->corner_tris[i];
for (int k = 0; k < 3; k++) {
if (!BLI_BITMAP_TEST(visit, lt.tri[k])) {
loop_indices.append(lt.tri[k]);
BLI_BITMAP_ENABLE(visit, lt.tri[k]);
if (!BLI_BITMAP_TEST(visit, tri[k])) {
loop_indices.append(tri[k]);
BLI_BITMAP_ENABLE(visit, tri[k]);
}
}
}

@ -22,7 +22,6 @@ struct PBVHBatches;
}
struct PBVHGPUFormat;
struct MLoopTri;
struct BMVert;
struct BMFace;
@ -43,7 +42,7 @@ struct PBVHNode {
/* List of primitives for this node. Semantics depends on
* PBVH type:
*
* - PBVH_FACES: Indices into the #PBVH::looptris array.
* - PBVH_FACES: Indices into the #PBVH::corner_tris array.
* - PBVH_GRIDS: Multires grid indices.
* - PBVH_BMESH: Unused. See PBVHNode.bm_faces.
*
@ -84,7 +83,7 @@ struct PBVHNode {
* array. The array is sized to match 'totprim', and each of
* the face's corners gets an index into the vert_indices
* array, in the same order as the corners in the original
* MLoopTri.
* triangle.
*
* Used for leaf nodes in a mesh-based PBVH (not multires.)
*/
@ -157,8 +156,8 @@ struct PBVH {
blender::OffsetIndices<int> faces;
blender::Span<int> corner_verts;
/* Owned by the #PBVH, because after deformations they have to be recomputed. */
blender::Array<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Array<blender::int3> corner_tris;
blender::Span<int> corner_tri_faces;
/* Grid Data */
CCGKey gridkey;

@ -418,10 +418,10 @@ static void update_geom_primitives(PBVH &pbvh, const uv_islands::MeshData &mesh_
{
PBVHData &pbvh_data = data_get(pbvh);
pbvh_data.clear_data();
for (const MLoopTri &lt : mesh_data.looptris) {
pbvh_data.geom_primitives.append(int3(mesh_data.corner_verts[lt.tri[0]],
mesh_data.corner_verts[lt.tri[1]],
mesh_data.corner_verts[lt.tri[2]]));
for (const int3 &tri : mesh_data.corner_tris) {
pbvh_data.geom_primitives.append(int3(mesh_data.corner_verts[tri[0]],
mesh_data.corner_verts[tri[1]],
mesh_data.corner_verts[tri[2]]));
}
}
@ -673,7 +673,7 @@ static bool update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
const VArraySpan uv_map = *attributes.lookup<float2>(active_uv_name, ATTR_DOMAIN_CORNER);
uv_islands::MeshData mesh_data(
pbvh->looptris, mesh->corner_verts(), uv_map, pbvh->vert_positions);
pbvh->corner_tris, mesh->corner_verts(), uv_map, pbvh->vert_positions);
uv_islands::UVIslands islands(mesh_data);
uv_islands::UVIslandsMask uv_masks;
@ -696,7 +696,7 @@ static bool update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
islands.extend_borders(mesh_data, uv_masks);
update_geom_primitives(*pbvh, mesh_data);
UVPrimitiveLookup uv_primitive_lookup(mesh_data.looptris.size(), islands);
UVPrimitiveLookup uv_primitive_lookup(mesh_data.corner_tris.size(), islands);
EncodePixelsUserData user_data;
user_data.mesh_data = &mesh_data;

@ -104,17 +104,17 @@ class NonManifoldUVEdges : public Vector<Edge<CoordSpace::UV>> {
{
int num_non_manifold_edges = count_non_manifold_edges(mesh_data);
reserve(num_non_manifold_edges);
for (const int primitive_id : mesh_data.looptris.index_range()) {
for (const int primitive_id : mesh_data.corner_tris.index_range()) {
for (const int edge_id : mesh_data.primitive_to_edge_map[primitive_id]) {
if (is_manifold(mesh_data, edge_id)) {
continue;
}
const MLoopTri &lt = mesh_data.looptris[primitive_id];
const int3 &tri = mesh_data.corner_tris[primitive_id];
const uv_islands::MeshEdge &mesh_edge = mesh_data.edges[edge_id];
Edge<CoordSpace::UV> edge;
edge.vertex_1.coordinate = find_uv(mesh_data, lt, mesh_edge.vert1);
edge.vertex_2.coordinate = find_uv(mesh_data, lt, mesh_edge.vert2);
edge.vertex_1.coordinate = find_uv(mesh_data, tri, mesh_edge.vert1);
edge.vertex_2.coordinate = find_uv(mesh_data, tri, mesh_edge.vert2);
append(edge);
}
}
@ -138,7 +138,7 @@ class NonManifoldUVEdges : public Vector<Edge<CoordSpace::UV>> {
static int64_t count_non_manifold_edges(const uv_islands::MeshData &mesh_data)
{
int64_t result = 0;
for (const int primitive_id : mesh_data.looptris.index_range()) {
for (const int primitive_id : mesh_data.corner_tris.index_range()) {
for (const int edge_id : mesh_data.primitive_to_edge_map[primitive_id]) {
if (is_manifold(mesh_data, edge_id)) {
continue;
@ -154,10 +154,10 @@ class NonManifoldUVEdges : public Vector<Edge<CoordSpace::UV>> {
return mesh_data.edge_to_primitive_map[edge_id].size() == 2;
}
static float2 find_uv(const uv_islands::MeshData &mesh_data, const MLoopTri &lt, int vertex_i)
static float2 find_uv(const uv_islands::MeshData &mesh_data, const int3 &tri, int vertex_i)
{
for (int i = 0; i < 3; i++) {
const int loop_i = lt.tri[i];
const int loop_i = tri[i];
const int vert = mesh_data.corner_verts[loop_i];
if (vert == vertex_i) {
return mesh_data.uv_map[loop_i];

@ -42,14 +42,14 @@ static void uv_primitive_append_to_uv_vertices(UVPrimitive &uv_primitive)
* \{ */
static int primitive_get_other_uv_vertex(const MeshData &mesh_data,
const MLoopTri &lt,
const int3 &tri,
const int v1,
const int v2)
{
const Span<int> corner_verts = mesh_data.corner_verts;
BLI_assert(ELEM(v1, corner_verts[lt.tri[0]], corner_verts[lt.tri[1]], corner_verts[lt.tri[2]]));
BLI_assert(ELEM(v2, corner_verts[lt.tri[0]], corner_verts[lt.tri[1]], corner_verts[lt.tri[2]]));
for (const int loop : lt.tri) {
BLI_assert(ELEM(v1, corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]));
BLI_assert(ELEM(v2, corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]));
for (const int loop : {tri[0], tri[1], tri[2]}) {
const int vert = corner_verts[loop];
if (!ELEM(vert, v1, v2)) {
return vert;
@ -59,12 +59,12 @@ static int primitive_get_other_uv_vertex(const MeshData &mesh_data,
}
static bool primitive_has_shared_uv_edge(const Span<float2> uv_map,
const MLoopTri &lt,
const MLoopTri &lt_other)
const int3 &tri,
const int3 &tri_other)
{
int shared_uv_verts = 0;
for (const int loop : lt.tri) {
for (const int other_loop : lt_other.tri) {
for (const int loop : {tri[0], tri[1], tri[2]}) {
for (const int other_loop : {tri_other[0], tri_other[1], tri_other[2]}) {
if (uv_map[loop] == uv_map[other_loop]) {
shared_uv_verts += 1;
}
@ -73,22 +73,22 @@ static bool primitive_has_shared_uv_edge(const Span<float2> uv_map,
return shared_uv_verts >= 2;
}
static int get_uv_loop(const MeshData &mesh_data, const MLoopTri &lt, const int vert)
static int get_uv_loop(const MeshData &mesh_data, const int3 &tri, const int vert)
{
for (const int loop : lt.tri) {
for (const int loop : {tri[0], tri[1], tri[2]}) {
if (mesh_data.corner_verts[loop] == vert) {
return loop;
}
}
BLI_assert_unreachable();
return lt.tri[0];
return tri[0];
}
static rctf primitive_uv_bounds(const MLoopTri &lt, const Span<float2> uv_map)
static rctf primitive_uv_bounds(const int3 &tri, const Span<float2> uv_map)
{
rctf result;
BLI_rctf_init_minmax(&result);
for (const int loop : lt.tri) {
for (const int loop : {tri[0], tri[1], tri[2]}) {
BLI_rctf_do_minmax_v(&result, uv_map[loop]);
}
return result;
@ -102,15 +102,15 @@ static rctf primitive_uv_bounds(const MLoopTri &lt, const Span<float2> uv_map)
static void mesh_data_init_edges(MeshData &mesh_data)
{
mesh_data.edges.reserve(mesh_data.looptris.size() * 2);
mesh_data.edges.reserve(mesh_data.corner_tris.size() * 2);
Map<OrderedEdge, int> eh;
eh.reserve(mesh_data.looptris.size() * 3);
for (int64_t i = 0; i < mesh_data.looptris.size(); i++) {
const MLoopTri &lt = mesh_data.looptris[i];
eh.reserve(mesh_data.corner_tris.size() * 3);
for (int64_t i = 0; i < mesh_data.corner_tris.size(); i++) {
const int3 &tri = mesh_data.corner_tris[i];
Vector<int, 3> edges;
for (int j = 0; j < 3; j++) {
int v1 = mesh_data.corner_verts[lt.tri[j]];
int v2 = mesh_data.corner_verts[lt.tri[(j + 1) % 3]];
int v1 = mesh_data.corner_verts[tri[j]];
int v2 = mesh_data.corner_verts[tri[(j + 1) % 3]];
int64_t edge_index;
eh.add_or_modify(
@ -132,7 +132,7 @@ static void mesh_data_init_edges(MeshData &mesh_data)
}
/* Build edge to neighboring triangle map. */
mesh_data.edge_to_primitive_map = EdgeToPrimitiveMap(mesh_data.edges.size());
for (const int prim_i : mesh_data.looptris.index_range()) {
for (const int prim_i : mesh_data.corner_tris.index_range()) {
for (const int edge_i : mesh_data.primitive_to_edge_map[prim_i]) {
mesh_data.edge_to_primitive_map.add(prim_i, edge_i);
}
@ -158,8 +158,8 @@ static void extract_uv_neighbors(const MeshData &mesh_data,
}
if (primitive_has_shared_uv_edge(mesh_data.uv_map,
mesh_data.looptris[primitive_i],
mesh_data.looptris[other_primitive_i]))
mesh_data.corner_tris[primitive_i],
mesh_data.corner_tris[other_primitive_i]))
{
prims_to_add.append(other_primitive_i);
}
@ -169,12 +169,12 @@ static void extract_uv_neighbors(const MeshData &mesh_data,
static int mesh_data_init_primitive_uv_island_ids(MeshData &mesh_data)
{
mesh_data.uv_island_ids.reinitialize(mesh_data.looptris.size());
mesh_data.uv_island_ids.reinitialize(mesh_data.corner_tris.size());
mesh_data.uv_island_ids.fill(INVALID_UV_ISLAND_ID);
int uv_island_id = 0;
Vector<int> prims_to_add;
for (const int primitive_i : mesh_data.looptris.index_range()) {
for (const int primitive_i : mesh_data.corner_tris.index_range()) {
/* Early exit when uv island id is already extracted during uv neighbor extractions. */
if (mesh_data.uv_island_ids[primitive_i] != INVALID_UV_ISLAND_ID) {
continue;
@ -198,17 +198,17 @@ static void mesh_data_init(MeshData &mesh_data)
mesh_data.uv_island_len = mesh_data_init_primitive_uv_island_ids(mesh_data);
}
MeshData::MeshData(const Span<MLoopTri> looptris,
MeshData::MeshData(const Span<int3> corner_tris,
const Span<int> corner_verts,
const Span<float2> uv_map,
const Span<float3> vert_positions)
: looptris(looptris),
: corner_tris(corner_tris),
corner_verts(corner_verts),
uv_map(uv_map),
vert_positions(vert_positions),
vert_to_edge_map(vert_positions.size()),
edge_to_primitive_map(0),
primitive_to_edge_map(looptris.size())
primitive_to_edge_map(corner_tris.size())
{
mesh_data_init(*this);
}
@ -420,13 +420,13 @@ static UVPrimitive *add_primitive(const MeshData &mesh_data,
const int primitive_i)
{
UVPrimitive uv_primitive(primitive_i);
const MLoopTri &lt_primitive = mesh_data.looptris[primitive_i];
const int3 &tri = mesh_data.corner_tris[primitive_i];
uv_island.uv_primitives.append(uv_primitive);
UVPrimitive *uv_primitive_ptr = &uv_island.uv_primitives.last();
for (const int edge_i : mesh_data.primitive_to_edge_map[primitive_i]) {
const MeshEdge &edge = mesh_data.edges[edge_i];
const int loop_1 = get_uv_loop(mesh_data, lt_primitive, edge.vert1);
const int loop_2 = get_uv_loop(mesh_data, lt_primitive, edge.vert2);
const int loop_1 = get_uv_loop(mesh_data, tri, edge.vert1);
const int loop_2 = get_uv_loop(mesh_data, tri, edge.vert2);
UVEdge uv_edge_template;
uv_edge_template.vertices[0] = uv_island.lookup_or_create(UVVertex(mesh_data, loop_1));
uv_edge_template.vertices[1] = uv_island.lookup_or_create(UVVertex(mesh_data, loop_2));
@ -501,8 +501,8 @@ static std::optional<UVBorderCorner> sharpest_border_corner(UVIsland &island)
/** The inner edge of a fan. */
struct FanSegment {
const int primitive_index;
const MLoopTri *lt_primitive;
int primitive_index;
int3 tri;
/* UVs order are already applied. So `uvs[0]` matches `primitive->vertices[vert_order[0]]`. */
float2 uvs[3];
int vert_order[3];
@ -511,27 +511,24 @@ struct FanSegment {
bool found : 1;
} flags;
FanSegment(const MeshData &mesh_data,
const int primitive_index,
const MLoopTri *lt_primitive,
int vertex)
: primitive_index(primitive_index), lt_primitive(lt_primitive)
FanSegment(const MeshData &mesh_data, const int primitive_index, const int3 tri, int vertex)
: primitive_index(primitive_index), tri(tri)
{
flags.found = false;
/* Reorder so the first edge starts with the given vertex. */
if (mesh_data.corner_verts[lt_primitive->tri[1]] == vertex) {
if (mesh_data.corner_verts[tri[1]] == vertex) {
vert_order[0] = 1;
vert_order[1] = 2;
vert_order[2] = 0;
}
else if (mesh_data.corner_verts[lt_primitive->tri[2]] == vertex) {
else if (mesh_data.corner_verts[tri[2]] == vertex) {
vert_order[0] = 2;
vert_order[1] = 0;
vert_order[2] = 1;
}
else {
BLI_assert(mesh_data.corner_verts[lt_primitive->tri[0]] == vertex);
BLI_assert(mesh_data.corner_verts[tri[0]] == vertex);
vert_order[0] = 0;
vert_order[1] = 1;
vert_order[2] = 2;
@ -541,9 +538,9 @@ struct FanSegment {
void print_debug(const MeshData &mesh_data) const
{
std::stringstream ss;
ss << " v1:" << mesh_data.corner_verts[lt_primitive->tri[vert_order[0]]];
ss << " v2:" << mesh_data.corner_verts[lt_primitive->tri[vert_order[1]]];
ss << " v3:" << mesh_data.corner_verts[lt_primitive->tri[vert_order[2]]];
ss << " v1:" << mesh_data.corner_verts[tri[vert_order[0]]];
ss << " v2:" << mesh_data.corner_verts[tri[vert_order[1]]];
ss << " v3:" << mesh_data.corner_verts[tri[vert_order[2]]];
ss << " uv1:" << uvs[0];
ss << " uv2:" << uvs[1];
ss << " uv3:" << uvs[2];
@ -584,14 +581,14 @@ struct Fan {
continue;
}
const MLoopTri &other_lt = mesh_data.looptris[other_primitive_i];
const int3 &other_tri = mesh_data.corner_tris[other_primitive_i];
for (const int edge_i : mesh_data.primitive_to_edge_map[other_primitive_i]) {
const MeshEdge &edge = mesh_data.edges[edge_i];
if (edge_i == current_edge || (edge.vert1 != vertex && edge.vert2 != vertex)) {
continue;
}
segments.append(FanSegment(mesh_data, other_primitive_i, &other_lt, vertex));
segments.append(FanSegment(mesh_data, other_primitive_i, other_tri, vertex));
current_edge = edge_i;
previous_primitive = other_primitive_i;
stop = true;
@ -632,9 +629,9 @@ struct Fan {
void init_uv_coordinates(const MeshData &mesh_data, UVVertex &uv_vertex)
{
for (FanSegment &fan_edge : segments) {
int other_v = mesh_data.corner_verts[fan_edge.lt_primitive->tri[fan_edge.vert_order[0]]];
int other_v = mesh_data.corner_verts[fan_edge.tri[fan_edge.vert_order[0]]];
if (other_v == uv_vertex.vertex) {
other_v = mesh_data.corner_verts[fan_edge.lt_primitive->tri[fan_edge.vert_order[1]]];
other_v = mesh_data.corner_verts[fan_edge.tri[fan_edge.vert_order[1]]];
}
for (UVEdge *edge : uv_vertex.uv_edges) {
@ -662,7 +659,7 @@ struct Fan {
bool contains_vertex_on_outside(const MeshData &mesh_data, const int vertex_index) const
{
for (const FanSegment &segment : segments) {
int v2 = mesh_data.corner_verts[segment.lt_primitive->tri[segment.vert_order[1]]];
int v2 = mesh_data.corner_verts[segment.tri[segment.vert_order[1]]];
if (vertex_index == v2) {
return true;
}
@ -679,8 +676,8 @@ struct Fan {
{
int current_vert = from_vertex;
for (FanSegment *segment : path) {
int v1 = mesh_data.corner_verts[segment->lt_primitive->tri[segment->vert_order[1]]];
int v2 = mesh_data.corner_verts[segment->lt_primitive->tri[segment->vert_order[2]]];
int v1 = mesh_data.corner_verts[segment->tri[segment->vert_order[1]]];
int v2 = mesh_data.corner_verts[segment->tri[segment->vert_order[2]]];
if (!ELEM(current_vert, v1, v2)) {
return false;
}
@ -710,8 +707,7 @@ struct Fan {
int index = 0;
while (true) {
FanSegment *segment = edge_order[index];
int v2 =
mesh_data.corner_verts[segment->lt_primitive->tri[segment->vert_order[from_vert_order]]];
int v2 = mesh_data.corner_verts[segment->tri[segment->vert_order[from_vert_order]]];
if (v2 == from_vertex) {
break;
}
@ -722,8 +718,7 @@ struct Fan {
FanSegment *segment = edge_order[index];
result.append(segment);
int v3 =
mesh_data.corner_verts[segment->lt_primitive->tri[segment->vert_order[to_vert_order]]];
int v3 = mesh_data.corner_verts[segment->tri[segment->vert_order[to_vert_order]]];
if (v3 == to_vertex) {
break;
}
@ -807,21 +802,21 @@ static void add_uv_primitive_shared_uv_edge(const MeshData &mesh_data,
const int mesh_primitive_i)
{
UVPrimitive prim1(mesh_primitive_i);
const MLoopTri &lt = mesh_data.looptris[mesh_primitive_i];
const int3 &tri = mesh_data.corner_tris[mesh_primitive_i];
const int other_vert_i = primitive_get_other_uv_vertex(
mesh_data, lt, connected_vert_1->vertex, connected_vert_2->vertex);
mesh_data, tri, connected_vert_1->vertex, connected_vert_2->vertex);
UVVertex vert_template;
vert_template.uv = uv_unconnected;
vert_template.vertex = other_vert_i;
UVVertex *vert_ptr = island.lookup_or_create(vert_template);
const int loop_1 = get_uv_loop(mesh_data, lt, connected_vert_1->vertex);
const int loop_1 = get_uv_loop(mesh_data, tri, connected_vert_1->vertex);
vert_template.uv = connected_vert_1->uv;
vert_template.vertex = mesh_data.corner_verts[loop_1];
UVVertex *vert_1_ptr = island.lookup_or_create(vert_template);
const int loop_2 = get_uv_loop(mesh_data, lt, connected_vert_2->vertex);
const int loop_2 = get_uv_loop(mesh_data, tri, connected_vert_2->vertex);
vert_template.uv = connected_vert_2->uv;
vert_template.vertex = mesh_data.corner_verts[loop_2];
UVVertex *vert_2_ptr = island.lookup_or_create(vert_template);
@ -857,9 +852,9 @@ static int find_fill_primitive(const MeshData &mesh_data, UVBorderCorner &corner
const MeshEdge &edge = mesh_data.edges[edge_i];
if (corner.first->edge->has_same_vertices(edge)) {
for (const int primitive_i : mesh_data.edge_to_primitive_map[edge_i]) {
const MLoopTri &lt = mesh_data.looptris[primitive_i];
const int3 &tri = mesh_data.corner_tris[primitive_i];
const int other_vert = primitive_get_other_uv_vertex(
mesh_data, lt, edge.vert1, edge.vert2);
mesh_data, tri, edge.vert1, edge.vert2);
if (other_vert == corner.second->get_uv_vertex(1)->vertex) {
return primitive_i;
}
@ -922,7 +917,7 @@ static void extend_at_vert(const MeshData &mesh_data,
* When all edges are already added and its winding solution contains one segment to be added,
* the segment should be split into two segments in order one for both sides.
*
* Although the lt_fill_primitive can fill the missing segment it could lead to a squashed
* Although the tri_fill can fill the missing segment it could lead to a squashed
* triangle when the corner angle is near 180 degrees. In order to fix this we will
* always add two segments both using the same fill primitive.
*/
@ -987,9 +982,9 @@ static void extend_at_vert(const MeshData &mesh_data,
FanSegment &segment = *winding_solution[segment_index];
const int fill_primitive_i = segment.primitive_index;
const MLoopTri &lt_fill_primitive = mesh_data.looptris[fill_primitive_i];
const int3 &tri_fill = mesh_data.corner_tris[fill_primitive_i];
const int other_prim_vertex = primitive_get_other_uv_vertex(
mesh_data, lt_fill_primitive, uv_vertex->vertex, shared_edge_vertex);
mesh_data, tri_fill, uv_vertex->vertex, shared_edge_vertex);
UVVertex uv_vertex_template;
uv_vertex_template.vertex = uv_vertex->vertex;
@ -1316,10 +1311,10 @@ bool UVPrimitive::has_shared_edge(const UVPrimitive &other) const
bool UVPrimitive::has_shared_edge(const MeshData &mesh_data, const int primitive_i) const
{
for (const UVEdge *uv_edge : edges) {
const MLoopTri &lt_primitive = mesh_data.looptris[primitive_i];
int loop_1 = lt_primitive.tri[2];
const int3 &tri = mesh_data.corner_tris[primitive_i];
int loop_1 = tri[2];
for (int i = 0; i < 3; i++) {
int loop_2 = lt_primitive.tri[i];
int loop_2 = tri[i];
if (uv_edge->has_shared_edge(mesh_data.uv_map, loop_1, loop_2)) {
return true;
}
@ -1332,8 +1327,8 @@ bool UVPrimitive::has_shared_edge(const MeshData &mesh_data, const int primitive
const UVVertex *UVPrimitive::get_uv_vertex(const MeshData &mesh_data,
const uint8_t mesh_vert_index) const
{
const MLoopTri &lt = mesh_data.looptris[this->primitive_i];
const int mesh_vertex = mesh_data.corner_verts[lt.tri[mesh_vert_index]];
const int3 &tri = mesh_data.corner_tris[this->primitive_i];
const int mesh_vertex = mesh_data.corner_verts[tri[mesh_vert_index]];
for (const UVEdge *uv_edge : edges) {
for (const UVVertex *uv_vert : uv_edge->vertices) {
if (uv_vert->vertex == mesh_vertex) {
@ -1455,7 +1450,7 @@ UVIslands::UVIslands(const MeshData &mesh_data)
islands.append_as(UVIsland());
UVIsland *uv_island = &islands.last();
uv_island->id = uv_island_id;
for (const int primitive_i : mesh_data.looptris.index_range()) {
for (const int primitive_i : mesh_data.corner_tris.index_range()) {
if (mesh_data.uv_island_ids[primitive_i] == uv_island_id) {
add_primitive(mesh_data, *uv_island, primitive_i);
}
@ -1523,9 +1518,9 @@ static void add_uv_island(const MeshData &mesh_data,
{
for (const VectorList<UVPrimitive>::UsedVector &uv_primitives : uv_island.uv_primitives) {
for (const UVPrimitive &uv_primitive : uv_primitives) {
const MLoopTri &lt = mesh_data.looptris[uv_primitive.primitive_i];
const int3 &tri = mesh_data.corner_tris[uv_primitive.primitive_i];
rctf uv_bounds = primitive_uv_bounds(lt, mesh_data.uv_map);
rctf uv_bounds = primitive_uv_bounds(tri, mesh_data.uv_map);
rcti buffer_bounds;
buffer_bounds.xmin = max_ii(
floor((uv_bounds.xmin - tile.udim_offset.x) * tile.mask_resolution.x), 0);
@ -1542,9 +1537,9 @@ static void add_uv_island(const MeshData &mesh_data,
for (int x = buffer_bounds.xmin; x < buffer_bounds.xmax + 1; x++) {
float2 uv(float(x) / tile.mask_resolution.x, float(y) / tile.mask_resolution.y);
float3 weights;
barycentric_weights_v2(mesh_data.uv_map[lt.tri[0]],
mesh_data.uv_map[lt.tri[1]],
mesh_data.uv_map[lt.tri[2]],
barycentric_weights_v2(mesh_data.uv_map[tri[0]],
mesh_data.uv_map[tri[1]],
mesh_data.uv_map[tri[2]],
uv + tile.udim_offset,
weights);
if (!barycentric_inside_triangle_v2(weights)) {

@ -118,7 +118,7 @@ class TriangleToEdgeMap {
*/
struct MeshData {
public:
Span<MLoopTri> looptris;
Span<int3> corner_tris;
Span<int> corner_verts;
Span<float2> uv_map;
Span<float3> vert_positions;
@ -139,7 +139,7 @@ struct MeshData {
int64_t uv_island_len;
public:
explicit MeshData(Span<MLoopTri> looptris,
explicit MeshData(Span<int3> corner_tris,
Span<int> corner_verts,
Span<float2> uv_map,
Span<float3> vert_positions);

@ -347,7 +347,7 @@ static Mesh *rigidbody_get_mesh(Object *ob)
case RBO_MESH_FINAL:
return BKE_object_get_evaluated_mesh(ob);
case RBO_MESH_BASE:
/* This mesh may be used for computing looptris, which should be done
/* This mesh may be used for computing corner_tris, which should be done
* on the original; otherwise every time the CoW is recreated it will
* have to be recomputed. */
BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE);
@ -405,8 +405,8 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
const blender::Span<blender::float3> positions = mesh->vert_positions();
const int totvert = mesh->totvert;
const blender::Span<MLoopTri> looptris = mesh->looptris();
const int tottri = looptris.size();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
const int tottri = corner_tris.size();
const blender::Span<int> corner_verts = mesh->corner_verts();
/* sanity checking - potential case when no data will be present */
@ -429,12 +429,12 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
if (positions.data()) {
for (i = 0; i < tottri; i++) {
/* add first triangle - verts 1,2,3 */
const MLoopTri &lt = looptris[i];
const blender::int3 &tri = corner_tris[i];
int vtri[3];
vtri[0] = corner_verts[lt.tri[0]];
vtri[1] = corner_verts[lt.tri[1]];
vtri[2] = corner_verts[lt.tri[2]];
vtri[0] = corner_verts[tri[0]];
vtri[1] = corner_verts[tri[1]];
vtri[2] = corner_verts[tri[2]];
RB_trimesh_add_triangle_indices(mdata, i, UNPACK3(vtri));
}
@ -673,14 +673,14 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
}
const blender::Span<blender::float3> positions = mesh->vert_positions();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
const blender::Span<int> corner_verts = mesh->corner_verts();
if (!positions.is_empty() && !looptris.is_empty()) {
if (!positions.is_empty() && !corner_tris.is_empty()) {
BKE_mesh_calc_volume(reinterpret_cast<const float(*)[3]>(positions.data()),
positions.size(),
looptris.data(),
looptris.size(),
corner_tris.data(),
corner_tris.size(),
corner_verts.data(),
&volume,
nullptr);
@ -747,13 +747,13 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
}
const blender::Span<blender::float3> positions = mesh->vert_positions();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
if (!positions.is_empty() && !looptris.is_empty()) {
if (!positions.is_empty() && !corner_tris.is_empty()) {
BKE_mesh_calc_volume(reinterpret_cast<const float(*)[3]>(positions.data()),
positions.size(),
looptris.data(),
looptris.size(),
corner_tris.data(),
corner_tris.size(),
mesh->corner_verts().data(),
nullptr,
r_center);

@ -133,7 +133,7 @@ bool BKE_shrinkwrap_init_tree(
return false;
}
data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRIS, 4);
data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_CORNER_TRIS, 4);
if (data->bvh == nullptr) {
return false;
@ -226,24 +226,24 @@ static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Me
data->edge_is_boundary = std::move(edge_is_boundary);
/* Build the boundary looptris bit-mask. */
const blender::Span<MLoopTri> looptris = mesh->looptris();
/* Build the boundary corner_tris bit-mask. */
const blender::Span<int3> corner_tris = mesh->corner_tris();
blender::BitVector<> looptri_has_boundary(looptris.size(), false);
blender::BitVector<> tri_has_boundary(corner_tris.size(), false);
for (const int64_t i : looptris.index_range()) {
const int3 real_edges = bke::mesh::looptri_get_real_edges(
edges, corner_verts, corner_edges, looptris[i]);
for (const int64_t i : corner_tris.index_range()) {
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
edges, corner_verts, corner_edges, corner_tris[i]);
for (int j = 0; j < 3; j++) {
if (real_edges[j] >= 0 && edge_mode[real_edges[j]]) {
looptri_has_boundary[i].set();
tri_has_boundary[i].set();
break;
}
}
}
data->looptri_has_boundary = std::move(looptri_has_boundary);
data->tri_has_boundary = std::move(tri_has_boundary);
/* Find boundary vertices and build a mapping table for compact storage of data. */
Array<int> vert_boundary_id(mesh->totvert, 0);
@ -994,20 +994,20 @@ static void target_project_edge(const ShrinkwrapTreeData *tree,
}
}
/* Target normal projection BVH callback - based on mesh_looptri_nearest_point. */
static void mesh_looptris_target_project(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
/* Target normal projection BVH callback - based on mesh_corner_tri_nearest_point. */
static void mesh_corner_tris_target_project(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
{
using namespace blender;
const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
const BVHTreeFromMesh *data = &tree->treeData;
const MLoopTri *lt = &data->looptris[index];
const int3 &tri = data->corner_tris[index];
const int tri_verts[3] = {
data->corner_verts[lt->tri[0]],
data->corner_verts[lt->tri[1]],
data->corner_verts[lt->tri[2]],
data->corner_verts[tri[0]],
data->corner_verts[tri[1]],
data->corner_verts[tri[2]],
};
const float *vtri_co[3] = {
data->vert_positions[tri_verts[0]],
@ -1044,10 +1044,10 @@ static void mesh_looptris_target_project(void *userdata,
update_hit(nearest, index, co, hit_co, hit_no);
}
/* Boundary edges */
else if (tree->boundary && tree->boundary->looptri_has_boundary[index]) {
else if (tree->boundary && tree->boundary->tri_has_boundary[index]) {
const BitSpan is_boundary = tree->boundary->edge_is_boundary;
const int3 edges = bke::mesh::looptri_get_real_edges(
data->edges, data->corner_verts, tree->corner_edges, *lt);
const int3 edges = bke::mesh::corner_tri_get_real_edges(
data->edges, data->corner_verts, tree->corner_edges, tri);
for (int i = 0; i < 3; i++) {
if (edges[i] >= 0 && is_boundary[edges[i]]) {
@ -1070,7 +1070,7 @@ void BKE_shrinkwrap_find_nearest_surface(ShrinkwrapTreeData *tree,
#endif
BLI_bvhtree_find_nearest_ex(
tree->bvh, co, nearest, mesh_looptris_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
tree->bvh, co, nearest, mesh_corner_tris_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
#ifdef TRACE_TARGET_PROJECT
printf("====== TARGET PROJECT END: %d %g ======\n\n", nearest->index, nearest->dist_sq);
@ -1163,27 +1163,28 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdat
void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
const SpaceTransform *transform,
int looptri_idx,
int corner_tri_idx,
const float hit_co[3],
const float hit_no[3],
float r_no[3])
{
using namespace blender;
const BVHTreeFromMesh *treeData = &tree->treeData;
const MLoopTri *lt = &treeData->looptris[looptri_idx];
const int face_i = tree->mesh->looptri_faces()[looptri_idx];
const int3 &tri = treeData->corner_tris[corner_tri_idx];
const int face_i = tree->mesh->corner_tri_faces()[corner_tri_idx];
/* Interpolate smooth normals if enabled. */
if (!(tree->sharp_faces && tree->sharp_faces[face_i])) {
const int vert_indices[3] = {treeData->corner_verts[lt->tri[0]],
treeData->corner_verts[lt->tri[1]],
treeData->corner_verts[lt->tri[2]]};
const int vert_indices[3] = {treeData->corner_verts[tri[0]],
treeData->corner_verts[tri[1]],
treeData->corner_verts[tri[2]]};
float w[3], no[3][3], tmp_co[3];
/* Custom and auto smooth split normals. */
if (!tree->corner_normals.is_empty()) {
copy_v3_v3(no[0], tree->corner_normals[lt->tri[0]]);
copy_v3_v3(no[1], tree->corner_normals[lt->tri[1]]);
copy_v3_v3(no[2], tree->corner_normals[lt->tri[2]]);
copy_v3_v3(no[0], tree->corner_normals[tri[0]]);
copy_v3_v3(no[1], tree->corner_normals[tri[1]]);
copy_v3_v3(no[2], tree->corner_normals[tri[2]]);
}
/* Ordinary vertex normals. */
else {
@ -1219,7 +1220,7 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
else if (!tree->face_normals.is_empty()) {
copy_v3_v3(r_no, tree->face_normals[face_i]);
}
/* Finally fallback to the looptris normal. */
/* Finally fallback to the corner_tris normal. */
else {
copy_v3_v3(r_no, hit_no);
}

@ -2769,7 +2769,6 @@ static void mesh_faces_to_scratch(Object *ob)
{
SoftBody *sb = ob->soft;
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
MLoopTri *lt;
BodyFace *bodyface;
int a;
const blender::Span<int> corner_verts = mesh->corner_verts();
@ -2777,19 +2776,17 @@ static void mesh_faces_to_scratch(Object *ob)
/* Allocate and copy faces. */
sb->scratch->bodyface_num = poly_to_tri_count(mesh->faces_num, mesh->totloop);
blender::Array<MLoopTri> looptris(sb->scratch->bodyface_num);
blender::bke::mesh::looptris_calc(
mesh->vert_positions(), mesh->faces(), mesh->corner_verts(), looptris);
lt = looptris.data();
blender::Array<blender::int3> corner_tris(sb->scratch->bodyface_num);
blender::bke::mesh::corner_tris_calc(
mesh->vert_positions(), mesh->faces(), mesh->corner_verts(), corner_tris);
bodyface = sb->scratch->bodyface = static_cast<BodyFace *>(
MEM_mallocN(sizeof(BodyFace) * sb->scratch->bodyface_num, "SB_body_Faces"));
for (a = 0; a < sb->scratch->bodyface_num; a++, lt++, bodyface++) {
bodyface->v1 = corner_verts[lt->tri[0]];
bodyface->v2 = corner_verts[lt->tri[1]];
bodyface->v3 = corner_verts[lt->tri[2]];
for (a = 0; a < sb->scratch->bodyface_num; a++, bodyface++) {
bodyface->v1 = corner_verts[corner_tris[a][0]];
bodyface->v2 = corner_verts[corner_tris[a][1]];
bodyface->v3 = corner_verts[corner_tris[a][2]];
zero_v3(bodyface->ext_force);
bodyface->ext_force[0] = bodyface->ext_force[1] = bodyface->ext_force[2] = 0.0f;
bodyface->flag = 0;

@ -22,7 +22,6 @@
struct GPUBatch;
struct PBVHNode;
struct Mesh;
struct MLoopTri;
struct CustomData;
struct SubdivCCG;
struct BMesh;
@ -82,8 +81,8 @@ struct PBVH_GPU_Args {
VArraySpan<bool> hide_poly;
Span<MLoopTri> looptris;
Span<int> looptri_faces;
Span<int3> corner_tris;
Span<int> tri_faces;
/* BMesh. */
const Set<BMFace *, 0> *bm_faces;

@ -45,7 +45,7 @@ enum {
};
enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_CORNER_TRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
MR_ITER_LOOSE_EDGE = 1 << 2,
MR_ITER_LOOSE_VERT = 1 << 3,
@ -56,7 +56,7 @@ enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
MR_DATA_LOOP_NOR = 1 << 2,
MR_DATA_LOOPTRI = 1 << 3,
MR_DATA_CORNER_TRI = 1 << 3,
MR_DATA_LOOSE_GEOM = 1 << 4,
/** Force loop normals calculation. */
MR_DATA_TAN_LOOP_NOR = 1 << 5,

@ -78,7 +78,7 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
{
for (const ExtractorRunData &data : *this) {
const MeshExtract *extractor = data.extractor;
if ((iter_type & MR_ITER_LOOPTRI) && *(&extractor->iter_looptri_bm + is_mesh)) {
if ((iter_type & MR_ITER_CORNER_TRI) && *(&extractor->iter_looptri_bm + is_mesh)) {
result.append(data);
continue;
}
@ -279,18 +279,18 @@ static void extract_range_iter_looptri_bm(void *__restrict userdata,
}
}
static void extract_range_iter_looptri_mesh(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
static void extract_range_iter_corner_tri_mesh(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData &mr = *data->mr;
const MLoopTri *lt = &((const MLoopTri *)data->elems)[iter];
const int3 &tri = ((const int3 *)data->elems)[iter];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_looptri_mesh(
mr, lt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
run_data.extractor->iter_corner_tri_mesh(
mr, tri, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
@ -397,9 +397,9 @@ BLI_INLINE void extract_task_range_run_iter(const MeshRenderData &mr,
TaskParallelRangeFunc func;
int stop;
switch (iter_type) {
case MR_ITER_LOOPTRI:
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;
case MR_ITER_CORNER_TRI:
range_data.elems = is_mesh ? mr.corner_tris.data() : (void *)mr.edit_bmesh->looptris;
func = is_mesh ? extract_range_iter_corner_tri_mesh : extract_range_iter_looptri_bm;
stop = mr.tri_len;
break;
case MR_ITER_POLY:
@ -447,8 +447,9 @@ static void extract_task_range_run(void *__restrict taskdata)
extract_init(*data->mr, *data->cache, *data->extractors, data->mbuflist, userdata_chunk);
if (iter_type & MR_ITER_LOOPTRI) {
extract_task_range_run_iter(*data->mr, data->extractors, MR_ITER_LOOPTRI, is_mesh, &settings);
if (iter_type & MR_ITER_CORNER_TRI) {
extract_task_range_run_iter(
*data->mr, data->extractors, MR_ITER_CORNER_TRI, is_mesh, &settings);
}
if (iter_type & MR_ITER_POLY) {
extract_task_range_run_iter(*data->mr, data->extractors, MR_ITER_POLY, is_mesh, &settings);
@ -534,7 +535,7 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data)
const eMRDataType data_flag = update_task_data->data_flag;
mesh_render_data_update_normals(mr, data_flag);
mesh_render_data_update_looptris(mr, iter_type, data_flag);
mesh_render_data_update_corner_tris(mr, iter_type, data_flag);
mesh_render_data_update_loose_geom(mr, *update_task_data->cache, iter_type, data_flag);
mesh_render_data_update_faces_sorted(mr, *update_task_data->cache, data_flag);
}
@ -870,7 +871,7 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
return;
}
mesh_render_data_update_looptris(mr, MR_ITER_LOOPTRI, MR_DATA_LOOPTRI);
mesh_render_data_update_corner_tris(mr, MR_ITER_CORNER_TRI, MR_DATA_CORNER_TRI);
mesh_render_data_update_normals(mr, MR_DATA_TAN_LOOP_NOR);
mesh_render_data_update_loose_geom(
mr, mbc, MR_ITER_LOOSE_EDGE | MR_ITER_LOOSE_VERT, MR_DATA_LOOSE_GEOM);

@ -414,20 +414,20 @@ const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *mesh)
return &mesh->vert_data;
}
void mesh_render_data_update_looptris(MeshRenderData &mr,
const eMRIterType iter_type,
const eMRDataType data_flag)
void mesh_render_data_update_corner_tris(MeshRenderData &mr,
const eMRIterType iter_type,
const eMRDataType data_flag)
{
if (mr.extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
mr.looptris = mr.mesh->looptris();
mr.looptri_faces = mr.mesh->looptri_faces();
if ((iter_type & MR_ITER_CORNER_TRI) || (data_flag & MR_DATA_CORNER_TRI)) {
mr.corner_tris = mr.mesh->corner_tris();
mr.corner_tri_faces = mr.mesh->corner_tri_faces();
}
}
else {
/* #BMesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
if ((iter_type & MR_ITER_CORNER_TRI) || (data_flag & MR_DATA_CORNER_TRI)) {
/* Edit mode ensures this is valid, no need to calculate. */
BLI_assert((mr.bm->totloop == 0) || (mr.edit_bmesh->looptris != nullptr));
}

@ -592,7 +592,7 @@ static void mesh_batch_cache_init(Object *object, Mesh *mesh)
if (cache->is_editmode == false) {
// cache->edge_len = mesh_render_edges_len_get(mesh);
// cache->tri_len = mesh_render_looptris_len_get(mesh);
// cache->tri_len = mesh_render_corner_tris_len_get(mesh);
// cache->face_len = mesh_render_faces_len_get(mesh);
// cache->vert_len = mesh_render_verts_len_get(mesh);
}
@ -649,7 +649,7 @@ static void mesh_batch_cache_request_surface_batches(MeshBatchCache &cache)
}
}
/* Free batches with material-mapped looptris.
/* Free batches with material-mapped corner_tris.
* NOTE: The updating of the indices buffers (#tris_per_mat) is handled in the extractors.
* No need to discard they here. */
static void mesh_batch_cache_discard_surface_batches(MeshBatchCache &cache)

@ -423,15 +423,15 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
BMFace *f = nullptr;
/* Alternative to using `poly_to_tri_count(i, BM_elem_index_get(f->l_first))`
* without having to add an extra loop. */
int looptri_index = 0;
int tri_index = 0;
BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, i) {
const int f_looptris_len = f->len - 2;
const int f_corner_tris_len = f->len - 2;
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
n = 0;
area = 0;
zero_v3(vmid);
BMLoop *(*l)[3] = &em->looptris[looptri_index];
for (int j = 0; j < f_looptris_len; j++) {
BMLoop *(*l)[3] = &em->looptris[tri_index];
for (int j = 0; j < f_corner_tris_len; j++) {
if (use_coords) {
copy_v3_v3(v1, vert_coords[BM_elem_index_get(l[j][0]->v)]);
@ -477,7 +477,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
}
looptri_index += f_looptris_len;
tri_index += f_corner_tris_len;
}
}

@ -127,17 +127,17 @@ void extract_data_vert_faces(const PBVH_GPU_Args &args, const Span<T> attribute,
using Converter = AttributeConverter<T>;
using VBOType = typename Converter::VBOType;
const Span<int> corner_verts = args.corner_verts;
const Span<MLoopTri> looptris = args.looptris;
const Span<int> looptri_faces = args.looptri_faces;
const Span<int3> corner_tris = args.corner_tris;
const Span<int> tri_faces = args.tri_faces;
const Span<bool> hide_poly = args.hide_poly;
VBOType *data = static_cast<VBOType *>(GPU_vertbuf_get_data(&vbo));
for (const int looptri_i : args.prim_indices) {
if (!hide_poly.is_empty() && hide_poly[looptri_faces[looptri_i]]) {
for (const int tri_i : args.prim_indices) {
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
continue;
}
for (int i : IndexRange(3)) {
const int vert = corner_verts[looptris[looptri_i].tri[i]];
const int vert = corner_verts[corner_tris[tri_i][i]];
*data = Converter::convert(attribute[vert]);
data++;
}
@ -150,12 +150,12 @@ void extract_data_face_faces(const PBVH_GPU_Args &args, const Span<T> attribute,
using Converter = AttributeConverter<T>;
using VBOType = typename Converter::VBOType;
const Span<int> looptri_faces = args.looptri_faces;
const Span<int> tri_faces = args.tri_faces;
const Span<bool> hide_poly = args.hide_poly;
VBOType *data = static_cast<VBOType *>(GPU_vertbuf_get_data(&vbo));
for (const int looptri_i : args.prim_indices) {
const int face = looptri_faces[looptri_i];
for (const int tri_i : args.prim_indices) {
const int face = tri_faces[tri_i];
if (!hide_poly.is_empty() && hide_poly[face]) {
continue;
}
@ -170,17 +170,17 @@ void extract_data_corner_faces(const PBVH_GPU_Args &args, const Span<T> attribut
using Converter = AttributeConverter<T>;
using VBOType = typename Converter::VBOType;
const Span<MLoopTri> looptris = args.looptris;
const Span<int> looptri_faces = args.looptri_faces;
const Span<int3> corner_tris = args.corner_tris;
const Span<int> tri_faces = args.tri_faces;
const Span<bool> hide_poly = args.hide_poly;
VBOType *data = static_cast<VBOType *>(GPU_vertbuf_get_data(&vbo));
for (const int looptri_i : args.prim_indices) {
if (!hide_poly.is_empty() && hide_poly[looptri_faces[looptri_i]]) {
for (const int tri_i : args.prim_indices) {
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
continue;
}
for (int i : IndexRange(3)) {
const int corner = looptris[looptri_i].tri[i];
const int corner = corner_tris[tri_i][i];
*data = Converter::convert(attribute[corner]);
data++;
}
@ -339,8 +339,8 @@ struct PBVHBatches {
switch (args.pbvh_type) {
case PBVH_FACES: {
if (!args.hide_poly.is_empty()) {
for (const int looptri_i : args.prim_indices) {
if (!args.hide_poly[args.looptri_faces[looptri_i]]) {
for (const int tri_i : args.prim_indices) {
if (!args.hide_poly[args.tri_faces[tri_i]]) {
count++;
}
}
@ -444,8 +444,8 @@ struct PBVHBatches {
short4 face_no;
int last_face = -1;
for (const int looptri_i : args.prim_indices) {
const int face_i = args.looptri_faces[looptri_i];
for (const int tri_i : args.prim_indices) {
const int face_i = args.tri_faces[tri_i];
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
continue;
}
@ -459,7 +459,7 @@ struct PBVHBatches {
}
else {
for (const int i : IndexRange(3)) {
const int vert = args.corner_verts[args.looptris[looptri_i].tri[i]];
const int vert = args.corner_verts[args.corner_tris[tri_i][i]];
*data = normal_float_to_short(args.vert_normals[vert]);
data++;
}
@ -684,16 +684,16 @@ struct PBVHBatches {
ATTR_DOMAIN_POINT)) {
const VArraySpan<float> mask_span(mask);
const Span<int> corner_verts = args.corner_verts;
const Span<MLoopTri> looptris = args.looptris;
const Span<int> looptri_faces = args.looptri_faces;
const Span<int3> corner_tris = args.corner_tris;
const Span<int> tri_faces = args.tri_faces;
const Span<bool> hide_poly = args.hide_poly;
for (const int looptri_i : args.prim_indices) {
if (!hide_poly.is_empty() && hide_poly[looptri_faces[looptri_i]]) {
for (const int tri_i : args.prim_indices) {
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
continue;
}
for (int i : IndexRange(3)) {
const int vert = corner_verts[looptris[looptri_i].tri[i]];
const int vert = corner_verts[corner_tris[tri_i][i]];
*data = mask_span[vert];
data++;
}
@ -712,11 +712,11 @@ struct PBVHBatches {
int last_face = -1;
uchar4 fset_color(UCHAR_MAX);
for (const int looptri_i : args.prim_indices) {
if (!args.hide_poly.is_empty() && args.hide_poly[args.looptri_faces[looptri_i]]) {
for (const int tri_i : args.prim_indices) {
if (!args.hide_poly.is_empty() && args.hide_poly[args.tri_faces[tri_i]]) {
continue;
}
const int face_i = args.looptri_faces[looptri_i];
const int face_i = args.tri_faces[tri_i];
if (last_face != face_i) {
last_face = face_i;
@ -1031,20 +1031,20 @@ struct PBVHBatches {
const bke::AttributeAccessor attributes = args.mesh->attributes();
const VArray material_indices = *attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
material_index = material_indices[args.looptri_faces[args.prim_indices.first()]];
material_index = material_indices[args.tri_faces[args.prim_indices.first()]];
const Span<int2> edges = args.mesh->edges();
/* Calculate number of edges. */
int edge_count = 0;
for (const int looptri_i : args.prim_indices) {
const int face_i = args.looptri_faces[looptri_i];
for (const int tri_i : args.prim_indices) {
const int face_i = args.tri_faces[tri_i];
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
continue;
}
const int3 real_edges = bke::mesh::looptri_get_real_edges(
edges, args.corner_verts, args.corner_edges, args.looptris[looptri_i]);
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
edges, args.corner_verts, args.corner_edges, args.corner_tris[tri_i]);
if (real_edges[0] != -1) {
edge_count++;
@ -1061,14 +1061,14 @@ struct PBVHBatches {
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, edge_count * 2, INT_MAX);
int vertex_i = 0;
for (const int looptri_i : args.prim_indices) {
const int face_i = args.looptri_faces[looptri_i];
for (const int tri_i : args.prim_indices) {
const int face_i = args.tri_faces[tri_i];
if (!args.hide_poly.is_empty() && args.hide_poly[face_i]) {
continue;
}
const int3 real_edges = bke::mesh::looptri_get_real_edges(
edges, args.corner_verts, args.corner_edges, args.looptris[looptri_i]);
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
edges, args.corner_verts, args.corner_edges, args.corner_tris[tri_i]);
if (real_edges[0] != -1) {
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i, vertex_i + 1);

@ -10,6 +10,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "ED_uvedit.hh"
@ -31,7 +32,8 @@ void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuf
eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
{
eMRIterType type = (eMRIterType)0;
SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
SET_FLAG_FROM_TEST(
type, (ext->iter_looptri_bm || ext->iter_corner_tri_mesh), MR_ITER_CORNER_TRI);
SET_FLAG_FROM_TEST(type, (ext->iter_face_bm || ext->iter_face_mesh), MR_ITER_POLY);
SET_FLAG_FROM_TEST(
type, (ext->iter_loose_edge_bm || ext->iter_loose_edge_mesh), MR_ITER_LOOSE_EDGE);

@ -13,7 +13,6 @@
#include "BLI_math_vector_types.hh"
#include "BLI_virtual_array.hh"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "BKE_mesh.hh"
@ -28,6 +27,7 @@
struct DRWSubdivCache;
struct BMVert;
struct BMEdge;
struct BMEditMesh;
struct BMFace;
struct BMLoop;
@ -93,8 +93,8 @@ struct MeshRenderData {
BMFace *efa_act;
BMFace *efa_act_uv;
/* The triangulation of #Mesh faces, owned by the mesh. */
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<blender::int3> corner_tris;
blender::Span<int> corner_tri_faces;
blender::VArraySpan<int> material_indices;
blender::bke::MeshNormalDomain normals_domain;
@ -179,7 +179,7 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData &mr, const BMFace *e
using ExtractTriBMeshFn = void(const MeshRenderData &mr, BMLoop **elt, int elt_index, void *data);
using ExtractTriMeshFn = void(const MeshRenderData &mr,
const MLoopTri *lt,
const blender::int3 &tri,
int elt_index,
void *data);
using ExtractFaceBMeshFn = void(const MeshRenderData &mr,
@ -240,7 +240,7 @@ struct MeshExtract {
ExtractInitFn *init;
/** Executed on one (or more if use_threading) worker thread(s). */
ExtractTriBMeshFn *iter_looptri_bm;
ExtractTriMeshFn *iter_looptri_mesh;
ExtractTriMeshFn *iter_corner_tri_mesh;
ExtractFaceBMeshFn *iter_face_bm;
ExtractFaceMeshFn *iter_face_mesh;
ExtractLEdgeBMeshFn *iter_loose_edge_bm;
@ -297,9 +297,9 @@ void mesh_render_data_update_faces_sorted(MeshRenderData &mr,
/**
* Part of the creation of the #MeshRenderData that happens in a thread.
*/
void mesh_render_data_update_looptris(MeshRenderData &mr,
eMRIterType iter_type,
eMRDataType data_flag);
void mesh_render_data_update_corner_tris(MeshRenderData &mr,
eMRIterType iter_type,
eMRDataType data_flag);
/* draw_cache_extract_mesh_extractors.c */

@ -54,18 +54,18 @@ static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData & /*mr*/,
BM_elem_index_get(elt[2]));
}
static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData &mr,
const MLoopTri *lt,
const int elt_index,
void *_data)
static void extract_edituv_tris_iter_corner_tri_mesh(const MeshRenderData &mr,
const int3 &tri,
const int elt_index,
void *_data)
{
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
const int face_i = mr.looptri_faces[elt_index];
const int face_i = mr.corner_tri_faces[elt_index];
const BMFace *efa = bm_original_face_get(mr, face_i);
const bool mp_hidden = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) : true;
const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false;
edituv_tri_add(data, mp_hidden, mp_select, lt->tri[0], lt->tri[1], lt->tri[2]);
edituv_tri_add(data, mp_hidden, mp_select, tri[0], tri[1], tri[2]);
}
static void extract_edituv_tris_finish(const MeshRenderData & /*mr*/,
@ -147,7 +147,7 @@ constexpr MeshExtract create_extractor_edituv_tris()
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_tris_init;
extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh;
extractor.iter_corner_tri_mesh = extract_edituv_tris_iter_corner_tri_mesh;
extractor.finish = extract_edituv_tris_finish;
extractor.init_subdiv = extract_edituv_tris_init_subdiv;
extractor.iter_subdiv_bm = extract_edituv_tris_iter_subdiv_bm;

@ -125,23 +125,23 @@ static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData & /*mr*
}
}
static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData &mr,
const MLoopTri *lt,
const int elt_index,
void *_data)
static void extract_lines_adjacency_iter_corner_tri_mesh(const MeshRenderData &mr,
const int3 &tri,
const int elt_index,
void *_data)
{
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
const int face_i = mr.looptri_faces[elt_index];
const int face_i = mr.corner_tri_faces[elt_index];
const bool hidden = mr.use_hide && !mr.hide_poly.is_empty() && mr.hide_poly[face_i];
if (hidden) {
return;
}
lines_adjacency_triangle(mr.corner_verts[lt->tri[0]],
mr.corner_verts[lt->tri[1]],
mr.corner_verts[lt->tri[2]],
lt->tri[0],
lt->tri[1],
lt->tri[2],
lines_adjacency_triangle(mr.corner_verts[tri[0]],
mr.corner_verts[tri[1]],
mr.corner_verts[tri[2]],
tri[0],
tri[1],
tri[2],
data);
}
@ -251,7 +251,7 @@ constexpr MeshExtract create_extractor_lines_adjacency()
MeshExtract extractor = {nullptr};
extractor.init = extract_lines_adjacency_init;
extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh;
extractor.iter_corner_tri_mesh = extract_lines_adjacency_iter_corner_tri_mesh;
extractor.finish = extract_lines_adjacency_finish;
extractor.init_subdiv = extract_lines_adjacency_init_subdiv;
extractor.iter_subdiv_bm = extract_lines_adjacency_iter_subdiv_bm;

@ -78,9 +78,9 @@ static void extract_tris_iter_face_mesh(const MeshRenderData &mr,
int tri_len = face.size() - 2;
for (int offs = 0; offs < tri_len; offs++) {
const MLoopTri *lt = &mr.looptris[tri_first_index_real + offs];
const int3 &tri = mr.corner_tris[tri_first_index_real + offs];
int tri_index = tri_first_index + offs;
GPU_indexbuf_set_tri_verts(elb, tri_index, lt->tri[0], lt->tri[1], lt->tri[2]);
GPU_indexbuf_set_tri_verts(elb, tri_index, tri[0], tri[1], tri[2]);
}
}
@ -148,7 +148,7 @@ constexpr MeshExtract create_extractor_tris()
extractor.iter_face_mesh = extract_tris_iter_face_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
extractor.finish = extract_tris_finish;
extractor.data_type = MR_DATA_LOOPTRI | MR_DATA_POLYS_SORTED;
extractor.data_type = MR_DATA_CORNER_TRI | MR_DATA_POLYS_SORTED;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris);
@ -187,19 +187,19 @@ static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData & /*mr*
}
}
static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData &mr,
const MLoopTri *lt,
const int lt_index,
void *_data)
static void extract_tris_single_mat_iter_corner_tri_mesh(const MeshRenderData &mr,
const int3 &tri,
const int tri_index,
void *_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
const int face_i = mr.looptri_faces[lt_index];
const int face_i = mr.corner_tri_faces[tri_index];
const bool hidden = mr.use_hide && !mr.hide_poly.is_empty() && mr.hide_poly[face_i];
if (hidden) {
GPU_indexbuf_set_tri_restart(elb, lt_index);
GPU_indexbuf_set_tri_restart(elb, tri_index);
}
else {
GPU_indexbuf_set_tri_verts(elb, lt_index, lt->tri[0], lt->tri[1], lt->tri[2]);
GPU_indexbuf_set_tri_verts(elb, tri_index, tri[0], tri[1], tri[2]);
}
}
@ -234,7 +234,7 @@ constexpr MeshExtract create_extractor_tris_single_mat()
extractor.init = extract_tris_single_mat_init;
extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
extractor.iter_corner_tri_mesh = extract_tris_single_mat_iter_corner_tri_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
extractor.finish = extract_tris_single_mat_finish;
extractor.data_type = MR_DATA_NONE;

@ -6,6 +6,8 @@
* \ingroup draw
*/
#include "DNA_meshdata_types.h"
#include "extract_mesh.hh"
#include "draw_cache_impl.hh"

@ -216,14 +216,14 @@ static void statvis_calc_thickness(const MeshRenderData &mr, float *r_thickness)
else {
BVHTreeFromMesh treeData = {nullptr};
BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr.mesh, BVHTREE_FROM_LOOPTRIS, 4);
const Span<MLoopTri> looptris = mr.looptris;
const Span<int> looptri_faces = mr.looptri_faces;
for (const int i : looptris.index_range()) {
const int index = looptri_faces[i];
const float *cos[3] = {mr.vert_positions[mr.corner_verts[looptris[i].tri[0]]],
mr.vert_positions[mr.corner_verts[looptris[i].tri[1]]],
mr.vert_positions[mr.corner_verts[looptris[i].tri[2]]]};
BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr.mesh, BVHTREE_FROM_CORNER_TRIS, 4);
const Span<int3> corner_tris = mr.corner_tris;
const Span<int> tri_faces = mr.corner_tri_faces;
for (const int i : corner_tris.index_range()) {
const int index = tri_faces[i];
const float *cos[3] = {mr.vert_positions[mr.corner_verts[corner_tris[i][0]]],
mr.vert_positions[mr.corner_verts[corner_tris[i][1]]],
mr.vert_positions[mr.corner_verts[corner_tris[i][2]]]};
float ray_co[3];
float ray_no[3];
@ -265,8 +265,8 @@ static void statvis_calc_thickness(const MeshRenderData &mr, float *r_thickness)
struct BVHTree_OverlapData {
Span<float3> positions;
Span<int> corner_verts;
Span<MLoopTri> looptris;
Span<int> looptri_faces;
Span<int3> corner_tris;
Span<int> tri_faces;
float epsilon;
};
@ -274,19 +274,19 @@ static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int /*threa
{
BVHTree_OverlapData *data = static_cast<BVHTree_OverlapData *>(userdata);
if (UNLIKELY(data->looptri_faces[index_a] == data->looptri_faces[index_b])) {
if (UNLIKELY(data->tri_faces[index_a] == data->tri_faces[index_b])) {
return false;
}
const MLoopTri *lt_a = &data->looptris[index_a];
const MLoopTri *lt_b = &data->looptris[index_b];
const int3 tri_a = data->corner_tris[index_a];
const int3 tri_b = data->corner_tris[index_b];
const float *tri_a_co[3] = {data->positions[data->corner_verts[lt_a->tri[0]]],
data->positions[data->corner_verts[lt_a->tri[1]]],
data->positions[data->corner_verts[lt_a->tri[2]]]};
const float *tri_b_co[3] = {data->positions[data->corner_verts[lt_b->tri[0]]],
data->positions[data->corner_verts[lt_b->tri[1]]],
data->positions[data->corner_verts[lt_b->tri[2]]]};
const float *tri_a_co[3] = {data->positions[data->corner_verts[tri_a[0]]],
data->positions[data->corner_verts[tri_a[1]]],
data->positions[data->corner_verts[tri_a[2]]]};
const float *tri_b_co[3] = {data->positions[data->corner_verts[tri_b[0]]],
data->positions[data->corner_verts[tri_b[1]]],
data->positions[data->corner_verts[tri_b[2]]]};
float ix_pair[2][3];
int verts_shared = 0;
@ -344,21 +344,21 @@ static void statvis_calc_intersect(const MeshRenderData &mr, float *r_intersect)
uint overlap_len;
BVHTreeFromMesh treeData = {nullptr};
BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr.mesh, BVHTREE_FROM_LOOPTRIS, 4);
BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr.mesh, BVHTREE_FROM_CORNER_TRIS, 4);
BVHTree_OverlapData data = {};
data.positions = mr.vert_positions;
data.corner_verts = mr.corner_verts;
data.looptris = mr.looptris;
data.looptri_faces = mr.looptri_faces;
data.corner_tris = mr.corner_tris;
data.tri_faces = mr.corner_tri_faces;
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++) {
for (const IndexRange f_hit : {mr.faces[mr.looptri_faces[overlap[i].indexA]],
mr.faces[mr.looptri_faces[overlap[i].indexB]]})
for (const IndexRange f_hit : {mr.faces[mr.corner_tri_faces[overlap[i].indexA]],
mr.faces[mr.corner_tri_faces[overlap[i].indexB]]})
{
int l_index = f_hit.start();
for (int k = 0; k < f_hit.size(); k++, l_index++) {
@ -626,7 +626,7 @@ constexpr MeshExtract create_extractor_mesh_analysis()
extractor.finish = extract_analysis_iter_finish_mesh;
/* This is not needed for all visualization types.
* Maybe split into different extract. */
extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI;
extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_CORNER_TRI;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.mesh_analysis);

@ -6,6 +6,8 @@
* \ingroup draw
*/
#include "DNA_meshdata_types.h"
#include "extract_mesh.hh"
namespace blender::draw {

@ -120,8 +120,8 @@ static void extract_tan_init_common(const MeshRenderData &mr,
BKE_mesh_calc_loop_tangent_ex(reinterpret_cast<const float(*)[3]>(mr.vert_positions.data()),
mr.faces,
mr.corner_verts.data(),
mr.looptris.data(),
mr.looptri_faces.data(),
mr.corner_tris.data(),
mr.corner_tri_faces.data(),
mr.tri_len,
mr.sharp_faces,
cd_ldata,
@ -337,7 +337,7 @@ constexpr MeshExtract create_extractor_tan()
MeshExtract extractor = {nullptr};
extractor.init = extract_tan_init;
extractor.init_subdiv = extract_tan_init_subdiv;
extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI;
extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_CORNER_TRI;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.tan);
@ -363,7 +363,7 @@ constexpr MeshExtract create_extractor_tan_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tan_hq_init;
extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI;
extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_CORNER_TRI;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.tan);

@ -6,6 +6,8 @@
* \ingroup draw
*/
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
#include "BKE_deform.h"

@ -71,7 +71,7 @@ struct LaplacianSystem {
blender::Map<blender::OrderedEdge, int> edgehash; /* edge hash for construction */
struct HeatWeighting {
const MLoopTri *looptris;
const blender::int3 *corner_tris;
blender::Span<int> corner_verts; /* needed to find vertices by index */
int verts_num;
int tris_num;
@ -86,8 +86,8 @@ struct LaplacianSystem {
float *p; /* values from all p vectors */
float *mindist; /* minimum distance to a bone for all vertices */
BVHTree *bvhtree; /* ray tracing acceleration structure */
const MLoopTri **vltree; /* a looptri that the vertex belongs to */
BVHTree *bvhtree; /* ray tracing acceleration structure */
const blender::int3 **vltree; /* a corner_tri that the vertex belongs to */
} heat;
};
@ -373,15 +373,15 @@ struct BVHCallbackUserData {
static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
BVHCallbackUserData *data = (BVHCallbackUserData *)userdata;
const MLoopTri *lt = &data->sys->heat.looptris[index];
const blender::int3 &tri = data->sys->heat.corner_tris[index];
const blender::Span<int> corner_verts = data->sys->heat.corner_verts;
float(*verts)[3] = data->sys->heat.verts;
const float *vtri_co[3];
float dist_test;
vtri_co[0] = verts[corner_verts[lt->tri[0]]];
vtri_co[1] = verts[corner_verts[lt->tri[1]]];
vtri_co[2] = verts[corner_verts[lt->tri[2]]];
vtri_co[0] = verts[corner_verts[tri[0]]];
vtri_co[1] = verts[corner_verts[tri[1]]];
vtri_co[2] = verts[corner_verts[tri[2]]];
#ifdef USE_KDOPBVH_WATERTIGHT
if (isect_ray_tri_watertight_v3(
@ -405,7 +405,7 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTr
/* Ray-tracing for vertex to bone/vertex visibility. */
static void heat_ray_tree_create(LaplacianSystem *sys)
{
const MLoopTri *looptris = sys->heat.looptris;
const blender::int3 *corner_tris = sys->heat.corner_tris;
const blender::Span<int> corner_verts = sys->heat.corner_verts;
float(*verts)[3] = sys->heat.verts;
int tris_num = sys->heat.tris_num;
@ -413,17 +413,17 @@ static void heat_ray_tree_create(LaplacianSystem *sys)
int a;
sys->heat.bvhtree = BLI_bvhtree_new(tris_num, 0.0f, 4, 6);
sys->heat.vltree = static_cast<const MLoopTri **>(
MEM_callocN(sizeof(MLoopTri *) * verts_num, "HeatVFaces"));
sys->heat.vltree = static_cast<const blender::int3 **>(
MEM_callocN(sizeof(blender::int3 *) * verts_num, "HeatVFaces"));
for (a = 0; a < tris_num; a++) {
const MLoopTri *lt = &looptris[a];
const blender::int3 &tri = corner_tris[a];
float bb[6];
int vtri[3];
vtri[0] = corner_verts[lt->tri[0]];
vtri[1] = corner_verts[lt->tri[1]];
vtri[2] = corner_verts[lt->tri[2]];
vtri[0] = corner_verts[tri[0]];
vtri[1] = corner_verts[tri[1]];
vtri[2] = corner_verts[tri[2]];
INIT_MINMAX(bb, bb + 3);
minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]);
@ -433,9 +433,9 @@ static void heat_ray_tree_create(LaplacianSystem *sys)
BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
/* Setup inverse pointers to use on isect.orig */
sys->heat.vltree[vtri[0]] = lt;
sys->heat.vltree[vtri[1]] = lt;
sys->heat.vltree[vtri[2]] = lt;
sys->heat.vltree[vtri[0]] = &tri;
sys->heat.vltree[vtri[1]] = &tri;
sys->heat.vltree[vtri[2]] = &tri;
}
BLI_bvhtree_balance(sys->heat.bvhtree);
@ -445,7 +445,7 @@ static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
{
BVHTreeRayHit hit;
BVHCallbackUserData data;
const MLoopTri *lt;
const blender::int3 *lt;
float end[3];
int visible;
@ -572,7 +572,7 @@ static void heat_calc_vnormals(LaplacianSystem *sys)
static void heat_laplacian_create(LaplacianSystem *sys)
{
const MLoopTri *looptris = sys->heat.looptris, *lt;
const blender::int3 *corner_tris = sys->heat.corner_tris;
const blender::Span<int> corner_verts = sys->heat.corner_verts;
int tris_num = sys->heat.tris_num;
int verts_num = sys->heat.verts_num;
@ -588,11 +588,11 @@ static void heat_laplacian_create(LaplacianSystem *sys)
laplacian_add_vertex(sys, sys->heat.verts[a], 0);
}
for (a = 0, lt = looptris; a < tris_num; a++, lt++) {
for (a = 0; a < tris_num; a++) {
int vtri[3];
vtri[0] = corner_verts[lt->tri[0]];
vtri[1] = corner_verts[lt->tri[1]];
vtri[2] = corner_verts[lt->tri[2]];
vtri[0] = corner_verts[corner_tris[a][0]];
vtri[1] = corner_verts[corner_tris[a][1]];
vtri[2] = corner_verts[corner_tris[a][2]];
laplacian_add_triangle(sys, UNPACK3(vtri));
}
@ -608,7 +608,7 @@ static void heat_system_free(LaplacianSystem *sys)
{
BLI_bvhtree_free(sys->heat.bvhtree);
MEM_freeN((void *)sys->heat.vltree);
MEM_freeN((void *)sys->heat.looptris);
MEM_freeN((void *)sys->heat.corner_tris);
MEM_freeN(sys->heat.mindist);
MEM_freeN(sys->heat.H);
@ -642,7 +642,7 @@ void heat_bone_weighting(Object *ob,
const char **error_str)
{
LaplacianSystem *sys;
MLoopTri *looptris;
blender::int3 *corner_tris;
float solution, weight;
int *vertsflipped = nullptr, *mask = nullptr;
int a, tris_num, j, bbone, firstsegment, lastsegment;
@ -695,13 +695,13 @@ void heat_bone_weighting(Object *ob,
sys = laplacian_system_construct_begin(mesh->totvert, tris_num, 1);
sys->heat.tris_num = poly_to_tri_count(mesh->faces_num, mesh->totloop);
looptris = static_cast<MLoopTri *>(
MEM_mallocN(sizeof(*sys->heat.looptris) * sys->heat.tris_num, __func__));
corner_tris = static_cast<blender::int3 *>(
MEM_mallocN(sizeof(*sys->heat.corner_tris) * sys->heat.tris_num, __func__));
blender::bke::mesh::looptris_calc(
vert_positions, faces, corner_verts, {looptris, sys->heat.tris_num});
blender::bke::mesh::corner_tris_calc(
vert_positions, faces, corner_verts, {corner_tris, sys->heat.tris_num});
sys->heat.looptris = looptris;
sys->heat.corner_tris = corner_tris;
sys->heat.corner_verts = corner_verts;
sys->heat.verts_num = mesh->totvert;
sys->heat.verts = verts;
@ -921,8 +921,8 @@ struct MeshDeformBind {
struct {
blender::OffsetIndices<int> faces;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<blender::int3> corner_tris;
blender::Span<int> tri_faces;
blender::Span<blender::float3> face_normals;
} cagemesh_cache;
};
@ -952,17 +952,17 @@ static void harmonic_ray_callback(void *userdata,
MeshRayCallbackData *data = static_cast<MeshRayCallbackData *>(userdata);
MeshDeformBind *mdb = data->mdb;
const blender::Span<int> corner_verts = mdb->cagemesh_cache.corner_verts;
const blender::Span<int> looptri_faces = mdb->cagemesh_cache.looptri_faces;
const blender::Span<int> tri_faces = mdb->cagemesh_cache.tri_faces;
const blender::Span<blender::float3> face_normals = mdb->cagemesh_cache.face_normals;
MeshDeformIsect *isec = data->isec;
float no[3], co[3], dist;
float *face[3];
const MLoopTri *lt = &mdb->cagemesh_cache.looptris[index];
const blender::int3 &tri = mdb->cagemesh_cache.corner_tris[index];
face[0] = mdb->cagecos[corner_verts[lt->tri[0]]];
face[1] = mdb->cagecos[corner_verts[lt->tri[1]]];
face[2] = mdb->cagecos[corner_verts[lt->tri[2]]];
face[0] = mdb->cagecos[corner_verts[tri[0]]];
face[1] = mdb->cagecos[corner_verts[tri[1]]];
face[2] = mdb->cagecos[corner_verts[tri[2]]];
bool isect_ray_tri = isect_ray_tri_watertight_v3(
ray->origin, ray->isect_precalc, UNPACK3(face), &dist, nullptr);
@ -972,7 +972,7 @@ static void harmonic_ray_callback(void *userdata,
}
if (!face_normals.is_empty()) {
copy_v3_v3(no, face_normals[looptri_faces[index]]);
copy_v3_v3(no, face_normals[tri_faces[index]]);
}
else {
normal_tri_v3(no, UNPACK3(face));
@ -1028,7 +1028,7 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb,
BVH_RAYCAST_WATERTIGHT) != -1)
{
const blender::Span<int> corner_verts = mdb->cagemesh_cache.corner_verts;
const int face_i = mdb->cagemesh_cache.looptri_faces[hit.index];
const int face_i = mdb->cagemesh_cache.tri_faces[hit.index];
const blender::IndexRange face = mdb->cagemesh_cache.faces[face_i];
const float(*cagecos)[3] = mdb->cagecos;
const float len = isect_mdef.lambda;
@ -1603,7 +1603,8 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
mdb->boundisect = static_cast<MDefBoundIsect *(*)[6]>(
MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect"));
mdb->semibound = static_cast<int *>(MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound"));
mdb->bvhtree = BKE_bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagemesh, BVHTREE_FROM_LOOPTRIS, 4);
mdb->bvhtree = BKE_bvhtree_from_mesh_get(
&mdb->bvhdata, mdb->cagemesh, BVHTREE_FROM_CORNER_TRIS, 4);
mdb->inside = static_cast<int *>(MEM_callocN(sizeof(int) * mdb->verts_num, "MDefInside"));
if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
@ -1623,8 +1624,8 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
Mesh *mesh = mdb->cagemesh;
mdb->cagemesh_cache.faces = mesh->faces();
mdb->cagemesh_cache.corner_verts = mesh->corner_verts();
mdb->cagemesh_cache.looptris = mesh->looptris();
mdb->cagemesh_cache.looptri_faces = mesh->looptri_faces();
mdb->cagemesh_cache.corner_tris = mesh->corner_tris();
mdb->cagemesh_cache.tri_faces = mesh->corner_tri_faces();
mdb->cagemesh_cache.face_normals = mesh->face_normals();
}

@ -269,13 +269,13 @@ static void try_convert_single_object(Object &curves_ob,
Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data);
BVHTreeFromMesh surface_bvh;
BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
const Span<float3> positions_cu = curves.positions();
const Span<int> looptri_faces = surface_me.looptri_faces();
const Span<int> tri_faces = surface_me.corner_tri_faces();
if (looptri_faces.is_empty()) {
if (tri_faces.is_empty()) {
*r_could_not_convert_some_curves = true;
}
@ -342,8 +342,8 @@ static void try_convert_single_object(Object &curves_ob,
surface_bvh.tree, root_pos_su, &nearest, surface_bvh.nearest_callback, &surface_bvh);
BLI_assert(nearest.index >= 0);
const int looptri_i = nearest.index;
const int face_i = looptri_faces[looptri_i];
const int tri_i = nearest.index;
const int face_i = tri_faces[tri_i];
const int mface_i = find_mface_for_root_position(
positions, mfaces, poly_to_mface_map[face_i], root_pos_su);
@ -588,7 +588,7 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
const Mesh &surface_mesh = *static_cast<const Mesh *>(surface_ob.data);
const Span<float3> surface_positions = surface_mesh.vert_positions();
const Span<int> corner_verts = surface_mesh.corner_verts();
const Span<MLoopTri> surface_looptris = surface_mesh.looptris();
const Span<int3> surface_corner_tris = surface_mesh.corner_tris();
VArraySpan<float2> surface_uv_map;
if (curves_id.surface_uv_map != nullptr) {
const bke::AttributeAccessor surface_attributes = surface_mesh.attributes();
@ -605,7 +605,7 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
switch (attach_mode) {
case AttachMode::Nearest: {
BVHTreeFromMesh surface_bvh;
BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
@ -624,8 +624,8 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
&nearest,
surface_bvh.nearest_callback,
&surface_bvh);
const int looptri_index = nearest.index;
if (looptri_index == -1) {
const int tri_index = nearest.index;
if (tri_index == -1) {
continue;
}
@ -639,11 +639,11 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
}
if (!surface_uv_map.is_empty()) {
const MLoopTri &lt = surface_looptris[looptri_index];
const int3 &tri = surface_corner_tris[tri_index];
const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
surface_positions, corner_verts, lt, new_first_point_pos_su);
surface_positions, corner_verts, tri, new_first_point_pos_su);
const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coords, lt, surface_uv_map);
bary_coords, tri, surface_uv_map);
surface_uv_coords[curve_i] = uv;
}
}
@ -656,7 +656,7 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
break;
}
using geometry::ReverseUVSampler;
ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_corner_tris};
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
@ -671,12 +671,12 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
continue;
}
const MLoopTri &lt = surface_looptris[lookup_result.looptri_index];
const int3 &tri = surface_corner_tris[lookup_result.tri_index];
const float3 &bary_coords = lookup_result.bary_weights;
const float3 &p0_su = surface_positions[corner_verts[lt.tri[0]]];
const float3 &p1_su = surface_positions[corner_verts[lt.tri[1]]];
const float3 &p2_su = surface_positions[corner_verts[lt.tri[2]]];
const float3 &p0_su = surface_positions[corner_verts[tri[0]]];
const float3 &p1_su = surface_positions[corner_verts[tri[1]]];
const float3 &p2_su = surface_positions[corner_verts[tri[2]]];
float3 new_first_point_pos_su;
interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);

@ -1075,14 +1075,14 @@ static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets,
}
/* Populate through adjacent triangles, first triangle wins. */
const int looptris_num = poly_to_tri_count(me_eval->faces_num, me_eval->totloop);
MLoopTri *looptris = static_cast<MLoopTri *>(
MEM_mallocN(sizeof(*looptris) * looptris_num, __func__));
const int corner_tris_num = poly_to_tri_count(me_eval->faces_num, me_eval->totloop);
blender::int3 *corner_tris = static_cast<blender::int3 *>(
MEM_mallocN(sizeof(*corner_tris) * corner_tris_num, __func__));
const blender::Span<int> corner_verts = me_eval->corner_verts();
blender::bke::mesh::looptris_calc(
me_eval->vert_positions(), me_eval->faces(), corner_verts, {looptris, looptris_num});
const blender::Span<int> looptri_faces = me_eval->looptri_faces();
blender::bke::mesh::corner_tris_calc(
me_eval->vert_positions(), me_eval->faces(), corner_verts, {corner_tris, corner_tris_num});
const blender::Span<int> tri_faces = me_eval->corner_tri_faces();
/* For mapping back to original mesh in case there are modifiers. */
const int *vert_origindex = static_cast<const int *>(
@ -1092,12 +1092,12 @@ static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets,
const blender::OffsetIndices orig_faces = mesh->faces();
const blender::Span<int> orig_corner_verts = mesh->corner_verts();
for (int i = 0; i < looptris_num; i++) {
const MLoopTri *lt = &looptris[i];
const int face_i = looptri_faces[i];
for (int i = 0; i < corner_tris_num; i++) {
const blender::int3 &tri = corner_tris[i];
const int face_i = tri_faces[i];
for (int j = 0; j < 3; j++) {
uint l = lt->tri[j];
uint l = tri[j];
const int v = corner_verts[l];
/* Map back to original loop if there are modifiers. */
@ -1138,7 +1138,7 @@ static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets,
}
}
MEM_freeN(looptris);
MEM_freeN(corner_tris);
}
static void bake_result_add_to_rgba(float rgba[4], const float *result, const int channels_num)

@ -535,7 +535,8 @@ static bool PE_create_shape_tree(PEData *data, Object *shapeob)
return false;
}
return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_LOOPTRIS, 4) != nullptr);
return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_CORNER_TRIS, 4) !=
nullptr);
}
static void PE_free_shape_tree(PEData *data)

@ -95,7 +95,7 @@ struct AddOperationExecutor {
Mesh *surface_eval_ = nullptr;
Span<float3> surface_positions_eval_;
Span<int> surface_corner_verts_eval_;
Span<MLoopTri> surface_looptris_eval_;
Span<int3> surface_corner_tris_eval_;
VArraySpan<float2> surface_uv_map_eval_;
BVHTreeFromMesh surface_bvh_eval_;
@ -145,8 +145,8 @@ struct AddOperationExecutor {
}
surface_positions_eval_ = surface_eval_->vert_positions();
surface_corner_verts_eval_ = surface_eval_->corner_verts();
surface_looptris_eval_ = surface_eval_->looptris();
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRIS, 2);
surface_corner_tris_eval_ = surface_eval_->corner_tris();
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
@ -206,9 +206,9 @@ struct AddOperationExecutor {
return;
}
const Span<MLoopTri> surface_looptris_orig = surface_orig.looptris();
const Span<int3> surface_corner_tris_orig = surface_orig.corner_tris();
const Span<float3> corner_normals_su = surface_orig.corner_normals();
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_corner_tris_orig};
geometry::AddCurvesOnMeshInputs add_inputs;
add_inputs.uvs = sampled_uvs;
@ -222,7 +222,7 @@ struct AddOperationExecutor {
add_inputs.fallback_curve_length = brush_settings_->curve_length;
add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
add_inputs.transforms = &transforms_;
add_inputs.surface_looptris = surface_looptris_orig;
add_inputs.surface_corner_tris = surface_corner_tris_orig;
add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
add_inputs.surface = &surface_orig;
add_inputs.corner_normals_su = corner_normals_su;
@ -296,14 +296,14 @@ struct AddOperationExecutor {
return;
}
const int looptri_index = ray_hit.index;
const MLoopTri &lt = surface_looptris_eval_[looptri_index];
const int tri_index = ray_hit.index;
const int3 &tri = surface_corner_tris_eval_[tri_index];
const float3 brush_pos_su = ray_hit.co;
const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
surface_positions_eval_, surface_corner_verts_eval_, lt, brush_pos_su);
surface_positions_eval_, surface_corner_verts_eval_, tri, brush_pos_su);
const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coords, lt, surface_uv_map_eval_);
bary_coords, tri, surface_uv_map_eval_);
r_sampled_uvs.append(uv);
}
@ -331,7 +331,7 @@ struct AddOperationExecutor {
break;
}
Vector<float3> bary_coords;
Vector<int> looptri_indices;
Vector<int> tri_indices;
Vector<float3> positions_su;
const int missing_amount = add_amount_ + old_amount - r_sampled_uvs.size();
@ -356,12 +356,12 @@ struct AddOperationExecutor {
add_amount_,
missing_amount,
bary_coords,
looptri_indices,
tri_indices,
positions_su);
for (const int i : IndexRange(new_points)) {
const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
r_sampled_uvs.append(uv);
}
}
@ -422,23 +422,23 @@ struct AddOperationExecutor {
const float brush_radius_sq_su = pow2f(brush_radius_su);
/* Find surface triangles within brush radius. */
Vector<int> selected_looptri_indices;
Vector<int> selected_tri_indices;
if (use_front_face_) {
BLI_bvhtree_range_query_cpp(
*surface_bvh_eval_.tree,
brush_pos_su,
brush_radius_su,
[&](const int index, const float3 & /*co*/, const float /*dist_sq*/) {
const MLoopTri &lt = surface_looptris_eval_[index];
const float3 &v0_su = surface_positions_eval_[surface_corner_verts_eval_[lt.tri[0]]];
const float3 &v1_su = surface_positions_eval_[surface_corner_verts_eval_[lt.tri[1]]];
const float3 &v2_su = surface_positions_eval_[surface_corner_verts_eval_[lt.tri[2]]];
const int3 &tri = surface_corner_tris_eval_[index];
const float3 &v0_su = surface_positions_eval_[surface_corner_verts_eval_[tri[0]]];
const float3 &v1_su = surface_positions_eval_[surface_corner_verts_eval_[tri[1]]];
const float3 &v2_su = surface_positions_eval_[surface_corner_verts_eval_[tri[2]]];
float3 normal_su;
normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
if (math::dot(normal_su, view_direction_su) >= 0.0f) {
return;
}
selected_looptri_indices.append(index);
selected_tri_indices.append(index);
});
}
else {
@ -447,7 +447,7 @@ struct AddOperationExecutor {
brush_pos_su,
brush_radius_su,
[&](const int index, const float3 & /*co*/, const float /*dist_sq*/) {
selected_looptri_indices.append(index);
selected_tri_indices.append(index);
});
}
@ -467,21 +467,21 @@ struct AddOperationExecutor {
break;
}
Vector<float3> bary_coords;
Vector<int> looptri_indices;
Vector<int> tri_indices;
Vector<float3> positions_su;
const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
rng,
*surface_eval_,
selected_looptri_indices,
selected_tri_indices,
brush_pos_su,
brush_radius_su,
approximate_density_su,
bary_coords,
looptri_indices,
tri_indices,
positions_su);
for (const int i : IndexRange(new_points)) {
const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
r_sampled_uvs.append(uv);
}
}

@ -193,7 +193,7 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
Mesh *surface_eval = BKE_object_get_evaluated_mesh(surface_object_eval);
BVHTreeFromMesh surface_bvh;
BKE_bvhtree_from_mesh_get(&surface_bvh, surface_eval, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh, surface_eval, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
const float3 center_ray_start_su = math::transform_point(world_to_surface_mat,

@ -80,7 +80,7 @@ struct DensityAddOperationExecutor {
Object *surface_ob_eval_ = nullptr;
Mesh *surface_eval_ = nullptr;
Span<MLoopTri> surface_looptris_eval_;
Span<int3> surface_corner_tris_eval_;
VArraySpan<float2> surface_uv_map_eval_;
BVHTreeFromMesh surface_bvh_eval_;
@ -131,9 +131,9 @@ struct DensityAddOperationExecutor {
return;
}
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
surface_looptris_eval_ = surface_eval_->looptris();
surface_corner_tris_eval_ = surface_eval_->corner_tris();
/* Find UV map. */
VArraySpan<float2> surface_uv_map;
if (curves_id_orig_->surface_uv_map != nullptr) {
@ -258,8 +258,8 @@ struct DensityAddOperationExecutor {
self_->new_deformed_root_positions_.extend(new_positions_cu);
const Span<float3> corner_normals_su = surface_orig_->corner_normals();
const Span<MLoopTri> surface_looptris_orig = surface_orig_->looptris();
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
const Span<int3> surface_corner_tris_orig = surface_orig_->corner_tris();
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_corner_tris_orig};
geometry::AddCurvesOnMeshInputs add_inputs;
add_inputs.uvs = new_uvs;
@ -275,7 +275,7 @@ struct DensityAddOperationExecutor {
add_inputs.transforms = &transforms_;
add_inputs.surface = surface_orig_;
add_inputs.corner_normals_su = corner_normals_su;
add_inputs.surface_looptris = surface_looptris_orig;
add_inputs.surface_corner_tris = surface_corner_tris_orig;
add_inputs.reverse_uv_sampler = &reverse_uv_sampler;
add_inputs.old_roots_kdtree = self_->original_curve_roots_kdtree_;
@ -341,7 +341,7 @@ struct DensityAddOperationExecutor {
transforms_.world_to_curves;
Vector<float3> positions_su;
Vector<float3> bary_coords;
Vector<int> looptri_indices;
Vector<int> tri_indices;
const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
rng,
*surface_eval_,
@ -359,7 +359,7 @@ struct DensityAddOperationExecutor {
brush_settings_->density_add_attempts,
brush_settings_->density_add_attempts,
bary_coords,
looptri_indices,
tri_indices,
positions_su);
/* Remove some sampled points randomly based on the brush falloff and strength. */
@ -374,14 +374,14 @@ struct DensityAddOperationExecutor {
const float weight = brush_strength_ * radius_falloff;
if (rng.get_float() > weight) {
bary_coords.remove_and_reorder(i);
looptri_indices.remove_and_reorder(i);
tri_indices.remove_and_reorder(i);
positions_su.remove_and_reorder(i);
}
}
for (const int i : bary_coords.index_range()) {
const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
r_uvs.append(uv);
}
r_positions_su.extend(positions_su);
@ -413,13 +413,13 @@ struct DensityAddOperationExecutor {
transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu);
const float brush_radius_sq_su = pow2f(brush_radius_su);
Vector<int> selected_looptri_indices;
Vector<int> selected_corner_tri_indices;
BLI_bvhtree_range_query_cpp(
*surface_bvh_eval_.tree,
brush_pos_su,
brush_radius_su,
[&](const int index, const float3 & /*co*/, const float /*dist_sq*/) {
selected_looptri_indices.append(index);
selected_corner_tri_indices.append(index);
});
const float brush_plane_area_su = M_PI * brush_radius_sq_su;
@ -428,16 +428,16 @@ struct DensityAddOperationExecutor {
Vector<float3> positions_su;
Vector<float3> bary_coords;
Vector<int> looptri_indices;
Vector<int> tri_indices;
const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
rng,
*surface_eval_,
selected_looptri_indices,
selected_corner_tri_indices,
brush_pos_su,
brush_radius_su,
approximate_density_su,
bary_coords,
looptri_indices,
tri_indices,
positions_su);
/* Remove some sampled points randomly based on the brush falloff and strength. */
@ -450,14 +450,14 @@ struct DensityAddOperationExecutor {
const float weight = brush_strength_ * radius_falloff;
if (rng.get_float() > weight) {
bary_coords.remove_and_reorder(i);
looptri_indices.remove_and_reorder(i);
tri_indices.remove_and_reorder(i);
positions_su.remove_and_reorder(i);
}
}
for (const int i : bary_coords.index_range()) {
const float2 uv = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coords[i], surface_looptris_eval_[looptri_indices[i]], surface_uv_map_eval_);
bary_coords[i], surface_corner_tris_eval_[tri_indices[i]], surface_uv_map_eval_);
r_uvs.append(uv);
}
r_positions_su.extend(positions_su);
@ -550,7 +550,7 @@ struct DensitySubtractOperationExecutor {
}
surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_);
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
@ -834,7 +834,7 @@ static bool use_add_density_mode(const BrushStrokeMode brush_mode,
const CurvesSurfaceTransforms transforms(curves_ob_orig, curves_id_orig.surface);
BVHTreeFromMesh surface_bvh_eval;
BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_mesh_eval, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_mesh_eval, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); });
const float2 brush_pos_re = stroke_start.mouse_position;

@ -1031,7 +1031,7 @@ static int min_distance_edit_invoke(bContext *C, wmOperator *op, const wmEvent *
}
BVHTreeFromMesh surface_bvh_eval;
BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_me_eval, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_me_eval, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); });
const int2 mouse_pos_int_re{event->mval};

@ -77,7 +77,7 @@ struct PuffOperationExecutor {
const Mesh *surface_ = nullptr;
Span<float3> surface_positions_;
Span<int> surface_corner_verts_;
Span<MLoopTri> surface_looptris_;
Span<int3> surface_corner_tris_;
Span<float3> corner_normals_su_;
BVHTreeFromMesh surface_bvh_;
@ -119,9 +119,9 @@ struct PuffOperationExecutor {
surface_positions_ = surface_->vert_positions();
surface_corner_verts_ = surface_->corner_verts();
surface_looptris_ = surface_->looptris();
surface_corner_tris_ = surface_->corner_tris();
corner_normals_su_ = surface_->corner_normals();
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
if (stroke_extension.is_first) {
@ -292,15 +292,15 @@ struct PuffOperationExecutor {
surface_bvh_.nearest_callback,
&surface_bvh_);
const MLoopTri &lt = surface_looptris_[nearest.index];
const int3 &tri = surface_corner_tris_[nearest.index];
const float3 closest_pos_su = nearest.co;
const float3 &v0_su = surface_positions_[surface_corner_verts_[lt.tri[0]]];
const float3 &v1_su = surface_positions_[surface_corner_verts_[lt.tri[1]]];
const float3 &v2_su = surface_positions_[surface_corner_verts_[lt.tri[2]]];
const float3 &v0_su = surface_positions_[surface_corner_verts_[tri[0]]];
const float3 &v1_su = surface_positions_[surface_corner_verts_[tri[1]]];
const float3 &v2_su = surface_positions_[surface_corner_verts_[tri[2]]];
float3 bary_coords;
interp_weights_tri_v3(bary_coords, v0_su, v1_su, v2_su, closest_pos_su);
const float3 normal_su = geometry::compute_surface_point_normal(
lt, bary_coords, corner_normals_su_);
tri, bary_coords, corner_normals_su_);
const float3 normal_cu = math::normalize(
math::transform_direction(transforms_.surface_to_curves_normal, normal_su));

@ -100,7 +100,7 @@ struct SlideOperationExecutor {
Object *surface_ob_orig_ = nullptr;
const Mesh *surface_orig_ = nullptr;
Span<MLoopTri> surface_looptris_orig_;
Span<int3> surface_corner_tris_orig_;
VArraySpan<float2> surface_uv_map_orig_;
Span<float3> corner_normals_orig_su_;
@ -108,7 +108,7 @@ struct SlideOperationExecutor {
Mesh *surface_eval_ = nullptr;
Span<float3> surface_positions_eval_;
Span<int> surface_corner_verts_eval_;
Span<MLoopTri> surface_looptris_eval_;
Span<int3> surface_corner_tris_eval_;
VArraySpan<float2> surface_uv_map_eval_;
BVHTreeFromMesh surface_bvh_eval_;
@ -171,7 +171,7 @@ struct SlideOperationExecutor {
report_empty_original_surface(stroke_extension.reports);
return;
}
surface_looptris_orig_ = surface_orig_->looptris();
surface_corner_tris_orig_ = surface_orig_->corner_tris();
corner_normals_orig_su_ = surface_orig_->corner_normals();
surface_uv_map_orig_ = *surface_orig_->attributes().lookup<float2>(uv_map_name,
ATTR_DOMAIN_CORNER);
@ -191,7 +191,7 @@ struct SlideOperationExecutor {
report_empty_evaluated_surface(stroke_extension.reports);
return;
}
surface_looptris_eval_ = surface_eval_->looptris();
surface_corner_tris_eval_ = surface_eval_->corner_tris();
surface_positions_eval_ = surface_eval_->vert_positions();
surface_corner_verts_eval_ = surface_eval_->corner_verts();
surface_uv_map_eval_ = *surface_eval_->attributes().lookup<float2>(uv_map_name,
@ -200,7 +200,7 @@ struct SlideOperationExecutor {
report_missing_uv_map_on_evaluated_surface(stroke_extension.reports);
return;
}
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); });
if (stroke_extension.is_first) {
@ -244,7 +244,8 @@ struct SlideOperationExecutor {
if (!brush_3d.has_value()) {
return;
}
const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_, surface_looptris_orig_};
const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_,
surface_corner_tris_orig_};
for (const float4x4 &brush_transform : brush_transforms) {
self_->slide_info_.append_as();
SlideInfo &slide_info = self_->slide_info_.last();
@ -287,7 +288,7 @@ struct SlideOperationExecutor {
}
/* Compute the normal at the initial surface position. */
const float3 point_no = geometry::compute_surface_point_normal(
surface_looptris_orig_[result.looptri_index],
surface_corner_tris_orig_[result.tri_index],
result.bary_weights,
corner_normals_orig_su_);
const float3 normal_cu = math::normalize(
@ -300,7 +301,8 @@ struct SlideOperationExecutor {
void slide_with_symmetry()
{
const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_, surface_looptris_orig_};
const ReverseUVSampler reverse_uv_sampler_orig{surface_uv_map_orig_,
surface_corner_tris_orig_};
for (const SlideInfo &slide_info : self_->slide_info_) {
this->slide(slide_info.curves_to_slide, reverse_uv_sampler_orig, slide_info.brush_transform);
}
@ -364,25 +366,25 @@ struct SlideOperationExecutor {
const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
/* Find the ray hit that is closest to the initial curve root position. */
int looptri_index_eval;
int tri_index_eval;
float3 hit_pos_eval_su;
if (!this->find_closest_ray_hit(ray_start_su,
ray_direction_su,
old_first_pos_eval_su,
looptri_index_eval,
tri_index_eval,
hit_pos_eval_su))
{
continue;
}
/* Compute the uv of the new surface position on the evaluated mesh. */
const MLoopTri &lt_eval = surface_looptris_eval_[looptri_index_eval];
const int3 &tri_eval = surface_corner_tris_eval_[tri_index_eval];
const float3 bary_weights_eval = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
surface_positions_eval_, surface_corner_verts_eval_, lt_eval, hit_pos_eval_su);
surface_positions_eval_, surface_corner_verts_eval_, tri_eval, hit_pos_eval_su);
const float2 uv = bke::attribute_math::mix3(bary_weights_eval,
surface_uv_map_eval_[lt_eval.tri[0]],
surface_uv_map_eval_[lt_eval.tri[1]],
surface_uv_map_eval_[lt_eval.tri[2]]);
surface_uv_map_eval_[tri_eval[0]],
surface_uv_map_eval_[tri_eval[1]],
surface_uv_map_eval_[tri_eval[2]]);
/* Try to find the same uv on the original surface. */
const ReverseUVSampler::Result result = reverse_uv_sampler_orig.sample(uv);
@ -390,7 +392,7 @@ struct SlideOperationExecutor {
found_invalid_uv_mapping_.store(true);
continue;
}
const MLoopTri &lt_orig = surface_looptris_orig_[result.looptri_index];
const int3 &tri_orig = surface_corner_tris_orig_[result.tri_index];
const float3 &bary_weights_orig = result.bary_weights;
/* Gather old and new surface normal. */
@ -398,14 +400,14 @@ struct SlideOperationExecutor {
const float3 new_normal_cu = math::normalize(
math::transform_point(transforms_.surface_to_curves_normal,
geometry::compute_surface_point_normal(
lt_orig, result.bary_weights, corner_normals_orig_su_)));
tri_orig, result.bary_weights, corner_normals_orig_su_)));
/* Gather old and new surface position. */
const float3 new_first_pos_orig_su = bke::attribute_math::mix3<float3>(
bary_weights_orig,
positions_orig_su[corner_verts_orig[lt_orig.tri[0]]],
positions_orig_su[corner_verts_orig[lt_orig.tri[1]]],
positions_orig_su[corner_verts_orig[lt_orig.tri[2]]]);
positions_orig_su[corner_verts_orig[tri_orig[0]]],
positions_orig_su[corner_verts_orig[tri_orig[1]]],
positions_orig_su[corner_verts_orig[tri_orig[2]]]);
const float3 old_first_pos_orig_cu = self_->initial_positions_cu_[first_point_i];
const float3 new_first_pos_orig_cu = math::transform_point(transforms_.surface_to_curves,
new_first_pos_orig_su);
@ -425,11 +427,11 @@ struct SlideOperationExecutor {
bool find_closest_ray_hit(const float3 &ray_start_su,
const float3 &ray_direction_su,
const float3 &point_su,
int &r_looptri_index,
int &r_tri_index,
float3 &r_hit_pos)
{
float best_dist_sq_su = FLT_MAX;
int best_looptri_index_eval;
int best_tri_index_eval;
float3 best_hit_pos_su;
BLI_bvhtree_ray_cast_all_cpp(
*surface_bvh_eval_.tree,
@ -437,8 +439,8 @@ struct SlideOperationExecutor {
ray_direction_su,
0.0f,
FLT_MAX,
[&](const int looptri_index, const BVHTreeRay &ray, BVHTreeRayHit &hit) {
surface_bvh_eval_.raycast_callback(&surface_bvh_eval_, looptri_index, &ray, &hit);
[&](const int tri_index, const BVHTreeRay &ray, BVHTreeRayHit &hit) {
surface_bvh_eval_.raycast_callback(&surface_bvh_eval_, tri_index, &ray, &hit);
if (hit.index < 0) {
return;
}
@ -447,14 +449,14 @@ struct SlideOperationExecutor {
if (dist_sq_su < best_dist_sq_su) {
best_dist_sq_su = dist_sq_su;
best_hit_pos_su = hit_pos_su;
best_looptri_index_eval = hit.index;
best_tri_index_eval = hit.index;
}
});
if (best_dist_sq_su == FLT_MAX) {
return false;
}
r_looptri_index = best_looptri_index_eval;
r_tri_index = best_tri_index_eval;
r_hit_pos = best_hit_pos_su;
return true;
}

@ -110,6 +110,8 @@
#include "paint_intern.hh"
using blender::int3;
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr);
/* Defines and Structs */
@ -434,8 +436,8 @@ struct ProjPaintState {
const bool *hide_poly_eval;
const int *material_indices;
const bool *sharp_faces_eval;
blender::Span<MLoopTri> looptris_eval;
blender::Span<int> looptri_faces_eval;
blender::Span<int3> corner_tris_eval;
blender::Span<int> corner_tri_faces_eval;
const float (*mloopuv_stencil_eval)[2];
@ -519,21 +521,20 @@ struct VertSeam {
};
/* -------------------------------------------------------------------- */
/** \name MLoopTri accessor functions.
/** \name Corner triangle accessor functions
* \{ */
#define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) \
ps->corner_verts_eval[lt->tri[0]], ps->corner_verts_eval[lt->tri[1]], \
ps->corner_verts_eval[lt->tri[2]],
#define PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri) \
ps->corner_verts_eval[tri[0]], ps->corner_verts_eval[tri[1]], ps->corner_verts_eval[tri[2]],
#define PS_LOOPTRI_AS_UV_3(uvlayer, face_i, lt) \
uvlayer[face_i][lt->tri[0]], uvlayer[face_i][lt->tri[1]], uvlayer[face_i][lt->tri[2]],
#define PS_CORNER_TRI_AS_UV_3(uvlayer, face_i, tri) \
uvlayer[face_i][tri[0]], uvlayer[face_i][tri[1]], uvlayer[face_i][tri[2]],
#define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, face_i, lt) \
#define PS_CORNER_TRI_ASSIGN_UV_3(uv_tri, uvlayer, face_i, tri) \
{ \
(uv_tri)[0] = uvlayer[face_i][lt->tri[0]]; \
(uv_tri)[1] = uvlayer[face_i][lt->tri[1]]; \
(uv_tri)[2] = uvlayer[face_i][lt->tri[2]]; \
(uv_tri)[0] = uvlayer[face_i][tri[0]]; \
(uv_tri)[1] = uvlayer[face_i][tri[1]]; \
(uv_tri)[2] = uvlayer[face_i][tri[2]]; \
} \
((void)0)
@ -565,7 +566,7 @@ static Material *tex_get_material(const ProjPaintState *ps, int face_i)
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const int face_i = ps->looptri_faces_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
Material *ma = tex_get_material(ps, face_i);
return ma ? ma->texpaintslot + ma->paint_active_slot : nullptr;
}
@ -576,7 +577,7 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
return ps->stencil_ima;
}
const int face_i = ps->looptri_faces_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
Material *ma = tex_get_material(ps, face_i);
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : nullptr;
return slot ? slot->ima : ps->canvas_ima;
@ -584,14 +585,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 face_i = ps->looptri_faces_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
Material *ma = tex_get_material(ps, face_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 face_i = ps->looptri_faces_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
Material *ma = tex_get_material(ps, face_i);
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : nullptr;
return slot ? slot->ima : ps->clone_ima;
@ -687,11 +688,11 @@ 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->looptris_eval[tri_index];
const int3 &tri = ps->corner_tris_eval[tri_index];
const float *vtri_ss[3] = {
ps->screenCoords[ps->corner_verts_eval[lt->tri[0]]],
ps->screenCoords[ps->corner_verts_eval[lt->tri[1]]],
ps->screenCoords[ps->corner_verts_eval[lt->tri[2]]],
ps->screenCoords[ps->corner_verts_eval[tri[0]]],
ps->screenCoords[ps->corner_verts_eval[tri[1]]],
ps->screenCoords[ps->corner_verts_eval[tri[2]]],
};
if (isect_point_tri_v2(pt, UNPACK3(vtri_ss))) {
@ -737,8 +738,7 @@ static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, floa
static bool project_paint_PickColor(
const ProjPaintState *ps, const float pt[2], float *rgba_fp, uchar *rgba, const bool interp)
{
const MLoopTri *lt;
const float *lt_tri_uv[3];
const float *tri_uv[3];
float w[3], uv[2];
int tri_index;
Image *ima;
@ -751,14 +751,15 @@ static bool project_paint_PickColor(
return false;
}
lt = &ps->looptris_eval[tri_index];
PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->poly_to_loop_uv, ps->looptri_faces_eval[tri_index], lt);
const int3 &tri = ps->corner_tris_eval[tri_index];
PS_CORNER_TRI_ASSIGN_UV_3(
tri_uv, ps->poly_to_loop_uv, ps->corner_tri_faces_eval[tri_index], tri);
interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
interp_v2_v2v2v2(uv, UNPACK3(tri_uv), w);
ima = project_paint_face_paint_image(ps, tri_index);
/** we must have got the imbuf before getting here. */
int tile_number = project_paint_face_paint_tile(ima, lt_tri_uv[0]);
int tile_number = project_paint_face_paint_tile(ima, tri_uv[0]);
/* XXX get appropriate ImageUser instead */
ImageUser iuser;
BKE_imageuser_default(&iuser);
@ -929,19 +930,19 @@ 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->looptris_eval[tri_index];
const int3 &tri = ps->corner_tris_eval[tri_index];
const float *vtri_ss[3] = {
ps->screenCoords[ps->corner_verts_eval[lt->tri[0]]],
ps->screenCoords[ps->corner_verts_eval[lt->tri[1]]],
ps->screenCoords[ps->corner_verts_eval[lt->tri[2]]],
ps->screenCoords[ps->corner_verts_eval[tri[0]]],
ps->screenCoords[ps->corner_verts_eval[tri[1]]],
ps->screenCoords[ps->corner_verts_eval[tri[2]]],
};
float w[3];
if (do_clip) {
const float *vtri_co[3] = {
ps->vert_positions_eval[ps->corner_verts_eval[lt->tri[0]]],
ps->vert_positions_eval[ps->corner_verts_eval[lt->tri[1]]],
ps->vert_positions_eval[ps->corner_verts_eval[lt->tri[2]]],
ps->vert_positions_eval[ps->corner_verts_eval[tri[0]]],
ps->vert_positions_eval[ps->corner_verts_eval[tri[1]]],
ps->vert_positions_eval[ps->corner_verts_eval[tri[2]]],
};
isect_ret = project_paint_occlude_ptv_clip(
pixelScreenCo, UNPACK3(vtri_ss), UNPACK3(vtri_co), w, ps->is_ortho, ps->rv3d);
@ -1135,10 +1136,10 @@ 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->looptris_eval[tri_index];
const int face_i = ps->looptri_faces_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, face_i, lt)};
float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
const int3 &tri = ps->corner_tris_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
const float *tri_uv[3] = {PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, face_i, tri)};
float winding = cross_tri_v2(tri_uv[0], tri_uv[1], tri_uv[2]);
if (winding > 0) {
ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_CW;
@ -1156,12 +1157,13 @@ static bool check_seam(const ProjPaintState *ps,
int *other_face,
int *orig_fidx)
{
const MLoopTri *orig_lt = &ps->looptris_eval[orig_face];
const int orig_poly_i = ps->looptri_faces_eval[orig_face];
const float *orig_lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_poly_i, orig_lt)};
const int3 &orig_tri = ps->corner_tris_eval[orig_face];
const int orig_poly_i = ps->corner_tri_faces_eval[orig_face];
const float *orig_tri_uv[3] = {
PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, orig_poly_i, orig_tri)};
/* vert indices from face vert order indices */
const uint i1 = ps->corner_verts_eval[orig_lt->tri[orig_i1_fidx]];
const uint i2 = ps->corner_verts_eval[orig_lt->tri[orig_i2_fidx]];
const uint i1 = ps->corner_verts_eval[orig_tri[orig_i1_fidx]];
const uint i2 = ps->corner_verts_eval[orig_tri[orig_i2_fidx]];
LinkNode *node;
/* index in face */
int i1_fidx = -1, i2_fidx = -1;
@ -1170,25 +1172,25 @@ 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->looptris_eval[tri_index];
const int face_i = ps->looptri_faces_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri)};
/* could check if the 2 faces images match here,
* but then there wouldn't be a way to return the opposite face's info */
/* We need to know the order of the verts in the adjacent face
* set the i1_fidx and i2_fidx to (0,1,2,3) */
i1_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i1);
i2_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i2);
i1_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(vert_tri, i1);
i2_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(vert_tri, i2);
/* Only need to check if 'i2_fidx' is valid because
* we know i1_fidx is the same vert on both faces. */
if (i2_fidx != -1) {
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, face_i, lt)};
const float *tri_uv[3] = {PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, face_i, tri)};
Image *tpage = project_paint_face_paint_image(ps, tri_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
int orig_tile = project_paint_face_paint_tile(orig_tpage, orig_lt_tri_uv[0]);
int tile = project_paint_face_paint_tile(tpage, tri_uv[0]);
int orig_tile = project_paint_face_paint_tile(orig_tpage, orig_tri_uv[0]);
BLI_assert(i1_fidx != -1);
@ -1207,8 +1209,8 @@ static bool check_seam(const ProjPaintState *ps,
/* first test if they have the same image */
if ((orig_tpage == tpage) && (orig_tile == tile) &&
cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx]))
cmp_uv(orig_tri_uv[orig_i1_fidx], tri_uv[i1_fidx]) &&
cmp_uv(orig_tri_uv[orig_i2_fidx], tri_uv[i2_fidx]))
{
/* if faces don't have the same winding in uv space,
* they are on the same side so edge is boundary */
@ -1322,7 +1324,7 @@ static void uv_image_outset(const ProjPaintState *ps,
int fidx[2];
uint loop_index;
uint vert[2];
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int3 &tri = ps->corner_tris_eval[tri_index];
float ibuf_inv[2];
@ -1338,7 +1340,7 @@ static void uv_image_outset(const ProjPaintState *ps,
continue;
}
loop_index = lt->tri[fidx[0]];
loop_index = tri[fidx[0]];
seam_data = &ps->loopSeamData[loop_index];
seam_uvs = seam_data->seam_uvs;
@ -1350,7 +1352,7 @@ static void uv_image_outset(const ProjPaintState *ps,
fidx[1] = (fidx[0] == 2) ? 0 : fidx[0] + 1;
vert[0] = ps->corner_verts_eval[loop_index];
vert[1] = ps->corner_verts_eval[lt->tri[fidx[1]]];
vert[1] = ps->corner_verts_eval[tri[fidx[1]]];
for (uint i = 0; i < 2; i++) {
VertSeam *seam;
@ -1405,9 +1407,9 @@ static void insert_seam_vert_array(const ProjPaintState *ps,
const int ibuf_x,
const int ibuf_y)
{
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int face_i = ps->looptri_faces_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, face_i, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
const float *tri_uv[3] = {PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, face_i, tri)};
const int fidx[2] = {fidx1, ((fidx1 + 1) % 3)};
float vec[2];
@ -1417,9 +1419,9 @@ static void insert_seam_vert_array(const ProjPaintState *ps,
vseam->next = nullptr;
vseam->tri = tri_index;
vseam->loop = lt->tri[fidx[0]];
vseam->loop = tri[fidx[0]];
sub_v2_v2v2(vec, lt_tri_uv[fidx[1]], lt_tri_uv[fidx[0]]);
sub_v2_v2v2(vec, tri_uv[fidx[1]], tri_uv[fidx[0]]);
vec[0] *= ibuf_x;
vec[1] *= ibuf_y;
vseam->angle = atan2f(vec[1], vec[0]);
@ -1428,15 +1430,15 @@ static void insert_seam_vert_array(const ProjPaintState *ps,
BLI_assert((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) != 0);
vseam->normal_cw = (ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW);
copy_v2_v2(vseam->uv, lt_tri_uv[fidx[0]]);
copy_v2_v2(vseam->uv, tri_uv[fidx[0]]);
vseam[1] = vseam[0];
vseam[1].angle += vseam[1].angle > 0.0f ? -M_PI : M_PI;
vseam[1].normal_cw = !vseam[1].normal_cw;
copy_v2_v2(vseam[1].uv, lt_tri_uv[fidx[1]]);
copy_v2_v2(vseam[1].uv, tri_uv[fidx[1]]);
for (uint i = 0; i < 2; i++) {
const int vert = ps->corner_verts_eval[lt->tri[fidx[i]]];
const int vert = ps->corner_verts_eval[tri[fidx[i]]];
ListBase *list = &ps->vertSeams[vert];
VertSeam *item = static_cast<VertSeam *>(list->first);
@ -1466,7 +1468,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->looptris_eval[tri_index];
const int3 &tri = ps->corner_tris_eval[tri_index];
LinkNode *node;
/* initialize face winding if needed */
@ -1475,8 +1477,8 @@ static void project_face_seams_init(const ProjPaintState *ps,
}
do {
if (init_all || (ps->corner_verts_eval[lt->tri[fidx[0]]] == vert_index) ||
(ps->corner_verts_eval[lt->tri[fidx[1]]] == vert_index))
if (init_all || (ps->corner_verts_eval[tri[fidx[0]]] == vert_index) ||
(ps->corner_verts_eval[tri[fidx[1]]] == vert_index))
{
if ((ps->faceSeamFlags[tri_index] &
(PROJ_FACE_SEAM0 << fidx[0] | PROJ_FACE_NOSEAM0 << fidx[0])) == 0)
@ -1525,7 +1527,7 @@ static void project_face_seams_init(const ProjPaintState *ps,
continue;
}
vert = ps->corner_verts_eval[lt->tri[fidx[i]]];
vert = ps->corner_verts_eval[tri[fidx[i]]];
for (node = ps->vertFaces[vert]; node; node = node->next) {
const int tri = POINTER_AS_INT(node->link);
@ -1652,15 +1654,12 @@ static float screen_px_line_point_factor_v2_persp(const ProjPaintState *ps,
return line_point_factor_v2(zero, v1_proj, v2_proj);
}
static void project_face_pixel(const float *lt_tri_uv[3],
ImBuf *ibuf_other,
const float w[3],
uchar rgba_ub[4],
float rgba_f[4])
static void project_face_pixel(
const float *tri_uv[3], ImBuf *ibuf_other, const float w[3], uchar rgba_ub[4], float rgba_f[4])
{
float uv_other[2], x, y;
interp_v2_v2v2v2(uv_other, UNPACK3(lt_tri_uv), w);
interp_v2_v2v2v2(uv_other, UNPACK3(tri_uv), w);
/* use */
uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
@ -1687,16 +1686,16 @@ 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->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]]};
const int3 &tri_other = ps->corner_tris_eval[tri_index];
const float *other_tri_uv[3] = {ps->mloopuv_stencil_eval[tri_other[0]],
ps->mloopuv_stencil_eval[tri_other[1]],
ps->mloopuv_stencil_eval[tri_other[2]]};
/* #BKE_image_acquire_ibuf - TODO: this may be slow. */
uchar rgba_ub[4];
float rgba_f[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
project_face_pixel(other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
if (ibuf_other->float_buffer.data) { /* from float to float */
mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) * (1.0f / 3.0f)) * rgba_f[3];
@ -1726,12 +1725,12 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
}
if (ps->do_mask_cavity) {
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri)};
float ca1, ca2, ca3, ca_mask;
ca1 = ps->cavities[lt_vtri[0]];
ca2 = ps->cavities[lt_vtri[1]];
ca3 = ps->cavities[lt_vtri[2]];
ca1 = ps->cavities[vert_tri[0]];
ca2 = ps->cavities[vert_tri[1]];
ca3 = ps->cavities[vert_tri[2]];
ca_mask = w[0] * ca1 + w[1] * ca2 + w[2] * ca3;
ca_mask = BKE_curvemapping_evaluateF(ps->cavity_curve, 0, ca_mask);
@ -1741,16 +1740,16 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
/* calculate mask */
if (ps->do_mask_normal) {
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int face_i = ps->looptri_faces_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri)};
float no[3], angle_cos;
if (!(ps->sharp_faces_eval && ps->sharp_faces_eval[face_i])) {
const float *no1, *no2, *no3;
no1 = ps->vert_normals[lt_vtri[0]];
no2 = ps->vert_normals[lt_vtri[1]];
no3 = ps->vert_normals[lt_vtri[2]];
no1 = ps->vert_normals[vert_tri[0]];
no2 = ps->vert_normals[vert_tri[1]];
no3 = ps->vert_normals[vert_tri[2]];
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@ -1761,9 +1760,9 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
/* In case the normalizing per pixel isn't optimal,
* we could cache or access from evaluated mesh. */
normal_tri_v3(no,
ps->vert_positions_eval[lt_vtri[0]],
ps->vert_positions_eval[lt_vtri[1]],
ps->vert_positions_eval[lt_vtri[2]]);
ps->vert_positions_eval[vert_tri[0]],
ps->vert_positions_eval[vert_tri[1]],
ps->vert_positions_eval[vert_tri[2]]);
}
if (UNLIKELY(ps->is_flip_object)) {
@ -1778,9 +1777,9 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
float viewDirPersp[3];
const float *co1, *co2, *co3;
co1 = ps->vert_positions_eval[lt_vtri[0]];
co2 = ps->vert_positions_eval[lt_vtri[1]];
co3 = ps->vert_positions_eval[lt_vtri[2]];
co1 = ps->vert_positions_eval[vert_tri[0]];
co2 = ps->vert_positions_eval[vert_tri[1]];
co3 = ps->vert_positions_eval[vert_tri[2]];
/* Get the direction from the viewPoint to the pixel and normalize */
viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
@ -1981,22 +1980,22 @@ 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->looptris_eval[tri_index];
const int poly_other_i = ps->looptri_faces_eval[tri_index];
const float *lt_other_tri_uv[3] = {
PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, poly_other_i, lt_other)};
const int3 &tri_other = ps->corner_tris_eval[tri_index];
const int poly_other_i = ps->corner_tri_faces_eval[tri_index];
const float *other_tri_uv[3] = {
PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv_clone, poly_other_i, tri_other)};
/* #BKE_image_acquire_ibuf - TODO: this may be slow. */
if (ibuf->float_buffer.data) {
if (ibuf_other->float_buffer.data) { /* from float to float */
project_face_pixel(
lt_other_tri_uv, ibuf_other, w, nullptr, ((ProjPixelClone *)projPixel)->clonepx.f);
other_tri_uv, ibuf_other, w, nullptr, ((ProjPixelClone *)projPixel)->clonepx.f);
}
else { /* from char to float */
uchar rgba_ub[4];
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, nullptr);
project_face_pixel(other_tri_uv, ibuf_other, w, rgba_ub, nullptr);
srgb_to_linearrgb_uchar4(rgba, rgba_ub);
straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
}
@ -2004,17 +2003,14 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
else {
if (ibuf_other->float_buffer.data) { /* float to char */
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, nullptr, rgba);
project_face_pixel(other_tri_uv, ibuf_other, w, nullptr, rgba);
premul_to_straight_v4(rgba);
linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
}
else { /* char to char */
project_face_pixel(lt_other_tri_uv,
ibuf_other,
w,
((ProjPixelClone *)projPixel)->clonepx.ch,
nullptr);
project_face_pixel(
other_tri_uv, ibuf_other, w, ((ProjPixelClone *)projPixel)->clonepx.ch, nullptr);
}
}
@ -3016,10 +3012,10 @@ static void project_paint_face_init(const ProjPaintState *ps,
ps->projImages + image_index,
};
const MLoopTri *lt = &ps->looptris_eval[tri_index];
const int face_i = ps->looptri_faces_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, face_i, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri)};
const float *tri_uv[3] = {PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, face_i, tri)};
/* UV/pixel seeking data */
/* Image X/Y-Pixel */
@ -3028,7 +3024,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
/* Image floating point UV - same as x, y but from 0.0-1.0 */
float uv[2];
/* vert co screen-space, these will be assigned to lt_vtri[0-2] */
/* vert co screen-space, these will be assigned to vert_tri[0-2] */
const float *v1coSS, *v2coSS, *v3coSS;
/* Vertex screen-space coords. */
@ -3036,7 +3032,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
float w[3], wco[3];
/* for convenience only, these will be assigned to lt_tri_uv[0],1,2 or lt_tri_uv[0],2,3 */
/* for convenience only, these will be assigned to tri_uv[0],1,2 or tri_uv[0],2,3 */
float *uv1co, *uv2co, *uv3co;
float pixelScreenCo[4];
bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
@ -3046,7 +3042,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
/* Variables for getting UV-space bounds. */
/* Bucket bounds in UV space so we can init pixels only for this face. */
float lt_uv_pxoffset[3][2];
float tri_uv_pxoffset[3][2];
float xhalfpx, yhalfpx;
const float ibuf_xf = float(ibuf->x), ibuf_yf = float(ibuf->y);
@ -3060,11 +3056,11 @@ static void project_paint_face_init(const ProjPaintState *ps,
const bool do_backfacecull = ps->do_backfacecull;
const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
vCo[0] = ps->vert_positions_eval[lt_vtri[0]];
vCo[1] = ps->vert_positions_eval[lt_vtri[1]];
vCo[2] = ps->vert_positions_eval[lt_vtri[2]];
vCo[0] = ps->vert_positions_eval[vert_tri[0]];
vCo[1] = ps->vert_positions_eval[vert_tri[1]];
vCo[2] = ps->vert_positions_eval[vert_tri[2]];
/* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
/* Use tri_uv_pxoffset instead of tri_uv so we can offset the UV half a pixel
* this is done so we can avoid offsetting all the pixels by 0.5 which causes
* problems when wrapping negative coords */
xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
@ -3079,23 +3075,23 @@ static void project_paint_face_init(const ProjPaintState *ps,
* but since the first thing most people try is painting onto a quad- better make it work.
*/
lt_uv_pxoffset[0][0] = lt_tri_uv[0][0] - xhalfpx;
lt_uv_pxoffset[0][1] = lt_tri_uv[0][1] - yhalfpx;
tri_uv_pxoffset[0][0] = tri_uv[0][0] - xhalfpx;
tri_uv_pxoffset[0][1] = tri_uv[0][1] - yhalfpx;
lt_uv_pxoffset[1][0] = lt_tri_uv[1][0] - xhalfpx;
lt_uv_pxoffset[1][1] = lt_tri_uv[1][1] - yhalfpx;
tri_uv_pxoffset[1][0] = tri_uv[1][0] - xhalfpx;
tri_uv_pxoffset[1][1] = tri_uv[1][1] - yhalfpx;
lt_uv_pxoffset[2][0] = lt_tri_uv[2][0] - xhalfpx;
lt_uv_pxoffset[2][1] = lt_tri_uv[2][1] - yhalfpx;
tri_uv_pxoffset[2][0] = tri_uv[2][0] - xhalfpx;
tri_uv_pxoffset[2][1] = tri_uv[2][1] - yhalfpx;
{
uv1co = lt_uv_pxoffset[0]; /* Was `lt_tri_uv[i1];`. */
uv2co = lt_uv_pxoffset[1]; /* Was `lt_tri_uv[i2];`. */
uv3co = lt_uv_pxoffset[2]; /* Was `lt_tri_uv[i3];`. */
uv1co = tri_uv_pxoffset[0]; /* Was `tri_uv[i1];`. */
uv2co = tri_uv_pxoffset[1]; /* Was `tri_uv[i2];`. */
uv3co = tri_uv_pxoffset[2]; /* Was `tri_uv[i3];`. */
v1coSS = ps->screenCoords[lt_vtri[0]];
v2coSS = ps->screenCoords[lt_vtri[1]];
v3coSS = ps->screenCoords[lt_vtri[2]];
v1coSS = ps->screenCoords[vert_tri[0]];
v2coSS = ps->screenCoords[vert_tri[1]];
v3coSS = ps->screenCoords[vert_tri[2]];
/* This function gives is a concave polyline in UV space from the clipped tri. */
project_bucket_clip_face(is_ortho,
@ -3160,9 +3156,9 @@ static void project_paint_face_init(const ProjPaintState *ps,
* because it is a relatively expensive operation. */
if (do_clip || do_3d_mapping) {
interp_v3_v3v3v3(wco,
ps->vert_positions_eval[lt_vtri[0]],
ps->vert_positions_eval[lt_vtri[1]],
ps->vert_positions_eval[lt_vtri[2]],
ps->vert_positions_eval[vert_tri[0]],
ps->vert_positions_eval[vert_tri[1]],
ps->vert_positions_eval[vert_tri[2]],
w);
if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
/* Watch out that no code below this needs to run */
@ -3263,22 +3259,22 @@ static void project_paint_face_init(const ProjPaintState *ps,
float fac1, fac2;
/* Pixel-space UVs. */
float lt_puv[3][2];
float tri_puv[3][2];
lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
lt_puv[0][1] = lt_uv_pxoffset[0][1] * ibuf->y;
tri_puv[0][0] = tri_uv_pxoffset[0][0] * ibuf->x;
tri_puv[0][1] = tri_uv_pxoffset[0][1] * ibuf->y;
lt_puv[1][0] = lt_uv_pxoffset[1][0] * ibuf->x;
lt_puv[1][1] = lt_uv_pxoffset[1][1] * ibuf->y;
tri_puv[1][0] = tri_uv_pxoffset[1][0] * ibuf->x;
tri_puv[1][1] = tri_uv_pxoffset[1][1] * ibuf->y;
lt_puv[2][0] = lt_uv_pxoffset[2][0] * ibuf->x;
lt_puv[2][1] = lt_uv_pxoffset[2][1] * ibuf->y;
tri_puv[2][0] = tri_uv_pxoffset[2][0] * ibuf->x;
tri_puv[2][1] = tri_uv_pxoffset[2][1] * ibuf->y;
if ((ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM0) ||
(ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM1) ||
(ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM2))
{
uv_image_outset(ps, lt_uv_pxoffset, lt_puv, tri_index, ibuf->x, ibuf->y);
uv_image_outset(ps, tri_uv_pxoffset, tri_puv, tri_index, ibuf->x, ibuf->y);
}
/* ps->loopSeamUVs can't be modified when threading, now this is done we can unlock. */
@ -3287,9 +3283,9 @@ static void project_paint_face_init(const ProjPaintState *ps,
BLI_thread_unlock(LOCK_CUSTOM1);
}
vCoSS[0] = ps->screenCoords[lt_vtri[0]];
vCoSS[1] = ps->screenCoords[lt_vtri[1]];
vCoSS[2] = ps->screenCoords[lt_vtri[2]];
vCoSS[0] = ps->screenCoords[vert_tri[0]];
vCoSS[1] = ps->screenCoords[vert_tri[1]];
vCoSS[2] = ps->screenCoords[vert_tri[2]];
/* PROJ_FACE_SCALE_SEAM must be slightly less than 1.0f */
if (is_ortho) {
@ -3313,7 +3309,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
{
/* Avoid div by zero. */
if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) {
uint loop_idx = ps->looptris_eval[tri_index].tri[fidx1];
uint loop_idx = ps->corner_tris_eval[tri_index][fidx1];
LoopSeamData *seam_data = &ps->loopSeamData[loop_idx];
float(*seam_uvs)[2] = seam_data->seam_uvs;
@ -3328,8 +3324,10 @@ static void project_paint_face_init(const ProjPaintState *ps,
ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]);
}
interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1);
interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2);
interp_v2_v2v2(
seam_subsection[0], tri_uv_pxoffset[fidx1], tri_uv_pxoffset[fidx2], fac1);
interp_v2_v2v2(
seam_subsection[1], tri_uv_pxoffset[fidx1], tri_uv_pxoffset[fidx2], fac2);
interp_v2_v2v2(seam_subsection[2], seam_uvs[0], seam_uvs[1], fac2);
interp_v2_v2v2(seam_subsection[3], seam_uvs[0], seam_uvs[1], fac1);
@ -3368,14 +3366,14 @@ static void project_paint_face_init(const ProjPaintState *ps,
if ((seam_data->corner_dist_sq[0] > 0.0f) &&
(len_squared_v2v2(puv, seam_data->seam_puvs[0]) <
seam_data->corner_dist_sq[0]) &&
(len_squared_v2v2(puv, lt_puv[fidx1]) > ps->seam_bleed_px_sq))
(len_squared_v2v2(puv, tri_puv[fidx1]) > ps->seam_bleed_px_sq))
{
in_bounds = false;
}
else if ((seam_data->corner_dist_sq[1] > 0.0f) &&
(len_squared_v2v2(puv, seam_data->seam_puvs[1]) <
seam_data->corner_dist_sq[1]) &&
(len_squared_v2v2(puv, lt_puv[fidx2]) > ps->seam_bleed_px_sq))
(len_squared_v2v2(puv, tri_puv[fidx2]) > ps->seam_bleed_px_sq))
{
in_bounds = false;
}
@ -3554,13 +3552,13 @@ 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->looptris_eval[tri_index];
const int face_i = ps->looptri_faces_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, face_i, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int face_i = ps->corner_tri_faces_eval[tri_index];
const float *tri_uv[3] = {PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, face_i, tri)};
/* Image context switching */
tpage = project_paint_face_paint_image(ps, tri_index);
int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
int tile = project_paint_face_paint_tile(tpage, tri_uv[0]);
if (tpage_last != tpage || tile_last != tile) {
tpage_last = tpage;
tile_last = tile;
@ -3605,11 +3603,11 @@ static void project_bucket_init(const ProjPaintState *ps,
static bool project_bucket_face_isect(ProjPaintState *ps,
int bucket_x,
int bucket_y,
const MLoopTri *lt)
const int3 &tri)
{
/* TODO: replace this with a trickier method that uses side-of-line for all
* #ProjPaintState.screenCoords edges against the closest bucket corner. */
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri)};
rctf bucket_bounds;
float p1[2], p2[2], p3[2], p4[2];
const float *v, *v1, *v2, *v3;
@ -3621,15 +3619,15 @@ static bool project_bucket_face_isect(ProjPaintState *ps,
fidx = 2;
do {
v = ps->screenCoords[lt_vtri[fidx]];
v = ps->screenCoords[vert_tri[fidx]];
if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
return true;
}
} while (fidx--);
v1 = ps->screenCoords[lt_vtri[0]];
v2 = ps->screenCoords[lt_vtri[1]];
v3 = ps->screenCoords[lt_vtri[2]];
v1 = ps->screenCoords[vert_tri[0]];
v2 = ps->screenCoords[vert_tri[1]];
v3 = ps->screenCoords[vert_tri[2]];
p1[0] = bucket_bounds.xmin;
p1[1] = bucket_bounds.ymin;
@ -3658,10 +3656,10 @@ static bool project_bucket_face_isect(ProjPaintState *ps,
* TODO: when painting occluded, sort the faces on their min-Z
* and only add faces that faces that are not occluded */
static void project_paint_delayed_face_init(ProjPaintState *ps,
const MLoopTri *lt,
const int3 &corner_tri,
const int tri_index)
{
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, corner_tri)};
float min[2], max[2], *vCoSS;
/* for ps->bucketRect indexing */
int bucketMin[2], bucketMax[2];
@ -3675,7 +3673,7 @@ static void project_paint_delayed_face_init(ProjPaintState *ps,
fidx = 2;
do {
vCoSS = ps->screenCoords[lt_vtri[fidx]];
vCoSS = ps->screenCoords[vert_tri[fidx]];
minmax_v2v2_v2(min, max, vCoSS);
} while (fidx--);
@ -3684,7 +3682,7 @@ static void project_paint_delayed_face_init(ProjPaintState *ps,
for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
has_x_isect = 0;
for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
if (project_bucket_face_isect(ps, bucket_x, bucket_y, lt)) {
if (project_bucket_face_isect(ps, bucket_x, bucket_y, corner_tri)) {
int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
BLI_linklist_prepend_arena(&ps->bucketFaces[bucket_index],
/* cast to a pointer to shut up the compiler */
@ -3709,9 +3707,9 @@ static void project_paint_delayed_face_init(ProjPaintState *ps,
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
/* set as uninitialized */
ps->loopSeamData[lt->tri[0]].seam_uvs[0][0] = FLT_MAX;
ps->loopSeamData[lt->tri[1]].seam_uvs[0][0] = FLT_MAX;
ps->loopSeamData[lt->tri[2]].seam_uvs[0][0] = FLT_MAX;
ps->loopSeamData[corner_tri[0]].seam_uvs[0][0] = FLT_MAX;
ps->loopSeamData[corner_tri[1]].seam_uvs[0][0] = FLT_MAX;
ps->loopSeamData[corner_tri[2]].seam_uvs[0][0] = FLT_MAX;
}
#endif
}
@ -3951,8 +3949,8 @@ static void proj_paint_state_seam_bleed_init(ProjPaintState *ps)
{
if (ps->seam_bleed_px > 0.0f) {
ps->vertFaces = MEM_cnew_array<LinkNode *>(ps->totvert_eval, "paint-vertFaces");
ps->faceSeamFlags = MEM_cnew_array<ushort>(ps->looptris_eval.size(), __func__);
ps->faceWindingFlags = MEM_cnew_array<char>(ps->looptris_eval.size(), __func__);
ps->faceSeamFlags = MEM_cnew_array<ushort>(ps->corner_tris_eval.size(), __func__);
ps->faceWindingFlags = MEM_cnew_array<char>(ps->corner_tris_eval.size(), __func__);
ps->loopSeamData = static_cast<LoopSeamData *>(
MEM_mallocN(sizeof(LoopSeamData) * ps->totloop_eval, "paint-loopSeamUVs"));
ps->vertSeams = MEM_cnew_array<ListBase>(ps->totvert_eval, "paint-vertSeams");
@ -4033,26 +4031,26 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
#ifndef PROJ_DEBUG_NOSEAMBLEED
static void project_paint_bleed_add_face_user(const ProjPaintState *ps,
MemArena *arena,
const MLoopTri *lt,
const int3 &corner_tri,
const int tri_index)
{
/* add face user if we have bleed enabled, set the UV seam flags later */
/* annoying but we need to add all faces even ones we never use elsewhere */
if (ps->seam_bleed_px > 0.0f) {
const int face_i = ps->looptri_faces_eval[tri_index];
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, face_i, lt)};
const int face_i = ps->corner_tri_faces_eval[tri_index];
const float *tri_uv[3] = {PS_CORNER_TRI_AS_UV_3(ps->poly_to_loop_uv, face_i, corner_tri)};
/* Check for degenerate triangles. Degenerate faces cause trouble with bleed computations.
* Ideally this would be checked later, not to add to the cost of computing non-degenerate
* triangles, but that would allow other triangles to still find adjacent seams on degenerate
* triangles, potentially causing incorrect results. */
if (area_tri_v2(UNPACK3(lt_tri_uv)) > 0.0f) {
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
if (area_tri_v2(UNPACK3(tri_uv)) > 0.0f) {
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, corner_tri)};
void *tri_index_p = POINTER_FROM_INT(tri_index);
BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[0]], tri_index_p, arena);
BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[1]], tri_index_p, arena);
BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[2]], tri_index_p, arena);
BLI_linklist_prepend_arena(&ps->vertFaces[vert_tri[0]], tri_index_p, arena);
BLI_linklist_prepend_arena(&ps->vertFaces[vert_tri[1]], tri_index_p, arena);
BLI_linklist_prepend_arena(&ps->vertFaces[vert_tri[2]], tri_index_p, arena);
}
else {
ps->faceSeamFlags[tri_index] |= PROJ_FACE_DEGENERATE;
@ -4109,8 +4107,8 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->faces_num_eval = ps->me_eval->faces_num;
ps->totloop_eval = ps->me_eval->totloop;
ps->looptris_eval = ps->me_eval->looptris();
ps->looptri_faces_eval = ps->me_eval->looptri_faces();
ps->corner_tris_eval = ps->me_eval->corner_tris();
ps->corner_tri_faces_eval = ps->me_eval->corner_tri_faces();
ps->poly_to_loop_uv = static_cast<const float(**)[2]>(
MEM_mallocN(ps->faces_num_eval * sizeof(float(*)[2]), "proj_paint_mtfaces"));
@ -4184,7 +4182,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->looptri_faces_eval[tri_index]] = lc->mloopuv_clone_base;
ps->poly_to_loop_uv_clone[ps->corner_tri_faces_eval[tri_index]] = lc->mloopuv_clone_base;
}
return false;
}
@ -4216,7 +4214,7 @@ static bool project_paint_check_face_paintable(const ProjPaintState *ps,
{
if (ps->do_face_sel) {
int orig_index;
const int face_i = ps->looptri_faces_eval[tri_i];
const int face_i = ps->corner_tri_faces_eval[tri_i];
if ((face_lookup->index_mp_to_orig != nullptr) &&
((orig_index = (face_lookup->index_mp_to_orig[face_i])) != ORIGINDEX_NONE))
{
@ -4226,7 +4224,7 @@ static bool project_paint_check_face_paintable(const ProjPaintState *ps,
}
else {
int orig_index;
const int face_i = ps->looptri_faces_eval[tri_i];
const int face_i = ps->corner_tri_faces_eval[tri_i];
if ((face_lookup->index_mp_to_orig != nullptr) &&
((orig_index = (face_lookup->index_mp_to_orig[face_i])) != ORIGINDEX_NONE))
{
@ -4243,13 +4241,13 @@ struct ProjPaintFaceCoSS {
};
static void proj_paint_face_coSS_init(const ProjPaintState *ps,
const MLoopTri *lt,
const int3 &corner_tri,
ProjPaintFaceCoSS *coSS)
{
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
coSS->v1 = ps->screenCoords[lt_vtri[0]];
coSS->v2 = ps->screenCoords[lt_vtri[1]];
coSS->v3 = ps->screenCoords[lt_vtri[2]];
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, corner_tri)};
coSS->v1 = ps->screenCoords[vert_tri[0]];
coSS->v2 = ps->screenCoords[vert_tri[1]];
coSS->v3 = ps->screenCoords[vert_tri[2]];
}
/* Return true if face should be culled, false otherwise */
@ -4344,12 +4342,12 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
int tile_last = -1, tile;
int image_index = -1, tri_index;
int prev_poly = -1;
const blender::Span<MLoopTri> looptris = ps->looptris_eval;
const blender::Span<int> looptri_faces = ps->looptri_faces_eval;
const blender::Span<int3> corner_tris = ps->corner_tris_eval;
const blender::Span<int> tri_faces = ps->corner_tri_faces_eval;
BLI_assert(ps->image_tot == 0);
for (tri_index = 0; tri_index < ps->looptris_eval.size(); tri_index++) {
for (tri_index = 0; tri_index < ps->corner_tris_eval.size(); tri_index++) {
bool is_face_paintable;
bool skip_tri = false;
@ -4400,12 +4398,12 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
tpage = ps->stencil_ima;
}
ps->poly_to_loop_uv[looptri_faces[tri_index]] = mloopuv_base;
ps->poly_to_loop_uv[tri_faces[tri_index]] = mloopuv_base;
tile = project_paint_face_paint_tile(tpage, mloopuv_base[looptris[tri_index].tri[0]]);
tile = project_paint_face_paint_tile(tpage, mloopuv_base[corner_tris[tri_index][0]]);
#ifndef PROJ_DEBUG_NOSEAMBLEED
project_paint_bleed_add_face_user(ps, arena, &looptris[tri_index], tri_index);
project_paint_bleed_add_face_user(ps, arena, corner_tris[tri_index], tri_index);
#endif
if (skip_tri || project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
@ -4416,7 +4414,7 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
if (is_face_paintable && tpage) {
ProjPaintFaceCoSS coSS;
proj_paint_face_coSS_init(ps, &looptris[tri_index], &coSS);
proj_paint_face_coSS_init(ps, corner_tris[tri_index], &coSS);
if (is_multi_view == false) {
if (project_paint_flt_max_cull(ps, &coSS)) {
@ -4433,10 +4431,10 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
/* Back-face culls individual triangles but mask normal will use face. */
if (ps->do_backfacecull) {
if (ps->do_mask_normal) {
if (prev_poly != looptri_faces[tri_index]) {
if (prev_poly != tri_faces[tri_index]) {
bool culled = true;
const blender::IndexRange poly = ps->faces_eval[looptri_faces[tri_index]];
prev_poly = looptri_faces[tri_index];
const blender::IndexRange poly = ps->faces_eval[tri_faces[tri_index]];
prev_poly = tri_faces[tri_index];
for (const int corner : poly) {
if (!(ps->vertFlags[ps->corner_verts_eval[corner]] & PROJ_VERT_CULL)) {
culled = false;
@ -4496,7 +4494,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, &looptris[tri_index], tri_index);
project_paint_delayed_face_init(ps, corner_tris[tri_index], tri_index);
}
}
}
@ -5746,15 +5744,15 @@ 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->looptris_eval[tri_index];
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
const int3 &tri = ps->corner_tris_eval[tri_index];
const int vert_tri[3] = {PS_CORNER_TRI_AS_VERT_INDEX_3(ps, tri)};
float world[3];
UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;
interp_v3_v3v3v3(world,
ps->vert_positions_eval[lt_vtri[0]],
ps->vert_positions_eval[lt_vtri[1]],
ps->vert_positions_eval[lt_vtri[2]],
ps->vert_positions_eval[vert_tri[0]],
ps->vert_positions_eval[vert_tri[1]],
ps->vert_positions_eval[vert_tri[2]],
w);
ups->average_stroke_counter++;

@ -1683,10 +1683,10 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
BM_mesh_bm_from_me(bm, trim_mesh, &bm_from_me_params);
BM_mesh_bm_from_me(bm, sculpt_mesh, &bm_from_me_params);
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
BMLoop *(*looptris)[3] = static_cast<BMLoop *(*)[3]>(
MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__));
BM_mesh_calc_tessellation_beauty(bm, looptris);
const int corner_tris_tot = poly_to_tri_count(bm->totface, bm->totloop);
BMLoop *(*corner_tris)[3] = static_cast<BMLoop *(*)[3]>(
MEM_malloc_arrayN(corner_tris_tot, sizeof(*corner_tris), __func__));
BM_mesh_calc_tessellation_beauty(bm, corner_tris);
BMIter iter;
int i;
@ -1734,8 +1734,8 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
break;
}
BM_mesh_boolean(bm,
looptris,
looptris_tot,
corner_tris,
corner_tris_tot,
bm_face_isect_pair,
nullptr,
2,
@ -1745,7 +1745,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
boolean_mode);
}
MEM_freeN(looptris);
MEM_freeN(corner_tris);
BMeshToMeshParams convert_params{};
convert_params.calc_object_remap = false;

@ -274,8 +274,8 @@ static void imapaint_pick_uv(const Mesh *me_eval,
int view[4];
const ePaintCanvasSource mode = ePaintCanvasSource(scene->toolsettings->imapaint.mode);
const blender::Span<MLoopTri> tris = me_eval->looptris();
const blender::Span<int> looptri_faces = me_eval->looptri_faces();
const blender::Span<blender::int3> tris = me_eval->corner_tris();
const blender::Span<int> tri_faces = me_eval->corner_tri_faces();
const blender::Span<blender::float3> positions = me_eval->vert_positions();
const blender::Span<int> corner_verts = me_eval->corner_verts();
@ -299,7 +299,7 @@ static void imapaint_pick_uv(const Mesh *me_eval,
/* test all faces in the derivedmesh with the original index of the picked face */
/* face means poly here, not triangle, indeed */
for (const int i : tris.index_range()) {
const int face_i = looptri_faces[i];
const int face_i = tri_faces[i];
const int findex = index_mp_to_orig ? index_mp_to_orig[face_i] : face_i;
if (findex == faceindex) {
@ -308,7 +308,7 @@ static void imapaint_pick_uv(const Mesh *me_eval,
float tri_co[3][3];
for (int j = 3; j--;) {
copy_v3_v3(tri_co[j], positions[corner_verts[tris[i].tri[j]]]);
copy_v3_v3(tri_co[j], positions[corner_verts[tris[i][j]]]);
}
if (mode == PAINT_CANVAS_SOURCE_MATERIAL) {
@ -332,9 +332,9 @@ static void imapaint_pick_uv(const Mesh *me_eval,
CustomData_get_layer(&me_eval->loop_data, CD_PROP_FLOAT2));
}
tri_uv[0] = mloopuv[tris[i].tri[0]];
tri_uv[1] = mloopuv[tris[i].tri[1]];
tri_uv[2] = mloopuv[tris[i].tri[2]];
tri_uv[0] = mloopuv[tris[i][0]];
tri_uv[1] = mloopuv[tris[i][1]];
tri_uv[2] = mloopuv[tris[i][2]];
p[0] = xy[0];
p[1] = xy[1];

@ -34,9 +34,12 @@ static void snap_object_data_mesh_get(const Mesh *me_eval,
bool use_hide,
BVHTreeFromMesh *r_treedata)
{
/* The BVHTree from looptris is always required. */
BKE_bvhtree_from_mesh_get(
r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRIS_NO_HIDDEN : BVHTREE_FROM_LOOPTRIS, 4);
/* The BVHTree from corner_tris is always required. */
BKE_bvhtree_from_mesh_get(r_treedata,
me_eval,
use_hide ? BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN :
BVHTREE_FROM_CORNER_TRIS,
4);
}
/** \} */
@ -49,18 +52,18 @@ static void snap_object_data_mesh_get(const Mesh *me_eval,
* Support for storing all depths, not just the first (ray-cast 'all'). */
/* Callback to ray-cast with back-face culling (#Mesh). */
static void mesh_looptris_raycast_backface_culling_cb(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
static void mesh_corner_tris_raycast_backface_culling_cb(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const blender::Span<blender::float3> positions = data->vert_positions;
const MLoopTri *lt = &data->looptris[index];
const int3 &tri = data->corner_tris[index];
const float *vtri_co[3] = {
positions[data->corner_verts[lt->tri[0]]],
positions[data->corner_verts[lt->tri[1]]],
positions[data->corner_verts[lt->tri[2]]],
positions[data->corner_verts[tri[0]]],
positions[data->corner_verts[tri[1]]],
positions[data->corner_verts[tri[2]]],
};
float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
@ -131,7 +134,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
BVHTreeFromMesh treedata;
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
const blender::Span<int> looptri_faces = me_eval->looptri_faces();
const blender::Span<int> tri_faces = me_eval->corner_tri_faces();
if (treedata.tree == nullptr) {
return retval;
@ -166,14 +169,14 @@ static bool raycastMesh(SnapObjectContext *sctx,
0.0f,
&hit,
sctx->runtime.params.use_backface_culling ?
mesh_looptris_raycast_backface_culling_cb :
mesh_corner_tris_raycast_backface_culling_cb :
treedata.raycast_callback,
&treedata) != -1)
{
hit.dist += len_diff;
hit.dist /= local_scale;
if (hit.dist <= depth_max) {
hit.index = looptri_faces[hit.index];
hit.index = tri_faces[hit.index];
retval = true;
}
SnapData::register_result_raycast(sctx, ob_eval, &me_eval->id, obmat, &hit, is_in_front);
@ -224,7 +227,7 @@ class SnapData_Mesh : public SnapData {
const int2 *edges; /* only used for #BVHTreeFromMeshEdges */
const int *corner_verts;
const int *corner_edges;
const MLoopTri *looptris;
const int3 *corner_tris;
SnapData_Mesh(SnapObjectContext *sctx, const Mesh *mesh_eval, const float4x4 &obmat)
: SnapData(sctx, obmat)
@ -234,7 +237,7 @@ class SnapData_Mesh : public SnapData {
this->edges = mesh_eval->edges().data();
this->corner_verts = mesh_eval->corner_verts().data();
this->corner_edges = mesh_eval->corner_edges().data();
this->looptris = mesh_eval->looptris().data();
this->corner_tris = mesh_eval->corner_tris().data();
};
void get_vert_co(const int index, const float **r_co)
@ -286,10 +289,10 @@ static void cb_snap_tri_verts(void *userdata,
int vindex[3];
const int *corner_verts = data->corner_verts;
const MLoopTri *lt = &data->looptris[index];
vindex[0] = corner_verts[lt->tri[0]];
vindex[1] = corner_verts[lt->tri[1]];
vindex[2] = corner_verts[lt->tri[2]];
const int3 &tri = data->corner_tris[index];
vindex[0] = corner_verts[tri[0]];
vindex[1] = corner_verts[tri[1]];
vindex[2] = corner_verts[tri[2]];
if (data->use_backface_culling) {
const float3 *vert_positions = data->vert_positions;
@ -319,13 +322,13 @@ static void cb_snap_tri_edges(void *userdata,
{
SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
const int *corner_verts = data->corner_verts;
const MLoopTri *lt = &data->looptris[index];
const int3 &tri = data->corner_tris[index];
if (data->use_backface_culling) {
const float3 *vert_positions = data->vert_positions;
const float3 &t0 = vert_positions[corner_verts[lt->tri[0]]];
const float3 &t1 = vert_positions[corner_verts[lt->tri[1]]];
const float3 &t2 = vert_positions[corner_verts[lt->tri[2]]];
const float3 &t0 = vert_positions[corner_verts[tri[0]]];
const float3 &t1 = vert_positions[corner_verts[tri[1]]];
const float3 &t2 = vert_positions[corner_verts[tri[2]]];
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@ -335,9 +338,9 @@ static void cb_snap_tri_edges(void *userdata,
const int2 *edges = data->edges;
const int *corner_edges = data->corner_edges;
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
int eindex = corner_edges[lt->tri[j]];
int eindex = corner_edges[tri[j]];
const int2 &edge = edges[eindex];
const int2 tri_edge = {corner_verts[lt->tri[j]], corner_verts[lt->tri[j_next]]};
const int2 tri_edge = {corner_verts[tri[j]], corner_verts[tri[j_next]]};
if (ELEM(edge[0], tri_edge[0], tri_edge[1]) && ELEM(edge[1], tri_edge[0], tri_edge[1])) {
if (eindex == nearest->index) {
continue;
@ -513,7 +516,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
}
if (treedata.tree) {
/* Snap to looptris. */
/* Snap to corner_tris. */
BLI_bvhtree_find_nearest_projected(
treedata.tree,
nearest2d.pmat_local.ptr(),
@ -547,7 +550,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
}
if (treedata.tree) {
/* Snap to looptris verts. */
/* Snap to corner_tris verts. */
BLI_bvhtree_find_nearest_projected(
treedata.tree,
nearest2d.pmat_local.ptr(),

@ -390,14 +390,14 @@ int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3
return 0;
}
static bool testEdgeMark(Mesh *mesh, const FreestyleEdge *fed, const MLoopTri *lt, int i)
static bool testEdgeMark(Mesh *mesh, const FreestyleEdge *fed, const blender::int3 &tri, int i)
{
const Span<blender::int2> edges = mesh->edges();
const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges();
const int corner = lt->tri[i];
const int corner_next = lt->tri[(i + 1) % 3];
const int corner = tri[i];
const int corner_next = tri[(i + 1) % 3];
const blender::int2 &edge = edges[corner_edges[corner]];
if (!ELEM(corner_verts[corner_next], edge[0], edge[1])) {
@ -419,9 +419,11 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
// Compute loop triangles
int tottri = poly_to_tri_count(mesh->faces_num, mesh->totloop);
MLoopTri *looptris = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*looptris), __func__);
blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, corner_verts, {looptris, tottri});
const blender::Span<int> looptri_faces = mesh->looptri_faces();
blender::int3 *corner_tris = (blender::int3 *)MEM_malloc_arrayN(
tottri, sizeof(*corner_tris), __func__);
blender::bke::mesh::corner_tris_calc(
vert_positions, mesh_polys, corner_verts, {corner_tris, tottri});
const blender::Span<int> tri_faces = mesh->corner_tri_faces();
const blender::Span<blender::float3> lnors = mesh->corner_normals();
// Get other mesh data
@ -449,11 +451,11 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
float n1[3], n2[3], n3[3], facenormal[3];
int clip[3];
for (int a = 0; a < tottri; a++) {
const MLoopTri *lt = &looptris[a];
const int3 &tri = corner_tris[a];
copy_v3_v3(v1, vert_positions[corner_verts[lt->tri[0]]]);
copy_v3_v3(v2, vert_positions[corner_verts[lt->tri[1]]]);
copy_v3_v3(v3, vert_positions[corner_verts[lt->tri[2]]]);
copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
mul_m4_v3(obmat, v1);
mul_m4_v3(obmat, v2);
@ -471,7 +473,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
}
#endif
if (numFaces == 0) {
MEM_freeN(looptris);
MEM_freeN(corner_tris);
return;
}
@ -523,13 +525,13 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
// We parse the vlak nodes again and import meshes while applying the clipping
// by the near and far view planes.
for (int a = 0; a < tottri; a++) {
const MLoopTri *lt = &looptris[a];
const int poly_i = looptri_faces[a];
const int3 &tri = corner_tris[a];
const int poly_i = tri_faces[a];
Material *mat = BKE_object_material_get(ob, material_indices[poly_i] + 1);
copy_v3_v3(v1, vert_positions[corner_verts[lt->tri[0]]]);
copy_v3_v3(v2, vert_positions[corner_verts[lt->tri[1]]]);
copy_v3_v3(v3, vert_positions[corner_verts[lt->tri[2]]]);
copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
mul_m4_v3(obmat, v1);
mul_m4_v3(obmat, v2);
@ -540,9 +542,9 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
v3[2] += _z_offset;
if (_smooth && (!sharp_faces[poly_i])) {
copy_v3_v3(n1, lnors[lt->tri[0]]);
copy_v3_v3(n2, lnors[lt->tri[1]]);
copy_v3_v3(n3, lnors[lt->tri[2]]);
copy_v3_v3(n1, lnors[tri[0]]);
copy_v3_v3(n2, lnors[tri[1]]);
copy_v3_v3(n3, lnors[tri[2]]);
mul_mat3_m4_v3(nmat, n1);
mul_mat3_m4_v3(nmat, n2);
@ -569,9 +571,9 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
bool em1 = false, em2 = false, em3 = false;
if (fed) {
em1 = testEdgeMark(mesh, fed, lt, 0);
em2 = testEdgeMark(mesh, fed, lt, 1);
em3 = testEdgeMark(mesh, fed, lt, 2);
em1 = testEdgeMark(mesh, fed, tri, 0);
em2 = testEdgeMark(mesh, fed, tri, 1);
em3 = testEdgeMark(mesh, fed, tri, 2);
}
if (mat) {
@ -631,7 +633,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *mesh, int id)
}
}
MEM_freeN(looptris);
MEM_freeN(corner_tris);
// We might have several times the same vertex. We want a clean
// shape with no real-vertex. Here, we are making a cleaning pass.

@ -33,7 +33,7 @@ struct AddCurvesOnMeshInputs {
/** Information about the surface that the new curves are attached to. */
const Mesh *surface = nullptr;
Span<MLoopTri> surface_looptris;
Span<int3> surface_corner_tris;
const ReverseUVSampler *reverse_uv_sampler = nullptr;
Span<float3> corner_normals_su;
@ -60,7 +60,7 @@ struct AddCurvesOnMeshOutputs {
AddCurvesOnMeshOutputs add_curves_on_mesh(bke::CurvesGeometry &curves,
const AddCurvesOnMeshInputs &inputs);
float3 compute_surface_point_normal(const MLoopTri &lt,
float3 compute_surface_point_normal(const int3 &tri,
const float3 &bary_coord,
Span<float3> corner_normals);

@ -22,12 +22,12 @@ namespace blender::geometry {
class ReverseUVSampler {
private:
Span<float2> uv_map_;
Span<MLoopTri> looptris_;
Span<int3> corner_tris_;
int resolution_;
MultiValueMap<int2, int> looptris_by_cell_;
MultiValueMap<int2, int> corner_tris_by_cell_;
public:
ReverseUVSampler(Span<float2> uv_map, Span<MLoopTri> looptris);
ReverseUVSampler(Span<float2> uv_map, Span<int3> corner_tris);
enum class ResultType {
None,
@ -37,7 +37,7 @@ class ReverseUVSampler {
struct Result {
ResultType type = ResultType::None;
int looptri_index = -1;
int tri_index = -1;
float3 bary_weights;
};

@ -37,12 +37,12 @@ struct NeighborCurve {
static constexpr int max_neighbors = 5;
using NeighborCurves = Vector<NeighborCurve, max_neighbors>;
float3 compute_surface_point_normal(const MLoopTri &lt,
float3 compute_surface_point_normal(const int3 &corner_tri,
const float3 &bary_coord,
const Span<float3> corner_normals)
{
const float3 value = bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
bary_coord, lt, corner_normals);
bary_coord, corner_tri, corner_normals);
return math::normalize(value);
}
@ -141,7 +141,7 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves,
const Span<float> new_lengths_cu,
const Span<float3> new_normals_su,
const bke::CurvesSurfaceTransforms &transforms,
const Span<MLoopTri> looptris,
const Span<int3> corner_tris,
const ReverseUVSampler &reverse_uv_sampler,
const Span<float3> corner_normals_su)
{
@ -182,7 +182,7 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves,
}
const float3 neighbor_normal_su = compute_surface_point_normal(
looptris[result.looptri_index], result.bary_weights, corner_normals_su);
corner_tris[result.tri_index], result.bary_weights, corner_normals_su);
const float3 neighbor_normal_cu = math::normalize(
math::transform_direction(transforms.surface_to_curves_normal, neighbor_normal_su));
@ -245,7 +245,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
Vector<float3> root_positions_cu;
Vector<float3> bary_coords;
Vector<int> looptri_indices;
Vector<int> tri_indices;
Vector<float2> used_uvs;
/* Find faces that the passed in uvs belong to. */
@ -258,14 +258,14 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
outputs.uv_error = true;
continue;
}
const MLoopTri &lt = inputs.surface_looptris[result.looptri_index];
const int3 &tri = inputs.surface_corner_tris[result.tri_index];
bary_coords.append(result.bary_weights);
looptri_indices.append(result.looptri_index);
tri_indices.append(result.tri_index);
const float3 root_position_su = bke::attribute_math::mix3<float3>(
result.bary_weights,
surface_positions[surface_corner_verts[lt.tri[0]]],
surface_positions[surface_corner_verts[lt.tri[1]]],
surface_positions[surface_corner_verts[lt.tri[2]]]);
surface_positions[surface_corner_verts[tri[0]]],
surface_positions[surface_corner_verts[tri[1]]],
surface_positions[surface_corner_verts[tri[2]]]);
root_positions_cu.append(
math::transform_point(inputs.transforms->surface_to_curves, root_position_su));
used_uvs.append(uv);
@ -348,8 +348,8 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
/* Find surface normal at root points. */
Array<float3> new_normals_su(added_curves_num);
bke::mesh_surface_sample::sample_corner_normals(inputs.surface_looptris,
looptri_indices,
bke::mesh_surface_sample::sample_corner_normals(inputs.surface_corner_tris,
tri_indices,
bary_coords,
inputs.corner_normals_su,
IndexMask(added_curves_num),
@ -364,7 +364,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
new_lengths_cu,
new_normals_su,
*inputs.transforms,
inputs.surface_looptris,
inputs.surface_corner_tris,
*inputs.reverse_uv_sampler,
inputs.corner_normals_su);
}

@ -70,7 +70,7 @@ void solve_length_and_collision_constraints(const OffsetIndices<int> points_by_c
solve_length_constraints(points_by_curve, curve_selection, segment_lengths_cu, positions_cu);
BVHTreeFromMesh surface_bvh;
BKE_bvhtree_from_mesh_get(&surface_bvh, &surface, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&surface_bvh, &surface, BVHTREE_FROM_CORNER_TRIS, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
const float radius = 0.005f;

@ -2,6 +2,7 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_enumerable_thread_specific.hh"

@ -26,7 +26,7 @@ class OpenVDBMeshAdapter {
private:
Span<float3> positions_;
Span<int> corner_verts_;
Span<MLoopTri> looptris_;
Span<int3> corner_tris_;
float4x4 transform_;
public:
@ -40,14 +40,14 @@ class OpenVDBMeshAdapter {
OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform)
: positions_(mesh.vert_positions()),
corner_verts_(mesh.corner_verts()),
looptris_(mesh.looptris()),
corner_tris_(mesh.corner_tris()),
transform_(transform)
{
}
size_t OpenVDBMeshAdapter::polygonCount() const
{
return size_t(looptris_.size());
return size_t(corner_tris_.size());
}
size_t OpenVDBMeshAdapter::pointCount() const
@ -65,9 +65,9 @@ void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
size_t vertex_index,
openvdb::Vec3d &pos) const
{
const MLoopTri &lt = looptris_[polygon_index];
const int3 &tri = corner_tris_[polygon_index];
const float3 transformed_co = math::transform_point(
transform_, positions_[corner_verts_[lt.tri[vertex_index]]]);
transform_, positions_[corner_verts_[tri[vertex_index]]]);
pos = &transformed_co.x;
}
@ -150,10 +150,10 @@ static openvdb::FloatGrid::Ptr mesh_to_sdf_volume_grid(const Mesh &mesh,
const Span<float3> positions = mesh.vert_positions();
const Span<int> corner_verts = mesh.corner_verts();
const Span<MLoopTri> looptris = mesh.looptris();
const Span<int3> corner_tris = mesh.corner_tris();
std::vector<openvdb::Vec3s> points(positions.size());
std::vector<openvdb::Vec3I> triangles(looptris.size());
std::vector<openvdb::Vec3I> triangles(corner_tris.size());
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
@ -162,11 +162,11 @@ static openvdb::FloatGrid::Ptr mesh_to_sdf_volume_grid(const Mesh &mesh,
}
});
threading::parallel_for(looptris.index_range(), 2048, [&](const IndexRange range) {
threading::parallel_for(corner_tris.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
const MLoopTri &lt = looptris[i];
const int3 &tri = corner_tris[i];
triangles[i] = openvdb::Vec3I(
corner_verts[lt.tri[0]], corner_verts[lt.tri[1]], corner_verts[lt.tri[2]]);
corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]);
}
});

@ -16,16 +16,16 @@ static int2 uv_to_cell_key(const float2 &uv, const int resolution)
return int2{uv * resolution};
}
ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris)
: uv_map_(uv_map), looptris_(looptris)
ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<int3> corner_tris)
: uv_map_(uv_map), corner_tris_(corner_tris)
{
resolution_ = std::max<int>(3, std::sqrt(looptris.size()) * 2);
resolution_ = std::max<int>(3, std::sqrt(corner_tris.size()) * 2);
for (const int looptri_index : looptris.index_range()) {
const MLoopTri &lt = looptris[looptri_index];
const float2 &uv_0 = uv_map_[lt.tri[0]];
const float2 &uv_1 = uv_map_[lt.tri[1]];
const float2 &uv_2 = uv_map_[lt.tri[2]];
for (const int tri_i : corner_tris.index_range()) {
const int3 &tri = corner_tris[tri_i];
const float2 &uv_0 = uv_map_[tri[0]];
const float2 &uv_1 = uv_map_[tri[1]];
const float2 &uv_2 = uv_map_[tri[2]];
const int2 key_0 = uv_to_cell_key(uv_0, resolution_);
const int2 key_1 = uv_to_cell_key(uv_1, resolution_);
@ -37,7 +37,7 @@ ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTr
for (int key_x = min_key.x; key_x <= max_key.x; key_x++) {
for (int key_y = min_key.y; key_y <= max_key.y; key_y++) {
const int2 key{key_x, key_y};
looptris_by_cell_.add(key, looptri_index);
corner_tris_by_cell_.add(key, tri_i);
}
}
}
@ -46,22 +46,22 @@ ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTr
ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
{
const int2 cell_key = uv_to_cell_key(query_uv, resolution_);
const Span<int> looptri_indices = looptris_by_cell_.lookup(cell_key);
const Span<int> tri_indices = corner_tris_by_cell_.lookup(cell_key);
float best_dist = FLT_MAX;
float3 best_bary_weights;
int best_looptri_index;
int best_tri_index;
/* The distance to an edge that is allowed to be inside or outside the triangle. Without this,
* the lookup can fail for floating point accuracy reasons when the uv is almost exact on an
* edge. */
const float edge_epsilon = 0.00001f;
for (const int looptri_index : looptri_indices) {
const MLoopTri &lt = looptris_[looptri_index];
const float2 &uv_0 = uv_map_[lt.tri[0]];
const float2 &uv_1 = uv_map_[lt.tri[1]];
const float2 &uv_2 = uv_map_[lt.tri[2]];
for (const int tri_i : tri_indices) {
const int3 &tri = corner_tris_[tri_i];
const float2 &uv_0 = uv_map_[tri[0]];
const float2 &uv_1 = uv_map_[tri[1]];
const float2 &uv_2 = uv_map_[tri[2]];
float3 bary_weights;
if (!barycentric_coords_v2(uv_0, uv_1, uv_2, query_uv, bary_weights)) {
continue;
@ -86,14 +86,14 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
if (dist < best_dist) {
best_dist = dist;
best_bary_weights = bary_weights;
best_looptri_index = looptri_index;
best_tri_index = tri_i;
}
}
/* Allow using the closest (but not intersecting) triangle if the uv is almost exactly on an
* edge. */
if (best_dist < edge_epsilon) {
return Result{ResultType::Ok, best_looptri_index, math::clamp(best_bary_weights, 0.0f, 1.0f)};
return Result{ResultType::Ok, best_tri_index, math::clamp(best_bary_weights, 0.0f, 1.0f)};
}
return Result{};

@ -59,6 +59,8 @@
#include <algorithm> /* For `min/max`. */
using blender::int3;
struct LineartIsecSingle {
double v1[3], v2[3];
LineartTriangle *tri1, *tri2;
@ -1471,8 +1473,8 @@ struct EdgeFeatData {
blender::Span<blender::int2> edges;
blender::Span<int> corner_verts;
blender::Span<int> corner_edges;
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<int3> corner_tris;
blender::Span<int> tri_faces;
LineartTriangle *tri_array;
blender::VArray<bool> sharp_edges;
blender::VArray<bool> sharp_faces;
@ -1499,17 +1501,17 @@ static void feat_data_sum_reduce(const void *__restrict /*userdata*/,
feat_chunk_join->feat_edges += feat_chunk->feat_edges;
}
static void lineart_identify_looptri_feature_edges(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict tls)
static void lineart_identify_corner_tri_feature_edges(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict tls)
{
EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
Mesh *mesh = e_feat_data->mesh;
Object *ob_eval = e_feat_data->ob_eval;
LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
const blender::Span<MLoopTri> looptris = e_feat_data->looptris;
const blender::Span<int> looptri_faces = e_feat_data->looptri_faces;
const blender::Span<int3> corner_tris = e_feat_data->corner_tris;
const blender::Span<int> tri_faces = e_feat_data->tri_faces;
const blender::Span<int> material_indices = e_feat_data->material_indices;
uint16_t edge_flag_result = 0;
@ -1528,11 +1530,10 @@ static void lineart_identify_looptri_feature_edges(void *__restrict userdata,
FreestyleFace *ff1, *ff2;
int index = e_feat_data->freestyle_face_index;
if (index > -1) {
ff1 = &((FreestyleFace *)mesh->face_data.layers[index].data)[looptri_faces[i / 3]];
ff1 = &((FreestyleFace *)mesh->face_data.layers[index].data)[tri_faces[i / 3]];
}
if (edge_nabr[i].e > -1) {
ff2 = &(
(FreestyleFace *)mesh->face_data.layers[index].data)[looptri_faces[edge_nabr[i].e / 3]];
ff2 = &((FreestyleFace *)mesh->face_data.layers[index].data)[tri_faces[edge_nabr[i].e / 3]];
}
else {
/* Handle mesh boundary cases: We want mesh boundaries to respect
@ -1646,8 +1647,7 @@ static void lineart_identify_looptri_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->sharp_faces[looptri_faces[f1]]) &&
(!e_feat_data->sharp_faces[looptri_faces[f2]]))
(!e_feat_data->sharp_faces[tri_faces[f1]]) && (!e_feat_data->sharp_faces[tri_faces[f2]]))
{
do_crease = false;
}
@ -1656,8 +1656,8 @@ static void lineart_identify_looptri_feature_edges(void *__restrict userdata,
}
}
int mat1 = material_indices.is_empty() ? 0 : material_indices[looptri_faces[f1]];
int mat2 = material_indices.is_empty() ? 0 : material_indices[looptri_faces[f2]];
int mat1 = material_indices.is_empty() ? 0 : material_indices[tri_faces[f1]];
int mat2 = material_indices.is_empty() ? 0 : material_indices[tri_faces[f2]];
if (mat1 != mat2) {
Material *m1 = BKE_object_material_get_eval(ob_eval, mat1 + 1);
@ -1681,8 +1681,11 @@ static void lineart_identify_looptri_feature_edges(void *__restrict userdata,
}
}
const blender::int3 real_edges = blender::bke::mesh::looptri_get_real_edges(
e_feat_data->edges, e_feat_data->corner_verts, e_feat_data->corner_edges, looptris[i / 3]);
const blender::int3 real_edges = blender::bke::mesh::corner_tri_get_real_edges(
e_feat_data->edges,
e_feat_data->corner_verts,
e_feat_data->corner_edges,
corner_tris[i / 3]);
if (real_edges[i % 3] >= 0) {
if (ld->conf.use_crease && ld->conf.sharp_as_crease &&
@ -1789,8 +1792,8 @@ struct TriData {
LineartObjectInfo *ob_info;
blender::Span<blender::float3> positions;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<int3> corner_tris;
blender::Span<int> tri_faces;
blender::Span<int> material_indices;
LineartVert *vert_arr;
LineartTriangle *tri_arr;
@ -1806,8 +1809,8 @@ 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<int> corner_verts = tri_task_data->corner_verts;
const MLoopTri *lt = &tri_task_data->looptris[i];
const int face_i = tri_task_data->looptri_faces[i];
const int3 &corner_tri = tri_task_data->corner_tris[i];
const int face_i = tri_task_data->tri_faces[i];
const blender::Span<int> material_indices = tri_task_data->material_indices;
LineartVert *vert_arr = tri_task_data->vert_arr;
@ -1815,9 +1818,9 @@ static void lineart_load_tri_task(void *__restrict userdata,
tri = (LineartTriangle *)(((uchar *)tri) + tri_task_data->lineart_triangle_size * i);
int v1 = corner_verts[lt->tri[0]];
int v2 = corner_verts[lt->tri[1]];
int v3 = corner_verts[lt->tri[2]];
int v1 = corner_verts[corner_tri[0]];
int v2 = corner_verts[corner_tri[1]];
int v3 = corner_verts[corner_tri[2]];
tri->v[0] = &vert_arr[v1];
tri->v[1] = &vert_arr[v2];
@ -1866,8 +1869,8 @@ struct EdgeNeighborData {
LineartEdgeNeighbor *edge_nabr;
LineartAdjacentEdge *adj_e;
blender::Span<int> corner_verts;
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<int3> corner_tris;
blender::Span<int> tri_faces;
};
static void lineart_edge_neighbor_init_task(void *__restrict userdata,
@ -1876,13 +1879,13 @@ 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 *lt = &en_data->looptris[i / 3];
const int3 &tri = en_data->corner_tris[i / 3];
LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i];
const blender::Span<int> corner_verts = en_data->corner_verts;
adj_e->e = i;
adj_e->v1 = corner_verts[lt->tri[i % 3]];
adj_e->v2 = corner_verts[lt->tri[(i + 1) % 3]];
adj_e->v1 = corner_verts[tri[i % 3]];
adj_e->v2 = corner_verts[tri[(i + 1) % 3]];
if (adj_e->v1 > adj_e->v2) {
std::swap(adj_e->v1, adj_e->v2);
}
@ -1929,8 +1932,8 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *mesh, int total_ed
en_data.adj_e = adj_e;
en_data.edge_nabr = edge_nabr;
en_data.corner_verts = mesh->corner_verts();
en_data.looptris = mesh->looptris();
en_data.looptri_faces = mesh->looptri_faces();
en_data.corner_tris = mesh->corner_tris();
en_data.tri_faces = mesh->corner_tri_faces();
BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings);
@ -1959,7 +1962,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
}
/* Triangulate. */
const Span<MLoopTri> looptris = mesh->looptris();
const Span<int3> corner_tris = mesh->corner_tris();
const bke::AttributeAccessor attributes = mesh->attributes();
const VArraySpan material_indices = *attributes.lookup<int>("material_index", ATTR_DOMAIN_FACE);
@ -1982,7 +1985,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
LineartVert *la_v_arr = static_cast<LineartVert *>(
lineart_mem_acquire_thread(&la_data->render_data_pool, sizeof(LineartVert) * mesh->totvert));
LineartTriangle *la_tri_arr = static_cast<LineartTriangle *>(lineart_mem_acquire_thread(
&la_data->render_data_pool, looptris.size() * la_data->sizeof_triangle));
&la_data->render_data_pool, corner_tris.size() * la_data->sizeof_triangle));
Object *orig_ob = ob_info->original_ob;
@ -2024,15 +2027,15 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
int usage = ob_info->usage;
elem_link_node->element_count = looptris.size();
elem_link_node->element_count = corner_tris.size();
elem_link_node->object_ref = orig_ob;
elem_link_node->flags = eLineArtElementNodeFlag(
elem_link_node->flags |
((usage == OBJECT_LRT_NO_INTERSECTION) ? LRT_ELEMENT_NO_INTERSECTION : 0));
/* Note this memory is not from pool, will be deleted after culling. */
LineartTriangleAdjacent *tri_adj = static_cast<LineartTriangleAdjacent *>(
MEM_callocN(sizeof(LineartTriangleAdjacent) * looptris.size(), "LineartTriangleAdjacent"));
LineartTriangleAdjacent *tri_adj = static_cast<LineartTriangleAdjacent *>(MEM_callocN(
sizeof(LineartTriangleAdjacent) * corner_tris.size(), "LineartTriangleAdjacent"));
/* Link is minimal so we use pool anyway. */
BLI_spin_lock(&la_data->lock_task);
lineart_list_append_pointer_pool_thread(
@ -2064,8 +2067,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
TriData tri_data;
tri_data.ob_info = ob_info;
tri_data.positions = mesh->vert_positions();
tri_data.looptris = looptris;
tri_data.looptri_faces = mesh->looptri_faces();
tri_data.corner_tris = corner_tris;
tri_data.tri_faces = mesh->corner_tri_faces();
tri_data.corner_verts = mesh->corner_verts();
tri_data.material_indices = material_indices;
tri_data.vert_arr = la_v_arr;
@ -2073,9 +2076,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 = looptris.size() * 3;
uint32_t total_edges = corner_tris.size() * 3;
BLI_task_parallel_range(0, looptris.size(), &tri_data, lineart_load_tri_task, &tri_settings);
BLI_task_parallel_range(0, corner_tris.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
@ -2103,8 +2106,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
edge_feat_data.edges = mesh->edges();
edge_feat_data.corner_verts = mesh->corner_verts();
edge_feat_data.corner_edges = mesh->corner_edges();
edge_feat_data.looptris = looptris;
edge_feat_data.looptri_faces = mesh->looptri_faces();
edge_feat_data.corner_tris = corner_tris;
edge_feat_data.tri_faces = mesh->corner_tri_faces();
edge_feat_data.sharp_edges = sharp_edges;
edge_feat_data.sharp_faces = sharp_faces;
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(mesh, total_edges);
@ -2126,14 +2129,14 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
BLI_task_parallel_range(0,
total_edges,
&edge_feat_data,
lineart_identify_looptri_feature_edges,
lineart_identify_corner_tri_feature_edges,
&edge_feat_settings);
LooseEdgeData loose_data = {0};
if (la_data->conf.use_loose) {
/* Only identifying floating edges at this point because other edges has been taken care of
* inside #lineart_identify_looptri_feature_edges function. */
* inside #lineart_identify_corner_tri_feature_edges function. */
const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
loose_data.loose_array = static_cast<int *>(
MEM_malloc_arrayN(loose_edges.count, sizeof(int), __func__));

@ -93,10 +93,10 @@ void export_frame(Depsgraph *depsgraph,
/* Write triangles. */
const Span<float3> positions = mesh->vert_positions();
const blender::Span<int> corner_verts = mesh->corner_verts();
for (const MLoopTri &loop_tri : mesh->looptris()) {
for (const int3 &tri : mesh->corner_tris()) {
Triangle t;
for (int i = 0; i < 3; i++) {
float3 pos = positions[corner_verts[loop_tri.tri[i]]];
float3 pos = positions[corner_verts[tri[i]]];
mul_m4_v3(xform, pos);
pos *= global_scale;
t.vertices[i] = pos;

@ -260,35 +260,35 @@ void gather_vert_data(const Span<int> verts,
}
template<typename T>
void gather_face_data(const Span<int> looptri_faces,
void gather_face_data(const Span<int> tri_faces,
const IndexMask &triangles,
const Span<T> src_data,
MutableSpan<T> dst_data)
{
triangles.foreach_index_optimized<int>(GrainSize(1024), [&](const int src, const int dst) {
dst_data[dst] = src_data[looptri_faces[src]];
dst_data[dst] = src_data[tri_faces[src]];
});
}
template<typename T>
void gather_corner_data(const Span<MLoopTri> looptris,
void gather_corner_data(const Span<int3> corner_tris,
const IndexMask &triangles,
const Span<T> src_data,
MutableSpan<T> dst_data)
{
triangles.foreach_index_optimized<int>(GrainSize(1024), [&](const int src, const int dst) {
const MLoopTri &lt = looptris[src];
dst_data[dst * 3 + 0] = src_data[lt.tri[0]];
dst_data[dst * 3 + 1] = src_data[lt.tri[1]];
dst_data[dst * 3 + 2] = src_data[lt.tri[2]];
const int3 &tri = corner_tris[src];
dst_data[dst * 3 + 0] = src_data[tri[0]];
dst_data[dst * 3 + 1] = src_data[tri[1]];
dst_data[dst * 3 + 2] = src_data[tri[2]];
});
}
static void copy_submesh(const Mesh &mesh,
const Span<float3> vert_positions,
const Span<int> corner_verts,
const Span<MLoopTri> looptris,
const Span<int> looptri_faces,
const Span<int3> corner_tris,
const Span<int> tri_faces,
const std::pair<bke::MeshNormalDomain, Span<float3>> normals,
const Span<float2> uv_map,
const IndexMask &triangles,
@ -298,7 +298,7 @@ static void copy_submesh(const Mesh &mesh,
/* If all triangles are part of this submesh and there are no loose vertices that shouldn't be
* copied (Hydra will warn about this), vertex index compression can be completely skipped. */
const bool copy_all_verts = triangles.size() == looptris.size() &&
const bool copy_all_verts = triangles.size() == corner_tris.size() &&
mesh.verts_no_face().count == 0;
int dst_verts_num;
@ -306,7 +306,7 @@ static void copy_submesh(const Mesh &mesh,
if (copy_all_verts) {
/* Copy the vertex indices from the corner indices stored in every triangle. */
array_utils::gather(corner_verts,
looptris.cast<int>(),
corner_tris.cast<int>(),
MutableSpan(sm.face_vertex_indices.data(), sm.face_vertex_indices.size()));
dst_verts_num = vert_positions.size();
}
@ -315,10 +315,10 @@ static void copy_submesh(const Mesh &mesh,
* for vertices actually used by the subset of triangles. */
verts.reserve(triangles.size());
triangles.foreach_index([&](const int src, const int dst) {
const MLoopTri &lt = looptris[src];
sm.face_vertex_indices[dst * 3 + 0] = verts.index_of_or_add(corner_verts[lt.tri[0]]);
sm.face_vertex_indices[dst * 3 + 1] = verts.index_of_or_add(corner_verts[lt.tri[1]]);
sm.face_vertex_indices[dst * 3 + 2] = verts.index_of_or_add(corner_verts[lt.tri[2]]);
const int3 &tri = corner_tris[src];
sm.face_vertex_indices[dst * 3 + 0] = verts.index_of_or_add(corner_verts[tri[0]]);
sm.face_vertex_indices[dst * 3 + 1] = verts.index_of_or_add(corner_verts[tri[1]]);
sm.face_vertex_indices[dst * 3 + 2] = verts.index_of_or_add(corner_verts[tri[2]]);
});
dst_verts_num = verts.size();
}
@ -338,26 +338,26 @@ static void copy_submesh(const Mesh &mesh,
switch (normals.first) {
case bke::MeshNormalDomain::Face:
triangles.foreach_index(GrainSize(1024), [&](const int src, const int dst) {
std::fill_n(&dst_normals[dst * 3], 3, src_normals[looptri_faces[src]]);
std::fill_n(&dst_normals[dst * 3], 3, src_normals[tri_faces[src]]);
});
break;
case bke::MeshNormalDomain::Point:
triangles.foreach_index(GrainSize(1024), [&](const int src, const int dst) {
const MLoopTri &lt = looptris[src];
dst_normals[dst * 3 + 0] = src_normals[corner_verts[lt.tri[0]]];
dst_normals[dst * 3 + 1] = src_normals[corner_verts[lt.tri[1]]];
dst_normals[dst * 3 + 2] = src_normals[corner_verts[lt.tri[2]]];
const int3 &tri = corner_tris[src];
dst_normals[dst * 3 + 0] = src_normals[corner_verts[tri[0]]];
dst_normals[dst * 3 + 1] = src_normals[corner_verts[tri[1]]];
dst_normals[dst * 3 + 2] = src_normals[corner_verts[tri[2]]];
});
break;
case bke::MeshNormalDomain::Corner:
gather_corner_data(looptris, triangles, src_normals, dst_normals);
gather_corner_data(corner_tris, triangles, src_normals, dst_normals);
break;
}
if (!uv_map.is_empty()) {
resize_uninitialized(sm.uvs, triangles.size() * 3);
gather_corner_data(
looptris, triangles, uv_map, MutableSpan(sm.uvs.data(), sm.uvs.size()).cast<float2>());
corner_tris, triangles, uv_map, MutableSpan(sm.uvs.data(), sm.uvs.size()).cast<float2>());
}
}
@ -371,8 +371,8 @@ void MeshData::write_submeshes(const Mesh *mesh)
const Span<float3> vert_positions = mesh->vert_positions();
const Span<int> corner_verts = mesh->corner_verts();
const Span<MLoopTri> looptris = mesh->looptris();
const Span<int> looptri_faces = mesh->looptri_faces();
const Span<int3> corner_tris = mesh->corner_tris();
const Span<int> tri_faces = mesh->corner_tri_faces();
const std::pair<bke::MeshNormalDomain, Span<float3>> normals = get_mesh_normals(*mesh);
const bke::AttributeAccessor attributes = mesh->attributes();
const StringRef active_uv = CustomData_get_active_layer_name(&mesh->loop_data, CD_PROP_FLOAT2);
@ -383,11 +383,11 @@ void MeshData::write_submeshes(const Mesh *mesh)
copy_submesh(*mesh,
vert_positions,
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
normals,
uv_map,
looptris.index_range(),
corner_tris.index_range(),
submeshes_.first());
return;
}
@ -396,9 +396,9 @@ void MeshData::write_submeshes(const Mesh *mesh)
Array<IndexMask> triangles_by_material(submeshes_.size());
const int max_index = std::max(mat_count - 1, 0);
IndexMask::from_groups<int>(
looptris.index_range(),
corner_tris.index_range(),
memory,
[&](const int i) { return std::min(material_indices[looptri_faces[i]], max_index); },
[&](const int i) { return std::min(material_indices[tri_faces[i]], max_index); },
triangles_by_material);
threading::parallel_for(submeshes_.index_range(), 1, [&](const IndexRange range) {
@ -406,8 +406,8 @@ void MeshData::write_submeshes(const Mesh *mesh)
copy_submesh(*mesh,
vert_positions,
corner_verts,
looptris,
looptri_faces,
corner_tris,
tri_faces,
normals,
uv_map,
triangles_by_material[i],

@ -50,7 +50,6 @@ struct Key;
struct MCol;
struct MEdge;
struct MFace;
struct MLoopTri;
struct Material;
typedef struct Mesh {
@ -298,12 +297,12 @@ typedef struct Mesh {
/**
* Cached triangulation of mesh faces, depending on the face topology and the vertex positions.
*/
blender::Span<MLoopTri> looptris() const;
blender::Span<blender::int3> corner_tris() const;
/**
* A map containing the face index that each cached triangle from #Mesh::looptris() came from.
* A map containing the face index that each cached triangle from #Mesh::corner_tris() came from.
*/
blender::Span<int> looptri_faces() const;
blender::Span<int> corner_tri_faces() const;
/**
* Calculate the largest and smallest position values of vertices.

@ -41,59 +41,58 @@ enum {
* \{ */
/**
* #MLoopTri is runtime triangulation data for #Mesh, for functionality that doesn't support ngons.
* #Mesh::corner_tris() gives access to runtime triangulation data for #Mesh, for functionality
* that doesn't support ngons.
*
* Typical usage includes:
* - Viewport drawing.
* - #BVHTree creation.
* - Physics/collision detection.
*
* A mesh's triangulation data is generally accessed via #Mesh::looptris(), which uses a cache that
* is lazily calculated from faces, corner vert, and position arrays. In rare cases it is
* calculated directly too, with #bke::mesh::looptris_calc. When the underlying mesh data changes,
* the array is recalculated from scratch; there is no extra attempt to maintain the validity over
* time.
* A mesh's triangulation data, which uses a cache that is lazily calculated from faces, corner
* vert, and position arrays. In rare cases it is calculated directly too, with
* #bke::mesh::corner_tris_calc. When the underlying mesh data changes, the array is recalculated
* from scratch; there is no extra attempt to maintain the validity over time.
*
* #MLoopTri is stored in an array, where triangles from each face are stored sequentially.
* The triangles order is guaranteed to match the face order where the first triangle will always
* be from the first face, and the last triangle from the last face.
* The number of triangles for each polygon is guaranteed to be the corner count - 2, even for
* degenerate geometry (see #bke::mesh::face_triangles_num).
* Triangles are stored in an array, where triangles from each face are stored sequentially. The
* triangles order is guaranteed to match the face order where the first triangle will always be
* from the first face, and the last triangle from the last face. The number of triangles for each
* polygon is guaranteed to be the corner count - 2, even for degenerate geometry (see
* #bke::mesh::face_triangles_num).
*
* Storing corner indices (instead of vertex indices) gives more flexibility for accessing mesh
* data stored per-corner, though it does often add an extra level of indirection. The index of the
* corresponding face for each triangle is stored in a separate array, accessed with
* #Mesh::looptri_faces().
* #Mesh::corner_tri_faces().
*
* Examples:
* \code{.cc}
* // Access vertex locations.
* std::array<float3, 3> tri_positions{
* positions[corner_verts[lt.tri[0]]],
* positions[corner_verts[lt.tri[1]]],
* positions[corner_verts[lt.tri[2]]],
* positions[corner_verts[tri[0]]],
* positions[corner_verts[tri[1]]],
* positions[corner_verts[tri[2]]],
* };
*
* // Access UV coordinates (works for all face corner data, vertex colors... etc).
* std::array<float2, 3> tri_uvs{
* uv_map[lt.tri[0]],
* uv_map[lt.tri[1]],
* uv_map[lt.tri[2]],
* uv_map[tri[0]],
* uv_map[tri[1]],
* uv_map[tri[2]],
* };
*
* // Access all triangles in a given face.
* const IndexRange face = faces[i];
* const Span<MLoopTri> looptris = looptris.slice(poly_to_tri_count(i, face.start()),
* const Span<int3> corner_tris = corner_tris.slice(poly_to_tri_count(i, face.start()),
* bke::mesh::face_triangles_num(face.size()));
* \endcode
*
* It may also be useful to check whether or not two vertices of a triangle form an edge in the
* underlying mesh. See #bke::mesh::looptri_get_real_edges for a utility that does this. Note that
* a #MLoopTri may be in the middle of an ngon and not reference **any** real edges.
* underlying mesh. See #bke::mesh::corner_tri for a utility that does this. Note
* that a triangle may be in the middle of an ngon and not reference **any**
* real edges.
*/
typedef struct MLoopTri {
unsigned int tri[3];
} MLoopTri;
#
#
typedef struct MVertTri {

@ -2285,7 +2285,7 @@ enum {
/** Surface Deform vertex bind modes. */
enum {
MOD_SDEF_MODE_LOOPTRIS = 0,
MOD_SDEF_MODE_CORNER_TRIS = 0,
MOD_SDEF_MODE_NGONS = 1,
MOD_SDEF_MODE_CENTROID = 2,
};

@ -29,11 +29,11 @@ typedef struct vec2i {
typedef struct vec2d {
double x, y;
} vec2d;
*/
typedef struct vec3i {
int x, y, z;
} vec3i;
*/
typedef struct vec3f {
float x, y, z;
} vec3f;

@ -323,10 +323,10 @@ static int rna_MeshLoop_index_get(PointerRNA *ptr)
static int rna_MeshLoopTriangle_index_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const MLoopTri *lt = static_cast<const MLoopTri *>(ptr->data);
const int index = int(lt - mesh->looptris().data());
const blender::int3 *tri = static_cast<const blender::int3 *>(ptr->data);
const int index = int(tri - mesh->corner_tris().data());
BLI_assert(index >= 0);
BLI_assert(index < BKE_mesh_runtime_looptris_len(mesh));
BLI_assert(index < BKE_mesh_runtime_corner_tris_len(mesh));
return index;
}
@ -334,17 +334,17 @@ static int rna_MeshLoopTriangle_polygon_index_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const int index = rna_MeshLoopTriangle_index_get(ptr);
return mesh->looptri_faces()[index];
return mesh->corner_tri_faces()[index];
}
static void rna_Mesh_loop_triangles_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
rna_iterator_array_begin(iter,
const_cast<MLoopTri *>(looptris.data()),
sizeof(MLoopTri),
looptris.size(),
const_cast<blender::int3 *>(corner_tris.data()),
sizeof(blender::int3),
corner_tris.size(),
false,
nullptr);
}
@ -352,19 +352,19 @@ static void rna_Mesh_loop_triangles_begin(CollectionPropertyIterator *iter, Poin
static int rna_Mesh_loop_triangles_length(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
return BKE_mesh_runtime_looptris_len(mesh);
return BKE_mesh_runtime_corner_tris_len(mesh);
}
int rna_Mesh_loop_triangles_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
{
const Mesh *mesh = rna_mesh(ptr);
if (index < 0 || index >= BKE_mesh_runtime_looptris_len(mesh)) {
if (index < 0 || index >= BKE_mesh_runtime_corner_tris_len(mesh)) {
return false;
}
/* Casting away const is okay because this RNA type doesn't allow changing the value. */
r_ptr->owner_id = (ID *)&mesh->id;
r_ptr->type = &RNA_MeshLoopTriangle;
r_ptr->data = const_cast<MLoopTri *>(&mesh->looptris()[index]);
r_ptr->data = const_cast<blender::int3 *>(&mesh->corner_tris()[index]);
return true;
}
@ -373,9 +373,9 @@ static void rna_Mesh_loop_triangle_polygons_begin(CollectionPropertyIterator *it
{
const Mesh *mesh = rna_mesh(ptr);
rna_iterator_array_begin(iter,
const_cast<int *>(mesh->looptri_faces().data()),
const_cast<int *>(mesh->corner_tri_faces().data()),
sizeof(int),
BKE_mesh_runtime_looptris_len(mesh),
BKE_mesh_runtime_corner_tris_len(mesh),
false,
nullptr);
}
@ -383,13 +383,13 @@ static void rna_Mesh_loop_triangle_polygons_begin(CollectionPropertyIterator *it
int rna_Mesh_loop_triangle_polygons_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
{
const Mesh *mesh = rna_mesh(ptr);
if (index < 0 || index >= BKE_mesh_runtime_looptris_len(mesh)) {
if (index < 0 || index >= BKE_mesh_runtime_corner_tris_len(mesh)) {
return false;
}
/* Casting away const is okay because this RNA type doesn't allow changing the value. */
r_ptr->owner_id = (ID *)&mesh->id;
r_ptr->type = &RNA_ReadOnlyInteger;
r_ptr->data = const_cast<int *>(&mesh->looptri_faces()[index]);
r_ptr->data = const_cast<int *>(&mesh->corner_tri_faces()[index]);
return true;
}
@ -683,21 +683,21 @@ static void rna_MeshLoopTriangle_verts_get(PointerRNA *ptr, int *values)
{
Mesh *mesh = rna_mesh(ptr);
const blender::Span<int> corner_verts = mesh->corner_verts();
MLoopTri *lt = (MLoopTri *)ptr->data;
values[0] = corner_verts[lt->tri[0]];
values[1] = corner_verts[lt->tri[1]];
values[2] = corner_verts[lt->tri[2]];
blender::int3 tri = *(blender::int3 *)ptr->data;
values[0] = corner_verts[tri[0]];
values[1] = corner_verts[tri[1]];
values[2] = corner_verts[tri[2]];
}
static void rna_MeshLoopTriangle_normal_get(PointerRNA *ptr, float *values)
{
Mesh *mesh = rna_mesh(ptr);
MLoopTri *lt = (MLoopTri *)ptr->data;
blender::int3 tri = *(blender::int3 *)ptr->data;
const blender::Span<blender::float3> positions = mesh->vert_positions();
const blender::Span<int> corner_verts = mesh->corner_verts();
const int v1 = corner_verts[lt->tri[0]];
const int v2 = corner_verts[lt->tri[1]];
const int v3 = corner_verts[lt->tri[2]];
const int v1 = corner_verts[tri[0]];
const int v2 = corner_verts[tri[1]];
const int v3 = corner_verts[tri[2]];
normal_tri_v3(values, positions[v1], positions[v2], positions[v3]);
}
@ -706,21 +706,21 @@ static void rna_MeshLoopTriangle_split_normals_get(PointerRNA *ptr, float *value
{
Mesh *mesh = rna_mesh(ptr);
const blender::Span<blender::float3> loop_normals = mesh->corner_normals();
const MLoopTri *lt = (const MLoopTri *)ptr->data;
copy_v3_v3(values + 0, loop_normals[lt->tri[0]]);
copy_v3_v3(values + 3, loop_normals[lt->tri[1]]);
copy_v3_v3(values + 6, loop_normals[lt->tri[2]]);
const blender::int3 tri = *(const blender::int3 *)ptr->data;
copy_v3_v3(values + 0, loop_normals[tri[0]]);
copy_v3_v3(values + 3, loop_normals[tri[1]]);
copy_v3_v3(values + 6, loop_normals[tri[2]]);
}
static float rna_MeshLoopTriangle_area_get(PointerRNA *ptr)
{
Mesh *mesh = rna_mesh(ptr);
MLoopTri *lt = (MLoopTri *)ptr->data;
blender::int3 tri = *(blender::int3 *)ptr->data;
const blender::Span<blender::float3> positions = mesh->vert_positions();
const blender::Span<int> corner_verts = mesh->corner_verts();
const int v1 = corner_verts[lt->tri[0]];
const int v2 = corner_verts[lt->tri[1]];
const int v3 = corner_verts[lt->tri[2]];
const int v1 = corner_verts[tri[0]];
const int v2 = corner_verts[tri[1]];
const int v3 = corner_verts[tri[2]];
return area_tri_v3(positions[v1], positions[v2], positions[v3]);
}
@ -2106,7 +2106,7 @@ static void rna_def_mlooptri(BlenderRNA *brna)
const int splitnor_dim[] = {3, 3};
srna = RNA_def_struct(brna, "MeshLoopTriangle", nullptr);
RNA_def_struct_sdna(srna, "MLoopTri");
RNA_def_struct_sdna(srna, "vec3i");
RNA_def_struct_ui_text(srna, "Mesh Loop Triangle", "Tessellated triangle in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshLoopTriangle_path");
RNA_def_struct_ui_icon(srna, ICON_FACESEL);
@ -2118,7 +2118,7 @@ static void rna_def_mlooptri(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "loops", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, nullptr, "tri");
RNA_def_property_int_sdna(prop, nullptr, "x");
RNA_def_property_ui_text(prop, "Loops", "Indices of mesh loops that make up the triangle");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);

@ -82,9 +82,9 @@ static void rna_Mesh_free_tangents(Mesh *mesh)
CustomData_free_layers(&mesh->loop_data, CD_MLOOPTANGENT, mesh->totloop);
}
static void rna_Mesh_calc_looptri(Mesh *mesh)
static void rna_Mesh_calc_corner_tri(Mesh *mesh)
{
mesh->looptris();
mesh->corner_tris();
}
static void rna_Mesh_calc_smooth_groups(
@ -260,7 +260,7 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "free_tangents", "rna_Mesh_free_tangents");
RNA_def_function_ui_description(func, "Free tangents");
func = RNA_def_function(srna, "calc_loop_triangles", "rna_Mesh_calc_looptri");
func = RNA_def_function(srna, "calc_loop_triangles", "rna_Mesh_calc_corner_tri");
RNA_def_function_ui_description(func,
"Calculate loop triangle tessellation (supports editmode too)");

@ -73,7 +73,6 @@ static const EnumPropertyItem space_items[] = {
# include "DNA_curve_types.h"
# include "DNA_mesh_types.h"
# include "DNA_meshdata_types.h"
# include "DNA_scene_types.h"
# include "DNA_view3d_types.h"
@ -552,10 +551,10 @@ static void rna_Mesh_assign_verts_to_group(
# endif
/* don't call inside a loop */
static int mesh_looptri_to_face_index(Mesh *me_eval, const int tri_index)
static int mesh_corner_tri_to_face_index(Mesh *me_eval, const int tri_index)
{
const blender::Span<int> looptri_faces = me_eval->looptri_faces();
const int face_i = looptri_faces[tri_index];
const blender::Span<int> tri_faces = me_eval->corner_tri_faces();
const int face_i = tri_faces[tri_index];
const int *index_mp_to_orig = static_cast<const int *>(
CustomData_get_layer(&me_eval->face_data, CD_ORIGINDEX));
return index_mp_to_orig ? index_mp_to_orig[face_i] : face_i;
@ -629,7 +628,7 @@ static void rna_Object_ray_cast(Object *ob,
/* No need to managing allocation or freeing of the BVH data.
* This is generated and freed as needed. */
BKE_bvhtree_from_mesh_get(&treeData, mesh_eval, BVHTREE_FROM_LOOPTRIS, 4);
BKE_bvhtree_from_mesh_get(&treeData, mesh_eval, BVHTREE_FROM_CORNER_TRIS, 4);
/* may fail if the mesh has no faces, in that case the ray-cast misses */
if (treeData.tree != nullptr) {
@ -651,7 +650,7 @@ static void rna_Object_ray_cast(Object *ob,
copy_v3_v3(r_location, hit.co);
copy_v3_v3(r_normal, hit.no);
*r_index = mesh_looptri_to_face_index(mesh_eval, hit.index);
*r_index = mesh_corner_tri_to_face_index(mesh_eval, hit.index);
}
}
@ -687,7 +686,7 @@ static void rna_Object_closest_point_on_mesh(Object *ob,
/* No need to managing allocation or freeing of the BVH data.
* this is generated and freed as needed. */
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
BKE_bvhtree_from_mesh_get(&treeData, mesh_eval, BVHTREE_FROM_LOOPTRIS, 4);
BKE_bvhtree_from_mesh_get(&treeData, mesh_eval, BVHTREE_FROM_CORNER_TRIS, 4);
if (treeData.tree == nullptr) {
BKE_reportf(reports,
@ -709,7 +708,7 @@ static void rna_Object_closest_point_on_mesh(Object *ob,
copy_v3_v3(r_location, nearest.co);
copy_v3_v3(r_normal, nearest.no);
*r_index = mesh_looptri_to_face_index(mesh_eval, nearest.index);
*r_index = mesh_corner_tri_to_face_index(mesh_eval, nearest.index);
goto finally;
}

@ -155,12 +155,12 @@ static void deform_verts(ModifierData *md,
collmd->mvert_num = mvert_num;
{
const blender::Span<MLoopTri> looptris = mesh->looptris();
collmd->tri_num = looptris.size();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
collmd->tri_num = corner_tris.size();
MVertTri *tri = static_cast<MVertTri *>(
MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__));
BKE_mesh_runtime_verttris_from_looptris(
tri, mesh->corner_verts().data(), looptris.data(), collmd->tri_num);
BKE_mesh_runtime_verttris_from_corner_tris(
tri, mesh->corner_verts().data(), corner_tris.data(), collmd->tri_num);
collmd->tri = tri;
}

@ -76,7 +76,7 @@ struct LaplacianSystem {
/**
* An array of triangles, each triangle represents 3 vertex indices.
*
* \note This is derived from the meshes #MLoopTri array.
* \note This is derived from the Mesh::corner_tris() array.
*/
uint (*tris)[3];
/** Static vertex index list. */
@ -157,7 +157,7 @@ static void deleteLaplacianSystem(LaplacianSystem *sys)
}
static void createFaceRingMap(const int mvert_tot,
blender::Span<MLoopTri> looptris,
blender::Span<blender::int3> corner_tris,
blender::Span<int> corner_verts,
MeshElemMap **r_map,
int **r_indices)
@ -166,10 +166,10 @@ static void createFaceRingMap(const int mvert_tot,
int *indices, *index_iter;
MeshElemMap *map = MEM_cnew_array<MeshElemMap>(mvert_tot, __func__);
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
for (int j = 0; j < 3; j++) {
const int v_index = corner_verts[lt.tri[j]];
const int v_index = corner_verts[tri[j]];
map[v_index].count++;
indices_num++;
}
@ -181,10 +181,10 @@ static void createFaceRingMap(const int mvert_tot,
index_iter += map[i].count;
map[i].count = 0;
}
for (const int i : looptris.index_range()) {
const MLoopTri &lt = looptris[i];
for (const int i : corner_tris.index_range()) {
const blender::int3 &tri = corner_tris[i];
for (int j = 0; j < 3; j++) {
const int v_index = corner_verts[lt.tri[j]];
const int v_index = corner_verts[tri[j]];
map[v_index].indices[map[v_index].count] = i;
map[v_index].count++;
}
@ -567,11 +567,15 @@ static void initSystem(
const blender::Span<blender::int2> edges = mesh->edges();
const blender::Span<int> corner_verts = mesh->corner_verts();
const blender::Span<MLoopTri> looptris = mesh->looptris();
const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
anchors_num = STACK_SIZE(index_anchors);
lmd->cache_system = initLaplacianSystem(
verts_num, edges.size(), looptris.size(), anchors_num, lmd->anchor_grp_name, lmd->repeat);
lmd->cache_system = initLaplacianSystem(verts_num,
edges.size(),
corner_tris.size(),
anchors_num,
lmd->anchor_grp_name,
lmd->repeat);
sys = (LaplacianSystem *)lmd->cache_system;
memcpy(sys->index_anchors, index_anchors, sizeof(int) * anchors_num);
memcpy(sys->co, vertexCos, sizeof(float[3]) * verts_num);
@ -580,13 +584,14 @@ static void initSystem(
memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * verts_num);
lmd->verts_num = verts_num;
createFaceRingMap(mesh->totvert, looptris, corner_verts, &sys->ringf_map, &sys->ringf_indices);
createFaceRingMap(
mesh->totvert, corner_tris, corner_verts, &sys->ringf_map, &sys->ringf_indices);
createVertRingMap(mesh->totvert, edges, &sys->ringv_map, &sys->ringv_indices);
for (i = 0; i < sys->tris_num; i++) {
sys->tris[i][0] = corner_verts[looptris[i].tri[0]];
sys->tris[i][1] = corner_verts[looptris[i].tri[1]];
sys->tris[i][2] = corner_verts[looptris[i].tri[2]];
sys->tris[i][0] = corner_verts[corner_tris[i][0]];
sys->tris[i][1] = corner_verts[corner_tris[i][1]];
sys->tris[i][2] = corner_verts[corner_tris[i][2]];
}
}
}

@ -69,9 +69,9 @@ static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
input->mloop = (DualConLoop)mesh->corner_verts().data();
input->loop_stride = sizeof(int);
input->looptris = (DualConTri)mesh->looptris().data();
input->tri_stride = sizeof(MLoopTri);
input->tottri = BKE_mesh_runtime_looptris_len(mesh);
input->corner_tris = (DualConTri)mesh->corner_tris().data();
input->tri_stride = sizeof(blender::int3);
input->tottri = BKE_mesh_runtime_corner_tris_len(mesh);
const blender::Bounds<blender::float3> bounds = *mesh->bounds_min_max();
copy_v3_v3(input->min, bounds.min);

@ -168,7 +168,7 @@ static void deform_verts(ModifierData *md,
if (has_face) {
BKE_bvhtree_from_mesh_get(
surmd->runtime.bvhtree, surmd->runtime.mesh, BVHTREE_FROM_LOOPTRIS, 2);
surmd->runtime.bvhtree, surmd->runtime.mesh, BVHTREE_FROM_CORNER_TRIS, 2);
}
else if (has_edge) {
BKE_bvhtree_from_mesh_get(

@ -73,8 +73,8 @@ struct SDefBindCalcData {
blender::OffsetIndices<int> polys;
blender::Span<int> corner_verts;
blender::Span<int> corner_edges;
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
blender::Span<blender::int3> corner_tris;
blender::Span<int> tri_faces;
/** Coordinates to bind to, transformed into local space (compatible with `vertexCos`). */
float (*targetCos)[3];
@ -392,7 +392,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);
const blender::IndexRange face = data->polys[data->looptri_faces[nearest.index]];
const blender::IndexRange face = data->polys[data->tri_faces[nearest.index]];
for (int i = 0; i < face.size(); i++) {
const int edge_i = data->corner_edges[face.start() + i];
@ -699,7 +699,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
/* Compute the distance scale for the corner. The base value is the orthogonal
* distance from the corner to the chord, scaled by `sqrt(2)` to preserve the old
* values in case of a square grid. This doesn't use the centroid because the
* LOOPTRIS method only uses these three vertices. */
* corner_triS method only uses these three vertices. */
bpoly->scale_mid = area_tri_v2(vert0_v2, corner_v2, vert1_v2) /
len_v2v2(vert0_v2, vert1_v2) * sqrtf(2);
@ -1105,7 +1105,7 @@ static void bindVert(void *__restrict userdata,
sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight;
sdbind->verts_num = bpoly->verts_num;
sdbind->mode = MOD_SDEF_MODE_LOOPTRIS;
sdbind->mode = MOD_SDEF_MODE_CORNER_TRIS;
sdbind->vert_weights = static_cast<float *>(
MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefTriVertWeights"));
if (sdbind->vert_weights == nullptr) {
@ -1220,7 +1220,7 @@ static bool surfacedeformBind(Object *ob,
return false;
}
BKE_bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRIS, 2);
BKE_bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_CORNER_TRIS, 2);
if (treeData.tree == nullptr) {
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
@ -1259,8 +1259,8 @@ static bool surfacedeformBind(Object *ob,
data.edges = edges;
data.corner_verts = corner_verts;
data.corner_edges = corner_edges;
data.looptris = target->looptris();
data.looptri_faces = target->looptri_faces();
data.corner_tris = target->corner_tris();
data.tri_faces = target->corner_tri_faces();
data.targetCos = static_cast<float(*)[3]>(
MEM_malloc_arrayN(target_verts_num, sizeof(float[3]), "SDefTargetBindVertArray"));
data.bind_verts = smd_orig->verts;
@ -1383,8 +1383,8 @@ static void deformVert(void *__restrict userdata,
zero_v3(temp);
switch (sdbind->mode) {
/* ---------- looptri mode ---------- */
case MOD_SDEF_MODE_LOOPTRIS: {
/* ---------- corner_tri mode ---------- */
case MOD_SDEF_MODE_CORNER_TRIS: {
madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]);
@ -1670,7 +1670,8 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
BLO_write_uint32_array(
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_LOOPTRIS)) {
if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
{
BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
}
else {
@ -1698,7 +1699,8 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
BLO_read_uint32_array(
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
if (ELEM(smd->verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_LOOPTRIS)) {
if (ELEM(smd->verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
{
BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
}
else {

Some files were not shown because too many files have changed in this diff Show More