Blender V4.3
mesh_tangent.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <climits>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_math_geom.h"
16#include "BLI_math_vector.h"
17#include "BLI_string.h"
18#include "BLI_task.h"
19#include "BLI_utildefines.h"
20
21#include "BKE_attribute.hh"
22#include "BKE_customdata.hh"
23#include "BKE_mesh.hh"
24#include "BKE_mesh_tangent.hh"
25#include "BKE_report.hh"
26
27#include "mikktspace.hh"
28
29#include "BLI_strict_flags.h" /* Keep last. */
30
31using blender::float2;
32using blender::float3;
33using blender::int3;
35using blender::Span;
36
37/* -------------------------------------------------------------------- */
43 {
44 return uint(num_faces);
45 }
46
48 {
49 return uint(faces[face_num].size());
50 }
51
52 mikk::float3 GetPosition(const uint face_num, const uint vert_num)
53 {
54 const uint loop_idx = uint(faces[face_num].start()) + vert_num;
55 return mikk::float3(positions[corner_verts[loop_idx]]);
56 }
57
58 mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
59 {
60 const float *uv = luvs[uint(faces[face_num].start()) + vert_num];
61 return mikk::float3(uv[0], uv[1], 1.0f);
62 }
63
64 mikk::float3 GetNormal(const uint face_num, const uint vert_num)
65 {
66 return mikk::float3(corner_normals[uint(faces[face_num].start()) + vert_num]);
67 }
68
69 void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
70 {
71 float *p_res = tangents[uint(faces[face_num].start()) + vert_num];
72 copy_v4_fl4(p_res, T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
73 }
74
75 OffsetIndices<int> faces; /* faces */
76 const int *corner_verts; /* faces vertices */
77 const float (*positions)[3]; /* vertices */
78 const float (*luvs)[2]; /* texture coordinates */
79 const float (*corner_normals)[3]; /* loops' normals */
80 float (*tangents)[4]; /* output tangents */
81 int num_faces; /* number of polygons */
82};
83
84void BKE_mesh_calc_loop_tangent_single_ex(const float (*vert_positions)[3],
85 const int /*numVerts*/,
86 const int *corner_verts,
87 float (*r_looptangent)[4],
88 const float (*corner_normals)[3],
89 const float (*loop_uvs)[2],
90 const int /*numLoops*/,
91 const OffsetIndices<int> faces,
92 ReportList *reports)
93{
94 /* Compute Mikktspace's tangent normals. */
95 BKEMeshToTangent mesh_to_tangent;
96 mesh_to_tangent.faces = faces;
97 mesh_to_tangent.corner_verts = corner_verts;
98 mesh_to_tangent.positions = vert_positions;
99 mesh_to_tangent.luvs = loop_uvs;
100 mesh_to_tangent.corner_normals = corner_normals;
101 mesh_to_tangent.tangents = r_looptangent;
102 mesh_to_tangent.num_faces = int(faces.size());
103
105
106 /* First check we do have a tris/quads only mesh. */
107 for (const int64_t i : faces.index_range()) {
108 if (faces[i].size() > 4) {
110 reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
111 return;
112 }
113 }
114
115 mikk.genTangSpace();
116}
117
119 const char *uvmap,
120 float (*r_looptangents)[4],
121 ReportList *reports)
122{
123 using namespace blender;
124 using namespace blender::bke;
125 if (!uvmap) {
126 uvmap = CustomData_get_active_layer_name(&mesh->corner_data, CD_PROP_FLOAT2);
127 }
128
129 const AttributeAccessor attributes = mesh->attributes();
130 const VArraySpan uv_map = *attributes.lookup<float2>(uvmap, AttrDomain::Corner);
131 if (uv_map.is_empty()) {
132 BKE_reportf(reports,
133 RPT_ERROR,
134 "Tangent space computation needs a UV Map, \"%s\" not found, aborting",
135 uvmap);
136 return;
137 }
138
140 reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()),
141 mesh->verts_num,
142 mesh->corner_verts().data(),
143 r_looptangents,
144 reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data()),
145 reinterpret_cast<const float(*)[2]>(uv_map.data()),
146 mesh->corners_num,
147 mesh->faces(),
148 reports);
149}
150
153/* -------------------------------------------------------------------- */
157/* Necessary complexity to handle corner_tris as quads for correct tangents. */
158#define USE_TRI_DETECT_QUADS
159
162 {
163#ifdef USE_TRI_DETECT_QUADS
165#else
166 return uint(numTessFaces);
167#endif
168 }
169
171 {
172#ifdef USE_TRI_DETECT_QUADS
173 if (face_as_quad_map) {
174 const int face_index = tri_faces[face_as_quad_map[face_num]];
175 if (faces[face_index].size() == 4) {
176 return 4;
177 }
178 }
179 return 3;
180#else
181 UNUSED_VARS(pContext, face_num);
182 return 3;
183#endif
184 }
185
186 uint GetLoop(const uint face_num, const uint vert_num, int3 &tri, int &face_index)
187 {
188#ifdef USE_TRI_DETECT_QUADS
189 if (face_as_quad_map) {
190 tri = corner_tris[face_as_quad_map[face_num]];
191 face_index = tri_faces[face_as_quad_map[face_num]];
192 if (faces[face_index].size() == 4) {
193 return uint(faces[face_index][vert_num]);
194 }
195 /* fall through to regular triangle */
196 }
197 else {
198 tri = corner_tris[face_num];
199 face_index = tri_faces[face_num];
200 }
201#else
202 tri = &corner_tris[face_num];
203#endif
204
205 /* Safe to suppress since the way `face_as_quad_map` is used
206 * prevents out-of-bounds reads on the 4th component of the `int3`. */
207#ifdef __GNUC__
208# pragma GCC diagnostic push
209# pragma GCC diagnostic ignored "-Warray-bounds"
210#endif
211
212 return uint(tri[int(vert_num)]);
213
214#ifdef __GNUC__
215# pragma GCC diagnostic pop
216#endif
217 }
218
219 mikk::float3 GetPosition(const uint face_num, const uint vert_num)
220 {
221 int3 tri;
222 int face_index;
223 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
224 return mikk::float3(positions[corner_verts[loop_index]]);
225 }
226
227 mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
228 {
229 int3 tri;
230 int face_index;
231 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
232 if (mloopuv != nullptr) {
233 const float2 &uv = mloopuv[loop_index];
234 return mikk::float3(uv[0], uv[1], 1.0f);
235 }
236 const float *l_orco = orco[corner_verts[loop_index]];
237 float u, v;
238 map_to_sphere(&u, &v, l_orco[0], l_orco[1], l_orco[2]);
239 return mikk::float3(u, v, 1.0f);
240 }
241
242 mikk::float3 GetNormal(const uint face_num, const uint vert_num)
243 {
244 int3 tri;
245 int face_index;
246 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
247 if (!corner_normals.is_empty()) {
248 return mikk::float3(corner_normals[loop_index]);
249 }
250 if (!sharp_faces.is_empty() && sharp_faces[face_index]) { /* flat */
251 if (!face_normals.is_empty()) {
252 return mikk::float3(face_normals[face_index]);
253 }
254#ifdef USE_TRI_DETECT_QUADS
255 const blender::IndexRange face = faces[face_index];
256 float normal[3];
257 if (face.size() == 4) {
258 normal_quad_v3(normal,
259 positions[corner_verts[face[0]]],
260 positions[corner_verts[face[1]]],
261 positions[corner_verts[face[2]]],
262 positions[corner_verts[face[3]]]);
263 }
264 else
265#endif
266 {
267 normal_tri_v3(normal,
268 positions[corner_verts[tri[0]]],
269 positions[corner_verts[tri[1]]],
270 positions[corner_verts[tri[2]]]);
271 }
272 return mikk::float3(normal);
273 }
274 return mikk::float3(vert_normals[corner_verts[loop_index]]);
275 }
276
277 void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
278 {
279 int3 tri;
280 int face_index;
281 uint loop_index = GetLoop(face_num, vert_num, tri, face_index);
282
283 copy_v4_fl4(tangent[loop_index], T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
284 }
285
289 const int *tri_faces;
290 const float2 *mloopuv; /* texture coordinates */
291 OffsetIndices<int> faces;
292 const int *corner_verts; /* indices */
293 Span<float3> positions; /* vertex coordinates */
296 float (*tangent)[4]; /* destination */
299
300#ifdef USE_TRI_DETECT_QUADS
301 /* map from 'fake' face index to corner_tris,
302 * quads will point to the first corner_tris of the quad */
305#endif
306};
307
308static void DM_calc_loop_tangents_thread(TaskPool *__restrict /*pool*/, void *taskdata)
309{
310 SGLSLMeshToTangent *mesh_data = static_cast<SGLSLMeshToTangent *>(taskdata);
311
313 mikk.genTangSpace();
314}
315
317 CustomData *tan_data,
318 int numLoopData,
319 const char *layer_name)
320{
321 if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
322 CustomData_get_named_layer_index(uv_data, CD_PROP_FLOAT2, layer_name) != -1)
323 {
324 CustomData_add_layer_named(tan_data, CD_TANGENT, CD_SET_DEFAULT, numLoopData, layer_name);
325 }
326}
327
329 bool calc_active_tangent,
330 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
331 int tangent_names_count,
332 bool *rcalc_act,
333 bool *rcalc_ren,
334 int *ract_uv_n,
335 int *rren_uv_n,
336 char *ract_uv_name,
337 char *rren_uv_name,
338 short *rtangent_mask)
339{
340 /* Active uv in viewport */
341 int layer_index = CustomData_get_layer_index(loopData, CD_PROP_FLOAT2);
342 *ract_uv_n = CustomData_get_active_layer(loopData, CD_PROP_FLOAT2);
343 ract_uv_name[0] = 0;
344 if (*ract_uv_n != -1) {
346 ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name, MAX_CUSTOMDATA_LAYER_NAME);
347 }
348
349 /* Active tangent in render */
350 *rren_uv_n = CustomData_get_render_layer(loopData, CD_PROP_FLOAT2);
351 rren_uv_name[0] = 0;
352 if (*rren_uv_n != -1) {
354 rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name, MAX_CUSTOMDATA_LAYER_NAME);
355 }
356
357 /* If active tangent not in tangent_names we take it into account */
358 *rcalc_act = false;
359 *rcalc_ren = false;
360 for (int i = 0; i < tangent_names_count; i++) {
361 if (tangent_names[i][0] == 0) {
362 calc_active_tangent = true;
363 }
364 }
365 if (calc_active_tangent) {
366 *rcalc_act = true;
367 *rcalc_ren = true;
368 for (int i = 0; i < tangent_names_count; i++) {
369 if (STREQ(ract_uv_name, tangent_names[i])) {
370 *rcalc_act = false;
371 }
372 if (STREQ(rren_uv_name, tangent_names[i])) {
373 *rcalc_ren = false;
374 }
375 }
376 }
377 *rtangent_mask = 0;
378
379 const int uv_layer_num = CustomData_number_of_layers(loopData, CD_PROP_FLOAT2);
380 for (int n = 0; n < uv_layer_num; n++) {
381 const char *name = CustomData_get_layer_name(loopData, CD_PROP_FLOAT2, n);
382 bool add = false;
383 for (int i = 0; i < tangent_names_count; i++) {
384 if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
385 add = true;
386 break;
387 }
388 }
389 if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
390 (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))))
391 {
392 add = true;
393 }
394 if (add) {
395 *rtangent_mask |= short(1 << n);
396 }
397 }
398
399 if (uv_layer_num == 0) {
400 *rtangent_mask |= DM_TANGENT_MASK_ORCO;
401 }
402}
403
405 const OffsetIndices<int> faces,
406 const int *corner_verts,
407 const int3 *corner_tris,
408 const int *corner_tri_faces,
409 const uint corner_tris_len,
410 const Span<bool> sharp_faces,
411
412 const CustomData *loopdata,
413 bool calc_active_tangent,
414 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
415 int tangent_names_len,
416 const Span<float3> vert_normals,
417 const Span<float3> face_normals,
418 const Span<float3> corner_normals,
419 const Span<float3> vert_orco,
420 /* result */
421 CustomData *loopdata_out,
422 const uint loopdata_out_len,
423 short *tangent_mask_curr_p)
424{
425 int act_uv_n = -1;
426 int ren_uv_n = -1;
427 bool calc_act = false;
428 bool calc_ren = false;
429 char act_uv_name[MAX_CUSTOMDATA_LAYER_NAME];
430 char ren_uv_name[MAX_CUSTOMDATA_LAYER_NAME];
431 short tangent_mask = 0;
432 short tangent_mask_curr = *tangent_mask_curr_p;
433
435 calc_active_tangent,
436 tangent_names,
437 tangent_names_len,
438 &calc_act,
439 &calc_ren,
440 &act_uv_n,
441 &ren_uv_n,
442 act_uv_name,
443 ren_uv_name,
444 &tangent_mask);
445 if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
446 /* Check we have all the needed layers */
447 /* Allocate needed tangent layers */
448 for (int i = 0; i < tangent_names_len; i++) {
449 if (tangent_names[i][0]) {
451 loopdata, loopdata_out, int(loopdata_out_len), tangent_names[i]);
452 }
453 }
454 if ((tangent_mask & DM_TANGENT_MASK_ORCO) &&
455 CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
456 {
458 loopdata_out, CD_TANGENT, CD_SET_DEFAULT, int(loopdata_out_len), "");
459 }
460 if (calc_act && act_uv_name[0]) {
462 loopdata, loopdata_out, int(loopdata_out_len), act_uv_name);
463 }
464 if (calc_ren && ren_uv_name[0]) {
466 loopdata, loopdata_out, int(loopdata_out_len), ren_uv_name);
467 }
468
469#ifdef USE_TRI_DETECT_QUADS
470 int num_face_as_quad_map;
471 int *face_as_quad_map = nullptr;
472
473 /* map faces to quads */
474 if (corner_tris_len != uint(faces.size())) {
475 /* Over allocate, since we don't know how many ngon or quads we have. */
476
477 /* Map fake face index to corner_tris. */
478 face_as_quad_map = static_cast<int *>(MEM_mallocN(sizeof(int) * corner_tris_len, __func__));
479 int k, j;
480 for (k = 0, j = 0; j < int(corner_tris_len); k++, j++) {
481 face_as_quad_map[k] = j;
482 /* step over all quads */
483 if (faces[corner_tri_faces[j]].size() == 4) {
484 j++; /* Skips the next corner_tri. */
485 }
486 }
487 num_face_as_quad_map = k;
488 }
489 else {
490 num_face_as_quad_map = int(corner_tris_len);
491 }
492#endif
493
494 /* Calculation */
495 if (corner_tris_len != 0) {
497
498 tangent_mask_curr = 0;
499 /* Calculate tangent layers */
500 SGLSLMeshToTangent data_array[MAX_MTFACE];
501 const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
502 for (int n = 0; n < tangent_layer_num; n++) {
503 int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
505 SGLSLMeshToTangent *mesh2tangent = &data_array[n];
506 mesh2tangent->numTessFaces = int(corner_tris_len);
507#ifdef USE_TRI_DETECT_QUADS
508 mesh2tangent->face_as_quad_map = face_as_quad_map;
509 mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
510#endif
511 mesh2tangent->positions = vert_positions;
512 mesh2tangent->vert_normals = vert_normals;
513 mesh2tangent->faces = faces;
514 mesh2tangent->corner_verts = corner_verts;
515 mesh2tangent->corner_tris = corner_tris;
516 mesh2tangent->tri_faces = corner_tri_faces;
517 mesh2tangent->sharp_faces = sharp_faces;
518 /* NOTE: we assume we do have tessellated loop normals at this point
519 * (in case it is object-enabled), have to check this is valid. */
520 mesh2tangent->corner_normals = corner_normals;
521 mesh2tangent->face_normals = face_normals;
522
523 mesh2tangent->orco = {};
524 mesh2tangent->mloopuv = static_cast<const float2 *>(CustomData_get_layer_named(
525 loopdata, CD_PROP_FLOAT2, loopdata_out->layers[index].name));
526
527 /* Fill the resulting tangent_mask */
528 if (!mesh2tangent->mloopuv) {
529 mesh2tangent->orco = vert_orco;
530 if (mesh2tangent->orco.is_empty()) {
531 continue;
532 }
533
534 tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
535 }
536 else {
538 loopdata, CD_PROP_FLOAT2, loopdata_out->layers[index].name);
539 int uv_start = CustomData_get_layer_index(loopdata, CD_PROP_FLOAT2);
540 BLI_assert(uv_ind != -1 && uv_start != -1);
541 BLI_assert(uv_ind - uv_start < MAX_MTFACE);
542 tangent_mask_curr |= short(1 << (uv_ind - uv_start));
543 }
544
545 mesh2tangent->tangent = static_cast<float(*)[4]>(loopdata_out->layers[index].data);
546 BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, nullptr);
547 }
548
549 BLI_assert(tangent_mask_curr == tangent_mask);
552 }
553 else {
554 tangent_mask_curr = tangent_mask;
555 }
556#ifdef USE_TRI_DETECT_QUADS
557 if (face_as_quad_map) {
558 MEM_freeN(face_as_quad_map);
559 }
560# undef USE_TRI_DETECT_QUADS
561
562#endif
563
564 *tangent_mask_curr_p = tangent_mask_curr;
565
566 /* Update active layer index */
567 if (const char *active_uv_name = CustomData_get_active_layer_name(loopdata, CD_PROP_FLOAT2)) {
568 int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, active_uv_name);
569 if (tan_index != -1) {
570 CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
571 }
572 } /* else tangent has been built from orco */
573
574 /* Update render layer index */
575 if (const char *render_uv_name = CustomData_get_render_layer_name(loopdata, CD_PROP_FLOAT2)) {
576 int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, render_uv_name);
577 if (tan_index != -1) {
578 CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
579 }
580 } /* else tangent has been built from orco */
581 }
582}
583
585 bool calc_active_tangent,
586 const char (*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME],
587 int tangent_names_len)
588{
589 /* TODO(@ideasman42): store in Mesh.runtime to avoid recalculation. */
590 using namespace blender;
591 using namespace blender::bke;
592 const Span<int3> corner_tris = mesh_eval->corner_tris();
593 const bke::AttributeAccessor attributes = mesh_eval->attributes();
594 const VArraySpan sharp_face = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
595 const float3 *orco = static_cast<const float3 *>(
597 short tangent_mask = 0;
598 BKE_mesh_calc_loop_tangent_ex(mesh_eval->vert_positions(),
599 mesh_eval->faces(),
600 mesh_eval->corner_verts().data(),
601 corner_tris.data(),
602 mesh_eval->corner_tri_faces().data(),
603 uint(corner_tris.size()),
604 sharp_face,
605 &mesh_eval->corner_data,
606 calc_active_tangent,
607 tangent_names,
608 tangent_names_len,
609 mesh_eval->vert_normals(),
610 mesh_eval->face_normals(),
611 mesh_eval->corner_normals(),
612 /* may be nullptr */
613 orco ? Span(orco, mesh_eval->verts_num) : Span<float3>(),
614 /* result */
615 &mesh_eval->corner_data,
616 uint(mesh_eval->corners_num),
617 &tangent_mask);
618}
619
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_layer_index_n(const CustomData *data, eCustomDataType type, int n)
void CustomData_set_layer_render_index(CustomData *data, eCustomDataType type, int n)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
void CustomData_set_layer_active_index(CustomData *data, eCustomDataType type, int n)
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
int CustomData_get_render_layer(const CustomData *data, eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
#define DM_TANGENT_MASK_ORCO
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:56
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
bool map_to_sphere(float *r_u, float *r_v, float x, float y, float z)
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:57
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:471
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:394
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:431
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:450
#define UNUSED_VARS(...)
#define STREQ(a, b)
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_PROP_FLOAT2
#define MAX_MTFACE
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr bool is_empty() const
Definition BLI_span.hh:261
TaskPool * task_pool
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static char faces[256]
void BKE_mesh_calc_loop_tangents(Mesh *mesh_eval, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len)
void BKE_mesh_add_loop_tangent_named_layer_for_uv(const CustomData *uv_data, CustomData *tan_data, int numLoopData, const char *layer_name)
void BKE_mesh_calc_loop_tangent_single_ex(const float(*vert_positions)[3], const int, const int *corner_verts, float(*r_looptangent)[4], const float(*corner_normals)[3], const float(*loop_uvs)[2], const int, const OffsetIndices< int > faces, ReportList *reports)
void BKE_mesh_calc_loop_tangent_ex(const Span< float3 > vert_positions, const OffsetIndices< int > faces, const int *corner_verts, const int3 *corner_tris, const int *corner_tri_faces, const uint corner_tris_len, const Span< bool > sharp_faces, const CustomData *loopdata, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_len, const Span< float3 > vert_normals, const Span< float3 > face_normals, const Span< float3 > corner_normals, const Span< float3 > vert_orco, CustomData *loopdata_out, const uint loopdata_out_len, short *tangent_mask_curr_p)
static void DM_calc_loop_tangents_thread(TaskPool *__restrict, void *taskdata)
void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData, bool calc_active_tangent, const char(*tangent_names)[MAX_CUSTOMDATA_LAYER_NAME], int tangent_names_count, bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float(*r_looptangents)[4], ReportList *reports)
__int64 int64_t
Definition stdint.h:89
mikk::float3 GetNormal(const uint face_num, const uint vert_num)
const int * corner_verts
mikk::float3 GetPosition(const uint face_num, const uint vert_num)
void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
float(* tangents)[4]
const float(* corner_normals)[3]
OffsetIndices< int > faces
const float(* luvs)[2]
const float(* positions)[3]
uint GetNumVerticesOfFace(const uint face_num)
CustomDataLayer * layers
int corners_num
CustomData corner_data
CustomData vert_data
int verts_num
Span< float3 > positions
Span< bool > sharp_faces
mikk::float3 GetTexCoord(const uint face_num, const uint vert_num)
const int3 * corner_tris
uint GetNumVerticesOfFace(const uint face_num)
uint GetLoop(const uint face_num, const uint vert_num, int3 &tri, int &face_index)
Span< float3 > orco
OffsetIndices< int > faces
const int * corner_verts
const float2 * mloopuv
Span< float3 > face_normals
Span< float3 > vert_normals
void SetTangentSpace(const uint face_num, const uint vert_num, mikk::float3 T, bool orientation)
const int * face_as_quad_map
mikk::float3 GetNormal(const uint face_num, const uint vert_num)
Span< float3 > corner_normals
const int * tri_faces
mikk::float3 GetPosition(const uint face_num, const uint vert_num)