Blender  V3.3
paint_image_proj.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
9 #include <float.h>
10 #include <limits.h>
11 #include <math.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "MEM_guardedalloc.h"
16 
17 #ifdef WIN32
18 # include "BLI_winstuff.h"
19 #endif
20 
21 #include "BLI_blenlib.h"
22 #include "BLI_linklist.h"
23 #include "BLI_math.h"
24 #include "BLI_math_bits.h"
25 #include "BLI_math_color_blend.h"
26 #include "BLI_memarena.h"
27 #include "BLI_task.h"
28 #include "BLI_threads.h"
29 #include "BLI_utildefines.h"
30 
31 #include "atomic_ops.h"
32 
33 #include "BLT_translation.h"
34 
35 #include "IMB_imbuf.h"
36 #include "IMB_imbuf_types.h"
37 
38 #include "DNA_brush_types.h"
39 #include "DNA_customdata_types.h"
40 #include "DNA_defs.h"
41 #include "DNA_material_types.h"
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_node_types.h"
45 #include "DNA_object_enums.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48 
49 #include "BKE_attribute.h"
50 #include "BKE_brush.h"
51 #include "BKE_camera.h"
52 #include "BKE_colorband.h"
53 #include "BKE_colortools.h"
54 #include "BKE_context.h"
55 #include "BKE_customdata.h"
56 #include "BKE_global.h"
57 #include "BKE_idprop.h"
58 #include "BKE_image.h"
59 #include "BKE_lib_id.h"
60 #include "BKE_main.h"
61 #include "BKE_material.h"
62 #include "BKE_mesh.h"
63 #include "BKE_mesh_mapping.h"
64 #include "BKE_mesh_runtime.h"
65 #include "BKE_node.h"
66 #include "BKE_paint.h"
67 #include "BKE_report.h"
68 #include "BKE_scene.h"
69 #include "BKE_screen.h"
70 #include "DNA_screen_types.h"
71 #include "DNA_space_types.h"
72 
73 #include "DEG_depsgraph.h"
74 #include "DEG_depsgraph_query.h"
75 
76 #include "ED_node.h"
77 #include "ED_object.h"
78 #include "ED_paint.h"
79 #include "ED_screen.h"
80 #include "ED_uvedit.h"
81 #include "ED_view3d.h"
82 #include "ED_view3d_offscreen.h"
83 
84 #include "GPU_capabilities.h"
85 #include "GPU_init_exit.h"
86 
87 #include "NOD_shader.h"
88 
89 #include "UI_interface.h"
90 #include "UI_resources.h"
91 
92 #include "WM_api.h"
93 #include "WM_types.h"
94 
95 #include "RNA_access.h"
96 #include "RNA_define.h"
97 #include "RNA_enum_types.h"
98 #include "RNA_types.h"
99 
100 #include "IMB_colormanagement.h"
101 
102 //#include "bmesh_tools.h"
103 
104 #include "paint_intern.h"
105 
107 
108 /* Defines and Structs */
109 /* unit_float_to_uchar_clamp as inline function */
110 BLI_INLINE uchar f_to_char(const float val)
111 {
112  return unit_float_to_uchar_clamp(val);
113 }
114 
115 /* ProjectionPaint defines */
116 
117 /* approx the number of buckets to have under the brush,
118  * used with the brush size to set the ps->buckets_x and ps->buckets_y value.
119  *
120  * When 3 - a brush should have ~9 buckets under it at once
121  * ...this helps for threading while painting as well as
122  * avoiding initializing pixels that won't touch the brush */
123 #define PROJ_BUCKET_BRUSH_DIV 4
124 
125 #define PROJ_BUCKET_RECT_MIN 4
126 #define PROJ_BUCKET_RECT_MAX 256
127 
128 #define PROJ_BOUNDBOX_DIV 8
129 #define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
130 
131 //#define PROJ_DEBUG_PAINT 1
132 //#define PROJ_DEBUG_NOSEAMBLEED 1
133 //#define PROJ_DEBUG_PRINT_CLIP 1
134 #define PROJ_DEBUG_WINCLIP 1
135 
136 #ifndef PROJ_DEBUG_NOSEAMBLEED
137 /* projectFaceSeamFlags options */
138 //#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, back-facing or occluded. */
139 //#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
140 
141 /* If this face has a seam on any of its edges. */
142 # define PROJ_FACE_SEAM0 (1 << 0)
143 # define PROJ_FACE_SEAM1 (1 << 1)
144 # define PROJ_FACE_SEAM2 (1 << 2)
145 
146 # define PROJ_FACE_NOSEAM0 (1 << 4)
147 # define PROJ_FACE_NOSEAM1 (1 << 5)
148 # define PROJ_FACE_NOSEAM2 (1 << 6)
149 
150 /* If the seam is completely initialized, including adjacent seams. */
151 # define PROJ_FACE_SEAM_INIT0 (1 << 8)
152 # define PROJ_FACE_SEAM_INIT1 (1 << 9)
153 # define PROJ_FACE_SEAM_INIT2 (1 << 10)
154 
155 # define PROJ_FACE_DEGENERATE (1 << 12)
156 
157 /* face winding */
158 # define PROJ_FACE_WINDING_INIT 1
159 # define PROJ_FACE_WINDING_CW 2
160 
161 /* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
162  * as this number approaches 1.0f the likelihood increases of float precision errors where
163  * it is occluded by an adjacent face */
164 # define PROJ_FACE_SCALE_SEAM 0.99f
165 #endif /* PROJ_DEBUG_NOSEAMBLEED */
166 
167 #define PROJ_SRC_VIEW 1
168 #define PROJ_SRC_IMAGE_CAM 2
169 #define PROJ_SRC_IMAGE_VIEW 3
170 #define PROJ_SRC_VIEW_FILL 4
171 
172 #define PROJ_VIEW_DATA_ID "view_data"
173 /* viewmat + winmat + clip_start + clip_end + is_ortho */
174 #define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3)
175 
176 #define PROJ_BUCKET_NULL 0
177 #define PROJ_BUCKET_INIT (1 << 0)
178 // #define PROJ_BUCKET_CLONE_INIT (1<<1)
179 
180 /* used for testing doubles, if a point is on a line etc */
181 #define PROJ_GEOM_TOLERANCE 0.00075f
182 #define PROJ_PIXEL_TOLERANCE 0.01f
183 
184 /* vert flags */
185 #define PROJ_VERT_CULL 1
186 
187 /* to avoid locking in tile initialization */
188 #define TILE_PENDING POINTER_FROM_INT(-1)
189 
195 typedef struct ProjPaintImage {
201  volatile void **undoRect;
206  bool **valid;
207  bool touch;
209 
213 typedef struct ProjStrokeHandle {
214  /* Support for painting from multiple views at once,
215  * currently used to implement symmetry painting,
216  * we can assume at least the first is set while painting. */
220 
222 
224 
225  /* trick to bypass regular paint and allow clone picking */
227 
228  /* In ProjPaintState, only here for convenience */
232 
233 typedef struct LoopSeamData {
234  float seam_uvs[2][2];
235  float seam_puvs[2][2];
236  float corner_dist_sq[2];
238 
239 /* Main projection painting struct passed to all projection painting functions */
240 typedef struct ProjPaintState {
246  /* PROJ_SRC_**** */
247  int source;
248 
249  /* the paint color. It can change depending of inverted mode or not */
250  float paint_color[3];
252  float dither;
253 
255  short tool, blend, mode;
256 
257  float brush_size;
259  /* for symmetry, we need to store modified object matrix */
260  float obmat[4][4];
261  float obmat_imat[4][4];
262  /* end similarities with ImagePaintState */
263 
268 
269  /* projection painting only */
278 
280  char *vertFlags;
285 
288 
291 
295  float screenMin[2];
296  float screenMax[2];
301  int winx, winy;
302 
303  /* options for projection painting */
309 
327 
330  bool is_ortho;
339 #ifndef PROJ_DEBUG_NOSEAMBLEED
342 #endif
343  /* clone vars */
344  float cloneOffset[2];
345 
347  float projectMat[4][4];
349  float projectMatInv[4][4];
351  float viewDir[3];
353  float viewPos[3];
355 
356  /* reproject vars */
361 
362  /* threads */
364  int bucketMin[2];
365  int bucketMax[2];
368 
371 
372  /* -------------------------------------------------------------------- */
373  /* Vars shared between multiple views (keep last) */
379 #define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
380  MEMCPY_STRUCT_AFTER(ps_dst, ps_src, is_shared_user)
381 
382 #define PROJ_PAINT_STATE_SHARED_CLEAR(ps) MEMSET_STRUCT_AFTER(ps, 0, is_shared_user)
383 
385 
388  float *cavities;
389 
390 #ifndef PROJ_DEBUG_NOSEAMBLEED
402 #endif
403 
405 
412 
414  const float (*vert_normals)[3];
419 
421 
430 
431  /* Actual material for each index, either from object or Mesh datablock... */
433 
436 
437 typedef union pixelPointer {
439  float *f_pt;
444 
445 typedef union pixelStore {
446  uchar ch[4];
448  float f[4];
450 
451 typedef struct ProjPixel {
453  float projCoSS[2];
454  float worldCoSS[3];
455 
456  short x_px, y_px;
457 
461 
462  /* for various reasons we may want to mask out painting onto this pixel */
464 
465  /* Only used when the airbrush is disabled.
466  * Store the max mask value to avoid painting over an area with a lower opacity
467  * with an advantage that we can avoid touching the pixel at all, if the
468  * new mask value is lower than mask_accum */
470 
471  /* horrible hack, store tile valid flag pointer here to re-validate tiles
472  * used for anchored and drag-dot strokes */
473  bool *valid;
474 
479 
480 typedef struct ProjPixelClone {
481  struct ProjPixel __pp;
484 
485 /* undo tile pushing */
486 typedef struct {
488  bool masked;
492 } TileInfo;
493 
494 typedef struct VertSeam {
495  struct VertSeam *next, *prev;
496  int tri;
498  float angle;
499  bool normal_cw;
500  float uv[2];
502 
503 /* -------------------------------------------------------------------- */
507 BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_index)
508 {
509  return &ps->mpoly_eval[ps->mlooptri_eval[tri_index].poly];
510 }
511 
512 #define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) \
513  ps->mloop_eval[lt->tri[0]].v, ps->mloop_eval[lt->tri[1]].v, ps->mloop_eval[lt->tri[2]].v,
514 
515 #define PS_LOOPTRI_AS_UV_3(uvlayer, lt) \
516  uvlayer[lt->poly][lt->tri[0]].uv, uvlayer[lt->poly][lt->tri[1]].uv, \
517  uvlayer[lt->poly][lt->tri[2]].uv,
518 
519 #define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, lt) \
520  { \
521  (uv_tri)[0] = uvlayer[lt->poly][lt->tri[0]].uv; \
522  (uv_tri)[1] = uvlayer[lt->poly][lt->tri[1]].uv; \
523  (uv_tri)[2] = uvlayer[lt->poly][lt->tri[2]].uv; \
524  } \
525  ((void)0)
526 
529 /* Finish projection painting structs */
530 
531 static int project_paint_face_paint_tile(Image *ima, const float *uv)
532 {
533  if (ima == NULL || ima->source != IMA_SRC_TILED) {
534  return 0;
535  }
536 
537  /* Currently, faces are assumed to belong to one tile, so checking the first loop is enough. */
538  int tx = (int)uv[0];
539  int ty = (int)uv[1];
540  return 1001 + 10 * ty + tx;
541 }
542 
544 {
545  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
546  Material *ma = ps->mat_array[mp->mat_nr];
547  return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
548 }
549 
550 static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_index)
551 {
552  if (ps->do_stencil_brush) {
553  return ps->stencil_ima;
554  }
555 
556  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
557  Material *ma = ps->mat_array[mp->mat_nr];
558  TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
559  return slot ? slot->ima : ps->canvas_ima;
560 }
561 
563 {
564  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
565  Material *ma = ps->mat_array[mp->mat_nr];
566  return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
567 }
568 
569 static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
570 {
571  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
572  Material *ma = ps->mat_array[mp->mat_nr];
573  TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
574  return slot ? slot->ima : ps->clone_ima;
575 }
576 
580 static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
581 {
582  /* If we were not dealing with screen-space 2D coords we could simple do...
583  * ps->bucketRect[x + (y*ps->buckets_y)] */
584 
585  /* please explain?
586  * projCoSS[0] - ps->screenMin[0] : zero origin
587  * ... / ps->screen_width : range from 0.0 to 1.0
588  * ... * ps->buckets_x : use as a bucket index
589  *
590  * Second multiplication does similar but for vertical offset
591  */
592  return ((int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) +
593  (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) *
594  ps->buckets_x);
595 }
596 
597 static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2])
598 {
599  int bucket_index = project_bucket_offset(ps, projCoSS);
600 
601  if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) {
602  return -1;
603  }
604  return bucket_index;
605 }
606 
607 static float VecZDepthOrtho(
608  const float pt[2], const float v1[3], const float v2[3], const float v3[3], float w[3])
609 {
610  barycentric_weights_v2(v1, v2, v3, pt, w);
611  return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
612 }
613 
614 static float VecZDepthPersp(
615  const float pt[2], const float v1[4], const float v2[4], const float v3[4], float w[3])
616 {
617  float wtot_inv, wtot;
618  float w_tmp[3];
619 
620  barycentric_weights_v2_persp(v1, v2, v3, pt, w);
621  /* for the depth we need the weights to match what
622  * barycentric_weights_v2 would return, in this case its easiest just to
623  * undo the 4th axis division and make it unit-sum
624  *
625  * don't call barycentric_weights_v2() because our callers expect 'w'
626  * to be weighted from the perspective */
627  w_tmp[0] = w[0] * v1[3];
628  w_tmp[1] = w[1] * v2[3];
629  w_tmp[2] = w[2] * v3[3];
630 
631  wtot = w_tmp[0] + w_tmp[1] + w_tmp[2];
632 
633  if (wtot != 0.0f) {
634  wtot_inv = 1.0f / wtot;
635 
636  w_tmp[0] = w_tmp[0] * wtot_inv;
637  w_tmp[1] = w_tmp[1] * wtot_inv;
638  w_tmp[2] = w_tmp[2] * wtot_inv;
639  }
640  else { /* dummy values for zero area face */
641  w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f;
642  }
643  /* done mimicking barycentric_weights_v2() */
644 
645  return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]);
646 }
647 
648 /* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
649 static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3])
650 {
651  LinkNode *node;
652  float w_tmp[3];
653  int bucket_index;
654  int best_tri_index = -1;
655  float z_depth_best = FLT_MAX, z_depth;
656 
657  bucket_index = project_bucket_offset_safe(ps, pt);
658  if (bucket_index == -1) {
659  return -1;
660  }
661 
662  /* we could return 0 for 1 face buckets, as long as this function assumes
663  * that the point its testing is only every originated from an existing face */
664 
665  for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
666  const int tri_index = POINTER_AS_INT(node->link);
667  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
668  const float *vtri_ss[3] = {
669  ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
670  ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
671  ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
672  };
673 
674  if (isect_point_tri_v2(pt, UNPACK3(vtri_ss))) {
675  if (ps->is_ortho) {
676  z_depth = VecZDepthOrtho(pt, UNPACK3(vtri_ss), w_tmp);
677  }
678  else {
679  z_depth = VecZDepthPersp(pt, UNPACK3(vtri_ss), w_tmp);
680  }
681 
682  if (z_depth < z_depth_best) {
683  best_tri_index = tri_index;
684  z_depth_best = z_depth;
685  copy_v3_v3(w, w_tmp);
686  }
687  }
688  }
689 
691  return best_tri_index;
692 }
693 
694 /* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */
695 static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
696 {
697  /* use */
698  *x = fmodf(uv[0], 1.0f);
699  *y = fmodf(uv[1], 1.0f);
700 
701  if (*x < 0.0f) {
702  *x += 1.0f;
703  }
704  if (*y < 0.0f) {
705  *y += 1.0f;
706  }
707 
708  *x = *x * ibuf_x - 0.5f;
709  *y = *y * ibuf_y - 0.5f;
710 }
711 
712 /* Set the top-most face color that the screen space coord 'pt' touches
713  * (or return 0 if none touch) */
715  const ProjPaintState *ps, const float pt[2], float *rgba_fp, uchar *rgba, const bool interp)
716 {
717  const MLoopTri *lt;
718  const float *lt_tri_uv[3];
719  float w[3], uv[2];
720  int tri_index;
721  Image *ima;
722  ImBuf *ibuf;
723  int xi, yi;
724 
725  tri_index = project_paint_PickFace(ps, pt, w);
726 
727  if (tri_index == -1) {
728  return false;
729  }
730 
731  lt = &ps->mlooptri_eval[tri_index];
732  PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->poly_to_loop_uv, lt);
733 
734  interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
735 
736  ima = project_paint_face_paint_image(ps, tri_index);
738  int tile_number = project_paint_face_paint_tile(ima, lt_tri_uv[0]);
739  /* XXX get appropriate ImageUser instead */
740  ImageUser iuser;
741  BKE_imageuser_default(&iuser);
742  iuser.tile = tile_number;
743  iuser.framenr = ima->lastframe;
744  ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
745  if (ibuf == NULL) {
746  return false;
747  }
748 
749  if (interp) {
750  float x, y;
751  uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y);
752 
753  if (ibuf->rect_float) {
754  if (rgba_fp) {
755  bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y);
756  }
757  else {
758  float rgba_tmp_f[4];
759  bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y);
761  }
762  }
763  else {
764  if (rgba) {
766  }
767  else {
768  uchar rgba_tmp[4];
769  bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
770  straight_uchar_to_premul_float(rgba_fp, rgba_tmp);
771  }
772  }
773  }
774  else {
775  // xi = (int)((uv[0]*ibuf->x) + 0.5f);
776  // yi = (int)((uv[1]*ibuf->y) + 0.5f);
777  // if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return false;
778 
779  /* wrap */
780  xi = mod_i((int)(uv[0] * ibuf->x), ibuf->x);
781  yi = mod_i((int)(uv[1] * ibuf->y), ibuf->y);
782 
783  if (rgba) {
784  if (ibuf->rect_float) {
785  const float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4);
786  premul_float_to_straight_uchar(rgba, rgba_tmp_fp);
787  }
788  else {
789  *((uint *)rgba) = *(uint *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
790  }
791  }
792 
793  if (rgba_fp) {
794  if (ibuf->rect_float) {
795  copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
796  }
797  else {
798  uchar *tmp_ch = ((uchar *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
799  straight_uchar_to_premul_float(rgba_fp, tmp_ch);
800  }
801  }
802  }
803  BKE_image_release_ibuf(ima, ibuf, NULL);
804  return true;
805 }
806 
815 static int project_paint_occlude_ptv(const float pt[3],
816  const float v1[4],
817  const float v2[4],
818  const float v3[4],
819  float w[3],
820  const bool is_ortho)
821 {
822  /* if all are behind us, return false */
823  if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2]) {
824  return 0;
825  }
826 
827  /* do a 2D point in try intersection */
828  if (!isect_point_tri_v2(pt, v1, v2, v3)) {
829  return 0;
830  }
831 
832  /* From here on we know there IS an intersection */
833  /* if ALL of the verts are in front of us then we know it intersects ? */
834  if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
835  return 1;
836  }
837 
838  /* we intersect? - find the exact depth at the point of intersection */
839  /* Is this point is occluded by another face? */
840  if (is_ortho) {
841  if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) {
842  return 2;
843  }
844  }
845  else {
846  if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) {
847  return 2;
848  }
849  }
850  return -1;
851 }
852 
853 static int project_paint_occlude_ptv_clip(const float pt[3],
854  const float v1[4],
855  const float v2[4],
856  const float v3[4],
857  const float v1_3d[3],
858  const float v2_3d[3],
859  const float v3_3d[3],
860  float w[3],
861  const bool is_ortho,
862  RegionView3D *rv3d)
863 {
864  float wco[3];
865  int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, is_ortho);
866 
867  if (ret <= 0) {
868  return ret;
869  }
870 
871  if (ret == 1) { /* weights not calculated */
872  if (is_ortho) {
873  barycentric_weights_v2(v1, v2, v3, pt, w);
874  }
875  else {
876  barycentric_weights_v2_persp(v1, v2, v3, pt, w);
877  }
878  }
879 
880  /* Test if we're in the clipped area, */
881  interp_v3_v3v3v3(wco, v1_3d, v2_3d, v3_3d, w);
882 
883  if (!ED_view3d_clipping_test(rv3d, wco, true)) {
884  return 1;
885  }
886 
887  return -1;
888 }
889 
890 /* Check if a screen-space location is occluded by any other faces
891  * check, pixelScreenCo must be in screen-space, its Z-Depth only needs to be used for comparison
892  * and doesn't need to be correct in relation to X and Y coords
893  * (this is the case in perspective view) */
895  LinkNode *bucketFace,
896  const int orig_face,
897  const float pixelScreenCo[4])
898 {
899  int isect_ret;
900  const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
901 
902  /* we could return false for 1 face buckets, as long as this function assumes
903  * that the point its testing is only every originated from an existing face */
904 
905  for (; bucketFace; bucketFace = bucketFace->next) {
906  const int tri_index = POINTER_AS_INT(bucketFace->link);
907 
908  if (orig_face != tri_index) {
909  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
910  const float *vtri_ss[3] = {
911  ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
912  ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
913  ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
914  };
915  float w[3];
916 
917  if (do_clip) {
918  const float *vtri_co[3] = {
919  ps->mvert_eval[ps->mloop_eval[lt->tri[0]].v].co,
920  ps->mvert_eval[ps->mloop_eval[lt->tri[1]].v].co,
921  ps->mvert_eval[ps->mloop_eval[lt->tri[2]].v].co,
922  };
923  isect_ret = project_paint_occlude_ptv_clip(
924  pixelScreenCo, UNPACK3(vtri_ss), UNPACK3(vtri_co), w, ps->is_ortho, ps->rv3d);
925  }
926  else {
927  isect_ret = project_paint_occlude_ptv(pixelScreenCo, UNPACK3(vtri_ss), w, ps->is_ortho);
928  }
929 
930  if (isect_ret >= 1) {
931  /* TODO: we may want to cache the first hit,
932  * it is not possible to swap the face order in the list anymore */
933  return true;
934  }
935  }
936  }
937  return false;
938 }
939 
940 /* Basic line intersection, could move to math_geom.c, 2 points with a horizontal line
941  * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned. */
942 #define ISECT_TRUE 1
943 #define ISECT_TRUE_P1 2
944 #define ISECT_TRUE_P2 3
945 static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect)
946 {
947  float y_diff;
948 
949  /* are we touching the first point? - no interpolation needed */
950  if (y_level == p1[1]) {
951  *x_isect = p1[0];
952  return ISECT_TRUE_P1;
953  }
954  /* are we touching the second point? - no interpolation needed */
955  if (y_level == p2[1]) {
956  *x_isect = p2[0];
957  return ISECT_TRUE_P2;
958  }
959 
961  y_diff = fabsf(p1[1] - p2[1]);
962 
963  if (y_diff < 0.000001f) {
964  *x_isect = (p1[0] + p2[0]) * 0.5f;
965  return ISECT_TRUE;
966  }
967 
968  if (p1[1] > y_level && p2[1] < y_level) {
969  /* (p1[1] - p2[1]); */
970  *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff;
971  return ISECT_TRUE;
972  }
973  if (p1[1] < y_level && p2[1] > y_level) {
974  /* (p2[1] - p1[1]); */
975  *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff;
976  return ISECT_TRUE;
977  }
978  return 0;
979 }
980 
981 static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect)
982 {
983  float x_diff;
984 
985  if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */
986  *y_isect = p1[1];
987  return ISECT_TRUE_P1;
988  }
989  if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */
990  *y_isect = p2[1];
991  return ISECT_TRUE_P2;
992  }
993 
994  /* yuck, horizontal line, we can't do much here */
995  x_diff = fabsf(p1[0] - p2[0]);
996 
997  /* yuck, vertical line, we can't do much here */
998  if (x_diff < 0.000001f) {
999  *y_isect = (p1[0] + p2[0]) * 0.5f;
1000  return ISECT_TRUE;
1001  }
1002 
1003  if (p1[0] > x_level && p2[0] < x_level) {
1004  /* (p1[0] - p2[0]); */
1005  *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff;
1006  return ISECT_TRUE;
1007  }
1008  if (p1[0] < x_level && p2[0] > x_level) {
1009  /* (p2[0] - p1[0]); */
1010  *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff;
1011  return ISECT_TRUE;
1012  }
1013  return 0;
1014 }
1015 
1016 /* simple func use for comparing UV locations to check if there are seams.
1017  * Its possible this gives incorrect results, when the UVs for 1 face go into the next
1018  * tile, but do not do this for the adjacent face, it could return a false positive.
1019  * This is so unlikely that Id not worry about it. */
1020 #ifndef PROJ_DEBUG_NOSEAMBLEED
1021 static bool cmp_uv(const float vec2a[2], const float vec2b[2])
1022 {
1023  /* if the UV's are not between 0.0 and 1.0 */
1024  float xa = fmodf(vec2a[0], 1.0f);
1025  float ya = fmodf(vec2a[1], 1.0f);
1026 
1027  float xb = fmodf(vec2b[0], 1.0f);
1028  float yb = fmodf(vec2b[1], 1.0f);
1029 
1030  if (xa < 0.0f) {
1031  xa += 1.0f;
1032  }
1033  if (ya < 0.0f) {
1034  ya += 1.0f;
1035  }
1036 
1037  if (xb < 0.0f) {
1038  xb += 1.0f;
1039  }
1040  if (yb < 0.0f) {
1041  yb += 1.0f;
1042  }
1043 
1044  return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ?
1045  true :
1046  false;
1047 }
1048 #endif
1049 
1050 /* set min_px and max_px to the image space bounds of the UV coords
1051  * return zero if there is no area in the returned rectangle */
1052 #ifndef PROJ_DEBUG_NOSEAMBLEED
1053 static bool pixel_bounds_uv(const float uv_quad[4][2],
1054  rcti *bounds_px,
1055  const int ibuf_x,
1056  const int ibuf_y)
1057 {
1058  /* UV bounds */
1059  float min_uv[2], max_uv[2];
1060 
1061  INIT_MINMAX2(min_uv, max_uv);
1062 
1063  minmax_v2v2_v2(min_uv, max_uv, uv_quad[0]);
1064  minmax_v2v2_v2(min_uv, max_uv, uv_quad[1]);
1065  minmax_v2v2_v2(min_uv, max_uv, uv_quad[2]);
1066  minmax_v2v2_v2(min_uv, max_uv, uv_quad[3]);
1067 
1068  bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
1069  bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
1070 
1071  bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
1072  bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
1073 
1074  // printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);
1075 
1076  /* face uses no UV area when quantized to pixels? */
1077  return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? false : true;
1078 }
1079 #endif
1080 
1082  float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
1083 {
1084  /* UV bounds */
1085  float min_uv[2], max_uv[2];
1086 
1087  if (tot == 0) {
1088  return false;
1089  }
1090 
1091  INIT_MINMAX2(min_uv, max_uv);
1092 
1093  while (tot--) {
1094  minmax_v2v2_v2(min_uv, max_uv, (*uv));
1095  uv++;
1096  }
1097 
1098  bounds_px->xmin = (int)(ibuf_x * min_uv[0]);
1099  bounds_px->ymin = (int)(ibuf_y * min_uv[1]);
1100 
1101  bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1;
1102  bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1;
1103 
1104  // printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);
1105 
1106  /* face uses no UV area when quantized to pixels? */
1107  return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? false : true;
1108 }
1109 
1110 #ifndef PROJ_DEBUG_NOSEAMBLEED
1111 
1112 static void project_face_winding_init(const ProjPaintState *ps, const int tri_index)
1113 {
1114  /* detect the winding of faces in uv space */
1115  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
1116  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
1117  float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
1118 
1119  if (winding > 0) {
1120  ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_CW;
1121  }
1122 
1123  ps->faceWindingFlags[tri_index] |= PROJ_FACE_WINDING_INIT;
1124 }
1125 
1126 /* This function returns 1 if this face has a seam along the 2 face-vert indices
1127  * 'orig_i1_fidx' and 'orig_i2_fidx' */
1128 static bool check_seam(const ProjPaintState *ps,
1129  const int orig_face,
1130  const int orig_i1_fidx,
1131  const int orig_i2_fidx,
1132  int *other_face,
1133  int *orig_fidx)
1134 {
1135  const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
1136  const float *orig_lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt)};
1137  /* vert indices from face vert order indices */
1138  const uint i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
1139  const uint i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
1140  LinkNode *node;
1141  /* index in face */
1142  int i1_fidx = -1, i2_fidx = -1;
1143 
1144  for (node = ps->vertFaces[i1]; node; node = node->next) {
1145  const int tri_index = POINTER_AS_INT(node->link);
1146 
1147  if (tri_index != orig_face) {
1148  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
1149  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
1150  /* could check if the 2 faces images match here,
1151  * but then there wouldn't be a way to return the opposite face's info */
1152 
1153  /* We need to know the order of the verts in the adjacent face
1154  * set the i1_fidx and i2_fidx to (0,1,2,3) */
1155  i1_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i1);
1156  i2_fidx = BKE_MESH_TESSTRI_VINDEX_ORDER(lt_vtri, i2);
1157 
1158  /* Only need to check if 'i2_fidx' is valid because
1159  * we know i1_fidx is the same vert on both faces. */
1160  if (i2_fidx != -1) {
1161  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
1162  Image *tpage = project_paint_face_paint_image(ps, tri_index);
1163  Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
1164  int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
1165  int orig_tile = project_paint_face_paint_tile(orig_tpage, orig_lt_tri_uv[0]);
1166 
1167  BLI_assert(i1_fidx != -1);
1168 
1169  /* This IS an adjacent face!, now lets check if the UVs are ok */
1170 
1171  /* set up the other face */
1172  *other_face = tri_index;
1173 
1174  /* we check if difference is 1 here, else we might have a case of edge 2-0 for a tri */
1175  *orig_fidx = (i1_fidx < i2_fidx && (i2_fidx - i1_fidx == 1)) ? i1_fidx : i2_fidx;
1176 
1177  /* initialize face winding if needed */
1178  if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0) {
1179  project_face_winding_init(ps, tri_index);
1180  }
1181 
1182  /* first test if they have the same image */
1183  if ((orig_tpage == tpage) && (orig_tile == tile) &&
1184  cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
1185  cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx])) {
1186  /* if faces don't have the same winding in uv space,
1187  * they are on the same side so edge is boundary */
1188  if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW) !=
1189  (ps->faceWindingFlags[orig_face] & PROJ_FACE_WINDING_CW)) {
1190  return true;
1191  }
1192 
1193  // printf("SEAM (NONE)\n");
1194  return false;
1195  }
1196  // printf("SEAM (UV GAP)\n");
1197  return true;
1198  }
1199  }
1200  }
1201  // printf("SEAM (NO FACE)\n");
1202  *other_face = -1;
1203  return true;
1204 }
1205 
1207  uint loop_index,
1208  uint vert_index,
1209  VertSeam **r_seam)
1210 {
1211  ListBase *vert_seams = &ps->vertSeams[vert_index];
1212  VertSeam *seam = vert_seams->first;
1213  VertSeam *adjacent = NULL;
1214 
1215  while (seam->loop != loop_index) {
1216  seam = seam->next;
1217  }
1218 
1219  if (r_seam) {
1220  *r_seam = seam;
1221  }
1222 
1223  /* Circulate through the (sorted) vert seam array, in the direction of the seam normal,
1224  * until we find the first opposing seam, matching in UV space. */
1225  if (seam->normal_cw) {
1226  LISTBASE_CIRCULAR_BACKWARD_BEGIN (vert_seams, adjacent, seam) {
1227  if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) {
1228  break;
1229  }
1230  }
1231  LISTBASE_CIRCULAR_BACKWARD_END(vert_seams, adjacent, seam);
1232  }
1233  else {
1234  LISTBASE_CIRCULAR_FORWARD_BEGIN (vert_seams, adjacent, seam) {
1235  if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) {
1236  break;
1237  }
1238  }
1239  LISTBASE_CIRCULAR_FORWARD_END(vert_seams, adjacent, seam);
1240  }
1241 
1242  BLI_assert(adjacent);
1243 
1244  return adjacent;
1245 }
1246 
1247 /* Computes the normal of two seams at their intersection,
1248  * and returns the angle between the seam and its normal. */
1249 static float compute_seam_normal(VertSeam *seam, VertSeam *adj, float r_no[2])
1250 {
1251  const float PI_2 = M_PI * 2.0f;
1252  float angle[2];
1253  float angle_rel, angle_no;
1254 
1255  if (seam->normal_cw) {
1256  angle[0] = adj->angle;
1257  angle[1] = seam->angle;
1258  }
1259  else {
1260  angle[0] = seam->angle;
1261  angle[1] = adj->angle;
1262  }
1263 
1264  angle_rel = angle[1] - angle[0];
1265 
1266  if (angle_rel < 0.0f) {
1267  angle_rel += PI_2;
1268  }
1269 
1270  angle_rel *= 0.5f;
1271 
1272  angle_no = angle_rel + angle[0];
1273 
1274  if (angle_no > M_PI) {
1275  angle_no -= PI_2;
1276  }
1277 
1278  r_no[0] = cosf(angle_no);
1279  r_no[1] = sinf(angle_no);
1280 
1281  return angle_rel;
1282 }
1283 
1284 /* Calculate outset UV's, this is not the same as simply scaling the UVs,
1285  * since the outset coords are a margin that keep an even distance from the original UV's,
1286  * note that the image aspect is taken into account */
1287 static void uv_image_outset(const ProjPaintState *ps,
1288  float (*orig_uv)[2],
1289  float (*puv)[2],
1290  uint tri_index,
1291  const int ibuf_x,
1292  const int ibuf_y)
1293 {
1294  int fidx[2];
1295  uint loop_index;
1296  uint vert[2];
1297  const MLoopTri *ltri = &ps->mlooptri_eval[tri_index];
1298 
1299  float ibuf_inv[2];
1300 
1301  ibuf_inv[0] = 1.0f / (float)ibuf_x;
1302  ibuf_inv[1] = 1.0f / (float)ibuf_y;
1303 
1304  for (fidx[0] = 0; fidx[0] < 3; fidx[0]++) {
1305  LoopSeamData *seam_data;
1306  float(*seam_uvs)[2];
1307  float ang[2];
1308 
1309  if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM0 << fidx[0])) == 0) {
1310  continue;
1311  }
1312 
1313  loop_index = ltri->tri[fidx[0]];
1314 
1315  seam_data = &ps->loopSeamData[loop_index];
1316  seam_uvs = seam_data->seam_uvs;
1317 
1318  if (seam_uvs[0][0] != FLT_MAX) {
1319  continue;
1320  }
1321 
1322  fidx[1] = (fidx[0] == 2) ? 0 : fidx[0] + 1;
1323 
1324  vert[0] = ps->mloop_eval[loop_index].v;
1325  vert[1] = ps->mloop_eval[ltri->tri[fidx[1]]].v;
1326 
1327  for (uint i = 0; i < 2; i++) {
1328  VertSeam *seam;
1329  VertSeam *adj = find_adjacent_seam(ps, loop_index, vert[i], &seam);
1330  float no[2];
1331  float len_fact;
1332  float tri_ang;
1333 
1334  ang[i] = compute_seam_normal(seam, adj, no);
1335  tri_ang = ang[i] - M_PI_2;
1336 
1337  if (tri_ang > 0.0f) {
1338  const float dist = ps->seam_bleed_px * tanf(tri_ang);
1339  seam_data->corner_dist_sq[i] = square_f(dist);
1340  }
1341  else {
1342  seam_data->corner_dist_sq[i] = 0.0f;
1343  }
1344 
1345  len_fact = cosf(tri_ang);
1346  len_fact = UNLIKELY(len_fact < FLT_EPSILON) ? FLT_MAX : (1.0f / len_fact);
1347 
1348  /* Clamp the length factor, see: T62236. */
1349  len_fact = MIN2(len_fact, 10.0f);
1350 
1351  mul_v2_fl(no, ps->seam_bleed_px * len_fact);
1352 
1353  add_v2_v2v2(seam_data->seam_puvs[i], puv[fidx[i]], no);
1354 
1355  mul_v2_v2v2(seam_uvs[i], seam_data->seam_puvs[i], ibuf_inv);
1356  }
1357 
1358  /* Handle convergent normals (can self-intersect). */
1359  if ((ang[0] + ang[1]) < M_PI) {
1360  if (isect_seg_seg_v2_simple(orig_uv[fidx[0]], seam_uvs[0], orig_uv[fidx[1]], seam_uvs[1])) {
1361  float isect_co[2];
1362 
1364  orig_uv[fidx[0]], seam_uvs[0], orig_uv[fidx[1]], seam_uvs[1], isect_co);
1365 
1366  copy_v2_v2(seam_uvs[0], isect_co);
1367  copy_v2_v2(seam_uvs[1], isect_co);
1368  }
1369  }
1370  }
1371 }
1372 
1374  MemArena *arena,
1375  const int tri_index,
1376  const int fidx1,
1377  const int ibuf_x,
1378  const int ibuf_y)
1379 {
1380  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
1381  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
1382  const int fidx[2] = {fidx1, ((fidx1 + 1) % 3)};
1383  float vec[2];
1384 
1385  VertSeam *vseam = BLI_memarena_alloc(arena, sizeof(VertSeam[2]));
1386 
1387  vseam->prev = NULL;
1388  vseam->next = NULL;
1389 
1390  vseam->tri = tri_index;
1391  vseam->loop = lt->tri[fidx[0]];
1392 
1393  sub_v2_v2v2(vec, lt_tri_uv[fidx[1]], lt_tri_uv[fidx[0]]);
1394  vec[0] *= ibuf_x;
1395  vec[1] *= ibuf_y;
1396  vseam->angle = atan2f(vec[1], vec[0]);
1397 
1398  /* If face windings are not initialized, something must be wrong. */
1399  BLI_assert((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) != 0);
1400  vseam->normal_cw = (ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_CW);
1401 
1402  copy_v2_v2(vseam->uv, lt_tri_uv[fidx[0]]);
1403 
1404  vseam[1] = vseam[0];
1405  vseam[1].angle += vseam[1].angle > 0.0f ? -M_PI : M_PI;
1406  vseam[1].normal_cw = !vseam[1].normal_cw;
1407  copy_v2_v2(vseam[1].uv, lt_tri_uv[fidx[1]]);
1408 
1409  for (uint i = 0; i < 2; i++) {
1410  uint vert = ps->mloop_eval[lt->tri[fidx[i]]].v;
1411  ListBase *list = &ps->vertSeams[vert];
1412  VertSeam *item = list->first;
1413 
1414  while (item && item->angle < vseam[i].angle) {
1415  item = item->next;
1416  }
1417 
1418  BLI_insertlinkbefore(list, item, &vseam[i]);
1419  }
1420 }
1421 
1429  MemArena *arena,
1430  const int tri_index,
1431  const uint vert_index,
1432  bool init_all,
1433  const int ibuf_x,
1434  const int ibuf_y)
1435 {
1436  /* vars for the other face, we also set its flag */
1437  int other_face, other_fidx;
1438  /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
1439  int fidx[2] = {2, 0};
1440  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
1441  LinkNode *node;
1442 
1443  /* initialize face winding if needed */
1444  if ((ps->faceWindingFlags[tri_index] & PROJ_FACE_WINDING_INIT) == 0) {
1445  project_face_winding_init(ps, tri_index);
1446  }
1447 
1448  do {
1449  if (init_all || (ps->mloop_eval[lt->tri[fidx[0]]].v == vert_index) ||
1450  (ps->mloop_eval[lt->tri[fidx[1]]].v == vert_index)) {
1451  if ((ps->faceSeamFlags[tri_index] &
1452  (PROJ_FACE_SEAM0 << fidx[0] | PROJ_FACE_NOSEAM0 << fidx[0])) == 0) {
1453  if (check_seam(ps, tri_index, fidx[0], fidx[1], &other_face, &other_fidx)) {
1454  ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM0 << fidx[0];
1455  insert_seam_vert_array(ps, arena, tri_index, fidx[0], ibuf_x, ibuf_y);
1456 
1457  if (other_face != -1) {
1458  /* Check if the other seam is already set.
1459  * We don't want to insert it in the list twice. */
1460  if ((ps->faceSeamFlags[other_face] & (PROJ_FACE_SEAM0 << other_fidx)) == 0) {
1461  ps->faceSeamFlags[other_face] |= PROJ_FACE_SEAM0 << other_fidx;
1462  insert_seam_vert_array(ps, arena, other_face, other_fidx, ibuf_x, ibuf_y);
1463  }
1464  }
1465  }
1466  else {
1467  ps->faceSeamFlags[tri_index] |= PROJ_FACE_NOSEAM0 << fidx[0];
1468  ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM_INIT0 << fidx[0];
1469 
1470  if (other_face != -1) {
1471  /* second 4 bits for disabled */
1472  ps->faceSeamFlags[other_face] |= PROJ_FACE_NOSEAM0 << other_fidx;
1473  ps->faceSeamFlags[other_face] |= PROJ_FACE_SEAM_INIT0 << other_fidx;
1474  }
1475  }
1476  }
1477  }
1478 
1479  fidx[1] = fidx[0];
1480  } while (fidx[0]--);
1481 
1482  if (init_all) {
1483  char checked_verts = 0;
1484 
1485  fidx[0] = 2;
1486  fidx[1] = 0;
1487 
1488  do {
1489  if ((ps->faceSeamFlags[tri_index] & (PROJ_FACE_SEAM_INIT0 << fidx[0])) == 0) {
1490  for (uint i = 0; i < 2; i++) {
1491  uint vert;
1492 
1493  if ((checked_verts & (1 << fidx[i])) != 0) {
1494  continue;
1495  }
1496 
1497  vert = ps->mloop_eval[lt->tri[fidx[i]]].v;
1498 
1499  for (node = ps->vertFaces[vert]; node; node = node->next) {
1500  const int tri = POINTER_AS_INT(node->link);
1501 
1502  project_face_seams_init(ps, arena, tri, vert, false, ibuf_x, ibuf_y);
1503  }
1504 
1505  checked_verts |= 1 << fidx[i];
1506  }
1507 
1508  ps->faceSeamFlags[tri_index] |= PROJ_FACE_SEAM_INIT0 << fidx[0];
1509  }
1510 
1511  fidx[1] = fidx[0];
1512  } while (fidx[0]--);
1513  }
1514 }
1515 #endif // PROJ_DEBUG_NOSEAMBLEED
1516 
1517 /* Converts a UV location to a 3D screen-space location
1518  * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo
1519  *
1520  * This is used for finding a pixels location in screen-space for painting */
1521 static void screen_px_from_ortho(const float uv[2],
1522  const float v1co[3],
1523  const float v2co[3],
1524  const float v3co[3], /* Screenspace coords */
1525  const float uv1co[2],
1526  const float uv2co[2],
1527  const float uv3co[2],
1528  float pixelScreenCo[4],
1529  float w[3])
1530 {
1531  barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
1532  interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
1533 }
1534 
1535 /* same as screen_px_from_ortho except we
1536  * do perspective correction on the pixel coordinate */
1537 static void screen_px_from_persp(const float uv[2],
1538  const float v1co[4],
1539  const float v2co[4],
1540  const float v3co[4], /* screen-space coords */
1541  const float uv1co[2],
1542  const float uv2co[2],
1543  const float uv3co[2],
1544  float pixelScreenCo[4],
1545  float w[3])
1546 {
1547  float w_int[3];
1548  float wtot_inv, wtot;
1549  barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
1550 
1551  /* re-weight from the 4th coord of each screen vert */
1552  w_int[0] = w[0] * v1co[3];
1553  w_int[1] = w[1] * v2co[3];
1554  w_int[2] = w[2] * v3co[3];
1555 
1556  wtot = w_int[0] + w_int[1] + w_int[2];
1557 
1558  if (wtot > 0.0f) {
1559  wtot_inv = 1.0f / wtot;
1560  w_int[0] *= wtot_inv;
1561  w_int[1] *= wtot_inv;
1562  w_int[2] *= wtot_inv;
1563  }
1564  else {
1565  /* Dummy values for zero area face. */
1566  w[0] = w[1] = w[2] = w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f;
1567  }
1568  /* done re-weighting */
1569 
1570  /* do interpolation based on projected weight */
1571  interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w_int);
1572 }
1573 
1582 static void screen_px_to_vector_persp(int winx,
1583  int winy,
1584  const float projmat_inv[4][4],
1585  const float view_pos[3],
1586  const float co_px[2],
1587  float r_dir[3])
1588 {
1589  r_dir[0] = 2.0f * (co_px[0] / winx) - 1.0f;
1590  r_dir[1] = 2.0f * (co_px[1] / winy) - 1.0f;
1591  r_dir[2] = -0.5f;
1592  mul_project_m4_v3((float(*)[4])projmat_inv, r_dir);
1593  sub_v3_v3(r_dir, view_pos);
1594 }
1595 
1605  const float p[2],
1606  const float v1[3],
1607  const float v2[3])
1608 {
1609  const float zero[3] = {0};
1610  float v1_proj[3], v2_proj[3];
1611  float dir[3];
1612 
1613  screen_px_to_vector_persp(ps->winx, ps->winy, ps->projectMatInv, ps->viewPos, p, dir);
1614 
1615  sub_v3_v3v3(v1_proj, v1, ps->viewPos);
1616  sub_v3_v3v3(v2_proj, v2, ps->viewPos);
1617 
1618  project_plane_v3_v3v3(v1_proj, v1_proj, dir);
1619  project_plane_v3_v3v3(v2_proj, v2_proj, dir);
1620 
1621  return line_point_factor_v2(zero, v1_proj, v2_proj);
1622 }
1623 
1624 static void project_face_pixel(const float *lt_tri_uv[3],
1625  ImBuf *ibuf_other,
1626  const float w[3],
1627  uchar rgba_ub[4],
1628  float rgba_f[4])
1629 {
1630  float uv_other[2], x, y;
1631 
1632  interp_v2_v2v2v2(uv_other, UNPACK3(lt_tri_uv), w);
1633 
1634  /* use */
1635  uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
1636 
1637  if (ibuf_other->rect_float) { /* from float to float */
1638  bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y);
1639  }
1640  else { /* from char to float */
1641  bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y);
1642  }
1643 }
1644 
1645 /* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */
1647  const int tri_index,
1648  const float w[3])
1649 {
1650  float mask;
1651 
1652  /* Image Mask */
1653  if (ps->do_layer_stencil) {
1654  /* another UV maps image is masking this one's */
1655  ImBuf *ibuf_other;
1656  Image *other_tpage = ps->stencil_ima;
1657 
1658  if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
1659  const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
1660  const float *lt_other_tri_uv[3] = {ps->mloopuv_stencil_eval[lt_other->tri[0]].uv,
1661  ps->mloopuv_stencil_eval[lt_other->tri[1]].uv,
1662  ps->mloopuv_stencil_eval[lt_other->tri[2]].uv};
1663 
1664  /* #BKE_image_acquire_ibuf - TODO: this may be slow. */
1665  uchar rgba_ub[4];
1666  float rgba_f[4];
1667 
1668  project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
1669 
1670  if (ibuf_other->rect_float) { /* from float to float */
1671  mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) * (1.0f / 3.0f)) * rgba_f[3];
1672  }
1673  else { /* from char to float */
1674  mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) * (1.0f / (255.0f * 3.0f))) *
1675  (rgba_ub[3] * (1.0f / 255.0f));
1676  }
1677 
1678  BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
1679 
1680  if (!ps->do_layer_stencil_inv) {
1681  /* matching the gimps layer mask black/white rules, white==full opacity */
1682  mask = (1.0f - mask);
1683  }
1684 
1685  if (mask == 0.0f) {
1686  return 0.0f;
1687  }
1688  }
1689  else {
1690  return 0.0f;
1691  }
1692  }
1693  else {
1694  mask = 1.0f;
1695  }
1696 
1697  if (ps->do_mask_cavity) {
1698  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
1699  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
1700  float ca1, ca2, ca3, ca_mask;
1701  ca1 = ps->cavities[lt_vtri[0]];
1702  ca2 = ps->cavities[lt_vtri[1]];
1703  ca3 = ps->cavities[lt_vtri[2]];
1704 
1705  ca_mask = w[0] * ca1 + w[1] * ca2 + w[2] * ca3;
1706  ca_mask = BKE_curvemapping_evaluateF(ps->cavity_curve, 0, ca_mask);
1707  CLAMP(ca_mask, 0.0f, 1.0f);
1708  mask *= ca_mask;
1709  }
1710 
1711  /* calculate mask */
1712  if (ps->do_mask_normal) {
1713  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
1714  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
1715  const MPoly *mp = &ps->mpoly_eval[lt->poly];
1716  float no[3], angle_cos;
1717 
1718  if (mp->flag & ME_SMOOTH) {
1719  const float *no1, *no2, *no3;
1720  no1 = ps->vert_normals[lt_vtri[0]];
1721  no2 = ps->vert_normals[lt_vtri[1]];
1722  no3 = ps->vert_normals[lt_vtri[2]];
1723 
1724  no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
1725  no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
1726  no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2];
1727  normalize_v3(no);
1728  }
1729  else {
1730  /* In case the normalizing per pixel isn't optimal,
1731  * we could cache or access from evaluated mesh. */
1732  normal_tri_v3(no,
1733  ps->mvert_eval[lt_vtri[0]].co,
1734  ps->mvert_eval[lt_vtri[1]].co,
1735  ps->mvert_eval[lt_vtri[2]].co);
1736  }
1737 
1738  if (UNLIKELY(ps->is_flip_object)) {
1739  negate_v3(no);
1740  }
1741 
1742  /* now we can use the normal as a mask */
1743  if (ps->is_ortho) {
1744  angle_cos = dot_v3v3(ps->viewDir, no);
1745  }
1746  else {
1747  /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
1748  float viewDirPersp[3];
1749  const float *co1, *co2, *co3;
1750  co1 = ps->mvert_eval[lt_vtri[0]].co;
1751  co2 = ps->mvert_eval[lt_vtri[1]].co;
1752  co3 = ps->mvert_eval[lt_vtri[2]].co;
1753 
1754  /* Get the direction from the viewPoint to the pixel and normalize */
1755  viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
1756  viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
1757  viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
1758  normalize_v3(viewDirPersp);
1759  if (UNLIKELY(ps->is_flip_object)) {
1760  negate_v3(viewDirPersp);
1761  }
1762 
1763  angle_cos = dot_v3v3(viewDirPersp, no);
1764  }
1765 
1766  /* If back-face culling is disabled, allow painting on back faces. */
1767  if (!ps->do_backfacecull) {
1768  angle_cos = fabsf(angle_cos);
1769  }
1770 
1771  if (angle_cos <= ps->normal_angle__cos) {
1772  /* Outsize the normal limit. */
1773  return 0.0f;
1774  }
1775  if (angle_cos < ps->normal_angle_inner__cos) {
1776  mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
1777  } /* otherwise no mask normal is needed, we're within the limit */
1778  }
1779 
1780  /* This only works when the opacity doesn't change while painting, stylus pressure messes with
1781  * this so don't use it. */
1782  // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush);
1783 
1784  return mask;
1785 }
1786 
1787 static int project_paint_pixel_sizeof(const short tool)
1788 {
1789  if (ELEM(tool, PAINT_TOOL_CLONE, PAINT_TOOL_SMEAR)) {
1790  return sizeof(ProjPixelClone);
1791  }
1792  return sizeof(ProjPixel);
1793 }
1794 
1795 static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
1796 {
1797  ProjPaintImage *pjIma = tinf->pjima;
1798  int tile_index = tx + ty * tinf->tile_width;
1799  bool generate_tile = false;
1800 
1801  /* double check lock to avoid locking */
1802  if (UNLIKELY(!pjIma->undoRect[tile_index])) {
1803  if (tinf->lock) {
1804  BLI_spin_lock(tinf->lock);
1805  }
1806  if (LIKELY(!pjIma->undoRect[tile_index])) {
1807  pjIma->undoRect[tile_index] = TILE_PENDING;
1808  generate_tile = true;
1809  }
1810  if (tinf->lock) {
1811  BLI_spin_unlock(tinf->lock);
1812  }
1813  }
1814 
1815  if (generate_tile) {
1816  struct PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
1817  volatile void *undorect;
1818  if (tinf->masked) {
1819  undorect = ED_image_paint_tile_push(undo_tiles,
1820  pjIma->ima,
1821  pjIma->ibuf,
1822  tinf->tmpibuf,
1823  &pjIma->iuser,
1824  tx,
1825  ty,
1826  &pjIma->maskRect[tile_index],
1827  &pjIma->valid[tile_index],
1828  true,
1829  false);
1830  }
1831  else {
1832  undorect = ED_image_paint_tile_push(undo_tiles,
1833  pjIma->ima,
1834  pjIma->ibuf,
1835  tinf->tmpibuf,
1836  &pjIma->iuser,
1837  tx,
1838  ty,
1839  NULL,
1840  &pjIma->valid[tile_index],
1841  true,
1842  false);
1843  }
1844 
1845  BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf);
1846  /* tile ready, publish */
1847  if (tinf->lock) {
1848  BLI_spin_lock(tinf->lock);
1849  }
1850  pjIma->undoRect[tile_index] = undorect;
1851  if (tinf->lock) {
1852  BLI_spin_unlock(tinf->lock);
1853  }
1854  }
1855 
1856  return tile_index;
1857 }
1858 
1859 /* run this function when we know a bucket's, face's pixel can be initialized,
1860  * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
1862  MemArena *arena,
1863  const TileInfo *tinf,
1864  int x_px,
1865  int y_px,
1866  const float mask,
1867  const int tri_index,
1868  const float pixelScreenCo[4],
1869  const float world_spaceCo[3],
1870  const float w[3])
1871 {
1872  ProjPixel *projPixel;
1873  int x_tile, y_tile;
1874  int x_round, y_round;
1875  int tile_offset;
1876  /* Volatile is important here to ensure pending check is not optimized away by compiler. */
1877  volatile int tile_index;
1878 
1879  ProjPaintImage *projima = tinf->pjima;
1880  ImBuf *ibuf = projima->ibuf;
1881  /* wrap pixel location */
1882 
1883  x_px = mod_i(x_px, ibuf->x);
1884  y_px = mod_i(y_px, ibuf->y);
1885 
1887  projPixel = BLI_memarena_alloc(arena, ps->pixel_sizeof);
1888 
1889  /* calculate the undo tile offset of the pixel, used to store the original
1890  * pixel color and accumulated mask if any */
1891  x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS;
1892  y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS;
1893 
1894  x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE;
1895  y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE;
1896  // memset(projPixel, 0, size);
1897 
1898  tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE;
1899  tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
1900 
1901  /* other thread may be initializing the tile so wait here */
1902  while (projima->undoRect[tile_index] == TILE_PENDING) {
1903  /* pass */
1904  }
1905 
1909 
1910  projPixel->valid = projima->valid[tile_index];
1911 
1912  if (ibuf->rect_float) {
1913  projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
1914  projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
1915  zero_v4(projPixel->newColor.f);
1916  }
1917  else {
1918  projPixel->pixel.ch_pt = (uchar *)(ibuf->rect + (x_px + y_px * ibuf->x));
1919  projPixel->origColor.uint_pt = (uint *)projima->undoRect[tile_index] + tile_offset;
1920  projPixel->newColor.uint = 0;
1921  }
1922 
1923  /* Screen-space unclamped, we could keep its z and w values but don't need them at the moment. */
1924  if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
1925  copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
1926  }
1927 
1928  copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
1929 
1930  projPixel->x_px = x_px;
1931  projPixel->y_px = y_px;
1932 
1933  projPixel->mask = (ushort)(mask * 65535);
1934  if (ps->do_masking) {
1935  projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
1936  }
1937  else {
1938  projPixel->mask_accum = NULL;
1939  }
1940 
1941  /* which bounding box cell are we in?, needed for undo */
1942  projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
1943  ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) *
1945 
1946  /* done with view3d_project_float inline */
1947  if (ps->tool == PAINT_TOOL_CLONE) {
1948  if (ps->poly_to_loop_uv_clone) {
1949  ImBuf *ibuf_other;
1950  Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
1951 
1952  if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
1953  const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
1954  const float *lt_other_tri_uv[3] = {
1955  PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, lt_other)};
1956 
1957  /* #BKE_image_acquire_ibuf - TODO: this may be slow. */
1958 
1959  if (ibuf->rect_float) {
1960  if (ibuf_other->rect_float) { /* from float to float */
1962  lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
1963  }
1964  else { /* from char to float */
1965  uchar rgba_ub[4];
1966  float rgba[4];
1967  project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
1968  if (ps->use_colormanagement) {
1969  srgb_to_linearrgb_uchar4(rgba, rgba_ub);
1970  }
1971  else {
1972  rgba_uchar_to_float(rgba, rgba_ub);
1973  }
1974  straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
1975  }
1976  }
1977  else {
1978  if (ibuf_other->rect_float) { /* float to char */
1979  float rgba[4];
1980  project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
1982  if (ps->use_colormanagement) {
1983  linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
1984  }
1985  else {
1986  rgb_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
1987  }
1988  ((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
1989  }
1990  else { /* char to char */
1992  lt_other_tri_uv, ibuf_other, w, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
1993  }
1994  }
1995 
1996  BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
1997  }
1998  else {
1999  if (ibuf->rect_float) {
2000  ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
2001  }
2002  else {
2003  ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
2004  }
2005  }
2006  }
2007  else {
2008  float co[2];
2009  sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
2010 
2011  /* no need to initialize the bucket, we're only checking buckets faces and for this
2012  * the faces are already initialized in project_paint_delayed_face_init(...) */
2013  if (ibuf->rect_float) {
2014  if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
2015  /* zero alpha - ignore */
2016  ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
2017  }
2018  }
2019  else {
2020  if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
2021  /* zero alpha - ignore */
2022  ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
2023  }
2024  }
2025  }
2026  }
2027 
2028 #ifdef PROJ_DEBUG_PAINT
2029  if (ibuf->rect_float) {
2030  projPixel->pixel.f_pt[0] = 0;
2031  }
2032  else {
2033  projPixel->pixel.ch_pt[0] = 0;
2034  }
2035 #endif
2036  /* pointer arithmetic */
2037  projPixel->image_index = projima - ps->projImages;
2038 
2039  return projPixel;
2040 }
2041 
2042 static bool line_clip_rect2f(const rctf *cliprect,
2043  const rctf *rect,
2044  const float l1[2],
2045  const float l2[2],
2046  float l1_clip[2],
2047  float l2_clip[2])
2048 {
2049  /* first account for horizontal, then vertical lines */
2050  /* Horizontal. */
2051  if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
2052  /* is the line out of range on its Y axis? */
2053  if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
2054  return false;
2055  }
2056  /* line is out of range on its X axis */
2057  if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
2058  return false;
2059  }
2060 
2061  /* This is a single point (or close to). */
2062  if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
2063  if (BLI_rctf_isect_pt_v(rect, l1)) {
2064  copy_v2_v2(l1_clip, l1);
2065  copy_v2_v2(l2_clip, l2);
2066  return true;
2067  }
2068  return false;
2069  }
2070 
2071  copy_v2_v2(l1_clip, l1);
2072  copy_v2_v2(l2_clip, l2);
2073  CLAMP(l1_clip[0], rect->xmin, rect->xmax);
2074  CLAMP(l2_clip[0], rect->xmin, rect->xmax);
2075  return true;
2076  }
2077  if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
2078  /* is the line out of range on its X axis? */
2079  if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
2080  return false;
2081  }
2082 
2083  /* line is out of range on its Y axis */
2084  if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
2085  return false;
2086  }
2087 
2088  /* This is a single point (or close to). */
2089  if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
2090  if (BLI_rctf_isect_pt_v(rect, l1)) {
2091  copy_v2_v2(l1_clip, l1);
2092  copy_v2_v2(l2_clip, l2);
2093  return true;
2094  }
2095  return false;
2096  }
2097 
2098  copy_v2_v2(l1_clip, l1);
2099  copy_v2_v2(l2_clip, l2);
2100  CLAMP(l1_clip[1], rect->ymin, rect->ymax);
2101  CLAMP(l2_clip[1], rect->ymin, rect->ymax);
2102  return true;
2103  }
2104 
2105  float isect;
2106  short ok1 = 0;
2107  short ok2 = 0;
2108 
2109  /* Done with vertical lines */
2110 
2111  /* are either of the points inside the rectangle ? */
2112  if (BLI_rctf_isect_pt_v(rect, l1)) {
2113  copy_v2_v2(l1_clip, l1);
2114  ok1 = 1;
2115  }
2116 
2117  if (BLI_rctf_isect_pt_v(rect, l2)) {
2118  copy_v2_v2(l2_clip, l2);
2119  ok2 = 1;
2120  }
2121 
2122  /* line inside rect */
2123  if (ok1 && ok2) {
2124  return true;
2125  }
2126 
2127  /* top/bottom */
2128  if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) &&
2129  (isect <= cliprect->xmax)) {
2130  if (l1[1] < l2[1]) { /* line 1 is outside */
2131  l1_clip[0] = isect;
2132  l1_clip[1] = rect->ymin;
2133  ok1 = 1;
2134  }
2135  else {
2136  l2_clip[0] = isect;
2137  l2_clip[1] = rect->ymin;
2138  ok2 = 2;
2139  }
2140  }
2141 
2142  if (ok1 && ok2) {
2143  return true;
2144  }
2145 
2146  if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) &&
2147  (isect <= cliprect->xmax)) {
2148  if (l1[1] > l2[1]) { /* line 1 is outside */
2149  l1_clip[0] = isect;
2150  l1_clip[1] = rect->ymax;
2151  ok1 = 1;
2152  }
2153  else {
2154  l2_clip[0] = isect;
2155  l2_clip[1] = rect->ymax;
2156  ok2 = 2;
2157  }
2158  }
2159 
2160  if (ok1 && ok2) {
2161  return true;
2162  }
2163 
2164  /* left/right */
2165  if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) &&
2166  (isect <= cliprect->ymax)) {
2167  if (l1[0] < l2[0]) { /* line 1 is outside */
2168  l1_clip[0] = rect->xmin;
2169  l1_clip[1] = isect;
2170  ok1 = 1;
2171  }
2172  else {
2173  l2_clip[0] = rect->xmin;
2174  l2_clip[1] = isect;
2175  ok2 = 2;
2176  }
2177  }
2178 
2179  if (ok1 && ok2) {
2180  return true;
2181  }
2182 
2183  if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) &&
2184  (isect <= cliprect->ymax)) {
2185  if (l1[0] > l2[0]) { /* line 1 is outside */
2186  l1_clip[0] = rect->xmax;
2187  l1_clip[1] = isect;
2188  ok1 = 1;
2189  }
2190  else {
2191  l2_clip[0] = rect->xmax;
2192  l2_clip[1] = isect;
2193  ok2 = 2;
2194  }
2195  }
2196 
2197  if (ok1 && ok2) {
2198  return true;
2199  }
2200  return false;
2201 }
2202 
2208 #ifndef PROJ_DEBUG_NOSEAMBLEED
2209 
2210 static void scale_tri(float insetCos[3][3], const float *origCos[3], const float inset)
2211 {
2212  float cent[3];
2213  cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) * (1.0f / 3.0f);
2214  cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) * (1.0f / 3.0f);
2215  cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) * (1.0f / 3.0f);
2216 
2217  sub_v3_v3v3(insetCos[0], origCos[0], cent);
2218  sub_v3_v3v3(insetCos[1], origCos[1], cent);
2219  sub_v3_v3v3(insetCos[2], origCos[2], cent);
2220 
2221  mul_v3_fl(insetCos[0], inset);
2222  mul_v3_fl(insetCos[1], inset);
2223  mul_v3_fl(insetCos[2], inset);
2224 
2225  add_v3_v3(insetCos[0], cent);
2226  add_v3_v3(insetCos[1], cent);
2227  add_v3_v3(insetCos[2], cent);
2228 }
2229 #endif // PROJ_DEBUG_NOSEAMBLEED
2230 
2231 static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const float v2_2)
2232 {
2233  float x, y;
2234 
2235  x = v1[0] - v2_1;
2236  y = v1[1] - v2_2;
2237  return x * x + y * y;
2238 }
2239 
2246 static bool project_bucket_isect_circle(const float cent[2],
2247  const float radius_squared,
2248  const rctf *bucket_bounds)
2249 {
2250 
2251  /* Would normally to a simple intersection test,
2252  * however we know the bounds of these 2 already intersect so we only need to test
2253  * if the center is inside the vertical or horizontal bounds on either axis,
2254  * this is even less work than an intersection test.
2255  */
2256 #if 0
2257  if (BLI_rctf_isect_pt_v(bucket_bounds, cent)) {
2258  return true;
2259  }
2260 #endif
2261 
2262  if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
2263  (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1])) {
2264  return true;
2265  }
2266 
2267  /* out of bounds left */
2268  if (cent[0] < bucket_bounds->xmin) {
2269  /* lower left out of radius test */
2270  if (cent[1] < bucket_bounds->ymin) {
2271  return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) <
2272  radius_squared) ?
2273  true :
2274  false;
2275  }
2276  /* top left test */
2277  if (cent[1] > bucket_bounds->ymax) {
2278  return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) <
2279  radius_squared) ?
2280  true :
2281  false;
2282  }
2283  }
2284  else if (cent[0] > bucket_bounds->xmax) {
2285  /* lower right out of radius test */
2286  if (cent[1] < bucket_bounds->ymin) {
2287  return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) <
2288  radius_squared) ?
2289  true :
2290  false;
2291  }
2292  /* top right test */
2293  if (cent[1] > bucket_bounds->ymax) {
2294  return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) <
2295  radius_squared) ?
2296  true :
2297  false;
2298  }
2299  }
2300 
2301  return false;
2302 }
2303 
2304 /* Note for #rect_to_uvspace_ortho() and #rect_to_uvspace_persp()
2305  * in ortho view this function gives good results when bucket_bounds are outside the triangle
2306  * however in some cases, perspective view will mess up with faces
2307  * that have minimal screen-space area (viewed from the side).
2308  *
2309  * for this reason its not reliable in this case so we'll use the Simple Barycentric'
2310  * functions that only account for points inside the triangle.
2311  * however switching back to this for ortho is always an option. */
2312 
2313 static void rect_to_uvspace_ortho(const rctf *bucket_bounds,
2314  const float *v1coSS,
2315  const float *v2coSS,
2316  const float *v3coSS,
2317  const float *uv1co,
2318  const float *uv2co,
2319  const float *uv3co,
2320  float bucket_bounds_uv[4][2],
2321  const int flip)
2322 {
2323  float uv[2];
2324  float w[3];
2325 
2326  /* get the UV space bounding box */
2327  uv[0] = bucket_bounds->xmax;
2328  uv[1] = bucket_bounds->ymin;
2329  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2330  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
2331 
2332  // uv[0] = bucket_bounds->xmax; // set above
2333  uv[1] = bucket_bounds->ymax;
2334  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2335  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
2336 
2337  uv[0] = bucket_bounds->xmin;
2338  // uv[1] = bucket_bounds->ymax; // set above
2339  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2340  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
2341 
2342  // uv[0] = bucket_bounds->xmin; // set above
2343  uv[1] = bucket_bounds->ymin;
2344  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2345  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
2346 }
2347 
2348 /* same as above but use barycentric_weights_v2_persp */
2349 static void rect_to_uvspace_persp(const rctf *bucket_bounds,
2350  const float *v1coSS,
2351  const float *v2coSS,
2352  const float *v3coSS,
2353  const float *uv1co,
2354  const float *uv2co,
2355  const float *uv3co,
2356  float bucket_bounds_uv[4][2],
2357  const int flip)
2358 {
2359  float uv[2];
2360  float w[3];
2361 
2362  /* get the UV space bounding box */
2363  uv[0] = bucket_bounds->xmax;
2364  uv[1] = bucket_bounds->ymin;
2365  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2366  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
2367 
2368  // uv[0] = bucket_bounds->xmax; // set above
2369  uv[1] = bucket_bounds->ymax;
2370  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2371  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
2372 
2373  uv[0] = bucket_bounds->xmin;
2374  // uv[1] = bucket_bounds->ymax; // set above
2375  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2376  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
2377 
2378  // uv[0] = bucket_bounds->xmin; // set above
2379  uv[1] = bucket_bounds->ymin;
2380  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2381  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
2382 }
2383 
2384 /* This works as we need it to but we can save a few steps and not use it */
2385 
2386 #if 0
2387 static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2])
2388 {
2389  float v1[2], v2[2];
2390 
2391  v1[0] = p1[0] - p2[0];
2392  v1[1] = p1[1] - p2[1];
2393  v2[0] = p3[0] - p2[0];
2394  v2[1] = p3[1] - p2[1];
2395 
2396  return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
2397 }
2398 #endif
2399 
2400 #define ISECT_1 (1)
2401 #define ISECT_2 (1 << 1)
2402 #define ISECT_3 (1 << 2)
2403 #define ISECT_4 (1 << 3)
2404 #define ISECT_ALL3 ((1 << 3) - 1)
2405 #define ISECT_ALL4 ((1 << 4) - 1)
2406 
2407 /* limit must be a fraction over 1.0f */
2408 static bool IsectPT2Df_limit(
2409  const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float limit)
2410 {
2411  return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) /
2412  (area_tri_v2(v1, v2, v3))) < limit;
2413 }
2414 
2419 static int float_z_sort_flip(const void *p1, const void *p2)
2420 {
2421  return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
2422 }
2423 
2424 static int float_z_sort(const void *p1, const void *p2)
2425 {
2426  return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
2427 }
2428 
2429 /* assumes one point is within the rectangle */
2430 static bool line_rect_clip(const rctf *rect,
2431  const float l1[4],
2432  const float l2[4],
2433  const float uv1[2],
2434  const float uv2[2],
2435  float uv[2],
2436  bool is_ortho)
2437 {
2438  float min = FLT_MAX, tmp;
2439  float xlen = l2[0] - l1[0];
2440  float ylen = l2[1] - l1[1];
2441 
2442  /* 0.1 might seem too much, but remember, this is pixels! */
2443  if (xlen > 0.1f) {
2444  if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) <= 0) {
2445  tmp = rect->xmin;
2446  min = min_ff((tmp - l1[0]) / xlen, min);
2447  }
2448  else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) {
2449  tmp = rect->xmax;
2450  min = min_ff((tmp - l1[0]) / xlen, min);
2451  }
2452  }
2453 
2454  if (ylen > 0.1f) {
2455  if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) <= 0) {
2456  tmp = rect->ymin;
2457  min = min_ff((tmp - l1[1]) / ylen, min);
2458  }
2459  else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) {
2460  tmp = rect->ymax;
2461  min = min_ff((tmp - l1[1]) / ylen, min);
2462  }
2463  }
2464 
2465  if (min == FLT_MAX) {
2466  return false;
2467  }
2468 
2469  tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
2470 
2471  uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0]));
2472  uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1]));
2473 
2474  return true;
2475 }
2476 
2477 static void project_bucket_clip_face(const bool is_ortho,
2478  const bool is_flip_object,
2479  const rctf *cliprect,
2480  const rctf *bucket_bounds,
2481  const float *v1coSS,
2482  const float *v2coSS,
2483  const float *v3coSS,
2484  const float *uv1co,
2485  const float *uv2co,
2486  const float *uv3co,
2487  float bucket_bounds_uv[8][2],
2488  int *tot,
2489  bool cull)
2490 {
2491  int inside_bucket_flag = 0;
2492  int inside_face_flag = 0;
2493  int flip;
2494  bool collinear = false;
2495 
2496  float bucket_bounds_ss[4][2];
2497 
2498  /* detect pathological case where face the three vertices are almost collinear in screen space.
2499  * mostly those will be culled but when flood filling or with
2500  * smooth shading it's a possibility */
2501  if (min_fff(dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS),
2502  dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS),
2503  dist_squared_to_line_v2(v3coSS, v1coSS, v2coSS)) < PROJ_PIXEL_TOLERANCE) {
2504  collinear = true;
2505  }
2506 
2507  /* get the UV space bounding box */
2508  inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
2509  inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
2510  inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
2511 
2512  if (inside_bucket_flag == ISECT_ALL3) {
2513  /* is_flip_object is used here because we use the face winding */
2514  flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
2515  (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
2516 
2517  /* All screen-space points are inside the bucket bounding box,
2518  * this means we don't need to clip and can simply return the UVs. */
2519  if (flip) { /* facing the back? */
2520  copy_v2_v2(bucket_bounds_uv[0], uv3co);
2521  copy_v2_v2(bucket_bounds_uv[1], uv2co);
2522  copy_v2_v2(bucket_bounds_uv[2], uv1co);
2523  }
2524  else {
2525  copy_v2_v2(bucket_bounds_uv[0], uv1co);
2526  copy_v2_v2(bucket_bounds_uv[1], uv2co);
2527  copy_v2_v2(bucket_bounds_uv[2], uv3co);
2528  }
2529 
2530  *tot = 3;
2531  return;
2532  }
2533  /* Handle pathological case here,
2534  * no need for further intersections below since triangle area is almost zero. */
2535  if (collinear) {
2536  int flag;
2537 
2538  (*tot) = 0;
2539 
2540  if (cull) {
2541  return;
2542  }
2543 
2544  if (inside_bucket_flag & ISECT_1) {
2545  copy_v2_v2(bucket_bounds_uv[*tot], uv1co);
2546  (*tot)++;
2547  }
2548 
2549  flag = inside_bucket_flag & (ISECT_1 | ISECT_2);
2550  if (flag && flag != (ISECT_1 | ISECT_2)) {
2551  if (line_rect_clip(
2552  bucket_bounds, v1coSS, v2coSS, uv1co, uv2co, bucket_bounds_uv[*tot], is_ortho)) {
2553  (*tot)++;
2554  }
2555  }
2556 
2557  if (inside_bucket_flag & ISECT_2) {
2558  copy_v2_v2(bucket_bounds_uv[*tot], uv2co);
2559  (*tot)++;
2560  }
2561 
2562  flag = inside_bucket_flag & (ISECT_2 | ISECT_3);
2563  if (flag && flag != (ISECT_2 | ISECT_3)) {
2564  if (line_rect_clip(
2565  bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho)) {
2566  (*tot)++;
2567  }
2568  }
2569 
2570  if (inside_bucket_flag & ISECT_3) {
2571  copy_v2_v2(bucket_bounds_uv[*tot], uv3co);
2572  (*tot)++;
2573  }
2574 
2575  flag = inside_bucket_flag & (ISECT_3 | ISECT_1);
2576  if (flag && flag != (ISECT_3 | ISECT_1)) {
2577  if (line_rect_clip(
2578  bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho)) {
2579  (*tot)++;
2580  }
2581  }
2582 
2583  if ((*tot) < 3) {
2584  /* no intersections to speak of, but more probable is that all face is just outside the
2585  * rectangle and culled due to float precision issues. Since above tests have failed,
2586  * just dump triangle as is for painting */
2587  *tot = 0;
2588  copy_v2_v2(bucket_bounds_uv[*tot], uv1co);
2589  (*tot)++;
2590  copy_v2_v2(bucket_bounds_uv[*tot], uv2co);
2591  (*tot)++;
2592  copy_v2_v2(bucket_bounds_uv[*tot], uv3co);
2593  (*tot)++;
2594  return;
2595  }
2596 
2597  return;
2598  }
2599 
2600  /* Get the UV space bounding box. */
2601  /* Use #IsectPT2Df_limit here so we catch points are touching the triangles edge
2602  * (or a small fraction over) */
2603  bucket_bounds_ss[0][0] = bucket_bounds->xmax;
2604  bucket_bounds_ss[0][1] = bucket_bounds->ymin;
2605  inside_face_flag |= (IsectPT2Df_limit(
2606  bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2607  ISECT_1 :
2608  0);
2609 
2610  bucket_bounds_ss[1][0] = bucket_bounds->xmax;
2611  bucket_bounds_ss[1][1] = bucket_bounds->ymax;
2612  inside_face_flag |= (IsectPT2Df_limit(
2613  bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2614  ISECT_2 :
2615  0);
2616 
2617  bucket_bounds_ss[2][0] = bucket_bounds->xmin;
2618  bucket_bounds_ss[2][1] = bucket_bounds->ymax;
2619  inside_face_flag |= (IsectPT2Df_limit(
2620  bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2621  ISECT_3 :
2622  0);
2623 
2624  bucket_bounds_ss[3][0] = bucket_bounds->xmin;
2625  bucket_bounds_ss[3][1] = bucket_bounds->ymin;
2626  inside_face_flag |= (IsectPT2Df_limit(
2627  bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2628  ISECT_4 :
2629  0);
2630 
2631  flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
2632  (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
2633 
2634  if (inside_face_flag == ISECT_ALL4) {
2635  /* Bucket is totally inside the screen-space face, we can safely use weights. */
2636 
2637  if (is_ortho) {
2639  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
2640  }
2641  else {
2643  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
2644  }
2645 
2646  *tot = 4;
2647  return;
2648  }
2649 
2650  {
2651  /* The Complicated Case!
2652  *
2653  * The 2 cases above are where the face is inside the bucket
2654  * or the bucket is inside the face.
2655  *
2656  * we need to make a convex poly-line from the intersection between the screen-space face
2657  * and the bucket bounds.
2658  *
2659  * There are a number of ways this could be done, currently it just collects all
2660  * intersecting verts, and line intersections, then sorts them clockwise, this is
2661  * a lot easier than evaluating the geometry to do a correct clipping on both shapes.
2662  */
2663 
2664  /* Add a bunch of points, we know must make up the convex hull
2665  * which is the clipped rect and triangle */
2666 
2667  /* Maximum possible 6 intersections when using a rectangle and triangle */
2668 
2669  /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
2670  float isectVCosSS[8][3];
2671  float v1_clipSS[2], v2_clipSS[2];
2672  float w[3];
2673 
2674  /* calc center */
2675  float cent[2] = {0.0f, 0.0f};
2676  // float up[2] = {0.0f, 1.0f};
2677  bool doubles;
2678 
2679  (*tot) = 0;
2680 
2681  if (inside_face_flag & ISECT_1) {
2682  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]);
2683  (*tot)++;
2684  }
2685  if (inside_face_flag & ISECT_2) {
2686  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]);
2687  (*tot)++;
2688  }
2689  if (inside_face_flag & ISECT_3) {
2690  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]);
2691  (*tot)++;
2692  }
2693  if (inside_face_flag & ISECT_4) {
2694  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]);
2695  (*tot)++;
2696  }
2697 
2698  if (inside_bucket_flag & ISECT_1) {
2699  copy_v2_v2(isectVCosSS[*tot], v1coSS);
2700  (*tot)++;
2701  }
2702  if (inside_bucket_flag & ISECT_2) {
2703  copy_v2_v2(isectVCosSS[*tot], v2coSS);
2704  (*tot)++;
2705  }
2706  if (inside_bucket_flag & ISECT_3) {
2707  copy_v2_v2(isectVCosSS[*tot], v3coSS);
2708  (*tot)++;
2709  }
2710 
2711  if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
2712  if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
2713  if ((inside_bucket_flag & ISECT_1) == 0) {
2714  copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
2715  (*tot)++;
2716  }
2717  if ((inside_bucket_flag & ISECT_2) == 0) {
2718  copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
2719  (*tot)++;
2720  }
2721  }
2722  }
2723 
2724  if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
2725  if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
2726  if ((inside_bucket_flag & ISECT_2) == 0) {
2727  copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
2728  (*tot)++;
2729  }
2730  if ((inside_bucket_flag & ISECT_3) == 0) {
2731  copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
2732  (*tot)++;
2733  }
2734  }
2735  }
2736 
2737  if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
2738  if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
2739  if ((inside_bucket_flag & ISECT_3) == 0) {
2740  copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
2741  (*tot)++;
2742  }
2743  if ((inside_bucket_flag & ISECT_1) == 0) {
2744  copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
2745  (*tot)++;
2746  }
2747  }
2748  }
2749 
2750  if ((*tot) < 3) { /* no intersections to speak of */
2751  *tot = 0;
2752  return;
2753  }
2754 
2755  /* now we have all points we need, collect their angles and sort them clockwise */
2756 
2757  for (int i = 0; i < (*tot); i++) {
2758  cent[0] += isectVCosSS[i][0];
2759  cent[1] += isectVCosSS[i][1];
2760  }
2761  cent[0] = cent[0] / (float)(*tot);
2762  cent[1] = cent[1] / (float)(*tot);
2763 
2764  /* Collect angles for every point around the center point */
2765 
2766 #if 0 /* uses a few more cycles than the above loop */
2767  for (int i = 0; i < (*tot); i++) {
2768  isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
2769  }
2770 #endif
2771 
2772  /* Abuse this var for the loop below */
2773  v1_clipSS[0] = cent[0];
2774  v1_clipSS[1] = cent[1] + 1.0f;
2775 
2776  for (int i = 0; i < (*tot); i++) {
2777  v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
2778  v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
2779  isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0],
2780  v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
2781  }
2782 
2783  if (flip) {
2784  qsort(isectVCosSS, *tot, sizeof(float[3]), float_z_sort_flip);
2785  }
2786  else {
2787  qsort(isectVCosSS, *tot, sizeof(float[3]), float_z_sort);
2788  }
2789 
2790  doubles = true;
2791  while (doubles == true) {
2792  doubles = false;
2793 
2794  for (int i = 0; i < (*tot); i++) {
2795  if (fabsf(isectVCosSS[(i + 1) % *tot][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE &&
2796  fabsf(isectVCosSS[(i + 1) % *tot][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE) {
2797  for (int j = i; j < (*tot) - 1; j++) {
2798  isectVCosSS[j][0] = isectVCosSS[j + 1][0];
2799  isectVCosSS[j][1] = isectVCosSS[j + 1][1];
2800  }
2801  /* keep looking for more doubles */
2802  doubles = true;
2803  (*tot)--;
2804  }
2805  }
2806 
2807  /* its possible there is only a few left after remove doubles */
2808  if ((*tot) < 3) {
2809  // printf("removed too many doubles B\n");
2810  *tot = 0;
2811  return;
2812  }
2813  }
2814 
2815  if (is_ortho) {
2816  for (int i = 0; i < (*tot); i++) {
2817  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
2818  interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
2819  }
2820  }
2821  else {
2822  for (int i = 0; i < (*tot); i++) {
2823  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
2824  interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
2825  }
2826  }
2827  }
2828 
2829 #ifdef PROJ_DEBUG_PRINT_CLIP
2830  /* include this at the bottom of the above function to debug the output */
2831 
2832  {
2833  /* If there are ever any problems, */
2834  float test_uv[4][2];
2835  int i;
2836  if (is_ortho) {
2838  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
2839  }
2840  else {
2842  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
2843  }
2844  printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ",
2845  test_uv[0][0],
2846  test_uv[0][1],
2847  test_uv[1][0],
2848  test_uv[1][1],
2849  test_uv[2][0],
2850  test_uv[2][1],
2851  test_uv[3][0],
2852  test_uv[3][1]);
2853 
2854  printf(" [(%f,%f), (%f,%f), (%f,%f)], ",
2855  uv1co[0],
2856  uv1co[1],
2857  uv2co[0],
2858  uv2co[1],
2859  uv3co[0],
2860  uv3co[1]);
2861 
2862  printf("[");
2863  for (int i = 0; i < (*tot); i++) {
2864  printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
2865  }
2866  printf("]),\\\n");
2867  }
2868 #endif
2869 }
2870 
2871 /*
2872  * # This script creates faces in a blender scene from printed data above.
2873  *
2874  * project_ls = [
2875  * ...(output from above block)...
2876  * ]
2877  *
2878  * from Blender import Scene, Mesh, Window, sys, Mathutils
2879  *
2880  * import bpy
2881  *
2882  * V = Mathutils.Vector
2883  *
2884  * def main():
2885  * sce = bpy.data.scenes.active
2886  *
2887  * for item in project_ls:
2888  * bb = item[0]
2889  * uv = item[1]
2890  * poly = item[2]
2891  *
2892  * me = bpy.data.meshes.new()
2893  * ob = sce.objects.new(me)
2894  *
2895  * me.verts.extend([V(bb[0]).xyz, V(bb[1]).xyz, V(bb[2]).xyz, V(bb[3]).xyz])
2896  * me.faces.extend([(0,1,2,3),])
2897  * me.verts.extend([V(uv[0]).xyz, V(uv[1]).xyz, V(uv[2]).xyz])
2898  * me.faces.extend([(4,5,6),])
2899  *
2900  * vs = [V(p).xyz for p in poly]
2901  * print len(vs)
2902  * l = len(me.verts)
2903  * me.verts.extend(vs)
2904  *
2905  * i = l
2906  * while i < len(me.verts):
2907  * ii = i + 1
2908  * if ii == len(me.verts):
2909  * ii = l
2910  * me.edges.extend([i, ii])
2911  * i += 1
2912  *
2913  * if __name__ == '__main__':
2914  * main()
2915  */
2916 
2917 #undef ISECT_1
2918 #undef ISECT_2
2919 #undef ISECT_3
2920 #undef ISECT_4
2921 #undef ISECT_ALL3
2922 #undef ISECT_ALL4
2923 
2924 /* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
2925  * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */
2926 static bool IsectPoly2Df(const float pt[2], const float uv[][2], const int tot)
2927 {
2928  int i;
2929  if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f) {
2930  return false;
2931  }
2932 
2933  for (i = 1; i < tot; i++) {
2934  if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f) {
2935  return false;
2936  }
2937  }
2938 
2939  return true;
2940 }
2941 static bool IsectPoly2Df_twoside(const float pt[2], const float uv[][2], const int tot)
2942 {
2943  const bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
2944 
2945  for (int i = 1; i < tot; i++) {
2946  if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side) {
2947  return false;
2948  }
2949  }
2950 
2951  return true;
2952 }
2953 
2954 /* One of the most important function for projection painting,
2955  * since it selects the pixels to be added into each bucket.
2956  *
2957  * initialize pixels from this face where it intersects with the bucket_index,
2958  * optionally initialize pixels for removing seams */
2960  const int thread_index,
2961  const int bucket_index,
2962  const int tri_index,
2963  const int image_index,
2964  const rctf *clip_rect,
2965  const rctf *bucket_bounds,
2966  ImBuf *ibuf,
2967  ImBuf **tmpibuf)
2968 {
2969  /* Projection vars, to get the 3D locations into screen space. */
2970  MemArena *arena = ps->arena_mt[thread_index];
2971  LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
2972  LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
2973  bool threaded = (ps->thread_tot > 1);
2974 
2975  TileInfo tinf = {
2976  ps->tile_lock,
2977  ps->do_masking,
2979  tmpibuf,
2980  ps->projImages + image_index,
2981  };
2982 
2983  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
2984  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
2985  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
2986 
2987  /* UV/pixel seeking data */
2988  /* Image X/Y-Pixel */
2989  int x, y;
2990  float mask;
2991  /* Image floating point UV - same as x, y but from 0.0-1.0 */
2992  float uv[2];
2993 
2994  /* vert co screen-space, these will be assigned to lt_vtri[0-2] */
2995  const float *v1coSS, *v2coSS, *v3coSS;
2996 
2997  /* Vertex screen-space coords. */
2998  const float *vCo[3];
2999 
3000  float w[3], wco[3];
3001 
3002  /* for convenience only, these will be assigned to lt_tri_uv[0],1,2 or lt_tri_uv[0],2,3 */
3003  float *uv1co, *uv2co, *uv3co;
3004  float pixelScreenCo[4];
3005  bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
3006 
3007  /* Image-space bounds. */
3008  rcti bounds_px;
3009  /* Variables for getting UV-space bounds. */
3010 
3011  /* Bucket bounds in UV space so we can init pixels only for this face. */
3012  float lt_uv_pxoffset[3][2];
3013  float xhalfpx, yhalfpx;
3014  const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
3015 
3016  /* for early loop exit */
3017  int has_x_isect = 0, has_isect = 0;
3018 
3019  float uv_clip[8][2];
3020  int uv_clip_tot;
3021  const bool is_ortho = ps->is_ortho;
3022  const bool is_flip_object = ps->is_flip_object;
3023  const bool do_backfacecull = ps->do_backfacecull;
3024  const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
3025 
3026  vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
3027  vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
3028  vCo[2] = ps->mvert_eval[lt_vtri[2]].co;
3029 
3030  /* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
3031  * this is done so we can avoid offsetting all the pixels by 0.5 which causes
3032  * problems when wrapping negative coords */
3033  xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
3034  yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
3035 
3036  /* Note about (PROJ_GEOM_TOLERANCE/x) above...
3037  * Needed to add this offset since UV coords are often quads aligned to pixels.
3038  * In this case pixels can be exactly between 2 triangles causing nasty
3039  * artifacts.
3040  *
3041  * This workaround can be removed and painting will still work on most cases
3042  * but since the first thing most people try is painting onto a quad- better make it work.
3043  */
3044 
3045  lt_uv_pxoffset[0][0] = lt_tri_uv[0][0] - xhalfpx;
3046  lt_uv_pxoffset[0][1] = lt_tri_uv[0][1] - yhalfpx;
3047 
3048  lt_uv_pxoffset[1][0] = lt_tri_uv[1][0] - xhalfpx;
3049  lt_uv_pxoffset[1][1] = lt_tri_uv[1][1] - yhalfpx;
3050 
3051  lt_uv_pxoffset[2][0] = lt_tri_uv[2][0] - xhalfpx;
3052  lt_uv_pxoffset[2][1] = lt_tri_uv[2][1] - yhalfpx;
3053 
3054  {
3055  uv1co = lt_uv_pxoffset[0]; /* was lt_tri_uv[i1]; */
3056  uv2co = lt_uv_pxoffset[1]; /* was lt_tri_uv[i2]; */
3057  uv3co = lt_uv_pxoffset[2]; /* was lt_tri_uv[i3]; */
3058 
3059  v1coSS = ps->screenCoords[lt_vtri[0]];
3060  v2coSS = ps->screenCoords[lt_vtri[1]];
3061  v3coSS = ps->screenCoords[lt_vtri[2]];
3062 
3063  /* This function gives is a concave polyline in UV space from the clipped tri. */
3064  project_bucket_clip_face(is_ortho,
3065  is_flip_object,
3066  clip_rect,
3067  bucket_bounds,
3068  v1coSS,
3069  v2coSS,
3070  v3coSS,
3071  uv1co,
3072  uv2co,
3073  uv3co,
3074  uv_clip,
3075  &uv_clip_tot,
3076  do_backfacecull || ps->do_occlude);
3077 
3078  /* Sometimes this happens, better just allow for 8 intersections
3079  * even though there should be max 6 */
3080 #if 0
3081  if (uv_clip_tot > 6) {
3082  printf("this should never happen! %d\n", uv_clip_tot);
3083  }
3084 #endif
3085 
3086  if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
3087 #if 0
3088  project_paint_undo_tiles_init(
3089  &bounds_px, ps->projImages + image_index, tmpibuf, tile_width, threaded, ps->do_masking);
3090 #endif
3091  /* clip face and */
3092 
3093  has_isect = 0;
3094  for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
3095  // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
3096  /* use pixel offset UV coords instead */
3097  uv[1] = (float)y / ibuf_yf;
3098 
3099  has_x_isect = 0;
3100  for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
3101  // uv[0] = (((float)x) + 0.5f) / ibuf->x;
3102  /* use pixel offset UV coords instead */
3103  uv[0] = (float)x / ibuf_xf;
3104 
3105  /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesn't work,
3106  * could check the poly direction but better to do this */
3107  if ((do_backfacecull == true && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
3108  (do_backfacecull == false && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) {
3109 
3110  has_x_isect = has_isect = 1;
3111 
3112  if (is_ortho) {
3114  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3115  }
3116  else {
3118  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3119  }
3120 
3121  /* A pity we need to get the world-space pixel location here
3122  * because it is a relatively expensive operation. */
3123  if (do_clip || do_3d_mapping) {
3124  interp_v3_v3v3v3(wco,
3125  ps->mvert_eval[lt_vtri[0]].co,
3126  ps->mvert_eval[lt_vtri[1]].co,
3127  ps->mvert_eval[lt_vtri[2]].co,
3128  w);
3129  if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
3130  /* Watch out that no code below this needs to run */
3131  continue;
3132  }
3133  }
3134 
3135  /* Is this UV visible from the view? - ray-trace */
3136  /* project_paint_PickFace is less complex, use for testing */
3137  // if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
3138  if ((ps->do_occlude == false) ||
3139  !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo)) {
3140  mask = project_paint_uvpixel_mask(ps, tri_index, w);
3141 
3142  if (mask > 0.0f) {
3144  bucketPixelNodes,
3146  ps, arena, &tinf, x, y, mask, tri_index, pixelScreenCo, wco, w),
3147  arena);
3148  }
3149  }
3150  }
3151  //#if 0
3152  else if (has_x_isect) {
3153  /* assuming the face is not a bow-tie - we know we can't intersect again on the X */
3154  break;
3155  }
3156  //#endif
3157  }
3158 
3159 #if 0 /* TODO: investigate why this doesn't work sometimes! it should! */
3160  /* no intersection for this entire row,
3161  * after some intersection above means we can quit now */
3162  if (has_x_isect == 0 && has_isect) {
3163  break;
3164  }
3165 #endif
3166  }
3167  }
3168  }
3169 
3170 #ifndef PROJ_DEBUG_NOSEAMBLEED
3171  if (ps->seam_bleed_px > 0.0f && !(ps->faceSeamFlags[tri_index] & PROJ_FACE_DEGENERATE)) {
3172  int face_seam_flag;
3173 
3174  if (threaded) {
3175  /* Other threads could be modifying these vars. */
3177  }
3178 
3179  face_seam_flag = ps->faceSeamFlags[tri_index];
3180 
3181  /* are any of our edges un-initialized? */
3182  if ((face_seam_flag & PROJ_FACE_SEAM_INIT0) == 0 ||
3183  (face_seam_flag & PROJ_FACE_SEAM_INIT1) == 0 ||
3184  (face_seam_flag & PROJ_FACE_SEAM_INIT2) == 0) {
3185  project_face_seams_init(ps, arena, tri_index, 0, true, ibuf->x, ibuf->y);
3186  face_seam_flag = ps->faceSeamFlags[tri_index];
3187 # if 0
3188  printf("seams - %d %d %d %d\n",
3189  flag & PROJ_FACE_SEAM0,
3190  flag & PROJ_FACE_SEAM1,
3191  flag & PROJ_FACE_SEAM2);
3192 # endif
3193  }
3194 
3195  if ((face_seam_flag & (PROJ_FACE_SEAM0 | PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2)) == 0) {
3196 
3197  if (threaded) {
3198  /* Other threads could be modifying these vars. */
3200  }
3201  }
3202  else {
3203  /* we have a seam - deal with it! */
3204 
3205  /* Inset face coords.
3206  * - screen-space in orthographic view.
3207  * - world-space in perspective view.
3208  */
3209  float insetCos[3][3];
3210 
3211  /* Vertex screen-space coords. */
3212  const float *vCoSS[3];
3213 
3214  /* Store the screen-space coords of the face,
3215  * clipped by the bucket's screen aligned rectangle. */
3216  float bucket_clip_edges[2][2];
3217  float edge_verts_inset_clip[2][3];
3218  /* face edge pairs - loop through these:
3219  * ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
3220  int fidx1, fidx2;
3221 
3222  float seam_subsection[4][2];
3223  float fac1, fac2;
3224 
3225  /* Pixel-space UV's. */
3226  float lt_puv[3][2];
3227 
3228  lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
3229  lt_puv[0][1] = lt_uv_pxoffset[0][1] * ibuf->y;
3230 
3231  lt_puv[1][0] = lt_uv_pxoffset[1][0] * ibuf->x;
3232  lt_puv[1][1] = lt_uv_pxoffset[1][1] * ibuf->y;
3233 
3234  lt_puv[2][0] = lt_uv_pxoffset[2][0] * ibuf->x;
3235  lt_puv[2][1] = lt_uv_pxoffset[2][1] * ibuf->y;
3236 
3237  if ((ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM0) ||
3238  (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM1) ||
3239  (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM2)) {
3240  uv_image_outset(ps, lt_uv_pxoffset, lt_puv, tri_index, ibuf->x, ibuf->y);
3241  }
3242 
3243  /* ps->loopSeamUVs can't be modified when threading, now this is done we can unlock. */
3244  if (threaded) {
3245  /* Other threads could be modifying these vars */
3247  }
3248 
3249  vCoSS[0] = ps->screenCoords[lt_vtri[0]];
3250  vCoSS[1] = ps->screenCoords[lt_vtri[1]];
3251  vCoSS[2] = ps->screenCoords[lt_vtri[2]];
3252 
3253  /* PROJ_FACE_SCALE_SEAM must be slightly less than 1.0f */
3254  if (is_ortho) {
3255  scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
3256  }
3257  else {
3258  scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
3259  }
3260 
3261  for (fidx1 = 0; fidx1 < 3; fidx1++) {
3262  /* next fidx in the face (0,1,2) -> (1,2,0) */
3263  fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1;
3264 
3265  if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
3266  line_clip_rect2f(clip_rect,
3267  bucket_bounds,
3268  vCoSS[fidx1],
3269  vCoSS[fidx2],
3270  bucket_clip_edges[0],
3271  bucket_clip_edges[1])) {
3272  /* Avoid div by zero. */
3273  if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) {
3274  uint loop_idx = ps->mlooptri_eval[tri_index].tri[fidx1];
3275  LoopSeamData *seam_data = &ps->loopSeamData[loop_idx];
3276  float(*seam_uvs)[2] = seam_data->seam_uvs;
3277 
3278  if (is_ortho) {
3279  fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
3280  fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
3281  }
3282  else {
3284  ps, bucket_clip_edges[0], vCo[fidx1], vCo[fidx2]);
3286  ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]);
3287  }
3288 
3289  interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1);
3290  interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2);
3291 
3292  interp_v2_v2v2(seam_subsection[2], seam_uvs[0], seam_uvs[1], fac2);
3293  interp_v2_v2v2(seam_subsection[3], seam_uvs[0], seam_uvs[1], fac1);
3294 
3295  /* if the bucket_clip_edges values Z values was kept we could avoid this
3296  * Inset needs to be added so occlusion tests won't hit adjacent faces */
3297  interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
3298  interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
3299 
3300  if (pixel_bounds_uv(seam_subsection, &bounds_px, ibuf->x, ibuf->y)) {
3301  /* bounds between the seam rect and the uvspace bucket pixels */
3302 
3303  has_isect = 0;
3304  for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
3305  // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
3306  /* use offset uvs instead */
3307  uv[1] = (float)y / ibuf_yf;
3308 
3309  has_x_isect = 0;
3310  for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
3311  const float puv[2] = {(float)x, (float)y};
3312  bool in_bounds;
3313  // uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
3314  /* use offset uvs instead */
3315  uv[0] = (float)x / ibuf_xf;
3316 
3317  /* test we're inside uvspace bucket and triangle bounds */
3318  if (equals_v2v2(seam_uvs[0], seam_uvs[1])) {
3319  in_bounds = isect_point_tri_v2(uv, UNPACK3(seam_subsection));
3320  }
3321  else {
3322  in_bounds = isect_point_quad_v2(uv, UNPACK4(seam_subsection));
3323  }
3324 
3325  if (in_bounds) {
3326  if ((seam_data->corner_dist_sq[0] > 0.0f) &&
3327  (len_squared_v2v2(puv, seam_data->seam_puvs[0]) <
3328  seam_data->corner_dist_sq[0]) &&
3329  (len_squared_v2v2(puv, lt_puv[fidx1]) > ps->seam_bleed_px_sq)) {
3330  in_bounds = false;
3331  }
3332  else if ((seam_data->corner_dist_sq[1] > 0.0f) &&
3333  (len_squared_v2v2(puv, seam_data->seam_puvs[1]) <
3334  seam_data->corner_dist_sq[1]) &&
3335  (len_squared_v2v2(puv, lt_puv[fidx2]) > ps->seam_bleed_px_sq)) {
3336  in_bounds = false;
3337  }
3338  }
3339 
3340  if (in_bounds) {
3341  float pixel_on_edge[4];
3342  float fac;
3343 
3344  if (is_ortho) {
3346  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3347  }
3348  else {
3350  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3351  }
3352 
3353  /* We need the coord of the pixel on the edge, for the occlusion query. */
3354  fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
3356  pixel_on_edge, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
3357 
3358  if (!is_ortho) {
3359  pixel_on_edge[3] = 1.0f;
3360  /* cast because of const */
3361  mul_m4_v4((float(*)[4])ps->projectMat, pixel_on_edge);
3362  pixel_on_edge[0] = (float)(ps->winx * 0.5f) +
3363  (ps->winx * 0.5f) * pixel_on_edge[0] / pixel_on_edge[3];
3364  pixel_on_edge[1] = (float)(ps->winy * 0.5f) +
3365  (ps->winy * 0.5f) * pixel_on_edge[1] / pixel_on_edge[3];
3366  /* Use the depth for bucket point occlusion */
3367  pixel_on_edge[2] = pixel_on_edge[2] / pixel_on_edge[3];
3368  }
3369 
3370  if ((ps->do_occlude == false) ||
3372  ps, bucketFaceNodes, tri_index, pixel_on_edge)) {
3373  /* A pity we need to get the world-space pixel location here
3374  * because it is a relatively expensive operation. */
3375  if (do_clip || do_3d_mapping) {
3376  interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
3377 
3378  if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
3379  /* Watch out that no code below
3380  * this needs to run */
3381  continue;
3382  }
3383  }
3384 
3385  mask = project_paint_uvpixel_mask(ps, tri_index, w);
3386 
3387  if (mask > 0.0f) {
3389  bucketPixelNodes,
3391  ps, arena, &tinf, x, y, mask, tri_index, pixelScreenCo, wco, w),
3392  arena);
3393  }
3394  }
3395  }
3396  else if (has_x_isect) {
3397  /* assuming the face is not a bow-tie - we know
3398  * we can't intersect again on the X */
3399  break;
3400  }
3401  }
3402 
3403 # if 0 /* TODO: investigate why this doesn't work sometimes! it should! */
3404  /* no intersection for this entire row,
3405  * after some intersection above means we can quit now */
3406  if (has_x_isect == 0 && has_isect) {
3407  break;
3408  }
3409 # endif
3410  }
3411  }
3412  }
3413  }
3414  }
3415  }
3416  }
3417 #else
3418  UNUSED_VARS(vCo, threaded);
3419 #endif /* PROJ_DEBUG_NOSEAMBLEED */
3420 }
3421 
3427  const float min[2],
3428  const float max[2],
3429  int bucketMin[2],
3430  int bucketMax[2])
3431 {
3432  /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
3433 
3434  /* XXX(jwilkins ): the offset of 0.5 is always truncated to zero and the offset of 1.5f
3435  * is always truncated to 1, is this really correct? */
3436 
3437  /* these offsets of 0.5 and 1.5 seem odd but they are correct */
3438  bucketMin[0] =
3439  (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f);
3440  bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) *
3441  ps->buckets_y) +
3442  0.5f);
3443 
3444  bucketMax[0] =
3445  (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
3446  bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) *
3447  ps->buckets_y) +
3448  1.5f);
3449 
3450  /* in case the rect is outside the mesh 2d bounds */
3451  CLAMP(bucketMin[0], 0, ps->buckets_x);
3452  CLAMP(bucketMin[1], 0, ps->buckets_y);
3453 
3454  CLAMP(bucketMax[0], 0, ps->buckets_x);
3455  CLAMP(bucketMax[1], 0, ps->buckets_y);
3456 }
3457 
3458 /* set bucket_bounds to a screen space-aligned floating point bound-box */
3460  const int bucket_x,
3461  const int bucket_y,
3462  rctf *bucket_bounds)
3463 {
3464  /* left */
3465  bucket_bounds->xmin = (ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)));
3466  /* right */
3467  bucket_bounds->xmax = (ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)));
3468 
3469  /* bottom */
3470  bucket_bounds->ymin = (ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)));
3471  /* top */
3472  bucket_bounds->ymax = (ps->screenMin[1] +
3473  ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)));
3474 }
3475 
3476 /* Fill this bucket with pixels from the faces that intersect it.
3477  *
3478  * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
3479 static void project_bucket_init(const ProjPaintState *ps,
3480  const int thread_index,
3481  const int bucket_index,
3482  const rctf *clip_rect,
3483  const rctf *bucket_bounds)
3484 {
3485  LinkNode *node;
3486  int tri_index, image_index = 0;
3487  ImBuf *ibuf = NULL;
3488  Image *tpage_last = NULL, *tpage;
3489  ImBuf *tmpibuf = NULL;
3490  int tile_last = 0;
3491 
3492  if (ps->image_tot == 1) {
3493  /* Simple loop, no context switching */
3494  ibuf = ps->projImages[0].ibuf;
3495 
3496  for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
3498  thread_index,
3499  bucket_index,
3500  POINTER_AS_INT(node->link),
3501  0,
3502  clip_rect,
3503  bucket_bounds,
3504  ibuf,
3505  &tmpibuf);
3506  }
3507  }
3508  else {
3509 
3510  /* More complicated loop, switch between images */
3511  for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
3512  tri_index = POINTER_AS_INT(node->link);
3513 
3514  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
3515  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
3516 
3517  /* Image context switching */
3518  tpage = project_paint_face_paint_image(ps, tri_index);
3519  int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
3520  if (tpage_last != tpage || tile_last != tile) {
3521  tpage_last = tpage;
3522  tile_last = tile;
3523 
3524  ibuf = NULL;
3525  for (image_index = 0; image_index < ps->image_tot; image_index++) {
3526  ProjPaintImage *projIma = &ps->projImages[image_index];
3527  if ((projIma->ima == tpage) && (projIma->iuser.tile == tile)) {
3528  ibuf = projIma->ibuf;
3529  break;
3530  }
3531  }
3532  BLI_assert(ibuf != NULL);
3533  }
3534  /* context switching done */
3535 
3537  thread_index,
3538  bucket_index,
3539  tri_index,
3540  image_index,
3541  clip_rect,
3542  bucket_bounds,
3543  ibuf,
3544  &tmpibuf);
3545  }
3546  }
3547 
3548  if (tmpibuf) {
3549  IMB_freeImBuf(tmpibuf);
3550  }
3551 
3552  ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
3553 }
3554 
3555 /* We want to know if a bucket and a face overlap in screen-space.
3556  *
3557  * NOTE: if this ever returns false positives its not that bad, since a face in the bounding area
3558  * will have its pixels calculated when it might not be needed later, (at the moment at least)
3559  * obviously it shouldn't have bugs though. */
3560 
3562  int bucket_x,
3563  int bucket_y,
3564  const MLoopTri *lt)
3565 {
3566  /* TODO: replace this with a trickier method that uses side-of-line for all
3567  * #ProjPaintState.screenCoords edges against the closest bucket corner. */
3568  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
3569  rctf bucket_bounds;
3570  float p1[2], p2[2], p3[2], p4[2];
3571  const float *v, *v1, *v2, *v3;
3572  int fidx;
3573 
3574  project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
3575 
3576  /* Is one of the faces verts in the bucket bounds? */
3577 
3578  fidx = 2;
3579  do {
3580  v = ps->screenCoords[lt_vtri[fidx]];
3581  if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
3582  return true;
3583  }
3584  } while (fidx--);
3585 
3586  v1 = ps->screenCoords[lt_vtri[0]];
3587  v2 = ps->screenCoords[lt_vtri[1]];
3588  v3 = ps->screenCoords[lt_vtri[2]];
3589 
3590  p1[0] = bucket_bounds.xmin;
3591  p1[1] = bucket_bounds.ymin;
3592  p2[0] = bucket_bounds.xmin;
3593  p2[1] = bucket_bounds.ymax;
3594  p3[0] = bucket_bounds.xmax;
3595  p3[1] = bucket_bounds.ymax;
3596  p4[0] = bucket_bounds.xmax;
3597  p4[1] = bucket_bounds.ymin;
3598 
3599  if (isect_point_tri_v2(p1, v1, v2, v3) || isect_point_tri_v2(p2, v1, v2, v3) ||
3600  isect_point_tri_v2(p3, v1, v2, v3) || isect_point_tri_v2(p4, v1, v2, v3) ||
3601  /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
3602  (isect_seg_seg_v2(p1, p2, v1, v2) || isect_seg_seg_v2(p1, p2, v2, v3)) ||
3603  (isect_seg_seg_v2(p2, p3, v1, v2) || isect_seg_seg_v2(p2, p3, v2, v3)) ||
3604  (isect_seg_seg_v2(p3, p4, v1, v2) || isect_seg_seg_v2(p3, p4, v2, v3)) ||
3605  (isect_seg_seg_v2(p4, p1, v1, v2) || isect_seg_seg_v2(p4, p1, v2, v3))) {
3606  return true;
3607  }
3608 
3609  return false;
3610 }
3611 
3612 /* Add faces to the bucket but don't initialize its pixels
3613  * TODO: when painting occluded, sort the faces on their min-Z
3614  * and only add faces that faces that are not occluded */
3616  const MLoopTri *lt,
3617  const int tri_index)
3618 {
3619  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
3620  float min[2], max[2], *vCoSS;
3621  /* for ps->bucketRect indexing */
3622  int bucketMin[2], bucketMax[2];
3623  int fidx, bucket_x, bucket_y;
3624  /* for early loop exit */
3625  int has_x_isect = -1, has_isect = 0;
3626  /* just use the first thread arena since threading has not started yet */
3627  MemArena *arena = ps->arena_mt[0];
3628 
3629  INIT_MINMAX2(min, max);
3630 
3631  fidx = 2;
3632  do {
3633  vCoSS = ps->screenCoords[lt_vtri[fidx]];
3634  minmax_v2v2_v2(min, max, vCoSS);
3635  } while (fidx--);
3636 
3637  project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
3638 
3639  for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
3640  has_x_isect = 0;
3641  for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
3642  if (project_bucket_face_isect(ps, bucket_x, bucket_y, lt)) {
3643  int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
3644  BLI_linklist_prepend_arena(&ps->bucketFaces[bucket_index],
3645  /* cast to a pointer to shut up the compiler */
3646  POINTER_FROM_INT(tri_index),
3647  arena);
3648 
3649  has_x_isect = has_isect = 1;
3650  }
3651  else if (has_x_isect) {
3652  /* assuming the face is not a bow-tie - we know we can't intersect again on the X */
3653  break;
3654  }
3655  }
3656 
3657  /* no intersection for this entire row,
3658  * after some intersection above means we can quit now */
3659  if (has_x_isect == 0 && has_isect) {
3660  break;
3661  }
3662  }
3663 
3664 #ifndef PROJ_DEBUG_NOSEAMBLEED
3665  if (ps->seam_bleed_px > 0.0f) {
3666  /* set as uninitialized */
3667  ps->loopSeamData[lt->tri[0]].seam_uvs[0][0] = FLT_MAX;
3668  ps->loopSeamData[lt->tri[1]].seam_uvs[0][0] = FLT_MAX;
3669  ps->loopSeamData[lt->tri[2]].seam_uvs[0][0] = FLT_MAX;
3670  }
3671 #endif
3672 }
3673 
3674 static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmetry_flag)
3675 {
3676  float mat[3][3];
3677  float viewmat[4][4];
3678  float viewinv[4][4];
3679 
3680  ps->viewDir[0] = 0.0f;
3681  ps->viewDir[1] = 0.0f;
3682  ps->viewDir[2] = 1.0f;
3683 
3684  copy_m4_m4(ps->obmat, ps->ob->obmat);
3685 
3686  if (symmetry_flag) {
3687  int i;
3688  for (i = 0; i < 3; i++) {
3689  if ((symmetry_flag >> i) & 1) {
3690  negate_v3(ps->obmat[i]);
3691  ps->is_flip_object = !ps->is_flip_object;
3692  }
3693  }
3694  }
3695 
3696  invert_m4_m4(ps->obmat_imat, ps->obmat);
3697 
3699  /* normal drawing */
3700  ps->winx = ps->region->winx;
3701  ps->winy = ps->region->winy;
3702 
3703  copy_m4_m4(viewmat, ps->rv3d->viewmat);
3704  copy_m4_m4(viewinv, ps->rv3d->viewinv);
3705 
3707 
3709  ps->depsgraph, ps->v3d, ps->rv3d, &ps->clip_start, &ps->clip_end, true);
3710  }
3711  else {
3712  /* re-projection */
3713  float winmat[4][4];
3714  float vmat[4][4];
3715 
3716  ps->winx = ps->reproject_ibuf->x;
3717  ps->winy = ps->reproject_ibuf->y;
3718 
3719  if (ps->source == PROJ_SRC_IMAGE_VIEW) {
3720  /* image stores camera data, tricky */
3721  IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
3722  IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
3723 
3724  const float *array = (float *)IDP_Array(view_data);
3725 
3726  /* use image array, written when creating image */
3727  memcpy(winmat, array, sizeof(winmat));
3728  array += sizeof(winmat) / sizeof(float);
3729  memcpy(viewmat, array, sizeof(viewmat));
3730  array += sizeof(viewmat) / sizeof(float);
3731  ps->clip_start = array[0];
3732  ps->clip_end = array[1];
3733  ps->is_ortho = array[2] ? 1 : 0;
3734 
3735  invert_m4_m4(viewinv, viewmat);
3736  }
3737  else if (ps->source == PROJ_SRC_IMAGE_CAM) {
3738  Object *cam_ob_eval = DEG_get_evaluated_object(ps->depsgraph, ps->scene->camera);
3740 
3741  /* viewmat & viewinv */
3742  copy_m4_m4(viewinv, cam_ob_eval->obmat);
3743  normalize_m4(viewinv);
3744  invert_m4_m4(viewmat, viewinv);
3745 
3746  /* window matrix, clipping and ortho */
3748  BKE_camera_params_from_object(&params, cam_ob_eval);
3749  BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
3751 
3752  copy_m4_m4(winmat, params.winmat);
3753  ps->clip_start = params.clip_start;
3754  ps->clip_end = params.clip_end;
3755  ps->is_ortho = params.is_ortho;
3756  }
3757  else {
3758  BLI_assert(0);
3759  }
3760 
3761  /* same as #ED_view3d_ob_project_mat_get */
3762  mul_m4_m4m4(vmat, viewmat, ps->obmat);
3763  mul_m4_m4m4(ps->projectMat, winmat, vmat);
3764  }
3765 
3767 
3768  /* viewDir - object relative */
3769  copy_m3_m4(mat, viewinv);
3770  mul_m3_v3(mat, ps->viewDir);
3771  copy_m3_m4(mat, ps->obmat_imat);
3772  mul_m3_v3(mat, ps->viewDir);
3773  normalize_v3(ps->viewDir);
3774 
3775  if (UNLIKELY(ps->is_flip_object)) {
3776  negate_v3(ps->viewDir);
3777  }
3778 
3779  /* viewPos - object relative */
3780  copy_v3_v3(ps->viewPos, viewinv[3]);
3781  copy_m3_m4(mat, ps->obmat_imat);
3782  mul_m3_v3(mat, ps->viewPos);
3783  add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
3784 }
3785 
3786 static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
3787 {
3788  const MVert *mv;
3789  float *projScreenCo;
3790  float projMargin;
3791  int a;
3792 
3793  INIT_MINMAX2(ps->screenMin, ps->screenMax);
3794 
3795  ps->screenCoords = MEM_mallocN(sizeof(float) * ps->totvert_eval * 4, "ProjectPaint ScreenVerts");
3796  projScreenCo = *ps->screenCoords;
3797 
3798  if (ps->is_ortho) {
3799  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
3800  mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
3801 
3802  /* screen space, not clamped */
3803  projScreenCo[0] = (float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projScreenCo[0];
3804  projScreenCo[1] = (float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projScreenCo[1];
3805  minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
3806  }
3807  }
3808  else {
3809  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
3810  copy_v3_v3(projScreenCo, mv->co);
3811  projScreenCo[3] = 1.0f;
3812 
3813  mul_m4_v4(ps->projectMat, projScreenCo);
3814 
3815  if (projScreenCo[3] > ps->clip_start) {
3816  /* screen space, not clamped */
3817  projScreenCo[0] = (float)(ps->winx * 0.5f) +
3818  (ps->winx * 0.5f) * projScreenCo[0] / projScreenCo[3];
3819  projScreenCo[1] = (float)(ps->winy * 0.5f) +
3820  (ps->winy * 0.5f) * projScreenCo[1] / projScreenCo[3];
3821  /* Use the depth for bucket point occlusion */
3822  projScreenCo[2] = projScreenCo[2] / projScreenCo[3];
3823  minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
3824  }
3825  else {
3826  /* TODO: deal with cases where 1 side of a face goes behind the view ?
3827  *
3828  * After some research this is actually very tricky, only option is to
3829  * clip the derived mesh before painting, which is a Pain */
3830  projScreenCo[0] = FLT_MAX;
3831  }
3832  }
3833  }
3834 
3835  /* If this border is not added we get artifacts for faces that
3836  * have a parallel edge and at the bounds of the 2D projected verts eg
3837  * - a single screen aligned quad */
3838  projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
3839  ps->screenMax[0] += projMargin;
3840  ps->screenMin[0] -= projMargin;
3841  projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
3842  ps->screenMax[1] += projMargin;
3843  ps->screenMin[1] -= projMargin;
3844 
3845  if (ps->source == PROJ_SRC_VIEW) {
3846 #ifdef PROJ_DEBUG_WINCLIP
3847  CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
3848  CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
3849 
3850  CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
3851  CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
3852 #else
3853  UNUSED_VARS(diameter);
3854 #endif
3855  }
3856  else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
3857  ps->screenMin[0] = 0;
3858  ps->screenMax[0] = (float)(ps->winx);
3859 
3860  ps->screenMin[1] = 0;
3861  ps->screenMax[1] = (float)(ps->winy);
3862  }
3863 }
3864 
3866 {
3867  const MEdge *me;
3868  float *cavities;
3869  int a;
3870 
3871  if (ps->do_mask_cavity) {
3872  int *counter = MEM_callocN(sizeof(int) * ps->totvert_eval, "counter");
3873  float(*edges)[3] = MEM_callocN(sizeof(float[3]) * ps->totvert_eval, "edges");
3874  ps->cavities = MEM_mallocN(sizeof(float) * ps->totvert_eval, "ProjectPaint Cavities");
3875  cavities = ps->cavities;
3876 
3877  for (a = 0, me = ps->medge_eval; a < ps->totedge_eval; a++, me++) {
3878  float e[3];
3879  sub_v3_v3v3(e, ps->mvert_eval[me->v1].co, ps->mvert_eval[me->v2].co);
3880  normalize_v3(e);
3881  add_v3_v3(edges[me->v2], e);
3882  counter[me->v2]++;
3883  sub_v3_v3(edges[me->v1], e);
3884  counter[me->v1]++;
3885  }
3886  for (a = 0; a < ps->totvert_eval; a++) {
3887  if (counter[a] > 0) {
3888  mul_v3_fl(edges[a], 1.0f / counter[a]);
3889  /* Augment the difference. */
3890  cavities[a] = saacos(10.0f * dot_v3v3(ps->vert_normals[a], edges[a])) * (float)M_1_PI;
3891  }
3892  else {
3893  cavities[a] = 0.0;
3894  }
3895  }
3896 
3897  MEM_freeN(counter);
3898  MEM_freeN(edges);
3899  }
3900 }
3901 
3902 #ifndef PROJ_DEBUG_NOSEAMBLEED
3904 {
3905  if (ps->seam_bleed_px > 0.0f) {
3906  ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->totvert_eval, "paint-vertFaces");
3907  ps->faceSeamFlags = MEM_callocN(sizeof(ushort) * ps->totlooptri_eval, "paint-faceSeamFlags");
3908  ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->totlooptri_eval,
3909  "paint-faceWindindFlags");
3910  ps->loopSeamData = MEM_mallocN(sizeof(LoopSeamData) * ps->totloop_eval, "paint-loopSeamUVs");
3911  ps->vertSeams = MEM_callocN(sizeof(ListBase) * ps->totvert_eval, "paint-vertSeams");
3912  }
3913 }
3914 #endif
3915 
3916 static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads)
3917 {
3918  /* Thread stuff
3919  *
3920  * very small brushes run a lot slower multi-threaded since the advantage with
3921  * threads is being able to fill in multiple buckets at once.
3922  * Only use threads for bigger brushes. */
3923 
3925 
3926  /* workaround for T35057, disable threading if diameter is less than is possible for
3927  * optimum bucket number generation */
3928  if (reset_threads) {
3929  ps->thread_tot = 1;
3930  }
3931 
3932  if (ps->is_shared_user == false) {
3933  if (ps->thread_tot > 1) {
3934  ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
3935  BLI_spin_init(ps->tile_lock);
3936  }
3937 
3939  }
3940 
3941  for (int a = 0; a < ps->thread_tot; a++) {
3942  ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
3943  }
3944 }
3945 
3947 {
3948  if (ps->do_backfacecull && ps->do_mask_normal) {
3949  float viewDirPersp[3];
3950  const MVert *mv;
3951  float no[3];
3952  int a;
3953 
3954  ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
3955 
3956  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
3957  copy_v3_v3(no, ps->vert_normals[a]);
3958  if (UNLIKELY(ps->is_flip_object)) {
3959  negate_v3(no);
3960  }
3961 
3962  if (ps->is_ortho) {
3963  if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) {
3964  /* 1 vert of this face is towards us */
3965  ps->vertFlags[a] |= PROJ_VERT_CULL;
3966  }
3967  }
3968  else {
3969  sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
3970  normalize_v3(viewDirPersp);
3971  if (UNLIKELY(ps->is_flip_object)) {
3972  negate_v3(viewDirPersp);
3973  }
3974  if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) {
3975  /* 1 vert of this face is towards us */
3976  ps->vertFlags[a] |= PROJ_VERT_CULL;
3977  }
3978  }
3979  }
3980  }
3981  else {
3982  ps->vertFlags = NULL;
3983  }
3984 }
3985 
3986 #ifndef PROJ_DEBUG_NOSEAMBLEED
3988  MemArena *arena,
3989  const MLoopTri *lt,
3990  const int tri_index)
3991 {
3992  /* add face user if we have bleed enabled, set the UV seam flags later */
3993  /* annoying but we need to add all faces even ones we never use elsewhere */
3994  if (ps->seam_bleed_px > 0.0f) {
3995  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
3996 
3997  /* Check for degenerate triangles. Degenerate faces cause trouble with bleed computations.
3998  * Ideally this would be checked later, not to add to the cost of computing non-degenerate
3999  * triangles, but that would allow other triangles to still find adjacent seams on degenerate
4000  * triangles, potentially causing incorrect results. */
4001  if (area_tri_v2(UNPACK3(lt_tri_uv)) > 0.0f) {
4002  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
4003  void *tri_index_p = POINTER_FROM_INT(tri_index);
4004 
4005  BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[0]], tri_index_p, arena);
4006  BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[1]], tri_index_p, arena);
4007  BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[2]], tri_index_p, arena);
4008  }
4009  else {
4010  ps->faceSeamFlags[tri_index] |= PROJ_FACE_DEGENERATE;
4011  }
4012  }
4013 }
4014 #endif
4015 
4016 /* Return true if evaluated mesh can be painted on, false otherwise */
4018 {
4020  Object *ob = ps->ob;
4021 
4022  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
4023  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
4024 
4025  if (scene_eval == NULL || ob_eval == NULL) {
4026  return false;
4027  }
4028 
4029  CustomData_MeshMasks cddata_masks = scene_eval->customdata_mask;
4030  cddata_masks.fmask |= CD_MASK_MTFACE;
4031  cddata_masks.lmask |= CD_MASK_MLOOPUV;
4032  if (ps->do_face_sel) {
4033  cddata_masks.vmask |= CD_MASK_ORIGINDEX;
4034  cddata_masks.emask |= CD_MASK_ORIGINDEX;
4035  cddata_masks.pmask |= CD_MASK_ORIGINDEX;
4036  }
4037  ps->me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
4038 
4040  ps->me_eval = NULL;
4041  return false;
4042  }
4043 
4044  /* Build final material array, we use this a lot here. */
4045  /* materials start from 1, default material is 0 */
4046  const int totmat = ob->totcol + 1;
4047  ps->mat_array = MEM_malloc_arrayN(totmat, sizeof(*ps->mat_array), __func__);
4048  /* We leave last material as empty - rationale here is being able to index
4049  * the materials by using the mf->mat_nr directly and leaving the last
4050  * material as NULL in case no materials exist on mesh, so indexing will not fail. */
4051  for (int i = 0; i < totmat - 1; i++) {
4052  ps->mat_array[i] = BKE_object_material_get(ob, i + 1);
4053  }
4054  ps->mat_array[totmat - 1] = NULL;
4055 
4056  ps->mvert_eval = ps->me_eval->mvert;
4058  if (ps->do_mask_cavity) {
4059  ps->medge_eval = ps->me_eval->medge;
4060  }
4061  ps->mloop_eval = ps->me_eval->mloop;
4062  ps->mpoly_eval = ps->me_eval->mpoly;
4063 
4064  ps->totvert_eval = ps->me_eval->totvert;
4065  ps->totedge_eval = ps->me_eval->totedge;
4066  ps->totpoly_eval = ps->me_eval->totpoly;
4067  ps->totloop_eval = ps->me_eval->totloop;
4068 
4071 
4072  ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
4073 
4074  return true;
4075 }
4076 
4077 typedef struct {
4082 
4084 {
4085  const MLoopUV *mloopuv_clone_base = NULL;
4086 
4087  /* use clone mtface? */
4088  if (ps->do_layer_clone) {
4089  const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
4090 
4091  ps->poly_to_loop_uv_clone = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *),
4092  "proj_paint_mtfaces");
4093 
4094  if (layer_num != -1) {
4095  mloopuv_clone_base = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
4096  }
4097 
4098  if (mloopuv_clone_base == NULL) {
4099  /* get active instead */
4100  mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4101  }
4102  }
4103 
4104  memset(layer_clone, 0, sizeof(*layer_clone));
4105  layer_clone->mloopuv_clone_base = mloopuv_clone_base;
4106 }
4107 
4108 /* Return true if face should be skipped, false otherwise */
4110  ProjPaintLayerClone *lc,
4111  const TexPaintSlot *slot,
4112  const int tri_index)
4113 {
4114  if (ps->do_layer_clone) {
4115  if (ps->do_material_slots) {
4116  lc->slot_clone = project_paint_face_clone_slot(ps, tri_index);
4117  /* all faces should have a valid slot, reassert here */
4118  if (ELEM(lc->slot_clone, NULL, slot)) {
4119  return true;
4120  }
4121  }
4122  else if (ps->clone_ima == ps->canvas_ima) {
4123  return true;
4124  }
4125 
4126  if (ps->do_material_slots) {
4127  if (lc->slot_clone != lc->slot_last_clone) {
4128  if (!lc->slot_clone->uvname ||
4130  &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
4132  }
4133  lc->slot_last_clone = lc->slot_clone;
4134  }
4135  }
4136 
4137  /* will set multiple times for 4+ sided poly */
4138  ps->poly_to_loop_uv_clone[ps->mlooptri_eval[tri_index].poly] = lc->mloopuv_clone_base;
4139  }
4140  return false;
4141 }
4142 
4143 typedef struct {
4145 
4146  const int *index_mp_to_orig;
4148 
4150 {
4151  memset(face_lookup, 0, sizeof(*face_lookup));
4152  if (ps->do_face_sel) {
4154  face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
4155  }
4156 }
4157 
4158 /* Return true if face should be considered selected, false otherwise */
4160  const ProjPaintFaceLookup *face_lookup,
4161  const MLoopTri *lt)
4162 {
4163  if (ps->do_face_sel) {
4164  int orig_index;
4165  const MPoly *mp;
4166 
4167  if ((face_lookup->index_mp_to_orig != NULL) &&
4168  (((orig_index = (face_lookup->index_mp_to_orig[lt->poly]))) != ORIGINDEX_NONE)) {
4169  mp = &face_lookup->mpoly_orig[orig_index];
4170  }
4171  else {
4172  mp = &ps->mpoly_eval[lt->poly];
4173  }
4174 
4175  return ((mp->flag & ME_FACE_SEL) != 0);
4176  }
4177  return true;
4178 }
4179 
4180 typedef struct {
4181  const float *v1;
4182  const float *v2;
4183  const float *v3;
4185 
4187  const MLoopTri *lt,
4188  ProjPaintFaceCoSS *coSS)
4189 {
4190  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
4191  coSS->v1 = ps->screenCoords[lt_vtri[0]];
4192  coSS->v2 = ps->screenCoords[lt_vtri[1]];
4193  coSS->v3 = ps->screenCoords[lt_vtri[2]];
4194 }
4195 
4196 /* Return true if face should be culled, false otherwise */
4198 {
4199  if (!ps->is_ortho) {
4200  if (coSS->v1[0] == FLT_MAX || coSS->v2[0] == FLT_MAX || coSS->v3[0] == FLT_MAX) {
4201  return true;
4202  }
4203  }
4204  return false;
4205 }
4206 
4207 #ifdef PROJ_DEBUG_WINCLIP
4208 /* Return true if face should be culled, false otherwise */
4209 static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceCoSS *coSS)
4210 {
4211  /* ignore faces outside the view */
4212  return ((ps->source != PROJ_SRC_VIEW_FILL) &&
4213  ((coSS->v1[0] < ps->screenMin[0] && coSS->v2[0] < ps->screenMin[0] &&
4214  coSS->v3[0] < ps->screenMin[0]) ||
4215 
4216  (coSS->v1[0] > ps->screenMax[0] && coSS->v2[0] > ps->screenMax[0] &&
4217  coSS->v3[0] > ps->screenMax[0]) ||
4218 
4219  (coSS->v1[1] < ps->screenMin[1] && coSS->v2[1] < ps->screenMin[1] &&
4220  coSS->v3[1] < ps->screenMin[1]) ||
4221 
4222  (coSS->v1[1] > ps->screenMax[1] && coSS->v2[1] > ps->screenMax[1] &&
4223  coSS->v3[1] > ps->screenMax[1])));
4224 }
4225 #endif /* PROJ_DEBUG_WINCLIP */
4226 
4227 typedef struct PrepareImageEntry {
4232 
4234  MemArena *arena,
4235  ListBase *used_images)
4236 {
4237  ProjPaintImage *projIma;
4238  PrepareImageEntry *entry;
4239  int i;
4240 
4241  /* build an array of images we use */
4242  projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
4243 
4244  for (entry = used_images->first, i = 0; entry; entry = entry->next, i++, projIma++) {
4245  projIma->iuser = entry->iuser;
4246  int size;
4247  projIma->ima = entry->ima;
4248  projIma->touch = 0;
4249  projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
4250  if (projIma->ibuf == NULL) {
4251  projIma->iuser.tile = 0;
4252  projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
4253  BLI_assert(projIma->ibuf != NULL);
4254  }
4255  size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
4256  ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
4260  projIma->undoRect = (volatile void **)BLI_memarena_alloc(arena, size);
4261  memset((void *)projIma->undoRect, 0, size);
4262  projIma->maskRect = BLI_memarena_alloc(arena, size);
4263  memset(projIma->maskRect, 0, size);
4264  projIma->valid = BLI_memarena_alloc(arena, size);
4265  memset(projIma->valid, 0, size);
4266  }
4267 }
4268 
4270  MemArena *arena,
4271  const ProjPaintFaceLookup *face_lookup,
4272  ProjPaintLayerClone *layer_clone,
4273  const MLoopUV *mloopuv_base,
4274  const bool is_multi_view)
4275 {
4276  /* Image Vars - keep track of images we have used */
4277  ListBase used_images = {NULL};
4278 
4279  Image *tpage_last = NULL, *tpage;
4280  TexPaintSlot *slot_last = NULL;
4281  TexPaintSlot *slot = NULL;
4282  int tile_last = -1, tile;
4283  const MLoopTri *lt;
4284  int image_index = -1, tri_index;
4285  int prev_poly = -1;
4286 
4287  BLI_assert(ps->image_tot == 0);
4288 
4289  for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
4290  bool is_face_sel;
4291  bool skip_tri = false;
4292 
4293  is_face_sel = project_paint_check_face_sel(ps, face_lookup, lt);
4294 
4295  if (!ps->do_stencil_brush) {
4296  slot = project_paint_face_paint_slot(ps, tri_index);
4297  /* all faces should have a valid slot, reassert here */
4298  if (slot == NULL) {
4299  mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4300  tpage = ps->canvas_ima;
4301  }
4302  else {
4303  if (slot != slot_last) {
4304  if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(
4305  &ps->me_eval->ldata, CD_MLOOPUV, slot->uvname))) {
4306  mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4307  }
4308  slot_last = slot;
4309  }
4310 
4311  /* Don't allow using the same image for painting and stenciling. */
4312  if (slot->ima == ps->stencil_ima) {
4313  /* Delay continuing the loop until after loop_uvs and bleed faces are initialized.
4314  * While this shouldn't be used, face-winding reads all polys.
4315  * It's less trouble to set all faces to valid UV's,
4316  * avoiding NULL checks all over. */
4317  skip_tri = true;
4318  tpage = NULL;
4319  }
4320  else {
4321  tpage = slot->ima;
4322  }
4323  }
4324  }
4325  else {
4326  tpage = ps->stencil_ima;
4327  }
4328 
4329  ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
4330 
4331  tile = project_paint_face_paint_tile(tpage, mloopuv_base[lt->tri[0]].uv);
4332 
4333 #ifndef PROJ_DEBUG_NOSEAMBLEED
4334  project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
4335 #endif
4336 
4337  if (skip_tri || project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
4338  continue;
4339  }
4340 
4341  BLI_assert(mloopuv_base != NULL);
4342 
4343  if (is_face_sel && tpage) {
4344  ProjPaintFaceCoSS coSS;
4345  proj_paint_face_coSS_init(ps, lt, &coSS);
4346 
4347  if (is_multi_view == false) {
4348  if (project_paint_flt_max_cull(ps, &coSS)) {
4349  continue;
4350  }
4351 
4352 #ifdef PROJ_DEBUG_WINCLIP
4353  if (project_paint_winclip(ps, &coSS)) {
4354  continue;
4355  }
4356 
4357 #endif // PROJ_DEBUG_WINCLIP
4358 
4359  /* Back-face culls individual triangles but mask normal will use polygon. */
4360  if (ps->do_backfacecull) {
4361  if (ps->do_mask_normal) {
4362  if (prev_poly != lt->poly) {
4363  int iloop;
4364  bool culled = true;
4365  const MPoly *poly = ps->mpoly_eval + lt->poly;
4366  int poly_loops = poly->totloop;
4367  prev_poly = lt->poly;
4368  for (iloop = 0; iloop < poly_loops; iloop++) {
4369  if (!(ps->vertFlags[ps->mloop_eval[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
4370  culled = false;
4371  break;
4372  }
4373  }
4374 
4375  if (culled) {
4376  /* poly loops - 2 is number of triangles for poly,
4377  * but counter gets incremented when continuing, so decrease by 3 */
4378  int poly_tri = poly_loops - 3;
4379  tri_index += poly_tri;
4380  lt += poly_tri;
4381  continue;
4382  }
4383  }
4384  }
4385  else {
4386  if ((line_point_side_v2(coSS.v1, coSS.v2, coSS.v3) < 0.0f) != ps->is_flip_object) {
4387  continue;
4388  }
4389  }
4390  }
4391  }
4392 
4393  if (tpage_last != tpage || tile_last != tile) {
4394  image_index = 0;
4395  for (PrepareImageEntry *e = used_images.first; e; e = e->next, image_index++) {
4396  if (e->ima == tpage && e->iuser.tile == tile) {
4397  break;
4398  }
4399  }
4400 
4401  if (image_index == ps->image_tot) {
4402  /* XXX get appropriate ImageUser instead */
4403  ImageUser iuser;
4405  iuser.tile = tile;
4406  iuser.framenr = tpage->lastframe;
4407  if (BKE_image_has_ibuf(tpage, &iuser)) {
4408  PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
4409  e->ima = tpage;
4410  e->iuser = iuser;
4411  BLI_addtail(&used_images, e);
4412  ps->image_tot++;
4413  }
4414  else {
4415  image_index = -1;
4416  }
4417  }
4418 
4419  tpage_last = tpage;
4420  tile_last = tile;
4421  }
4422 
4423  if (image_index != -1) {
4424  /* Initialize the faces screen pixels */
4425  /* Add this to a list to initialize later */
4426  project_paint_delayed_face_init(ps, lt, tri_index);
4427  }
4428  }
4429  }
4430 
4431  /* Build an array of images we use. */
4432  if (ps->is_shared_user == false) {
4433  project_paint_build_proj_ima(ps, arena, &used_images);
4434  }
4435 
4436  /* we have built the array, discard the linked list */
4437  BLI_freelistN(&used_images);
4438 }
4439 
4440 /* run once per stroke before projection painting */
4441 static void project_paint_begin(const bContext *C,
4442  ProjPaintState *ps,
4443  const bool is_multi_view,
4444  const char symmetry_flag)
4445 {
4446  ProjPaintLayerClone layer_clone;
4447  ProjPaintFaceLookup face_lookup;
4448  const MLoopUV *mloopuv_base = NULL;
4449 
4450  /* At the moment this is just ps->arena_mt[0], but use this to show were not multi-threading. */
4451  MemArena *arena;
4452 
4453  const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
4454 
4455  bool reset_threads = false;
4456 
4457  /* ---- end defines ---- */
4458 
4459  if (ps->source == PROJ_SRC_VIEW) {
4460  /* faster clipping lookups */
4462  }
4463 
4464  ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
4465  ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
4466 
4467  /* paint onto the derived mesh */
4468  if (ps->is_shared_user == false) {
4469  if (!proj_paint_state_mesh_eval_init(C, ps)) {
4470  return;
4471  }
4472  }
4473 
4474  proj_paint_face_lookup_init(ps, &face_lookup);
4475  proj_paint_layer_clone_init(ps, &layer_clone);
4476 
4477  if (ps->do_layer_stencil || ps->do_stencil_brush) {
4478  // int layer_num = CustomData_get_stencil_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4479  int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
4480  if (layer_num != -1) {
4482  &ps->me_eval->ldata, CD_MLOOPUV, layer_num);
4483  }
4484 
4485  if (ps->mloopuv_stencil_eval == NULL) {
4486  /* get active instead */
4488  }
4489 
4490  if (ps->do_stencil_brush) {
4491  mloopuv_base = ps->mloopuv_stencil_eval;
4492  }
4493  }
4494 
4495  /* when using sub-surface or multi-resolution,
4496  * mesh-data arrays are thrown away, we need to keep a copy. */
4497  if (ps->is_shared_user == false) {
4499  }
4500 
4501  proj_paint_state_viewport_init(ps, symmetry_flag);
4502 
4503  /* calculate vert screen coords
4504  * run this early so we can calculate the x/y resolution of our bucket rect */
4506 
4507  /* only for convenience */
4508  ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
4509  ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
4510 
4511  ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
4512  ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
4513 
4514  // printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y);
4515 
4517  reset_threads = true;
4518  }
4519 
4520  /* Really high values could cause problems since it has to allocate a few
4521  * `(ps->buckets_x * ps->buckets_y)` sized arrays. */
4524 
4525  ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y,
4526  "paint-bucketRect");
4527  ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y,
4528  "paint-bucketFaces");
4529 
4530  ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
4531 #ifndef PROJ_DEBUG_NOSEAMBLEED
4532  if (ps->is_shared_user == false) {
4534  }
4535 #endif
4536 
4537  proj_paint_state_thread_init(ps, reset_threads);
4538  arena = ps->arena_mt[0];
4539 
4541 
4543  ps, arena, &face_lookup, &layer_clone, mloopuv_base, is_multi_view);
4544 }
4545 
4546 static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
4547 {
4548  /* setup clone offset */
4549  if (ps->tool == PAINT_TOOL_CLONE) {
4550  float projCo[4];
4551  copy_v3_v3(projCo, ps->scene->cursor.location);
4552  mul_m4_v3(ps->obmat_imat, projCo);
4553 
4554  projCo[3] = 1.0f;
4555  mul_m4_v4(ps->projectMat, projCo);
4556  ps->cloneOffset[0] = mouse[0] -
4557  ((float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projCo[0] / projCo[3]);
4558  ps->cloneOffset[1] = mouse[1] -
4559  ((float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projCo[1] / projCo[3]);
4560  }
4561 }
4562 
4564 {
4565  int a;
4566 
4567  /* dereference used image buffers */
4568  if (ps->is_shared_user == false) {
4569  ProjPaintImage *projIma;
4570  for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
4571  BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
4572  DEG_id_tag_update(&projIma->ima->id, 0);
4573  }
4574  }
4575 
4576  if (ps->reproject_ibuf_free_float) {
4578  }
4579  if (ps->reproject_ibuf_free_uchar) {
4581  }
4583 
4584  MEM_freeN(ps->screenCoords);
4585  MEM_freeN(ps->bucketRect);
4586  MEM_freeN(ps->bucketFaces);
4587  MEM_freeN(ps->bucketFlags);
4588 
4589  if (ps->is_shared_user == false) {
4590  if (ps->mat_array != NULL) {
4591  MEM_freeN(ps->mat_array);
4592  }
4593 
4594  /* must be set for non-shared */
4596  if (ps->poly_to_loop_uv) {
4597  MEM_freeN((void *)ps->poly_to_loop_uv);
4598  }
4599 
4600  if (ps->do_layer_clone) {
4601  MEM_freeN((void *)ps->poly_to_loop_uv_clone);
4602  }
4603  if (ps->thread_tot > 1) {
4604  BLI_spin_end(ps->tile_lock);
4605  MEM_freeN((void *)ps->tile_lock);
4606  }
4607 
4609 
4610 #ifndef PROJ_DEBUG_NOSEAMBLEED
4611  if (ps->seam_bleed_px > 0.0f) {
4612  MEM_freeN(ps->vertFaces);
4613  MEM_freeN(ps->faceSeamFlags);
4615  MEM_freeN(ps->loopSeamData);
4616  MEM_freeN(ps->vertSeams);
4617  }
4618 #endif
4619 
4620  if (ps->do_mask_cavity) {
4621  MEM_freeN(ps->cavities);
4622  }
4623 
4624  ps->me_eval = NULL;
4625  }
4626 
4627  if (ps->blurkernel) {
4629  MEM_freeN(ps->blurkernel);
4630  }
4631 
4632  if (ps->vertFlags) {
4633  MEM_freeN(ps->vertFlags);
4634  }
4635 
4636  for (a = 0; a < ps->thread_tot; a++) {
4638  }
4639 }
4640 
4641 /* 1 = an undo, -1 is a redo. */
4643 {
4645 }
4646 
4648 {
4649  int tot = PROJ_BOUNDBOX_SQUARED;
4650  while (tot--) {
4652  pr++;
4653  }
4654 }
4655 
4657  ImagePaintPartialRedraw *pr_other,
4658  int tot)
4659 {
4660  bool touch = false;
4661  while (tot--) {
4663  if (!BLI_rcti_is_empty(&pr->dirty_region)) {
4664  touch = true;
4665  }
4666 
4667  pr++;
4668  pr_other++;
4669  }
4670 
4671  return touch;
4672 }
4673 
4674 /* Loop over all images on this mesh and update any we have touched */
4676 {
4678  ProjPaintImage *projIma;
4679  int a, i;
4680  bool redraw = false;
4681 
4682  for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
4683  if (projIma->touch) {
4684  /* look over each bound cell */
4685  for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
4686  pr = &(projIma->partRedrawRect[i]);
4687  if (BLI_rcti_is_valid(&pr->dirty_region)) {
4688  set_imapaintpartial(pr);
4689  imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
4690  redraw = 1;
4691  }
4692 
4694  }
4695 
4696  /* clear for reuse */
4697  projIma->touch = 0;
4698  }
4699  }
4700 
4701  return redraw;
4702 }
4703 
4704 /* run this per painting onto each mouse location */
4705 static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
4706 {
4707  if (ps->source == PROJ_SRC_VIEW) {
4708  float min_brush[2], max_brush[2];
4709  const float radius = ps->brush_size;
4710 
4711  /* so we don't have a bucket bounds that is way too small to paint into */
4712 #if 0
4713  /* This doesn't work yet. */
4714  if (radius < 1.0f) {
4715  radius = 1.0f;
4716  }
4717 #endif
4718 
4719  min_brush[0] = mval_f[0] - radius;
4720  min_brush[1] = mval_f[1] - radius;
4721 
4722  max_brush[0] = mval_f[0] + radius;
4723  max_brush[1] = mval_f[1] + radius;
4724 
4725  /* offset to make this a valid bucket index */
4726  project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
4727 
4728  /* mouse outside the model areas? */
4729  if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) {
4730  return false;
4731  }
4732  }
4733  else { /* reproject: PROJ_SRC_* */
4734  ps->bucketMin[0] = 0;
4735  ps->bucketMin[1] = 0;
4736 
4737  ps->bucketMax[0] = ps->buckets_x;
4738  ps->bucketMax[1] = ps->buckets_y;
4739  }
4740 
4741  ps->context_bucket_index = ps->bucketMin[0] + ps->bucketMin[1] * ps->buckets_x;
4742  return true;
4743 }
4744 
4746  int *bucket_index,
4747  rctf *bucket_bounds,
4748  const float mval[2])
4749 {
4750  const int diameter = 2 * ps->brush_size;
4751 
4752  const int max_bucket_idx = ps->bucketMax[0] + (ps->bucketMax[1] - 1) * ps->buckets_x;
4753 
4754  for (int bidx = atomic_fetch_and_add_int32(&ps->context_bucket_index, 1); bidx < max_bucket_idx;
4756  const int bucket_y = bidx / ps->buckets_x;
4757  const int bucket_x = bidx - (bucket_y * ps->buckets_x);
4758 
4759  BLI_assert(bucket_y >= ps->bucketMin[1] && bucket_y < ps->bucketMax[1]);
4760  if (bucket_x >= ps->bucketMin[0] && bucket_x < ps->bucketMax[0]) {
4761  /* Use bucket_bounds for #project_bucket_isect_circle and #project_bucket_init. */
4762  project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
4763 
4764  if ((ps->source != PROJ_SRC_VIEW) ||
4765  project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds)) {
4766  *bucket_index = bidx;
4767 
4768  return true;
4769  }
4770  }
4771  }
4772 
4773  return false;
4774 }
4775 
4776 /* Each thread gets one of these, also used as an argument to pass to project_paint_op */
4777 typedef struct ProjectHandle {
4778  /* args */
4780  float prevmval[2];
4781  float mval[2];
4782 
4783  /* Annoying but we need to have image bounds per thread,
4784  * then merge into ps->projectPartialRedraws. */
4785 
4786  /* array of partial redraws */
4788 
4789  /* thread settings */
4791 
4792  struct ImagePool *pool;
4794 
4795 static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float mask)
4796 {
4797  const uchar *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
4798 
4799  if (clone_pt[3]) {
4800  uchar clone_rgba[4];
4801 
4802  clone_rgba[0] = clone_pt[0];
4803  clone_rgba[1] = clone_pt[1];
4804  clone_rgba[2] = clone_pt[2];
4805  clone_rgba[3] = (uchar)(clone_pt[3] * mask);
4806 
4807  if (ps->do_masking) {
4809  projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend);
4810  }
4811  else {
4812  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend);
4813  }
4814  }
4815 }
4816 
4817 static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
4818 {
4819  const float *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.f;
4820 
4821  if (clone_pt[3]) {
4822  float clone_rgba[4];
4823 
4824  mul_v4_v4fl(clone_rgba, clone_pt, mask);
4825 
4826  if (ps->do_masking) {
4828  projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend);
4829  }
4830  else {
4831  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend);
4832  }
4833  }
4834 }
4835 
4842  ProjPixel *projPixel,
4843  float mask,
4844  MemArena *smearArena,
4845  LinkNode **smearPixels,
4846  const float co[2])
4847 {
4848  uchar rgba_ub[4];
4849 
4850  if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0) {
4851  return;
4852  }
4853 
4855  ((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, mask);
4856  BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
4857 }
4858 
4860  ProjPixel *projPixel,
4861  float mask,
4862  MemArena *smearArena,
4863  LinkNode **smearPixels_f,
4864  const float co[2])
4865 {
4866  float rgba[4];
4867 
4868  if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0) {
4869  return;
4870  }
4871 
4873  ((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, mask);
4874  BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
4875 }
4876 
4878  ProjPixel *projPixel,
4879  float mask,
4880  MemArena *softenArena,
4881  LinkNode **softenPixels)
4882 {
4883  float accum_tot = 0.0f;
4884  int xk, yk;
4885  BlurKernel *kernel = ps->blurkernel;
4886  float *rgba = projPixel->newColor.f;
4887 
4888  /* rather than painting, accumulate surrounding colors */
4889  zero_v4(rgba);
4890 
4891  for (yk = 0; yk < kernel->side; yk++) {
4892  for (xk = 0; xk < kernel->side; xk++) {
4893  float rgba_tmp[4];
4894  float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
4895 
4896  add_v2_v2(co_ofs, projPixel->projCoSS);
4897 
4898  if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
4899  float weight = kernel->wdata[xk + yk * kernel->side];
4900  mul_v4_fl(rgba_tmp, weight);
4901  add_v4_v4(rgba, rgba_tmp);
4902  accum_tot += weight;
4903  }
4904  }
4905  }
4906 
4907  if (LIKELY(accum_tot != 0)) {
4908  mul_v4_fl(rgba, 1.0f / (float)accum_tot);
4909 
4910  if (ps->mode == BRUSH_STROKE_INVERT) {
4911  /* subtract blurred image from normal image gives high pass filter */
4912  sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba);
4913 
4914  /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
4915  * colored speckles appearing in final image, and also to check for threshold */
4917  if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
4918  float alpha = projPixel->pixel.f_pt[3];
4919  projPixel->pixel.f_pt[3] = rgba[3] = mask;
4920 
4921  /* add to enhance edges */
4922  blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba);
4923  rgba[3] = alpha;
4924  }
4925  else {
4926  return;
4927  }
4928  }
4929  else {
4931  }
4932 
4933  BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
4934  }
4935 }
4936 
4938  ProjPixel *projPixel,
4939  float mask,
4940  MemArena *softenArena,
4941  LinkNode **softenPixels)
4942 {
4943  float accum_tot = 0;
4944  int xk, yk;
4945  BlurKernel *kernel = ps->blurkernel;
4946  /* convert to byte after */
4947  float rgba[4];
4948 
4949  /* rather than painting, accumulate surrounding colors */
4950  zero_v4(rgba);
4951 
4952  for (yk = 0; yk < kernel->side; yk++) {
4953  for (xk = 0; xk < kernel->side; xk++) {
4954  float rgba_tmp[4];
4955  float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
4956 
4957  add_v2_v2(co_ofs, projPixel->projCoSS);
4958 
4959  if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
4960  float weight = kernel->wdata[xk + yk * kernel->side];
4961  mul_v4_fl(rgba_tmp, weight);
4962  add_v4_v4(rgba, rgba_tmp);
4963  accum_tot += weight;
4964  }
4965  }
4966  }
4967 
4968  if (LIKELY(accum_tot != 0)) {
4969  uchar *rgba_ub = projPixel->newColor.ch;
4970 
4971  mul_v4_fl(rgba, 1.0f / (float)accum_tot);
4972 
4973  if (ps->mode == BRUSH_STROKE_INVERT) {
4974  float rgba_pixel[4];
4975 
4976  straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt);
4977 
4978  /* subtract blurred image from normal image gives high pass filter */
4979  sub_v3_v3v3(rgba, rgba_pixel, rgba);
4980  /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
4981  * colored speckles appearing in final image, and also to check for threshold */
4983  if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
4984  float alpha = rgba_pixel[3];
4985  rgba[3] = rgba_pixel[3] = mask;
4986 
4987  /* add to enhance edges */
4988  blend_color_add_float(rgba, rgba_pixel, rgba);
4989 
4990  rgba[3] = alpha;
4992  }
4993  else {
4994  return;
4995  }
4996  }
4997  else {
4999  blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask);
5000  }
5001  BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
5002  }
5003 }
5004 
5006  ProjPixel *projPixel,
5007  const float texrgb[3],
5008  float mask,
5009  float dither,
5010  float u,
5011  float v)
5012 {
5013  float rgb[3];
5014  uchar rgba_ub[4];
5015 
5016  if (ps->is_texbrush) {
5017  mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
5018  /* TODO(sergey): Support texture paint color space. */
5019  if (ps->use_colormanagement) {
5021  }
5022  else {
5023  copy_v3_v3(rgb, rgb);
5024  }
5025  }
5026  else {
5027  copy_v3_v3(rgb, ps->paint_color);
5028  }
5029 
5030  if (dither > 0.0f) {
5031  float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v);
5032  }
5033  else {
5035  }
5036  rgba_ub[3] = f_to_char(mask);
5037 
5038  if (ps->do_masking) {
5039  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
5040  }
5041  else {
5042  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
5043  }
5044 }
5045 
5047  ProjPixel *projPixel,
5048  const float texrgb[3],
5049  float mask)
5050 {
5051  float rgba[4];
5052 
5054 
5055  if (ps->is_texbrush) {
5056  mul_v3_v3(rgba, texrgb);
5057  }
5058 
5059  mul_v3_fl(rgba, mask);
5060  rgba[3] = mask;
5061 
5062  if (ps->do_masking) {
5063  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
5064  }
5065  else {
5066  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
5067  }
5068 }
5069 
5070 static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
5071 {
5072  uchar rgba_ub[4];
5073  rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
5074  rgba_ub[3] = f_to_char(mask);
5075 
5076  if (ps->do_masking) {
5077  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
5078  }
5079  else {
5080  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
5081  }
5082 }
5083 
5084 static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
5085 {
5086  float rgba[4];
5087  rgba[0] = rgba[1] = rgba[2] = ps->stencil_value;
5088  rgba[3] = mask;
5089 
5090  if (ps->do_masking) {
5091  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
5092  }
5093  else {
5094  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
5095  }
5096 }
5097 
5099  const ProjPixel *projPixel)
5100 {
5101  rcti rect_to_add;
5102  BLI_rcti_init(
5103  &rect_to_add, projPixel->x_px, projPixel->x_px + 1, projPixel->y_px, projPixel->y_px + 1);
5104  BLI_rcti_do_minmax_rcti(&cell->dirty_region, &rect_to_add);
5105 }
5106 
5107 static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
5108 {
5109  /* Use the original alpha channel data instead of the modified one */
5110  if (is_floatbuf) {
5111  /* slightly more involved case since floats are in premultiplied space we need
5112  * to make sure alpha is consistent, see T44627 */
5113  float rgb_straight[4];
5114  premul_to_straight_v4_v4(rgb_straight, pixel->pixel.f_pt);
5115  rgb_straight[3] = pixel->origColor.f_pt[3];
5116  straight_to_premul_v4_v4(pixel->pixel.f_pt, rgb_straight);
5117  }
5118  else {
5119  pixel->pixel.ch_pt[3] = pixel->origColor.ch_pt[3];
5120  }
5121 }
5122 
5123 /* Run this for single and multi-threaded painting. */
5124 static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v)
5125 {
5126  /* First unpack args from the struct */
5127  ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
5128  ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
5129  const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
5130  const float *pos = ((ProjectHandle *)ph_v)->mval;
5131  const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
5132  struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
5133  /* Done with args from ProjectHandle */
5134 
5135  LinkNode *node;
5136  ProjPixel *projPixel;
5137  Brush *brush = ps->brush;
5138 
5139  int last_index = -1;
5140  ProjPaintImage *last_projIma = NULL;
5141  ImagePaintPartialRedraw *last_partial_redraw_cell;
5142 
5143  float dist_sq, dist;
5144 
5145  float falloff;
5146  int bucket_index;
5147  bool is_floatbuf = false;
5148  const short tool = ps->tool;
5149  rctf bucket_bounds;
5150 
5151  /* for smear only */
5152  float pos_ofs[2] = {0};
5153  float co[2];
5154  ushort mask_short;
5155  const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
5156  const float brush_radius = ps->brush_size;
5157  /* avoid a square root with every dist comparison */
5158  const float brush_radius_sq = brush_radius * brush_radius;
5159 
5160  const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
5161  0 :
5162  (brush->flag & BRUSH_LOCK_ALPHA) != 0;
5163 
5164  LinkNode *smearPixels = NULL;
5165  LinkNode *smearPixels_f = NULL;
5166  /* mem arena for this brush projection only */
5167  MemArena *smearArena = NULL;
5168 
5169  LinkNode *softenPixels = NULL;
5170  LinkNode *softenPixels_f = NULL;
5171  /* mem arena for this brush projection only */
5172  MemArena *softenArena = NULL;
5173 
5174  if (tool == PAINT_TOOL_SMEAR) {
5175  pos_ofs[0] = pos[0] - lastpos[0];
5176  pos_ofs[1] = pos[1] - lastpos[1];
5177 
5178  smearArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint smear arena");
5179  }
5180  else if (tool == PAINT_TOOL_SOFTEN) {
5181  softenArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint soften arena");
5182  }
5183 
5184  // printf("brush bounds %d %d %d %d\n",
5185  // bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]);
5186 
5187  while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
5188 
5189  /* Check this bucket and its faces are initialized */
5190  if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
5191  rctf clip_rect = bucket_bounds;
5192  clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
5193  clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
5194  clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
5195  clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
5196  /* No pixels initialized */
5197  project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
5198  }
5199 
5200  if (ps->source != PROJ_SRC_VIEW) {
5201 
5202  /* Re-Projection, simple, no brushes! */
5203 
5204  for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
5205  projPixel = (ProjPixel *)node->link;
5206 
5207  /* copy of code below */
5208  if (last_index != projPixel->image_index) {
5209  last_index = projPixel->image_index;
5210  last_projIma = projImages + last_index;
5211 
5212  last_projIma->touch = 1;
5213  is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
5214  }
5215  /* end copy */
5216 
5217  /* fill tools */
5218  if (ps->source == PROJ_SRC_VIEW_FILL) {
5219  if (brush->flag & BRUSH_USE_GRADIENT) {
5220  /* these could probably be cached instead of being done per pixel */
5221  float tangent[2];
5222  float line_len_sq_inv, line_len;
5223  float f;
5224  float color_f[4];
5225  const float p[2] = {
5226  projPixel->projCoSS[0] - lastpos[0],
5227  projPixel->projCoSS[1] - lastpos[1],
5228  };
5229 
5230  sub_v2_v2v2(tangent, pos, lastpos);
5231  line_len = len_squared_v2(tangent);
5232  line_len_sq_inv = 1.0f / line_len;
5233  line_len = sqrtf(line_len);
5234 
5235  switch (brush->gradient_fill_mode) {
5236  case BRUSH_GRADIENT_LINEAR: {
5237  f = dot_v2v2(p, tangent) * line_len_sq_inv;
5238  break;
5239  }
5240  case BRUSH_GRADIENT_RADIAL:
5241  default: {
5242  f = len_v2(p) / line_len;
5243  break;
5244  }
5245  }
5246  BKE_colorband_evaluate(brush->gradient, f, color_f);
5247  color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush_alpha;
5248 
5249  if (is_floatbuf) {
5250  /* Convert to premutliplied. */
5251  mul_v3_fl(color_f, color_f[3]);
5253  projPixel->pixel.f_pt, projPixel->origColor.f_pt, color_f, ps->blend);
5254  }
5255  else {
5256  linearrgb_to_srgb_v3_v3(color_f, color_f);
5257 
5258  if (ps->dither > 0.0f) {
5260  projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px);
5261  }
5262  else {
5263  unit_float_to_uchar_clamp_v3(projPixel->newColor.ch, color_f);
5264  }
5265  projPixel->newColor.ch[3] = unit_float_to_uchar_clamp(color_f[3]);
5266  IMB_blend_color_byte(projPixel->pixel.ch_pt,
5267  projPixel->origColor.ch_pt,
5268  projPixel->newColor.ch,
5269  ps->blend);
5270  }
5271  }
5272  else {
5273  if (is_floatbuf) {
5274  float newColor_f[4];
5275  newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush_alpha;
5276  copy_v3_v3(newColor_f, ps->paint_color_linear);
5277 
5279  projPixel->pixel.f_pt, projPixel->origColor.f_pt, newColor_f, ps->blend);
5280  }
5281  else {
5282  float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5283  projPixel->newColor.ch[3] = mask * 255 * brush_alpha;
5284 
5285  rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
5286  IMB_blend_color_byte(projPixel->pixel.ch_pt,
5287  projPixel->origColor.ch_pt,
5288  projPixel->newColor.ch,
5289  ps->blend);
5290  }
5291  }
5292 
5293  if (lock_alpha) {
5294  copy_original_alpha_channel(projPixel, is_floatbuf);
5295  }
5296 
5297  last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
5298  image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
5299  }
5300  else {
5301  if (is_floatbuf) {
5303 
5305  NULL,
5306  projPixel->newColor.f,
5307  projPixel->projCoSS[0],
5308  projPixel->projCoSS[1]);
5309  if (projPixel->newColor.f[3]) {
5310  float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5311 
5312  mul_v4_v4fl(projPixel->newColor.f, projPixel->newColor.f, mask);
5313 
5315  projPixel->pixel.f_pt, projPixel->origColor.f_pt, projPixel->newColor.f);
5316  }
5317  }
5318  else {
5320 
5322  projPixel->newColor.ch,
5323  NULL,
5324  projPixel->projCoSS[0],
5325  projPixel->projCoSS[1]);
5326  if (projPixel->newColor.ch[3]) {
5327  float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5328  projPixel->newColor.ch[3] *= mask;
5329 
5331  projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, projPixel->newColor.ch);
5332  }
5333  }
5334  }
5335  }
5336  }
5337  else {
5338  /* Normal brush painting */
5339 
5340  for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
5341 
5342  projPixel = (ProjPixel *)node->link;
5343 
5344  dist_sq = len_squared_v2v2(projPixel->projCoSS, pos);
5345 
5346  /* Faster alternative to `dist < radius` without a #sqrtf. */
5347  if (dist_sq <= brush_radius_sq) {
5348  dist = sqrtf(dist_sq);
5349 
5350  falloff = BKE_brush_curve_strength_clamped(ps->brush, dist, brush_radius);
5351 
5352  if (falloff > 0.0f) {
5353  float texrgb[3];
5354  float mask;
5355 
5356  /* Extra mask for normal, layer stencil, etc. */
5357  float custom_mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5358 
5359  /* Mask texture. */
5360  if (ps->is_maskbrush) {
5361  float texmask = BKE_brush_sample_masktex(
5362  ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
5363  CLAMP(texmask, 0.0f, 1.0f);
5364  custom_mask *= texmask;
5365  }
5366 
5367  /* Color texture (alpha used as mask). */
5368  if (ps->is_texbrush) {
5369  MTex *mtex = &brush->mtex;
5370  float samplecos[3];
5371  float texrgba[4];
5372 
5373  /* taking 3d copy to account for 3D mapping too.
5374  * It gets concatenated during sampling */
5375  if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
5376  copy_v3_v3(samplecos, projPixel->worldCoSS);
5377  }
5378  else {
5379  copy_v2_v2(samplecos, projPixel->projCoSS);
5380  samplecos[2] = 0.0f;
5381  }
5382 
5383  /* NOTE: for clone and smear,
5384  * we only use the alpha, could be a special function */
5385  BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
5386 
5387  copy_v3_v3(texrgb, texrgba);
5388  custom_mask *= texrgba[3];
5389  }
5390  else {
5391  zero_v3(texrgb);
5392  }
5393 
5394  if (ps->do_masking) {
5395  /* masking to keep brush contribution to a pixel limited. note we do not do
5396  * a simple max(mask, mask_accum), as this is very sensitive to spacing and
5397  * gives poor results for strokes crossing themselves.
5398  *
5399  * Instead we use a formula that adds up but approaches brush_alpha slowly
5400  * and never exceeds it, which gives nice smooth results. */
5401  float mask_accum = *projPixel->mask_accum;
5402  float max_mask = brush_alpha * custom_mask * falloff * 65535.0f;
5403 
5404  if (brush->flag & BRUSH_ACCUMULATE) {
5405  mask = mask_accum + max_mask;
5406  }
5407  else {
5408  mask = mask_accum + (max_mask - mask_accum * falloff);
5409  }
5410 
5411  mask = min_ff(mask, 65535.0f);
5412  mask_short = (ushort)mask;
5413 
5414  if (mask_short > *projPixel->mask_accum) {
5415  *projPixel->mask_accum = mask_short;
5416  mask = mask_short * (1.0f / 65535.0f);
5417  }
5418  else {
5419  /* Go onto the next pixel */
5420  continue;
5421  }
5422  }
5423  else {
5424  mask = brush_alpha * custom_mask * falloff;
5425  }
5426 
5427  if (mask > 0.0f) {
5428 
5429  /* copy of code above */
5430  if (last_index != projPixel->image_index) {
5431  last_index = projPixel->image_index;
5432  last_projIma = projImages + last_index;
5433 
5434  last_projIma->touch = 1;
5435  is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
5436  }
5437  /* end copy */
5438 
5439  /* Validate undo tile, since we will modify it. */
5440  *projPixel->valid = true;
5441 
5442  last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
5443  image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
5444 
5445  /* texrgb is not used for clone, smear or soften */
5446  switch (tool) {
5447  case PAINT_TOOL_CLONE:
5448  if (is_floatbuf) {
5449  do_projectpaint_clone_f(ps, projPixel, mask);
5450  }
5451  else {
5452  do_projectpaint_clone(ps, projPixel, mask);
5453  }
5454  break;
5455  case PAINT_TOOL_SMEAR:
5456  sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
5457 
5458  if (is_floatbuf) {
5459  do_projectpaint_smear_f(ps, projPixel, mask, smearArena, &smearPixels_f, co);
5460  }
5461  else {
5462  do_projectpaint_smear(ps, projPixel, mask, smearArena, &smearPixels, co);
5463  }
5464  break;
5465  case PAINT_TOOL_SOFTEN:
5466  if (is_floatbuf) {
5467  do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
5468  }
5469  else {
5470  do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
5471  }
5472  break;
5473  case PAINT_TOOL_MASK:
5474  if (is_floatbuf) {
5475  do_projectpaint_mask_f(ps, projPixel, mask);
5476  }
5477  else {
5478  do_projectpaint_mask(ps, projPixel, mask);
5479  }
5480  break;
5481  default:
5482  if (is_floatbuf) {
5483  do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
5484  }
5485  else {
5487  ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
5488  }
5489  break;
5490  }
5491 
5492  if (lock_alpha) {
5493  copy_original_alpha_channel(projPixel, is_floatbuf);
5494  }
5495  }
5496 
5497  /* done painting */
5498  }
5499  }
5500  }
5501  }
5502  }
5503 
5504  if (tool == PAINT_TOOL_SMEAR) {
5505 
5506  for (node = smearPixels; node; node = node->next) { /* this won't run for a float image */
5507  projPixel = node->link;
5508  *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
5509  if (lock_alpha) {
5510  copy_original_alpha_channel(projPixel, false);
5511  }
5512  }
5513 
5514  for (node = smearPixels_f; node; node = node->next) {
5515  projPixel = node->link;
5516  copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
5517  if (lock_alpha) {
5518  copy_original_alpha_channel(projPixel, true);
5519  }
5520  }
5521 
5522  BLI_memarena_free(smearArena);
5523  }
5524  else if (tool == PAINT_TOOL_SOFTEN) {
5525 
5526  for (node = softenPixels; node; node = node->next) { /* this won't run for a float image */
5527  projPixel = node->link;
5528  *projPixel->pixel.uint_pt = projPixel->newColor.uint;
5529  if (lock_alpha) {
5530  copy_original_alpha_channel(projPixel, false);
5531  }
5532  }
5533 
5534  for (node = softenPixels_f; node; node = node->next) {
5535  projPixel = node->link;
5536  copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f);
5537  if (lock_alpha) {
5538  copy_original_alpha_channel(projPixel, true);
5539  }
5540  }
5541 
5542  BLI_memarena_free(softenArena);
5543  }
5544 }
5545 
5546 static bool project_paint_op(void *state, const float lastpos[2], const float pos[2])
5547 {
5548  /* First unpack args from the struct */
5550  bool touch_any = false;
5551 
5553  TaskPool *task_pool = NULL;
5554  int a, i;
5555 
5556  struct ImagePool *image_pool;
5557 
5558  if (!project_bucket_iter_init(ps, pos)) {
5559  return touch_any;
5560  }
5561 
5562  if (ps->thread_tot > 1) {
5564  }
5565 
5566  image_pool = BKE_image_pool_new();
5567 
5569  /* This means we are reprojecting an image, make sure the image has the needed data available.
5570  */
5571  bool float_dest = false;
5572  bool uchar_dest = false;
5573  /* Check if the destination images are float or uchar. */
5574  for (i = 0; i < ps->image_tot; i++) {
5575  if (ps->projImages[i].ibuf->rect != NULL) {
5576  uchar_dest = true;
5577  }
5578  if (ps->projImages[i].ibuf->rect_float != NULL) {
5579  float_dest = true;
5580  }
5581  }
5582 
5583  /* Generate missing data if needed. */
5584  if (float_dest && ps->reproject_ibuf->rect_float == NULL) {
5586  ps->reproject_ibuf_free_float = true;
5587  }
5588  if (uchar_dest && ps->reproject_ibuf->rect == NULL) {
5590  ps->reproject_ibuf_free_uchar = true;
5591  }
5592  }
5593 
5594  /* get the threads running */
5595  for (a = 0; a < ps->thread_tot; a++) {
5596 
5597  /* set defaults in handles */
5598  // memset(&handles[a], 0, sizeof(BakeShade));
5599 
5600  handles[a].ps = ps;
5601  copy_v2_v2(handles[a].mval, pos);
5602  copy_v2_v2(handles[a].prevmval, lastpos);
5603 
5604  /* thread specific */
5605  handles[a].thread_index = a;
5606 
5607  handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a],
5608  ps->image_tot * sizeof(ProjPaintImage));
5609 
5610  memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
5611 
5612  /* image bounds */
5613  for (i = 0; i < ps->image_tot; i++) {
5614  handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(
5616  memcpy(handles[a].projImages[i].partRedrawRect,
5617  ps->projImages[i].partRedrawRect,
5619  }
5620 
5621  handles[a].pool = image_pool;
5622 
5623  if (task_pool != NULL) {
5625  }
5626  }
5627 
5628  if (task_pool != NULL) { /* wait for everything to be done */
5631  }
5632  else {
5634  }
5635 
5636  BKE_image_pool_free(image_pool);
5637 
5638  /* move threaded bounds back into ps->projectPartialRedraws */
5639  for (i = 0; i < ps->image_tot; i++) {
5640  int touch = 0;
5641  for (a = 0; a < ps->thread_tot; a++) {
5643  handles[a].projImages[i].partRedrawRect,
5645  }
5646 
5647  if (touch) {
5648  ps->projImages[i].touch = 1;
5649  touch_any = 1;
5650  }
5651  }
5652 
5653  /* Calculate pivot for rotation around selection if needed. */
5654  if (U.uiflag & USER_ORBIT_SELECTION) {
5655  float w[3];
5656  int tri_index;
5657 
5658  tri_index = project_paint_PickFace(ps, pos, w);
5659 
5660  if (tri_index != -1) {
5661  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
5662  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
5663  float world[3];
5665 
5667  ps->mvert_eval[lt_vtri[0]].co,
5668  ps->mvert_eval[lt_vtri[1]].co,
5669  ps->mvert_eval[lt_vtri[2]].co,
5670  w);
5671 
5672  ups->average_stroke_counter++;
5673  mul_m4_v3(ps->obmat, world);
5675  ups->last_stroke_valid = true;
5676  }
5677  }
5678 
5679  return touch_any;
5680 }
5681 
5683  void *ps_handle_p,
5684  const float prev_pos[2],
5685  const float pos[2],
5686  const bool eraser,
5687  float pressure,
5688  float distance,
5689  float size,
5690  /* extra view */
5691  ProjPaintState *ps)
5692 {
5693  ProjStrokeHandle *ps_handle = ps_handle_p;
5694  Brush *brush = ps->brush;
5695  Scene *scene = ps->scene;
5696 
5697  ps->brush_size = size;
5698  ps->blend = brush->blend;
5699  if (eraser) {
5701  }
5702 
5703  /* handle gradient and inverted stroke color here */
5706  brush,
5707  false,
5708  ps->mode == BRUSH_STROKE_INVERT,
5709  distance,
5710  pressure,
5711  ps->paint_color,
5712  NULL);
5713  if (ps->use_colormanagement) {
5715  }
5716  else {
5718  }
5719  }
5720  else if (ps->tool == PAINT_TOOL_MASK) {
5721  ps->stencil_value = brush->weight;
5722 
5723  if ((ps->mode == BRUSH_STROKE_INVERT) ^
5725  ps->stencil_value = 1.0f - ps->stencil_value;
5726  }
5727  }
5728 
5729  if (project_paint_op(ps, prev_pos, pos)) {
5730  ps_handle->need_redraw = true;
5732  }
5733 }
5734 
5736  void *ps_handle_p,
5737  const float prev_pos[2],
5738  const float pos[2],
5739  const bool eraser,
5740  float pressure,
5741  float distance,
5742  float size)
5743 {
5744  int i;
5745  ProjStrokeHandle *ps_handle = ps_handle_p;
5746 
5747  /* clone gets special treatment here to avoid going through image initialization */
5748  if (ps_handle->is_clone_cursor_pick) {
5749  Scene *scene = ps_handle->scene;
5751  View3D *v3d = CTX_wm_view3d(C);
5752  ARegion *region = CTX_wm_region(C);
5753  float *cursor = scene->cursor.location;
5754  const int mval_i[2] = {(int)pos[0], (int)pos[1]};
5755 
5757 
5758  if (!ED_view3d_autodist(depsgraph, region, v3d, mval_i, cursor, false, NULL)) {
5759  return;
5760  }
5761 
5763  ED_region_tag_redraw(region);
5764 
5765  return;
5766  }
5767 
5768  for (i = 0; i < ps_handle->ps_views_tot; i++) {
5769  ProjPaintState *ps = ps_handle->ps_views[i];
5770  paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
5771  }
5772 }
5773 
5774 /* initialize project paint settings from context */
5775 static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int mode)
5776 {
5778  ToolSettings *settings = scene->toolsettings;
5779 
5780  /* brush */
5781  ps->mode = mode;
5782  ps->brush = BKE_paint_brush(&settings->imapaint.paint);
5783  if (ps->brush) {
5784  Brush *brush = ps->brush;
5785  ps->tool = brush->imagepaint_tool;
5786  ps->blend = brush->blend;
5787  /* only check for inversion for the soften tool, elsewhere,
5788  * a resident brush inversion flag can cause issues */
5789  if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
5790  ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
5793 
5794  ps->blurkernel = paint_new_blur_kernel(brush, true);
5795  }
5796 
5797  /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
5799  ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true :
5800  false;
5801  ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
5802  }
5803  else {
5804  /* Brush may be NULL. */
5805  ps->do_masking = false;
5806  ps->is_texbrush = false;
5807  ps->is_maskbrush = false;
5808  }
5809 
5810  /* sizeof(ProjPixel), since we alloc this a _lot_ */
5812  BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
5813 
5814  /* these can be NULL */
5815  ps->v3d = CTX_wm_view3d(C);
5816  ps->rv3d = CTX_wm_region_view3d(C);
5817  ps->region = CTX_wm_region(C);
5818 
5820  ps->scene = scene;
5821  /* allow override of active object */
5822  ps->ob = ob;
5823 
5825  ps->stencil_ima = settings->imapaint.stencil;
5826  ps->canvas_ima = (!ps->do_material_slots) ? settings->imapaint.canvas : NULL;
5827  ps->clone_ima = (!ps->do_material_slots) ? settings->imapaint.clone : NULL;
5828 
5829  ps->do_mask_cavity = (settings->imapaint.paint.flags & PAINT_USE_CAVITY_MASK) ? true : false;
5830  ps->cavity_curve = settings->imapaint.paint.cavity_curve;
5831 
5832  /* setup projection painting data */
5833  if (ps->tool != PAINT_TOOL_FILL) {
5834  ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? false : true;
5835  ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? false : true;
5836  ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? false : true;
5837  }
5838  else {
5839  ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
5840  }
5841 
5842  if (ps->tool == PAINT_TOOL_CLONE) {
5843  ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
5844  }
5845 
5847  /* deactivate stenciling for the stencil brush :) */
5849  !(ps->do_stencil_brush) && ps->stencil_ima);
5851  0);
5852 
5853 #ifndef PROJ_DEBUG_NOSEAMBLEED
5854  /* pixel num to bleed */
5855  ps->seam_bleed_px = settings->imapaint.seam_bleed;
5856  ps->seam_bleed_px_sq = square_s(settings->imapaint.seam_bleed);
5857 #endif
5858 
5859  if (ps->do_mask_normal) {
5860  ps->normal_angle_inner = settings->imapaint.normal_angle;
5861  ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
5862  }
5863  else {
5864  ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle;
5865  }
5866 
5867  ps->normal_angle_inner *= (float)(M_PI_2 / 90);
5868  ps->normal_angle *= (float)(M_PI_2 / 90);
5870 
5871  if (ps->normal_angle_range <= 0.0f) {
5872  /* no need to do blending */
5873  ps->do_mask_normal = false;
5874  }
5875 
5876  ps->normal_angle__cos = cosf(ps->normal_angle);
5878 
5879  ps->dither = settings->imapaint.dither;
5880 
5882 }
5883 
5884 void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
5885 {
5886  ProjStrokeHandle *ps_handle;
5888  ToolSettings *settings = scene->toolsettings;
5889  char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
5890 
5891  ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
5892  ps_handle->scene = scene;
5893  ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
5894 
5895  /* bypass regular stroke logic */
5896  if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) && (mode == BRUSH_STROKE_INVERT)) {
5898  ps_handle->is_clone_cursor_pick = true;
5899  return ps_handle;
5900  }
5901 
5902  ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
5903 
5905  ps_handle->symmetry_flags = mesh->symmetry;
5906  ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
5907  bool is_multi_view = (ps_handle->ps_views_tot != 1);
5908 
5909  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5910  ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
5911  ps_handle->ps_views[i] = ps;
5912  }
5913 
5914  if (ps_handle->symmetry_flags) {
5915  int index = 0;
5916 
5917  int x = 0;
5918  do {
5919  int y = 0;
5920  do {
5921  int z = 0;
5922  do {
5923  symmetry_flag_views[index++] = ((x ? PAINT_SYMM_X : 0) | (y ? PAINT_SYMM_Y : 0) |
5924  (z ? PAINT_SYMM_Z : 0));
5925  BLI_assert(index <= ps_handle->ps_views_tot);
5926  } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
5927  } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
5928  } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
5929  BLI_assert(index == ps_handle->ps_views_tot);
5930  }
5931 
5932  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5933  ProjPaintState *ps = ps_handle->ps_views[i];
5934 
5935  project_state_init(C, ob, ps, mode);
5936 
5937  if (ps->ob == NULL) {
5938  ps_handle->ps_views_tot = i + 1;
5939  goto fail;
5940  }
5941  }
5942 
5943  /* Don't allow brush size below 2 */
5944  if (BKE_brush_size_get(scene, ps_handle->brush) < 2) {
5945  BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
5946  }
5947 
5948  /* allocate and initialize spatial data structures */
5949 
5950  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5951  ProjPaintState *ps = ps_handle->ps_views[i];
5952 
5955 
5956  /* re-use! */
5957  if (i != 0) {
5958  ps->is_shared_user = true;
5959  PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
5960  }
5961 
5962  project_paint_begin(C, ps, is_multi_view, symmetry_flag_views[i]);
5963  if (ps->me_eval == NULL) {
5964  goto fail;
5965  }
5966 
5967  paint_proj_begin_clone(ps, mouse);
5968  }
5969 
5970  paint_brush_init_tex(ps_handle->brush);
5971 
5972  return ps_handle;
5973 
5974 fail:
5975  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5976  ProjPaintState *ps = ps_handle->ps_views[i];
5977  MEM_freeN(ps);
5978  }
5979  MEM_freeN(ps_handle);
5980  return NULL;
5981 }
5982 
5983 void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
5984 {
5985  ProjStrokeHandle *ps_handle = ps_handle_p;
5986 
5987  if (ps_handle->need_redraw) {
5988  ps_handle->need_redraw = false;
5989  }
5990  else if (!final) {
5991  return;
5992  }
5993 
5994  if (final) {
5995  /* compositor listener deals with updating */
5997  }
5998  else {
6000  }
6001 }
6002 
6003 void paint_proj_stroke_done(void *ps_handle_p)
6004 {
6005  ProjStrokeHandle *ps_handle = ps_handle_p;
6006  Scene *scene = ps_handle->scene;
6007 
6008  if (ps_handle->is_clone_cursor_pick) {
6009  MEM_freeN(ps_handle);
6010  return;
6011  }
6012 
6013  for (int i = 1; i < ps_handle->ps_views_tot; i++) {
6014  PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
6015  }
6016 
6017  BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
6018 
6019  paint_brush_exit_tex(ps_handle->brush);
6020 
6021  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
6022  ProjPaintState *ps;
6023  ps = ps_handle->ps_views[i];
6024  project_paint_end(ps);
6025  MEM_freeN(ps);
6026  }
6027 
6028  MEM_freeN(ps_handle);
6029 }
6030 /* use project paint to re-apply an image */
6032 {
6033  Main *bmain = CTX_data_main(C);
6034  Image *image = BLI_findlink(&bmain->images, RNA_enum_get(op->ptr, "image"));
6036  ViewLayer *view_layer = CTX_data_view_layer(C);
6037  ProjPaintState ps = {NULL};
6038  int orig_brush_size;
6039  IDProperty *idgroup;
6040  IDProperty *view_data = NULL;
6041  Object *ob = OBACT(view_layer);
6042  bool uvs, mat, tex;
6043 
6044  if (ob == NULL || ob->type != OB_MESH) {
6045  BKE_report(op->reports, RPT_ERROR, "No active mesh object");
6046  return OPERATOR_CANCELLED;
6047  }
6048 
6049  if (!ED_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
6050  ED_paint_data_warning(op->reports, uvs, mat, tex, true);
6052  return OPERATOR_CANCELLED;
6053  }
6054 
6056 
6057  if (image == NULL) {
6058  BKE_report(op->reports, RPT_ERROR, "Image could not be found");
6059  return OPERATOR_CANCELLED;
6060  }
6061 
6062  ps.reproject_image = image;
6064 
6065  if ((ps.reproject_ibuf == NULL) ||
6066  ((ps.reproject_ibuf->rect || ps.reproject_ibuf->rect_float) == false)) {
6067  BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
6068  return OPERATOR_CANCELLED;
6069  }
6070 
6071  idgroup = IDP_GetProperties(&image->id, 0);
6072 
6073  if (idgroup) {
6075 
6076  /* type check to make sure its ok */
6077  if (view_data != NULL &&
6078  (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT)) {
6079  BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
6080  return OPERATOR_CANCELLED;
6081  }
6082  }
6083 
6084  if (view_data) {
6085  /* image has stored view projection info */
6087  }
6088  else {
6090 
6091  if (scene->camera == NULL) {
6092  BKE_report(op->reports, RPT_ERROR, "No active camera set");
6093  return OPERATOR_CANCELLED;
6094  }
6095  }
6096 
6097  /* override */
6098  ps.is_texbrush = false;
6099  ps.is_maskbrush = false;
6100  ps.do_masking = false;
6101  orig_brush_size = BKE_brush_size_get(scene, ps.brush);
6102  /* cover the whole image */
6103  BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize);
6104 
6105  /* so pixels are initialized with minimal info */
6106  ps.tool = PAINT_TOOL_DRAW;
6107 
6109 
6110  /* allocate and initialize spatial data structures */
6111  project_paint_begin(C, &ps, false, 0);
6112 
6113  if (ps.me_eval == NULL) {
6114  BKE_brush_size_set(scene, ps.brush, orig_brush_size);
6115  BKE_report(op->reports, RPT_ERROR, "Could not get valid evaluated mesh");
6116  return OPERATOR_CANCELLED;
6117  }
6118 
6120 
6121  const float pos[2] = {0.0, 0.0};
6122  const float lastpos[2] = {0.0, 0.0};
6123  int a;
6124 
6125  project_paint_op(&ps, lastpos, pos);
6126 
6128 
6129  for (a = 0; a < ps.image_tot; a++) {
6132  }
6133 
6134  project_paint_end(&ps);
6135 
6137 
6139  BKE_brush_size_set(scene, ps.brush, orig_brush_size);
6140 
6141  return OPERATOR_FINISHED;
6142 }
6143 
6145 {
6146  PropertyRNA *prop;
6147 
6148  /* identifiers */
6149  ot->name = "Project Image";
6150  ot->idname = "PAINT_OT_project_image";
6151  ot->description = "Project an edited render from the active camera back onto the object";
6152 
6153  /* api callbacks */
6156 
6157  /* flags */
6159 
6160  prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
6163  ot->prop = prop;
6164 }
6165 
6167 {
6168  bScreen *screen = CTX_wm_screen(C);
6169  if (!(screen && BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0))) {
6170  CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from");
6171  return false;
6172  }
6173  if (G.background || !GPU_is_init()) {
6174  return false;
6175  }
6176  return true;
6177 }
6178 
6180 {
6181  Image *image;
6182  ImBuf *ibuf;
6183  char filename[FILE_MAX];
6184 
6185  Main *bmain = CTX_data_main(C);
6188  ToolSettings *settings = scene->toolsettings;
6189  int w = settings->imapaint.screen_grab_size[0];
6190  int h = settings->imapaint.screen_grab_size[1];
6191  int maxsize;
6192  char err_out[256] = "unknown";
6193 
6195  if (!area) {
6196  BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
6197  return OPERATOR_CANCELLED;
6198  }
6199 
6201  if (!region) {
6202  BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
6203  return OPERATOR_CANCELLED;
6204  }
6205  RegionView3D *rv3d = region->regiondata;
6206 
6207  RNA_string_get(op->ptr, "filepath", filename);
6208 
6209  maxsize = GPU_max_texture_size();
6210 
6211  if (w > maxsize) {
6212  w = maxsize;
6213  }
6214  if (h > maxsize) {
6215  h = maxsize;
6216  }
6217 
6218  /* Create a copy of the overlays where they are all turned off, except the
6219  * texture paint overlay opacity */
6220  View3D *v3d = area->spacedata.first;
6221  View3D v3d_copy = *v3d;
6222  v3d_copy.gridflag = 0;
6223  v3d_copy.flag2 = 0;
6224  v3d_copy.flag = V3D_HIDE_HELPLINES;
6225  v3d_copy.gizmo_flag = V3D_GIZMO_HIDE;
6226 
6227  memset(&v3d_copy.overlay, 0, sizeof(View3DOverlay));
6232 
6234  scene,
6235  v3d_copy.shading.type,
6236  &v3d_copy,
6237  region,
6238  w,
6239  h,
6240  IB_rect,
6241  R_ALPHAPREMUL,
6242  NULL,
6243  false,
6244  NULL,
6245  err_out);
6246 
6247  if (!ibuf) {
6248  /* Mostly happens when OpenGL offscreen buffer was failed to create, */
6249  /* but could be other reasons. Should be handled in the future. nazgul */
6250  BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out);
6251  return OPERATOR_CANCELLED;
6252  }
6253 
6254  image = BKE_image_add_from_imbuf(bmain, ibuf, "image_view");
6255 
6256  /* Drop reference to ibuf so that the image owns it */
6257  IMB_freeImBuf(ibuf);
6258 
6259  if (image) {
6260  /* now for the trickiness. store the view projection here!
6261  * re-projection will reuse this */
6262  IDPropertyTemplate val;
6263  IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
6264  IDProperty *view_data;
6265  bool is_ortho;
6266  float *array;
6267 
6269  val.array.type = IDP_FLOAT;
6270  view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID);
6271 
6272  array = (float *)IDP_Array(view_data);
6273  memcpy(array, rv3d->winmat, sizeof(rv3d->winmat));
6274  array += sizeof(rv3d->winmat) / sizeof(float);
6275  memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat));
6276  array += sizeof(rv3d->viewmat) / sizeof(float);
6277  is_ortho = ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &array[0], &array[1], true);
6278  /* using float for a bool is dodgy but since its an extra member in the array...
6279  * easier than adding a single bool prop */
6280  array[2] = is_ortho ? 1.0f : 0.0f;
6281 
6282  IDP_AddToGroup(idgroup, view_data);
6283  }
6284 
6285  return OPERATOR_FINISHED;
6286 }
6287 
6289 {
6290  /* identifiers */
6291  ot->name = "Image from View";
6292  ot->idname = "PAINT_OT_image_from_view";
6293  ot->description = "Make an image from biggest 3D view for reprojection";
6294 
6295  /* api callbacks */
6298 
6299  /* flags */
6300  ot->flag = OPTYPE_REGISTER;
6301 
6302  RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file");
6303 }
6304 
6305 /*********************************************
6306  * Data generation for projective texturing *
6307  * *******************************************/
6308 
6309 void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil)
6310 {
6311  BKE_reportf(reports,
6312  RPT_WARNING,
6313  "Missing%s%s%s%s detected!",
6314  !uvs ? " UVs," : "",
6315  !mat ? " Materials," : "",
6316  !tex ? " Textures," : "",
6317  !stencil ? " Stencil," : "");
6318 }
6319 
6321  Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
6322 {
6323  Mesh *me;
6324  int layernum;
6326  Brush *br = BKE_paint_brush(&imapaint->paint);
6327  bool hasmat = true;
6328  bool hastex = true;
6329  bool hasstencil = true;
6330  bool hasuvs = true;
6331 
6332  imapaint->missing_data = 0;
6333 
6334  BLI_assert(ob->type == OB_MESH);
6335 
6336  if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
6337  /* no material, add one */
6338  if (ob->totcol == 0) {
6339  hasmat = false;
6340  hastex = false;
6341  }
6342  else {
6343  /* there may be material slots but they may be empty, check */
6344  hasmat = false;
6345  hastex = false;
6346 
6347  for (int i = 1; i < ob->totcol + 1; i++) {
6348  Material *ma = BKE_object_material_get(ob, i);
6349 
6350  if (ma && !ID_IS_LINKED(ma) && !ID_IS_OVERRIDE_LIBRARY(ma)) {
6351  hasmat = true;
6352  if (ma->texpaintslot == NULL) {
6353  /* refresh here just in case */
6355  }
6356  if (ma->texpaintslot != NULL &&
6357  (ma->texpaintslot[ma->paint_active_slot].ima == NULL ||
6360  hastex = true;
6361  break;
6362  }
6363  }
6364  }
6365  }
6366  }
6367  else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
6368  if (imapaint->canvas == NULL || ID_IS_LINKED(imapaint->canvas)) {
6369  hastex = false;
6370  }
6371  }
6372 
6373  me = BKE_mesh_from_object(ob);
6374  layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
6375 
6376  if (layernum == 0) {
6377  hasuvs = false;
6378  }
6379 
6380  /* Make sure we have a stencil to paint on! */
6381  if (br && br->imagepaint_tool == PAINT_TOOL_MASK) {
6383 
6384  if (imapaint->stencil == NULL) {
6385  hasstencil = false;
6386  }
6387  }
6388 
6389  if (!hasuvs) {
6390  imapaint->missing_data |= IMAGEPAINT_MISSING_UVS;
6391  }
6392  if (!hasmat) {
6394  }
6395  if (!hastex) {
6396  imapaint->missing_data |= IMAGEPAINT_MISSING_TEX;
6397  }
6398  if (!hasstencil) {
6400  }
6401 
6402  if (uvs) {
6403  *uvs = hasuvs;
6404  }
6405  if (mat) {
6406  *mat = hasmat;
6407  }
6408  if (tex) {
6409  *tex = hastex;
6410  }
6411  if (stencil) {
6412  *stencil = hasstencil;
6413  }
6414 
6415  return hasuvs && hasmat && hastex && hasstencil;
6416 }
6417 
6418 /* Add layer operator */
6419 enum {
6427 };
6428 
6430  {LAYER_BASE_COLOR, "BASE_COLOR", 0, "Base Color", ""},
6431  {LAYER_SPECULAR, "SPECULAR", 0, "Specular", ""},
6432  {LAYER_ROUGHNESS, "ROUGHNESS", 0, "Roughness", ""},
6433  {LAYER_METALLIC, "METALLIC", 0, "Metallic", ""},
6434  {LAYER_NORMAL, "NORMAL", 0, "Normal", ""},
6435  {LAYER_BUMP, "BUMP", 0, "Bump", ""},
6436  {LAYER_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
6437  {0, NULL, 0, NULL, NULL},
6438 };
6439 
6441 {
6442  Material *ma = BKE_object_material_get(ob, ob->actcol);
6443  if (!ma) {
6444  Main *bmain = CTX_data_main(C);
6445  ma = BKE_material_add(bmain, "Material");
6447  }
6448  return ma;
6449 }
6450 
6451 static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
6452 {
6453  Image *ima;
6454  float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
6455  char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
6456  int width = 1024;
6457  int height = 1024;
6458  bool use_float = false;
6459  short gen_type = IMA_GENTYPE_BLANK;
6460  bool alpha = false;
6461 
6462  if (op) {
6463  width = RNA_int_get(op->ptr, "width");
6464  height = RNA_int_get(op->ptr, "height");
6465  use_float = RNA_boolean_get(op->ptr, "float");
6466  gen_type = RNA_enum_get(op->ptr, "generated_type");
6467  RNA_float_get_array(op->ptr, "color", color);
6468  alpha = RNA_boolean_get(op->ptr, "alpha");
6469  RNA_string_get(op->ptr, "name", imagename);
6470  }
6471 
6472  /* TODO(lukas): Add option for tiled image. */
6473  ima = BKE_image_add_generated(bmain,
6474  width,
6475  height,
6476  imagename,
6477  alpha ? 32 : 24,
6478  use_float,
6479  gen_type,
6480  color,
6481  false,
6482  is_data,
6483  false);
6484 
6485  return ima;
6486 }
6487 
6489 {
6490  char name[MAX_NAME] = "";
6491  float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
6492  eAttrDomain domain = ATTR_DOMAIN_POINT;
6494 
6495  if (op) {
6496  RNA_string_get(op->ptr, "name", name);
6497  RNA_float_get_array(op->ptr, "color", color);
6498  domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
6499  type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
6500  }
6501 
6502  ID *id = (ID *)ob->data;
6503  CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
6504 
6505  if (!layer) {
6506  return NULL;
6507  }
6508 
6510 
6513  }
6514 
6516 
6517  return layer;
6518 }
6519 
6527 static void default_paint_slot_color_get(int layer_type, Material *ma, float color[4])
6528 {
6529  switch (layer_type) {
6530  case LAYER_BASE_COLOR:
6531  case LAYER_SPECULAR:
6532  case LAYER_ROUGHNESS:
6533  case LAYER_METALLIC: {
6534  bNodeTree *ntree = NULL;
6535  bNode *in_node = ma ? ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED) : NULL;
6536  if (!in_node) {
6537  /* An existing material or Principled BSDF node could not be found.
6538  * Copy default color values from a default Principled BSDF instead. */
6539  ntree = ntreeAddTree(NULL, "Temporary Shader Nodetree", ntreeType_Shader->idname);
6541  }
6542  bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[layer_type].name);
6543  switch (in_sock->type) {
6544  case SOCK_FLOAT: {
6545  bNodeSocketValueFloat *socket_data = in_sock->default_value;
6546  copy_v3_fl(color, socket_data->value);
6547  color[3] = 1.0f;
6548  break;
6549  }
6550  case SOCK_VECTOR:
6551  case SOCK_RGBA: {
6552  bNodeSocketValueRGBA *socket_data = in_sock->default_value;
6553  copy_v3_v3(color, socket_data->value);
6554  color[3] = 1.0f;
6555  break;
6556  }
6557  default:
6559  rgba_float_args_set(color, 0.0f, 0.0f, 0.0f, 1.0f);
6560  break;
6561  }
6562  /* Cleanup */
6563  if (ntree) {
6565  MEM_freeN(ntree);
6566  }
6567  return;
6568  }
6569  case LAYER_NORMAL:
6570  /* Neutral tangent space normal map. */
6571  rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
6572  break;
6573  case LAYER_BUMP:
6574  case LAYER_DISPLACEMENT:
6575  /* Neutral displacement and bump map. */
6576  rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
6577  break;
6578  }
6579 }
6580 
6582 {
6585  Material *ma;
6586  Image *ima = NULL;
6587  CustomDataLayer *layer = NULL;
6588 
6589  if (!ob) {
6590  return false;
6591  }
6592 
6594 
6595  if (ma) {
6596  Main *bmain = CTX_data_main(C);
6597  int type = RNA_enum_get(op->ptr, "type");
6598  bool is_data = (type > LAYER_BASE_COLOR);
6599 
6600  bNode *new_node;
6601  bNodeTree *ntree = ma->nodetree;
6602 
6603  if (!ntree) {
6604  ED_node_shader_default(C, &ma->id);
6605  ntree = ma->nodetree;
6606  }
6607 
6608  ma->use_nodes = true;
6609 
6610  const ePaintCanvasSource slot_type = ob->mode == OB_MODE_SCULPT ?
6612  "slot_type") :
6614 
6615  /* Create a new node. */
6616  switch (slot_type) {
6619  ima = proj_paint_image_create(op, bmain, is_data);
6620  new_node->id = &ima->id;
6621  break;
6622  }
6625  if ((layer = proj_paint_color_attribute_create(op, ob))) {
6627  ((NodeShaderAttribute *)new_node->storage)->name, layer->name, MAX_NAME);
6628  }
6629  break;
6630  }
6633  return false;
6634  }
6635  nodeSetActive(ntree, new_node);
6636 
6637  /* Connect to first available principled BSDF node. */
6639  bNode *out_node = new_node;
6640 
6641  if (in_node != NULL) {
6642  bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
6643  bNodeSocket *in_sock = NULL;
6644 
6645  if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
6646  in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
6647  }
6648  else if (type == LAYER_NORMAL) {
6649  bNode *nor_node;
6651 
6652  in_sock = nodeFindSocket(nor_node, SOCK_IN, "Color");
6653  nodeAddLink(ntree, out_node, out_sock, nor_node, in_sock);
6654 
6655  in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
6656  out_sock = nodeFindSocket(nor_node, SOCK_OUT, "Normal");
6657 
6658  out_node = nor_node;
6659  }
6660  else if (type == LAYER_BUMP) {
6661  bNode *bump_node;
6662  bump_node = nodeAddStaticNode(C, ntree, SH_NODE_BUMP);
6663 
6664  in_sock = nodeFindSocket(bump_node, SOCK_IN, "Height");
6665  nodeAddLink(ntree, out_node, out_sock, bump_node, in_sock);
6666 
6667  in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
6668  out_sock = nodeFindSocket(bump_node, SOCK_OUT, "Normal");
6669 
6670  out_node = bump_node;
6671  }
6672  else if (type == LAYER_DISPLACEMENT) {
6673  /* Connect to the displacement output socket */
6675 
6676  if (in_node != NULL) {
6677  in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
6678  }
6679  else {
6680  in_sock = NULL;
6681  }
6682  }
6683 
6684  /* Check if the socket in already connected to something */
6685  bNodeLink *link = in_sock ? in_sock->link : NULL;
6686  if (in_sock != NULL && link == NULL) {
6687  nodeAddLink(ntree, out_node, out_sock, in_node, in_sock);
6688 
6689  nodePositionRelative(out_node, in_node, out_sock, in_sock);
6690  }
6691  }
6692 
6694  /* In case we added more than one node, position them too. */
6695  nodePositionPropagate(out_node);
6696 
6697  if (ima) {
6701  }
6702  if (layer) {
6706  }
6707 
6708  DEG_id_tag_update(&ntree->id, 0);
6711 
6713 
6714  return true;
6715  }
6716 
6717  return false;
6718 }
6719 
6720 static int get_texture_layer_type(wmOperator *op, const char *prop_name)
6721 {
6722  int type_value = RNA_enum_get(op->ptr, prop_name);
6723  int type = RNA_enum_from_value(layer_type_items, type_value);
6724  BLI_assert(type != -1);
6725  return type;
6726 }
6727 
6729 {
6730  if (proj_paint_add_slot(C, op)) {
6731  return OPERATOR_FINISHED;
6732  }
6733  return OPERATOR_CANCELLED;
6734 }
6735 
6737  int texture_type,
6738  char *dst,
6739  int dst_length)
6740 {
6741  Material *ma = BKE_object_material_get(ob, ob->actcol);
6742  const char *base_name = ma ? &ma->id.name[2] : &ob->id.name[2];
6743  BLI_snprintf(dst, dst_length, "%s %s", base_name, layer_type_items[texture_type].name);
6744 }
6745 
6747  wmOperator *op,
6748  const wmEvent *UNUSED(event))
6749 {
6751  Material *ma = BKE_object_material_get(ob, ob->actcol);
6752 
6753  int type = get_texture_layer_type(op, "type");
6754 
6755  /* Set default name. */
6756  char imagename[MAX_ID_NAME - 2];
6757  get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
6758  RNA_string_set(op->ptr, "name", imagename);
6759 
6760  /* Set default color. Copy the color from nodes, so it matches the existing material. */
6761  float color[4];
6763  RNA_float_set_array(op->ptr, "color", color);
6764 
6765  return WM_operator_props_dialog_popup(C, op, 300);
6766 }
6767 
6769 {
6770  uiLayout *layout = op->layout;
6771  uiLayoutSetPropSep(layout, true);
6772  uiLayoutSetPropDecorate(layout, false);
6775 
6776  if (ob->mode == OB_MODE_SCULPT) {
6777  slot_type = (ePaintCanvasSource)RNA_enum_get(op->ptr, "slot_type");
6778  uiItemR(layout, op->ptr, "slot_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
6779  }
6780 
6781  uiItemR(layout, op->ptr, "name", 0, NULL, ICON_NONE);
6782 
6783  switch (slot_type) {
6785  uiLayout *col = uiLayoutColumn(layout, true);
6786  uiItemR(col, op->ptr, "width", 0, NULL, ICON_NONE);
6787  uiItemR(col, op->ptr, "height", 0, NULL, ICON_NONE);
6788 
6789  uiItemR(layout, op->ptr, "alpha", 0, NULL, ICON_NONE);
6790  uiItemR(layout, op->ptr, "generated_type", 0, NULL, ICON_NONE);
6791  uiItemR(layout, op->ptr, "float", 0, NULL, ICON_NONE);
6792  break;
6793  }
6795  uiItemR(layout, op->ptr, "domain", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
6796  uiItemR(layout, op->ptr, "data_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
6797  break;
6800  break;
6801  }
6802 
6803  uiItemR(layout, op->ptr, "color", 0, NULL, ICON_NONE);
6804 }
6805 
6806 #define IMA_DEF_NAME N_("Untitled")
6807 
6809 {
6810  PropertyRNA *prop;
6811  static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
6812 
6813  static const EnumPropertyItem slot_type_items[3] = {
6814  {PAINT_CANVAS_SOURCE_IMAGE, "IMAGE", 0, "Image", ""},
6815  {PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE, "COLOR_ATTRIBUTE", 0, "Color Attribute", ""},
6816  {0, NULL, 0, NULL, NULL},
6817  };
6818 
6819  static const EnumPropertyItem domain_items[3] = {
6820  {ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""},
6821  {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
6822  {0, NULL, 0, NULL, NULL},
6823  };
6824 
6825  static const EnumPropertyItem attribute_type_items[3] = {
6826  {CD_PROP_COLOR, "COLOR", 0, "Color", ""},
6827  {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", ""},
6828  {0, NULL, 0, NULL, NULL},
6829  };
6830 
6831  /* identifiers */
6832  ot->name = "Add Paint Slot";
6833  ot->description = "Add a paint slot";
6834  ot->idname = "PAINT_OT_add_texture_paint_slot";
6835 
6836  /* api callbacks */
6841 
6842  /* flags */
6843  ot->flag = OPTYPE_UNDO;
6844 
6845  /* Shared Properties */
6846  prop = RNA_def_enum(ot->srna,
6847  "type",
6849  0,
6850  "Material Layer Type",
6851  "Material layer type of new paint slot");
6853 
6854  prop = RNA_def_enum(
6855  ot->srna, "slot_type", slot_type_items, 0, "Slot Type", "Type of new paint slot");
6856 
6857  prop = RNA_def_string(
6858  ot->srna, "name", IMA_DEF_NAME, MAX_NAME, "Name", "Name for new paint slot source");
6860 
6861  prop = RNA_def_float_color(
6862  ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
6864  RNA_def_property_float_array_default(prop, default_color);
6865 
6866  /* Image Properties */
6867  prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
6869 
6870  prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
6872 
6873  RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
6874 
6875  RNA_def_enum(ot->srna,
6876  "generated_type",
6879  "Generated Type",
6880  "Fill the image with a grid for UV map testing");
6881 
6883  ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth");
6884 
6885  /* Color Attribute Properties */
6886  RNA_def_enum(ot->srna,
6887  "domain",
6888  domain_items,
6890  "Domain",
6891  "Type of element that attribute is stored on");
6892 
6893  RNA_def_enum(ot->srna,
6894  "data_type",
6895  attribute_type_items,
6896  CD_PROP_COLOR,
6897  "Data Type",
6898  "Type of data stored in attribute");
6899 }
6900 
6902 {
6903  /* no checks here, poll function does them for us */
6904  Main *bmain = CTX_data_main(C);
6907 
6908  ED_uvedit_add_simple_uvs(bmain, scene, ob);
6909 
6911 
6912  DEG_id_tag_update(ob->data, 0);
6915  return OPERATOR_FINISHED;
6916 }
6917 
6919 {
6921 
6922  if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) {
6923  return false;
6924  }
6925  return true;
6926 }
6927 
6929 {
6930  /* identifiers */
6931  ot->name = "Add Simple UVs";
6932  ot->description = "Add cube map uvs on mesh";
6933  ot->idname = "PAINT_OT_add_simple_uvs";
6934 
6935  /* api callbacks */
6938 
6939  /* flags */
6941 }
typedef float(TangentPoint)[2]
Generic geometry attributes built on CustomData.
void BKE_id_attributes_active_color_set(struct ID *id, struct CustomDataLayer *active_layer)
Definition: attribute.cc:715
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
void BKE_id_attributes_render_color_set(struct ID *id, struct CustomDataLayer *active_layer)
Definition: attribute.cc:727
struct CustomDataLayer * BKE_id_attribute_new(struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports)
Definition: attribute.cc:220
struct CustomDataLayer * BKE_id_attributes_render_color_get(const struct ID *id)
float BKE_brush_sample_masktex(const struct Scene *scene, struct Brush *br, const float point[2], int thread, struct ImagePool *pool)
float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, float len)
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int size)
Definition: brush.cc:2234
float BKE_brush_sample_tex_3d(const struct Scene *scene, const struct Brush *br, const float point[3], float rgba[4], int thread, struct ImagePool *pool)
float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush)
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
Camera data-block and utility functions.
void BKE_camera_params_init(CameraParams *params)
Definition: camera.c:265
void BKE_camera_params_from_object(CameraParams *params, const struct Object *cam_ob)
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy)
Definition: camera.c:364
void BKE_camera_params_compute_matrix(CameraParams *params)
Definition: camera.c:429
bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4])
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
CustomData interface, see also DNA_customdata_types.h.
int CustomData_number_of_layers(const struct CustomData *data, int type)
int CustomData_get_clone_layer(const struct CustomData *data, int type)
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
int CustomData_get_stencil_layer(const struct CustomData *data, int type)
#define ORIGINDEX_NONE
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
void * CustomData_get_layer(const struct CustomData *data, int type)
struct IDProperty * IDP_GetProperties(struct ID *id, bool create_if_needed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:778
struct IDProperty * IDP_New(char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:887
struct IDProperty * IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop, const char *name, char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL()
Definition: idprop.c:631
struct IDProperty * IDP_GetPropertyFromGroup(const struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define IDP_Array(prop)
Definition: BKE_idprop.h:245
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser)
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
struct ImagePool * BKE_image_pool_new(void)
struct Image * BKE_image_add_generated(struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], bool stereo3d, bool is_data, bool tiled)
void BKE_image_free_gputextures(struct Image *ima)
Definition: image_gpu.cc:516
void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf)
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition: BKE_image.h:134
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal)
struct Image * BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name)
void BKE_imageuser_default(struct ImageUser *iuser)
void BKE_image_pool_free(struct ImagePool *pool)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:687
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma, const struct Object *ob)
Definition: material.c:1501
void BKE_object_material_assign(struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type)
Definition: material.c:1047
struct Material * BKE_material_add(struct Main *bmain, const char *name)
Definition: material.c:289
@ BKE_MAT_ASSIGN_USERPREF
Definition: BKE_material.h:80
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
const float(* BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3]
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
struct Mesh * mesh_get_eval_final(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
struct bNode * ntreeFindType(const struct bNodeTree *ntree, int type)
#define SH_NODE_BSDF_PRINCIPLED
Definition: BKE_node.h:1164
#define SH_NODE_BUMP
Definition: BKE_node.h:1141
void nodePositionPropagate(struct bNode *node)
Definition: node.cc:2663
void ntreeFreeTree(struct bNodeTree *ntree)
Definition: node.cc:3106
void nodePositionRelative(struct bNode *from_node, struct bNode *to_node, struct bNodeSocket *from_sock, struct bNodeSocket *to_sock)
Definition: node.cc:2621
#define SH_NODE_OUTPUT_MATERIAL
Definition: BKE_node.h:1101
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2296
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
struct bNodeTree * ntreeAddTree(struct Main *bmain, const char *name, const char *idname)
Definition: node.cc:2674
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2151
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:3644
#define SH_NODE_ATTRIBUTE
Definition: BKE_node.h:1106
bool BKE_object_attributes_active_color_fill(struct Object *ob, const float fill_color[4], bool only_selected)
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
@ PAINT_MODE_TEXTURE_3D
Definition: BKE_paint.h:73
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.c:83
int BKE_scene_num_threads(const struct Scene *scene)
bool BKE_scene_check_color_management_enabled(const struct Scene *scene)
struct ARegion * BKE_area_find_region_active_win(struct ScrArea *area)
Definition: screen.c:883
struct ARegion struct ARegion struct ScrArea struct ScrArea * BKE_screen_find_big_area(struct bScreen *screen, int spacetype, short min)
Definition: screen.c:937
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
#define LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:314
#define LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:318
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:325
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:329
#define M_1_PI
Definition: BLI_math_base.h:41
MINLINE float saacos(float fac)
int pow_i(int base, int exp)
Definition: math_base.c:12
MINLINE float min_ff(float a, float b)
#define M_PI_2
Definition: BLI_math_base.h:23
MINLINE int mod_i(int i, int n)
MINLINE float square_f(float a)
MINLINE float min_fff(float a, float b, float c)
#define M_PI
Definition: BLI_math_base.h:20
MINLINE int square_s(short a)
MINLINE int count_bits_i(unsigned int n)
MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4])
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void rgba_float_args_set(float col[4], float r, float g, float b, float a)
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
MINLINE void premul_to_straight_v4(float color[4])
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:383
MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float dither, float s, float t)
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
MINLINE void linearrgb_to_srgb_uchar3(unsigned char srgb[3], const float linear[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
Definition: math_color.c:391
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float t)
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
Definition: math_geom.c:1108
int isect_point_quad_v2(const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
Definition: math_geom.c:1536
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
Definition: math_geom.c:3700
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2])
bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
Definition: math_geom.c:1303
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:3274
float resolve_quad_u_v2(const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2])
Definition: math_geom.c:4441
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2])
Definition: math_geom.c:1296
void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
Definition: math_geom.c:3746
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:270
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
Definition: math_geom.c:1516
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
void mul_project_m4_v3(const float M[4][4], float vec[3])
Definition: math_matrix.c:820
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void mul_m4_v4(const float M[4][4], float r[4])
Definition: math_matrix.c:862
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void normalize_m4(float R[4][4]) ATTR_NONNULL()
Definition: math_matrix.c:1945
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
Definition: math_vector.c:160
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v2_v2v2v2(float r[2], const float a[2], const float b[2], const float c[2], const float t[3])
Definition: math_vector.c:22
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:890
MINLINE void add_v2_v2(float r[2], const float a[2])
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
Definition: math_vector.c:638
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
MINLINE void zero_v4(float r[4])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:94
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:64
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:116
#define FILE_MAX
void BLI_rcti_init_minmax(struct rcti *rect)
Definition: rct.c:477
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
bool BLI_rcti_is_valid(const struct rcti *rect)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
bool BLI_rcti_is_empty(const struct rcti *rect)
void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other)
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
@ TASK_PRIORITY_HIGH
Definition: BLI_task.h:57
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition: task_pool.cc:480
TaskPool * BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority)
Definition: task_pool.cc:417
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:440
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:459
pthread_spinlock_t SpinLock
Definition: BLI_threads.h:110
void BLI_thread_unlock(int type)
Definition: threads.cc:361
@ LOCK_CUSTOM1
Definition: BLI_threads.h:69
void BLI_thread_lock(int type)
Definition: threads.cc:356
#define BLENDER_MAX_THREADS
Definition: BLI_threads.h:19
void BLI_spin_init(SpinLock *spin)
Definition: threads.cc:419
void BLI_spin_unlock(SpinLock *spin)
Definition: threads.cc:452
void BLI_spin_lock(SpinLock *spin)
Definition: threads.cc:433
void BLI_spin_end(SpinLock *spin)
Definition: threads.cc:467
#define INIT_MINMAX2(min, max)
#define UNPACK4(a)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define LIKELY(x)
Compatibility-like things for windows.
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ IDP_FLOAT
Definition: DNA_ID.h:138
@ IDP_ARRAY
Definition: DNA_ID.h:140
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_SHADING
Definition: DNA_ID.h:811
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define MAX_ID_NAME
Definition: DNA_ID.h:337
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
@ BRUSH_LOCK_ALPHA
@ BRUSH_ACCUMULATE
@ BRUSH_DIR_IN
@ BRUSH_USE_GRADIENT
@ PAINT_TOOL_CLONE
@ PAINT_TOOL_SMEAR
@ PAINT_TOOL_SOFTEN
@ PAINT_TOOL_MASK
@ PAINT_TOOL_FILL
@ PAINT_TOOL_DRAW
@ BRUSH_GRADIENT_LINEAR
@ BRUSH_GRADIENT_RADIAL
#define CD_MASK_ORIGINDEX
#define CD_MASK_MTFACE
eCustomDataType
@ CD_PROP_BYTE_COLOR
@ CD_ORIGINDEX
@ CD_PROP_COLOR
@ CD_MLOOPUV
#define CD_MASK_MLOOPUV
#define MAX_NAME
Definition: DNA_defs.h:48
@ IMA_GENTYPE_BLANK
@ IMA_SRC_TILED
@ ME_EDIT_PAINT_FACE_SEL
@ ME_SMOOTH
@ ME_FACE_SEL
@ SOCK_OUT
@ SOCK_IN
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_RGBA
@ OB_MODE_SCULPT
@ OB_MODE_TEXTURE_PAINT
Object is a sort of wrapper for general info.
@ OB_MESH
@ OB_NEG_SCALE
#define IMAGEPAINT_PROJECT_FLAT
#define IMAGEPAINT_PROJECT_LAYER_STENCIL
#define IMAGEPAINT_MODE_IMAGE
#define IMAGEPAINT_PROJECT_XRAY
#define IMAGEPAINT_PROJECT_LAYER_CLONE
#define IMAGEPAINT_MODE_MATERIAL
@ PAINT_USE_CAVITY_MASK
#define OBACT(_view_layer)
#define IMAGEPAINT_PROJECT_LAYER_STENCIL_INV
@ R_ALPHAPREMUL
ePaintCanvasSource
@ PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE
@ PAINT_CANVAS_SOURCE_IMAGE
@ PAINT_CANVAS_SOURCE_MATERIAL
@ PAINT_SYMM_Y
@ PAINT_SYMM_X
@ PAINT_SYMM_Z
#define IMAGEPAINT_DRAWING
#define IMAGEPAINT_MISSING_STENCIL
#define IMAGEPAINT_PROJECT_BACKFACE
#define IMAGEPAINT_MISSING_MATERIAL
#define IMAGEPAINT_MISSING_UVS
#define IMAGEPAINT_MISSING_TEX
@ SPACE_VIEW3D
#define MTEX_MAP_MODE_3D
@ USER_ORBIT_SELECTION
@ V3D_OVERLAY_HIDE_OBJECT_ORIGINS
@ V3D_OVERLAY_HIDE_BONES
@ V3D_OVERLAY_HIDE_MOTION_PATHS
@ V3D_OVERLAY_HIDE_OBJECT_XTRAS
@ V3D_OVERLAY_HIDE_CURSOR
@ V3D_OVERLAY_HIDE_TEXT
#define V3D_HIDE_HELPLINES
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ V3D_GIZMO_HIDE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_node_shader_default(const struct bContext *C, struct ID *id)
void ED_node_tree_propagate_change(const struct bContext *C, struct Main *bmain, struct bNodeTree *ntree)
struct Object * ED_object_active_context(const struct bContext *C)
#define ED_IMAGE_UNDO_TILE_NUMBER(size)
Definition: ED_paint.h:106
void ED_image_undo_push_begin(const char *name, int paint_mode)
Definition: image_undo.cc:1095
void ED_image_paint_tile_lock_end(void)
Definition: image_undo.cc:69
void ED_image_paint_tile_lock_init(void)
Definition: image_undo.cc:64
#define ED_IMAGE_UNDO_TILE_SIZE
Definition: ED_paint.h:105
struct PaintTileMap * ED_image_paint_tile_map_get(void)
Definition: image_undo.cc:1061
void ED_image_undo_push_end(void)
Definition: image_undo.cc:1133
void * ED_image_paint_tile_push(PaintTileMap *paint_tile_map, struct Image *image, struct ImBuf *ibuf, struct ImBuf **tmpibuf, struct ImageUser *iuser, int x_tile, int y_tile, unsigned short **r_mask, bool **r_valid, bool use_thread_lock, bool find_prev)
Definition: image_undo.cc:192
#define ED_IMAGE_UNDO_TILE_BITS
Definition: ED_paint.h:104
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:729
bool ED_operator_object_active_editable_mesh(struct bContext *C)
Definition: screen_ops.c:413
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob)
bool ED_view3d_clip_range_get(const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, bool use_ortho_factor)
void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, const float obmat[4][4], float r_pmat[4][4])
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], bool is_local)
void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4])
Definition: view3d_edit.c:755
void view3d_operator_needs_opengl(const struct bContext *C)
bool ED_view3d_autodist(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int mval[2], float mouse_worldloc[3], bool alphaoverride, const float fallback_depth_pt[3])
struct ImBuf * ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph, struct Scene *scene, eDrawType drawtype, struct View3D *v3d, struct ARegion *region, int sizex, int sizey, eImBufFlags imbuf_flag, int alpha_mode, const char *viewname, bool restore_rv3d_mats, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1831
int GPU_max_texture_size(void)
bool GPU_is_init(void)
Definition: gpu_init_exit.c:63
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:805
void imb_freerectfloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:80
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:696
void imb_freerectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:97
void IMB_blend_color_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], IMB_BlendMode mode)
Definition: rectop.c:24
@ IMB_BLEND_ERASE_ALPHA
Definition: IMB_imbuf.h:216
@ IMB_BLEND_ADD_ALPHA
Definition: IMB_imbuf.h:217
void bicubic_interpolation_color(const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:80
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition: rectop.c:112
void bilinear_interpolation_color_wrap(const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:142
Contains defines and structs used throughout the imbuf module.
@ IB_rect
Read Guarded memory(de)allocation.
#define MEM_SIZE_OPTIMAL(size)
struct bNodeTreeType * ntreeType_Shader
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
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 SH_NODE_TEX_IMAGE
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
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 SH_NODE_NORMAL_MAP
const EnumPropertyItem * RNA_image_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free)
@ PROP_ENUM_NO_TRANSLATE
Definition: RNA_types.h:294
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
@ PROP_PIXEL
Definition: RNA_types.h:141
@ PROP_COLOR_GAMMA
Definition: RNA_types.h:165
#define C
Definition: RandGen.cpp:25
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
@ UI_ITEM_R_EXPAND
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
#define NC_SCENE
Definition: WM_types.h:328
#define NA_ADDED
Definition: WM_types.h:525
#define ND_TOOLSETTINGS
Definition: WM_types.h:397
#define NA_EDITED
Definition: WM_types.h:523
#define NC_IMAGE
Definition: WM_types.h:334
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
short source
int lastframe
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
#define tanf(x)
Definition: cuda/compat.h:104
OperationNode * node
Scene scene
World world
const Depsgraph * depsgraph
SyclQueue void void size_t num_bytes SyclQueue void const char void *memory_device_pointer KernelContext int kernel
TaskPool * task_pool
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
bNodeTree * ntree
uint pos
uint col
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global int * counter
const int tile_index
ccl_global const KernelWorkTile * tile
const int state
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
#define unit_float_to_uchar_clamp_v3(v1, v2)
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
Definition: math_float2.h:232
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define G(x, y, z)
#define atan2f(x, y)
Definition: metal/compat.h:227
#define fmodf(x, y)
Definition: metal/compat.h:230
#define acosf(x)
Definition: metal/compat.h:222
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned a[3]
Definition: RandGen.cpp:78
static void area(int d1, int d2, int e1, int e2, float weights[2])
T distance(const T &a, const T &b)
static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal)
static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal)
void paint_delete_blur_kernel(BlurKernel *kernel)
Definition: paint_image.cc:240
BlurKernel * paint_new_blur_kernel(Brush *br, bool proj)
Definition: paint_image.cc:171
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
Definition: paint_image.cc:144
void paint_brush_init_tex(Brush *brush)
Definition: paint_image.cc:374
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
Definition: paint_image.cc:84
bool paint_use_opacity_masking(Brush *brush)
Definition: paint_image.cc:317
void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display)
Definition: paint_image.cc:332
void paint_brush_exit_tex(Brush *brush)
Definition: paint_image.cc:390
static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *softenArena, LinkNode **softenPixels)
void * paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
static bool project_paint_clone_face_skip(ProjPaintState *ps, ProjPaintLayerClone *lc, const TexPaintSlot *slot, const int tri_index)
static bool project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, const float pixelScreenCo[4])
static void screen_px_from_ortho(const float uv[2], const float v1co[3], const float v2co[3], const float v3co[3], const float uv1co[2], const float uv2co[2], const float uv3co[2], float pixelScreenCo[4], float w[3])
static int project_paint_face_paint_tile(Image *ima, const float *uv)
static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3])
static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MLoopTri *lt)
static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], float *rgba_fp, uchar *rgba, const bool interp)
static void image_paint_partial_redraw_expand(ImagePaintPartialRedraw *cell, const ProjPixel *projPixel)
#define ISECT_TRUE_P1
#define PROJ_FACE_SEAM2
static void project_paint_begin(const bContext *C, ProjPaintState *ps, const bool is_multi_view, const char symmetry_flag)
#define PROJ_SRC_VIEW_FILL
#define ISECT_ALL4
static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2])
static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceCoSS *coSS)
static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *ps)
static void paint_proj_stroke_ps(const bContext *UNUSED(C), void *ps_handle_p, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size, ProjPaintState *ps)
static Image * project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
static Image * proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
struct ProjectHandle ProjectHandle
struct ProjPixelClone ProjPixelClone
static void rect_to_uvspace_ortho(const rctf *bucket_bounds, const float *v1coSS, const float *v2coSS, const float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[4][2], const int flip)
static bool add_simple_uvs_poll(bContext *C)
#define PROJ_VIEW_DATA_SIZE
static void project_paint_bleed_add_face_user(const ProjPaintState *ps, MemArena *arena, const MLoopTri *lt, const int tri_index)
#define PROJ_BUCKET_NULL
static Material * get_or_create_current_material(bContext *C, Object *ob)
static bool IsectPT2Df_limit(const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float limit)
#define ISECT_TRUE
static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
#define PROJ_FACE_SEAM1
#define ISECT_TRUE_P2
static int get_texture_layer_type(wmOperator *op, const char *prop_name)
#define IMA_DEF_NAME
void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
static bool texture_paint_image_from_view_poll(bContext *C)
#define PROJ_BOUNDBOX_DIV
struct PrepareImageEntry PrepareImageEntry
static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
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 screen_px_from_persp(const float uv[2], const float v1co[4], const float v2co[4], const float v3co[4], const float uv1co[2], const float uv2co[2], const float uv3co[2], float pixelScreenCo[4], float w[3])
static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
static void project_paint_prepare_all_faces(ProjPaintState *ps, MemArena *arena, const ProjPaintFaceLookup *face_lookup, ProjPaintLayerClone *layer_clone, const MLoopUV *mloopuv_base, const bool is_multi_view)
#define ISECT_4
#define PROJ_FACE_SEAM0
static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *clip_rect, const rctf *bucket_bounds)
static bool line_rect_clip(const rctf *rect, const float l1[4], const float l2[4], const float uv1[2], const float uv2[2], float uv[2], bool is_ortho)
static void proj_paint_face_lookup_init(const ProjPaintState *ps, ProjPaintFaceLookup *face_lookup)
#define TILE_PENDING
static bool cmp_uv(const float vec2a[2], const float vec2b[2])
#define PS_LOOPTRI_AS_UV_3(uvlayer, lt)
#define PROJ_GEOM_TOLERANCE
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask)
static void project_paint_build_proj_ima(ProjPaintState *ps, MemArena *arena, ListBase *used_images)
BLI_INLINE const MPoly * ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_index)
void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil)
#define PROJ_SRC_IMAGE_CAM
static void proj_paint_layer_clone_init(ProjPaintState *ps, ProjPaintLayerClone *layer_clone)
#define PROJ_FACE_NOSEAM0
static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect)
#define PROJ_BUCKET_BRUSH_DIV
#define PROJ_FACE_SEAM_INIT2
#define PROJ_BUCKET_RECT_MAX
BLI_INLINE uchar f_to_char(const float val)
struct ProjPaintState ProjPaintState
static int float_z_sort_flip(const void *p1, const void *p2)
#define PROJ_SRC_IMAGE_VIEW
static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, const rctf *bucket_bounds)
static ProjPixel * project_paint_uvpixel_init(const ProjPaintState *ps, MemArena *arena, const TileInfo *tinf, int x_px, int y_px, const float mask, const int tri_index, const float pixelScreenCo[4], const float world_spaceCo[3], const float w[3])
static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *smearArena, LinkNode **smearPixels, const float co[2])
@ LAYER_NORMAL
@ LAYER_DISPLACEMENT
@ LAYER_ROUGHNESS
@ LAYER_METALLIC
@ LAYER_BUMP
@ LAYER_BASE_COLOR
@ LAYER_SPECULAR
#define PROJ_FACE_WINDING_INIT
static CustomDataLayer * proj_paint_color_attribute_create(wmOperator *op, Object *ob)
void PAINT_OT_add_simple_uvs(wmOperatorType *ot)
static bool project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
#define PROJ_BUCKET_RECT_MIN
static bool project_paint_check_face_sel(const ProjPaintState *ps, const ProjPaintFaceLookup *face_lookup, const MLoopTri *lt)
static bool project_image_refresh_tagged(ProjPaintState *ps)
#define PROJ_VERT_CULL
#define PROJ_FACE_WINDING_CW
static bool check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx)
static int float_z_sort(const void *p1, const void *p2)
static void scale_tri(float insetCos[3][3], const float *origCos[3], const float inset)
static void proj_paint_state_cavity_init(ProjPaintState *ps)
static bool partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot)
static void project_paint_delayed_face_init(ProjPaintState *ps, const MLoopTri *lt, const int tri_index)
void paint_proj_stroke(const bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size)
static int project_paint_occlude_ptv(const float pt[3], const float v1[4], const float v2[4], const float v3[4], float w[3], const bool is_ortho)
bool ED_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
static void project_paint_end(ProjPaintState *ps)
static void get_default_texture_layer_name_for_object(Object *ob, int texture_type, char *dst, int dst_length)
void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
static void project_face_winding_init(const ProjPaintState *ps, const int tri_index)
static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect)
struct ProjStrokeHandle ProjStrokeHandle
static void default_paint_slot_color_get(int layer_type, Material *ma, float color[4])
static bool pixel_bounds_array(float(*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot)
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
static void insert_seam_vert_array(const ProjPaintState *ps, MemArena *arena, const int tri_index, const int fidx1, const int ibuf_x, const int ibuf_y)
static float project_paint_uvpixel_mask(const ProjPaintState *ps, const int tri_index, const float w[3])
static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *softenArena, LinkNode **softenPixels)
static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
static const EnumPropertyItem layer_type_items[]
#define PROJ_PIXEL_TOLERANCE
static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
static Image * project_paint_face_paint_image(const ProjPaintState *ps, int tri_index)
static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
union pixelStore PixelStore
static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v)
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
static void proj_paint_state_seam_bleed_init(ProjPaintState *ps)
#define ISECT_3
static VertSeam * find_adjacent_seam(const ProjPaintState *ps, uint loop_index, uint vert_index, VertSeam **r_seam)
struct ProjPaintImage ProjPaintImage
static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float mask)
#define PROJ_VIEW_DATA_ID
static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds)
static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const float v2_2)
static int project_paint_pixel_sizeof(const short tool)
#define PROJ_PAINT_STATE_SHARED_CLEAR(ps)
#define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src)
static bool pixel_bounds_uv(const float uv_quad[4][2], rcti *bounds_px, const int ibuf_x, const int ibuf_y)
void PAINT_OT_project_image(wmOperatorType *ot)
static bool project_paint_op(void *state, const float lastpos[2], const float pos[2])
static float screen_px_line_point_factor_v2_persp(const ProjPaintState *ps, const float p[2], const float v1[3], const float v2[3])
union pixelPointer PixelPointer
static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
static bool proj_paint_add_slot(bContext *C, wmOperator *op)
static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask, float dither, float u, float v)
static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
static float VecZDepthOrtho(const float pt[2], const float v1[3], const float v2[3], const float v3[3], float w[3])
#define PROJ_BOUNDBOX_SQUARED
void paint_proj_stroke_done(void *ps_handle_p)
struct ProjPixel ProjPixel
#define ISECT_1
static bool IsectPoly2Df(const float pt[2], const float uv[][2], const int tot)
static void project_face_seams_init(const ProjPaintState *ps, MemArena *arena, const int tri_index, const uint vert_index, bool init_all, const int ibuf_x, const int ibuf_y)
static TexPaintSlot * project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
#define PROJ_FACE_SEAM_INIT0
static bool line_clip_rect2f(const rctf *cliprect, const rctf *rect, const float l1[2], const float l2[2], float l1_clip[2], float l2_clip[2])
#define PROJ_BUCKET_INIT
#define ISECT_2
static float VecZDepthPersp(const float pt[2], const float v1[4], const float v2[4], const float v3[4], float w[3])
static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
#define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)
static TexPaintSlot * project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
#define PROJ_FACE_DEGENERATE
static int project_paint_occlude_ptv_clip(const float pt[3], const float v1[4], const float v2[4], const float v3[4], const float v1_3d[3], const float v2_3d[3], const float v3_3d[3], float w[3], const bool is_ortho, RegionView3D *rv3d)
static void proj_paint_face_coSS_init(const ProjPaintState *ps, const MLoopTri *lt, ProjPaintFaceCoSS *coSS)
static float compute_seam_normal(VertSeam *seam, VertSeam *adj, float r_no[2])
static bool IsectPoly2Df_twoside(const float pt[2], const float uv[][2], const int tot)
static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads)
#define PROJ_SRC_VIEW
#define ISECT_ALL3
#define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, lt)
static void screen_px_to_vector_persp(int winx, int winy, const float projmat_inv[4][4], const float view_pos[3], const float co_px[2], float r_dir[3])
struct VertSeam VertSeam
static void project_bucket_clip_face(const bool is_ortho, const bool is_flip_object, const rctf *cliprect, const rctf *bucket_bounds, const float *v1coSS, const float *v2coSS, const float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[8][2], int *tot, bool cull)
static void texture_paint_add_texture_paint_slot_ui(bContext *C, wmOperator *op)
static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmetry_flag)
static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int tri_index, const int image_index, const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf)
static bool project_paint_flt_max_cull(const ProjPaintState *ps, const ProjPaintFaceCoSS *coSS)
#define PROJ_FACE_SCALE_SEAM
void PAINT_OT_image_from_view(wmOperatorType *ot)
static void uv_image_outset(const ProjPaintState *ps, float(*orig_uv)[2], float(*puv)[2], uint tri_index, const int ibuf_x, const int ibuf_y)
static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int mode)
struct LoopSeamData LoopSeamData
static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
#define PROJ_FACE_SEAM_INIT1
static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *smearArena, LinkNode **smearPixels_f, const float co[2])
static void rect_to_uvspace_persp(const rctf *bucket_bounds, const float *v1coSS, const float *v2coSS, const float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[4][2], const int flip)
@ BRUSH_STROKE_NORMAL
Definition: paint_intern.h:449
@ BRUSH_STROKE_INVERT
Definition: paint_intern.h:450
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:5116
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
Definition: rna_access.c:1736
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:4992
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_string_file_name(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3759
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3687
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3922
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1534
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
Definition: rna_define.c:2043
const EnumPropertyItem rna_enum_image_generated_type_items[]
Definition: rna_image.c:31
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:26
#define min(a, b)
Definition: sort.c:35
void * regiondata
struct ColorBand * gradient
struct MTex mtex
float sharp_threshold
char gradient_fill_mode
char imagepaint_tool
short blend
struct MTex mask_mtex
float weight
int len
Definition: DNA_ID.h:121
char subtype
Definition: DNA_ID.h:108
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
unsigned int * rect
float * rect_float
struct Image * stencil
struct Image * canvas
struct Image * clone
void * link
Definition: BLI_linklist.h:24
struct LinkNode * next
Definition: BLI_linklist.h:23
void * first
Definition: DNA_listBase.h:31
float seam_puvs[2][2]
float seam_uvs[2][2]
float corner_dist_sq[2]
unsigned int v1
unsigned int v2
unsigned int poly
unsigned int tri[3]
unsigned int v
short mat_nr
char brush_map_mode
struct Tex * tex
float co[3]
Definition: BKE_main.h:121
ListBase images
Definition: BKE_main.h:176
struct bNodeTree * nodetree
short paint_active_slot
struct TexPaintSlot * texpaintslot
short paint_clone_slot
struct MLoopTri_Store looptris
struct MEdge * medge
char symmetry
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
CustomData pdata
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
short transflag
float obmat[4][4]
void * data
struct CurveMapping * cavity_curve
struct PrepareImageEntry * next
struct PrepareImageEntry * prev
const MPoly * mpoly_orig
const int * index_mp_to_orig
ImagePaintPartialRedraw * partRedrawRect
volatile void ** undoRect
const TexPaintSlot * slot_last_clone
const TexPaintSlot * slot_clone
const MLoopUV * mloopuv_clone_base
float projectMat[4][4]
Material ** mat_array
Depsgraph * depsgraph
LoopSeamData * loopSeamData
float obmat[4][4]
const float(* vert_normals)[3]
const MLoopUV ** poly_to_loop_uv_clone
const MVert * mvert_eval
const MLoopUV ** poly_to_loop_uv
const MPoly * mpoly_eval
float paint_color_linear[3]
bool reproject_ibuf_free_float
const MEdge * medge_eval
const MLoop * mloop_eval
ushort * faceSeamFlags
SpinLock * tile_lock
ListBase * vertSeams
struct CurveMapping * cavity_curve
LinkNode ** bucketFaces
LinkNode ** bucketRect
float projectMatInv[4][4]
RegionView3D * rv3d
const MLoopUV * mloopuv_stencil_eval
LinkNode ** vertFaces
ProjPaintImage * projImages
float obmat_imat[4][4]
BlurKernel * blurkernel
MemArena * arena_mt[BLENDER_MAX_THREADS]
float(* screenCoords)[4]
const MLoopTri * mlooptri_eval
bool reproject_ibuf_free_uchar
float normal_angle_inner__cos
PixelStore clonepx
struct ProjPixel __pp
ushort image_index
PixelStore newColor
float projCoSS[2]
PixelPointer pixel
uchar bb_cell_index
PixelPointer origColor
float worldCoSS[3]
ushort * mask_accum
struct ProjPaintState * ps_views[8]
ProjPaintState * ps
ProjPaintImage * projImages
struct ImagePool * pool
float viewmat[4][4]
float viewinv[4][4]
float winmat[4][4]
struct CustomData_MeshMasks customdata_mask
struct ToolSettings * toolsettings
View3DCursor cursor
struct Object * camera
struct Image * ima
SpinLock * lock
ushort tile_width
ImBuf ** tmpibuf
ProjPaintImage * pjima
struct ImagePaintSettings imapaint
struct UnifiedPaintSettings unified_paint_settings
struct VertSeam * prev
struct VertSeam * next
float uv[2]
float texture_paint_mode_opacity
View3DOverlay overlay
char gizmo_flag
View3DShading shading
struct bNodeLink * link
void * default_value
char idname[64]
Definition: BKE_node.h:375
struct ID * id
void * storage
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:954
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
float max
struct IDPropertyTemplate::@27 array
ParamHandle ** handles
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width)
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))