Blender V4.3
texture_margin.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
9#include "BLI_assert.h"
10#include "BLI_math_geom.h"
11#include "BLI_math_vector.hh"
13#include "BLI_vector.hh"
14
15#include "BKE_attribute.hh"
16#include "BKE_customdata.hh"
17#include "BKE_mesh.hh"
19#include "BKE_mesh_mapping.hh"
20
21#include "IMB_imbuf.hh"
22#include "IMB_interp.hh"
23
24#include "MEM_guardedalloc.h"
25
26#include "zbuf.h" // for rasterizer
27
28#include "RE_texture_margin.h"
29
30#include <algorithm>
31#include <cmath>
32#include <valarray>
33
35
41 static const int directions[8][2];
42 static const int distances[8];
43
45 Vector<int> loop_adjacency_map_;
47 Array<int> loop_to_face_map_;
48
49 int w_, h_;
50 float uv_offset_[2];
51 Vector<uint32_t> pixel_data_;
52 ZSpan zspan_;
53 uint32_t value_to_store_;
54 bool write_mask_;
55 char *mask_;
56
57 OffsetIndices<int> faces_;
58 Span<int> corner_edges_;
59 Span<float2> mloopuv_;
60 int totedge_;
61
62 public:
64 size_t h,
65 const float uv_offset[2],
66 const int totedge,
67 const OffsetIndices<int> faces,
68 const Span<int> corner_edges,
69 const Span<float2> mloopuv)
70 : w_(w),
71 h_(h),
72 faces_(faces),
73 corner_edges_(corner_edges),
74 mloopuv_(mloopuv),
75 totedge_(totedge)
76 {
77 copy_v2_v2(uv_offset_, uv_offset);
78
79 pixel_data_.resize(w_ * h_, 0xFFFFFFFF);
80
81 zbuf_alloc_span(&zspan_, w_, h_);
82
83 build_tables();
84 }
85
87 {
88 zbuf_free_span(&zspan_);
89 }
90
91 inline void set_pixel(int x, int y, uint32_t value)
92 {
93 BLI_assert(x < w_);
94 BLI_assert(x >= 0);
95 pixel_data_[y * w_ + x] = value;
96 }
97
98 inline uint32_t get_pixel(int x, int y) const
99 {
100 if (x < 0 || y < 0 || x >= w_ || y >= h_) {
101 return 0xFFFFFFFF;
102 }
103
104 return pixel_data_[y * w_ + x];
105 }
106
107 void rasterize_tri(float *v1, float *v2, float *v3, uint32_t value, char *mask, bool writemask)
108 {
109 /* NOTE: This is not thread safe, because the value to be written by the rasterizer is
110 * a class member. If this is ever made multi-threaded each thread needs to get its own. */
111 value_to_store_ = value;
112 mask_ = mask;
113 write_mask_ = writemask;
115 &zspan_, this, &(v1[0]), &(v2[0]), &(v3[0]), TextureMarginMap::zscan_store_pixel);
116 }
117
118 static void zscan_store_pixel(
119 void *map, int x, int y, [[maybe_unused]] float u, [[maybe_unused]] float v)
120 {
121 /* NOTE: Not thread safe, see comment above. */
122 TextureMarginMap *m = static_cast<TextureMarginMap *>(map);
123 if (m->mask_) {
124 if (m->write_mask_) {
125 /* if there is a mask and write_mask_ is true, write to the mask */
126 m->mask_[y * m->w_ + x] = 1;
127 m->set_pixel(x, y, m->value_to_store_);
128 }
129 else {
130 /* if there is a mask and write_mask_ is false, read the mask
131 * to decide if the map needs to be written
132 */
133 if (m->mask_[y * m->w_ + x] != 0) {
134 m->set_pixel(x, y, m->value_to_store_);
135 }
136 }
137 }
138 else {
139 m->set_pixel(x, y, m->value_to_store_);
140 }
141 }
142
143/* The map contains 2 kinds of pixels: DijkstraPixels and face indices. The top bit determines
144 * what kind it is. With the top bit set, it is a 'dijkstra' pixel. The bottom 4 bits encode the
145 * direction of the shortest path and the remaining 27 bits are used to store the distance. If
146 * the top bit is not set, the rest of the bits is used to store the face index.
147 */
148#define PackDijkstraPixel(dist, dir) (0x80000000 + ((dist) << 4) + (dir))
149#define DijkstraPixelGetDistance(dp) (((dp) ^ 0x80000000) >> 4)
150#define DijkstraPixelGetDirection(dp) ((dp) & 0xF)
151#define IsDijkstraPixel(dp) ((dp) & 0x80000000)
152#define DijkstraPixelIsUnset(dp) ((dp) == 0xFFFFFFFF)
153
158 void grow_dijkstra(int margin)
159 {
160 class DijkstraActivePixel {
161 public:
162 DijkstraActivePixel(int dist, int _x, int _y) : distance(dist), x(_x), y(_y) {}
163 int distance;
164 int x, y;
165 };
166 auto cmp_dijkstrapixel_fun = [](DijkstraActivePixel const &a1, DijkstraActivePixel const &a2) {
167 return a1.distance > a2.distance;
168 };
169
170 Vector<DijkstraActivePixel> active_pixels;
171 for (int y = 0; y < h_; y++) {
172 for (int x = 0; x < w_; x++) {
173 if (DijkstraPixelIsUnset(get_pixel(x, y))) {
174 for (int i = 0; i < 8; i++) {
175 int xx = x - directions[i][0];
176 int yy = y - directions[i][1];
177
178 if (xx >= 0 && xx < w_ && yy >= 0 && yy < w_ && !IsDijkstraPixel(get_pixel(xx, yy))) {
179 set_pixel(x, y, PackDijkstraPixel(distances[i], i));
180 active_pixels.append(DijkstraActivePixel(distances[i], x, y));
181 break;
182 }
183 }
184 }
185 }
186 }
187
188 /* Not strictly needed because at this point it already is a heap. */
189#if 0
190 std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
191#endif
192
193 while (active_pixels.size()) {
194 std::pop_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
195 DijkstraActivePixel p = active_pixels.pop_last();
196
197 int dist = p.distance;
198
199 if (dist < 2 * (margin + 1)) {
200 for (int i = 0; i < 8; i++) {
201 int x = p.x + directions[i][0];
202 int y = p.y + directions[i][1];
203 if (x >= 0 && x < w_ && y >= 0 && y < h_) {
204 uint32_t dp = get_pixel(x, y);
205 if (IsDijkstraPixel(dp) && (DijkstraPixelGetDistance(dp) > dist + distances[i])) {
207 set_pixel(x, y, PackDijkstraPixel(dist + distances[i], i));
208 active_pixels.append(DijkstraActivePixel(dist + distances[i], x, y));
209 std::push_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
210 }
211 }
212 }
213 }
214 }
215 }
216
222 void lookup_pixels(ImBuf *ibuf, char *mask, int maxPolygonSteps)
223 {
224 float4 *ibuf_ptr_fl = reinterpret_cast<float4 *>(ibuf->float_buffer.data);
225 uchar4 *ibuf_ptr_ch = reinterpret_cast<uchar4 *>(ibuf->byte_buffer.data);
226 size_t pixel_index = 0;
227 for (int y = 0; y < h_; y++) {
228 for (int x = 0; x < w_; x++) {
229 uint32_t dp = pixel_data_[pixel_index];
230 if (IsDijkstraPixel(dp) && !DijkstraPixelIsUnset(dp)) {
231 int dist = DijkstraPixelGetDistance(dp);
232 int direction = DijkstraPixelGetDirection(dp);
233
234 int xx = x;
235 int yy = y;
236
237 /* Follow the dijkstra directions to find the face this margin pixels belongs to. */
238 while (dist > 0) {
239 xx -= directions[direction][0];
240 yy -= directions[direction][1];
241 dp = get_pixel(xx, yy);
242 dist -= distances[direction];
243 BLI_assert(!dist || (dist == DijkstraPixelGetDistance(dp)));
244 direction = DijkstraPixelGetDirection(dp);
245 }
246
247 uint32_t face = get_pixel(xx, yy);
248
250
251 float destX, destY;
252
253 int other_poly;
254 bool found_pixel_in_polygon = false;
255 if (lookup_pixel_polygon_neighborhood(x, y, &face, &destX, &destY, &other_poly)) {
256
257 for (int i = 0; i < maxPolygonSteps; i++) {
258 /* Force to pixel grid. */
259 int nx = int(round(destX));
260 int ny = int(round(destY));
261 uint32_t polygon_from_map = get_pixel(nx, ny);
262 if (other_poly == polygon_from_map) {
263 found_pixel_in_polygon = true;
264 break;
265 }
266
267 float dist_to_edge;
268 /* Look up again, but starting from the face we were expected to land in. */
269 if (!lookup_pixel(nx, ny, other_poly, &destX, &destY, &other_poly, &dist_to_edge)) {
270 found_pixel_in_polygon = false;
271 break;
272 }
273 }
274
275 if (found_pixel_in_polygon) {
276 if (ibuf_ptr_fl) {
277 ibuf_ptr_fl[pixel_index] = imbuf::interpolate_bilinear_border_fl(
278 ibuf, destX, destY);
279 }
280 if (ibuf_ptr_ch) {
281 ibuf_ptr_ch[pixel_index] = imbuf::interpolate_bilinear_border_byte(
282 ibuf, destX, destY);
283 }
284 /* Add our new pixels to the assigned pixel map. */
285 mask[pixel_index] = 1;
286 }
287 }
288 }
289 else if (DijkstraPixelIsUnset(dp) || !IsDijkstraPixel(dp)) {
290 /* These are not margin pixels, make sure the extend filter which is run after this step
291 * leaves them alone.
292 */
293 mask[pixel_index] = 1;
294 }
295 pixel_index++;
296 }
297 }
298 }
299
300 private:
301 float2 uv_to_xy(const float2 &mloopuv) const
302 {
303 float2 ret;
304 ret.x = (((mloopuv[0] - uv_offset_[0]) * w_) - (0.5f + 0.001f));
305 ret.y = (((mloopuv[1] - uv_offset_[1]) * h_) - (0.5f + 0.001f));
306 return ret;
307 }
308
309 void build_tables()
310 {
311 loop_to_face_map_ = blender::bke::mesh::build_corner_to_face_map(faces_);
312
313 loop_adjacency_map_.resize(corner_edges_.size(), -1);
314
315 Vector<int> tmpmap;
316 tmpmap.resize(totedge_, -1);
317
318 for (const int64_t i : corner_edges_.index_range()) {
319 int edge = corner_edges_[i];
320 if (tmpmap[edge] == -1) {
321 loop_adjacency_map_[i] = -1;
322 tmpmap[edge] = i;
323 }
324 else {
325 BLI_assert(tmpmap[edge] >= 0);
326 loop_adjacency_map_[i] = tmpmap[edge];
327 loop_adjacency_map_[tmpmap[edge]] = i;
328 }
329 }
330 }
331
338 bool lookup_pixel_polygon_neighborhood(
339 float x, float y, uint32_t *r_start_poly, float *r_destx, float *r_desty, int *r_other_poly)
340 {
341 float found_dist;
342 if (lookup_pixel(x, y, *r_start_poly, r_destx, r_desty, r_other_poly, &found_dist)) {
343 return true;
344 }
345
346 int loopstart = faces_[*r_start_poly].start();
347 int totloop = faces_[*r_start_poly].size();
348
349 float destx, desty;
350 int foundpoly;
351
352 float mindist = -1.0f;
353
354 /* Loop over all adjacent polygons and determine which edge is closest.
355 * This could be optimized by only inspecting neighbors which are on the edge of an island.
356 * But it seems fast enough for now and that would add a lot of complexity. */
357 for (int i = 0; i < totloop; i++) {
358 int otherloop = loop_adjacency_map_[i + loopstart];
359
360 if (otherloop < 0) {
361 continue;
362 }
363
364 uint32_t face = loop_to_face_map_[otherloop];
365
366 if (lookup_pixel(x, y, face, &destx, &desty, &foundpoly, &found_dist)) {
367 if (mindist < 0.0f || found_dist < mindist) {
368 mindist = found_dist;
369 *r_other_poly = foundpoly;
370 *r_destx = destx;
371 *r_desty = desty;
372 *r_start_poly = face;
373 }
374 }
375 }
376
377 return mindist >= 0.0f;
378 }
379
386 bool lookup_pixel(float x,
387 float y,
388 int src_poly,
389 float *r_destx,
390 float *r_desty,
391 int *r_other_poly,
392 float *r_dist_to_edge)
393 {
394 float2 point(x, y);
395
396 *r_destx = *r_desty = 0;
397
398 int found_edge = -1;
399 float found_dist = -1;
400 float found_t = 0;
401
402 /* Find the closest edge on which the point x,y can be projected.
403 */
404 for (size_t i = 0; i < faces_[src_poly].size(); i++) {
405 int l1 = faces_[src_poly].start() + i;
406 int l2 = l1 + 1;
407 if (l2 >= faces_[src_poly].start() + faces_[src_poly].size()) {
408 l2 = faces_[src_poly].start();
409 }
410 /* edge points */
411 float2 edgepoint1 = uv_to_xy(mloopuv_[l1]);
412 float2 edgepoint2 = uv_to_xy(mloopuv_[l2]);
413 /* Vector AB is the vector from the first edge point to the second edge point.
414 * Vector AP is the vector from the first edge point to our point under investigation. */
415 float2 ab = edgepoint2 - edgepoint1;
416 float2 ap = point - edgepoint1;
417
418 /* Project ap onto ab. */
419 float dotv = math::dot(ab, ap);
420
421 float ablensq = math::length_squared(ab);
422
423 float t = dotv / ablensq;
424
425 if (t >= 0.0 && t <= 1.0) {
426
427 /* Find the point on the edge closest to P */
428 float2 reflect_point = edgepoint1 + (t * ab);
429 /* This is the vector to P, so 90 degrees out from the edge. */
430 float2 reflect_vec = reflect_point - point;
431
432 float reflectLen = sqrt(reflect_vec[0] * reflect_vec[0] + reflect_vec[1] * reflect_vec[1]);
433 float cross = ab[0] * reflect_vec[1] - ab[1] * reflect_vec[0];
434 /* Only if P is on the outside of the edge, which means the cross product is positive,
435 * we consider this edge.
436 */
437 bool valid = (cross > 0.0);
438
439 if (valid && (found_dist < 0 || reflectLen < found_dist)) {
440 /* Stother_ab the info of the closest edge so far. */
441 found_dist = reflectLen;
442 found_t = t;
443 found_edge = i + faces_[src_poly].start();
444 }
445 }
446 }
447
448 if (found_edge < 0) {
449 return false;
450 }
451
452 *r_dist_to_edge = found_dist;
453
454 /* Get the 'other' edge. I.E. the UV edge from the neighbor face. */
455 int other_edge = loop_adjacency_map_[found_edge];
456
457 if (other_edge < 0) {
458 return false;
459 }
460
461 int dst_poly = loop_to_face_map_[other_edge];
462
463 if (r_other_poly) {
464 *r_other_poly = dst_poly;
465 }
466
467 int other_edge2 = other_edge + 1;
468 if (other_edge2 >= faces_[dst_poly].start() + faces_[dst_poly].size()) {
469 other_edge2 = faces_[dst_poly].start();
470 }
471
472 float2 other_edgepoint1 = uv_to_xy(mloopuv_[other_edge]);
473 float2 other_edgepoint2 = uv_to_xy(mloopuv_[other_edge2]);
474
475 /* Calculate the vector from the order edges last point to its first point. */
476 float2 other_ab = other_edgepoint1 - other_edgepoint2;
477 float2 other_reflect_point = other_edgepoint2 + (found_t * other_ab);
478 float2 perpendicular_other_ab;
479 perpendicular_other_ab.x = other_ab.y;
480 perpendicular_other_ab.y = -other_ab.x;
481
482 /* The new point is dound_dist distance from other_reflect_point at a 90 degree angle to
483 * other_ab */
484 float2 new_point = other_reflect_point + (found_dist / math::length(perpendicular_other_ab)) *
485 perpendicular_other_ab;
486
487 *r_destx = new_point.x;
488 *r_desty = new_point.y;
489
490 return true;
491 }
492}; // class TextureMarginMap
493
494const int TextureMarginMap::directions[8][2] = {
495 {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}};
496const int TextureMarginMap::distances[8] = {2, 3, 2, 3, 2, 3, 2, 3};
497
498static void generate_margin(ImBuf *ibuf,
499 char *mask,
500 const int margin,
501 const Span<float3> vert_positions,
502 const int edges_num,
503 const OffsetIndices<int> faces,
504 const Span<int> corner_edges,
505 const Span<int> corner_verts,
506 const Span<float2> mloopuv,
507 const float uv_offset[2])
508{
509 Array<int3> corner_tris(poly_to_tri_count(faces.size(), corner_edges.size()));
510 bke::mesh::corner_tris_calc(vert_positions, faces, corner_verts, corner_tris);
511
512 Array<int> tri_faces(corner_tris.size());
514
515 TextureMarginMap map(ibuf->x, ibuf->y, uv_offset, edges_num, faces, corner_edges, mloopuv);
516
517 bool draw_new_mask = false;
518 /* Now the map contains 3 sorts of values: 0xFFFFFFFF for empty pixels, `0x80000000 + polyindex`
519 * for margin pixels, just `polyindex` for face pixels. */
520 if (mask) {
521 mask = (char *)MEM_dupallocN(mask);
522 }
523 else {
524 mask = (char *)MEM_callocN(sizeof(char) * ibuf->x * ibuf->y, __func__);
525 draw_new_mask = true;
526 }
527
528 for (const int i : corner_tris.index_range()) {
529 const int3 tri = corner_tris[i];
530 float vec[3][2];
531
532 for (int a = 0; a < 3; a++) {
533 const float *uv = mloopuv[tri[a]];
534
535 /* NOTE(@ideasman42): workaround for pixel aligned UVs which are common and can screw up
536 * our intersection tests where a pixel gets in between 2 faces or the middle of a quad,
537 * camera aligned quads also have this problem but they are less common.
538 * Add a small offset to the UVs, fixes bug #18685. */
539 vec[a][0] = (uv[0] - uv_offset[0]) * float(ibuf->x) - (0.5f + 0.001f);
540 vec[a][1] = (uv[1] - uv_offset[1]) * float(ibuf->y) - (0.5f + 0.002f);
541 }
542
543 /* NOTE: we need the top bit for the dijkstra distance map. */
544 BLI_assert(tri_faces[i] < 0x80000000);
545
546 map.rasterize_tri(vec[0], vec[1], vec[2], tri_faces[i], mask, draw_new_mask);
547 }
548
549 char *tmpmask = (char *)MEM_dupallocN(mask);
550 /* Extend (with averaging) by 2 pixels. Those will be overwritten, but it
551 * helps linear interpolations on the edges of polygons. */
552 IMB_filter_extend(ibuf, tmpmask, 2);
553 MEM_freeN(tmpmask);
554
555 map.grow_dijkstra(margin);
556
557 /* Looking further than 3 polygons away leads to so much cumulative rounding
558 * that it isn't worth it. So hard-code it to 3. */
559 map.lookup_pixels(ibuf, mask, 3);
560
561 /* Use the extend filter to fill in the missing pixels at the corners, not strictly correct, but
562 * the visual difference seems very minimal. This also catches pixels we missed because of very
563 * narrow polygons.
564 */
565 IMB_filter_extend(ibuf, mask, margin);
566
567 MEM_freeN(mask);
568}
569
570} // namespace blender::render::texturemargin
571
573 char *mask,
574 const int margin,
575 const Mesh *mesh,
576 char const *uv_layer,
577 const float uv_offset[2])
578{
579 using namespace blender;
580 const blender::StringRef uv_map_name = (uv_layer && uv_layer[0]) ?
581 uv_layer :
582 CustomData_get_active_layer_name(&mesh->corner_data,
584 const blender::bke::AttributeAccessor attributes = mesh->attributes();
585 const VArraySpan<float2> uv_map = *attributes.lookup<float2>(uv_map_name,
586 bke::AttrDomain::Corner);
587
589 mask,
590 margin,
591 mesh->vert_positions(),
592 mesh->edges_num,
593 mesh->faces(),
594 mesh->corner_edges(),
595 mesh->corner_verts(),
596 uv_map,
597 uv_offset);
598}
599
601 ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2])
602{
603 const blender::float2 *mloopuv = static_cast<const blender::float2 *>(
605
607 ibuf,
608 mask,
609 margin,
610 {reinterpret_cast<const blender::float3 *>(dm->getVertArray(dm)), dm->getNumVerts(dm)},
611 dm->getNumEdges(dm),
612 blender::Span(dm->getPolyArray(dm), dm->getNumPolys(dm) + 1),
613 {dm->getCornerEdgeArray(dm), dm->getNumLoops(dm)},
614 {dm->getCornerVertArray(dm), dm->getNumLoops(dm)},
615 {mloopuv, dm->getNumLoops(dm)},
616 uv_offset);
617}
CustomData interface, see also DNA_customdata_types.h.
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
#define BLI_assert(a)
Definition BLI_assert.h:50
sqrt(x)+1/max(0
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
MINLINE void copy_v2_v2(float r[2], const float a[2])
@ CD_PROP_FLOAT2
void IMB_filter_extend(ImBuf *ibuf, char *mask, int filter)
Definition filter.cc:319
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
int64_t size() const
Definition BLI_array.hh:245
IndexRange index_range() const
Definition BLI_array.hh:349
constexpr int64_t size() const
Definition BLI_span.hh:253
int64_t size() const
void append(const T &value)
void resize(const int64_t new_size)
void rasterize_tri(float *v1, float *v2, float *v3, uint32_t value, char *mask, bool writemask)
void set_pixel(int x, int y, uint32_t value)
TextureMarginMap(size_t w, size_t h, const float uv_offset[2], const int totedge, const OffsetIndices< int > faces, const Span< int > corner_edges, const Span< float2 > mloopuv)
void lookup_pixels(ImBuf *ibuf, char *mask, int maxPolygonSteps)
static void zscan_store_pixel(void *map, int x, int y, float u, float v)
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_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
void corner_tris_calc(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< int3 > corner_tris)
Array< int > build_corner_to_face_map(OffsetIndices< int > faces)
void corner_tris_calc_face_indices(OffsetIndices< int > faces, MutableSpan< int > tri_faces)
uchar4 interpolate_bilinear_border_byte(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:74
float4 interpolate_bilinear_border_fl(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:78
T length_squared(const VecBase< T, Size > &a)
T length(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
static void generate_margin(ImBuf *ibuf, char *mask, const int margin, const Span< float3 > vert_positions, const int edges_num, const OffsetIndices< int > faces, const Span< int > corner_edges, const Span< int > corner_verts, const Span< float2 > mloopuv, const float uv_offset[2])
float distance(float a, float b)
return ret
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
int *(* getPolyArray)(DerivedMesh *dm)
int(* getNumVerts)(DerivedMesh *dm)
int *(* getCornerVertArray)(DerivedMesh *dm)
int(* getNumPolys)(DerivedMesh *dm)
int(* getNumEdges)(DerivedMesh *dm)
float *(* getVertArray)(DerivedMesh *dm)
void *(* getLoopDataArray)(DerivedMesh *dm, eCustomDataType type)
int *(* getCornerEdgeArray)(DerivedMesh *dm)
int(* getNumLoops)(DerivedMesh *dm)
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
Definition zbuf.h:16
float x
float y
#define PackDijkstraPixel(dist, dir)
void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf, char *mask, const int margin, const Mesh *mesh, char const *uv_layer, const float uv_offset[2])
void RE_generate_texturemargin_adjacentfaces_dm(ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2])
#define DijkstraPixelIsUnset(dp)
#define DijkstraPixelGetDistance(dp)
#define DijkstraPixelGetDirection(dp)
#define IsDijkstraPixel(dp)
void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void(*func)(void *, int, int, float, float))
Definition zbuf.cc:160
void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
Definition zbuf.cc:32
void zbuf_free_span(ZSpan *zspan)
Definition zbuf.cc:43