Blender  V2.93
paint_image_proj.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14  *
15  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
16  * All rights reserved.
17  *
18  * The Original Code is: some of this file.
19  */
20 
26 #include <float.h>
27 #include <math.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "MEM_guardedalloc.h"
32 
33 #ifdef WIN32
34 # include "BLI_winstuff.h"
35 #endif
36 
37 #include "BLI_blenlib.h"
38 #include "BLI_linklist.h"
39 #include "BLI_math.h"
40 #include "BLI_math_bits.h"
41 #include "BLI_math_color_blend.h"
42 #include "BLI_memarena.h"
43 #include "BLI_task.h"
44 #include "BLI_threads.h"
45 #include "BLI_utildefines.h"
46 
47 #include "atomic_ops.h"
48 
49 #include "BLT_translation.h"
50 
51 #include "IMB_imbuf.h"
52 #include "IMB_imbuf_types.h"
53 
54 #include "DNA_brush_types.h"
55 #include "DNA_material_types.h"
56 #include "DNA_mesh_types.h"
57 #include "DNA_meshdata_types.h"
58 #include "DNA_node_types.h"
59 #include "DNA_object_types.h"
60 
61 #include "BKE_brush.h"
62 #include "BKE_camera.h"
63 #include "BKE_colorband.h"
64 #include "BKE_colortools.h"
65 #include "BKE_context.h"
66 #include "BKE_customdata.h"
67 #include "BKE_global.h"
68 #include "BKE_idprop.h"
69 #include "BKE_image.h"
70 #include "BKE_lib_id.h"
71 #include "BKE_main.h"
72 #include "BKE_material.h"
73 #include "BKE_mesh.h"
74 #include "BKE_mesh_mapping.h"
75 #include "BKE_mesh_runtime.h"
76 #include "BKE_node.h"
77 #include "BKE_paint.h"
78 #include "BKE_report.h"
79 #include "BKE_scene.h"
80 #include "BKE_screen.h"
81 
82 #include "DEG_depsgraph.h"
83 #include "DEG_depsgraph_query.h"
84 
85 #include "ED_node.h"
86 #include "ED_object.h"
87 #include "ED_paint.h"
88 #include "ED_screen.h"
89 #include "ED_uvedit.h"
90 #include "ED_view3d.h"
91 #include "ED_view3d_offscreen.h"
92 
93 #include "GPU_capabilities.h"
94 #include "GPU_init_exit.h"
95 
96 #include "WM_api.h"
97 #include "WM_types.h"
98 
99 #include "RNA_access.h"
100 #include "RNA_define.h"
101 #include "RNA_enum_types.h"
102 
103 #include "IMB_colormanagement.h"
104 
105 //#include "bmesh_tools.h"
106 
107 #include "paint_intern.h"
108 
110 
111 /* Defines and Structs */
112 /* unit_float_to_uchar_clamp as inline function */
113 BLI_INLINE uchar f_to_char(const float val)
114 {
115  return unit_float_to_uchar_clamp(val);
116 }
117 
118 /* ProjectionPaint defines */
119 
120 /* approx the number of buckets to have under the brush,
121  * used with the brush size to set the ps->buckets_x and ps->buckets_y value.
122  *
123  * When 3 - a brush should have ~9 buckets under it at once
124  * ...this helps for threading while painting as well as
125  * avoiding initializing pixels that wont touch the brush */
126 #define PROJ_BUCKET_BRUSH_DIV 4
127 
128 #define PROJ_BUCKET_RECT_MIN 4
129 #define PROJ_BUCKET_RECT_MAX 256
130 
131 #define PROJ_BOUNDBOX_DIV 8
132 #define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
133 
134 //#define PROJ_DEBUG_PAINT 1
135 //#define PROJ_DEBUG_NOSEAMBLEED 1
136 //#define PROJ_DEBUG_PRINT_CLIP 1
137 #define PROJ_DEBUG_WINCLIP 1
138 
139 #ifndef PROJ_DEBUG_NOSEAMBLEED
140 /* projectFaceSeamFlags options */
141 //#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, back-facing or occluded. */
142 //#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
143 
144 /* If this face has a seam on any of its edges. */
145 # define PROJ_FACE_SEAM0 (1 << 0)
146 # define PROJ_FACE_SEAM1 (1 << 1)
147 # define PROJ_FACE_SEAM2 (1 << 2)
148 
149 # define PROJ_FACE_NOSEAM0 (1 << 4)
150 # define PROJ_FACE_NOSEAM1 (1 << 5)
151 # define PROJ_FACE_NOSEAM2 (1 << 6)
152 
153 /* If the seam is completely initialized, including adjacent seams. */
154 # define PROJ_FACE_SEAM_INIT0 (1 << 8)
155 # define PROJ_FACE_SEAM_INIT1 (1 << 9)
156 # define PROJ_FACE_SEAM_INIT2 (1 << 10)
157 
158 # define PROJ_FACE_DEGENERATE (1 << 12)
159 
160 /* face winding */
161 # define PROJ_FACE_WINDING_INIT 1
162 # define PROJ_FACE_WINDING_CW 2
163 
164 /* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
165  * as this number approaches 1.0f the likelihood increases of float precision errors where
166  * it is occluded by an adjacent face */
167 # define PROJ_FACE_SCALE_SEAM 0.99f
168 #endif /* PROJ_DEBUG_NOSEAMBLEED */
169 
170 #define PROJ_SRC_VIEW 1
171 #define PROJ_SRC_IMAGE_CAM 2
172 #define PROJ_SRC_IMAGE_VIEW 3
173 #define PROJ_SRC_VIEW_FILL 4
174 
175 #define PROJ_VIEW_DATA_ID "view_data"
176 /* viewmat + winmat + clip_start + clip_end + is_ortho */
177 #define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3)
178 
179 #define PROJ_BUCKET_NULL 0
180 #define PROJ_BUCKET_INIT (1 << 0)
181 // #define PROJ_BUCKET_CLONE_INIT (1<<1)
182 
183 /* used for testing doubles, if a point is on a line etc */
184 #define PROJ_GEOM_TOLERANCE 0.00075f
185 #define PROJ_PIXEL_TOLERANCE 0.01f
186 
187 /* vert flags */
188 #define PROJ_VERT_CULL 1
189 
190 /* to avoid locking in tile initialization */
191 #define TILE_PENDING POINTER_FROM_INT(-1)
192 
198 typedef struct ProjPaintImage {
204  volatile void **undoRect;
209  bool **valid;
210  bool touch;
212 
216 typedef struct ProjStrokeHandle {
217  /* Support for painting from multiple views at once,
218  * currently used to implement symmetry painting,
219  * we can assume at least the first is set while painting. */
223 
225 
227 
228  /* trick to bypass regular paint and allow clone picking */
230 
231  /* In ProjPaintState, only here for convenience */
235 
236 typedef struct LoopSeamData {
237  float seam_uvs[2][2];
238  float seam_puvs[2][2];
239  float corner_dist_sq[2];
241 
242 /* Main projection painting struct passed to all projection painting functions */
243 typedef struct ProjPaintState {
249  /* PROJ_SRC_**** */
250  int source;
251 
252  /* the paint color. It can change depending of inverted mode or not */
253  float paint_color[3];
255  float dither;
256 
258  short tool, blend, mode;
259 
260  float brush_size;
262  /* for symmetry, we need to store modified object matrix */
263  float obmat[4][4];
264  float obmat_imat[4][4];
265  /* end similarities with ImagePaintState */
266 
271 
272  /* projection painting only */
281 
283  char *vertFlags;
288 
291 
294 
298  float screenMin[2];
299  float screenMax[2];
304  int winx, winy;
305 
306  /* options for projection painting */
312 
330 
333  bool is_ortho;
342 #ifndef PROJ_DEBUG_NOSEAMBLEED
345 #endif
346  /* clone vars */
347  float cloneOffset[2];
348 
350  float projectMat[4][4];
352  float projectMatInv[4][4];
354  float viewDir[3];
356  float viewPos[3];
358 
359  /* reproject vars */
364 
365  /* threads */
367  int bucketMin[2];
368  int bucketMax[2];
371 
374 
375  /* -------------------------------------------------------------------- */
376  /* Vars shared between multiple views (keep last) */
382 #define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
383  MEMCPY_STRUCT_AFTER(ps_dst, ps_src, is_shared_user)
384 
385 #define PROJ_PAINT_STATE_SHARED_CLEAR(ps) MEMSET_STRUCT_AFTER(ps, 0, is_shared_user)
386 
388 
391  float *cavities;
392 
393 #ifndef PROJ_DEBUG_NOSEAMBLEED
405 #endif
406 
408 
415 
421 
423 
432 
433  /* Actual material for each index, either from object or Mesh datablock... */
435 
438 
439 typedef union pixelPointer {
441  float *f_pt;
446 
447 typedef union pixelStore {
448  uchar ch[4];
450  float f[4];
452 
453 typedef struct ProjPixel {
455  float projCoSS[2];
456  float worldCoSS[3];
457 
458  short x_px, y_px;
459 
463 
464  /* for various reasons we may want to mask out painting onto this pixel */
466 
467  /* Only used when the airbrush is disabled.
468  * Store the max mask value to avoid painting over an area with a lower opacity
469  * with an advantage that we can avoid touching the pixel at all, if the
470  * new mask value is lower than mask_accum */
472 
473  /* horrible hack, store tile valid flag pointer here to re-validate tiles
474  * used for anchored and drag-dot strokes */
475  bool *valid;
476 
481 
482 typedef struct ProjPixelClone {
483  struct ProjPixel __pp;
486 
487 /* undo tile pushing */
488 typedef struct {
490  bool masked;
494 } TileInfo;
495 
496 typedef struct VertSeam {
497  struct VertSeam *next, *prev;
498  int tri;
500  float angle;
501  bool normal_cw;
502  float uv[2];
504 
505 /* -------------------------------------------------------------------- */
509 BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_index)
510 {
511  return &ps->mpoly_eval[ps->mlooptri_eval[tri_index].poly];
512 }
513 
514 #define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) \
515  ps->mloop_eval[lt->tri[0]].v, ps->mloop_eval[lt->tri[1]].v, ps->mloop_eval[lt->tri[2]].v,
516 
517 #define PS_LOOPTRI_AS_UV_3(uvlayer, lt) \
518  uvlayer[lt->poly][lt->tri[0]].uv, uvlayer[lt->poly][lt->tri[1]].uv, \
519  uvlayer[lt->poly][lt->tri[2]].uv,
520 
521 #define PS_LOOPTRI_ASSIGN_UV_3(uv_tri, uvlayer, lt) \
522  { \
523  (uv_tri)[0] = uvlayer[lt->poly][lt->tri[0]].uv; \
524  (uv_tri)[1] = uvlayer[lt->poly][lt->tri[1]].uv; \
525  (uv_tri)[2] = uvlayer[lt->poly][lt->tri[2]].uv; \
526  } \
527  ((void)0)
528 
531 /* Finish projection painting structs */
532 
533 static int project_paint_face_paint_tile(Image *ima, const float *uv)
534 {
535  if (ima == NULL || ima->source != IMA_SRC_TILED) {
536  return 0;
537  }
538 
539  /* Currently, faces are assumed to belong to one tile, so checking the first loop is enough. */
540  int tx = (int)uv[0];
541  int ty = (int)uv[1];
542  return 1001 + 10 * ty + tx;
543 }
544 
546 {
547  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
548  Material *ma = ps->mat_array[mp->mat_nr];
549  return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
550 }
551 
552 static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_index)
553 {
554  if (ps->do_stencil_brush) {
555  return ps->stencil_ima;
556  }
557 
558  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
559  Material *ma = ps->mat_array[mp->mat_nr];
560  TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
561  return slot ? slot->ima : ps->canvas_ima;
562 }
563 
565 {
566  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
567  Material *ma = ps->mat_array[mp->mat_nr];
568  return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
569 }
570 
571 static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
572 {
573  const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
574  Material *ma = ps->mat_array[mp->mat_nr];
575  TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
576  return slot ? slot->ima : ps->clone_ima;
577 }
578 
579 /* fast projection bucket array lookup, use the safe version for bound checking */
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);
760  premul_float_to_straight_uchar(rgba, rgba_tmp_f);
761  }
762  }
763  else {
764  if (rgba) {
765  bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
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 cant do much here */
995  x_diff = fabsf(p1[0] - p2[0]);
996 
997  /* yuck, vertical line, we cant 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 short *no1, *no2, *no3;
1720  no1 = ps->mvert_eval[lt_vtri[0]].no;
1721  no2 = ps->mvert_eval[lt_vtri[1]].no;
1722  no3 = ps->mvert_eval[lt_vtri[2]].no;
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 #if 1
1731  /* In case the normalizing per pixel isn't optimal,
1732  * we could cache or access from evaluated mesh. */
1733  normal_tri_v3(no,
1734  ps->mvert_eval[lt_vtri[0]].co,
1735  ps->mvert_eval[lt_vtri[1]].co,
1736  ps->mvert_eval[lt_vtri[2]].co);
1737 #else
1738  /* Don't use because some modifiers don't have normal data (subsurf for eg). */
1739  copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, tri_index, CD_NORMAL));
1740 #endif
1741  }
1742 
1743  if (UNLIKELY(ps->is_flip_object)) {
1744  negate_v3(no);
1745  }
1746 
1747  /* now we can use the normal as a mask */
1748  if (ps->is_ortho) {
1749  angle_cos = dot_v3v3(ps->viewDir, no);
1750  }
1751  else {
1752  /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
1753  float viewDirPersp[3];
1754  const float *co1, *co2, *co3;
1755  co1 = ps->mvert_eval[lt_vtri[0]].co;
1756  co2 = ps->mvert_eval[lt_vtri[1]].co;
1757  co3 = ps->mvert_eval[lt_vtri[2]].co;
1758 
1759  /* Get the direction from the viewPoint to the pixel and normalize */
1760  viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
1761  viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
1762  viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
1763  normalize_v3(viewDirPersp);
1764  if (UNLIKELY(ps->is_flip_object)) {
1765  negate_v3(viewDirPersp);
1766  }
1767 
1768  angle_cos = dot_v3v3(viewDirPersp, no);
1769  }
1770 
1771  /* If backface culling is disabled, allow painting on back faces. */
1772  if (!ps->do_backfacecull) {
1773  angle_cos = fabsf(angle_cos);
1774  }
1775 
1776  if (angle_cos <= ps->normal_angle__cos) {
1777  /* outsize the normal limit*/
1778  return 0.0f;
1779  }
1780  if (angle_cos < ps->normal_angle_inner__cos) {
1781  mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
1782  } /* otherwise no mask normal is needed, we're within the limit */
1783  }
1784 
1785  /* This only works when the opacity doesn't change while painting, stylus pressure messes with
1786  * this so don't use it. */
1787  // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush);
1788 
1789  return mask;
1790 }
1791 
1792 static int project_paint_pixel_sizeof(const short tool)
1793 {
1794  if (ELEM(tool, PAINT_TOOL_CLONE, PAINT_TOOL_SMEAR)) {
1795  return sizeof(ProjPixelClone);
1796  }
1797  return sizeof(ProjPixel);
1798 }
1799 
1800 static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
1801 {
1802  ProjPaintImage *pjIma = tinf->pjima;
1803  int tile_index = tx + ty * tinf->tile_width;
1804  bool generate_tile = false;
1805 
1806  /* double check lock to avoid locking */
1807  if (UNLIKELY(!pjIma->undoRect[tile_index])) {
1808  if (tinf->lock) {
1809  BLI_spin_lock(tinf->lock);
1810  }
1811  if (LIKELY(!pjIma->undoRect[tile_index])) {
1812  pjIma->undoRect[tile_index] = TILE_PENDING;
1813  generate_tile = true;
1814  }
1815  if (tinf->lock) {
1816  BLI_spin_unlock(tinf->lock);
1817  }
1818  }
1819 
1820  if (generate_tile) {
1821  ListBase *undo_tiles = ED_image_paint_tile_list_get();
1822  volatile void *undorect;
1823  if (tinf->masked) {
1824  undorect = ED_image_paint_tile_push(undo_tiles,
1825  pjIma->ima,
1826  pjIma->ibuf,
1827  tinf->tmpibuf,
1828  &pjIma->iuser,
1829  tx,
1830  ty,
1831  &pjIma->maskRect[tile_index],
1832  &pjIma->valid[tile_index],
1833  true,
1834  false);
1835  }
1836  else {
1837  undorect = ED_image_paint_tile_push(undo_tiles,
1838  pjIma->ima,
1839  pjIma->ibuf,
1840  tinf->tmpibuf,
1841  &pjIma->iuser,
1842  tx,
1843  ty,
1844  NULL,
1845  &pjIma->valid[tile_index],
1846  true,
1847  false);
1848  }
1849 
1850  BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf);
1851  /* tile ready, publish */
1852  if (tinf->lock) {
1853  BLI_spin_lock(tinf->lock);
1854  }
1855  pjIma->undoRect[tile_index] = undorect;
1856  if (tinf->lock) {
1857  BLI_spin_unlock(tinf->lock);
1858  }
1859  }
1860 
1861  return tile_index;
1862 }
1863 
1864 /* run this function when we know a bucket's, face's pixel can be initialized,
1865  * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
1867  MemArena *arena,
1868  const TileInfo *tinf,
1869  int x_px,
1870  int y_px,
1871  const float mask,
1872  const int tri_index,
1873  const float pixelScreenCo[4],
1874  const float world_spaceCo[3],
1875  const float w[3])
1876 {
1877  ProjPixel *projPixel;
1878  int x_tile, y_tile;
1879  int x_round, y_round;
1880  int tile_offset;
1881  /* volatile is important here to ensure pending check is not optimized away by compiler*/
1882  volatile int tile_index;
1883 
1884  ProjPaintImage *projima = tinf->pjima;
1885  ImBuf *ibuf = projima->ibuf;
1886  /* wrap pixel location */
1887 
1888  x_px = mod_i(x_px, ibuf->x);
1889  y_px = mod_i(y_px, ibuf->y);
1890 
1892  projPixel = BLI_memarena_alloc(arena, ps->pixel_sizeof);
1893 
1894  /* calculate the undo tile offset of the pixel, used to store the original
1895  * pixel color and accumulated mask if any */
1896  x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS;
1897  y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS;
1898 
1899  x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE;
1900  y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE;
1901  // memset(projPixel, 0, size);
1902 
1903  tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE;
1904  tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
1905 
1906  /* other thread may be initializing the tile so wait here */
1907  while (projima->undoRect[tile_index] == TILE_PENDING) {
1908  /* pass */
1909  }
1910 
1911  BLI_assert(tile_index <
1914 
1915  projPixel->valid = projima->valid[tile_index];
1916 
1917  if (ibuf->rect_float) {
1918  projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
1919  projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
1920  zero_v4(projPixel->newColor.f);
1921  }
1922  else {
1923  projPixel->pixel.ch_pt = (uchar *)(ibuf->rect + (x_px + y_px * ibuf->x));
1924  projPixel->origColor.uint_pt = (uint *)projima->undoRect[tile_index] + tile_offset;
1925  projPixel->newColor.uint = 0;
1926  }
1927 
1928  /* Screen-space unclamped, we could keep its z and w values but don't need them at the moment. */
1929  if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
1930  copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
1931  }
1932 
1933  copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
1934 
1935  projPixel->x_px = x_px;
1936  projPixel->y_px = y_px;
1937 
1938  projPixel->mask = (ushort)(mask * 65535);
1939  if (ps->do_masking) {
1940  projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
1941  }
1942  else {
1943  projPixel->mask_accum = NULL;
1944  }
1945 
1946  /* which bounding box cell are we in?, needed for undo */
1947  projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
1948  ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) *
1950 
1951  /* done with view3d_project_float inline */
1952  if (ps->tool == PAINT_TOOL_CLONE) {
1953  if (ps->poly_to_loop_uv_clone) {
1954  ImBuf *ibuf_other;
1955  Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
1956 
1957  if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
1958  const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
1959  const float *lt_other_tri_uv[3] = {
1960  PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, lt_other)};
1961 
1962  /* BKE_image_acquire_ibuf - TODO - this may be slow */
1963 
1964  if (ibuf->rect_float) {
1965  if (ibuf_other->rect_float) { /* from float to float */
1967  lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
1968  }
1969  else { /* from char to float */
1970  uchar rgba_ub[4];
1971  float rgba[4];
1972  project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
1973  if (ps->use_colormanagement) {
1974  srgb_to_linearrgb_uchar4(rgba, rgba_ub);
1975  }
1976  else {
1977  rgba_uchar_to_float(rgba, rgba_ub);
1978  }
1979  straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
1980  }
1981  }
1982  else {
1983  if (ibuf_other->rect_float) { /* float to char */
1984  float rgba[4];
1985  project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
1986  premul_to_straight_v4(rgba);
1987  if (ps->use_colormanagement) {
1988  linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
1989  }
1990  else {
1991  rgb_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
1992  }
1993  ((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
1994  }
1995  else { /* char to char */
1997  lt_other_tri_uv, ibuf_other, w, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
1998  }
1999  }
2000 
2001  BKE_image_release_ibuf(other_tpage, ibuf_other, NULL);
2002  }
2003  else {
2004  if (ibuf->rect_float) {
2005  ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
2006  }
2007  else {
2008  ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
2009  }
2010  }
2011  }
2012  else {
2013  float co[2];
2014  sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
2015 
2016  /* no need to initialize the bucket, we're only checking buckets faces and for this
2017  * the faces are already initialized in project_paint_delayed_face_init(...) */
2018  if (ibuf->rect_float) {
2019  if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) {
2020  /* zero alpha - ignore */
2021  ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0;
2022  }
2023  }
2024  else {
2025  if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) {
2026  /* zero alpha - ignore */
2027  ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0;
2028  }
2029  }
2030  }
2031  }
2032 
2033 #ifdef PROJ_DEBUG_PAINT
2034  if (ibuf->rect_float) {
2035  projPixel->pixel.f_pt[0] = 0;
2036  }
2037  else {
2038  projPixel->pixel.ch_pt[0] = 0;
2039  }
2040 #endif
2041  /* pointer arithmetic */
2042  projPixel->image_index = projima - ps->projImages;
2043 
2044  return projPixel;
2045 }
2046 
2047 static bool line_clip_rect2f(const rctf *cliprect,
2048  const rctf *rect,
2049  const float l1[2],
2050  const float l2[2],
2051  float l1_clip[2],
2052  float l2_clip[2])
2053 {
2054  /* first account for horizontal, then vertical lines */
2055  /* horiz */
2056  if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
2057  /* is the line out of range on its Y axis? */
2058  if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
2059  return false;
2060  }
2061  /* line is out of range on its X axis */
2062  if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) {
2063  return false;
2064  }
2065 
2066  /* this is a single point (or close to)*/
2067  if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
2068  if (BLI_rctf_isect_pt_v(rect, l1)) {
2069  copy_v2_v2(l1_clip, l1);
2070  copy_v2_v2(l2_clip, l2);
2071  return true;
2072  }
2073  return false;
2074  }
2075 
2076  copy_v2_v2(l1_clip, l1);
2077  copy_v2_v2(l2_clip, l2);
2078  CLAMP(l1_clip[0], rect->xmin, rect->xmax);
2079  CLAMP(l2_clip[0], rect->xmin, rect->xmax);
2080  return true;
2081  }
2082  if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
2083  /* is the line out of range on its X axis? */
2084  if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
2085  return false;
2086  }
2087 
2088  /* line is out of range on its Y axis */
2089  if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) {
2090  return false;
2091  }
2092 
2093  /* this is a single point (or close to)*/
2094  if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
2095  if (BLI_rctf_isect_pt_v(rect, l1)) {
2096  copy_v2_v2(l1_clip, l1);
2097  copy_v2_v2(l2_clip, l2);
2098  return true;
2099  }
2100  return false;
2101  }
2102 
2103  copy_v2_v2(l1_clip, l1);
2104  copy_v2_v2(l2_clip, l2);
2105  CLAMP(l1_clip[1], rect->ymin, rect->ymax);
2106  CLAMP(l2_clip[1], rect->ymin, rect->ymax);
2107  return true;
2108  }
2109 
2110  float isect;
2111  short ok1 = 0;
2112  short ok2 = 0;
2113 
2114  /* Done with vertical lines */
2115 
2116  /* are either of the points inside the rectangle ? */
2117  if (BLI_rctf_isect_pt_v(rect, l1)) {
2118  copy_v2_v2(l1_clip, l1);
2119  ok1 = 1;
2120  }
2121 
2122  if (BLI_rctf_isect_pt_v(rect, l2)) {
2123  copy_v2_v2(l2_clip, l2);
2124  ok2 = 1;
2125  }
2126 
2127  /* line inside rect */
2128  if (ok1 && ok2) {
2129  return true;
2130  }
2131 
2132  /* top/bottom */
2133  if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) &&
2134  (isect <= cliprect->xmax)) {
2135  if (l1[1] < l2[1]) { /* line 1 is outside */
2136  l1_clip[0] = isect;
2137  l1_clip[1] = rect->ymin;
2138  ok1 = 1;
2139  }
2140  else {
2141  l2_clip[0] = isect;
2142  l2_clip[1] = rect->ymin;
2143  ok2 = 2;
2144  }
2145  }
2146 
2147  if (ok1 && ok2) {
2148  return true;
2149  }
2150 
2151  if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) &&
2152  (isect <= cliprect->xmax)) {
2153  if (l1[1] > l2[1]) { /* line 1 is outside */
2154  l1_clip[0] = isect;
2155  l1_clip[1] = rect->ymax;
2156  ok1 = 1;
2157  }
2158  else {
2159  l2_clip[0] = isect;
2160  l2_clip[1] = rect->ymax;
2161  ok2 = 2;
2162  }
2163  }
2164 
2165  if (ok1 && ok2) {
2166  return true;
2167  }
2168 
2169  /* left/right */
2170  if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) &&
2171  (isect <= cliprect->ymax)) {
2172  if (l1[0] < l2[0]) { /* line 1 is outside */
2173  l1_clip[0] = rect->xmin;
2174  l1_clip[1] = isect;
2175  ok1 = 1;
2176  }
2177  else {
2178  l2_clip[0] = rect->xmin;
2179  l2_clip[1] = isect;
2180  ok2 = 2;
2181  }
2182  }
2183 
2184  if (ok1 && ok2) {
2185  return true;
2186  }
2187 
2188  if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) &&
2189  (isect <= cliprect->ymax)) {
2190  if (l1[0] > l2[0]) { /* line 1 is outside */
2191  l1_clip[0] = rect->xmax;
2192  l1_clip[1] = isect;
2193  ok1 = 1;
2194  }
2195  else {
2196  l2_clip[0] = rect->xmax;
2197  l2_clip[1] = isect;
2198  ok2 = 2;
2199  }
2200  }
2201 
2202  if (ok1 && ok2) {
2203  return true;
2204  }
2205  return false;
2206 }
2207 
2213 #ifndef PROJ_DEBUG_NOSEAMBLEED
2214 
2215 static void scale_tri(float insetCos[3][3], const float *origCos[3], const float inset)
2216 {
2217  float cent[3];
2218  cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) * (1.0f / 3.0f);
2219  cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) * (1.0f / 3.0f);
2220  cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) * (1.0f / 3.0f);
2221 
2222  sub_v3_v3v3(insetCos[0], origCos[0], cent);
2223  sub_v3_v3v3(insetCos[1], origCos[1], cent);
2224  sub_v3_v3v3(insetCos[2], origCos[2], cent);
2225 
2226  mul_v3_fl(insetCos[0], inset);
2227  mul_v3_fl(insetCos[1], inset);
2228  mul_v3_fl(insetCos[2], inset);
2229 
2230  add_v3_v3(insetCos[0], cent);
2231  add_v3_v3(insetCos[1], cent);
2232  add_v3_v3(insetCos[2], cent);
2233 }
2234 #endif // PROJ_DEBUG_NOSEAMBLEED
2235 
2236 static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const float v2_2)
2237 {
2238  float x, y;
2239 
2240  x = v1[0] - v2_1;
2241  y = v1[1] - v2_2;
2242  return x * x + y * y;
2243 }
2244 
2251 static bool project_bucket_isect_circle(const float cent[2],
2252  const float radius_squared,
2253  const rctf *bucket_bounds)
2254 {
2255 
2256  /* Would normally to a simple intersection test,
2257  * however we know the bounds of these 2 already intersect so we only need to test
2258  * if the center is inside the vertical or horizontal bounds on either axis,
2259  * this is even less work than an intersection test.
2260  */
2261 #if 0
2262  if (BLI_rctf_isect_pt_v(bucket_bounds, cent)) {
2263  return true;
2264  }
2265 #endif
2266 
2267  if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
2268  (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1])) {
2269  return true;
2270  }
2271 
2272  /* out of bounds left */
2273  if (cent[0] < bucket_bounds->xmin) {
2274  /* lower left out of radius test */
2275  if (cent[1] < bucket_bounds->ymin) {
2276  return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) <
2277  radius_squared) ?
2278  true :
2279  false;
2280  }
2281  /* top left test */
2282  if (cent[1] > bucket_bounds->ymax) {
2283  return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) <
2284  radius_squared) ?
2285  true :
2286  false;
2287  }
2288  }
2289  else if (cent[0] > bucket_bounds->xmax) {
2290  /* lower right out of radius test */
2291  if (cent[1] < bucket_bounds->ymin) {
2292  return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) <
2293  radius_squared) ?
2294  true :
2295  false;
2296  }
2297  /* top right test */
2298  if (cent[1] > bucket_bounds->ymax) {
2299  return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) <
2300  radius_squared) ?
2301  true :
2302  false;
2303  }
2304  }
2305 
2306  return false;
2307 }
2308 
2309 /* Note for #rect_to_uvspace_ortho() and #rect_to_uvspace_persp()
2310  * in ortho view this function gives good results when bucket_bounds are outside the triangle
2311  * however in some cases, perspective view will mess up with faces
2312  * that have minimal screen-space area (viewed from the side).
2313  *
2314  * for this reason its not reliable in this case so we'll use the Simple Barycentric'
2315  * functions that only account for points inside the triangle.
2316  * however switching back to this for ortho is always an option. */
2317 
2318 static void rect_to_uvspace_ortho(const rctf *bucket_bounds,
2319  const float *v1coSS,
2320  const float *v2coSS,
2321  const float *v3coSS,
2322  const float *uv1co,
2323  const float *uv2co,
2324  const float *uv3co,
2325  float bucket_bounds_uv[4][2],
2326  const int flip)
2327 {
2328  float uv[2];
2329  float w[3];
2330 
2331  /* get the UV space bounding box */
2332  uv[0] = bucket_bounds->xmax;
2333  uv[1] = bucket_bounds->ymin;
2334  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2335  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
2336 
2337  // uv[0] = bucket_bounds->xmax; // set above
2338  uv[1] = bucket_bounds->ymax;
2339  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2340  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
2341 
2342  uv[0] = bucket_bounds->xmin;
2343  // uv[1] = bucket_bounds->ymax; // set above
2344  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2345  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
2346 
2347  // uv[0] = bucket_bounds->xmin; // set above
2348  uv[1] = bucket_bounds->ymin;
2349  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w);
2350  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
2351 }
2352 
2353 /* same as above but use barycentric_weights_v2_persp */
2354 static void rect_to_uvspace_persp(const rctf *bucket_bounds,
2355  const float *v1coSS,
2356  const float *v2coSS,
2357  const float *v3coSS,
2358  const float *uv1co,
2359  const float *uv2co,
2360  const float *uv3co,
2361  float bucket_bounds_uv[4][2],
2362  const int flip)
2363 {
2364  float uv[2];
2365  float w[3];
2366 
2367  /* get the UV space bounding box */
2368  uv[0] = bucket_bounds->xmax;
2369  uv[1] = bucket_bounds->ymin;
2370  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2371  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w);
2372 
2373  // uv[0] = bucket_bounds->xmax; // set above
2374  uv[1] = bucket_bounds->ymax;
2375  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2376  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w);
2377 
2378  uv[0] = bucket_bounds->xmin;
2379  // uv[1] = bucket_bounds->ymax; // set above
2380  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2381  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w);
2382 
2383  // uv[0] = bucket_bounds->xmin; // set above
2384  uv[1] = bucket_bounds->ymin;
2385  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w);
2386  interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w);
2387 }
2388 
2389 /* This works as we need it to but we can save a few steps and not use it */
2390 
2391 #if 0
2392 static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2])
2393 {
2394  float v1[2], v2[2];
2395 
2396  v1[0] = p1[0] - p2[0];
2397  v1[1] = p1[1] - p2[1];
2398  v2[0] = p3[0] - p2[0];
2399  v2[1] = p3[1] - p2[1];
2400 
2401  return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
2402 }
2403 #endif
2404 
2405 #define ISECT_1 (1)
2406 #define ISECT_2 (1 << 1)
2407 #define ISECT_3 (1 << 2)
2408 #define ISECT_4 (1 << 3)
2409 #define ISECT_ALL3 ((1 << 3) - 1)
2410 #define ISECT_ALL4 ((1 << 4) - 1)
2411 
2412 /* limit must be a fraction over 1.0f */
2413 static bool IsectPT2Df_limit(
2414  const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float limit)
2415 {
2416  return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) /
2417  (area_tri_v2(v1, v2, v3))) < limit;
2418 }
2419 
2424 static int float_z_sort_flip(const void *p1, const void *p2)
2425 {
2426  return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1);
2427 }
2428 
2429 static int float_z_sort(const void *p1, const void *p2)
2430 {
2431  return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1);
2432 }
2433 
2434 /* assumes one point is within the rectangle */
2435 static bool line_rect_clip(const rctf *rect,
2436  const float l1[4],
2437  const float l2[4],
2438  const float uv1[2],
2439  const float uv2[2],
2440  float uv[2],
2441  bool is_ortho)
2442 {
2443  float min = FLT_MAX, tmp;
2444  float xlen = l2[0] - l1[0];
2445  float ylen = l2[1] - l1[1];
2446 
2447  /* 0.1 might seem too much, but remember, this is pixels! */
2448  if (xlen > 0.1f) {
2449  if ((l1[0] - rect->xmin) * (l2[0] - rect->xmin) <= 0) {
2450  tmp = rect->xmin;
2451  min = min_ff((tmp - l1[0]) / xlen, min);
2452  }
2453  else if ((l1[0] - rect->xmax) * (l2[0] - rect->xmax) < 0) {
2454  tmp = rect->xmax;
2455  min = min_ff((tmp - l1[0]) / xlen, min);
2456  }
2457  }
2458 
2459  if (ylen > 0.1f) {
2460  if ((l1[1] - rect->ymin) * (l2[1] - rect->ymin) <= 0) {
2461  tmp = rect->ymin;
2462  min = min_ff((tmp - l1[1]) / ylen, min);
2463  }
2464  else if ((l1[1] - rect->ymax) * (l2[1] - rect->ymax) < 0) {
2465  tmp = rect->ymax;
2466  min = min_ff((tmp - l1[1]) / ylen, min);
2467  }
2468  }
2469 
2470  if (min == FLT_MAX) {
2471  return false;
2472  }
2473 
2474  tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
2475 
2476  uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0]));
2477  uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1]));
2478 
2479  return true;
2480 }
2481 
2482 static void project_bucket_clip_face(const bool is_ortho,
2483  const bool is_flip_object,
2484  const rctf *cliprect,
2485  const rctf *bucket_bounds,
2486  const float *v1coSS,
2487  const float *v2coSS,
2488  const float *v3coSS,
2489  const float *uv1co,
2490  const float *uv2co,
2491  const float *uv3co,
2492  float bucket_bounds_uv[8][2],
2493  int *tot,
2494  bool cull)
2495 {
2496  int inside_bucket_flag = 0;
2497  int inside_face_flag = 0;
2498  int flip;
2499  bool collinear = false;
2500 
2501  float bucket_bounds_ss[4][2];
2502 
2503  /* detect pathological case where face the three vertices are almost collinear in screen space.
2504  * mostly those will be culled but when flood filling or with
2505  * smooth shading it's a possibility */
2506  if (min_fff(dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS),
2507  dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS),
2508  dist_squared_to_line_v2(v3coSS, v1coSS, v2coSS)) < PROJ_PIXEL_TOLERANCE) {
2509  collinear = true;
2510  }
2511 
2512  /* get the UV space bounding box */
2513  inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS);
2514  inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1;
2515  inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
2516 
2517  if (inside_bucket_flag == ISECT_ALL3) {
2518  /* is_flip_object is used here because we use the face winding */
2519  flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
2520  (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
2521 
2522  /* All screen-space points are inside the bucket bounding box,
2523  * this means we don't need to clip and can simply return the UVs. */
2524  if (flip) { /* facing the back? */
2525  copy_v2_v2(bucket_bounds_uv[0], uv3co);
2526  copy_v2_v2(bucket_bounds_uv[1], uv2co);
2527  copy_v2_v2(bucket_bounds_uv[2], uv1co);
2528  }
2529  else {
2530  copy_v2_v2(bucket_bounds_uv[0], uv1co);
2531  copy_v2_v2(bucket_bounds_uv[1], uv2co);
2532  copy_v2_v2(bucket_bounds_uv[2], uv3co);
2533  }
2534 
2535  *tot = 3;
2536  return;
2537  }
2538  /* Handle pathological case here,
2539  * no need for further intersections below since triangle area is almost zero. */
2540  if (collinear) {
2541  int flag;
2542 
2543  (*tot) = 0;
2544 
2545  if (cull) {
2546  return;
2547  }
2548 
2549  if (inside_bucket_flag & ISECT_1) {
2550  copy_v2_v2(bucket_bounds_uv[*tot], uv1co);
2551  (*tot)++;
2552  }
2553 
2554  flag = inside_bucket_flag & (ISECT_1 | ISECT_2);
2555  if (flag && flag != (ISECT_1 | ISECT_2)) {
2556  if (line_rect_clip(
2557  bucket_bounds, v1coSS, v2coSS, uv1co, uv2co, bucket_bounds_uv[*tot], is_ortho)) {
2558  (*tot)++;
2559  }
2560  }
2561 
2562  if (inside_bucket_flag & ISECT_2) {
2563  copy_v2_v2(bucket_bounds_uv[*tot], uv2co);
2564  (*tot)++;
2565  }
2566 
2567  flag = inside_bucket_flag & (ISECT_2 | ISECT_3);
2568  if (flag && flag != (ISECT_2 | ISECT_3)) {
2569  if (line_rect_clip(
2570  bucket_bounds, v2coSS, v3coSS, uv2co, uv3co, bucket_bounds_uv[*tot], is_ortho)) {
2571  (*tot)++;
2572  }
2573  }
2574 
2575  if (inside_bucket_flag & ISECT_3) {
2576  copy_v2_v2(bucket_bounds_uv[*tot], uv3co);
2577  (*tot)++;
2578  }
2579 
2580  flag = inside_bucket_flag & (ISECT_3 | ISECT_1);
2581  if (flag && flag != (ISECT_3 | ISECT_1)) {
2582  if (line_rect_clip(
2583  bucket_bounds, v3coSS, v1coSS, uv3co, uv1co, bucket_bounds_uv[*tot], is_ortho)) {
2584  (*tot)++;
2585  }
2586  }
2587 
2588  if ((*tot) < 3) {
2589  /* no intersections to speak of, but more probable is that all face is just outside the
2590  * rectangle and culled due to float precision issues. Since above tests have failed,
2591  * just dump triangle as is for painting */
2592  *tot = 0;
2593  copy_v2_v2(bucket_bounds_uv[*tot], uv1co);
2594  (*tot)++;
2595  copy_v2_v2(bucket_bounds_uv[*tot], uv2co);
2596  (*tot)++;
2597  copy_v2_v2(bucket_bounds_uv[*tot], uv3co);
2598  (*tot)++;
2599  return;
2600  }
2601 
2602  return;
2603  }
2604 
2605  /* get the UV space bounding box */
2606  /* use IsectPT2Df_limit here so we catch points are are touching the tri edge
2607  * (or a small fraction over) */
2608  bucket_bounds_ss[0][0] = bucket_bounds->xmax;
2609  bucket_bounds_ss[0][1] = bucket_bounds->ymin;
2610  inside_face_flag |= (IsectPT2Df_limit(
2611  bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2612  ISECT_1 :
2613  0);
2614 
2615  bucket_bounds_ss[1][0] = bucket_bounds->xmax;
2616  bucket_bounds_ss[1][1] = bucket_bounds->ymax;
2617  inside_face_flag |= (IsectPT2Df_limit(
2618  bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2619  ISECT_2 :
2620  0);
2621 
2622  bucket_bounds_ss[2][0] = bucket_bounds->xmin;
2623  bucket_bounds_ss[2][1] = bucket_bounds->ymax;
2624  inside_face_flag |= (IsectPT2Df_limit(
2625  bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2626  ISECT_3 :
2627  0);
2628 
2629  bucket_bounds_ss[3][0] = bucket_bounds->xmin;
2630  bucket_bounds_ss[3][1] = bucket_bounds->ymin;
2631  inside_face_flag |= (IsectPT2Df_limit(
2632  bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ?
2633  ISECT_4 :
2634  0);
2635 
2636  flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
2637  (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
2638 
2639  if (inside_face_flag == ISECT_ALL4) {
2640  /* Bucket is totally inside the screen-space face, we can safely use weights. */
2641 
2642  if (is_ortho) {
2644  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
2645  }
2646  else {
2648  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip);
2649  }
2650 
2651  *tot = 4;
2652  return;
2653  }
2654 
2655  {
2656  /* The Complicated Case!
2657  *
2658  * The 2 cases above are where the face is inside the bucket
2659  * or the bucket is inside the face.
2660  *
2661  * we need to make a convex poly-line from the intersection between the screen-space face
2662  * and the bucket bounds.
2663  *
2664  * There are a number of ways this could be done, currently it just collects all
2665  * intersecting verts, and line intersections, then sorts them clockwise, this is
2666  * a lot easier than evaluating the geometry to do a correct clipping on both shapes.
2667  */
2668 
2669  /* Add a bunch of points, we know must make up the convex hull
2670  * which is the clipped rect and triangle */
2671 
2672  /* Maximum possible 6 intersections when using a rectangle and triangle */
2673 
2674  /* The 3rd float is used to store angle for qsort(), NOT as a Z location */
2675  float isectVCosSS[8][3];
2676  float v1_clipSS[2], v2_clipSS[2];
2677  float w[3];
2678 
2679  /* calc center */
2680  float cent[2] = {0.0f, 0.0f};
2681  /*float up[2] = {0.0f, 1.0f};*/
2682  bool doubles;
2683 
2684  (*tot) = 0;
2685 
2686  if (inside_face_flag & ISECT_1) {
2687  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]);
2688  (*tot)++;
2689  }
2690  if (inside_face_flag & ISECT_2) {
2691  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]);
2692  (*tot)++;
2693  }
2694  if (inside_face_flag & ISECT_3) {
2695  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]);
2696  (*tot)++;
2697  }
2698  if (inside_face_flag & ISECT_4) {
2699  copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]);
2700  (*tot)++;
2701  }
2702 
2703  if (inside_bucket_flag & ISECT_1) {
2704  copy_v2_v2(isectVCosSS[*tot], v1coSS);
2705  (*tot)++;
2706  }
2707  if (inside_bucket_flag & ISECT_2) {
2708  copy_v2_v2(isectVCosSS[*tot], v2coSS);
2709  (*tot)++;
2710  }
2711  if (inside_bucket_flag & ISECT_3) {
2712  copy_v2_v2(isectVCosSS[*tot], v3coSS);
2713  (*tot)++;
2714  }
2715 
2716  if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
2717  if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
2718  if ((inside_bucket_flag & ISECT_1) == 0) {
2719  copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
2720  (*tot)++;
2721  }
2722  if ((inside_bucket_flag & ISECT_2) == 0) {
2723  copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
2724  (*tot)++;
2725  }
2726  }
2727  }
2728 
2729  if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
2730  if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
2731  if ((inside_bucket_flag & ISECT_2) == 0) {
2732  copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
2733  (*tot)++;
2734  }
2735  if ((inside_bucket_flag & ISECT_3) == 0) {
2736  copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
2737  (*tot)++;
2738  }
2739  }
2740  }
2741 
2742  if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
2743  if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
2744  if ((inside_bucket_flag & ISECT_3) == 0) {
2745  copy_v2_v2(isectVCosSS[*tot], v1_clipSS);
2746  (*tot)++;
2747  }
2748  if ((inside_bucket_flag & ISECT_1) == 0) {
2749  copy_v2_v2(isectVCosSS[*tot], v2_clipSS);
2750  (*tot)++;
2751  }
2752  }
2753  }
2754 
2755  if ((*tot) < 3) { /* no intersections to speak of */
2756  *tot = 0;
2757  return;
2758  }
2759 
2760  /* now we have all points we need, collect their angles and sort them clockwise */
2761 
2762  for (int i = 0; i < (*tot); i++) {
2763  cent[0] += isectVCosSS[i][0];
2764  cent[1] += isectVCosSS[i][1];
2765  }
2766  cent[0] = cent[0] / (float)(*tot);
2767  cent[1] = cent[1] / (float)(*tot);
2768 
2769  /* Collect angles for every point around the center point */
2770 
2771 #if 0 /* uses a few more cycles than the above loop */
2772  for (int i = 0; i < (*tot); i++) {
2773  isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]);
2774  }
2775 #endif
2776 
2777  /* Abuse this var for the loop below */
2778  v1_clipSS[0] = cent[0];
2779  v1_clipSS[1] = cent[1] + 1.0f;
2780 
2781  for (int i = 0; i < (*tot); i++) {
2782  v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
2783  v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
2784  isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0],
2785  v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
2786  }
2787 
2788  if (flip) {
2789  qsort(isectVCosSS, *tot, sizeof(float[3]), float_z_sort_flip);
2790  }
2791  else {
2792  qsort(isectVCosSS, *tot, sizeof(float[3]), float_z_sort);
2793  }
2794 
2795  doubles = true;
2796  while (doubles == true) {
2797  doubles = false;
2798 
2799  for (int i = 0; i < (*tot); i++) {
2800  if (fabsf(isectVCosSS[(i + 1) % *tot][0] - isectVCosSS[i][0]) < PROJ_PIXEL_TOLERANCE &&
2801  fabsf(isectVCosSS[(i + 1) % *tot][1] - isectVCosSS[i][1]) < PROJ_PIXEL_TOLERANCE) {
2802  for (int j = i; j < (*tot) - 1; j++) {
2803  isectVCosSS[j][0] = isectVCosSS[j + 1][0];
2804  isectVCosSS[j][1] = isectVCosSS[j + 1][1];
2805  }
2806  /* keep looking for more doubles */
2807  doubles = true;
2808  (*tot)--;
2809  }
2810  }
2811 
2812  /* its possible there is only a few left after remove doubles */
2813  if ((*tot) < 3) {
2814  // printf("removed too many doubles B\n");
2815  *tot = 0;
2816  return;
2817  }
2818  }
2819 
2820  if (is_ortho) {
2821  for (int i = 0; i < (*tot); i++) {
2822  barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
2823  interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
2824  }
2825  }
2826  else {
2827  for (int i = 0; i < (*tot); i++) {
2828  barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w);
2829  interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w);
2830  }
2831  }
2832  }
2833 
2834 #ifdef PROJ_DEBUG_PRINT_CLIP
2835  /* include this at the bottom of the above function to debug the output */
2836 
2837  {
2838  /* If there are ever any problems, */
2839  float test_uv[4][2];
2840  int i;
2841  if (is_ortho) {
2843  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
2844  }
2845  else {
2847  bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
2848  }
2849  printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ",
2850  test_uv[0][0],
2851  test_uv[0][1],
2852  test_uv[1][0],
2853  test_uv[1][1],
2854  test_uv[2][0],
2855  test_uv[2][1],
2856  test_uv[3][0],
2857  test_uv[3][1]);
2858 
2859  printf(" [(%f,%f), (%f,%f), (%f,%f)], ",
2860  uv1co[0],
2861  uv1co[1],
2862  uv2co[0],
2863  uv2co[1],
2864  uv3co[0],
2865  uv3co[1]);
2866 
2867  printf("[");
2868  for (int i = 0; i < (*tot); i++) {
2869  printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]);
2870  }
2871  printf("]),\\\n");
2872  }
2873 #endif
2874 }
2875 
2876 /*
2877  * # This script creates faces in a blender scene from printed data above.
2878  *
2879  * project_ls = [
2880  * ...(output from above block)...
2881  * ]
2882  *
2883  * from Blender import Scene, Mesh, Window, sys, Mathutils
2884  *
2885  * import bpy
2886  *
2887  * V = Mathutils.Vector
2888  *
2889  * def main():
2890  * sce = bpy.data.scenes.active
2891  *
2892  * for item in project_ls:
2893  * bb = item[0]
2894  * uv = item[1]
2895  * poly = item[2]
2896  *
2897  * me = bpy.data.meshes.new()
2898  * ob = sce.objects.new(me)
2899  *
2900  * me.verts.extend([V(bb[0]).xyz, V(bb[1]).xyz, V(bb[2]).xyz, V(bb[3]).xyz])
2901  * me.faces.extend([(0,1,2,3),])
2902  * me.verts.extend([V(uv[0]).xyz, V(uv[1]).xyz, V(uv[2]).xyz])
2903  * me.faces.extend([(4,5,6),])
2904  *
2905  * vs = [V(p).xyz for p in poly]
2906  * print len(vs)
2907  * l = len(me.verts)
2908  * me.verts.extend(vs)
2909  *
2910  * i = l
2911  * while i < len(me.verts):
2912  * ii = i + 1
2913  * if ii == len(me.verts):
2914  * ii = l
2915  * me.edges.extend([i, ii])
2916  * i += 1
2917  *
2918  * if __name__ == '__main__':
2919  * main()
2920  */
2921 
2922 #undef ISECT_1
2923 #undef ISECT_2
2924 #undef ISECT_3
2925 #undef ISECT_4
2926 #undef ISECT_ALL3
2927 #undef ISECT_ALL4
2928 
2929 /* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise
2930  * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */
2931 static bool IsectPoly2Df(const float pt[2], const float uv[][2], const int tot)
2932 {
2933  int i;
2934  if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f) {
2935  return false;
2936  }
2937 
2938  for (i = 1; i < tot; i++) {
2939  if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f) {
2940  return false;
2941  }
2942  }
2943 
2944  return true;
2945 }
2946 static bool IsectPoly2Df_twoside(const float pt[2], const float uv[][2], const int tot)
2947 {
2948  const bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
2949 
2950  for (int i = 1; i < tot; i++) {
2951  if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side) {
2952  return false;
2953  }
2954  }
2955 
2956  return true;
2957 }
2958 
2959 /* One of the most important function for projection painting,
2960  * since it selects the pixels to be added into each bucket.
2961  *
2962  * initialize pixels from this face where it intersects with the bucket_index,
2963  * optionally initialize pixels for removing seams */
2965  const int thread_index,
2966  const int bucket_index,
2967  const int tri_index,
2968  const int image_index,
2969  const rctf *clip_rect,
2970  const rctf *bucket_bounds,
2971  ImBuf *ibuf,
2972  ImBuf **tmpibuf)
2973 {
2974  /* Projection vars, to get the 3D locations into screen space */
2975  MemArena *arena = ps->arena_mt[thread_index];
2976  LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
2977  LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
2978  bool threaded = (ps->thread_tot > 1);
2979 
2980  TileInfo tinf = {
2981  ps->tile_lock,
2982  ps->do_masking,
2984  tmpibuf,
2985  ps->projImages + image_index,
2986  };
2987 
2988  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
2989  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
2990  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
2991 
2992  /* UV/pixel seeking data */
2993  /* Image X/Y-Pixel */
2994  int x, y;
2995  float mask;
2996  /* Image floating point UV - same as x, y but from 0.0-1.0 */
2997  float uv[2];
2998 
2999  /* vert co screen-space, these will be assigned to lt_vtri[0-2] */
3000  const float *v1coSS, *v2coSS, *v3coSS;
3001 
3002  /* Vertex screen-space coords. */
3003  const float *vCo[3];
3004 
3005  float w[3], wco[3];
3006 
3007  /* for convenience only, these will be assigned to lt_tri_uv[0],1,2 or lt_tri_uv[0],2,3 */
3008  float *uv1co, *uv2co, *uv3co;
3009  float pixelScreenCo[4];
3010  bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
3011 
3012  /* Image-space bounds. */
3013  rcti bounds_px;
3014  /* Variables for getting UV-space bounds. */
3015 
3016  /* bucket bounds in UV space so we can init pixels only for this face, */
3017  float lt_uv_pxoffset[3][2];
3018  float xhalfpx, yhalfpx;
3019  const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y;
3020 
3021  /* for early loop exit */
3022  int has_x_isect = 0, has_isect = 0;
3023 
3024  float uv_clip[8][2];
3025  int uv_clip_tot;
3026  const bool is_ortho = ps->is_ortho;
3027  const bool is_flip_object = ps->is_flip_object;
3028  const bool do_backfacecull = ps->do_backfacecull;
3029  const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
3030 
3031  vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
3032  vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
3033  vCo[2] = ps->mvert_eval[lt_vtri[2]].co;
3034 
3035  /* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
3036  * this is done so we can avoid offsetting all the pixels by 0.5 which causes
3037  * problems when wrapping negative coords */
3038  xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
3039  yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
3040 
3041  /* Note about (PROJ_GEOM_TOLERANCE/x) above...
3042  * Needed to add this offset since UV coords are often quads aligned to pixels.
3043  * In this case pixels can be exactly between 2 triangles causing nasty
3044  * artifacts.
3045  *
3046  * This workaround can be removed and painting will still work on most cases
3047  * but since the first thing most people try is painting onto a quad- better make it work.
3048  */
3049 
3050  lt_uv_pxoffset[0][0] = lt_tri_uv[0][0] - xhalfpx;
3051  lt_uv_pxoffset[0][1] = lt_tri_uv[0][1] - yhalfpx;
3052 
3053  lt_uv_pxoffset[1][0] = lt_tri_uv[1][0] - xhalfpx;
3054  lt_uv_pxoffset[1][1] = lt_tri_uv[1][1] - yhalfpx;
3055 
3056  lt_uv_pxoffset[2][0] = lt_tri_uv[2][0] - xhalfpx;
3057  lt_uv_pxoffset[2][1] = lt_tri_uv[2][1] - yhalfpx;
3058 
3059  {
3060  uv1co = lt_uv_pxoffset[0]; /* was lt_tri_uv[i1]; */
3061  uv2co = lt_uv_pxoffset[1]; /* was lt_tri_uv[i2]; */
3062  uv3co = lt_uv_pxoffset[2]; /* was lt_tri_uv[i3]; */
3063 
3064  v1coSS = ps->screenCoords[lt_vtri[0]];
3065  v2coSS = ps->screenCoords[lt_vtri[1]];
3066  v3coSS = ps->screenCoords[lt_vtri[2]];
3067 
3068  /* This function gives is a concave polyline in UV space from the clipped tri*/
3069  project_bucket_clip_face(is_ortho,
3070  is_flip_object,
3071  clip_rect,
3072  bucket_bounds,
3073  v1coSS,
3074  v2coSS,
3075  v3coSS,
3076  uv1co,
3077  uv2co,
3078  uv3co,
3079  uv_clip,
3080  &uv_clip_tot,
3081  do_backfacecull || ps->do_occlude);
3082 
3083  /* Sometimes this happens, better just allow for 8 intersections
3084  * even though there should be max 6 */
3085 #if 0
3086  if (uv_clip_tot > 6) {
3087  printf("this should never happen! %d\n", uv_clip_tot);
3088  }
3089 #endif
3090 
3091  if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
3092 #if 0
3093  project_paint_undo_tiles_init(
3094  &bounds_px, ps->projImages + image_index, tmpibuf, tile_width, threaded, ps->do_masking);
3095 #endif
3096  /* clip face and */
3097 
3098  has_isect = 0;
3099  for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
3100  // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
3101  /* use pixel offset UV coords instead */
3102  uv[1] = (float)y / ibuf_yf;
3103 
3104  has_x_isect = 0;
3105  for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
3106  // uv[0] = (((float)x) + 0.5f) / ibuf->x;
3107  /* use pixel offset UV coords instead */
3108  uv[0] = (float)x / ibuf_xf;
3109 
3110  /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesn't work,
3111  * could check the poly direction but better to do this */
3112  if ((do_backfacecull == true && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) ||
3113  (do_backfacecull == false && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) {
3114 
3115  has_x_isect = has_isect = 1;
3116 
3117  if (is_ortho) {
3119  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3120  }
3121  else {
3123  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3124  }
3125 
3126  /* a pity we need to get the worldspace pixel location here */
3127  if (do_clip || do_3d_mapping) {
3128  interp_v3_v3v3v3(wco,
3129  ps->mvert_eval[lt_vtri[0]].co,
3130  ps->mvert_eval[lt_vtri[1]].co,
3131  ps->mvert_eval[lt_vtri[2]].co,
3132  w);
3133  if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
3134  /* Watch out that no code below this needs to run */
3135  continue;
3136  }
3137  }
3138 
3139  /* Is this UV visible from the view? - raytrace */
3140  /* project_paint_PickFace is less complex, use for testing */
3141  // if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
3142  if ((ps->do_occlude == false) ||
3143  !project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo)) {
3144  mask = project_paint_uvpixel_mask(ps, tri_index, w);
3145 
3146  if (mask > 0.0f) {
3148  bucketPixelNodes,
3150  ps, arena, &tinf, x, y, mask, tri_index, pixelScreenCo, wco, w),
3151  arena);
3152  }
3153  }
3154  }
3155  //#if 0
3156  else if (has_x_isect) {
3157  /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
3158  break;
3159  }
3160  //#endif
3161  }
3162 
3163 #if 0 /* TODO - investigate why this doesn't work sometimes! it should! */
3164  /* no intersection for this entire row,
3165  * after some intersection above means we can quit now */
3166  if (has_x_isect == 0 && has_isect) {
3167  break;
3168  }
3169 #endif
3170  }
3171  }
3172  }
3173 
3174 #ifndef PROJ_DEBUG_NOSEAMBLEED
3175  if (ps->seam_bleed_px > 0.0f && !(ps->faceSeamFlags[tri_index] & PROJ_FACE_DEGENERATE)) {
3176  int face_seam_flag;
3177 
3178  if (threaded) {
3179  /* Other threads could be modifying these vars. */
3181  }
3182 
3183  face_seam_flag = ps->faceSeamFlags[tri_index];
3184 
3185  /* are any of our edges un-initialized? */
3186  if ((face_seam_flag & PROJ_FACE_SEAM_INIT0) == 0 ||
3187  (face_seam_flag & PROJ_FACE_SEAM_INIT1) == 0 ||
3188  (face_seam_flag & PROJ_FACE_SEAM_INIT2) == 0) {
3189  project_face_seams_init(ps, arena, tri_index, 0, true, ibuf->x, ibuf->y);
3190  face_seam_flag = ps->faceSeamFlags[tri_index];
3191 # if 0
3192  printf("seams - %d %d %d %d\n",
3193  flag & PROJ_FACE_SEAM0,
3194  flag & PROJ_FACE_SEAM1,
3195  flag & PROJ_FACE_SEAM2);
3196 # endif
3197  }
3198 
3199  if ((face_seam_flag & (PROJ_FACE_SEAM0 | PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2)) == 0) {
3200 
3201  if (threaded) {
3202  /* Other threads could be modifying these vars. */
3204  }
3205  }
3206  else {
3207  /* we have a seam - deal with it! */
3208 
3209  /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */
3210  float insetCos[3][3];
3211 
3212  /* Vertex screen-space coords. */
3213  const float *vCoSS[3];
3214 
3215  /* Store the screen-space coords of the face,
3216  * clipped by the bucket's screen aligned rectangle. */
3217  float bucket_clip_edges[2][2];
3218  float edge_verts_inset_clip[2][3];
3219  /* face edge pairs - loop through these:
3220  * ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
3221  int fidx1, fidx2;
3222 
3223  float seam_subsection[4][2];
3224  float fac1, fac2;
3225 
3226  /* Pixelspace UVs. */
3227  float lt_puv[3][2];
3228 
3229  lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
3230  lt_puv[0][1] = lt_uv_pxoffset[0][1] * ibuf->y;
3231 
3232  lt_puv[1][0] = lt_uv_pxoffset[1][0] * ibuf->x;
3233  lt_puv[1][1] = lt_uv_pxoffset[1][1] * ibuf->y;
3234 
3235  lt_puv[2][0] = lt_uv_pxoffset[2][0] * ibuf->x;
3236  lt_puv[2][1] = lt_uv_pxoffset[2][1] * ibuf->y;
3237 
3238  if ((ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM0) ||
3239  (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM1) ||
3240  (ps->faceSeamFlags[tri_index] & PROJ_FACE_SEAM2)) {
3241  uv_image_outset(ps, lt_uv_pxoffset, lt_puv, tri_index, ibuf->x, ibuf->y);
3242  }
3243 
3244  /* ps->loopSeamUVs cant be modified when threading, now this is done we can unlock. */
3245  if (threaded) {
3246  /* Other threads could be modifying these vars */
3248  }
3249 
3250  vCoSS[0] = ps->screenCoords[lt_vtri[0]];
3251  vCoSS[1] = ps->screenCoords[lt_vtri[1]];
3252  vCoSS[2] = ps->screenCoords[lt_vtri[2]];
3253 
3254  /* PROJ_FACE_SCALE_SEAM must be slightly less than 1.0f */
3255  if (is_ortho) {
3256  scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM);
3257  }
3258  else {
3259  scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM);
3260  }
3261 
3262  for (fidx1 = 0; fidx1 < 3; fidx1++) {
3263  /* next fidx in the face (0,1,2) -> (1,2,0) */
3264  fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1;
3265 
3266  if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
3267  line_clip_rect2f(clip_rect,
3268  bucket_bounds,
3269  vCoSS[fidx1],
3270  vCoSS[fidx2],
3271  bucket_clip_edges[0],
3272  bucket_clip_edges[1])) {
3273  /* Avoid div by zero. */
3274  if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) {
3275  uint loop_idx = ps->mlooptri_eval[tri_index].tri[fidx1];
3276  LoopSeamData *seam_data = &ps->loopSeamData[loop_idx];
3277  float(*seam_uvs)[2] = seam_data->seam_uvs;
3278 
3279  if (is_ortho) {
3280  fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
3281  fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
3282  }
3283  else {
3285  ps, bucket_clip_edges[0], vCo[fidx1], vCo[fidx2]);
3287  ps, bucket_clip_edges[1], vCo[fidx1], vCo[fidx2]);
3288  }
3289 
3290  interp_v2_v2v2(seam_subsection[0], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac1);
3291  interp_v2_v2v2(seam_subsection[1], lt_uv_pxoffset[fidx1], lt_uv_pxoffset[fidx2], fac2);
3292 
3293  interp_v2_v2v2(seam_subsection[2], seam_uvs[0], seam_uvs[1], fac2);
3294  interp_v2_v2v2(seam_subsection[3], seam_uvs[0], seam_uvs[1], fac1);
3295 
3296  /* if the bucket_clip_edges values Z values was kept we could avoid this
3297  * Inset needs to be added so occlusion tests wont hit adjacent faces */
3298  interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1);
3299  interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2);
3300 
3301  if (pixel_bounds_uv(seam_subsection, &bounds_px, ibuf->x, ibuf->y)) {
3302  /* bounds between the seam rect and the uvspace bucket pixels */
3303 
3304  has_isect = 0;
3305  for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
3306  // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
3307  /* use offset uvs instead */
3308  uv[1] = (float)y / ibuf_yf;
3309 
3310  has_x_isect = 0;
3311  for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
3312  const float puv[2] = {(float)x, (float)y};
3313  bool in_bounds;
3314  // uv[0] = (((float)x) + 0.5f) / (float)ibuf->x;
3315  /* use offset uvs instead */
3316  uv[0] = (float)x / ibuf_xf;
3317 
3318  /* test we're inside uvspace bucket and triangle bounds */
3319  if (equals_v2v2(seam_uvs[0], seam_uvs[1])) {
3320  in_bounds = isect_point_tri_v2(uv, UNPACK3(seam_subsection));
3321  }
3322  else {
3323  in_bounds = isect_point_quad_v2(uv, UNPACK4(seam_subsection));
3324  }
3325 
3326  if (in_bounds) {
3327  if ((seam_data->corner_dist_sq[0] > 0.0f) &&
3328  (len_squared_v2v2(puv, seam_data->seam_puvs[0]) <
3329  seam_data->corner_dist_sq[0]) &&
3330  (len_squared_v2v2(puv, lt_puv[fidx1]) > ps->seam_bleed_px_sq)) {
3331  in_bounds = false;
3332  }
3333  else if ((seam_data->corner_dist_sq[1] > 0.0f) &&
3334  (len_squared_v2v2(puv, seam_data->seam_puvs[1]) <
3335  seam_data->corner_dist_sq[1]) &&
3336  (len_squared_v2v2(puv, lt_puv[fidx2]) > ps->seam_bleed_px_sq)) {
3337  in_bounds = false;
3338  }
3339  }
3340 
3341  if (in_bounds) {
3342  float pixel_on_edge[4];
3343  float fac;
3344 
3345  if (is_ortho) {
3347  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3348  }
3349  else {
3351  uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
3352  }
3353 
3354  /* We need the coord of the pixel on the edge, for the occlusion query. */
3355  fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
3357  pixel_on_edge, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
3358 
3359  if (!is_ortho) {
3360  pixel_on_edge[3] = 1.0f;
3361  /* cast because of const */
3362  mul_m4_v4((float(*)[4])ps->projectMat, pixel_on_edge);
3363  pixel_on_edge[0] = (float)(ps->winx * 0.5f) +
3364  (ps->winx * 0.5f) * pixel_on_edge[0] / pixel_on_edge[3];
3365  pixel_on_edge[1] = (float)(ps->winy * 0.5f) +
3366  (ps->winy * 0.5f) * pixel_on_edge[1] / pixel_on_edge[3];
3367  /* Use the depth for bucket point occlusion */
3368  pixel_on_edge[2] = pixel_on_edge[2] / pixel_on_edge[3];
3369  }
3370 
3371  if ((ps->do_occlude == false) ||
3373  ps, bucketFaceNodes, tri_index, pixel_on_edge)) {
3374  /* a pity we need to get the worldspace
3375  * pixel location here */
3376  if (do_clip || do_3d_mapping) {
3377  interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
3378 
3379  if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
3380  /* Watch out that no code below
3381  * this needs to run */
3382  continue;
3383  }
3384  }
3385 
3386  mask = project_paint_uvpixel_mask(ps, tri_index, w);
3387 
3388  if (mask > 0.0f) {
3390  bucketPixelNodes,
3392  ps, arena, &tinf, x, y, mask, tri_index, pixelScreenCo, wco, w),
3393  arena);
3394  }
3395  }
3396  }
3397  else if (has_x_isect) {
3398  /* assuming the face is not a bow-tie - we know
3399  * we can't intersect again on the X */
3400  break;
3401  }
3402  }
3403 
3404 # if 0 /* TODO - investigate why this doesn't work sometimes! it should! */
3405  /* no intersection for this entire row,
3406  * after some intersection above means we can quit now */
3407  if (has_x_isect == 0 && has_isect) {
3408  break;
3409  }
3410 # endif
3411  }
3412  }
3413  }
3414  }
3415  }
3416  }
3417  }
3418 #else
3419  UNUSED_VARS(vCo, threaded);
3420 #endif /* PROJ_DEBUG_NOSEAMBLEED */
3421 }
3422 
3428  const float min[2],
3429  const float max[2],
3430  int bucketMin[2],
3431  int bucketMax[2])
3432 {
3433  /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
3434 
3435  /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f
3436  * is always truncated to 1, is this really correct?? - jwilkins */
3437 
3438  /* these offsets of 0.5 and 1.5 seem odd but they are correct */
3439  bucketMin[0] =
3440  (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f);
3441  bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) *
3442  ps->buckets_y) +
3443  0.5f);
3444 
3445  bucketMax[0] =
3446  (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
3447  bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) *
3448  ps->buckets_y) +
3449  1.5f);
3450 
3451  /* in case the rect is outside the mesh 2d bounds */
3452  CLAMP(bucketMin[0], 0, ps->buckets_x);
3453  CLAMP(bucketMin[1], 0, ps->buckets_y);
3454 
3455  CLAMP(bucketMax[0], 0, ps->buckets_x);
3456  CLAMP(bucketMax[1], 0, ps->buckets_y);
3457 }
3458 
3459 /* set bucket_bounds to a screen space-aligned floating point bound-box */
3461  const int bucket_x,
3462  const int bucket_y,
3463  rctf *bucket_bounds)
3464 {
3465  /* left */
3466  bucket_bounds->xmin = (ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)));
3467  /* right */
3468  bucket_bounds->xmax = (ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)));
3469 
3470  /* bottom */
3471  bucket_bounds->ymin = (ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)));
3472  /* top */
3473  bucket_bounds->ymax = (ps->screenMin[1] +
3474  ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)));
3475 }
3476 
3477 /* Fill this bucket with pixels from the faces that intersect it.
3478  *
3479  * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
3480 static void project_bucket_init(const ProjPaintState *ps,
3481  const int thread_index,
3482  const int bucket_index,
3483  const rctf *clip_rect,
3484  const rctf *bucket_bounds)
3485 {
3486  LinkNode *node;
3487  int tri_index, image_index = 0;
3488  ImBuf *ibuf = NULL;
3489  Image *tpage_last = NULL, *tpage;
3490  ImBuf *tmpibuf = NULL;
3491  int tile_last = 0;
3492 
3493  if (ps->image_tot == 1) {
3494  /* Simple loop, no context switching */
3495  ibuf = ps->projImages[0].ibuf;
3496 
3497  for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
3499  thread_index,
3500  bucket_index,
3501  POINTER_AS_INT(node->link),
3502  0,
3503  clip_rect,
3504  bucket_bounds,
3505  ibuf,
3506  &tmpibuf);
3507  }
3508  }
3509  else {
3510 
3511  /* More complicated loop, switch between images */
3512  for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
3513  tri_index = POINTER_AS_INT(node->link);
3514 
3515  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
3516  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
3517 
3518  /* Image context switching */
3519  tpage = project_paint_face_paint_image(ps, tri_index);
3520  int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
3521  if (tpage_last != tpage || tile_last != tile) {
3522  tpage_last = tpage;
3523  tile_last = tile;
3524 
3525  ibuf = NULL;
3526  for (image_index = 0; image_index < ps->image_tot; image_index++) {
3527  ProjPaintImage *projIma = &ps->projImages[image_index];
3528  if ((projIma->ima == tpage) && (projIma->iuser.tile == tile)) {
3529  ibuf = projIma->ibuf;
3530  break;
3531  }
3532  }
3533  BLI_assert(ibuf != NULL);
3534  }
3535  /* context switching done */
3536 
3538  thread_index,
3539  bucket_index,
3540  tri_index,
3541  image_index,
3542  clip_rect,
3543  bucket_bounds,
3544  ibuf,
3545  &tmpibuf);
3546  }
3547  }
3548 
3549  if (tmpibuf) {
3550  IMB_freeImBuf(tmpibuf);
3551  }
3552 
3553  ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
3554 }
3555 
3556 /* We want to know if a bucket and a face overlap in screen-space
3557  *
3558  * Note, if this ever returns false positives its not that bad, since a face in the bounding area
3559  * will have its pixels calculated when it might not be needed later, (at the moment at least)
3560  * obviously it shouldn't have bugs though */
3561 
3563  int bucket_x,
3564  int bucket_y,
3565  const MLoopTri *lt)
3566 {
3567  /* TODO - replace this with a trickier method that uses side-of-line for all
3568  * #ProjPaintState.screenCoords edges against the closest bucket corner. */
3569  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
3570  rctf bucket_bounds;
3571  float p1[2], p2[2], p3[2], p4[2];
3572  const float *v, *v1, *v2, *v3;
3573  int fidx;
3574 
3575  project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds);
3576 
3577  /* Is one of the faces verts in the bucket bounds? */
3578 
3579  fidx = 2;
3580  do {
3581  v = ps->screenCoords[lt_vtri[fidx]];
3582  if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) {
3583  return true;
3584  }
3585  } while (fidx--);
3586 
3587  v1 = ps->screenCoords[lt_vtri[0]];
3588  v2 = ps->screenCoords[lt_vtri[1]];
3589  v3 = ps->screenCoords[lt_vtri[2]];
3590 
3591  p1[0] = bucket_bounds.xmin;
3592  p1[1] = bucket_bounds.ymin;
3593  p2[0] = bucket_bounds.xmin;
3594  p2[1] = bucket_bounds.ymax;
3595  p3[0] = bucket_bounds.xmax;
3596  p3[1] = bucket_bounds.ymax;
3597  p4[0] = bucket_bounds.xmax;
3598  p4[1] = bucket_bounds.ymin;
3599 
3600  if (isect_point_tri_v2(p1, v1, v2, v3) || isect_point_tri_v2(p2, v1, v2, v3) ||
3601  isect_point_tri_v2(p3, v1, v2, v3) || isect_point_tri_v2(p4, v1, v2, v3) ||
3602  /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
3603  (isect_seg_seg_v2(p1, p2, v1, v2) || isect_seg_seg_v2(p1, p2, v2, v3)) ||
3604  (isect_seg_seg_v2(p2, p3, v1, v2) || isect_seg_seg_v2(p2, p3, v2, v3)) ||
3605  (isect_seg_seg_v2(p3, p4, v1, v2) || isect_seg_seg_v2(p3, p4, v2, v3)) ||
3606  (isect_seg_seg_v2(p4, p1, v1, v2) || isect_seg_seg_v2(p4, p1, v2, v3))) {
3607  return true;
3608  }
3609 
3610  return false;
3611 }
3612 
3613 /* Add faces to the bucket but don't initialize its pixels
3614  * TODO - when painting occluded, sort the faces on their min-Z
3615  * and only add faces that faces that are not occluded */
3617  const MLoopTri *lt,
3618  const int tri_index)
3619 {
3620  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
3621  float min[2], max[2], *vCoSS;
3622  /* for ps->bucketRect indexing */
3623  int bucketMin[2], bucketMax[2];
3624  int fidx, bucket_x, bucket_y;
3625  /* for early loop exit */
3626  int has_x_isect = -1, has_isect = 0;
3627  /* just use the first thread arena since threading has not started yet */
3628  MemArena *arena = ps->arena_mt[0];
3629 
3630  INIT_MINMAX2(min, max);
3631 
3632  fidx = 2;
3633  do {
3634  vCoSS = ps->screenCoords[lt_vtri[fidx]];
3635  minmax_v2v2_v2(min, max, vCoSS);
3636  } while (fidx--);
3637 
3638  project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax);
3639 
3640  for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) {
3641  has_x_isect = 0;
3642  for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) {
3643  if (project_bucket_face_isect(ps, bucket_x, bucket_y, lt)) {
3644  int bucket_index = bucket_x + (bucket_y * ps->buckets_x);
3645  BLI_linklist_prepend_arena(&ps->bucketFaces[bucket_index],
3646  /* cast to a pointer to shut up the compiler */
3647  POINTER_FROM_INT(tri_index),
3648  arena);
3649 
3650  has_x_isect = has_isect = 1;
3651  }
3652  else if (has_x_isect) {
3653  /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
3654  break;
3655  }
3656  }
3657 
3658  /* no intersection for this entire row,
3659  * after some intersection above means we can quit now */
3660  if (has_x_isect == 0 && has_isect) {
3661  break;
3662  }
3663  }
3664 
3665 #ifndef PROJ_DEBUG_NOSEAMBLEED
3666  if (ps->seam_bleed_px > 0.0f) {
3667  /* set as uninitialized */
3668  ps->loopSeamData[lt->tri[0]].seam_uvs[0][0] = FLT_MAX;
3669  ps->loopSeamData[lt->tri[1]].seam_uvs[0][0] = FLT_MAX;
3670  ps->loopSeamData[lt->tri[2]].seam_uvs[0][0] = FLT_MAX;
3671  }
3672 #endif
3673 }
3674 
3675 static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmetry_flag)
3676 {
3677  float mat[3][3];
3678  float viewmat[4][4];
3679  float viewinv[4][4];
3680 
3681  ps->viewDir[0] = 0.0f;
3682  ps->viewDir[1] = 0.0f;
3683  ps->viewDir[2] = 1.0f;
3684 
3685  copy_m4_m4(ps->obmat, ps->ob->obmat);
3686 
3687  if (symmetry_flag) {
3688  int i;
3689  for (i = 0; i < 3; i++) {
3690  if ((symmetry_flag >> i) & 1) {
3691  negate_v3(ps->obmat[i]);
3692  ps->is_flip_object = !ps->is_flip_object;
3693  }
3694  }
3695  }
3696 
3697  invert_m4_m4(ps->obmat_imat, ps->obmat);
3698 
3700  /* normal drawing */
3701  ps->winx = ps->region->winx;
3702  ps->winy = ps->region->winy;
3703 
3704  copy_m4_m4(viewmat, ps->rv3d->viewmat);
3705  copy_m4_m4(viewinv, ps->rv3d->viewinv);
3706 
3708 
3710  ps->depsgraph, ps->v3d, ps->rv3d, &ps->clip_start, &ps->clip_end, true);
3711  }
3712  else {
3713  /* re-projection */
3714  float winmat[4][4];
3715  float vmat[4][4];
3716 
3717  ps->winx = ps->reproject_ibuf->x;
3718  ps->winy = ps->reproject_ibuf->y;
3719 
3720  if (ps->source == PROJ_SRC_IMAGE_VIEW) {
3721  /* image stores camera data, tricky */
3722  IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
3723  IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
3724 
3725  const float *array = (float *)IDP_Array(view_data);
3726 
3727  /* use image array, written when creating image */
3728  memcpy(winmat, array, sizeof(winmat));
3729  array += sizeof(winmat) / sizeof(float);
3730  memcpy(viewmat, array, sizeof(viewmat));
3731  array += sizeof(viewmat) / sizeof(float);
3732  ps->clip_start = array[0];
3733  ps->clip_end = array[1];
3734  ps->is_ortho = array[2] ? 1 : 0;
3735 
3736  invert_m4_m4(viewinv, viewmat);
3737  }
3738  else if (ps->source == PROJ_SRC_IMAGE_CAM) {
3739  Object *cam_ob_eval = DEG_get_evaluated_object(ps->depsgraph, ps->scene->camera);
3741 
3742  /* viewmat & viewinv */
3743  copy_m4_m4(viewinv, cam_ob_eval->obmat);
3744  normalize_m4(viewinv);
3745  invert_m4_m4(viewmat, viewinv);
3746 
3747  /* window matrix, clipping and ortho */
3749  BKE_camera_params_from_object(&params, cam_ob_eval);
3750  BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
3752 
3753  copy_m4_m4(winmat, params.winmat);
3754  ps->clip_start = params.clip_start;
3755  ps->clip_end = params.clip_end;
3756  ps->is_ortho = params.is_ortho;
3757  }
3758  else {
3759  BLI_assert(0);
3760  }
3761 
3762  /* same as #ED_view3d_ob_project_mat_get */
3763  mul_m4_m4m4(vmat, viewmat, ps->obmat);
3764  mul_m4_m4m4(ps->projectMat, winmat, vmat);
3765  }
3766 
3768 
3769  /* viewDir - object relative */
3770  copy_m3_m4(mat, viewinv);
3771  mul_m3_v3(mat, ps->viewDir);
3772  copy_m3_m4(mat, ps->obmat_imat);
3773  mul_m3_v3(mat, ps->viewDir);
3774  normalize_v3(ps->viewDir);
3775 
3776  if (UNLIKELY(ps->is_flip_object)) {
3777  negate_v3(ps->viewDir);
3778  }
3779 
3780  /* viewPos - object relative */
3781  copy_v3_v3(ps->viewPos, viewinv[3]);
3782  copy_m3_m4(mat, ps->obmat_imat);
3783  mul_m3_v3(mat, ps->viewPos);
3784  add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
3785 }
3786 
3787 static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
3788 {
3789  const MVert *mv;
3790  float *projScreenCo;
3791  float projMargin;
3792  int a;
3793 
3794  INIT_MINMAX2(ps->screenMin, ps->screenMax);
3795 
3796  ps->screenCoords = MEM_mallocN(sizeof(float) * ps->totvert_eval * 4, "ProjectPaint ScreenVerts");
3797  projScreenCo = *ps->screenCoords;
3798 
3799  if (ps->is_ortho) {
3800  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
3801  mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
3802 
3803  /* screen space, not clamped */
3804  projScreenCo[0] = (float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projScreenCo[0];
3805  projScreenCo[1] = (float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projScreenCo[1];
3806  minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
3807  }
3808  }
3809  else {
3810  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
3811  copy_v3_v3(projScreenCo, mv->co);
3812  projScreenCo[3] = 1.0f;
3813 
3814  mul_m4_v4(ps->projectMat, projScreenCo);
3815 
3816  if (projScreenCo[3] > ps->clip_start) {
3817  /* screen space, not clamped */
3818  projScreenCo[0] = (float)(ps->winx * 0.5f) +
3819  (ps->winx * 0.5f) * projScreenCo[0] / projScreenCo[3];
3820  projScreenCo[1] = (float)(ps->winy * 0.5f) +
3821  (ps->winy * 0.5f) * projScreenCo[1] / projScreenCo[3];
3822  /* Use the depth for bucket point occlusion */
3823  projScreenCo[2] = projScreenCo[2] / projScreenCo[3];
3824  minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo);
3825  }
3826  else {
3827  /* TODO - deal with cases where 1 side of a face goes behind the view ?
3828  *
3829  * After some research this is actually very tricky, only option is to
3830  * clip the derived mesh before painting, which is a Pain */
3831  projScreenCo[0] = FLT_MAX;
3832  }
3833  }
3834  }
3835 
3836  /* If this border is not added we get artifacts for faces that
3837  * have a parallel edge and at the bounds of the 2D projected verts eg
3838  * - a single screen aligned quad */
3839  projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f;
3840  ps->screenMax[0] += projMargin;
3841  ps->screenMin[0] -= projMargin;
3842  projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f;
3843  ps->screenMax[1] += projMargin;
3844  ps->screenMin[1] -= projMargin;
3845 
3846  if (ps->source == PROJ_SRC_VIEW) {
3847 #ifdef PROJ_DEBUG_WINCLIP
3848  CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter));
3849  CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter));
3850 
3851  CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
3852  CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
3853 #else
3854  UNUSED_VARS(diameter);
3855 #endif
3856  }
3857  else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
3858  ps->screenMin[0] = 0;
3859  ps->screenMax[0] = (float)(ps->winx);
3860 
3861  ps->screenMin[1] = 0;
3862  ps->screenMax[1] = (float)(ps->winy);
3863  }
3864 }
3865 
3867 {
3868  const MVert *mv;
3869  const MEdge *me;
3870  float *cavities;
3871  int a;
3872 
3873  if (ps->do_mask_cavity) {
3874  int *counter = MEM_callocN(sizeof(int) * ps->totvert_eval, "counter");
3875  float(*edges)[3] = MEM_callocN(sizeof(float[3]) * ps->totvert_eval, "edges");
3876  ps->cavities = MEM_mallocN(sizeof(float) * ps->totvert_eval, "ProjectPaint Cavities");
3877  cavities = ps->cavities;
3878 
3879  for (a = 0, me = ps->medge_eval; a < ps->totedge_eval; a++, me++) {
3880  float e[3];
3881  sub_v3_v3v3(e, ps->mvert_eval[me->v1].co, ps->mvert_eval[me->v2].co);
3882  normalize_v3(e);
3883  add_v3_v3(edges[me->v2], e);
3884  counter[me->v2]++;
3885  sub_v3_v3(edges[me->v1], e);
3886  counter[me->v1]++;
3887  }
3888  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
3889  if (counter[a] > 0) {
3890  float no[3];
3891  mul_v3_fl(edges[a], 1.0f / counter[a]);
3892  normal_short_to_float_v3(no, mv->no);
3893  /* Augment the difference. */
3894  cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
3895  }
3896  else {
3897  cavities[a] = 0.0;
3898  }
3899  }
3900 
3901  MEM_freeN(counter);
3902  MEM_freeN(edges);
3903  }
3904 }
3905 
3906 #ifndef PROJ_DEBUG_NOSEAMBLEED
3908 {
3909  if (ps->seam_bleed_px > 0.0f) {
3910  ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->totvert_eval, "paint-vertFaces");
3911  ps->faceSeamFlags = MEM_callocN(sizeof(ushort) * ps->totlooptri_eval, "paint-faceSeamFlags");
3912  ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->totlooptri_eval,
3913  "paint-faceWindindFlags");
3914  ps->loopSeamData = MEM_mallocN(sizeof(LoopSeamData) * ps->totloop_eval, "paint-loopSeamUVs");
3915  ps->vertSeams = MEM_callocN(sizeof(ListBase) * ps->totvert_eval, "paint-vertSeams");
3916  }
3917 }
3918 #endif
3919 
3920 static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads)
3921 {
3922  /* Thread stuff
3923  *
3924  * very small brushes run a lot slower multi-threaded since the advantage with
3925  * threads is being able to fill in multiple buckets at once.
3926  * Only use threads for bigger brushes. */
3927 
3929 
3930  /* workaround for T35057, disable threading if diameter is less than is possible for
3931  * optimum bucket number generation */
3932  if (reset_threads) {
3933  ps->thread_tot = 1;
3934  }
3935 
3936  if (ps->is_shared_user == false) {
3937  if (ps->thread_tot > 1) {
3938  ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
3939  BLI_spin_init(ps->tile_lock);
3940  }
3941 
3943  }
3944 
3945  for (int a = 0; a < ps->thread_tot; a++) {
3946  ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
3947  }
3948 }
3949 
3951 {
3952  if (ps->do_backfacecull && ps->do_mask_normal) {
3953  float viewDirPersp[3];
3954  const MVert *mv;
3955  float no[3];
3956  int a;
3957 
3958  ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
3959 
3960  for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
3961  normal_short_to_float_v3(no, mv->no);
3962  if (UNLIKELY(ps->is_flip_object)) {
3963  negate_v3(no);
3964  }
3965 
3966  if (ps->is_ortho) {
3967  if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) {
3968  /* 1 vert of this face is towards us */
3969  ps->vertFlags[a] |= PROJ_VERT_CULL;
3970  }
3971  }
3972  else {
3973  sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
3974  normalize_v3(viewDirPersp);
3975  if (UNLIKELY(ps->is_flip_object)) {
3976  negate_v3(viewDirPersp);
3977  }
3978  if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) {
3979  /* 1 vert of this face is towards us */
3980  ps->vertFlags[a] |= PROJ_VERT_CULL;
3981  }
3982  }
3983  }
3984  }
3985  else {
3986  ps->vertFlags = NULL;
3987  }
3988 }
3989 
3990 #ifndef PROJ_DEBUG_NOSEAMBLEED
3992  MemArena *arena,
3993  const MLoopTri *lt,
3994  const int tri_index)
3995 {
3996  /* add face user if we have bleed enabled, set the UV seam flags later */
3997  /* annoying but we need to add all faces even ones we never use elsewhere */
3998  if (ps->seam_bleed_px > 0.0f) {
3999  const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
4000 
4001  /* Check for degenerate triangles. Degenerate faces cause trouble with bleed computations.
4002  * Ideally this would be checked later, not to add to the cost of computing non-degenerate
4003  * triangles, but that would allow other triangles to still find adjacent seams on degenerate
4004  * triangles, potentially causing incorrect results. */
4005  if (area_tri_v2(UNPACK3(lt_tri_uv)) > 0.0f) {
4006  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
4007  void *tri_index_p = POINTER_FROM_INT(tri_index);
4008 
4009  BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[0]], tri_index_p, arena);
4010  BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[1]], tri_index_p, arena);
4011  BLI_linklist_prepend_arena(&ps->vertFaces[lt_vtri[2]], tri_index_p, arena);
4012  }
4013  else {
4014  ps->faceSeamFlags[tri_index] |= PROJ_FACE_DEGENERATE;
4015  }
4016  }
4017 }
4018 #endif
4019 
4020 /* Return true if evaluated mesh can be painted on, false otherwise */
4022 {
4024  Object *ob = ps->ob;
4025 
4026  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
4027  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
4028 
4029  if (scene_eval == NULL || ob_eval == NULL) {
4030  return false;
4031  }
4032 
4033  CustomData_MeshMasks cddata_masks = scene_eval->customdata_mask;
4034  cddata_masks.fmask |= CD_MASK_MTFACE;
4035  cddata_masks.lmask |= CD_MASK_MLOOPUV;
4036  if (ps->do_face_sel) {
4037  cddata_masks.vmask |= CD_MASK_ORIGINDEX;
4038  cddata_masks.emask |= CD_MASK_ORIGINDEX;
4039  cddata_masks.pmask |= CD_MASK_ORIGINDEX;
4040  }
4041  ps->me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
4042 
4044  ps->me_eval = NULL;
4045  return false;
4046  }
4047 
4048  /* Build final material array, we use this a lot here. */
4049  /* materials start from 1, default material is 0 */
4050  const int totmat = ob->totcol + 1;
4051  ps->mat_array = MEM_malloc_arrayN(totmat, sizeof(*ps->mat_array), __func__);
4052  /* We leave last material as empty - rationale here is being able to index
4053  * the materials by using the mf->mat_nr directly and leaving the last
4054  * material as NULL in case no materials exist on mesh, so indexing will not fail. */
4055  for (int i = 0; i < totmat - 1; i++) {
4056  ps->mat_array[i] = BKE_object_material_get(ob, i + 1);
4057  }
4058  ps->mat_array[totmat - 1] = NULL;
4059 
4060  ps->mvert_eval = ps->me_eval->mvert;
4061  if (ps->do_mask_cavity) {
4062  ps->medge_eval = ps->me_eval->medge;
4063  }
4064  ps->mloop_eval = ps->me_eval->mloop;
4065  ps->mpoly_eval = ps->me_eval->mpoly;
4066 
4067  ps->totvert_eval = ps->me_eval->totvert;
4068  ps->totedge_eval = ps->me_eval->totedge;
4069  ps->totpoly_eval = ps->me_eval->totpoly;
4070  ps->totloop_eval = ps->me_eval->totloop;
4071 
4074 
4075  ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
4076 
4077  return true;
4078 }
4079 
4080 typedef struct {
4085 
4087 {
4088  MLoopUV *mloopuv_clone_base = NULL;
4089 
4090  /* use clone mtface? */
4091  if (ps->do_layer_clone) {
4092  const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
4093 
4094  ps->poly_to_loop_uv_clone = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *),
4095  "proj_paint_mtfaces");
4096 
4097  if (layer_num != -1) {
4098  mloopuv_clone_base = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
4099  }
4100 
4101  if (mloopuv_clone_base == NULL) {
4102  /* get active instead */
4103  mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4104  }
4105  }
4106 
4107  memset(layer_clone, 0, sizeof(*layer_clone));
4108  layer_clone->mloopuv_clone_base = mloopuv_clone_base;
4109 }
4110 
4111 /* Return true if face should be skipped, false otherwise */
4113  ProjPaintLayerClone *lc,
4114  const TexPaintSlot *slot,
4115  const int tri_index)
4116 {
4117  if (ps->do_layer_clone) {
4118  if (ps->do_material_slots) {
4119  lc->slot_clone = project_paint_face_clone_slot(ps, tri_index);
4120  /* all faces should have a valid slot, reassert here */
4121  if (ELEM(lc->slot_clone, NULL, slot)) {
4122  return true;
4123  }
4124  }
4125  else if (ps->clone_ima == ps->canvas_ima) {
4126  return true;
4127  }
4128 
4129  if (ps->do_material_slots) {
4130  if (lc->slot_clone != lc->slot_last_clone) {
4131  if (!lc->slot_clone->uvname ||
4133  &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
4135  }
4136  lc->slot_last_clone = lc->slot_clone;
4137  }
4138  }
4139 
4140  /* will set multiple times for 4+ sided poly */
4141  ps->poly_to_loop_uv_clone[ps->mlooptri_eval[tri_index].poly] = lc->mloopuv_clone_base;
4142  }
4143  return false;
4144 }
4145 
4146 typedef struct {
4148 
4149  const int *index_mp_to_orig;
4151 
4153 {
4154  memset(face_lookup, 0, sizeof(*face_lookup));
4155  if (ps->do_face_sel) {
4156  face_lookup->index_mp_to_orig = CustomData_get_layer(&ps->me_eval->pdata, CD_ORIGINDEX);
4157  face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
4158  }
4159 }
4160 
4161 /* Return true if face should be considered selected, false otherwise */
4163  const ProjPaintFaceLookup *face_lookup,
4164  const MLoopTri *lt)
4165 {
4166  if (ps->do_face_sel) {
4167  int orig_index;
4168  const MPoly *mp;
4169 
4170  if ((face_lookup->index_mp_to_orig != NULL) &&
4171  (((orig_index = (face_lookup->index_mp_to_orig[lt->poly]))) != ORIGINDEX_NONE)) {
4172  mp = &face_lookup->mpoly_orig[orig_index];
4173  }
4174  else {
4175  mp = &ps->mpoly_eval[lt->poly];
4176  }
4177 
4178  return ((mp->flag & ME_FACE_SEL) != 0);
4179  }
4180  return true;
4181 }
4182 
4183 typedef struct {
4184  const float *v1;
4185  const float *v2;
4186  const float *v3;
4188 
4190  const MLoopTri *lt,
4191  ProjPaintFaceCoSS *coSS)
4192 {
4193  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
4194  coSS->v1 = ps->screenCoords[lt_vtri[0]];
4195  coSS->v2 = ps->screenCoords[lt_vtri[1]];
4196  coSS->v3 = ps->screenCoords[lt_vtri[2]];
4197 }
4198 
4199 /* Return true if face should be culled, false otherwise */
4201 {
4202  if (!ps->is_ortho) {
4203  if (coSS->v1[0] == FLT_MAX || coSS->v2[0] == FLT_MAX || coSS->v3[0] == FLT_MAX) {
4204  return true;
4205  }
4206  }
4207  return false;
4208 }
4209 
4210 #ifdef PROJ_DEBUG_WINCLIP
4211 /* Return true if face should be culled, false otherwise */
4212 static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceCoSS *coSS)
4213 {
4214  /* ignore faces outside the view */
4215  return ((ps->source != PROJ_SRC_VIEW_FILL) &&
4216  ((coSS->v1[0] < ps->screenMin[0] && coSS->v2[0] < ps->screenMin[0] &&
4217  coSS->v3[0] < ps->screenMin[0]) ||
4218 
4219  (coSS->v1[0] > ps->screenMax[0] && coSS->v2[0] > ps->screenMax[0] &&
4220  coSS->v3[0] > ps->screenMax[0]) ||
4221 
4222  (coSS->v1[1] < ps->screenMin[1] && coSS->v2[1] < ps->screenMin[1] &&
4223  coSS->v3[1] < ps->screenMin[1]) ||
4224 
4225  (coSS->v1[1] > ps->screenMax[1] && coSS->v2[1] > ps->screenMax[1] &&
4226  coSS->v3[1] > ps->screenMax[1])));
4227 }
4228 #endif /* PROJ_DEBUG_WINCLIP */
4229 
4230 typedef struct PrepareImageEntry {
4235 
4237  MemArena *arena,
4238  ListBase *used_images)
4239 {
4240  ProjPaintImage *projIma;
4241  PrepareImageEntry *entry;
4242  int i;
4243 
4244  /* build an array of images we use */
4245  projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
4246 
4247  for (entry = used_images->first, i = 0; entry; entry = entry->next, i++, projIma++) {
4248  projIma->iuser = entry->iuser;
4249  int size;
4250  projIma->ima = entry->ima;
4251  projIma->touch = 0;
4252  projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
4253  if (projIma->ibuf == NULL) {
4254  projIma->iuser.tile = 0;
4255  projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
4256  BLI_assert(projIma->ibuf != NULL);
4257  }
4258  size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
4259  ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
4263  projIma->undoRect = (volatile void **)BLI_memarena_alloc(arena, size);
4264  memset((void *)projIma->undoRect, 0, size);
4265  projIma->maskRect = BLI_memarena_alloc(arena, size);
4266  memset(projIma->maskRect, 0, size);
4267  projIma->valid = BLI_memarena_alloc(arena, size);
4268  memset(projIma->valid, 0, size);
4269  }
4270 }
4271 
4273  MemArena *arena,
4274  const ProjPaintFaceLookup *face_lookup,
4275  ProjPaintLayerClone *layer_clone,
4276  const MLoopUV *mloopuv_base,
4277  const bool is_multi_view)
4278 {
4279  /* Image Vars - keep track of images we have used */
4280  ListBase used_images = {NULL};
4281 
4282  Image *tpage_last = NULL, *tpage;
4283  TexPaintSlot *slot_last = NULL;
4284  TexPaintSlot *slot = NULL;
4285  int tile_last = -1, tile;
4286  const MLoopTri *lt;
4287  int image_index = -1, tri_index;
4288  int prev_poly = -1;
4289 
4290  BLI_assert(ps->image_tot == 0);
4291 
4292  for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
4293  bool is_face_sel;
4294  bool skip_tri = false;
4295 
4296  is_face_sel = project_paint_check_face_sel(ps, face_lookup, lt);
4297 
4298  if (!ps->do_stencil_brush) {
4299  slot = project_paint_face_paint_slot(ps, tri_index);
4300  /* all faces should have a valid slot, reassert here */
4301  if (slot == NULL) {
4302  mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4303  tpage = ps->canvas_ima;
4304  }
4305  else {
4306  if (slot != slot_last) {
4307  if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(
4308  &ps->me_eval->ldata, CD_MLOOPUV, slot->uvname))) {
4309  mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4310  }
4311  slot_last = slot;
4312  }
4313 
4314  /* Don't allow using the same image for painting and stenciling. */
4315  if (slot->ima == ps->stencil_ima) {
4316  /* Delay continuing the loop until after loop_uvs and bleed faces are initialized.
4317  * While this shouldn't be used, face-winding reads all polys.
4318  * It's less trouble to set all faces to valid UV's,
4319  * avoiding NULL checks all over. */
4320  skip_tri = true;
4321  tpage = NULL;
4322  }
4323  else {
4324  tpage = slot->ima;
4325  }
4326  }
4327  }
4328  else {
4329  tpage = ps->stencil_ima;
4330  }
4331 
4332  ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
4333 
4334  tile = project_paint_face_paint_tile(tpage, mloopuv_base[lt->tri[0]].uv);
4335 
4336 #ifndef PROJ_DEBUG_NOSEAMBLEED
4337  project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
4338 #endif
4339 
4340  if (skip_tri || project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
4341  continue;
4342  }
4343 
4344  BLI_assert(mloopuv_base != NULL);
4345 
4346  if (is_face_sel && tpage) {
4347  ProjPaintFaceCoSS coSS;
4348  proj_paint_face_coSS_init(ps, lt, &coSS);
4349 
4350  if (is_multi_view == false) {
4351  if (project_paint_flt_max_cull(ps, &coSS)) {
4352  continue;
4353  }
4354 
4355 #ifdef PROJ_DEBUG_WINCLIP
4356  if (project_paint_winclip(ps, &coSS)) {
4357  continue;
4358  }
4359 
4360 #endif // PROJ_DEBUG_WINCLIP
4361 
4362  /* backface culls individual triangles but mask normal will use polygon */
4363  if (ps->do_backfacecull) {
4364  if (ps->do_mask_normal) {
4365  if (prev_poly != lt->poly) {
4366  int iloop;
4367  bool culled = true;
4368  const MPoly *poly = ps->mpoly_eval + lt->poly;
4369  int poly_loops = poly->totloop;
4370  prev_poly = lt->poly;
4371  for (iloop = 0; iloop < poly_loops; iloop++) {
4372  if (!(ps->vertFlags[ps->mloop_eval[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
4373  culled = false;
4374  break;
4375  }
4376  }
4377 
4378  if (culled) {
4379  /* poly loops - 2 is number of triangles for poly,
4380  * but counter gets incremented when continuing, so decrease by 3 */
4381  int poly_tri = poly_loops - 3;
4382  tri_index += poly_tri;
4383  lt += poly_tri;
4384  continue;
4385  }
4386  }
4387  }
4388  else {
4389  if ((line_point_side_v2(coSS.v1, coSS.v2, coSS.v3) < 0.0f) != ps->is_flip_object) {
4390  continue;
4391  }
4392  }
4393  }
4394  }
4395 
4396  if (tpage_last != tpage || tile_last != tile) {
4397  image_index = 0;
4398  for (PrepareImageEntry *e = used_images.first; e; e = e->next, image_index++) {
4399  if (e->ima == tpage && e->iuser.tile == tile) {
4400  break;
4401  }
4402  }
4403 
4404  if (image_index == ps->image_tot) {
4405  /* XXX get appropriate ImageUser instead */
4406  ImageUser iuser;
4408  iuser.tile = tile;
4409  iuser.framenr = tpage->lastframe;
4410  if (BKE_image_has_ibuf(tpage, &iuser)) {
4411  PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
4412  e->ima = tpage;
4413  e->iuser = iuser;
4414  BLI_addtail(&used_images, e);
4415  ps->image_tot++;
4416  }
4417  else {
4418  image_index = -1;
4419  }
4420  }
4421 
4422  tpage_last = tpage;
4423  tile_last = tile;
4424  }
4425 
4426  if (image_index != -1) {
4427  /* Initialize the faces screen pixels */
4428  /* Add this to a list to initialize later */
4429  project_paint_delayed_face_init(ps, lt, tri_index);
4430  }
4431  }
4432  }
4433 
4434  /* build an array of images we use*/
4435  if (ps->is_shared_user == false) {
4436  project_paint_build_proj_ima(ps, arena, &used_images);
4437  }
4438 
4439  /* we have built the array, discard the linked list */
4440  BLI_freelistN(&used_images);
4441 }
4442 
4443 /* run once per stroke before projection painting */
4444 static void project_paint_begin(const bContext *C,
4445  ProjPaintState *ps,
4446  const bool is_multi_view,
4447  const char symmetry_flag)
4448 {
4449  ProjPaintLayerClone layer_clone;
4450  ProjPaintFaceLookup face_lookup;
4451  const MLoopUV *mloopuv_base = NULL;
4452 
4453  /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
4454  MemArena *arena;
4455 
4456  const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
4457 
4458  bool reset_threads = false;
4459 
4460  /* ---- end defines ---- */
4461 
4462  if (ps->source == PROJ_SRC_VIEW) {
4463  /* faster clipping lookups */
4465  }
4466 
4467  ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
4468  ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
4469 
4470  /* paint onto the derived mesh */
4471  if (ps->is_shared_user == false) {
4472  if (!proj_paint_state_mesh_eval_init(C, ps)) {
4473  return;
4474  }
4475  }
4476 
4477  proj_paint_face_lookup_init(ps, &face_lookup);
4478  proj_paint_layer_clone_init(ps, &layer_clone);
4479 
4480  if (ps->do_layer_stencil || ps->do_stencil_brush) {
4481  // int layer_num = CustomData_get_stencil_layer(&ps->me_eval->ldata, CD_MLOOPUV);
4482  int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
4483  if (layer_num != -1) {
4485  &ps->me_eval->ldata, CD_MLOOPUV, layer_num);
4486  }
4487 
4488  if (ps->mloopuv_stencil_eval == NULL) {
4489  /* get active instead */
4491  }
4492 
4493  if (ps->do_stencil_brush) {
4494  mloopuv_base = ps->mloopuv_stencil_eval;
4495  }
4496  }
4497 
4498  /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
4499  if (ps->is_shared_user == false) {
4501  }
4502 
4503  proj_paint_state_viewport_init(ps, symmetry_flag);
4504 
4505  /* calculate vert screen coords
4506  * run this early so we can calculate the x/y resolution of our bucket rect */
4508 
4509  /* only for convenience */
4510  ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
4511  ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
4512 
4513  ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
4514  ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
4515 
4516  /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
4517 
4519  reset_threads = true;
4520  }
4521 
4522  /* really high values could cause problems since it has to allocate a few
4523  * (ps->buckets_x*ps->buckets_y) sized arrays */
4526 
4527  ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y,
4528  "paint-bucketRect");
4529  ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y,
4530  "paint-bucketFaces");
4531 
4532  ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
4533 #ifndef PROJ_DEBUG_NOSEAMBLEED
4534  if (ps->is_shared_user == false) {
4536  }
4537 #endif
4538 
4539  proj_paint_state_thread_init(ps, reset_threads);
4540  arena = ps->arena_mt[0];
4541 
4543 
4545  ps, arena, &face_lookup, &layer_clone, mloopuv_base, is_multi_view);
4546 }
4547 
4548 static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
4549 {
4550  /* setup clone offset */
4551  if (ps->tool == PAINT_TOOL_CLONE) {
4552  float projCo[4];
4553  copy_v3_v3(projCo, ps->scene->cursor.location);
4554  mul_m4_v3(ps->obmat_imat, projCo);
4555 
4556  projCo[3] = 1.0f;
4557  mul_m4_v4(ps->projectMat, projCo);
4558  ps->cloneOffset[0] = mouse[0] -
4559  ((float)(ps->winx * 0.5f) + (ps->winx * 0.5f) * projCo[0] / projCo[3]);
4560  ps->cloneOffset[1] = mouse[1] -
4561  ((float)(ps->winy * 0.5f) + (ps->winy * 0.5f) * projCo[1] / projCo[3]);
4562  }
4563 }
4564 
4566 {
4567  int a;
4568 
4569  /* dereference used image buffers */
4570  if (ps->is_shared_user == false) {
4571  ProjPaintImage *projIma;
4572  for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
4573  BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
4574  DEG_id_tag_update(&projIma->ima->id, 0);
4575  }
4576  }
4577 
4578  if (ps->reproject_ibuf_free_float) {
4580  }
4581  if (ps->reproject_ibuf_free_uchar) {
4583  }
4585 
4586  MEM_freeN(ps->screenCoords);
4587  MEM_freeN(ps->bucketRect);
4588  MEM_freeN(ps->bucketFaces);
4589  MEM_freeN(ps->bucketFlags);
4590 
4591  if (ps->is_shared_user == false) {
4592  if (ps->mat_array != NULL) {
4593  MEM_freeN(ps->mat_array);
4594  }
4595 
4596  /* must be set for non-shared */
4598  if (ps->poly_to_loop_uv) {
4599  MEM_freeN((void *)ps->poly_to_loop_uv);
4600  }
4601 
4602  if (ps->do_layer_clone) {
4603  MEM_freeN((void *)ps->poly_to_loop_uv_clone);
4604  }
4605  if (ps->thread_tot > 1) {
4606  BLI_spin_end(ps->tile_lock);
4607  MEM_freeN((void *)ps->tile_lock);
4608  }
4609 
4611 
4612 #ifndef PROJ_DEBUG_NOSEAMBLEED
4613  if (ps->seam_bleed_px > 0.0f) {
4614  MEM_freeN(ps->vertFaces);
4615  MEM_freeN(ps->faceSeamFlags);
4617  MEM_freeN(ps->loopSeamData);
4618  MEM_freeN(ps->vertSeams);
4619  }
4620 #endif
4621 
4622  if (ps->do_mask_cavity) {
4623  MEM_freeN(ps->cavities);
4624  }
4625 
4626  ps->me_eval = NULL;
4627  }
4628 
4629  if (ps->blurkernel) {
4631  MEM_freeN(ps->blurkernel);
4632  }
4633 
4634  if (ps->vertFlags) {
4635  MEM_freeN(ps->vertFlags);
4636  }
4637 
4638  for (a = 0; a < ps->thread_tot; a++) {
4640  }
4641 }
4642 
4643 /* 1 = an undo, -1 is a redo. */
4645 {
4646  pr->x1 = INT_MAX;
4647  pr->y1 = INT_MAX;
4648 
4649  pr->x2 = -1;
4650  pr->y2 = -1;
4651 
4652  pr->enabled = 1;
4653 }
4654 
4656 {
4657  int tot = PROJ_BOUNDBOX_SQUARED;
4658  while (tot--) {
4660  pr++;
4661  }
4662 }
4663 
4665  ImagePaintPartialRedraw *pr_other,
4666  int tot)
4667 {
4668  bool touch = 0;
4669  while (tot--) {
4670  pr->x1 = min_ii(pr->x1, pr_other->x1);
4671  pr->y1 = min_ii(pr->y1, pr_other->y1);
4672 
4673  pr->x2 = max_ii(pr->x2, pr_other->x2);
4674  pr->y2 = max_ii(pr->y2, pr_other->y2);
4675 
4676  if (pr->x2 != -1) {
4677  touch = 1;
4678  }
4679 
4680  pr++;
4681  pr_other++;
4682  }
4683 
4684  return touch;
4685 }
4686 
4687 /* Loop over all images on this mesh and update any we have touched */
4689 {
4691  ProjPaintImage *projIma;
4692  int a, i;
4693  bool redraw = false;
4694 
4695  for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
4696  if (projIma->touch) {
4697  /* look over each bound cell */
4698  for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
4699  pr = &(projIma->partRedrawRect[i]);
4700  if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
4701  set_imapaintpartial(pr);
4702  imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
4703  redraw = 1;
4704  }
4705 
4707  }
4708 
4709  /* clear for reuse */
4710  projIma->touch = 0;
4711  }
4712  }
4713 
4714  return redraw;
4715 }
4716 
4717 /* run this per painting onto each mouse location */
4718 static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
4719 {
4720  if (ps->source == PROJ_SRC_VIEW) {
4721  float min_brush[2], max_brush[2];
4722  const float radius = ps->brush_size;
4723 
4724  /* so we don't have a bucket bounds that is way too small to paint into */
4725 #if 0
4726  /* This doesn't work yet. */
4727  if (radius < 1.0f) {
4728  radius = 1.0f;
4729  }
4730 #endif
4731 
4732  min_brush[0] = mval_f[0] - radius;
4733  min_brush[1] = mval_f[1] - radius;
4734 
4735  max_brush[0] = mval_f[0] + radius;
4736  max_brush[1] = mval_f[1] + radius;
4737 
4738  /* offset to make this a valid bucket index */
4739  project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax);
4740 
4741  /* mouse outside the model areas? */
4742  if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) {
4743  return false;
4744  }
4745  }
4746  else { /* reproject: PROJ_SRC_* */
4747  ps->bucketMin[0] = 0;
4748  ps->bucketMin[1] = 0;
4749 
4750  ps->bucketMax[0] = ps->buckets_x;
4751  ps->bucketMax[1] = ps->buckets_y;
4752  }
4753 
4754  ps->context_bucket_index = ps->bucketMin[0] + ps->bucketMin[1] * ps->buckets_x;
4755  return true;
4756 }
4757 
4759  int *bucket_index,
4760  rctf *bucket_bounds,
4761  const float mval[2])
4762 {
4763  const int diameter = 2 * ps->brush_size;
4764 
4765  const int max_bucket_idx = ps->bucketMax[0] + (ps->bucketMax[1] - 1) * ps->buckets_x;
4766 
4767  for (int bidx = atomic_fetch_and_add_int32(&ps->context_bucket_index, 1); bidx < max_bucket_idx;
4769  const int bucket_y = bidx / ps->buckets_x;
4770  const int bucket_x = bidx - (bucket_y * ps->buckets_x);
4771 
4772  BLI_assert(bucket_y >= ps->bucketMin[1] && bucket_y < ps->bucketMax[1]);
4773  if (bucket_x >= ps->bucketMin[0] && bucket_x < ps->bucketMax[0]) {
4774  /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/
4775  project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
4776 
4777  if ((ps->source != PROJ_SRC_VIEW) ||
4778  project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds)) {
4779  *bucket_index = bidx;
4780 
4781  return true;
4782  }
4783  }
4784  }
4785 
4786  return false;
4787 }
4788 
4789 /* Each thread gets one of these, also used as an argument to pass to project_paint_op */
4790 typedef struct ProjectHandle {
4791  /* args */
4793  float prevmval[2];
4794  float mval[2];
4795 
4796  /* Annoying but we need to have image bounds per thread,
4797  * then merge into ps->projectPartialRedraws. */
4798 
4799  /* array of partial redraws */
4801 
4802  /* thread settings */
4804 
4805  struct ImagePool *pool;
4807 
4808 static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float mask)
4809 {
4810  const uchar *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
4811 
4812  if (clone_pt[3]) {
4813  uchar clone_rgba[4];
4814 
4815  clone_rgba[0] = clone_pt[0];
4816  clone_rgba[1] = clone_pt[1];
4817  clone_rgba[2] = clone_pt[2];
4818  clone_rgba[3] = (uchar)(clone_pt[3] * mask);
4819 
4820  if (ps->do_masking) {
4822  projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend);
4823  }
4824  else {
4825  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend);
4826  }
4827  }
4828 }
4829 
4830 static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
4831 {
4832  const float *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.f;
4833 
4834  if (clone_pt[3]) {
4835  float clone_rgba[4];
4836 
4837  mul_v4_v4fl(clone_rgba, clone_pt, mask);
4838 
4839  if (ps->do_masking) {
4841  projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend);
4842  }
4843  else {
4844  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend);
4845  }
4846  }
4847 }
4848 
4855  ProjPixel *projPixel,
4856  float mask,
4857  MemArena *smearArena,
4858  LinkNode **smearPixels,
4859  const float co[2])
4860 {
4861  uchar rgba_ub[4];
4862 
4863  if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0) {
4864  return;
4865  }
4866 
4868  ((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, mask);
4869  BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena);
4870 }
4871 
4873  ProjPixel *projPixel,
4874  float mask,
4875  MemArena *smearArena,
4876  LinkNode **smearPixels_f,
4877  const float co[2])
4878 {
4879  float rgba[4];
4880 
4881  if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0) {
4882  return;
4883  }
4884 
4886  ((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, mask);
4887  BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
4888 }
4889 
4891  ProjPixel *projPixel,
4892  float mask,
4893  MemArena *softenArena,
4894  LinkNode **softenPixels)
4895 {
4896  float accum_tot = 0.0f;
4897  int xk, yk;
4898  BlurKernel *kernel = ps->blurkernel;
4899  float *rgba = projPixel->newColor.f;
4900 
4901  /* rather than painting, accumulate surrounding colors */
4902  zero_v4(rgba);
4903 
4904  for (yk = 0; yk < kernel->side; yk++) {
4905  for (xk = 0; xk < kernel->side; xk++) {
4906  float rgba_tmp[4];
4907  float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
4908 
4909  add_v2_v2(co_ofs, projPixel->projCoSS);
4910 
4911  if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
4912  float weight = kernel->wdata[xk + yk * kernel->side];
4913  mul_v4_fl(rgba_tmp, weight);
4914  add_v4_v4(rgba, rgba_tmp);
4915  accum_tot += weight;
4916  }
4917  }
4918  }
4919 
4920  if (LIKELY(accum_tot != 0)) {
4921  mul_v4_fl(rgba, 1.0f / (float)accum_tot);
4922 
4923  if (ps->mode == BRUSH_STROKE_INVERT) {
4924  /* subtract blurred image from normal image gives high pass filter */
4925  sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba);
4926 
4927  /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
4928  * colored speckles appearing in final image, and also to check for threshold */
4929  rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
4930  if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
4931  float alpha = projPixel->pixel.f_pt[3];
4932  projPixel->pixel.f_pt[3] = rgba[3] = mask;
4933 
4934  /* add to enhance edges */
4935  blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba);
4936  rgba[3] = alpha;
4937  }
4938  else {
4939  return;
4940  }
4941  }
4942  else {
4943  blend_color_interpolate_float(rgba, projPixel->pixel.f_pt, rgba, mask);
4944  }
4945 
4946  BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
4947  }
4948 }
4949 
4951  ProjPixel *projPixel,
4952  float mask,
4953  MemArena *softenArena,
4954  LinkNode **softenPixels)
4955 {
4956  float accum_tot = 0;
4957  int xk, yk;
4958  BlurKernel *kernel = ps->blurkernel;
4959  /* convert to byte after */
4960  float rgba[4];
4961 
4962  /* rather than painting, accumulate surrounding colors */
4963  zero_v4(rgba);
4964 
4965  for (yk = 0; yk < kernel->side; yk++) {
4966  for (xk = 0; xk < kernel->side; xk++) {
4967  float rgba_tmp[4];
4968  float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
4969 
4970  add_v2_v2(co_ofs, projPixel->projCoSS);
4971 
4972  if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
4973  float weight = kernel->wdata[xk + yk * kernel->side];
4974  mul_v4_fl(rgba_tmp, weight);
4975  add_v4_v4(rgba, rgba_tmp);
4976  accum_tot += weight;
4977  }
4978  }
4979  }
4980 
4981  if (LIKELY(accum_tot != 0)) {
4982  uchar *rgba_ub = projPixel->newColor.ch;
4983 
4984  mul_v4_fl(rgba, 1.0f / (float)accum_tot);
4985 
4986  if (ps->mode == BRUSH_STROKE_INVERT) {
4987  float rgba_pixel[4];
4988 
4989  straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt);
4990 
4991  /* subtract blurred image from normal image gives high pass filter */
4992  sub_v3_v3v3(rgba, rgba_pixel, rgba);
4993  /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
4994  * colored speckles appearing in final image, and also to check for threshold */
4995  rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
4996  if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
4997  float alpha = rgba_pixel[3];
4998  rgba[3] = rgba_pixel[3] = mask;
4999 
5000  /* add to enhance edges */
5001  blend_color_add_float(rgba, rgba_pixel, rgba);
5002 
5003  rgba[3] = alpha;
5004  premul_float_to_straight_uchar(rgba_ub, rgba);
5005  }
5006  else {
5007  return;
5008  }
5009  }
5010  else {
5011  premul_float_to_straight_uchar(rgba_ub, rgba);
5012  blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask);
5013  }
5014  BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
5015  }
5016 }
5017 
5019  ProjPixel *projPixel,
5020  const float texrgb[3],
5021  float mask,
5022  float dither,
5023  float u,
5024  float v)
5025 {
5026  float rgb[3];
5027  uchar rgba_ub[4];
5028 
5029  if (ps->is_texbrush) {
5030  mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
5031  /* TODO(sergey): Support texture paint color space. */
5032  if (ps->use_colormanagement) {
5033  linearrgb_to_srgb_v3_v3(rgb, rgb);
5034  }
5035  else {
5036  copy_v3_v3(rgb, rgb);
5037  }
5038  }
5039  else {
5040  copy_v3_v3(rgb, ps->paint_color);
5041  }
5042 
5043  if (dither > 0.0f) {
5044  float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v);
5045  }
5046  else {
5047  unit_float_to_uchar_clamp_v3(rgba_ub, rgb);
5048  }
5049  rgba_ub[3] = f_to_char(mask);
5050 
5051  if (ps->do_masking) {
5052  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
5053  }
5054  else {
5055  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
5056  }
5057 }
5058 
5060  ProjPixel *projPixel,
5061  const float texrgb[3],
5062  float mask)
5063 {
5064  float rgba[4];
5065 
5066  copy_v3_v3(rgba, ps->paint_color_linear);
5067 
5068  if (ps->is_texbrush) {
5069  mul_v3_v3(rgba, texrgb);
5070  }
5071 
5072  mul_v3_fl(rgba, mask);
5073  rgba[3] = mask;
5074 
5075  if (ps->do_masking) {
5076  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
5077  }
5078  else {
5079  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
5080  }
5081 }
5082 
5083 static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
5084 {
5085  uchar rgba_ub[4];
5086  rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
5087  rgba_ub[3] = f_to_char(mask);
5088 
5089  if (ps->do_masking) {
5090  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
5091  }
5092  else {
5093  IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
5094  }
5095 }
5096 
5097 static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
5098 {
5099  float rgba[4];
5100  rgba[0] = rgba[1] = rgba[2] = ps->stencil_value;
5101  rgba[3] = mask;
5102 
5103  if (ps->do_masking) {
5104  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
5105  }
5106  else {
5107  IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
5108  }
5109 }
5110 
5112  const ProjPixel *projPixel)
5113 {
5114  cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
5115  cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
5116 
5117  cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
5118  cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
5119 }
5120 
5121 static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
5122 {
5123  /* Use the original alpha channel data instead of the modified one */
5124  if (is_floatbuf) {
5125  /* slightly more involved case since floats are in premultiplied space we need
5126  * to make sure alpha is consistent, see T44627 */
5127  float rgb_straight[4];
5128  premul_to_straight_v4_v4(rgb_straight, pixel->pixel.f_pt);
5129  rgb_straight[3] = pixel->origColor.f_pt[3];
5130  straight_to_premul_v4_v4(pixel->pixel.f_pt, rgb_straight);
5131  }
5132  else {
5133  pixel->pixel.ch_pt[3] = pixel->origColor.ch_pt[3];
5134  }
5135 }
5136 
5137 /* Run this for single and multi-threaded painting. */
5138 static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v)
5139 {
5140  /* First unpack args from the struct */
5141  ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
5142  ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages;
5143  const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
5144  const float *pos = ((ProjectHandle *)ph_v)->mval;
5145  const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
5146  struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
5147  /* Done with args from ProjectHandle */
5148 
5149  LinkNode *node;
5150  ProjPixel *projPixel;
5151  Brush *brush = ps->brush;
5152 
5153  int last_index = -1;
5154  ProjPaintImage *last_projIma = NULL;
5155  ImagePaintPartialRedraw *last_partial_redraw_cell;
5156 
5157  float dist_sq, dist;
5158 
5159  float falloff;
5160  int bucket_index;
5161  bool is_floatbuf = false;
5162  const short tool = ps->tool;
5163  rctf bucket_bounds;
5164 
5165  /* for smear only */
5166  float pos_ofs[2] = {0};
5167  float co[2];
5168  ushort mask_short;
5169  const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
5170  const float brush_radius = ps->brush_size;
5171  /* avoid a square root with every dist comparison */
5172  const float brush_radius_sq = brush_radius * brush_radius;
5173 
5174  const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
5175  0 :
5176  (brush->flag & BRUSH_LOCK_ALPHA) != 0;
5177 
5178  LinkNode *smearPixels = NULL;
5179  LinkNode *smearPixels_f = NULL;
5180  /* mem arena for this brush projection only */
5181  MemArena *smearArena = NULL;
5182 
5183  LinkNode *softenPixels = NULL;
5184  LinkNode *softenPixels_f = NULL;
5185  /* mem arena for this brush projection only */
5186  MemArena *softenArena = NULL;
5187 
5188  if (tool == PAINT_TOOL_SMEAR) {
5189  pos_ofs[0] = pos[0] - lastpos[0];
5190  pos_ofs[1] = pos[1] - lastpos[1];
5191 
5192  smearArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint smear arena");
5193  }
5194  else if (tool == PAINT_TOOL_SOFTEN) {
5195  softenArena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "paint soften arena");
5196  }
5197 
5198  /* printf("brush bounds %d %d %d %d\n",
5199  * bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
5200 
5201  while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) {
5202 
5203  /* Check this bucket and its faces are initialized */
5204  if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
5205  rctf clip_rect = bucket_bounds;
5206  clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
5207  clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
5208  clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
5209  clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
5210  /* No pixels initialized */
5211  project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
5212  }
5213 
5214  if (ps->source != PROJ_SRC_VIEW) {
5215 
5216  /* Re-Projection, simple, no brushes! */
5217 
5218  for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
5219  projPixel = (ProjPixel *)node->link;
5220 
5221  /* copy of code below */
5222  if (last_index != projPixel->image_index) {
5223  last_index = projPixel->image_index;
5224  last_projIma = projImages + last_index;
5225 
5226  last_projIma->touch = 1;
5227  is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
5228  }
5229  /* end copy */
5230 
5231  /* fill tools */
5232  if (ps->source == PROJ_SRC_VIEW_FILL) {
5233  if (brush->flag & BRUSH_USE_GRADIENT) {
5234  /* these could probably be cached instead of being done per pixel */
5235  float tangent[2];
5236  float line_len_sq_inv, line_len;
5237  float f;
5238  float color_f[4];
5239  const float p[2] = {
5240  projPixel->projCoSS[0] - lastpos[0],
5241  projPixel->projCoSS[1] - lastpos[1],
5242  };
5243 
5244  sub_v2_v2v2(tangent, pos, lastpos);
5245  line_len = len_squared_v2(tangent);
5246  line_len_sq_inv = 1.0f / line_len;
5247  line_len = sqrtf(line_len);
5248 
5249  switch (brush->gradient_fill_mode) {
5250  case BRUSH_GRADIENT_LINEAR: {
5251  f = dot_v2v2(p, tangent) * line_len_sq_inv;
5252  break;
5253  }
5254  case BRUSH_GRADIENT_RADIAL:
5255  default: {
5256  f = len_v2(p) / line_len;
5257  break;
5258  }
5259  }
5260  BKE_colorband_evaluate(brush->gradient, f, color_f);
5261  color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush_alpha;
5262 
5263  if (is_floatbuf) {
5264  /* convert to premultipied */
5265  mul_v3_fl(color_f, color_f[3]);
5267  projPixel->pixel.f_pt, projPixel->origColor.f_pt, color_f, ps->blend);
5268  }
5269  else {
5270  linearrgb_to_srgb_v3_v3(color_f, color_f);
5271 
5272  if (ps->dither > 0.0f) {
5274  projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px);
5275  }
5276  else {
5277  unit_float_to_uchar_clamp_v3(projPixel->newColor.ch, color_f);
5278  }
5279  projPixel->newColor.ch[3] = unit_float_to_uchar_clamp(color_f[3]);
5280  IMB_blend_color_byte(projPixel->pixel.ch_pt,
5281  projPixel->origColor.ch_pt,
5282  projPixel->newColor.ch,
5283  ps->blend);
5284  }
5285  }
5286  else {
5287  if (is_floatbuf) {
5288  float newColor_f[4];
5289  newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush_alpha;
5290  copy_v3_v3(newColor_f, ps->paint_color_linear);
5291 
5293  projPixel->pixel.f_pt, projPixel->origColor.f_pt, newColor_f, ps->blend);
5294  }
5295  else {
5296  float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5297  projPixel->newColor.ch[3] = mask * 255 * brush_alpha;
5298 
5299  rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
5300  IMB_blend_color_byte(projPixel->pixel.ch_pt,
5301  projPixel->origColor.ch_pt,
5302  projPixel->newColor.ch,
5303  ps->blend);
5304  }
5305  }
5306 
5307  if (lock_alpha) {
5308  copy_original_alpha_channel(projPixel, is_floatbuf);
5309  }
5310 
5311  last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
5312  image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
5313  }
5314  else {
5315  if (is_floatbuf) {
5317 
5319  NULL,
5320  projPixel->newColor.f,
5321  projPixel->projCoSS[0],
5322  projPixel->projCoSS[1]);
5323  if (projPixel->newColor.f[3]) {
5324  float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5325 
5326  mul_v4_v4fl(projPixel->newColor.f, projPixel->newColor.f, mask);
5327 
5329  projPixel->pixel.f_pt, projPixel->origColor.f_pt, projPixel->newColor.f);
5330  }
5331  }
5332  else {
5334 
5336  projPixel->newColor.ch,
5337  NULL,
5338  projPixel->projCoSS[0],
5339  projPixel->projCoSS[1]);
5340  if (projPixel->newColor.ch[3]) {
5341  float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5342  projPixel->newColor.ch[3] *= mask;
5343 
5345  projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, projPixel->newColor.ch);
5346  }
5347  }
5348  }
5349  }
5350  }
5351  else {
5352  /* Normal brush painting */
5353 
5354  for (node = ps->bucketRect[bucket_index]; node; node = node->next) {
5355 
5356  projPixel = (ProjPixel *)node->link;
5357 
5358  dist_sq = len_squared_v2v2(projPixel->projCoSS, pos);
5359 
5360  /*if (dist < radius) {*/ /* correct but uses a sqrtf */
5361  if (dist_sq <= brush_radius_sq) {
5362  dist = sqrtf(dist_sq);
5363 
5364  falloff = BKE_brush_curve_strength_clamped(ps->brush, dist, brush_radius);
5365 
5366  if (falloff > 0.0f) {
5367  float texrgb[3];
5368  float mask;
5369 
5370  /* Extra mask for normal, layer stencil, .. */
5371  float custom_mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
5372 
5373  /* Mask texture. */
5374  if (ps->is_maskbrush) {
5375  float texmask = BKE_brush_sample_masktex(
5376  ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
5377  CLAMP(texmask, 0.0f, 1.0f);
5378  custom_mask *= texmask;
5379  }
5380 
5381  /* Color texture (alpha used as mask). */
5382  if (ps->is_texbrush) {
5383  MTex *mtex = &brush->mtex;
5384  float samplecos[3];
5385  float texrgba[4];
5386 
5387  /* taking 3d copy to account for 3D mapping too.
5388  * It gets concatenated during sampling */
5389  if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
5390  copy_v3_v3(samplecos, projPixel->worldCoSS);
5391  }
5392  else {
5393  copy_v2_v2(samplecos, projPixel->projCoSS);
5394  samplecos[2] = 0.0f;
5395  }
5396 
5397  /* note, for clone and smear,
5398  * we only use the alpha, could be a special function */
5399  BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
5400 
5401  copy_v3_v3(texrgb, texrgba);
5402  custom_mask *= texrgba[3];
5403  }
5404  else {
5405  zero_v3(texrgb);
5406  }
5407 
5408  if (ps->do_masking) {
5409  /* masking to keep brush contribution to a pixel limited. note we do not do
5410  * a simple max(mask, mask_accum), as this is very sensitive to spacing and
5411  * gives poor results for strokes crossing themselves.
5412  *
5413  * Instead we use a formula that adds up but approaches brush_alpha slowly
5414  * and never exceeds it, which gives nice smooth results. */
5415  float mask_accum = *projPixel->mask_accum;
5416  float max_mask = brush_alpha * custom_mask * falloff * 65535.0f;
5417 
5418  if (brush->flag & BRUSH_ACCUMULATE) {
5419  mask = mask_accum + max_mask;
5420  }
5421  else {
5422  mask = mask_accum + (max_mask - mask_accum * falloff);
5423  }
5424 
5425  mask = min_ff(mask, 65535.0f);
5426  mask_short = (ushort)mask;
5427 
5428  if (mask_short > *projPixel->mask_accum) {
5429  *projPixel->mask_accum = mask_short;
5430  mask = mask_short * (1.0f / 65535.0f);
5431  }
5432  else {
5433  /* Go onto the next pixel */
5434  continue;
5435  }
5436  }
5437  else {
5438  mask = brush_alpha * custom_mask * falloff;
5439  }
5440 
5441  if (mask > 0.0f) {
5442 
5443  /* copy of code above */
5444  if (last_index != projPixel->image_index) {
5445  last_index = projPixel->image_index;
5446  last_projIma = projImages + last_index;
5447 
5448  last_projIma->touch = 1;
5449  is_floatbuf = (last_projIma->ibuf->rect_float != NULL);
5450  }
5451  /* end copy */
5452 
5453  /* validate undo tile, since we will modify t*/
5454  *projPixel->valid = true;
5455 
5456  last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
5457  image_paint_partial_redraw_expand(last_partial_redraw_cell, projPixel);
5458 
5459  /* texrgb is not used for clone, smear or soften */
5460  switch (tool) {
5461  case PAINT_TOOL_CLONE:
5462  if (is_floatbuf) {
5463  do_projectpaint_clone_f(ps, projPixel, mask);
5464  }
5465  else {
5466  do_projectpaint_clone(ps, projPixel, mask);
5467  }
5468  break;
5469  case PAINT_TOOL_SMEAR:
5470  sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs);
5471 
5472  if (is_floatbuf) {
5473  do_projectpaint_smear_f(ps, projPixel, mask, smearArena, &smearPixels_f, co);
5474  }
5475  else {
5476  do_projectpaint_smear(ps, projPixel, mask, smearArena, &smearPixels, co);
5477  }
5478  break;
5479  case PAINT_TOOL_SOFTEN:
5480  if (is_floatbuf) {
5481  do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
5482  }
5483  else {
5484  do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
5485  }
5486  break;
5487  case PAINT_TOOL_MASK:
5488  if (is_floatbuf) {
5489  do_projectpaint_mask_f(ps, projPixel, mask);
5490  }
5491  else {
5492  do_projectpaint_mask(ps, projPixel, mask);
5493  }
5494  break;
5495  default:
5496  if (is_floatbuf) {
5497  do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
5498  }
5499  else {
5501  ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
5502  }
5503  break;
5504  }
5505 
5506  if (lock_alpha) {
5507  copy_original_alpha_channel(projPixel, is_floatbuf);
5508  }
5509  }
5510 
5511  /* done painting */
5512  }
5513  }
5514  }
5515  }
5516  }
5517 
5518  if (tool == PAINT_TOOL_SMEAR) {
5519 
5520  for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */
5521  projPixel = node->link;
5522  *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint;
5523  if (lock_alpha) {
5524  copy_original_alpha_channel(projPixel, false);
5525  }
5526  }
5527 
5528  for (node = smearPixels_f; node; node = node->next) {
5529  projPixel = node->link;
5530  copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
5531  if (lock_alpha) {
5532  copy_original_alpha_channel(projPixel, true);
5533  }
5534  }
5535 
5536  BLI_memarena_free(smearArena);
5537  }
5538  else if (tool == PAINT_TOOL_SOFTEN) {
5539 
5540  for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */
5541  projPixel = node->link;
5542  *projPixel->pixel.uint_pt = projPixel->newColor.uint;
5543  if (lock_alpha) {
5544  copy_original_alpha_channel(projPixel, false);
5545  }
5546  }
5547 
5548  for (node = softenPixels_f; node; node = node->next) {
5549  projPixel = node->link;
5550  copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f);
5551  if (lock_alpha) {
5552  copy_original_alpha_channel(projPixel, true);
5553  }
5554  }
5555 
5556  BLI_memarena_free(softenArena);
5557  }
5558 }
5559 
5560 static bool project_paint_op(void *state, const float lastpos[2], const float pos[2])
5561 {
5562  /* First unpack args from the struct */
5564  bool touch_any = false;
5565 
5567  TaskPool *task_pool = NULL;
5568  int a, i;
5569 
5570  struct ImagePool *image_pool;
5571 
5572  if (!project_bucket_iter_init(ps, pos)) {
5573  return touch_any;
5574  }
5575 
5576  if (ps->thread_tot > 1) {
5578  }
5579 
5580  image_pool = BKE_image_pool_new();
5581 
5583  /* This means we are reprojecting an image, make sure the image has the needed data available.
5584  */
5585  bool float_dest = false;
5586  bool uchar_dest = false;
5587  /* Check if the destination images are float or uchar. */
5588  for (i = 0; i < ps->image_tot; i++) {
5589  if (ps->projImages[i].ibuf->rect != NULL) {
5590  uchar_dest = true;
5591  }
5592  if (ps->projImages[i].ibuf->rect_float != NULL) {
5593  float_dest = true;
5594  }
5595  }
5596 
5597  /* Generate missing data if needed. */
5598  if (float_dest && ps->reproject_ibuf->rect_float == NULL) {
5600  ps->reproject_ibuf_free_float = true;
5601  }
5602  if (uchar_dest && ps->reproject_ibuf->rect == NULL) {
5604  ps->reproject_ibuf_free_uchar = true;
5605  }
5606  }
5607 
5608  /* get the threads running */
5609  for (a = 0; a < ps->thread_tot; a++) {
5610 
5611  /* set defaults in handles */
5612  // memset(&handles[a], 0, sizeof(BakeShade));
5613 
5614  handles[a].ps = ps;
5615  copy_v2_v2(handles[a].mval, pos);
5616  copy_v2_v2(handles[a].prevmval, lastpos);
5617 
5618  /* thread specific */
5619  handles[a].thread_index = a;
5620 
5621  handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a],
5622  ps->image_tot * sizeof(ProjPaintImage));
5623 
5624  memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
5625 
5626  /* image bounds */
5627  for (i = 0; i < ps->image_tot; i++) {
5628  handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(
5630  memcpy(handles[a].projImages[i].partRedrawRect,
5631  ps->projImages[i].partRedrawRect,
5633  }
5634 
5635  handles[a].pool = image_pool;
5636 
5637  if (task_pool != NULL) {
5639  }
5640  }
5641 
5642  if (task_pool != NULL) { /* wait for everything to be done */
5645  }
5646  else {
5648  }
5649 
5650  BKE_image_pool_free(image_pool);
5651 
5652  /* move threaded bounds back into ps->projectPartialRedraws */
5653  for (i = 0; i < ps->image_tot; i++) {
5654  int touch = 0;
5655  for (a = 0; a < ps->thread_tot; a++) {
5657  handles[a].projImages[i].partRedrawRect,
5659  }
5660 
5661  if (touch) {
5662  ps->projImages[i].touch = 1;
5663  touch_any = 1;
5664  }
5665  }
5666 
5667  /* Calculate pivot for rotation around selection if needed. */
5668  if (U.uiflag & USER_ORBIT_SELECTION) {
5669  float w[3];
5670  int tri_index;
5671 
5672  tri_index = project_paint_PickFace(ps, pos, w);
5673 
5674  if (tri_index != -1) {
5675  const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
5676  const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
5677  float world[3];
5679 
5681  ps->mvert_eval[lt_vtri[0]].co,
5682  ps->mvert_eval[lt_vtri[1]].co,
5683  ps->mvert_eval[lt_vtri[2]].co,
5684  w);
5685 
5686  ups->average_stroke_counter++;
5687  mul_m4_v3(ps->obmat, world);
5689  ups->last_stroke_valid = true;
5690  }
5691  }
5692 
5693  return touch_any;
5694 }
5695 
5697  void *ps_handle_p,
5698  const float prev_pos[2],
5699  const float pos[2],
5700  const bool eraser,
5701  float pressure,
5702  float distance,
5703  float size,
5704  /* extra view */
5705  ProjPaintState *ps)
5706 {
5707  ProjStrokeHandle *ps_handle = ps_handle_p;
5708  Brush *brush = ps->brush;
5709  Scene *scene = ps->scene;
5710 
5711  ps->brush_size = size;
5712  ps->blend = brush->blend;
5713  if (eraser) {
5715  }
5716 
5717  /* handle gradient and inverted stroke color here */
5720  brush,
5721  false,
5722  ps->mode == BRUSH_STROKE_INVERT,
5723  distance,
5724  pressure,
5725  ps->paint_color,
5726  NULL);
5727  if (ps->use_colormanagement) {
5729  }
5730  else {
5732  }
5733  }
5734  else if (ps->tool == PAINT_TOOL_MASK) {
5735  ps->stencil_value = brush->weight;
5736 
5737  if ((ps->mode == BRUSH_STROKE_INVERT) ^
5739  ps->stencil_value = 1.0f - ps->stencil_value;
5740  }
5741  }
5742 
5743  if (project_paint_op(ps, prev_pos, pos)) {
5744  ps_handle->need_redraw = true;
5746  }
5747 }
5748 
5750  void *ps_handle_p,
5751  const float prev_pos[2],
5752  const float pos[2],
5753  const bool eraser,
5754  float pressure,
5755  float distance,
5756  float size)
5757 {
5758  int i;
5759  ProjStrokeHandle *ps_handle = ps_handle_p;
5760 
5761  /* clone gets special treatment here to avoid going through image initialization */
5762  if (ps_handle->is_clone_cursor_pick) {
5763  Scene *scene = ps_handle->scene;
5765  View3D *v3d = CTX_wm_view3d(C);
5766  ARegion *region = CTX_wm_region(C);
5767  float *cursor = scene->cursor.location;
5768  const int mval_i[2] = {(int)pos[0], (int)pos[1]};
5769 
5771 
5772  if (!ED_view3d_autodist(depsgraph, region, v3d, mval_i, cursor, false, NULL)) {
5773  return;
5774  }
5775 
5777  ED_region_tag_redraw(region);
5778 
5779  return;
5780  }
5781 
5782  for (i = 0; i < ps_handle->ps_views_tot; i++) {
5783  ProjPaintState *ps = ps_handle->ps_views[i];
5784  paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
5785  }
5786 }
5787 
5788 /* initialize project paint settings from context */
5789 static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int mode)
5790 {
5792  ToolSettings *settings = scene->toolsettings;
5793 
5794  /* brush */
5795  ps->mode = mode;
5796  ps->brush = BKE_paint_brush(&settings->imapaint.paint);
5797  if (ps->brush) {
5798  Brush *brush = ps->brush;
5799  ps->tool = brush->imagepaint_tool;
5800  ps->blend = brush->blend;
5801  /* only check for inversion for the soften tool, elsewhere,
5802  * a resident brush inversion flag can cause issues */
5803  if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
5804  ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
5807 
5808  ps->blurkernel = paint_new_blur_kernel(brush, true);
5809  }
5810 
5811  /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
5813  ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true :
5814  false;
5815  ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
5816  }
5817  else {
5818  /* brush may be NULL*/
5819  ps->do_masking = false;
5820  ps->is_texbrush = false;
5821  ps->is_maskbrush = false;
5822  }
5823 
5824  /* sizeof(ProjPixel), since we alloc this a _lot_ */
5826  BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
5827 
5828  /* these can be NULL */
5829  ps->v3d = CTX_wm_view3d(C);
5830  ps->rv3d = CTX_wm_region_view3d(C);
5831  ps->region = CTX_wm_region(C);
5832 
5834  ps->scene = scene;
5835  /* allow override of active object */
5836  ps->ob = ob;
5837 
5839  ps->stencil_ima = settings->imapaint.stencil;
5840  ps->canvas_ima = (!ps->do_material_slots) ? settings->imapaint.canvas : NULL;
5841  ps->clone_ima = (!ps->do_material_slots) ? settings->imapaint.clone : NULL;
5842 
5843  ps->do_mask_cavity = (settings->imapaint.paint.flags & PAINT_USE_CAVITY_MASK) ? true : false;
5844  ps->cavity_curve = settings->imapaint.paint.cavity_curve;
5845 
5846  /* setup projection painting data */
5847  if (ps->tool != PAINT_TOOL_FILL) {
5848  ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? false : true;
5849  ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? false : true;
5850  ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? false : true;
5851  }
5852  else {
5853  ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
5854  }
5855 
5856  if (ps->tool == PAINT_TOOL_CLONE) {
5857  ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
5858  }
5859 
5861  /* deactivate stenciling for the stencil brush :) */
5863  !(ps->do_stencil_brush) && ps->stencil_ima);
5865  0);
5866 
5867 #ifndef PROJ_DEBUG_NOSEAMBLEED
5868  /* pixel num to bleed */
5869  ps->seam_bleed_px = settings->imapaint.seam_bleed;
5870  ps->seam_bleed_px_sq = square_s(settings->imapaint.seam_bleed);
5871 #endif
5872 
5873  if (ps->do_mask_normal) {
5874  ps->normal_angle_inner = settings->imapaint.normal_angle;
5875  ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f;
5876  }
5877  else {
5878  ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle;
5879  }
5880 
5881  ps->normal_angle_inner *= (float)(M_PI_2 / 90);
5882  ps->normal_angle *= (float)(M_PI_2 / 90);
5884 
5885  if (ps->normal_angle_range <= 0.0f) {
5886  /* no need to do blending */
5887  ps->do_mask_normal = false;
5888  }
5889 
5890  ps->normal_angle__cos = cosf(ps->normal_angle);
5892 
5893  ps->dither = settings->imapaint.dither;
5894 
5896 }
5897 
5898 void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
5899 {
5900  ProjStrokeHandle *ps_handle;
5902  ToolSettings *settings = scene->toolsettings;
5903  char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
5904 
5905  ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
5906  ps_handle->scene = scene;
5907  ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
5908 
5909  /* bypass regular stroke logic */
5910  if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) && (mode == BRUSH_STROKE_INVERT)) {
5912  ps_handle->is_clone_cursor_pick = true;
5913  return ps_handle;
5914  }
5915 
5916  ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
5917 
5919  ps_handle->symmetry_flags = mesh->symmetry;
5920  ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
5921  bool is_multi_view = (ps_handle->ps_views_tot != 1);
5922 
5923  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5924  ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
5925  ps_handle->ps_views[i] = ps;
5926  }
5927 
5928  if (ps_handle->symmetry_flags) {
5929  int index = 0;
5930 
5931  int x = 0;
5932  do {
5933  int y = 0;
5934  do {
5935  int z = 0;
5936  do {
5937  symmetry_flag_views[index++] = ((x ? PAINT_SYMM_X : 0) | (y ? PAINT_SYMM_Y : 0) |
5938  (z ? PAINT_SYMM_Z : 0));
5939  BLI_assert(index <= ps_handle->ps_views_tot);
5940  } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
5941  } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
5942  } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
5943  BLI_assert(index == ps_handle->ps_views_tot);
5944  }
5945 
5946  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5947  ProjPaintState *ps = ps_handle->ps_views[i];
5948 
5949  project_state_init(C, ob, ps, mode);
5950 
5951  if (ps->ob == NULL) {
5952  ps_handle->ps_views_tot = i + 1;
5953  goto fail;
5954  }
5955  }
5956 
5957  /* Don't allow brush size below 2 */
5958  if (BKE_brush_size_get(scene, ps_handle->brush) < 2) {
5959  BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
5960  }
5961 
5962  /* allocate and initialize spatial data structures */
5963 
5964  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5965  ProjPaintState *ps = ps_handle->ps_views[i];
5966 
5969 
5970  /* re-use! */
5971  if (i != 0) {
5972  ps->is_shared_user = true;
5973  PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
5974  }
5975 
5976  project_paint_begin(C, ps, is_multi_view, symmetry_flag_views[i]);
5977  if (ps->me_eval == NULL) {
5978  goto fail;
5979  }
5980 
5981  paint_proj_begin_clone(ps, mouse);
5982  }
5983 
5984  paint_brush_init_tex(ps_handle->brush);
5985 
5986  return ps_handle;
5987 
5988 fail:
5989  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
5990  ProjPaintState *ps = ps_handle->ps_views[i];
5991  MEM_freeN(ps);
5992  }
5993  MEM_freeN(ps_handle);
5994  return NULL;
5995 }
5996 
5997 void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
5998 {
5999  ProjStrokeHandle *ps_handle = ps_handle_p;
6000 
6001  if (ps_handle->need_redraw) {
6002  ps_handle->need_redraw = false;
6003  }
6004  else if (!final) {
6005  return;
6006  }
6007 
6008  if (final) {
6009  /* compositor listener deals with updating */
6011  }
6012  else {
6014  }
6015 }
6016 
6017 void paint_proj_stroke_done(void *ps_handle_p)
6018 {
6019  ProjStrokeHandle *ps_handle = ps_handle_p;
6020  Scene *scene = ps_handle->scene;
6021 
6022  if (ps_handle->is_clone_cursor_pick) {
6023  MEM_freeN(ps_handle);
6024  return;
6025  }
6026 
6027  for (int i = 1; i < ps_handle->ps_views_tot; i++) {
6028  PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
6029  }
6030 
6031  BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
6032 
6033  paint_brush_exit_tex(ps_handle->brush);
6034 
6035  for (int i = 0; i < ps_handle->ps_views_tot; i++) {
6036  ProjPaintState *ps;
6037  ps = ps_handle->ps_views[i];
6038  project_paint_end(ps);
6039  MEM_freeN(ps);
6040  }
6041 
6042  MEM_freeN(ps_handle);
6043 }
6044 /* use project paint to re-apply an image */
6046 {
6047  Main *bmain = CTX_data_main(C);
6048  Image *image = BLI_findlink(&bmain->images, RNA_enum_get(op->ptr, "image"));
6050  ViewLayer *view_layer = CTX_data_view_layer(C);
6051  ProjPaintState ps = {NULL};
6052  int orig_brush_size;
6053  IDProperty *idgroup;
6054  IDProperty *view_data = NULL;
6055  Object *ob = OBACT(view_layer);
6056  bool uvs, mat, tex;
6057 
6058  if (ob == NULL || ob->type != OB_MESH) {
6059  BKE_report(op->reports, RPT_ERROR, "No active mesh object");
6060  return OPERATOR_CANCELLED;
6061  }
6062 
6063  if (!ED_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
6064  ED_paint_data_warning(op->reports, uvs, mat, tex, true);
6066  return OPERATOR_CANCELLED;
6067  }
6068 
6070 
6071  if (image == NULL) {
6072  BKE_report(op->reports, RPT_ERROR, "Image could not be found");
6073  return OPERATOR_CANCELLED;
6074  }
6075 
6076  ps.reproject_image = image;
6078 
6079  if ((ps.reproject_ibuf == NULL) ||
6080  ((ps.reproject_ibuf->rect || ps.reproject_ibuf->rect_float) == false)) {
6081  BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
6082  return OPERATOR_CANCELLED;
6083  }
6084 
6085  idgroup = IDP_GetProperties(&image->id, 0);
6086 
6087  if (idgroup) {
6089 
6090  /* type check to make sure its ok */
6091  if (view_data != NULL &&
6092  (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT)) {
6093  BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
6094  return OPERATOR_CANCELLED;
6095  }
6096  }
6097 
6098  if (view_data) {
6099  /* image has stored view projection info */
6101  }
6102  else {
6104 
6105  if (scene->camera == NULL) {
6106  BKE_report(op->reports, RPT_ERROR, "No active camera set");
6107  return OPERATOR_CANCELLED;
6108  }
6109  }
6110 
6111  /* override */
6112  ps.is_texbrush = false;
6113  ps.is_maskbrush = false;
6114  ps.do_masking = false;
6115  orig_brush_size = BKE_brush_size_get(scene, ps.brush);
6116  /* cover the whole image */
6117  BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize);
6118 
6119  /* so pixels are initialized with minimal info */
6120  ps.tool = PAINT_TOOL_DRAW;
6121 
6123 
6124  /* allocate and initialize spatial data structures */
6125  project_paint_begin(C, &ps, false, 0);
6126 
6127  if (ps.me_eval == NULL) {
6128  BKE_brush_size_set(scene, ps.brush, orig_brush_size);
6129  BKE_report(op->reports, RPT_ERROR, "Could not get valid evaluated mesh");
6130  return OPERATOR_CANCELLED;
6131  }
6132 
6134 
6135  const float pos[2] = {0.0, 0.0};
6136  const float lastpos[2] = {0.0, 0.0};
6137  int a;
6138 
6139  project_paint_op(&ps, lastpos, pos);
6140 
6142 
6143  for (a = 0; a < ps.image_tot; a++) {
6146  }
6147 
6148  project_paint_end(&ps);
6149 
6151 
6153  BKE_brush_size_set(scene, ps.brush, orig_brush_size);
6154 
6155  return OPERATOR_FINISHED;
6156 }
6157 
6159 {
6160  PropertyRNA *prop;
6161 
6162  /* identifiers */
6163  ot->name = "Project Image";
6164  ot->idname = "PAINT_OT_project_image";
6165  ot->description = "Project an edited render from the active camera back onto the object";
6166 
6167  /* api callbacks */
6170 
6171  /* flags */
6173 
6174  prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "");
6177  ot->prop = prop;
6178 }
6179 
6181 {
6182  bScreen *screen = CTX_wm_screen(C);
6183  if (!(screen && BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0))) {
6184  CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from");
6185  return false;
6186  }
6187  if (G.background || !GPU_is_init()) {
6188  return false;
6189  }
6190  return true;
6191 }
6192 
6194 {
6195  Image *image;
6196  ImBuf *ibuf;
6197  char filename[FILE_MAX];
6198 
6199  Main *bmain = CTX_data_main(C);
6202  ToolSettings *settings = scene->toolsettings;
6203  int w = settings->imapaint.screen_grab_size[0];
6204  int h = settings->imapaint.screen_grab_size[1];
6205  int maxsize;
6206  char err_out[256] = "unknown";
6207 
6209  if (!area) {
6210  BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
6211  return OPERATOR_CANCELLED;
6212  }
6213 
6215  if (!region) {
6216  BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
6217  return OPERATOR_CANCELLED;
6218  }
6219  RegionView3D *rv3d = region->regiondata;
6220 
6221  RNA_string_get(op->ptr, "filepath", filename);
6222 
6223  maxsize = GPU_max_texture_size();
6224 
6225  if (w > maxsize) {
6226  w = maxsize;
6227  }
6228  if (h > maxsize) {
6229  h = maxsize;
6230  }
6231 
6232  /* Create a copy of the overlays where they are all turned off, except the
6233  * texture paint overlay opacity */
6234  View3D *v3d = area->spacedata.first;
6235  View3D v3d_copy = *v3d;
6236  v3d_copy.gridflag = 0;
6237  v3d_copy.flag2 = 0;
6238  v3d_copy.flag = V3D_HIDE_HELPLINES;
6239  v3d_copy.gizmo_flag = V3D_GIZMO_HIDE;
6240 
6241  memset(&v3d_copy.overlay, 0, sizeof(View3DOverlay));
6246 
6248  scene,
6249  v3d_copy.shading.type,
6250  &v3d_copy,
6251  region,
6252  w,
6253  h,
6254  IB_rect,
6255  R_ALPHAPREMUL,
6256  NULL,
6257  false,
6258  NULL,
6259  err_out);
6260 
6261  if (!ibuf) {
6262  /* Mostly happens when OpenGL offscreen buffer was failed to create, */
6263  /* but could be other reasons. Should be handled in the future. nazgul */
6264  BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out);
6265  return OPERATOR_CANCELLED;
6266  }
6267 
6268  image = BKE_image_add_from_imbuf(bmain, ibuf, "image_view");
6269 
6270  /* Drop reference to ibuf so that the image owns it */
6271  IMB_freeImBuf(ibuf);
6272 
6273  if (image) {
6274  /* now for the trickiness. store the view projection here!
6275  * re-projection will reuse this */
6276  IDPropertyTemplate val;
6277  IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
6278  IDProperty *view_data;
6279  bool is_ortho;
6280  float *array;
6281 
6283  val.array.type = IDP_FLOAT;
6284  view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID);
6285 
6286  array = (float *)IDP_Array(view_data);
6287  memcpy(array, rv3d->winmat, sizeof(rv3d->winmat));
6288  array += sizeof(rv3d->winmat) / sizeof(float);
6289  memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat));
6290  array += sizeof(rv3d->viewmat) / sizeof(float);
6291  is_ortho = ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &array[0], &array[1], true);
6292  /* using float for a bool is dodgy but since its an extra member in the array...
6293  * easier than adding a single bool prop */
6294  array[2] = is_ortho ? 1.0f : 0.0f;
6295 
6296  IDP_AddToGroup(idgroup, view_data);
6297  }
6298 
6299  return OPERATOR_FINISHED;
6300 }
6301 
6303 {
6304  /* identifiers */
6305  ot->name = "Image from View";
6306  ot->idname = "PAINT_OT_image_from_view";
6307  ot->description = "Make an image from biggest 3D view for reprojection";
6308 
6309  /* api callbacks */
6312 
6313  /* flags */
6314  ot->flag = OPTYPE_REGISTER;
6315 
6316  RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file");
6317 }
6318 
6319 /*********************************************
6320  * Data generation for projective texturing *
6321  * *******************************************/
6322 
6323 void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil)
6324 {
6325  BKE_reportf(reports,
6326  RPT_WARNING,
6327  "Missing%s%s%s%s detected!",
6328  !uvs ? " UVs," : "",
6329  !mat ? " Materials," : "",
6330  !tex ? " Textures," : "",
6331  !stencil ? " Stencil," : "");
6332 }
6333 
6334 /* Make sure that active object has a material,
6335  * and assign UVs and image layers if they do not exist */
6337  Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
6338 {
6339  Mesh *me;
6340  int layernum;
6342  Brush *br = BKE_paint_brush(&imapaint->paint);
6343  bool hasmat = true;
6344  bool hastex = true;
6345  bool hasstencil = true;
6346  bool hasuvs = true;
6347 
6348  imapaint->missing_data = 0;
6349 
6350  BLI_assert(ob->type == OB_MESH);
6351 
6352  if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
6353  /* no material, add one */
6354  if (ob->totcol == 0) {
6355  hasmat = false;
6356  hastex = false;
6357  }
6358  else {
6359  /* there may be material slots but they may be empty, check */
6360  hasmat = false;
6361  hastex = false;
6362 
6363  for (int i = 1; i < ob->totcol + 1; i++) {
6364  Material *ma = BKE_object_material_get(ob, i);
6365 
6366  if (ma && !ID_IS_LINKED(ma)) {
6367  hasmat = true;
6368  if (ma->texpaintslot == NULL) {
6369  /* refresh here just in case */
6371  }
6372  if (ma->texpaintslot != NULL &&
6373  (ma->texpaintslot[ma->paint_active_slot].ima == NULL ||
6375  hastex = true;
6376  break;
6377  }
6378  }
6379  }
6380  }
6381  }
6382  else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
6383  if (imapaint->canvas == NULL || ID_IS_LINKED(imapaint->canvas)) {
6384  hastex = false;
6385  }
6386  }
6387 
6388  me = BKE_mesh_from_object(ob);
6389  layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
6390 
6391  if (layernum == 0) {
6392  hasuvs = false;
6393  }
6394 
6395  /* Make sure we have a stencil to paint on! */
6396  if (br && br->imagepaint_tool == PAINT_TOOL_MASK) {
6398 
6399  if (imapaint->stencil == NULL) {
6400  hasstencil = false;
6401  }
6402  }
6403 
6404  if (!hasuvs) {
6405  imapaint->missing_data |= IMAGEPAINT_MISSING_UVS;
6406  }
6407  if (!hasmat) {
6409  }
6410  if (!hastex) {
6411  imapaint->missing_data |= IMAGEPAINT_MISSING_TEX;
6412  }
6413  if (!hasstencil) {
6415  }
6416 
6417  if (uvs) {
6418  *uvs = hasuvs;
6419  }
6420  if (mat) {
6421  *mat = hasmat;
6422  }
6423  if (tex) {
6424  *tex = hastex;
6425  }
6426  if (stencil) {
6427  *stencil = hasstencil;
6428  }
6429 
6430  return hasuvs && hasmat && hastex && hasstencil;
6431 }
6432 
6433 /* Add layer operator */
6434 enum {
6442 };
6443 
6445  {LAYER_BASE_COLOR, "BASE_COLOR", 0, "Base Color", ""},
6446  {LAYER_SPECULAR, "SPECULAR", 0, "Specular", ""},
6447  {LAYER_ROUGHNESS, "ROUGHNESS", 0, "Roughness", ""},
6448  {LAYER_METALLIC, "METALLIC", 0, "Metallic", ""},
6449  {LAYER_NORMAL, "NORMAL", 0, "Normal", ""},
6450  {LAYER_BUMP, "BUMP", 0, "Bump", ""},
6451  {LAYER_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
6452  {0, NULL, 0, NULL, NULL},
6453 };
6454 
6455 static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
6456 {
6457  Image *ima;
6458  float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
6459  char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
6460  int width = 1024;
6461  int height = 1024;
6462  bool use_float = false;
6463  short gen_type = IMA_GENTYPE_BLANK;
6464  bool alpha = false;
6465 
6466  if (op) {
6467  width = RNA_int_get(op->ptr, "width");
6468  height = RNA_int_get(op->ptr, "height");
6469  use_float = RNA_boolean_get(op->ptr, "float");
6470  gen_type = RNA_enum_get(op->ptr, "generated_type");
6471  RNA_float_get_array(op->ptr, "color", color);
6472  alpha = RNA_boolean_get(op->ptr, "alpha");
6473  RNA_string_get(op->ptr, "name", imagename);
6474  }
6475  ima = BKE_image_add_generated(bmain,
6476  width,
6477  height,
6478  imagename,
6479  alpha ? 32 : 24,
6480  use_float,
6481  gen_type,
6482  color,
6483  false,
6484  is_data,
6485  false); /* TODO(lukas): Add option */
6486 
6487  return ima;
6488 }
6489 
6491 {
6492  if (RNA_struct_property_is_set(op->ptr, "color")) {
6493  return;
6494  }
6495 
6497  if (in_node == NULL) {
6498  return;
6499  }
6500 
6501  float color[4];
6502 
6503  if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
6504  /* Copy color from node, so result is unchanged after assigning textures. */
6505  bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
6506 
6507  switch (in_sock->type) {
6508  case SOCK_FLOAT: {
6509  bNodeSocketValueFloat *socket_data = in_sock->default_value;
6510  copy_v3_fl(color, socket_data->value);
6511  color[3] = 1.0f;
6512  break;
6513  }
6514  case SOCK_VECTOR:
6515  case SOCK_RGBA: {
6516  bNodeSocketValueRGBA *socket_data = in_sock->default_value;
6517  copy_v3_v3(color, socket_data->value);
6518  color[3] = 1.0f;
6519  break;
6520  }
6521  default: {
6522  return;
6523  }
6524  }
6525  }
6526  else if (type == LAYER_NORMAL) {
6527  /* Neutral tangent space normal map. */
6528  rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
6529  }
6530  else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) {
6531  /* Neutral displacement and bump map. */
6532  rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
6533  }
6534  else {
6535  return;
6536  }
6537 
6538  RNA_float_set_array(op->ptr, "color", color);
6539 }
6540 
6542 {
6545  Material *ma;
6546  Image *ima = NULL;
6547 
6548  if (!ob) {
6549  return false;
6550  }
6551 
6552  ma = BKE_object_material_get(ob, ob->actcol);
6553 
6554  if (ma) {
6555  Main *bmain = CTX_data_main(C);
6556  int type = RNA_enum_get(op->ptr, "type");
6557  bool is_data = (type > LAYER_BASE_COLOR);
6558 
6559  bNode *imanode;
6560  bNodeTree *ntree = ma->nodetree;
6561 
6562  if (!ntree) {
6563  ED_node_shader_default(C, &ma->id);
6564  ntree = ma->nodetree;
6565  }
6566 
6567  ma->use_nodes = true;
6568 
6569  /* try to add an image node */
6571 
6572  ima = proj_paint_image_create(op, bmain, is_data);
6573  imanode->id = &ima->id;
6574 
6575  nodeSetActive(ntree, imanode);
6576 
6577  /* Connect to first available principled bsdf node. */
6579  bNode *out_node = imanode;
6580 
6581  if (in_node != NULL) {
6582  bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
6583  bNodeSocket *in_sock = NULL;
6584 
6585  if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
6586  in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
6587  }
6588  else if (type == LAYER_NORMAL) {
6589  bNode *nor_node;
6591 
6592  in_sock = nodeFindSocket(nor_node, SOCK_IN, "Color");
6593  nodeAddLink(ntree, out_node, out_sock, nor_node, in_sock);
6594 
6595  in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
6596  out_sock = nodeFindSocket(nor_node, SOCK_OUT, "Normal");
6597 
6598  out_node = nor_node;
6599  }
6600  else if (type == LAYER_BUMP) {
6601  bNode *bump_node;
6602  bump_node = nodeAddStaticNode(C, ntree, SH_NODE_BUMP);
6603 
6604  in_sock = nodeFindSocket(bump_node, SOCK_IN, "Height");
6605  nodeAddLink(ntree, out_node, out_sock, bump_node, in_sock);
6606 
6607  in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
6608  out_sock = nodeFindSocket(bump_node, SOCK_OUT, "Normal");
6609 
6610  out_node = bump_node;
6611  }
6612  else if (type == LAYER_DISPLACEMENT) {
6613  /* Connect to the displacement output socket */
6615 
6616  if (in_node != NULL) {
6617  in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
6618  }
6619  else {
6620  in_sock = NULL;
6621  }
6622  }
6623 
6624  /* Check if the socket in already connected to something */
6625  bNodeLink *link = in_sock ? in_sock->link : NULL;
6626  if (in_sock != NULL && link == NULL) {
6627  nodeAddLink(ntree, out_node, out_sock, in_node, in_sock);
6628 
6629  nodePositionRelative(out_node, in_node, out_sock, in_sock);
6630  }
6631  }
6632 
6634  /* In case we added more than one node, position them too. */
6635  nodePositionPropagate(out_node);
6636 
6637  if (ima) {
6641  }
6642 
6643  DEG_id_tag_update(&ntree->id, 0);
6646 
6648 
6649  return true;
6650  }
6651 
6652  return false;
6653 }
6654 
6655 static int get_texture_layer_type(wmOperator *op, const char *prop_name)
6656 {
6657  int type_value = RNA_enum_get(op->ptr, prop_name);
6658  int type = RNA_enum_from_value(layer_type_items, type_value);
6659  BLI_assert(type != -1);
6660  return type;
6661 }
6662 
6664 {
6665  Material *ma = BKE_object_material_get(ob, ob->actcol);
6666  if (!ma) {
6667  Main *bmain = CTX_data_main(C);
6668  ma = BKE_material_add(bmain, "Material");
6670  }
6671  return ma;
6672 }
6673 
6675 {
6678 
6679  int type = get_texture_layer_type(op, "type");
6680  proj_paint_default_color(op, type, ma);
6681 
6682  if (proj_paint_add_slot(C, op)) {
6683  return OPERATOR_FINISHED;
6684  }
6685  return OPERATOR_CANCELLED;
6686 }
6687 
6689  int texture_type,
6690  char *dst,
6691  int dst_length)
6692 {
6693  Material *ma = BKE_object_material_get(ob, ob->actcol);
6694  const char *base_name = ma ? &ma->id.name[2] : &ob->id.name[2];
6695  BLI_snprintf(dst, dst_length, "%s %s", base_name, layer_type_items[texture_type].name);
6696 }
6697 
6699  wmOperator *op,
6700  const wmEvent *UNUSED(event))
6701 {
6702  /* Get material and default color to display in the popup. */
6705 
6706  int type = get_texture_layer_type(op, "type");
6707  proj_paint_default_color(op, type, ma);
6708 
6709  char imagename[MAX_ID_NAME - 2];
6710  get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
6711  RNA_string_set(op->ptr, "name", imagename);
6712 
6713  return WM_operator_props_dialog_popup(C, op, 300);
6714 }
6715 
6716 #define IMA_DEF_NAME N_("Untitled")
6717 
6719 {
6720  PropertyRNA *prop;
6721  static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
6722 
6723  /* identifiers */
6724  ot->name = "Add Texture Paint Slot";
6725  ot->description = "Add a texture paint slot";
6726  ot->idname = "PAINT_OT_add_texture_paint_slot";
6727 
6728  /* api callbacks */
6732 
6733  /* flags */
6734  ot->flag = OPTYPE_UNDO;
6735 
6736  /* properties */
6737  prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
6739  RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
6740  prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
6742  prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
6744  prop = RNA_def_float_color(
6745  ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
6747  RNA_def_property_float_array_default(prop, default_color);
6748  RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
6749  RNA_def_enum(ot->srna,
6750  "generated_type",
6753  "Generated Type",
6754  "Fill the image with a grid for UV map testing");
6756  ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth");
6757 }
6758 
6760 {
6761  /* no checks here, poll function does them for us */
6762  Main *bmain = CTX_data_main(C);
6765 
6766  ED_uvedit_add_simple_uvs(bmain, scene, ob);
6767 
6769 
6770  DEG_id_tag_update(ob->data, 0);
6773  return OPERATOR_FINISHED;
6774 }
6775 
6777 {
6779 
6780  if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) {
6781  return false;
6782  }
6783  return true;
6784 }
6785 
6787 {
6788  /* identifiers */
6789  ot->name = "Add Simple UVs";
6790  ot->description = "Add cube map uvs on mesh";
6791  ot->idname = "PAINT_OT_add_simple_uvs";
6792 
6793  /* api callbacks */
6796 
6797  /* flags */
6799 }
typedef float(TangentPoint)[2]
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int size)
Definition: brush.c:2234
float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush)
float BKE_brush_sample_masktex(const struct Scene *scene, struct Brush *br, const float point[2], const int thread, struct ImagePool *pool)
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
float BKE_brush_sample_tex_3d(const struct Scene *scene, const struct Brush *br, const float point[3], float rgba[4], const int thread, struct ImagePool *pool)
float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len)
Definition: brush.c:2464
Camera data-block and utility functions.
void BKE_camera_params_init(CameraParams *params)
Definition: camera.c:271
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:370
void BKE_camera_params_compute_matrix(CameraParams *params)
Definition: camera.c:436
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:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1006
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
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)
Definition: customdata.c:3217
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_GetPropertyTypeFromGroup(const struct IDProperty *prop, const char *name, const char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct IDProperty * IDP_GetProperties(struct ID *id, const bool create_if_needed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:769
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL()
Definition: idprop.c:643
struct IDProperty * IDP_GetPropertyFromGroup(const struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:907
#define IDP_Array(prop)
Definition: BKE_idprop.h:155
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
Definition: image.c:5113
bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser)
Definition: image.c:5134
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
Definition: image.c:5100
struct ImagePool * BKE_image_pool_new(void)
Definition: image.c:5173
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], const bool stereo3d, const bool is_data, const bool tiled)
Definition: image.c:963
void BKE_image_free_gputextures(struct Image *ima)
Definition: image_gpu.c:517
void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf)
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition: BKE_image.h:167
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal)
Definition: image.c:3499
struct Image * BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name)
Definition: image.c:1029
void BKE_imageuser_default(struct ImageUser *iuser)
Definition: image.c:3451
void BKE_image_pool_free(struct ImagePool *pool)
Definition: image.c:5181
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
@ BKE_MAT_ASSIGN_USERPREF
Definition: BKE_material.h:71
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma)
Definition: material.c:1307
void BKE_object_material_assign(struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type)
Definition: material.c:850
struct Material * BKE_material_add(struct Main *bmain, const char *name)
Definition: material.c:301
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.c:1271
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v)
struct Mesh * mesh_get_eval_final(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh)
Definition: mesh_runtime.c:155
struct bNode * ntreeFindType(const struct bNodeTree *ntree, int type)
#define SH_NODE_BSDF_PRINCIPLED
Definition: BKE_node.h:1058
#define SH_NODE_NORMAL_MAP
Definition: BKE_node.h:1040
void nodePositionPropagate(struct bNode *node)
Definition: node.cc:2518
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree)
Definition: node.cc:4262
void nodePositionRelative(struct bNode *from_node, struct bNode *to_node, struct bNodeSocket *from_sock, struct bNodeSocket *to_sock)
Definition: node.cc:2476
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2189
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2004
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:3694
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:604
@ PAINT_MODE_TEXTURE_3D
Definition: BKE_paint.h:84
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
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:918
struct ScrArea struct ScrArea * BKE_screen_find_big_area(struct bScreen *screen, const int spacetype, const short min)
Definition: screen.c:983
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
#define LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:150
#define LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:154
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:161
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:395
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:165
#define M_1_PI
Definition: BLI_math_base.h:59
MINLINE float saacos(float fac)
int pow_i(int base, int exp)
Definition: math_base.c:30
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI_2
Definition: BLI_math_base.h:41
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:38
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 straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
MINLINE void premul_to_straight_v4(float color[4])
MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a)
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:414
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:422
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:1151
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:1616
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:3943
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:1360
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:3469
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:4722
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:1353
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:3998
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:324
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:1595
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:51
void mul_project_m4_v3(const float M[4][4], float vec[3])
Definition: math_matrix.c:824
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void mul_m4_v4(const float M[4][4], float r[4])
Definition: math_matrix.c:866
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void normalize_m4(float R[4][4]) ATTR_NONNULL()
Definition: math_matrix.c:1952
MINLINE void mul_v4_v4fl(float r[3], const float a[4], float f)
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])
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t)
Definition: math_vector.c:32
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
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:191
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void normal_short_to_float_v3(float r[3], const short n[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], 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:42
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:1043
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:740
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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:109
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:131
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
#define FILE_MAX
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition: task_pool.cc:496
TaskPool * BLI_task_pool_create_suspended(void *userdata, TaskPriority priority)
Definition: task_pool.cc:433
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:456
@ TASK_PRIORITY_HIGH
Definition: BLI_task.h:67
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:475
pthread_spinlock_t SpinLock
Definition: BLI_threads.h:111
void BLI_thread_unlock(int type)
Definition: threads.cc:389
void BLI_thread_lock(int type)
Definition: threads.cc:384
@ LOCK_CUSTOM1
Definition: BLI_threads.h:70
#define BLENDER_MAX_THREADS
Definition: BLI_threads.h:35
void BLI_spin_init(SpinLock *spin)
Definition: threads.cc:447
void BLI_spin_unlock(SpinLock *spin)
Definition: threads.cc:480
void BLI_spin_lock(SpinLock *spin)
Definition: threads.cc:461
void BLI_spin_end(SpinLock *spin)
Definition: threads.cc:495
#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:51
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)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SHADING
Definition: DNA_ID.h:631
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
#define MAX_ID_NAME
Definition: DNA_ID.h:269
@ IDP_FLOAT
Definition: DNA_ID.h:99
@ IDP_ARRAY
Definition: DNA_ID.h:100
@ 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
@ CD_ORIGINDEX
@ CD_MLOOPUV
#define CD_MASK_MTFACE
#define CD_MASK_MLOOPUV
@ 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_TEXTURE_PAINT
Object is a sort of wrapper for general info.
@ OB_NEG_SCALE
@ OB_MESH
@ R_ALPHAPREMUL
#define IMAGEPAINT_PROJECT_FLAT
#define IMAGEPAINT_PROJECT_LAYER_STENCIL
#define IMAGEPAINT_PROJECT_XRAY
#define IMAGEPAINT_PROJECT_LAYER_CLONE
@ PAINT_USE_CAVITY_MASK
@ IMAGEPAINT_MODE_IMAGE
@ IMAGEPAINT_MODE_MATERIAL
#define OBACT(_view_layer)
#define IMAGEPAINT_PROJECT_LAYER_STENCIL_INV
@ 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
#define V3D_HIDE_HELPLINES
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ 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
@ V3D_GIZMO_HIDE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_node_shader_default(const struct bContext *C, struct ID *id)
struct Object * ED_object_active_context(const struct bContext *C)
#define ED_IMAGE_UNDO_TILE_NUMBER(size)
Definition: ED_paint.h:99
void ED_image_undo_push_begin(const char *name, int paint_mode)
Definition: image_undo.c:1066
void ED_image_paint_tile_lock_end(void)
Definition: image_undo.c:81
void ED_image_paint_tile_lock_init(void)
Definition: image_undo.c:76
#define ED_IMAGE_UNDO_TILE_SIZE
Definition: ED_paint.h:98
void ED_image_undo_push_end(void)
Definition: image_undo.c:1103
struct ListBase * ED_image_paint_tile_list_get(void)
Definition: image_undo.c:1027
void * ED_image_paint_tile_push(struct ListBase *paint_tiles, 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.c:181
#define ED_IMAGE_UNDO_TILE_BITS
Definition: ED_paint.h:97
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:745
bool ED_operator_object_active_editable_mesh(struct bContext *C)
Definition: screen_ops.c:384
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob)
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_autodist(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int mval[2], float mouse_worldloc[3], const bool alphaoverride, const float fallback_depth_pt[3])
bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor)
void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4])
Definition: view3d_edit.c:4921
void view3d_operator_needs_opengl(const struct bContext *C)
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local)
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, const bool restore_rv3d_mats, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1834
int GPU_max_texture_size(void)
bool GPU_is_init(void)
Definition: gpu_init_exit.c:76
_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 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 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 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 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:780
void imb_freerectfloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:97
void bicubic_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:98
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:720
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
void imb_freerectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:115
void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
Definition: imageprocess.c:148
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:41
@ IMB_BLEND_ERASE_ALPHA
Definition: IMB_imbuf.h:204
@ IMB_BLEND_ADD_ALPHA
Definition: IMB_imbuf.h:205
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition: rectop.c:129
Contains defines and structs used throughout the imbuf module.
@ IB_rect
Read Guarded memory(de)allocation.
#define MEM_SIZE_OPTIMAL(size)
Group RGB to Bright Vector Camera CLAMP
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume SH_NODE_BUMP
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume SH_NODE_TEX_IMAGE
Group RGB to Bright Vector Camera Vector Combine SH_NODE_OUTPUT_MATERIAL
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:279
@ PROP_HIDDEN
Definition: RNA_types.h:202
@ PROP_PIXEL
Definition: RNA_types.h:128
@ PROP_COLOR_GAMMA
Definition: RNA_types.h:151
#define C
Definition: RandGen.cpp:39
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define NC_SCENE
Definition: WM_types.h:279
#define NA_ADDED
Definition: WM_types.h:464
#define ND_TOOLSETTINGS
Definition: WM_types.h:349
#define NA_EDITED
Definition: WM_types.h:462
#define NC_IMAGE
Definition: WM_types.h:285
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
OperationNode * node
Scene scene
World world
const Depsgraph * depsgraph
static CCL_NAMESPACE_BEGIN const double alpha
TaskPool * task_pool
bNodeTree * ntree
struct TileInfo TileInfo
uint pos
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define sinf(x)
#define cosf(x)
#define tanf(x)
#define atan2f(x, y)
#define fmodf(x, y)
#define acosf(x)
#define fabsf(x)
#define sqrtf(x)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
#define unit_float_to_uchar_clamp_v3(v1, v2)
static ulong state[N]
static unsigned a[3]
Definition: RandGen.cpp:92
static void area(int d1, int d2, int e1, int e2, float weights[2])
void paint_delete_blur_kernel(BlurKernel *kernel)
Definition: paint_image.c:257
BlurKernel * paint_new_blur_kernel(Brush *br, bool proj)
Definition: paint_image.c:191
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
Definition: paint_image.c:167
void paint_brush_init_tex(Brush *brush)
Definition: paint_image.c:409
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
Definition: paint_image.c:97
bool paint_use_opacity_masking(Brush *brush)
Definition: paint_image.c:350
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.c:365
void paint_brush_exit_tex(Brush *brush)
Definition: paint_image.c:425
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])
@ LAYER_NORMAL
@ LAYER_DISPLACEMENT
@ LAYER_ROUGHNESS
@ LAYER_METALLIC
@ LAYER_BUMP
@ LAYER_BASE_COLOR
@ LAYER_SPECULAR
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])
#define PROJ_FACE_WINDING_INIT
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 void proj_paint_default_color(wmOperator *op, int type, Material *ma)
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 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 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:311
@ BRUSH_STROKE_INVERT
Definition: paint_intern.h:312
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:6550
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:6514
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
Definition: rna_access.c:1902
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
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:3747
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
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:3675
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:3911
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
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:3585
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3819
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1563
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:3771
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
Definition: rna_define.c:2064
const EnumPropertyItem rna_enum_image_generated_type_items[]
Definition: rna_image.c:43
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:40
#define min(a, b)
Definition: sort.c:51
void * regiondata
float * wdata
Definition: paint_intern.h:356
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:84
char subtype
Definition: DNA_ID.h:71
char name[66]
Definition: DNA_ID.h:283
unsigned int * rect
float * rect_float
struct Image * stencil
struct Image * canvas
struct Image * clone
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * first
Definition: DNA_listBase.h:47
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]
short no[3]
Definition: BKE_main.h:116
ListBase images
Definition: BKE_main.h:154
struct bNodeTree * nodetree
short paint_active_slot
struct TexPaintSlot * texpaintslot
short paint_clone_slot
struct MLoopTri_Store looptris
struct MEdge * medge
struct CustomData pdata ldata
char symmetry
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
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 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
struct ID * id
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
float max
struct IDPropertyTemplate::@28 array
ccl_device_inline float distance(const float2 &a, const float2 &b)
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
#define G(x, y, z)
ParamHandle ** handles
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
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))