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