LEFT | RIGHT |
1 /* | 1 /* |
2 * $Id$ | |
3 * imagepaint.c | |
4 * | |
5 * Functions to paint images in 2D and 3D. | |
6 *· | |
7 * ***** BEGIN GPL LICENSE BLOCK ***** | 2 * ***** BEGIN GPL LICENSE BLOCK ***** |
8 * | 3 * |
9 * This program is free software; you can redistribute it and/or | 4 * This program is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU General Public License | 5 * modify it under the terms of the GNU General Public License |
11 * as published by the Free Software Foundation; either version 2 | 6 * as published by the Free Software Foundation; either version 2 |
12 * of the License, or (at your option) any later version. | 7 * of the License, or (at your option) any later version. |
13 * | 8 * |
14 * This program is distributed in the hope that it will be useful, | 9 * This program is distributed in the hope that it will be useful, |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
18 * | 13 * |
19 * along with this program; if not, write to the Free Software Foundation, | 14 * along with this program; if not, write to the Free Software Foundation, |
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
21 * | 16 * |
22 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | 17 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. |
23 * All rights reserved. | 18 * All rights reserved. |
24 * | 19 * |
25 * The Original Code is: some of this file. | 20 * The Original Code is: some of this file. |
26 * | 21 * |
27 * Contributor(s): Jens Ole Wund (bjornmose), Campbell Barton (ideasman42) | 22 * Contributor(s): Jens Ole Wund (bjornmose), Campbell Barton (ideasman42) |
28 * | 23 * |
29 * ***** END GPL LICENSE BLOCK ***** | 24 * ***** END GPL LICENSE BLOCK ***** |
30 */ | 25 */ |
31 | 26 |
32 /** \file blender/editors/sculpt_paint/paint_image.c | 27 /** \file blender/editors/sculpt_paint/paint_image.c |
33 * \ingroup edsculpt | 28 * \ingroup edsculpt |
| 29 * \brief Functions to paint images in 2D and 3D. |
34 */ | 30 */ |
35 | |
36 | 31 |
37 #include <float.h> | 32 #include <float.h> |
38 #include <string.h> | 33 #include <string.h> |
39 #include <stdio.h> | 34 #include <stdio.h> |
40 #include <math.h> | 35 #include <math.h> |
41 | 36 |
42 #include "MEM_guardedalloc.h" | 37 #include "MEM_guardedalloc.h" |
43 | 38 |
44 #ifdef WIN32 | 39 #ifdef WIN32 |
45 #include "BLI_winstuff.h" | 40 # include "BLI_winstuff.h" |
46 #endif | 41 #endif |
| 42 |
47 #include "BLI_math.h" | 43 #include "BLI_math.h" |
48 #include "BLI_blenlib.h" | 44 #include "BLI_blenlib.h" |
49 #include "BLI_dynstr.h" | |
50 #include "BLI_linklist.h" | 45 #include "BLI_linklist.h" |
51 #include "BLI_memarena.h" | 46 #include "BLI_memarena.h" |
52 #include "BLI_threads.h" | 47 #include "BLI_threads.h" |
53 #include "BLI_utildefines.h" | 48 #include "BLI_utildefines.h" |
54 | 49 |
55 #include "PIL_time.h" | 50 #include "PIL_time.h" |
56 | 51 |
57 #include "IMB_imbuf.h" | 52 #include "IMB_imbuf.h" |
58 #include "IMB_imbuf_types.h" | 53 #include "IMB_imbuf_types.h" |
59 | 54 |
60 #include "DNA_brush_types.h" | 55 #include "DNA_brush_types.h" |
61 #include "DNA_mesh_types.h" | 56 #include "DNA_mesh_types.h" |
62 #include "DNA_meshdata_types.h" | 57 #include "DNA_node_types.h" |
63 #include "DNA_object_types.h" | 58 #include "DNA_object_types.h" |
64 #include "DNA_scene_types.h" | 59 |
65 #include "DNA_texture_types.h" | 60 #include "BKE_camera.h" |
66 | |
67 #include "BKE_context.h" | 61 #include "BKE_context.h" |
68 #include "BKE_depsgraph.h" | 62 #include "BKE_depsgraph.h" |
69 #include "BKE_DerivedMesh.h" | 63 #include "BKE_DerivedMesh.h" |
70 #include "BKE_idprop.h" | 64 #include "BKE_idprop.h" |
71 #include "BKE_brush.h" | 65 #include "BKE_brush.h" |
72 #include "BKE_image.h" | 66 #include "BKE_image.h" |
73 #include "BKE_library.h" | 67 #include "BKE_library.h" |
74 #include "BKE_main.h" | 68 #include "BKE_main.h" |
75 #include "BKE_mesh.h" | 69 #include "BKE_mesh.h" |
76 #include "BKE_node.h" | 70 #include "BKE_node.h" |
77 #include "BKE_object.h" | 71 #include "BKE_object.h" |
78 #include "BKE_paint.h" | 72 #include "BKE_paint.h" |
79 #include "BKE_report.h" | 73 #include "BKE_report.h" |
| 74 #include "BKE_scene.h" |
| 75 #include "BKE_colortools.h" |
| 76 |
| 77 #include "BKE_editmesh.h" |
80 | 78 |
81 #include "BIF_gl.h" | 79 #include "BIF_gl.h" |
82 #include "BIF_glutil.h" | 80 #include "BIF_glutil.h" |
83 | 81 |
84 #include "UI_view2d.h" | 82 #include "UI_view2d.h" |
85 | 83 |
86 #include "ED_image.h" | 84 #include "ED_image.h" |
| 85 #include "ED_object.h" |
87 #include "ED_screen.h" | 86 #include "ED_screen.h" |
88 #include "ED_sculpt.h" | 87 #include "ED_sculpt.h" |
| 88 #include "ED_uvedit.h" |
89 #include "ED_view3d.h" | 89 #include "ED_view3d.h" |
| 90 #include "ED_mesh.h" |
90 | 91 |
91 #include "WM_api.h" | 92 #include "WM_api.h" |
92 #include "WM_types.h" | 93 #include "WM_types.h" |
93 | 94 |
94 #include "RNA_access.h" | 95 #include "RNA_access.h" |
95 #include "RNA_define.h" | 96 #include "RNA_define.h" |
96 #include "RNA_enum_types.h" | 97 #include "RNA_enum_types.h" |
97 | 98 |
98 #include "GPU_draw.h" | 99 #include "GPU_draw.h" |
99 | 100 |
| 101 #include "IMB_colormanagement.h" |
| 102 |
100 #include "paint_intern.h" | 103 #include "paint_intern.h" |
101 | |
102 /* Defines and Structs */ | |
103 | |
104 #define IMAPAINT_CHAR_TO_FLOAT(c) ((c)/255.0f) | |
105 | |
106 #define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { (c)[0]=FTOCHAR((f)[0]); (c)[1]=FTOCHA
R((f)[1]); (c)[2]=FTOCHAR((f)[2]); } | |
107 #define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { (c)[0]=FTOCHAR((f)[0]); (c)[1]=FTOCH
AR((f)[1]); (c)[2]=FTOCHAR((f)[2]); (c)[3]=FTOCHAR((f)[3]); } | |
108 | |
109 #define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { (f)[0]=IMAPAINT_CHAR_TO_FLOAT((c)[0])
; (f)[1]=IMAPAINT_CHAR_TO_FLOAT((c)[1]); (f)[2]=IMAPAINT_CHAR_TO_FLOAT((c)[2]);
} | |
110 #define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { (f)[0]=IMAPAINT_CHAR_TO_FLOAT((c)[0]
); (f)[1]=IMAPAINT_CHAR_TO_FLOAT((c)[1]); (f)[2]=IMAPAINT_CHAR_TO_FLOAT((c)[2]);
(f)[3]=IMAPAINT_CHAR_TO_FLOAT((c)[3]); } | |
111 #define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b) | |
112 | |
113 #define IMAPAINT_TILE_BITS 6 | |
114 #define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS) | |
115 #define IMAPAINT_TILE_NUMBER(size) (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAI
NT_TILE_BITS) | |
116 | |
117 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s
hort texpaint); | |
118 | |
119 | |
120 typedef struct ImagePaintState { | |
121 SpaceImage *sima; | |
122 View2D *v2d; | |
123 Scene *scene; | |
124 bScreen *screen; | |
125 | |
126 Brush *brush; | |
127 short tool, blend; | |
128 Image *image; | |
129 ImBuf *canvas; | |
130 ImBuf *clonecanvas; | |
131 short clonefreefloat; | |
132 char *warnpackedfile; | |
133 char *warnmultifile; | |
134 | |
135 /* texture paint only */ | |
136 Object *ob; | |
137 Mesh *me; | |
138 int faceindex; | |
139 float uv[2]; | |
140 } ImagePaintState; | |
141 | |
142 typedef struct ImagePaintPartialRedraw { | |
143 int x1, y1, x2, y2; | |
144 int enabled; | |
145 } ImagePaintPartialRedraw; | |
146 | |
147 typedef struct ImagePaintRegion { | |
148 int destx, desty; | |
149 int srcx, srcy; | |
150 int width, height; | |
151 } ImagePaintRegion; | |
152 | |
153 /* ProjectionPaint defines */ | |
154 | |
155 /* approx the number of buckets to have under the brush, | |
156 * used with the brush size to set the ps->buckets_x and ps->buckets_y value. | |
157 *· | |
158 * When 3 - a brush should have ~9 buckets under it at once | |
159 * ...this helps for threading while painting as well as | |
160 * avoiding initializing pixels that wont touch the brush */ | |
161 #define PROJ_BUCKET_BRUSH_DIV 4 | |
162 | |
163 #define PROJ_BUCKET_RECT_MIN 4 | |
164 #define PROJ_BUCKET_RECT_MAX 256 | |
165 | |
166 #define PROJ_BOUNDBOX_DIV 8 | |
167 #define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV) | |
168 | |
169 //#define PROJ_DEBUG_PAINT 1 | |
170 //#define PROJ_DEBUG_NOSEAMBLEED 1 | |
171 //#define PROJ_DEBUG_PRINT_CLIP 1 | |
172 #define PROJ_DEBUG_WINCLIP 1 | |
173 | |
174 /* projectFaceSeamFlags options */ | |
175 //#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing o
r occluded */ | |
176 //#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces da
ta */ | |
177 #define PROJ_FACE_SEAM1 (1<<0) /* If this face has a seam on any of its edges *
/ | |
178 #define PROJ_FACE_SEAM2 (1<<1) | |
179 #define PROJ_FACE_SEAM3 (1<<2) | |
180 #define PROJ_FACE_SEAM4 (1<<3) | |
181 | |
182 #define PROJ_FACE_NOSEAM1 (1<<4) | |
183 #define PROJ_FACE_NOSEAM2 (1<<5) | |
184 #define PROJ_FACE_NOSEAM3 (1<<6) | |
185 #define PROJ_FACE_NOSEAM4 (1<<7) | |
186 | |
187 #define PROJ_SRC_VIEW 1 | |
188 #define PROJ_SRC_IMAGE_CAM 2 | |
189 #define PROJ_SRC_IMAGE_VIEW 3 | |
190 | |
191 #define PROJ_VIEW_DATA_ID "view_data" | |
192 #define PROJ_VIEW_DATA_SIZE (4*4 + 4*4 + 3) /* viewmat + winmat + clipsta + clip
end + is_ortho */ | |
193 | |
194 | |
195 /* a slightly scaled down face is used to get fake 3D location for edge pixels i
n the seams | |
196 * as this number approaches 1.0f the likelihood increases of float precision e
rrors where | |
197 * it is occluded by an adjacent face */ | |
198 #define PROJ_FACE_SCALE_SEAM 0.99f | |
199 | |
200 #define PROJ_BUCKET_NULL 0 | |
201 #define PROJ_BUCKET_INIT (1<<0) | |
202 // #define PROJ_BUCKET_CLONE_INIT (1<<1) | |
203 | |
204 /* used for testing doubles, if a point is on a line etc */ | |
205 #define PROJ_GEOM_TOLERANCE 0.00075f | |
206 | |
207 /* vert flags */ | |
208 #define PROJ_VERT_CULL 1 | |
209 | |
210 #define PI_80_DEG ((M_PI_2 / 9) * 8) | |
211 | |
212 /* This is mainly a convenience struct used so we can keep an array of images we
use | |
213 * Thir imbufs, etc, in 1 array, When using threads this array is copied for eac
h thread | |
214 * because 'partRedrawRect' and 'touch' values would not be thread safe */ | |
215 typedef struct ProjPaintImage { | |
216 Image *ima; | |
217 ImBuf *ibuf; | |
218 ImagePaintPartialRedraw *partRedrawRect; | |
219 void **undoRect; /* only used to build undo tiles after painting */ | |
220 int touch; | |
221 } ProjPaintImage; | |
222 | |
223 /* Main projection painting struct passed to all projection painting functions *
/ | |
224 typedef struct ProjPaintState { | |
225 View3D *v3d; | |
226 RegionView3D *rv3d; | |
227 ARegion *ar; | |
228 Scene *scene; | |
229 int source; /* PROJ_SRC_**** */ | |
230 | |
231 Brush *brush; | |
232 short tool, blend; | |
233 Object *ob; | |
234 /* end similarities with ImagePaintState */ | |
235 ········ | |
236 DerivedMesh *dm; | |
237 int dm_totface; | |
238 int dm_totvert; | |
239 int dm_release; | |
240 ········ | |
241 MVert *dm_mvert; | |
242 MFace *dm_mface; | |
243 MTFace *dm_mtface; | |
244 MTFace *dm_mtface_clone; /* other UV layer, use for cloni
ng between layers */ | |
245 MTFace *dm_mtface_stencil; | |
246 ········ | |
247 /* projection painting only */ | |
248 MemArena *arena_mt[BLENDER_MAX_THREADS];/* for multithreading, the first
item is sometimes used for non threaded cases too */ | |
249 LinkNode **bucketRect; /* screen sized 2D array
, each pixel has a linked list of ProjPixel's */ | |
250 LinkNode **bucketFaces; /* bucketRect aligned ar
ray linkList of faces overlapping each bucket */ | |
251 unsigned char *bucketFlags; /* store
if the bucks have been initialized */ | |
252 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
253 char *faceSeamFlags; /* store info about face
s, if they are initialized etc*/ | |
254 float (*faceSeamUVs)[4][2]; /* expanded UVs for face
s to use as seams */ | |
255 LinkNode **vertFaces; /* Only needed for when
seam_bleed_px is enabled, use to find UV seams */ | |
256 #endif | |
257 char *vertFlags; /* store options
per vert, now only store if the vert is pointing away from the view */ | |
258 int buckets_x; /* The size of t
he bucket grid, the grid span's screenMin/screenMax so you can paint outsize the
screen or with 2 brushes at once */ | |
259 int buckets_y; | |
260 ········ | |
261 ProjPaintImage *projImages; | |
262 ········ | |
263 int image_tot; /* size of projectImages array *
/ | |
264 ········ | |
265 float (*screenCoords)[4]; /* verts projected into floating point s
creen space */ | |
266 ········ | |
267 float screenMin[2]; /* 2D bounds for mesh verts on t
he screen's plane (screenspace) */ | |
268 float screenMax[2];· | |
269 float screen_width; /* Calculated from screenMin & s
creenMax */ | |
270 float screen_height; | |
271 int winx, winy; /* from the carea or from the pr
ojection render */ | |
272 ········ | |
273 /* options for projection painting */ | |
274 int do_layer_clone; | |
275 int do_layer_stencil; | |
276 int do_layer_stencil_inv; | |
277 ········ | |
278 short do_occlude; /* Use raytraced occlusion? - or
therwise will paint right through to the back*/ | |
279 short do_backfacecull; /* ignore faces with normals pointing away, skip
s a lot of raycasts if your normals are correctly flipped */ | |
280 short do_mask_normal; /* mask out pixels based on thei
r normals */ | |
281 float normal_angle; /* what angle to mask at
*/ | |
282 float normal_angle_inner; | |
283 float normal_angle_range; /* difference between normal_ang
le and normal_angle_inner, for easy access */ | |
284 ········ | |
285 short is_ortho; | |
286 short is_airbrush; /* only to avoid
using (ps.brush->flag & BRUSH_AIRBRUSH) */ | |
287 short is_texbrush; /* only to avoid
running */ | |
288 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
289 float seam_bleed_px; | |
290 #endif | |
291 /* clone vars */ | |
292 float cloneOffset[2]; | |
293 ········ | |
294 float projectMat[4][4]; /* Projection matrix, use for getting sc
reen coords */ | |
295 float viewDir[3]; /* View vector, use for do_backf
acecull and for ray casting with an ortho viewport */ | |
296 float viewPos[3]; /* View location in object relat
ive 3D space, so can compare to verts */ | |
297 float clipsta, clipend; | |
298 ········ | |
299 /* reproject vars */ | |
300 Image *reproject_image; | |
301 ImBuf *reproject_ibuf; | |
302 | |
303 | |
304 /* threads */ | |
305 int thread_tot; | |
306 int bucketMin[2]; | |
307 int bucketMax[2]; | |
308 int context_bucket_x, context_bucket_y; /* must lock threads while acces
sing these */ | |
309 } ProjPaintState; | |
310 | |
311 typedef union pixelPointer | |
312 { | |
313 float *f_pt; /* float buffer */ | |
314 unsigned int *uint_pt; /* 2 ways to access a char buffer */ | |
315 unsigned char *ch_pt; | |
316 } PixelPointer; | |
317 | |
318 typedef union pixelStore | |
319 { | |
320 unsigned char ch[4]; | |
321 unsigned int uint; | |
322 float f[4]; | |
323 } PixelStore; | |
324 | |
325 typedef struct ProjPixel { | |
326 float projCoSS[2]; /* the floating point screen projection of this pixel
*/ | |
327 ········ | |
328 /* Only used when the airbrush is disabled. | |
329 * Store the max mask value to avoid painting over an area with a lower
opacity | |
330 * with an advantage that we can avoid touching the pixel at all, if the········ | |
331 * new mask value is lower then mask_max */ | |
332 unsigned short mask_max; | |
333 ········ | |
334 /* for various reasons we may want to mask out painting onto this pixel
*/ | |
335 unsigned short mask; | |
336 ········ | |
337 short x_px, y_px; | |
338 ········ | |
339 PixelStore origColor; | |
340 PixelStore newColor; | |
341 PixelPointer pixel; | |
342 ········ | |
343 short image_index; /* if anyone wants to paint onto more then 32768 imag
es they can bite me */ | |
344 unsigned char bb_cell_index; | |
345 } ProjPixel; | |
346 | |
347 typedef struct ProjPixelClone { | |
348 struct ProjPixel __pp; | |
349 PixelStore clonepx; | |
350 } ProjPixelClone; | |
351 | |
352 /* Finish projection painting structs */ | |
353 | 104 |
354 typedef struct UndoImageTile { | 105 typedef struct UndoImageTile { |
355 struct UndoImageTile *next, *prev; | 106 struct UndoImageTile *next, *prev; |
356 | 107 |
357 » char idname[MAX_ID_NAME];» /* name instead of pointer*/ | 108 » char idname[MAX_ID_NAME]; /* name instead of pointer*/ |
358 | 109 » char ibufname[IB_FILENAME_SIZE]; |
359 » void *rect; | 110 |
| 111 » union { |
| 112 » » float *fp; |
| 113 » » unsigned int *uint; |
| 114 » » void *pt; |
| 115 » } rect; |
| 116 |
| 117 » unsigned short *mask; |
| 118 |
360 int x, y; | 119 int x, y; |
| 120 |
| 121 short source, use_float; |
| 122 char gen_type; |
361 } UndoImageTile; | 123 } UndoImageTile; |
362 | 124 |
| 125 /* this is a static resource for non-globality, |
| 126 * Maybe it should be exposed as part of the |
| 127 * paint operation, but for now just give a public interface */ |
363 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; | 128 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; |
364 | 129 |
| 130 ImagePaintPartialRedraw *get_imapaintpartial(void) |
| 131 { |
| 132 return &imapaintpartial; |
| 133 } |
| 134 |
| 135 void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) |
| 136 { |
| 137 imapaintpartial = *ippr; |
| 138 } |
| 139 |
365 /* UNDO */ | 140 /* UNDO */ |
366 | 141 |
367 static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
restore) | 142 static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
restore) |
368 { | 143 { |
369 /* copy or swap contents of tile->rect and region in ibuf->rect */ | 144 /* copy or swap contents of tile->rect and region in ibuf->rect */ |
370 » IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE, | 145 » IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, |
371 » » tile->y*IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SI
ZE); | 146 » tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_T
ILE_SIZE); |
372 | 147 |
373 » if(ibuf->rect_float) { | 148 » if (ibuf->rect_float) { |
374 » » SWAP(void*, tmpibuf->rect_float, tile->rect); | 149 » » SWAP(float *, tmpibuf->rect_float, tile->rect.fp); |
375 » } else { | 150 » } |
376 » » SWAP(void*, tmpibuf->rect, tile->rect); | 151 » else { |
377 » } | 152 » » SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); |
378 »······· | 153 » } |
379 » if(restore) | 154 »······· |
380 » » IMB_rectcpy(ibuf, tmpibuf, tile->x*IMAPAINT_TILE_SIZE, | 155 » if (restore) |
381 » » » tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IM
APAINT_TILE_SIZE); | 156 » » IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE, |
382 } | 157 » » tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SI
ZE, IMAPAINT_TILE_SIZE); |
383 | 158 } |
384 static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int
x_tile, int y_tile) | 159 |
385 { | 160 void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
gned short **mask) |
386 » ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_IMAGE); | 161 { |
| 162 » ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); |
| 163 » UndoImageTile *tile; |
| 164 » short use_float = ibuf->rect_float ? 1 : 0; |
| 165 |
| 166 » for (tile = lb->first; tile; tile = tile->next) { |
| 167 » » if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == t
ile->gen_type && ima->source == tile->source) { |
| 168 » » » if (tile->use_float == use_float) { |
| 169 » » » » if (strcmp(tile->idname, ima->id.name) == 0 && s
trcmp(tile->ibufname, ibuf->name) == 0) { |
| 170 » » » » » if (mask) { |
| 171 » » » » » » /* allocate mask if requested */ |
| 172 » » » » » » if (!tile->mask) { |
| 173 » » » » » » » tile->mask = MEM_callocN
(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, |
| 174 » » » » » » »
"UndoImageTile.mask"); |
| 175 » » » » » » } |
| 176 |
| 177 » » » » » » *mask = tile->mask; |
| 178 » » » » » } |
| 179 |
| 180 » » » » » return tile->rect.pt; |
| 181 » » » » } |
| 182 » » » } |
| 183 » » } |
| 184 » } |
| 185 »······· |
| 186 » return NULL; |
| 187 } |
| 188 |
| 189 void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
int y_tile) |
| 190 { |
| 191 » ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); |
387 UndoImageTile *tile; | 192 UndoImageTile *tile; |
388 int allocsize; | 193 int allocsize; |
389 | 194 » short use_float = ibuf->rect_float ? 1 : 0; |
390 » for(tile=lb->first; tile; tile=tile->next) | 195 » void *data; |
391 » » if(tile->x == x_tile && tile->y == y_tile && strcmp(tile->idname
, ima->id.name)==0) | 196 |
392 » » » return tile->rect; | 197 » /* check if tile is already pushed */ |
393 »······· | 198 » data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL); |
394 » if (*tmpibuf==NULL) | 199 » if (data) |
395 » » *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE
, 32, IB_rectfloat|IB_rect); | 200 » » return data; |
396 »······· | 201 »······· |
397 » tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); | 202 » if (*tmpibuf == NULL) |
398 » strcpy(tile->idname, ima->id.name); | 203 » » *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE
, 32, IB_rectfloat | IB_rect); |
399 » tile->x= x_tile; | 204 »······· |
400 » tile->y= y_tile; | 205 » tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); |
401 | 206 » BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname)); |
402 » allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4; | 207 » tile->x = x_tile; |
403 » allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char); | 208 » tile->y = y_tile; |
404 » tile->rect= MEM_mapallocN(allocsize, "UndeImageTile.rect"); | 209 |
| 210 » allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; |
| 211 » allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); |
| 212 » tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); |
| 213 |
| 214 » BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname)); |
| 215 |
| 216 » tile->gen_type = ima->gen_type; |
| 217 » tile->source = ima->source; |
| 218 » tile->use_float = use_float; |
405 | 219 |
406 undo_copy_tile(tile, *tmpibuf, ibuf, 0); | 220 undo_copy_tile(tile, *tmpibuf, ibuf, 0); |
407 undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); | 221 undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); |
408 | 222 |
409 BLI_addtail(lb, tile); | 223 BLI_addtail(lb, tile); |
410 ········ | 224 ········ |
411 » return tile->rect; | 225 » return tile->rect.pt; |
412 } | 226 } |
413 | 227 |
414 static void image_undo_restore(bContext *C, ListBase *lb) | 228 void image_undo_remove_masks(void) |
415 { | 229 { |
416 » Main *bmain= CTX_data_main(C); | 230 » ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); |
| 231 » UndoImageTile *tile; |
| 232 |
| 233 » for (tile = lb->first; tile; tile = tile->next) { |
| 234 » » if (tile->mask) { |
| 235 » » » MEM_freeN(tile->mask); |
| 236 » » » tile->mask = NULL; |
| 237 » » } |
| 238 » } |
| 239 } |
| 240 |
| 241 void image_undo_restore(bContext *C, ListBase *lb) |
| 242 { |
| 243 » Main *bmain = CTX_data_main(C); |
417 Image *ima = NULL; | 244 Image *ima = NULL; |
418 ImBuf *ibuf, *tmpibuf; | 245 ImBuf *ibuf, *tmpibuf; |
419 UndoImageTile *tile; | 246 UndoImageTile *tile; |
420 | 247 |
421 » tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, | 248 » tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, |
422 » » » » » » » IB_rectfloat|IB_rect); | 249 » IB_rectfloat | IB_rect); |
423 » | 250 |
424 » for(tile=lb->first; tile; tile=tile->next) { | 251 » for (tile = lb->first; tile; tile = tile->next) { |
| 252 » » short use_float; |
| 253 |
425 /* find image based on name, pointer becomes invalid with global
undo */ | 254 /* find image based on name, pointer becomes invalid with global
undo */ |
426 » » if(ima && strcmp(tile->idname, ima->id.name)==0); | 255 » » if (ima && strcmp(tile->idname, ima->id.name) == 0) { |
| 256 » » » /* ima is valid */ |
| 257 » » } |
427 else { | 258 else { |
428 » » » for(ima=bmain->image.first; ima; ima=ima->id.next) | 259 » » » ima = BLI_findstring(&bmain->image, tile->idname, offset
of(ID, name)); |
429 » » » » if(strcmp(tile->idname, ima->id.name)==0) | 260 » » } |
430 » » » » » break; | 261 |
431 » » } | 262 » » ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); |
432 | 263 |
433 » » ibuf= BKE_image_get_ibuf(ima, NULL); | 264 » » if (ima && ibuf && strcmp(tile->ibufname, ibuf->name) != 0) { |
434 | 265 » » » /* current ImBuf filename was changed, probably current
frame |
435 » » if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) | 266 » » » * was changed when paiting on image sequence, rather th
an storing |
| 267 » » » * full image user (which isn't so obvious, btw) try to
find ImBuf with |
| 268 » » » * matched file name in list of already loaded images */ |
| 269 |
| 270 » » » BKE_image_release_ibuf(ima, ibuf, NULL); |
| 271 |
| 272 » » » ibuf = BLI_findstring(&ima->ibufs, tile->ibufname, offse
tof(ImBuf, name)); |
| 273 » » } |
| 274 |
| 275 » » if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { |
| 276 » » » BKE_image_release_ibuf(ima, ibuf, NULL); |
436 continue; | 277 continue; |
| 278 } |
| 279 |
| 280 if (ima->gen_type != tile->gen_type || ima->source != tile->sour
ce) { |
| 281 BKE_image_release_ibuf(ima, ibuf, NULL); |
| 282 continue; |
| 283 } |
| 284 |
| 285 use_float = ibuf->rect_float ? 1 : 0; |
| 286 |
| 287 if (use_float != tile->use_float) { |
| 288 BKE_image_release_ibuf(ima, ibuf, NULL); |
| 289 continue; |
| 290 } |
437 | 291 |
438 undo_copy_tile(tile, tmpibuf, ibuf, 1); | 292 undo_copy_tile(tile, tmpibuf, ibuf, 1); |
439 | 293 |
440 GPU_free_image(ima); /* force OpenGL reload */ | 294 GPU_free_image(ima); /* force OpenGL reload */ |
441 » » if(ibuf->rect_float) | 295 » » if (ibuf->rect_float) |
442 ibuf->userflags |= IB_RECT_INVALID; /* force recreate of
char rect */ | 296 ibuf->userflags |= IB_RECT_INVALID; /* force recreate of
char rect */ |
443 » » if(ibuf->mipmap[0]) | 297 » » if (ibuf->mipmap[0]) |
444 » » » ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap re
creatiom */ | 298 » » » ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap r
ecreatiom */ |
445 | 299 » » ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; |
| 300 |
| 301 » » BKE_image_release_ibuf(ima, ibuf, NULL); |
446 } | 302 } |
447 | 303 |
448 IMB_freeImBuf(tmpibuf); | 304 IMB_freeImBuf(tmpibuf); |
449 } | 305 } |
450 | 306 |
451 static void image_undo_free(ListBase *lb) | 307 void image_undo_free(ListBase *lb) |
452 { | 308 { |
453 UndoImageTile *tile; | 309 UndoImageTile *tile; |
454 | 310 |
455 for(tile=lb->first; tile; tile=tile->next) | 311 for (tile = lb->first; tile; tile = tile->next) |
456 MEM_freeN(tile->rect); | 312 MEM_freeN(tile->rect.pt); |
457 } | |
458 | |
459 /* fast projection bucket array lookup, use the safe version for bound checking
*/ | |
460 static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[
2]) | |
461 { | |
462 /* If we were not dealing with screenspace 2D coords we could simple do.
.. | |
463 * ps->bucketRect[x + (y*ps->buckets_y)] */ | |
464 ········ | |
465 /* please explain? | |
466 * projCoSS[0] - ps->screenMin[0] : zero origin | |
467 * ... / ps->screen_width : range from 0.0
to 1.0 | |
468 * ... * ps->buckets_x : use as a bucket index | |
469 * | |
470 * Second multiplication does similar but for vertical offset | |
471 */ | |
472 return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_wid
th) * ps->buckets_x)) +· | |
473 ( ( (int)(((projCoSS[1] - ps->screenMin[1]) / ps->s
creen_height) * ps->buckets_y)) * ps->buckets_x); | |
474 } | |
475 | |
476 static int project_bucket_offset_safe(const ProjPaintState *ps, const float proj
CoSS[2]) | |
477 { | |
478 int bucket_index = project_bucket_offset(ps, projCoSS); | |
479 ········ | |
480 if (bucket_index < 0 || bucket_index >= ps->buckets_x*ps->buckets_y) {·· | |
481 return -1; | |
482 } | |
483 else { | |
484 return bucket_index; | |
485 } | |
486 } | |
487 | |
488 /* still use 2D X,Y space but this works for verts transformed by a perspective
matrix, using their 4th component as a weight */ | |
489 static void barycentric_weights_v2_persp(float v1[4], float v2[4], float v3[4],
float co[2], float w[3]) | |
490 { | |
491 float wtot_inv, wtot; | |
492 | |
493 w[0] = area_tri_signed_v2(v2, v3, co) / v1[3]; | |
494 w[1] = area_tri_signed_v2(v3, v1, co) / v2[3]; | |
495 w[2] = area_tri_signed_v2(v1, v2, co) / v3[3]; | |
496 wtot = w[0]+w[1]+w[2]; | |
497 | |
498 if (wtot != 0.0f) { | |
499 wtot_inv = 1.0f/wtot; | |
500 | |
501 w[0] = w[0]*wtot_inv; | |
502 w[1] = w[1]*wtot_inv; | |
503 w[2] = w[2]*wtot_inv; | |
504 } | |
505 else /* dummy values for zero area face */ | |
506 w[0] = w[1] = w[2] = 1.0f/3.0f; | |
507 } | |
508 | |
509 static float VecZDepthOrtho(float pt[2], float v1[3], float v2[3], float v3[3],
float w[3]) | |
510 { | |
511 barycentric_weights_v2(v1, v2, v3, pt, w); | |
512 return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]); | |
513 } | |
514 | |
515 static float VecZDepthPersp(float pt[2], float v1[3], float v2[3], float v3[3],
float w[3]) | |
516 { | |
517 float wtot_inv, wtot; | |
518 float w_tmp[3]; | |
519 | |
520 barycentric_weights_v2_persp(v1, v2, v3, pt, w); | |
521 /* for the depth we need the weights to match what | |
522 * barycentric_weights_v2 would return, in this case its easiest just to | |
523 * undo the 4th axis division and make it unit-sum | |
524 * | |
525 * don't call barycentric_weights_v2() becaue our callers expect 'w' | |
526 * to be weighted from the perspective */ | |
527 w_tmp[0]= w[0] * v1[3]; | |
528 w_tmp[1]= w[1] * v2[3]; | |
529 w_tmp[2]= w[2] * v3[3]; | |
530 | |
531 wtot = w_tmp[0]+w_tmp[1]+w_tmp[2]; | |
532 | |
533 if (wtot != 0.0f) { | |
534 wtot_inv = 1.0f/wtot; | |
535 | |
536 w_tmp[0] = w_tmp[0]*wtot_inv; | |
537 w_tmp[1] = w_tmp[1]*wtot_inv; | |
538 w_tmp[2] = w_tmp[2]*wtot_inv; | |
539 } | |
540 else /* dummy values for zero area face */ | |
541 w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f/3.0f; | |
542 /* done mimicing barycentric_weights_v2() */ | |
543 | |
544 return (v1[2]*w_tmp[0]) + (v2[2]*w_tmp[1]) + (v3[2]*w_tmp[2]); | |
545 } | |
546 | |
547 | |
548 /* Return the top-most face index that the screen space coord 'pt' touches (or -
1) */ | |
549 static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w
[3], int *side) | |
550 { | |
551 LinkNode *node; | |
552 float w_tmp[3]; | |
553 float *v1, *v2, *v3, *v4; | |
554 int bucket_index; | |
555 int face_index; | |
556 int best_side = -1; | |
557 int best_face_index = -1; | |
558 float z_depth_best = FLT_MAX, z_depth; | |
559 MFace *mf; | |
560 ········ | |
561 bucket_index = project_bucket_offset_safe(ps, pt); | |
562 if (bucket_index==-1) | |
563 return -1; | |
564 ········ | |
565 ········ | |
566 ········ | |
567 /* we could return 0 for 1 face buckets, as long as this function assume
s | |
568 * that the point its testing is only every originated from an existing
face */ | |
569 ········ | |
570 for (node= ps->bucketFaces[bucket_index]; node; node= node->next) { | |
571 face_index = GET_INT_FROM_POINTER(node->link); | |
572 mf= ps->dm_mface + face_index; | |
573 ················ | |
574 v1= ps->screenCoords[mf->v1]; | |
575 v2= ps->screenCoords[mf->v2]; | |
576 v3= ps->screenCoords[mf->v3]; | |
577 ················ | |
578 if (isect_point_tri_v2(pt, v1, v2, v3)) { | |
579 if (ps->is_ortho) z_depth= VecZDepthOrtho(pt, v1,
v2, v3, w_tmp); | |
580 else z_depth= VecZDepthPersp(
pt, v1, v2, v3, w_tmp); | |
581 ························ | |
582 if (z_depth < z_depth_best) { | |
583 best_face_index = face_index; | |
584 best_side = 0; | |
585 z_depth_best = z_depth; | |
586 VECCOPY(w, w_tmp); | |
587 } | |
588 } | |
589 else if (mf->v4) { | |
590 v4= ps->screenCoords[mf->v4]; | |
591 ························ | |
592 if (isect_point_tri_v2(pt, v1, v3, v4)) { | |
593 if (ps->is_ortho) z_depth= VecZDepthOrtho(
pt, v1, v3, v4, w_tmp); | |
594 else z_depth= VecZDep
thPersp(pt, v1, v3, v4, w_tmp); | |
595 | |
596 if (z_depth < z_depth_best) { | |
597 best_face_index = face_index; | |
598 best_side= 1; | |
599 z_depth_best = z_depth; | |
600 VECCOPY(w, w_tmp); | |
601 } | |
602 } | |
603 } | |
604 } | |
605 ········ | |
606 *side = best_side; | |
607 return best_face_index; /* will be -1 or a valid face */ | |
608 } | |
609 | |
610 /* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 r
ange */ | |
611 static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x,
float *y) | |
612 { | |
613 /* use */ | |
614 *x = (float)fmodf(uv[0], 1.0f); | |
615 *y = (float)fmodf(uv[1], 1.0f); | |
616 ········ | |
617 if (*x < 0.0f) *x += 1.0f; | |
618 if (*y < 0.0f) *y += 1.0f; | |
619 ········ | |
620 *x = *x * ibuf_x - 0.5f; | |
621 *y = *y * ibuf_y - 0.5f; | |
622 } | |
623 | |
624 /* Set the top-most face color that the screen space coord 'pt' touches (or retu
rn 0 if none touch) */ | |
625 static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
*rgba_fp, unsigned char *rgba, const int interp) | |
626 { | |
627 float w[3], uv[2]; | |
628 int side; | |
629 int face_index; | |
630 MTFace *tf; | |
631 ImBuf *ibuf; | |
632 int xi, yi; | |
633 ········ | |
634 ········ | |
635 face_index = project_paint_PickFace(ps, pt, w, &side); | |
636 ········ | |
637 if (face_index == -1) | |
638 return 0; | |
639 ········ | |
640 tf = ps->dm_mtface + face_index; | |
641 ········ | |
642 if (side == 0) { | |
643 interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); | |
644 } | |
645 else { /* QUAD */ | |
646 interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); | |
647 } | |
648 ········ | |
649 ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before gett
ing here */ | |
650 if (!ibuf) return 0; | |
651 ········ | |
652 if (interp) { | |
653 float x, y; | |
654 uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y); | |
655 ················ | |
656 if (ibuf->rect_float) { | |
657 if (rgba_fp) { | |
658 bilinear_interpolation_color_wrap(ibuf, NULL, rg
ba_fp, x, y); | |
659 } | |
660 else { | |
661 float rgba_tmp_f[4]; | |
662 bilinear_interpolation_color_wrap(ibuf, NULL, rg
ba_tmp_f, x, y); | |
663 IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f); | |
664 } | |
665 } | |
666 else { | |
667 if (rgba) { | |
668 bilinear_interpolation_color_wrap(ibuf, rgba, NU
LL, x, y); | |
669 } | |
670 else { | |
671 unsigned char rgba_tmp[4]; | |
672 bilinear_interpolation_color_wrap(ibuf, rgba_tmp
, NULL, x, y); | |
673 IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp); | |
674 } | |
675 } | |
676 } | |
677 else { | |
678 //xi = (int)((uv[0]*ibuf->x) + 0.5f); | |
679 //yi = (int)((uv[1]*ibuf->y) + 0.5f); | |
680 //if (xi<0 || xi>=ibuf->x || yi<0 || yi>=ibuf->y) return 0; | |
681 ················ | |
682 /* wrap */ | |
683 xi = ((int)(uv[0]*ibuf->x)) % ibuf->x; | |
684 if (xi<0) xi += ibuf->x; | |
685 yi = ((int)(uv[1]*ibuf->y)) % ibuf->y; | |
686 if (yi<0) yi += ibuf->y; | |
687 ················ | |
688 ················ | |
689 if (rgba) { | |
690 if (ibuf->rect_float) { | |
691 float *rgba_tmp_fp = ibuf->rect_float + (xi + yi
* ibuf->x * 4); | |
692 IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp); | |
693 } | |
694 else { | |
695 *((unsigned int *)rgba) = *(unsigned int *)(((ch
ar *)ibuf->rect) + ((xi + yi * ibuf->x) * 4)); | |
696 } | |
697 } | |
698 ················ | |
699 if (rgba_fp) { | |
700 if (ibuf->rect_float) { | |
701 QUATCOPY(rgba_fp, ((float *)ibuf->rect_float + (
(xi + yi * ibuf->x) * 4))); | |
702 } | |
703 else { | |
704 char *tmp_ch= ((char *)ibuf->rect) + ((xi + yi *
ibuf->x) * 4); | |
705 IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch); | |
706 } | |
707 } | |
708 } | |
709 return 1; | |
710 } | |
711 | |
712 /* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace o
cclusuion test) | |
713 * return... | |
714 * 0 : no occlusion | |
715 * -1 : no occlusion but 2D intersection is true (avoid testing the other half
of a quad) | |
716 * 1 : occluded | |
717 2 : occluded with w[3] weights set (need to know in some cases) */ | |
718 | |
719 static int project_paint_occlude_ptv(float pt[3], float v1[3], float v2[3], floa
t v3[3], float w[3], int is_ortho) | |
720 { | |
721 /* if all are behind us, return false */ | |
722 if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2]) | |
723 return 0; | |
724 ················ | |
725 /* do a 2D point in try intersection */ | |
726 if (!isect_point_tri_v2(pt, v1, v2, v3)) | |
727 return 0; /* we know there is */ | |
728 ········ | |
729 | |
730 /* From here on we know there IS an intersection */ | |
731 /* if ALL of the verts are infront of us then we know it intersects ? */ | |
732 if(v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) { | |
733 return 1; | |
734 } | |
735 else { | |
736 /* we intersect? - find the exact depth at the point of intersec
tion */ | |
737 /* Is this point is occluded by another face? */ | |
738 if (is_ortho) { | |
739 if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2; | |
740 } | |
741 else { | |
742 if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2; | |
743 } | |
744 } | |
745 return -1; | |
746 } | |
747 | |
748 | |
749 static int project_paint_occlude_ptv_clip( | |
750 const ProjPaintState *ps, const MFace *mf, | |
751 float pt[3], float v1[3], float v2[3], float v3[3], | |
752 const int side ) | |
753 { | |
754 float w[3], wco[3]; | |
755 int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho); | |
756 | |
757 if (ret <= 0) | |
758 return ret; | |
759 | |
760 if (ret==1) { /* weights not calculated */ | |
761 if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w
); | |
762 else barycentric_weights_v2_persp(v1,
v2, v3, pt, w); | |
763 } | |
764 | |
765 /* Test if we're in the clipped area, */ | |
766 if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mv
ert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); | |
767 else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mv
ert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); | |
768 ········ | |
769 if(!ED_view3d_test_clipping(ps->rv3d, wco, 1)) { | |
770 return 1; | |
771 } | |
772 ········ | |
773 return -1; | |
774 } | |
775 | |
776 | |
777 /* Check if a screenspace location is occluded by any other faces | |
778 * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be use
d for comparison | |
779 * and dosn't need to be correct in relation to X and Y coords (this is the case
in perspective view) */ | |
780 static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *buc
ketFace, const int orig_face, float pixelScreenCo[4]) | |
781 { | |
782 MFace *mf; | |
783 int face_index; | |
784 int isect_ret; | |
785 float w[3]; /* not needed when clipping */ | |
786 const short do_clip= ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; | |
787 ········ | |
788 /* we could return 0 for 1 face buckets, as long as this function assume
s | |
789 * that the point its testing is only every originated from an existing
face */ | |
790 | |
791 for (; bucketFace; bucketFace = bucketFace->next) { | |
792 face_index = GET_INT_FROM_POINTER(bucketFace->link); | |
793 | |
794 if (orig_face != face_index) { | |
795 mf = ps->dm_mface + face_index; | |
796 if(do_clip) | |
797 isect_ret = project_paint_occlude_ptv_clip(ps, m
f, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screen
Coords[mf->v3], 0); | |
798 else | |
799 isect_ret = project_paint_occlude_ptv(pixelScree
nCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3
], w, ps->is_ortho); | |
800 | |
801 /* Note, if isect_ret==-1 then we dont want to test the
other side of the quad */ | |
802 if (isect_ret==0 && mf->v4) { | |
803 if(do_clip) | |
804 isect_ret = project_paint_occlude_ptv_cl
ip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps
->screenCoords[mf->v4], 1); | |
805 else | |
806 isect_ret = project_paint_occlude_ptv(pi
xelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoord
s[mf->v4], w, ps->is_ortho); | |
807 } | |
808 if (isect_ret>=1) { | |
809 /* TODO - we may want to cache the first hit, | |
810 * it is not possible to swap the face order in
the list anymore */ | |
811 return 1; | |
812 } | |
813 } | |
814 } | |
815 return 0; | |
816 } | |
817 | |
818 /* basic line intersection, could move to math_geom.c, 2 points with a horiz lin
e | |
819 * 1 for an intersection, 2 if the first point is aligned, 3 if the second point
is aligned */ | |
820 #define ISECT_TRUE 1 | |
821 #define ISECT_TRUE_P1 2 | |
822 #define ISECT_TRUE_P2 3 | |
823 static int line_isect_y(const float p1[2], const float p2[2], const float y_leve
l, float *x_isect) | |
824 { | |
825 float y_diff; | |
826 ········ | |
827 if (y_level==p1[1]) { /* are we touching the first point? - no interpola
tion needed */ | |
828 *x_isect = p1[0]; | |
829 return ISECT_TRUE_P1; | |
830 } | |
831 if (y_level==p2[1]) { /* are we touching the second point? - no interpol
ation needed */ | |
832 *x_isect = p2[0]; | |
833 return ISECT_TRUE_P2; | |
834 } | |
835 ········ | |
836 y_diff= fabsf(p1[1]-p2[1]); /* yuck, horizontal line, we cant do much he
re */ | |
837 ········ | |
838 if (y_diff < 0.000001f) { | |
839 *x_isect = (p1[0]+p2[0]) * 0.5f; | |
840 return ISECT_TRUE;·············· | |
841 } | |
842 ········ | |
843 if (p1[1] > y_level && p2[1] < y_level) { | |
844 *x_isect = (p2[0]*(p1[1]-y_level) + p1[0]*(y_level-p2[1])) / y_d
iff; /*(p1[1]-p2[1]);*/ | |
845 return ISECT_TRUE; | |
846 } | |
847 else if (p1[1] < y_level && p2[1] > y_level) { | |
848 *x_isect = (p2[0]*(y_level-p1[1]) + p1[0]*(p2[1]-y_level)) / y_d
iff; /*(p2[1]-p1[1]);*/ | |
849 return ISECT_TRUE; | |
850 } | |
851 else { | |
852 return 0; | |
853 } | |
854 } | |
855 | |
856 static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
l, float *y_isect) | |
857 { | |
858 float x_diff; | |
859 ········ | |
860 if (x_level==p1[0]) { /* are we touching the first point? - no interpola
tion needed */ | |
861 *y_isect = p1[1]; | |
862 return ISECT_TRUE_P1; | |
863 } | |
864 if (x_level==p2[0]) { /* are we touching the second point? - no interpol
ation needed */ | |
865 *y_isect = p2[1]; | |
866 return ISECT_TRUE_P2; | |
867 } | |
868 ········ | |
869 x_diff= fabsf(p1[0]-p2[0]); /* yuck, horizontal line, we cant do much he
re */ | |
870 ········ | |
871 if (x_diff < 0.000001f) { /* yuck, vertical line, we cant do much here *
/ | |
872 *y_isect = (p1[0]+p2[0]) * 0.5f; | |
873 return ISECT_TRUE;·············· | |
874 } | |
875 ········ | |
876 if (p1[0] > x_level && p2[0] < x_level) { | |
877 *y_isect = (p2[1]*(p1[0]-x_level) + p1[1]*(x_level-p2[0])) / x_d
iff; /*(p1[0]-p2[0]);*/ | |
878 return ISECT_TRUE; | |
879 } | |
880 else if (p1[0] < x_level && p2[0] > x_level) { | |
881 *y_isect = (p2[1]*(x_level-p1[0]) + p1[1]*(p2[0]-x_level)) / x_d
iff; /*(p2[0]-p1[0]);*/ | |
882 return ISECT_TRUE; | |
883 } | |
884 else { | |
885 return 0; | |
886 } | |
887 } | |
888 | |
889 /* simple func use for comparing UV locations to check if there are seams. | |
890 * Its possible this gives incorrect results, when the UVs for 1 face go into th
e next· | |
891 * tile, but do not do this for the adjacent face, it could return a false posit
ive. | |
892 * This is so unlikely that Id not worry about it. */ | |
893 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
894 static int cmp_uv(const float vec2a[2], const float vec2b[2]) | |
895 { | |
896 /* if the UV's are not between 0.0 and 1.0 */ | |
897 float xa = (float)fmodf(vec2a[0], 1.0f); | |
898 float ya = (float)fmodf(vec2a[1], 1.0f); | |
899 ········ | |
900 float xb = (float)fmodf(vec2b[0], 1.0f); | |
901 float yb = (float)fmodf(vec2b[1], 1.0f);········ | |
902 ········ | |
903 if (xa < 0.0f) xa += 1.0f; | |
904 if (ya < 0.0f) ya += 1.0f; | |
905 ········ | |
906 if (xb < 0.0f) xb += 1.0f; | |
907 if (yb < 0.0f) yb += 1.0f; | |
908 ········ | |
909 return ((fabsf(xa-xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya-yb) < PROJ_GEO
M_TOLERANCE)) ? 1:0; | |
910 } | |
911 #endif | |
912 | |
913 /* set min_px and max_px to the image space bounds of the UV coords· | |
914 * return zero if there is no area in the returned rectangle */ | |
915 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
916 static int pixel_bounds_uv( | |
917 const float uv1[2], const float uv2[2], const float uv3[2], cons
t float uv4[2], | |
918 rcti *bounds_px, | |
919 const int ibuf_x, const int ibuf_y, | |
920 int is_quad | |
921 ) { | |
922 float min_uv[2], max_uv[2]; /* UV bounds */ | |
923 ········ | |
924 INIT_MINMAX2(min_uv, max_uv); | |
925 ········ | |
926 DO_MINMAX2(uv1, min_uv, max_uv); | |
927 DO_MINMAX2(uv2, min_uv, max_uv); | |
928 DO_MINMAX2(uv3, min_uv, max_uv); | |
929 if (is_quad) | |
930 DO_MINMAX2(uv4, min_uv, max_uv); | |
931 ········ | |
932 bounds_px->xmin = (int)(ibuf_x * min_uv[0]); | |
933 bounds_px->ymin = (int)(ibuf_y * min_uv[1]); | |
934 ········ | |
935 bounds_px->xmax = (int)(ibuf_x * max_uv[0]) +1; | |
936 bounds_px->ymax = (int)(ibuf_y * max_uv[1]) +1; | |
937 ········ | |
938 /*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*
/ | |
939 ········ | |
940 /* face uses no UV area when quantized to pixels? */ | |
941 return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_
px->ymax) ? 0 : 1; | |
942 } | |
943 #endif | |
944 | |
945 static int pixel_bounds_array(float (* uv)[2], rcti *bounds_px, const int ibuf_x
, const int ibuf_y, int tot) | |
946 { | |
947 float min_uv[2], max_uv[2]; /* UV bounds */ | |
948 ········ | |
949 if (tot==0) { | |
950 return 0; | |
951 } | |
952 ········ | |
953 INIT_MINMAX2(min_uv, max_uv); | |
954 ········ | |
955 while (tot--) { | |
956 DO_MINMAX2((*uv), min_uv, max_uv); | |
957 uv++; | |
958 } | |
959 ········ | |
960 bounds_px->xmin = (int)(ibuf_x * min_uv[0]); | |
961 bounds_px->ymin = (int)(ibuf_y * min_uv[1]); | |
962 ········ | |
963 bounds_px->xmax = (int)(ibuf_x * max_uv[0]) +1; | |
964 bounds_px->ymax = (int)(ibuf_y * max_uv[1]) +1; | |
965 ········ | |
966 /*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*
/ | |
967 ········ | |
968 /* face uses no UV area when quantized to pixels? */ | |
969 return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_
px->ymax) ? 0 : 1; | |
970 } | |
971 | |
972 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
973 | |
974 /* This function returns 1 if this face has a seam along the 2 face-vert indices | |
975 * 'orig_i1_fidx' and 'orig_i2_fidx' */ | |
976 static int check_seam(const ProjPaintState *ps, const int orig_face, const int o
rig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx) | |
977 { | |
978 LinkNode *node; | |
979 int face_index; | |
980 unsigned int i1, i2; | |
981 int i1_fidx = -1, i2_fidx = -1; /* index in face */ | |
982 MFace *mf; | |
983 MTFace *tf; | |
984 const MFace *orig_mf = ps->dm_mface + orig_face;·· | |
985 const MTFace *orig_tf = ps->dm_mtface + orig_face; | |
986 ········ | |
987 /* vert indices from face vert order indices */ | |
988 i1 = (*(&orig_mf->v1 + orig_i1_fidx)); | |
989 i2 = (*(&orig_mf->v1 + orig_i2_fidx)); | |
990 ········ | |
991 for (node = ps->vertFaces[i1]; node; node = node->next) { | |
992 face_index = GET_INT_FROM_POINTER(node->link); | |
993 | |
994 if (face_index != orig_face) { | |
995 mf = ps->dm_mface + face_index; | |
996 /* could check if the 2 faces images match here, | |
997 * but then there wouldn't be a way to return the opposi
te face's info */ | |
998 ························ | |
999 ························ | |
1000 /* We need to know the order of the verts in the adjacen
t face· | |
1001 * set the i1_fidx and i2_fidx to (0,1,2,3) */ | |
1002 if (mf->v1==i1) i1_fidx
= 0; | |
1003 else if (mf->v2==i1) i1_fidx = 1; | |
1004 else if (mf->v3==i1) i1_fidx = 2; | |
1005 else if (mf->v4 && mf->v4==i1) i1_fidx = 3; | |
1006 ························ | |
1007 if (mf->v1==i2) i2_fidx
= 0; | |
1008 else if (mf->v2==i2) i2_fidx = 1; | |
1009 else if (mf->v3==i2) i2_fidx = 2; | |
1010 else if (mf->v4 && mf->v4==i2) i2_fidx = 3; | |
1011 ························ | |
1012 /* Only need to check if 'i2_fidx' is valid because we k
now i1_fidx is the same vert on both faces */ | |
1013 if (i2_fidx != -1) { | |
1014 /* This IS an adjacent face!, now lets check if
the UVs are ok */ | |
1015 tf = ps->dm_mtface + face_index; | |
1016 ································ | |
1017 /* set up the other face */ | |
1018 *other_face = face_index; | |
1019 *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_
fidx; | |
1020 ································ | |
1021 /* first test if they have the same image */ | |
1022 if ( (orig_tf->tpage == tf->tpage) && | |
1023 cmp_uv(orig_tf->uv[orig_i1_fidx]
, tf->uv[i1_fidx]) && | |
1024 cmp_uv(orig_tf->uv[orig_i2_fidx]
, tf->uv[i2_fidx]) ) | |
1025 { | |
1026 // printf("SEAM (NONE)\n"); | |
1027 return 0; | |
1028 ········································ | |
1029 } | |
1030 else { | |
1031 // printf("SEAM (UV GAP)\n"); | |
1032 return 1; | |
1033 } | |
1034 } | |
1035 } | |
1036 } | |
1037 // printf("SEAM (NO FACE)\n"); | |
1038 *other_face = -1; | |
1039 return 1; | |
1040 } | |
1041 | |
1042 /* Calculate outset UV's, this is not the same as simply scaling the UVs, | |
1043 * since the outset coords are a margin that keep an even distance from the orig
inal UV's, | |
1044 * note that the image aspect is taken into account */ | |
1045 static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
oat scaler, const int ibuf_x, const int ibuf_y, const int is_quad) | |
1046 { | |
1047 float a1, a2, a3, a4=0.0f; | |
1048 float puv[4][2]; /* pixelspace uv's */ | |
1049 float no1[2], no2[2], no3[2], no4[2]; /* normals */ | |
1050 float dir1[2], dir2[2], dir3[2], dir4[2]; | |
1051 float ibuf_inv[2]; | |
1052 | |
1053 ibuf_inv[0]= 1.0f / (float)ibuf_x; | |
1054 ibuf_inv[1]= 1.0f / (float)ibuf_y; | |
1055 | |
1056 /* make UV's in pixel space so we can */ | |
1057 puv[0][0] = orig_uv[0][0] * ibuf_x; | |
1058 puv[0][1] = orig_uv[0][1] * ibuf_y; | |
1059 ········ | |
1060 puv[1][0] = orig_uv[1][0] * ibuf_x; | |
1061 puv[1][1] = orig_uv[1][1] * ibuf_y; | |
1062 ········ | |
1063 puv[2][0] = orig_uv[2][0] * ibuf_x; | |
1064 puv[2][1] = orig_uv[2][1] * ibuf_y; | |
1065 ········ | |
1066 if (is_quad) { | |
1067 puv[3][0] = orig_uv[3][0] * ibuf_x; | |
1068 puv[3][1] = orig_uv[3][1] * ibuf_y; | |
1069 } | |
1070 ········ | |
1071 /* face edge directions */ | |
1072 sub_v2_v2v2(dir1, puv[1], puv[0]); | |
1073 sub_v2_v2v2(dir2, puv[2], puv[1]); | |
1074 normalize_v2(dir1); | |
1075 normalize_v2(dir2); | |
1076 ········ | |
1077 if (is_quad) { | |
1078 sub_v2_v2v2(dir3, puv[3], puv[2]); | |
1079 sub_v2_v2v2(dir4, puv[0], puv[3]); | |
1080 normalize_v2(dir3); | |
1081 normalize_v2(dir4); | |
1082 } | |
1083 else { | |
1084 sub_v2_v2v2(dir3, puv[0], puv[2]); | |
1085 normalize_v2(dir3); | |
1086 } | |
1087 | |
1088 /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f) | |
1089 * This is incorrect. Its already given radians but without it wont work
. | |
1090 * need to look into a fix - campbell */ | |
1091 if (is_quad) { | |
1092 a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((f
loat)M_PI/180.0f)); | |
1093 a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((f
loat)M_PI/180.0f)); | |
1094 a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((f
loat)M_PI/180.0f)); | |
1095 a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((f
loat)M_PI/180.0f)); | |
1096 } | |
1097 else { | |
1098 a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((f
loat)M_PI/180.0f)); | |
1099 a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((f
loat)M_PI/180.0f)); | |
1100 a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((f
loat)M_PI/180.0f)); | |
1101 } | |
1102 ········ | |
1103 if (is_quad) { | |
1104 sub_v2_v2v2(no1, dir4, dir1); | |
1105 sub_v2_v2v2(no2, dir1, dir2); | |
1106 sub_v2_v2v2(no3, dir2, dir3); | |
1107 sub_v2_v2v2(no4, dir3, dir4); | |
1108 normalize_v2(no1); | |
1109 normalize_v2(no2); | |
1110 normalize_v2(no3); | |
1111 normalize_v2(no4); | |
1112 mul_v2_fl(no1, a1*scaler); | |
1113 mul_v2_fl(no2, a2*scaler); | |
1114 mul_v2_fl(no3, a3*scaler); | |
1115 mul_v2_fl(no4, a4*scaler); | |
1116 add_v2_v2v2(outset_uv[0], puv[0], no1); | |
1117 add_v2_v2v2(outset_uv[1], puv[1], no2); | |
1118 add_v2_v2v2(outset_uv[2], puv[2], no3); | |
1119 add_v2_v2v2(outset_uv[3], puv[3], no4); | |
1120 mul_v2_v2(outset_uv[0], ibuf_inv); | |
1121 mul_v2_v2(outset_uv[1], ibuf_inv); | |
1122 mul_v2_v2(outset_uv[2], ibuf_inv); | |
1123 mul_v2_v2(outset_uv[3], ibuf_inv); | |
1124 } | |
1125 else { | |
1126 sub_v2_v2v2(no1, dir3, dir1); | |
1127 sub_v2_v2v2(no2, dir1, dir2); | |
1128 sub_v2_v2v2(no3, dir2, dir3); | |
1129 normalize_v2(no1); | |
1130 normalize_v2(no2); | |
1131 normalize_v2(no3); | |
1132 mul_v2_fl(no1, a1*scaler); | |
1133 mul_v2_fl(no2, a2*scaler); | |
1134 mul_v2_fl(no3, a3*scaler); | |
1135 add_v2_v2v2(outset_uv[0], puv[0], no1); | |
1136 add_v2_v2v2(outset_uv[1], puv[1], no2); | |
1137 add_v2_v2v2(outset_uv[2], puv[2], no3); | |
1138 | |
1139 mul_v2_v2(outset_uv[0], ibuf_inv); | |
1140 mul_v2_v2(outset_uv[1], ibuf_inv); | |
1141 mul_v2_v2(outset_uv[2], ibuf_inv); | |
1142 } | |
1143 } | |
1144 | |
1145 /*· | |
1146 * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are
PROJ_FACE_NOSEAM1 to 4 | |
1147 * 1<<i - where i is (0-3)· | |
1148 *· | |
1149 * If we're multithreadng, make sure threads are locked when this is called | |
1150 */ | |
1151 static void project_face_seams_init(const ProjPaintState *ps, const int face_ind
ex, const int is_quad) | |
1152 { | |
1153 int other_face, other_fidx; /* vars for the other face, we also set its
flag */ | |
1154 int fidx1 = is_quad ? 3 : 2; | |
1155 int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2
) -> (1,2,0) for a tri */ | |
1156 ········ | |
1157 do { | |
1158 if ((ps->faceSeamFlags[face_index] & (1<<fidx1|16<<fidx1)) == 0)
{ | |
1159 if (check_seam(ps, face_index, fidx1, fidx2, &other_face
, &other_fidx)) { | |
1160 ps->faceSeamFlags[face_index] |= 1<<fidx1; | |
1161 if (other_face != -1) | |
1162 ps->faceSeamFlags[other_face] |= 1<<othe
r_fidx; | |
1163 } | |
1164 else { | |
1165 ps->faceSeamFlags[face_index] |= 16<<fidx1; | |
1166 if (other_face != -1) | |
1167 ps->faceSeamFlags[other_face] |= 16<<oth
er_fidx; /* second 4 bits for disabled */ | |
1168 } | |
1169 } | |
1170 ················ | |
1171 fidx2 = fidx1; | |
1172 } while (fidx1--); | |
1173 } | |
1174 #endif // PROJ_DEBUG_NOSEAMBLEED | |
1175 | |
1176 | |
1177 /* TODO - move to math_geom.c */ | |
1178 | |
1179 /* little sister we only need to know lambda */ | |
1180 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
1181 static float lambda_cp_line2(const float p[2], const float l1[2], const float l2
[2]) | |
1182 { | |
1183 float h[2], u[2]; | |
1184 ········ | |
1185 u[0] = l2[0] - l1[0]; | |
1186 u[1] = l2[1] - l1[1]; | |
1187 | |
1188 h[0] = p[0] - l1[0]; | |
1189 h[1] = p[1] - l1[1]; | |
1190 ········ | |
1191 return(dot_v2v2(u, h)/dot_v2v2(u, u)); | |
1192 } | |
1193 #endif // PROJ_DEBUG_NOSEAMBLEED | |
1194 | |
1195 | |
1196 /* Converts a UV location to a 3D screenspace location | |
1197 * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo | |
1198 *· | |
1199 * This is used for finding a pixels location in screenspace for painting */ | |
1200 static void screen_px_from_ortho( | |
1201 float uv[2], | |
1202 float v1co[3], float v2co[3], float v3co[3], /* Screenspace coor
ds */ | |
1203 float uv1co[2], float uv2co[2], float uv3co[2], | |
1204 float pixelScreenCo[4], | |
1205 float w[3]) | |
1206 { | |
1207 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); | |
1208 interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); | |
1209 } | |
1210 | |
1211 /* same as screen_px_from_ortho except we need to take into account | |
1212 * the perspective W coord for each vert */ | |
1213 static void screen_px_from_persp( | |
1214 float uv[2], | |
1215 float v1co[3], float v2co[3], float v3co[3], /* screenspace coor
ds */ | |
1216 float uv1co[2], float uv2co[2], float uv3co[2], | |
1217 float pixelScreenCo[4], | |
1218 float w[3]) | |
1219 { | |
1220 | |
1221 float wtot_inv, wtot; | |
1222 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); | |
1223 ········ | |
1224 /* re-weight from the 4th coord of each screen vert */ | |
1225 w[0] *= v1co[3]; | |
1226 w[1] *= v2co[3]; | |
1227 w[2] *= v3co[3]; | |
1228 ········ | |
1229 wtot = w[0]+w[1]+w[2]; | |
1230 ········ | |
1231 if (wtot > 0.0f) { | |
1232 wtot_inv = 1.0f / wtot; | |
1233 w[0] *= wtot_inv; | |
1234 w[1] *= wtot_inv; | |
1235 w[2] *= wtot_inv; | |
1236 } | |
1237 else { | |
1238 w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area fa
ce */ | |
1239 } | |
1240 /* done re-weighting */ | |
1241 ········ | |
1242 interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); | |
1243 } | |
1244 | |
1245 static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const
float w[3], int side, unsigned char rgba_ub[4], float rgba_f[4]) | |
1246 { | |
1247 float *uvCo1, *uvCo2, *uvCo3; | |
1248 float uv_other[2], x, y; | |
1249 ········ | |
1250 uvCo1 = (float *)tf_other->uv[0]; | |
1251 if (side==1) { | |
1252 uvCo2 = (float *)tf_other->uv[2]; | |
1253 uvCo3 = (float *)tf_other->uv[3]; | |
1254 } | |
1255 else { | |
1256 uvCo2 = (float *)tf_other->uv[1]; | |
1257 uvCo3 = (float *)tf_other->uv[2]; | |
1258 } | |
1259 ········ | |
1260 interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float*)w); | |
1261 ········ | |
1262 /* use */ | |
1263 uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y); | |
1264 ········ | |
1265 ········ | |
1266 if (ibuf_other->rect_float) { /* from float to float */ | |
1267 bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y
); | |
1268 } | |
1269 else { /* from char to float */ | |
1270 bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x,
y); | |
1271 } | |
1272 ················ | |
1273 } | |
1274 | |
1275 /* run this outside project_paint_uvpixel_init since pixels with mask 0 dont nee
d init */ | |
1276 static float project_paint_uvpixel_mask( | |
1277 const ProjPaintState *ps, | |
1278 const int face_index, | |
1279 const int side, | |
1280 const float w[3]) | |
1281 { | |
1282 float mask; | |
1283 ········ | |
1284 /* Image Mask */ | |
1285 if (ps->do_layer_stencil) { | |
1286 /* another UV layers image is masking this one's */ | |
1287 ImBuf *ibuf_other; | |
1288 const MTFace *tf_other = ps->dm_mtface_stencil + face_index; | |
1289 ················ | |
1290 if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other
->tpage, NULL))) { | |
1291 /* BKE_image_get_ibuf - TODO - this may be slow */ | |
1292 unsigned char rgba_ub[4]; | |
1293 float rgba_f[4]; | |
1294 ························ | |
1295 project_face_pixel(tf_other, ibuf_other, w, side, rgba_u
b, rgba_f); | |
1296 ························ | |
1297 if (ibuf_other->rect_float) { /* from float to float */ | |
1298 mask = ((rgba_f[0]+rgba_f[1]+rgba_f[2])/3.0f) *
rgba_f[3]; | |
1299 } | |
1300 else { /* from char to float */ | |
1301 mask = ((rgba_ub[0]+rgba_ub[1]+rgba_ub[2])/(256*
3.0f)) * (rgba_ub[3]/256.0f); | |
1302 } | |
1303 ························ | |
1304 if (!ps->do_layer_stencil_inv) /* matching the gimps lay
er mask black/white rules, white==full opacity */ | |
1305 mask = (1.0f - mask); | |
1306 | |
1307 if (mask == 0.0f) { | |
1308 return 0.0f; | |
1309 } | |
1310 } | |
1311 else { | |
1312 return 0.0f; | |
1313 } | |
1314 } else { | |
1315 mask = 1.0f; | |
1316 } | |
1317 ········ | |
1318 /* calculate mask */ | |
1319 if (ps->do_mask_normal) { | |
1320 MFace *mf = ps->dm_mface + face_index; | |
1321 short *no1, *no2, *no3; | |
1322 float no[3], angle; | |
1323 no1 = ps->dm_mvert[mf->v1].no; | |
1324 if (side==1) { | |
1325 no2 = ps->dm_mvert[mf->v3].no; | |
1326 no3 = ps->dm_mvert[mf->v4].no; | |
1327 } | |
1328 else { | |
1329 no2 = ps->dm_mvert[mf->v2].no; | |
1330 no3 = ps->dm_mvert[mf->v3].no; | |
1331 } | |
1332 ················ | |
1333 no[0] = w[0]*no1[0] + w[1]*no2[0] + w[2]*no3[0]; | |
1334 no[1] = w[0]*no1[1] + w[1]*no2[1] + w[2]*no3[1]; | |
1335 no[2] = w[0]*no1[2] + w[1]*no2[2] + w[2]*no3[2]; | |
1336 normalize_v3(no); | |
1337 ················ | |
1338 /* now we can use the normal as a mask */ | |
1339 if (ps->is_ortho) { | |
1340 angle = angle_normalized_v3v3((float *)ps->viewDir, no); | |
1341 } | |
1342 else { | |
1343 /* Annoying but for the perspective view we need to get
the pixels location in 3D space :/ */ | |
1344 float viewDirPersp[3]; | |
1345 float *co1, *co2, *co3; | |
1346 co1 = ps->dm_mvert[mf->v1].co; | |
1347 if (side==1) { | |
1348 co2 = ps->dm_mvert[mf->v3].co; | |
1349 co3 = ps->dm_mvert[mf->v4].co; | |
1350 } | |
1351 else { | |
1352 co2 = ps->dm_mvert[mf->v2].co; | |
1353 co3 = ps->dm_mvert[mf->v3].co; | |
1354 } | |
1355 | |
1356 /* Get the direction from the viewPoint to the pixel and
normalize */ | |
1357 viewDirPersp[0] = (ps->viewPos[0] - (w[0]*co1[0] + w[1]*
co2[0] + w[2]*co3[0])); | |
1358 viewDirPersp[1] = (ps->viewPos[1] - (w[0]*co1[1] + w[1]*
co2[1] + w[2]*co3[1])); | |
1359 viewDirPersp[2] = (ps->viewPos[2] - (w[0]*co1[2] + w[1]*
co2[2] + w[2]*co3[2])); | |
1360 normalize_v3(viewDirPersp); | |
1361 ························ | |
1362 angle = angle_normalized_v3v3(viewDirPersp, no); | |
1363 } | |
1364 ················ | |
1365 if (angle >= ps->normal_angle) { | |
1366 return 0.0f; /* outsize the normal limit*/ | |
1367 } | |
1368 else if (angle > ps->normal_angle_inner) { | |
1369 mask *= (ps->normal_angle - angle) / ps->normal_angle_ra
nge; | |
1370 } /* otherwise no mask normal is needed, were within the limit *
/ | |
1371 } | |
1372 ········ | |
1373 // This only works when the opacity dosnt change while painting, stylus
pressure messes with this | |
1374 // so dont use it. | |
1375 // if (ps->is_airbrush==0) mask *= brush_alpha(ps->brush); | |
1376 ········ | |
1377 return mask; | |
1378 } | |
1379 | |
1380 /* run this function when we know a bucket's, face's pixel can be initialized, | |
1381 * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */ | |
1382 static ProjPixel *project_paint_uvpixel_init( | |
1383 const ProjPaintState *ps, | |
1384 MemArena *arena, | |
1385 const ImBuf *ibuf, | |
1386 short x_px, short y_px, | |
1387 const float mask, | |
1388 const int face_index, | |
1389 const int image_index, | |
1390 const float pixelScreenCo[4], | |
1391 const int side, | |
1392 const float w[3]) | |
1393 { | |
1394 ProjPixel *projPixel; | |
1395 short size; | |
1396 ········ | |
1397 /* wrap pixel location */ | |
1398 x_px = x_px % ibuf->x; | |
1399 if (x_px<0) x_px += ibuf->x; | |
1400 y_px = y_px % ibuf->y; | |
1401 if (y_px<0) y_px += ibuf->y; | |
1402 ········ | |
1403 if (ps->tool==PAINT_TOOL_CLONE) { | |
1404 size = sizeof(ProjPixelClone); | |
1405 } | |
1406 else if (ps->tool==PAINT_TOOL_SMEAR) { | |
1407 size = sizeof(ProjPixelClone); | |
1408 } | |
1409 else { | |
1410 size = sizeof(ProjPixel); | |
1411 } | |
1412 ········ | |
1413 projPixel = (ProjPixel *)BLI_memarena_alloc(arena, size); | |
1414 //memset(projPixel, 0, size); | |
1415 ········ | |
1416 if (ibuf->rect_float) { | |
1417 projPixel->pixel.f_pt = (float *)ibuf->rect_float + ((x_px + y_p
x * ibuf->x) * 4); | |
1418 projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel
->pixel.f_pt[0];·· | |
1419 projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel
->pixel.f_pt[1];·· | |
1420 projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel
->pixel.f_pt[2];·· | |
1421 projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel
->pixel.f_pt[3];·· | |
1422 } | |
1423 else { | |
1424 projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px +
y_px * ibuf->x) * 4)); | |
1425 projPixel->origColor.uint = projPixel->newColor.uint = *projPixe
l->pixel.uint_pt; | |
1426 } | |
1427 ········ | |
1428 /* screenspace unclamped, we could keep its z and w values but dont need
them at the moment */ | |
1429 VECCOPY2D(projPixel->projCoSS, pixelScreenCo); | |
1430 ········ | |
1431 projPixel->x_px = x_px; | |
1432 projPixel->y_px = y_px; | |
1433 ········ | |
1434 projPixel->mask = (unsigned short)(mask * 65535); | |
1435 projPixel->mask_max = 0; | |
1436 ········ | |
1437 /* which bounding box cell are we in?, needed for undo */ | |
1438 projPixel->bb_cell_index = ((int)(((float)x_px/(float)ibuf->x) * PROJ_BO
UNDBOX_DIV)) + ((int)(((float)y_px/(float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_
BOUNDBOX_DIV ; | |
1439 ········ | |
1440 /* done with view3d_project_float inline */ | |
1441 if (ps->tool==PAINT_TOOL_CLONE) { | |
1442 if (ps->dm_mtface_clone) { | |
1443 ImBuf *ibuf_other; | |
1444 const MTFace *tf_other = ps->dm_mtface_clone + face_inde
x; | |
1445 ························ | |
1446 if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(
tf_other->tpage, NULL))) { | |
1447 /* BKE_image_get_ibuf - TODO - this may be slow
*/ | |
1448 ································ | |
1449 if (ibuf->rect_float) { | |
1450 if (ibuf_other->rect_float) { /* from fl
oat to float */ | |
1451 project_face_pixel(tf_other, ibu
f_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f); | |
1452 } | |
1453 else { /* from char to float */ | |
1454 unsigned char rgba_ub[4]; | |
1455 project_face_pixel(tf_other, ibu
f_other, w, side, rgba_ub, NULL); | |
1456 IMAPAINT_CHAR_RGBA_TO_FLOAT(((Pr
ojPixelClone *)projPixel)->clonepx.f, rgba_ub); | |
1457 } | |
1458 } | |
1459 else { | |
1460 if (ibuf_other->rect_float) { /* float t
o char */ | |
1461 float rgba[4]; | |
1462 project_face_pixel(tf_other, ibu
f_other, w, side, NULL, rgba); | |
1463 IMAPAINT_FLOAT_RGBA_TO_CHAR(((Pr
ojPixelClone *)projPixel)->clonepx.ch, rgba) | |
1464 } | |
1465 else { /* char to char */ | |
1466 project_face_pixel(tf_other, ibu
f_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL); | |
1467 } | |
1468 } | |
1469 } | |
1470 else { | |
1471 if (ibuf->rect_float) { | |
1472 ((ProjPixelClone *)projPixel)->clonepx.f
[3] = 0; | |
1473 } | |
1474 else { | |
1475 ((ProjPixelClone *)projPixel)->clonepx.c
h[3] = 0; | |
1476 } | |
1477 } | |
1478 ························ | |
1479 } | |
1480 else { | |
1481 float co[2]; | |
1482 sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneO
ffset); | |
1483 ························ | |
1484 /* no need to initialize the bucket, we're only checking
buckets faces and for this | |
1485 * the faces are already initialized in project_paint_de
layed_face_init(...) */ | |
1486 if (ibuf->rect_float) { | |
1487 if (!project_paint_PickColor(ps, co, ((ProjPixel
Clone *)projPixel)->clonepx.f, NULL, 1)) { | |
1488 ((ProjPixelClone *)projPixel)->clonepx.f
[3] = 0; /* zero alpha - ignore */ | |
1489 } | |
1490 } | |
1491 else { | |
1492 if (!project_paint_PickColor(ps, co, NULL, ((Pro
jPixelClone *)projPixel)->clonepx.ch, 1)) { | |
1493 ((ProjPixelClone *)projPixel)->clonepx.c
h[3] = 0; /* zero alpha - ignore */ | |
1494 } | |
1495 } | |
1496 } | |
1497 } | |
1498 ········ | |
1499 #ifdef PROJ_DEBUG_PAINT | |
1500 if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0; | |
1501 else projPixel->pixel.ch_pt[0] = 0; | |
1502 #endif | |
1503 projPixel->image_index = image_index; | |
1504 ········ | |
1505 return projPixel; | |
1506 } | |
1507 | |
1508 static int line_clip_rect2f( | |
1509 rctf *rect, | |
1510 const float l1[2], const float l2[2], | |
1511 float l1_clip[2], float l2_clip[2]) | |
1512 { | |
1513 /* first account for horizontal, then vertical lines */ | |
1514 /* horiz */ | |
1515 if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { | |
1516 /* is the line out of range on its Y axis? */ | |
1517 if (l1[1] < rect->ymin || l1[1] > rect->ymax) { | |
1518 return 0; | |
1519 } | |
1520 /* line is out of range on its X axis */ | |
1521 if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect-
>xmax && l2[0] > rect->xmax)) { | |
1522 return 0; | |
1523 } | |
1524 ················ | |
1525 ················ | |
1526 if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a sin
gle point (or close to)*/ | |
1527 if (BLI_in_rctf(rect, l1[0], l1[1])) { | |
1528 VECCOPY2D(l1_clip, l1); | |
1529 VECCOPY2D(l2_clip, l2); | |
1530 return 1; | |
1531 } | |
1532 else { | |
1533 return 0; | |
1534 } | |
1535 } | |
1536 ················ | |
1537 VECCOPY2D(l1_clip, l1); | |
1538 VECCOPY2D(l2_clip, l2); | |
1539 CLAMP(l1_clip[0], rect->xmin, rect->xmax); | |
1540 CLAMP(l2_clip[0], rect->xmin, rect->xmax); | |
1541 return 1; | |
1542 } | |
1543 else if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { | |
1544 /* is the line out of range on its X axis? */ | |
1545 if (l1[0] < rect->xmin || l1[0] > rect->xmax) { | |
1546 return 0; | |
1547 } | |
1548 ················ | |
1549 /* line is out of range on its Y axis */ | |
1550 if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect-
>ymax && l2[1] > rect->ymax)) { | |
1551 return 0; | |
1552 } | |
1553 ················ | |
1554 if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a sin
gle point (or close to)*/ | |
1555 if (BLI_in_rctf(rect, l1[0], l1[1])) { | |
1556 VECCOPY2D(l1_clip, l1); | |
1557 VECCOPY2D(l2_clip, l2); | |
1558 return 1; | |
1559 } | |
1560 else { | |
1561 return 0; | |
1562 } | |
1563 } | |
1564 ················ | |
1565 VECCOPY2D(l1_clip, l1); | |
1566 VECCOPY2D(l2_clip, l2); | |
1567 CLAMP(l1_clip[1], rect->ymin, rect->ymax); | |
1568 CLAMP(l2_clip[1], rect->ymin, rect->ymax); | |
1569 return 1; | |
1570 } | |
1571 else { | |
1572 float isect; | |
1573 short ok1 = 0; | |
1574 short ok2 = 0; | |
1575 ················ | |
1576 /* Done with vertical lines */ | |
1577 ················ | |
1578 /* are either of the points inside the rectangle ? */ | |
1579 if (BLI_in_rctf(rect, l1[0], l1[1])) { | |
1580 VECCOPY2D(l1_clip, l1); | |
1581 ok1 = 1; | |
1582 } | |
1583 ················ | |
1584 if (BLI_in_rctf(rect, l2[0], l2[1])) { | |
1585 VECCOPY2D(l2_clip, l2); | |
1586 ok2 = 1; | |
1587 } | |
1588 ················ | |
1589 /* line inside rect */ | |
1590 if (ok1 && ok2) return 1; | |
1591 ················ | |
1592 /* top/bottom */ | |
1593 if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->
xmin) && (isect <= rect->xmax)) { | |
1594 if (l1[1] < l2[1]) { /* line 1 is outside */ | |
1595 l1_clip[0] = isect; | |
1596 l1_clip[1] = rect->ymin; | |
1597 ok1 = 1; | |
1598 } | |
1599 else { | |
1600 l2_clip[0] = isect; | |
1601 l2_clip[1] = rect->ymin; | |
1602 ok2 = 2; | |
1603 } | |
1604 } | |
1605 ················ | |
1606 if (ok1 && ok2) return 1; | |
1607 ················ | |
1608 if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->
xmin) && (isect <= rect->xmax)) { | |
1609 if (l1[1] > l2[1]) { /* line 1 is outside */ | |
1610 l1_clip[0] = isect; | |
1611 l1_clip[1] = rect->ymax; | |
1612 ok1 = 1; | |
1613 } | |
1614 else { | |
1615 l2_clip[0] = isect; | |
1616 l2_clip[1] = rect->ymax; | |
1617 ok2 = 2; | |
1618 } | |
1619 } | |
1620 ················ | |
1621 if (ok1 && ok2) return 1; | |
1622 ················ | |
1623 /* left/right */ | |
1624 if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->
ymin) && (isect <= rect->ymax)) { | |
1625 if (l1[0] < l2[0]) { /* line 1 is outside */ | |
1626 l1_clip[0] = rect->xmin; | |
1627 l1_clip[1] = isect; | |
1628 ok1 = 1; | |
1629 } | |
1630 else { | |
1631 l2_clip[0] = rect->xmin; | |
1632 l2_clip[1] = isect; | |
1633 ok2 = 2; | |
1634 } | |
1635 } | |
1636 ········ | |
1637 if (ok1 && ok2) return 1; | |
1638 ················ | |
1639 if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->
ymin) && (isect <= rect->ymax)) { | |
1640 if (l1[0] > l2[0]) { /* line 1 is outside */ | |
1641 l1_clip[0] = rect->xmax; | |
1642 l1_clip[1] = isect; | |
1643 ok1 = 1; | |
1644 } | |
1645 else { | |
1646 l2_clip[0] = rect->xmax; | |
1647 l2_clip[1] = isect; | |
1648 ok2 = 2; | |
1649 } | |
1650 } | |
1651 ················ | |
1652 if (ok1 && ok2) { | |
1653 return 1; | |
1654 } | |
1655 else { | |
1656 return 0; | |
1657 } | |
1658 } | |
1659 } | |
1660 | |
1661 | |
1662 | |
1663 /* scale the quad & tri about its center | |
1664 * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coo
rds that are on the | |
1665 * edge of the face but slightly inside it occlusion tests dont return hits on a
djacent faces */ | |
1666 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
1667 static void scale_quad(float insetCos[4][3], float *origCos[4], const float inse
t) | |
1668 { | |
1669 float cent[3]; | |
1670 cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]
) / 4.0f; | |
1671 cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]
) / 4.0f; | |
1672 cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]
) / 4.0f; | |
1673 ········ | |
1674 sub_v3_v3v3(insetCos[0], origCos[0], cent); | |
1675 sub_v3_v3v3(insetCos[1], origCos[1], cent); | |
1676 sub_v3_v3v3(insetCos[2], origCos[2], cent); | |
1677 sub_v3_v3v3(insetCos[3], origCos[3], cent); | |
1678 ········ | |
1679 mul_v3_fl(insetCos[0], inset); | |
1680 mul_v3_fl(insetCos[1], inset); | |
1681 mul_v3_fl(insetCos[2], inset); | |
1682 mul_v3_fl(insetCos[3], inset); | |
1683 ········ | |
1684 add_v3_v3(insetCos[0], cent); | |
1685 add_v3_v3(insetCos[1], cent); | |
1686 add_v3_v3(insetCos[2], cent); | |
1687 add_v3_v3(insetCos[3], cent); | |
1688 } | |
1689 | |
1690 | |
1691 static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset
) | |
1692 { | |
1693 float cent[3]; | |
1694 cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f; | |
1695 cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f; | |
1696 cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f; | |
1697 ········ | |
1698 sub_v3_v3v3(insetCos[0], origCos[0], cent); | |
1699 sub_v3_v3v3(insetCos[1], origCos[1], cent); | |
1700 sub_v3_v3v3(insetCos[2], origCos[2], cent); | |
1701 ········ | |
1702 mul_v3_fl(insetCos[0], inset); | |
1703 mul_v3_fl(insetCos[1], inset); | |
1704 mul_v3_fl(insetCos[2], inset); | |
1705 ········ | |
1706 add_v3_v3(insetCos[0], cent); | |
1707 add_v3_v3(insetCos[1], cent); | |
1708 add_v3_v3(insetCos[2], cent); | |
1709 } | |
1710 #endif //PROJ_DEBUG_NOSEAMBLEED | |
1711 | |
1712 static float Vec2Lenf_nosqrt(const float *v1, const float *v2) | |
1713 { | |
1714 float x, y; | |
1715 | |
1716 x = v1[0]-v2[0]; | |
1717 y = v1[1]-v2[1]; | |
1718 return x*x+y*y; | |
1719 } | |
1720 | |
1721 static float Vec2Lenf_nosqrt_other(const float *v1, const float v2_1, const floa
t v2_2) | |
1722 { | |
1723 float x, y; | |
1724 | |
1725 x = v1[0]-v2_1; | |
1726 y = v1[1]-v2_2; | |
1727 return x*x+y*y; | |
1728 } | |
1729 | |
1730 /* note, use a squared value so we can use Vec2Lenf_nosqrt | |
1731 * be sure that you have done a bounds check first or this may fail */ | |
1732 /* only give bucket_bounds as an arg because we need it elsewhere */ | |
1733 static int project_bucket_isect_circle(const float cent[2], const float radius_s
quared, rctf *bucket_bounds) | |
1734 { | |
1735 ········· | |
1736 /* Would normally to a simple intersection test, however we know the bou
nds of these 2 already intersect· | |
1737 * so we only need to test if the center is inside the vertical or horiz
ontal bounds on either axis, | |
1738 * this is even less work then an intersection test | |
1739 *· | |
1740 if (BLI_in_rctf(bucket_bounds, cent[0], cent[1])) | |
1741 return 1; | |
1742 */ | |
1743 ········ | |
1744 if((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) ||
(bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1]) ) { | |
1745 return 1; | |
1746 } | |
1747 ········ | |
1748 /* out of bounds left */ | |
1749 if (cent[0] < bucket_bounds->xmin) { | |
1750 /* lower left out of radius test */ | |
1751 if (cent[1] < bucket_bounds->ymin) { | |
1752 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmin,
bucket_bounds->ymin) < radius_squared) ? 1 : 0; | |
1753 }· | |
1754 /* top left test */ | |
1755 else if (cent[1] > bucket_bounds->ymax) { | |
1756 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmin,
bucket_bounds->ymax) < radius_squared) ? 1 : 0; | |
1757 } | |
1758 } | |
1759 else if (cent[0] > bucket_bounds->xmax) { | |
1760 /* lower right out of radius test */ | |
1761 if (cent[1] < bucket_bounds->ymin) { | |
1762 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmax,
bucket_bounds->ymin) < radius_squared) ? 1 : 0; | |
1763 }· | |
1764 /* top right test */ | |
1765 else if (cent[1] > bucket_bounds->ymax) { | |
1766 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmax,
bucket_bounds->ymax) < radius_squared) ? 1 : 0; | |
1767 } | |
1768 } | |
1769 ········ | |
1770 return 0; | |
1771 } | |
1772 | |
1773 | |
1774 | |
1775 /* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp() | |
1776 * in ortho view this function gives good results when bucket_bounds are outside
the triangle | |
1777 * however in some cases, perspective view will mess up with faces that have min
imal screenspace area (viewed from the side) | |
1778 *· | |
1779 * for this reason its not relyable in this case so we'll use the Simple Barycen
tric' funcs that only account for points inside the triangle. | |
1780 * however switching back to this for ortho is always an option */ | |
1781 | |
1782 static void rect_to_uvspace_ortho( | |
1783 rctf *bucket_bounds, | |
1784 float *v1coSS, float *v2coSS, float *v3coSS, | |
1785 float *uv1co, float *uv2co, float *uv3co, | |
1786 float bucket_bounds_uv[4][2], | |
1787 const int flip) | |
1788 { | |
1789 float uv[2]; | |
1790 float w[3]; | |
1791 ········ | |
1792 /* get the UV space bounding box */ | |
1793 uv[0] = bucket_bounds->xmax; | |
1794 uv[1] = bucket_bounds->ymin; | |
1795 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); | |
1796 interp_v2_v2v2v2(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); | |
1797 | |
1798 //uv[0] = bucket_bounds->xmax; // set above | |
1799 uv[1] = bucket_bounds->ymax; | |
1800 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); | |
1801 interp_v2_v2v2v2(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); | |
1802 | |
1803 uv[0] = bucket_bounds->xmin; | |
1804 //uv[1] = bucket_bounds->ymax; // set above | |
1805 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); | |
1806 interp_v2_v2v2v2(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); | |
1807 | |
1808 //uv[0] = bucket_bounds->xmin; // set above | |
1809 uv[1] = bucket_bounds->ymin; | |
1810 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); | |
1811 interp_v2_v2v2v2(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); | |
1812 } | |
1813 | |
1814 /* same as above but use barycentric_weights_v2_persp */ | |
1815 static void rect_to_uvspace_persp( | |
1816 rctf *bucket_bounds, | |
1817 float *v1coSS, float *v2coSS, float *v3coSS, | |
1818 float *uv1co, float *uv2co, float *uv3co, | |
1819 float bucket_bounds_uv[4][2], | |
1820 const int flip | |
1821 ) | |
1822 { | |
1823 float uv[2]; | |
1824 float w[3]; | |
1825 ········ | |
1826 /* get the UV space bounding box */ | |
1827 uv[0] = bucket_bounds->xmax; | |
1828 uv[1] = bucket_bounds->ymin; | |
1829 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); | |
1830 interp_v2_v2v2v2(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); | |
1831 | |
1832 //uv[0] = bucket_bounds->xmax; // set above | |
1833 uv[1] = bucket_bounds->ymax; | |
1834 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); | |
1835 interp_v2_v2v2v2(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); | |
1836 | |
1837 uv[0] = bucket_bounds->xmin; | |
1838 //uv[1] = bucket_bounds->ymax; // set above | |
1839 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); | |
1840 interp_v2_v2v2v2(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); | |
1841 | |
1842 //uv[0] = bucket_bounds->xmin; // set above | |
1843 uv[1] = bucket_bounds->ymin; | |
1844 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); | |
1845 interp_v2_v2v2v2(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); | |
1846 } | |
1847 | |
1848 /* This works as we need it to but we can save a few steps and not use it */ | |
1849 | |
1850 #if 0 | |
1851 static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
t p3[2]) | |
1852 { | |
1853 float v1[2], v2[2]; | |
1854 ········ | |
1855 v1[0] = p1[0]-p2[0]; v1[1] = p1[1]-p2[1]; | |
1856 v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; | |
1857 ········ | |
1858 return -atan2(v1[0]*v2[1] - v1[1]*v2[0], v1[0]*v2[0]+v1[1]*v2[1]); | |
1859 } | |
1860 #endif | |
1861 | |
1862 #define ISECT_1 (1) | |
1863 #define ISECT_2 (1<<1) | |
1864 #define ISECT_3 (1<<2) | |
1865 #define ISECT_4 (1<<3) | |
1866 #define ISECT_ALL3 ((1<<3)-1) | |
1867 #define ISECT_ALL4 ((1<<4)-1) | |
1868 | |
1869 /* limit must be a fraction over 1.0f */ | |
1870 static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2],
float limit) | |
1871 { | |
1872 return ((area_tri_v2(pt,v1,v2) + area_tri_v2(pt,v2,v3) + area_tri_v2(pt,
v3,v1)) / (area_tri_v2(v1,v2,v3))) < limit; | |
1873 } | |
1874 | |
1875 /* Clip the face by a bucket and set the uv-space bucket_bounds_uv | |
1876 * so we have the clipped UV's to do pixel intersection tests with· | |
1877 * */ | |
1878 static int float_z_sort_flip(const void *p1, const void *p2) { | |
1879 return (((float *)p1)[2] < ((float *)p2)[2] ? 1:-1); | |
1880 } | |
1881 | |
1882 static int float_z_sort(const void *p1, const void *p2) { | |
1883 return (((float *)p1)[2] < ((float *)p2)[2] ?-1:1); | |
1884 } | |
1885 | |
1886 static void project_bucket_clip_face( | |
1887 const int is_ortho, | |
1888 rctf *bucket_bounds, | |
1889 float *v1coSS, float *v2coSS, float *v3coSS, | |
1890 float *uv1co, float *uv2co, float *uv3co, | |
1891 float bucket_bounds_uv[8][2], | |
1892 int *tot) | |
1893 { | |
1894 int inside_bucket_flag = 0; | |
1895 int inside_face_flag = 0; | |
1896 const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
(line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); | |
1897 ········ | |
1898 float bucket_bounds_ss[4][2]; | |
1899 | |
1900 /* get the UV space bounding box */ | |
1901 inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v1coSS[0], v1coSS[1]); | |
1902 inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v2coSS[0], v2coSS[1])
<< 1; | |
1903 inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v3coSS[0], v3coSS[1])
<< 2; | |
1904 ········ | |
1905 if (inside_bucket_flag == ISECT_ALL3) { | |
1906 /* all screenspace points are inside the bucket bounding box, th
is means we dont need to clip and can simply return the UVs */ | |
1907 if (flip) { /* facing the back? */ | |
1908 VECCOPY2D(bucket_bounds_uv[0], uv3co); | |
1909 VECCOPY2D(bucket_bounds_uv[1], uv2co); | |
1910 VECCOPY2D(bucket_bounds_uv[2], uv1co); | |
1911 } | |
1912 else { | |
1913 VECCOPY2D(bucket_bounds_uv[0], uv1co); | |
1914 VECCOPY2D(bucket_bounds_uv[1], uv2co); | |
1915 VECCOPY2D(bucket_bounds_uv[2], uv3co); | |
1916 } | |
1917 ················ | |
1918 *tot = 3;· | |
1919 return; | |
1920 } | |
1921 ········ | |
1922 /* get the UV space bounding box */ | |
1923 /* use IsectPT2Df_limit here so we catch points are are touching the tri
edge (or a small fraction over) */ | |
1924 bucket_bounds_ss[0][0] = bucket_bounds->xmax; | |
1925 bucket_bounds_ss[0][1] = bucket_bounds->ymin; | |
1926 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coS
S, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0); | |
1927 ········ | |
1928 bucket_bounds_ss[1][0] = bucket_bounds->xmax; | |
1929 bucket_bounds_ss[1][1] = bucket_bounds->ymax; | |
1930 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coS
S, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0); | |
1931 | |
1932 bucket_bounds_ss[2][0] = bucket_bounds->xmin; | |
1933 bucket_bounds_ss[2][1] = bucket_bounds->ymax; | |
1934 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coS
S, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0); | |
1935 | |
1936 bucket_bounds_ss[3][0] = bucket_bounds->xmin; | |
1937 bucket_bounds_ss[3][1] = bucket_bounds->ymin; | |
1938 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coS
S, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0); | |
1939 ········ | |
1940 if (inside_face_flag == ISECT_ALL4) { | |
1941 /* bucket is totally inside the screenspace face, we can safely
use weights */ | |
1942 ················ | |
1943 if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2c
oSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); | |
1944 else rect_to_uvspace_persp(bucket_bounds, v1c
oSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); | |
1945 ················ | |
1946 *tot = 4; | |
1947 return; | |
1948 } | |
1949 else { | |
1950 /* The Complicated Case!· | |
1951 *· | |
1952 * The 2 cases above are where the face is inside the bucket or
the bucket is inside the face. | |
1953 *· | |
1954 * we need to make a convex polyline from the intersection betwe
en the screenspace face | |
1955 * and the bucket bounds. | |
1956 *· | |
1957 * There are a number of ways this could be done, currently it j
ust collects all intersecting verts, | |
1958 * and line intersections, then sorts them clockwise, this is a
lot easier then evaluating the geometry to | |
1959 * do a correct clipping on both shapes. */ | |
1960 ················ | |
1961 ················ | |
1962 /* add a bunch of points, we know must make up the convex hull w
hich is the clipped rect and triangle */ | |
1963 ················ | |
1964 ················ | |
1965 ················ | |
1966 /* Maximum possible 6 intersections when using a rectangle and t
riangle */ | |
1967 float isectVCosSS[8][3]; /* The 3rd float is used to store angle
for qsort(), NOT as a Z location */ | |
1968 float v1_clipSS[2], v2_clipSS[2]; | |
1969 float w[3]; | |
1970 ················ | |
1971 /* calc center*/ | |
1972 float cent[2] = {0.0f, 0.0f}; | |
1973 /*float up[2] = {0.0f, 1.0f};*/ | |
1974 int i; | |
1975 short doubles; | |
1976 ················ | |
1977 (*tot) = 0; | |
1978 ················ | |
1979 if (inside_face_flag & ISECT_1) { VECCOPY2D(isectVCosSS[*tot], b
ucket_bounds_ss[0]); (*tot)++; } | |
1980 if (inside_face_flag & ISECT_2) { VECCOPY2D(isectVCosSS[*tot], b
ucket_bounds_ss[1]); (*tot)++; } | |
1981 if (inside_face_flag & ISECT_3) { VECCOPY2D(isectVCosSS[*tot], b
ucket_bounds_ss[2]); (*tot)++; } | |
1982 if (inside_face_flag & ISECT_4) { VECCOPY2D(isectVCosSS[*tot], b
ucket_bounds_ss[3]); (*tot)++; } | |
1983 ················ | |
1984 if (inside_bucket_flag & ISECT_1) { VECCOPY2D(isectVCosSS[*t
ot], v1coSS); (*tot)++; } | |
1985 if (inside_bucket_flag & ISECT_2) { VECCOPY2D(isectVCosSS[*t
ot], v2coSS); (*tot)++; } | |
1986 if (inside_bucket_flag & ISECT_3) { VECCOPY2D(isectVCosSS[*t
ot], v3coSS); (*tot)++; } | |
1987 ················ | |
1988 if ((inside_bucket_flag & (ISECT_1|ISECT_2)) != (ISECT_1|ISECT_2
)) { | |
1989 if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_c
lipSS, v2_clipSS)) { | |
1990 if ((inside_bucket_flag & ISECT_1)==0) { VECCOPY
2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; } | |
1991 if ((inside_bucket_flag & ISECT_2)==0) { VECCOPY
2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; } | |
1992 } | |
1993 } | |
1994 ················ | |
1995 if ((inside_bucket_flag & (ISECT_2|ISECT_3)) != (ISECT_2|ISECT_3
)) { | |
1996 if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_c
lipSS, v2_clipSS)) { | |
1997 if ((inside_bucket_flag & ISECT_2)==0) { VECCOPY
2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; } | |
1998 if ((inside_bucket_flag & ISECT_3)==0) { VECCOPY
2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; } | |
1999 } | |
2000 }······· | |
2001 ················ | |
2002 if ((inside_bucket_flag & (ISECT_3|ISECT_1)) != (ISECT_3|ISECT_1
)) { | |
2003 if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_c
lipSS, v2_clipSS)) { | |
2004 if ((inside_bucket_flag & ISECT_3)==0) { VECCOPY
2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; } | |
2005 if ((inside_bucket_flag & ISECT_1)==0) { VECCOPY
2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; } | |
2006 } | |
2007 } | |
2008 ················ | |
2009 ················ | |
2010 if ((*tot) < 3) { /* no intersections to speak of */ | |
2011 *tot = 0; | |
2012 return; | |
2013 } | |
2014 ········ | |
2015 /* now we have all points we need, collect their angles and sort
them clockwise */ | |
2016 ················ | |
2017 for(i=0; i<(*tot); i++) { | |
2018 cent[0] += isectVCosSS[i][0]; | |
2019 cent[1] += isectVCosSS[i][1]; | |
2020 } | |
2021 cent[0] = cent[0] / (float)(*tot); | |
2022 cent[1] = cent[1] / (float)(*tot); | |
2023 ················ | |
2024 ················ | |
2025 ················ | |
2026 /* Collect angles for every point around the center point */ | |
2027 | |
2028 ················ | |
2029 #if 0 /* uses a few more cycles then the above loop */ | |
2030 for(i=0; i<(*tot); i++) { | |
2031 isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVC
osSS[i]); | |
2032 } | |
2033 #endif | |
2034 | |
2035 v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */ | |
2036 v1_clipSS[1] = cent[1] + 1.0f; | |
2037 ················ | |
2038 for(i=0; i<(*tot); i++) { | |
2039 v2_clipSS[0] = isectVCosSS[i][0] - cent[0]; | |
2040 v2_clipSS[1] = isectVCosSS[i][1] - cent[1]; | |
2041 isectVCosSS[i][2] = atan2f(v1_clipSS[0]*v2_clipSS[1] - v
1_clipSS[1]*v2_clipSS[0], v1_clipSS[0]*v2_clipSS[0]+v1_clipSS[1]*v2_clipSS[1]);· | |
2042 } | |
2043 ················ | |
2044 if (flip) qsort(isectVCosSS, *tot, sizeof(float)*3, float_
z_sort_flip); | |
2045 else qsort(isectVCosSS, *tot, sizeof(float)*3, float_
z_sort); | |
2046 ················ | |
2047 /* remove doubles */ | |
2048 /* first/last check */ | |
2049 if (fabsf(isectVCosSS[0][0]-isectVCosSS[(*tot)-1][0]) < PROJ_GEO
M_TOLERANCE && fabsf(isectVCosSS[0][1]-isectVCosSS[(*tot)-1][1]) < PROJ_GEOM_TO
LERANCE) { | |
2050 (*tot)--; | |
2051 } | |
2052 ················ | |
2053 /* its possible there is only a few left after remove doubles */ | |
2054 if ((*tot) < 3) { | |
2055 // printf("removed too many doubles A\n"); | |
2056 *tot = 0; | |
2057 return; | |
2058 } | |
2059 ················ | |
2060 doubles = TRUE; | |
2061 while (doubles==TRUE) { | |
2062 doubles = FALSE; | |
2063 for(i=1; i<(*tot); i++) { | |
2064 if (fabsf(isectVCosSS[i-1][0]-isectVCosSS[i][0])
< PROJ_GEOM_TOLERANCE && | |
2065 fabsf(isectVCosSS[i-1][1]-isectVCosSS[i]
[1]) < PROJ_GEOM_TOLERANCE) | |
2066 { | |
2067 int j; | |
2068 for(j=i+1; j<(*tot); j++) { | |
2069 isectVCosSS[j-1][0] = isectVCosS
S[j][0];· | |
2070 isectVCosSS[j-1][1] = isectVCosS
S[j][1];· | |
2071 } | |
2072 doubles = TRUE; /* keep looking for more
doubles */ | |
2073 (*tot)--; | |
2074 } | |
2075 } | |
2076 } | |
2077 ················ | |
2078 /* its possible there is only a few left after remove doubles */ | |
2079 if ((*tot) < 3) { | |
2080 // printf("removed too many doubles B\n"); | |
2081 *tot = 0; | |
2082 return; | |
2083 } | |
2084 ················ | |
2085 ················ | |
2086 if (is_ortho) { | |
2087 for(i=0; i<(*tot); i++) { | |
2088 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, i
sectVCosSS[i], w); | |
2089 interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2
co, uv3co, w); | |
2090 } | |
2091 } | |
2092 else { | |
2093 for(i=0; i<(*tot); i++) { | |
2094 barycentric_weights_v2_persp(v1coSS, v2coSS, v3c
oSS, isectVCosSS[i], w); | |
2095 interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2
co, uv3co, w); | |
2096 } | |
2097 } | |
2098 } | |
2099 | |
2100 #ifdef PROJ_DEBUG_PRINT_CLIP | |
2101 /* include this at the bottom of the above function to debug the output
*/ | |
2102 | |
2103 { | |
2104 /* If there are ever any problems, */ | |
2105 float test_uv[4][2]; | |
2106 int i; | |
2107 if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2c
oSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); | |
2108 else rect_to_uvspace_persp(bucket_bou
nds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); | |
2109 printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0
], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1
], test_uv[3][0], test_uv[3][1]); | |
2110 ················ | |
2111 printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1],
uv2co[0], uv2co[1], uv3co[0], uv3co[1]); | |
2112 ················ | |
2113 printf("["); | |
2114 for (i=0; i < (*tot); i++) { | |
2115 printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bound
s_uv[i][1]); | |
2116 } | |
2117 printf("]),\\\n"); | |
2118 } | |
2119 #endif | |
2120 } | |
2121 | |
2122 /* | |
2123 # This script creates faces in a blender scene from printed data above. | |
2124 | |
2125 project_ls = [ | |
2126 ...(output from above block)... | |
2127 ] | |
2128 · | |
2129 from Blender import Scene, Mesh, Window, sys, Mathutils | |
2130 | |
2131 import bpy | |
2132 | |
2133 V = Mathutils.Vector | |
2134 | |
2135 def main(): | |
2136 sce = bpy.data.scenes.active | |
2137 ········ | |
2138 for item in project_ls: | |
2139 bb = item[0] | |
2140 uv = item[1] | |
2141 poly = item[2] | |
2142 ················ | |
2143 me = bpy.data.meshes.new() | |
2144 ob = sce.objects.new(me) | |
2145 ················ | |
2146 me.verts.extend([V(bb[0]).resize3D(), V(bb[1]).resize3D(), V(bb[
2]).resize3D(), V(bb[3]).resize3D()]) | |
2147 me.faces.extend([(0,1,2,3),]) | |
2148 me.verts.extend([V(uv[0]).resize3D(), V(uv[1]).resize3D(), V(uv[
2]).resize3D()]) | |
2149 me.faces.extend([(4,5,6),]) | |
2150 ················ | |
2151 vs = [V(p).resize3D() for p in poly] | |
2152 print len(vs) | |
2153 l = len(me.verts) | |
2154 me.verts.extend(vs) | |
2155 ················ | |
2156 i = l | |
2157 while i < len(me.verts): | |
2158 ii = i+1 | |
2159 if ii==len(me.verts): | |
2160 ii = l | |
2161 me.edges.extend([i, ii]) | |
2162 i+=1 | |
2163 | |
2164 if __name__ == '__main__': | |
2165 main() | |
2166 */····· | |
2167 | |
2168 | |
2169 #undef ISECT_1 | |
2170 #undef ISECT_2 | |
2171 #undef ISECT_3 | |
2172 #undef ISECT_4 | |
2173 #undef ISECT_ALL3 | |
2174 #undef ISECT_ALL4 | |
2175 | |
2176 ········ | |
2177 /* checks if pt is inside a convex 2D polyline, the polyline must be ordered rot
ating clockwise | |
2178 * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases *
/ | |
2179 static int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) | |
2180 { | |
2181 int i; | |
2182 if (line_point_side_v2(uv[tot-1], uv[0], pt) < 0.0f) | |
2183 return 0; | |
2184 ········ | |
2185 for (i=1; i<tot; i++) { | |
2186 if (line_point_side_v2(uv[i-1], uv[i], pt) < 0.0f) | |
2187 return 0; | |
2188 ················ | |
2189 } | |
2190 ········ | |
2191 return 1; | |
2192 } | |
2193 static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot) | |
2194 { | |
2195 int i; | |
2196 int side = (line_point_side_v2(uv[tot-1], uv[0], pt) > 0.0f); | |
2197 ········ | |
2198 for (i=1; i<tot; i++) { | |
2199 if ((line_point_side_v2(uv[i-1], uv[i], pt) > 0.0f) != side) | |
2200 return 0; | |
2201 ················ | |
2202 } | |
2203 ········ | |
2204 return 1; | |
2205 } | |
2206 | |
2207 /* One of the most important function for projectiopn painting, since it selects
the pixels to be added into each bucket. | |
2208 * initialize pixels from this face where it intersects with the bucket_index, o
ptionally initialize pixels for removing seams */ | |
2209 static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
ndex, const int bucket_index, const int face_index, const int image_index, rctf
*bucket_bounds, const ImBuf *ibuf) | |
2210 { | |
2211 /* Projection vars, to get the 3D locations into screen space */ | |
2212 MemArena *arena = ps->arena_mt[thread_index]; | |
2213 LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index; | |
2214 LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index]; | |
2215 ········ | |
2216 const MFace *mf = ps->dm_mface + face_index; | |
2217 const MTFace *tf = ps->dm_mtface + face_index; | |
2218 ········ | |
2219 /* UV/pixel seeking data */ | |
2220 int x; /* Image X-Pixel */ | |
2221 int y;/* Image Y-Pixel */ | |
2222 float mask; | |
2223 float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0
*/ | |
2224 ········ | |
2225 int side; | |
2226 float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be
assigned to mf->v1,2,3 or mf->v1,3,4 */ | |
2227 ········ | |
2228 float *vCo[4]; /* vertex screenspace coords */ | |
2229 ········ | |
2230 float w[3], wco[3]; | |
2231 ········ | |
2232 float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be ass
igned to tf->uv[0],1,2 or tf->uv[0],2,3 */ | |
2233 float pixelScreenCo[4]; | |
2234 ········ | |
2235 rcti bounds_px; /* ispace bounds */ | |
2236 /* vars for getting uvspace bounds */ | |
2237 ········ | |
2238 float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init
pixels only for this face, */ | |
2239 float xhalfpx, yhalfpx; | |
2240 const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y; | |
2241 ········ | |
2242 int has_x_isect = 0, has_isect = 0; /* for early loop exit */ | |
2243 ········ | |
2244 int i1, i2, i3; | |
2245 ········ | |
2246 float uv_clip[8][2]; | |
2247 int uv_clip_tot; | |
2248 const short is_ortho = ps->is_ortho; | |
2249 const short do_backfacecull = ps->do_backfacecull; | |
2250 const short do_clip= ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; | |
2251 ········ | |
2252 vCo[0] = ps->dm_mvert[mf->v1].co; | |
2253 vCo[1] = ps->dm_mvert[mf->v2].co; | |
2254 vCo[2] = ps->dm_mvert[mf->v3].co; | |
2255 ········ | |
2256 ········ | |
2257 /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a p
ixel | |
2258 * this is done so we can avoid offseting all the pixels by 0.5 which ca
uses | |
2259 * problems when wrapping negative coords */ | |
2260 xhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/3.0f) ) / ibuf_xf; | |
2261 yhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/4.0f) ) / ibuf_yf; | |
2262 ········ | |
2263 /* Note about (PROJ_GEOM_TOLERANCE/x) above... | |
2264 Needed to add this offset since UV coords are often quads aligned to p
ixels. | |
2265 In this case pixels can be exactly between 2 triangles causing nasty | |
2266 artifacts. | |
2267 ·········· | |
2268 This workaround can be removed and painting will still work on most ca
ses | |
2269 but since the first thing most people try is painting onto a quad- bet
ter make it work. | |
2270 */ | |
2271 | |
2272 | |
2273 | |
2274 tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx; | |
2275 tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx; | |
2276 | |
2277 tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx; | |
2278 tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx; | |
2279 ········ | |
2280 tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx; | |
2281 tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx;·· | |
2282 ········ | |
2283 if (mf->v4) { | |
2284 vCo[3] = ps->dm_mvert[ mf->v4 ].co; | |
2285 ················ | |
2286 tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx; | |
2287 tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx; | |
2288 side = 1; | |
2289 } | |
2290 else { | |
2291 side = 0; | |
2292 } | |
2293 ········ | |
2294 do { | |
2295 if (side==1) { | |
2296 i1=0; i2=2; i3=3; | |
2297 } | |
2298 else { | |
2299 i1=0; i2=1; i3=2; | |
2300 } | |
2301 ················ | |
2302 uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1]; | |
2303 uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2]; | |
2304 uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3]; | |
2305 | |
2306 v1coSS = ps->screenCoords[ (*(&mf->v1 + i1)) ]; | |
2307 v2coSS = ps->screenCoords[ (*(&mf->v1 + i2)) ]; | |
2308 v3coSS = ps->screenCoords[ (*(&mf->v1 + i3)) ]; | |
2309 ················ | |
2310 /* This funtion gives is a concave polyline in UV space from the
clipped quad and tri*/ | |
2311 project_bucket_clip_face( | |
2312 is_ortho, bucket_bounds, | |
2313 v1coSS, v2coSS, v3coSS, | |
2314 uv1co, uv2co, uv3co, | |
2315 uv_clip, &uv_clip_tot | |
2316 ); | |
2317 | |
2318 /* sometimes this happens, better just allow for 8 intersectiosn
even though there should be max 6 */ | |
2319 /* | |
2320 if (uv_clip_tot>6) { | |
2321 printf("this should never happen! %d\n", uv_clip_tot); | |
2322 }*/ | |
2323 ················ | |
2324 | |
2325 if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv
_clip_tot)) { | |
2326 ························ | |
2327 /* clip face and */ | |
2328 ························ | |
2329 has_isect = 0; | |
2330 for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { | |
2331 //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; | |
2332 uv[1] = (float)y / ibuf_yf; /* use pixel offset
UV coords instead */ | |
2333 ································ | |
2334 has_x_isect = 0; | |
2335 for (x = bounds_px.xmin; x < bounds_px.xmax; x++
) { | |
2336 //uv[0] = (((float)x) + 0.5f) / ibuf->x; | |
2337 uv[0] = (float)x / ibuf_xf; /* use pixel
offset UV coords instead */ | |
2338 ········································ | |
2339 /* Note about IsectPoly2Df_twoside, chec
king the face or uv flipping doesnt work, | |
2340 * could check the poly direction but be
tter to do this */ | |
2341 if( (do_backfacecull
&& IsectPoly2Df(uv, uv_clip, uv_clip_tot)) || | |
2342 (do_backfacecull==0
&& IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) { | |
2343 ················································ | |
2344 has_x_isect = has_isect = 1; | |
2345 ················································ | |
2346 if (is_ortho) screen_px_from_o
rtho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); | |
2347 else screen_p
x_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); | |
2348 ················································ | |
2349 /* a pitty we need to get the wo
rldspace pixel location here */ | |
2350 if(do_clip) { | |
2351 interp_v3_v3v3v3(wco, ps
->dm_mvert[ (*(&mf->v1 + i1)) ].co, ps->dm_mvert[ (*(&mf->v1 + i2)) ].co, ps->dm
_mvert[ (*(&mf->v1 + i3)) ].co, w); | |
2352 if(ED_view3d_test_clippi
ng(ps->rv3d, wco, 1)) { | |
2353 continue; /* Wat
ch out that no code below this needs to run */ | |
2354 } | |
2355 } | |
2356 ················································ | |
2357 /* Is this UV visible from the v
iew? - raytrace */ | |
2358 /* project_paint_PickFace is les
s complex, use for testing */ | |
2359 //if (project_paint_PickFace(ps,
pixelScreenCo, w, &side) == face_index) { | |
2360 if (ps->do_occlude==0 || !projec
t_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) { | |
2361 ························································ | |
2362 mask = project_paint_uvp
ixel_mask(ps, face_index, side, w); | |
2363 ························································ | |
2364 if (mask > 0.0f) { | |
2365 BLI_linklist_pre
pend_arena( | |
2366 bucketPi
xelNodes, | |
2367 project_
paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelSc
reenCo, side, w), | |
2368 arena | |
2369 ); | |
2370 } | |
2371 } | |
2372 ················································ | |
2373 } | |
2374 //#if 0 | |
2375 else if (has_x_isect) { | |
2376 /* assuming the face is not a bo
w-tie - we know we cant intersect again on the X */ | |
2377 break; | |
2378 } | |
2379 //#endif | |
2380 } | |
2381 ································ | |
2382 ································ | |
2383 #if 0 /* TODO - investigate why this dosnt work sometimes! it
should! */ | |
2384 /* no intersection for this entire row, after so
me intersection above means we can quit now */ | |
2385 if (has_x_isect==0 && has_isect) {· | |
2386 break; | |
2387 } | |
2388 #endif | |
2389 } | |
2390 } | |
2391 } while(side--); | |
2392 | |
2393 ········ | |
2394 ········ | |
2395 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
2396 if (ps->seam_bleed_px > 0.0f) { | |
2397 int face_seam_flag; | |
2398 ················ | |
2399 if (ps->thread_tot > 1) | |
2400 BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be
modifying these vars */ | |
2401 ················ | |
2402 face_seam_flag = ps->faceSeamFlags[face_index]; | |
2403 ················ | |
2404 /* are any of our edges un-initialized? */ | |
2405 if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 ||········ | |
2406 (face_seam_flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==
0 ||· | |
2407 (face_seam_flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==
0 ||· | |
2408 (face_seam_flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==
0 | |
2409 ) { | |
2410 project_face_seams_init(ps, face_index, mf->v4); | |
2411 face_seam_flag = ps->faceSeamFlags[face_index]; | |
2412 //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1,
flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4); | |
2413 } | |
2414 ················ | |
2415 if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE
_SEAM3|PROJ_FACE_SEAM4))==0) { | |
2416 ························ | |
2417 if (ps->thread_tot > 1) | |
2418 BLI_unlock_thread(LOCK_CUSTOM1); /* Other thread
s could be modifying these vars */ | |
2419 ························ | |
2420 } | |
2421 else { | |
2422 /* we have a seam - deal with it! */ | |
2423 ························ | |
2424 /* Now create new UV's for the seam face */ | |
2425 float (*outset_uv)[2] = ps->faceSeamUVs[face_index]; | |
2426 float insetCos[4][3]; /* inset face coords. NOTE!!! Scr
eenSace for ortho, Worldspace in prespective view */ | |
2427 | |
2428 float fac; | |
2429 float *vCoSS[4]; /* vertex screenspace coords */ | |
2430 ························ | |
2431 float bucket_clip_edges[2][2]; /* store the screenspace
coords of the face, clipped by the bucket's screen aligned rectangle */ | |
2432 float edge_verts_inset_clip[2][3]; | |
2433 int fidx1, fidx2; /* face edge pairs - loop throuh these
((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */ | |
2434 ························ | |
2435 float seam_subsection[4][2]; | |
2436 float fac1, fac2, ftot; | |
2437 ························ | |
2438 ························ | |
2439 if (outset_uv[0][0]==FLT_MAX) /* first time initialize *
/ | |
2440 uv_image_outset(tf_uv_pxoffset, outset_uv, ps->s
eam_bleed_px, ibuf->x, ibuf->y, mf->v4); | |
2441 ························ | |
2442 /* ps->faceSeamUVs cant be modified when threading, now
this is done we can unlock */ | |
2443 if (ps->thread_tot > 1) | |
2444 BLI_unlock_thread(LOCK_CUSTOM1); /* Other thread
s could be modifying these vars */ | |
2445 ························ | |
2446 vCoSS[0] = ps->screenCoords[mf->v1]; | |
2447 vCoSS[1] = ps->screenCoords[mf->v2]; | |
2448 vCoSS[2] = ps->screenCoords[mf->v3]; | |
2449 if (mf->v4) | |
2450 vCoSS[3] = ps->screenCoords[ mf->v4 ]; | |
2451 ························ | |
2452 /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f
*/ | |
2453 if (is_ortho) { | |
2454 if (mf->v4) scale_quad(insetCos, vCoSS, PROJ
_FACE_SCALE_SEAM); | |
2455 else scale_tri(insetCos, vCoSS, PROJ_
FACE_SCALE_SEAM); | |
2456 } | |
2457 else { | |
2458 if (mf->v4) scale_quad(insetCos, vCo, PROJ_F
ACE_SCALE_SEAM); | |
2459 else scale_tri(insetCos, vCo, PROJ_FA
CE_SCALE_SEAM); | |
2460 } | |
2461 ························ | |
2462 side = 0; /* for triangles this wont need to change */ | |
2463 ························ | |
2464 for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) { | |
2465 if (mf->v4) fidx2 = (fidx1==3) ? 0 :
fidx1+1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */ | |
2466 else fidx2 = (fidx1==2) ? 0 :
fidx1+1; /* next fidx in the face (0,1,2) -> (1,2,0) */ | |
2467 ································ | |
2468 if ( (face_seam_flag & (1<<fidx1)) && /* 1<<f
idx1 -> PROJ_FACE_SEAM# */ | |
2469 line_clip_rect2f(bucket_bounds,
vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]) | |
2470 ) { | |
2471 | |
2472 ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx
2]); /* screenspace edge length */ | |
2473 ········································ | |
2474 if (ftot > 0.0f) { /* avoid div by zero
*/ | |
2475 if (mf->v4) { | |
2476 if (fidx1==2 || fidx2==2
) side= 1; | |
2477 else
side= 0; | |
2478 } | |
2479 ················································ | |
2480 fac1 = len_v2v2(vCoSS[fidx1], bu
cket_clip_edges[0]) / ftot; | |
2481 fac2 = len_v2v2(vCoSS[fidx1], bu
cket_clip_edges[1]) / ftot; | |
2482 ················································ | |
2483 interp_v2_v2v2(seam_subsection[0
], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1); | |
2484 interp_v2_v2v2(seam_subsection[1
], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2); | |
2485 | |
2486 interp_v2_v2v2(seam_subsection[2
], outset_uv[fidx1], outset_uv[fidx2], fac2); | |
2487 interp_v2_v2v2(seam_subsection[3
], outset_uv[fidx1], outset_uv[fidx2], fac1); | |
2488 ················································ | |
2489 /* if the bucket_clip_edges valu
es Z values was kept we could avoid this | |
2490 * Inset needs to be added so oc
clusion tests wont hit adjacent faces */ | |
2491 interp_v3_v3v3(edge_verts_inset_
clip[0], insetCos[fidx1], insetCos[fidx2], fac1); | |
2492 interp_v3_v3v3(edge_verts_inset_
clip[1], insetCos[fidx1], insetCos[fidx2], fac2); | |
2493 ················································ | |
2494 | |
2495 if (pixel_bounds_uv(seam_subsect
ion[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px,
ibuf->x, ibuf->y, 1)) { | |
2496 /* bounds between the se
am rect and the uvspace bucket pixels */ | |
2497 ························································ | |
2498 has_isect = 0; | |
2499 for (y = bounds_px.ymin;
y < bounds_px.ymax; y++) { | |
2500 // uv[1] = (((fl
oat)y) + 0.5f) / (float)ibuf->y; | |
2501 uv[1] = (float)y
/ ibuf_yf; /* use offset uvs instead */ | |
2502 ································································ | |
2503 has_x_isect = 0; | |
2504 for (x = bounds_
px.xmin; x < bounds_px.xmax; x++) { | |
2505 //uv[0]
= (((float)x) + 0.5f) / (float)ibuf->x; | |
2506 uv[0] =
(float)x / ibuf_xf; /* use offset uvs instead */ | |
2507 ········································································ | |
2508 /* test
we're inside uvspace bucket and triangle bounds */ | |
2509 if (isec
t_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2],
seam_subsection[3])) { | |
2510 ················································································ | |
2511
/* We need to find the closest point along the face edge, | |
2512
* getting the screen_px_from_*** wont work because our actual location | |
2513
* is not relevent, since we are outside the face, Use VecLerpf to find | |
2514
* our location on the side of the face's UV */ | |
2515
/* | |
2516
if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3
co, pixelScreenCo); | |
2517
else screen_px_from_persp(ps, uv, v1co, v2co,
v3co, uv1co, uv2co, uv3co, pixelScreenCo); | |
2518
*/ | |
2519 ················································································ | |
2520
/* Since this is a seam we need to work out where on the line this pixel is */ | |
2521
//fac = lambda_cp_line2(uv, uv_seam_quad[0], uv_seam_quad[1]); | |
2522 ················································································ | |
2523
fac = lambda_cp_line2(uv, seam_subsection[0], seam_subsection[1]); | |
2524
if (fac < 0.0f) { VECCOPY(pixelScreenCo, edge_verts_inset_clip[0]); } | |
2525
else if (fac > 1.0f) { VECCOPY(pixelScreenCo, edge_verts_inset_clip[1]); } | |
2526
else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset
_clip[0], edge_verts_inset_clip[1], fac); } | |
2527 ················································································ | |
2528
if (!is_ortho) { | |
2529
pixelScreenCo[3] = 1.0f; | |
2530
mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because o
f const */ | |
2531
pixelScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*pixelScreenCo[
0]/pixelScreenCo[3]; | |
2532
pixelScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*pixelScreenCo[
1]/pixelScreenCo[3]; | |
2533
pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth f
or bucket point occlusion */ | |
2534
} | |
2535 ················································································ | |
2536
if (ps->do_occlude==0 || !project_bucket_point_occluded(ps, bucketFaceNodes, fac
e_index, pixelScreenCo)) { | |
2537 ······························································································· | |
2538
/* Only bother calculating the weights if we intersect */ | |
2539
if (ps->do_mask_normal || ps->dm_mtface_clone) { | |
2540 #if 1 | |
2541
/* get the UV on the line since we want to copy the pixels from
there for bleeding */ | |
2542
float uv_close[2]; | |
2543
float fac= closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1
], tf_uv_pxoffset[fidx2]); | |
2544
if (fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset
[fidx1]); | |
2545
else if (fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2])
; | |
2546 | |
2547
if (side) { | |
2548
barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset
[2], tf_uv_pxoffset[3], uv_close, w); | |
2549
} | |
2550
else { | |
2551
barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset
[1], tf_uv_pxoffset[2], uv_close, w); | |
2552
} | |
2553 #else
/* this is buggy with quads, dont use for now */ | |
2554 | |
2555
/* Cheat, we know where we are along the edge so work out the we
ights from that */ | |
2556
fac = fac1 + (fac * (fac2-fac1)); | |
2557 | |
2558
w[0]=w[1]=w[2]= 0.0; | |
2559
if (side) { | |
2560
w[fidx1?fidx1-1:0] = 1.0f-fac; | |
2561
w[fidx2?fidx2-1:0] = fac; | |
2562
} | |
2563
else { | |
2564
w[fidx1] = 1.0f-fac; | |
2565
w[fidx2] = fac; | |
2566
} | |
2567 #endif | |
2568
} | |
2569 ······························································································· | |
2570
/* a pitty we need to get the worldspace pixel location here */ | |
2571
if(do_clip) { | |
2572
if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, p
s->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); | |
2573
else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, p
s->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); | |
2574 | |
2575
if(ED_view3d_test_clipping(ps->rv3d, wco, 1)) { | |
2576
continue; /* Watch out that no code below this needs to
run */ | |
2577
} | |
2578
} | |
2579 ······························································································· | |
2580
mask = project_paint_uvpixel_mask(ps, face_index, side, w); | |
2581 ······························································································· | |
2582
if (mask > 0.0f) { | |
2583
BLI_linklist_prepend_arena( | |
2584
bucketPixelNodes, | |
2585
project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask,
face_index, image_index, pixelScreenCo, side, w), | |
2586
arena | |
2587
); | |
2588
} | |
2589 ······························································································· | |
2590
} | |
2591 } | |
2592 else if
(has_x_isect) { | |
2593
/* assuming the face is not a bow-tie - we know we cant intersect again on the X
*/ | |
2594
break; | |
2595 } | |
2596 } | |
2597 ································································ | |
2598 #if 0 /* TODO - investigate wh
y this dosnt work sometimes! it should! */ | |
2599 /* no intersecti
on for this entire row, after some intersection above means we can quit now */ | |
2600 if (has_x_isect=
=0 && has_isect) {· | |
2601 break; | |
2602 } | |
2603 #endif | |
2604 } | |
2605 } | |
2606 } | |
2607 } | |
2608 } | |
2609 } | |
2610 } | |
2611 #endif // PROJ_DEBUG_NOSEAMBLEED | |
2612 } | |
2613 | |
2614 | |
2615 /* takes floating point screenspace min/max and returns int min/max to be used a
s indices for ps->bucketRect, ps->bucketFlags */ | |
2616 static void project_paint_bucket_bounds(const ProjPaintState *ps, const float mi
n[2], const float max[2], int bucketMin[2], int bucketMax[2]) | |
2617 { | |
2618 /* divide by bucketWidth & bucketHeight so the bounds are offset in buck
et grid units */ | |
2619 /* XXX: the offset of 0.5 is always truncated to zero and the offset of
1.5f is always truncated to 1, is this really correct?? - jwilkins */ | |
2620 bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->scr
een_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd bu
t they are correct */ | |
2621 bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->scr
een_height) * ps->buckets_y) + 0.5f); | |
2622 ········ | |
2623 bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->scr
een_width) * ps->buckets_x) + 1.5f); | |
2624 bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->scr
een_height) * ps->buckets_y) + 1.5f); | |
2625 ········ | |
2626 /* incase the rect is outside the mesh 2d bounds */ | |
2627 CLAMP(bucketMin[0], 0, ps->buckets_x); | |
2628 CLAMP(bucketMin[1], 0, ps->buckets_y); | |
2629 ········ | |
2630 CLAMP(bucketMax[0], 0, ps->buckets_x); | |
2631 CLAMP(bucketMax[1], 0, ps->buckets_y); | |
2632 } | |
2633 | |
2634 /* set bucket_bounds to a screen space-aligned floating point bound-box */ | |
2635 static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x,
const int bucket_y, rctf *bucket_bounds) | |
2636 { | |
2637 bucket_bounds->xmin = ps->screenMin[0]+((bucket_x)*(ps->screen_width /
ps->buckets_x)); /* left */ | |
2638 bucket_bounds->xmax = ps->screenMin[0]+((bucket_x+1)*(ps->screen_width
/ ps->buckets_x)); /* right */ | |
2639 ········ | |
2640 bucket_bounds->ymin = ps->screenMin[1]+((bucket_y)*(ps->screen_height
/ ps->buckets_y)); /* bottom */ | |
2641 bucket_bounds->ymax = ps->screenMin[1]+((bucket_y+1)*(ps->screen_heigh
t / ps->buckets_y)); /* top */ | |
2642 } | |
2643 | |
2644 /* Fill this bucket with pixels from the faces that intersect it. | |
2645 *· | |
2646 * have bucket_bounds as an argument so we don;t need to give bucket_x/y the rec
t function needs */ | |
2647 static void project_bucket_init(const ProjPaintState *ps, const int thread_index
, const int bucket_index, rctf *bucket_bounds) | |
2648 { | |
2649 LinkNode *node; | |
2650 int face_index, image_index=0; | |
2651 ImBuf *ibuf = NULL; | |
2652 MTFace *tf; | |
2653 ········ | |
2654 Image *tpage_last = NULL; | |
2655 ········ | |
2656 | |
2657 if (ps->image_tot==1) { | |
2658 /* Simple loop, no context switching */ | |
2659 ibuf = ps->projImages[0].ibuf; | |
2660 ················ | |
2661 for (node = ps->bucketFaces[bucket_index]; node; node= node->nex
t) {· | |
2662 project_paint_face_init(ps, thread_index, bucket_index,
GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf); | |
2663 } | |
2664 } | |
2665 else { | |
2666 ················ | |
2667 /* More complicated loop, switch between images */ | |
2668 for (node = ps->bucketFaces[bucket_index]; node; node= node->nex
t) { | |
2669 face_index = GET_INT_FROM_POINTER(node->link); | |
2670 ································ | |
2671 /* Image context switching */ | |
2672 tf = ps->dm_mtface+face_index; | |
2673 if (tpage_last != tf->tpage) { | |
2674 tpage_last = tf->tpage; | |
2675 ································ | |
2676 image_index = -1; /* sanity check */ | |
2677 ································ | |
2678 for (image_index=0; image_index < ps->image_tot;
image_index++) { | |
2679 if (ps->projImages[image_index].ima == t
page_last) { | |
2680 ibuf = ps->projImages[image_inde
x].ibuf; | |
2681 break; | |
2682 } | |
2683 } | |
2684 } | |
2685 /* context switching done */ | |
2686 ························ | |
2687 project_paint_face_init(ps, thread_index, bucket_index,
face_index, image_index, bucket_bounds, ibuf); | |
2688 ························ | |
2689 } | |
2690 } | |
2691 ········ | |
2692 ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT; | |
2693 } | |
2694 | |
2695 | |
2696 /* We want to know if a bucket and a face overlap in screen-space | |
2697 *· | |
2698 * Note, if this ever returns false positives its not that bad, since a face in
the bounding area will have its pixels | |
2699 * calculated when it might not be needed later, (at the moment at least) | |
2700 * obviously it shouldn't have bugs though */ | |
2701 | |
2702 static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucke
t_y, const MFace *mf) | |
2703 { | |
2704 /* TODO - replace this with a tricker method that uses sideofline for al
l screenCoords's edges against the closest bucket corner */ | |
2705 rctf bucket_bounds; | |
2706 float p1[2], p2[2], p3[2], p4[2]; | |
2707 float *v, *v1,*v2,*v3,*v4=NULL; | |
2708 int fidx; | |
2709 ········ | |
2710 project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds); | |
2711 ········ | |
2712 /* Is one of the faces verts in the bucket bounds? */ | |
2713 ········ | |
2714 fidx = mf->v4 ? 3:2; | |
2715 do { | |
2716 v = ps->screenCoords[ (*(&mf->v1 + fidx)) ]; | |
2717 if (BLI_in_rctf(&bucket_bounds, v[0], v[1])) { | |
2718 return 1; | |
2719 } | |
2720 } while (fidx--); | |
2721 ········ | |
2722 v1 = ps->screenCoords[mf->v1]; | |
2723 v2 = ps->screenCoords[mf->v2]; | |
2724 v3 = ps->screenCoords[mf->v3]; | |
2725 if (mf->v4) { | |
2726 v4 = ps->screenCoords[mf->v4]; | |
2727 } | |
2728 ········ | |
2729 p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin; | |
2730 p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax; | |
2731 p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax; | |
2732 p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin; | |
2733 ················ | |
2734 if (mf->v4) { | |
2735 if( isect_point_quad_v2(p1, v1, v2, v3, v4) || isect_point_q
uad_v2(p2, v1, v2, v3, v4) || isect_point_quad_v2(p3, v1, v2, v3, v4) || isect_p
oint_quad_v2(p4, v1, v2, v3, v4) || | |
2736 /* we can avoid testing v3,v1 because another intersecti
on MUST exist if this intersects */ | |
2737 (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v
2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) || | |
2738 (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v
2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) || | |
2739 (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v
2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) || | |
2740 (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v
2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4)) | |
2741 ) { | |
2742 return 1; | |
2743 } | |
2744 } | |
2745 else { | |
2746 if( isect_point_tri_v2(p1, v1, v2, v3) || isect_point_tri_v2
(p2, v1, v2, v3) || isect_point_tri_v2(p3, v1, v2, v3) || isect_point_tri_v2(p4,
v1, v2, v3) || | |
2747 /* we can avoid testing v3,v1 because another intersecti
on MUST exist if this intersects */ | |
2748 (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v
2(p1, p2, v2, v3)) || | |
2749 (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v
2(p2, p3, v2, v3)) || | |
2750 (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v
2(p3, p4, v2, v3)) || | |
2751 (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v
2(p4, p1, v2, v3)) | |
2752 ) { | |
2753 return 1; | |
2754 } | |
2755 } | |
2756 | |
2757 return 0; | |
2758 } | |
2759 | |
2760 /* Add faces to the bucket but dont initialize its pixels | |
2761 * TODO - when painting occluded, sort the faces on their min-Z and only add fac
es that faces that are not occluded */ | |
2762 static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
const int face_index) | |
2763 { | |
2764 float min[2], max[2], *vCoSS; | |
2765 int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */ | |
2766 int fidx, bucket_x, bucket_y; | |
2767 int has_x_isect = -1, has_isect = 0; /* for early loop exit */ | |
2768 MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena si
nce threading has not started yet */ | |
2769 ········ | |
2770 INIT_MINMAX2(min, max); | |
2771 ········ | |
2772 fidx = mf->v4 ? 3:2; | |
2773 do { | |
2774 vCoSS = ps->screenCoords[ *(&mf->v1 + fidx) ]; | |
2775 DO_MINMAX2(vCoSS, min, max); | |
2776 } while (fidx--); | |
2777 ········ | |
2778 project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax); | |
2779 ········ | |
2780 for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) { | |
2781 has_x_isect = 0; | |
2782 for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x+
+) { | |
2783 if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf
)) { | |
2784 int bucket_index= bucket_x + (bucket_y * ps->buc
kets_x); | |
2785 BLI_linklist_prepend_arena( | |
2786 &ps->bucketFaces[ bucket_index ], | |
2787 SET_INT_IN_POINTER(face_index), /* cast
to a pointer to shut up the compiler */ | |
2788 arena | |
2789 ); | |
2790 ································ | |
2791 has_x_isect = has_isect = 1; | |
2792 } | |
2793 else if (has_x_isect) { | |
2794 /* assuming the face is not a bow-tie - we know
we cant intersect again on the X */ | |
2795 break; | |
2796 } | |
2797 } | |
2798 ················ | |
2799 /* no intersection for this entire row, after some intersection
above means we can quit now */ | |
2800 if (has_x_isect==0 && has_isect) {· | |
2801 break; | |
2802 } | |
2803 } | |
2804 ········ | |
2805 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
2806 if (ps->seam_bleed_px > 0.0f) { | |
2807 if (!mf->v4) { | |
2808 ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* s
o this wont show up as an untagged edge */ | |
2809 } | |
2810 **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized
*/ | |
2811 } | |
2812 #endif | |
2813 } | |
2814 | |
2815 static int project_paint_view_clip(View3D *v3d, RegionView3D *rv3d, float *clips
ta, float *clipend) | |
2816 { | |
2817 int orth= ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend); | |
2818 | |
2819 if (orth) { /* only needed for ortho */ | |
2820 float fac = 2.0f / ((*clipend) - (*clipsta)); | |
2821 *clipsta *= fac; | |
2822 *clipend *= fac; | |
2823 } | |
2824 | |
2825 return orth; | |
2826 } | |
2827 | |
2828 /* run once per stroke before projection painting */ | |
2829 static void project_paint_begin(ProjPaintState *ps) | |
2830 {······· | |
2831 /* Viewport vars */ | |
2832 float mat[3][3]; | |
2833 ········ | |
2834 float no[3]; | |
2835 ········ | |
2836 float *projScreenCo; /* Note, we could have 4D vectors are only needed f
or */ | |
2837 float projMargin; | |
2838 | |
2839 /* Image Vars - keep track of images we have used */ | |
2840 LinkNode *image_LinkList = NULL; | |
2841 LinkNode *node; | |
2842 ········ | |
2843 ProjPaintImage *projIma; | |
2844 Image *tpage_last = NULL; | |
2845 ········ | |
2846 /* Face vars */ | |
2847 MFace *mf; | |
2848 MTFace *tf; | |
2849 ········ | |
2850 int a, i; /* generic looping vars */ | |
2851 int image_index = -1, face_index; | |
2852 MVert *mv; | |
2853 ········ | |
2854 MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use
this to show were not multithreading */ | |
2855 | |
2856 const int diameter= 2*brush_size(ps->brush); | |
2857 ········ | |
2858 /* ---- end defines ---- */ | |
2859 ········ | |
2860 if(ps->source==PROJ_SRC_VIEW) | |
2861 ED_view3d_local_clipping(ps->rv3d, ps->ob->obmat); /* faster cli
pping lookups */ | |
2862 | |
2863 /* paint onto the derived mesh */ | |
2864 ········ | |
2865 /* Workaround for subsurf selection, try the display mesh first */ | |
2866 if (ps->source==PROJ_SRC_IMAGE_CAM) { | |
2867 /* using render mesh, assume only camera was rendered from */ | |
2868 ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene
->customdata_mask | CD_MASK_MTFACE); | |
2869 ps->dm_release= TRUE; | |
2870 } | |
2871 else if(ps->ob->derivedFinal && CustomData_has_layer( &ps->ob->derivedFi
nal->faceData, CD_MTFACE)) { | |
2872 ps->dm = ps->ob->derivedFinal; | |
2873 ps->dm_release= FALSE; | |
2874 } | |
2875 else { | |
2876 ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->cu
stomdata_mask | CD_MASK_MTFACE); | |
2877 ps->dm_release= TRUE; | |
2878 } | |
2879 ········ | |
2880 if ( !CustomData_has_layer( &ps->dm->faceData, CD_MTFACE) ) { | |
2881 ················ | |
2882 if(ps->dm_release) | |
2883 ps->dm->release(ps->dm); | |
2884 ················ | |
2885 ps->dm = NULL; | |
2886 return;· | |
2887 } | |
2888 ········ | |
2889 ps->dm_mvert = ps->dm->getVertArray(ps->dm); | |
2890 ps->dm_mface = ps->dm->getFaceArray(ps->dm); | |
2891 ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE); | |
2892 ········ | |
2893 ps->dm_totvert = ps->dm->getNumVerts(ps->dm); | |
2894 ps->dm_totface = ps->dm->getNumFaces(ps->dm); | |
2895 ········ | |
2896 /* use clone mtface? */ | |
2897 ········ | |
2898 ········ | |
2899 /* Note, use the original mesh for getting the clone and mask layer inde
x | |
2900 * this avoids re-generating the derived mesh just to get the new index
*/ | |
2901 if (ps->do_layer_clone) { | |
2902 //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData,
CD_MTFACE); | |
2903 int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->dat
a)->fdata, CD_MTFACE); | |
2904 if (layer_num != -1) | |
2905 ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->fa
ceData, CD_MTFACE, layer_num); | |
2906 ················ | |
2907 if (ps->dm_mtface_clone==NULL || ps->dm_mtface_clone==ps->dm_mtf
ace) { | |
2908 ps->do_layer_clone = 0; | |
2909 ps->dm_mtface_clone= NULL; | |
2910 printf("ACK!\n"); | |
2911 } | |
2912 } | |
2913 ········ | |
2914 if (ps->do_layer_stencil) { | |
2915 //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData
, CD_MTFACE); | |
2916 int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->d
ata)->fdata, CD_MTFACE); | |
2917 if (layer_num != -1) | |
2918 ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->
faceData, CD_MTFACE, layer_num); | |
2919 ················ | |
2920 if (ps->dm_mtface_stencil==NULL || ps->dm_mtface_stencil==ps->dm
_mtface) { | |
2921 ps->do_layer_stencil = 0; | |
2922 ps->dm_mtface_stencil = NULL; | |
2923 } | |
2924 } | |
2925 ········ | |
2926 /* when using subsurf or multires, mface arrays are thrown away, we need
to keep a copy */ | |
2927 if(ps->dm->type != DM_TYPE_CDDM) { | |
2928 ps->dm_mvert= MEM_dupallocN(ps->dm_mvert); | |
2929 ps->dm_mface= MEM_dupallocN(ps->dm_mface); | |
2930 /* looks like these are ok for now.*/ | |
2931 /* | |
2932 ps->dm_mtface= MEM_dupallocN(ps->dm_mtface); | |
2933 ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone); | |
2934 ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil); | |
2935 */ | |
2936 } | |
2937 ········ | |
2938 ps->viewDir[0] = 0.0f; | |
2939 ps->viewDir[1] = 0.0f; | |
2940 ps->viewDir[2] = 1.0f; | |
2941 ········ | |
2942 { | |
2943 float viewmat[4][4]; | |
2944 float viewinv[4][4]; | |
2945 | |
2946 invert_m4_m4(ps->ob->imat, ps->ob->obmat); | |
2947 | |
2948 if(ps->source==PROJ_SRC_VIEW) { | |
2949 /* normal drawing */ | |
2950 ps->winx= ps->ar->winx; | |
2951 ps->winy= ps->ar->winy; | |
2952 | |
2953 copy_m4_m4(viewmat, ps->rv3d->viewmat); | |
2954 copy_m4_m4(viewinv, ps->rv3d->viewinv); | |
2955 | |
2956 ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->proje
ctMat); | |
2957 | |
2958 ps->is_ortho= project_paint_view_clip(ps->v3d, ps->rv3d,
&ps->clipsta, &ps->clipend); | |
2959 } | |
2960 else { | |
2961 /* reprojection */ | |
2962 float winmat[4][4]; | |
2963 float vmat[4][4]; | |
2964 | |
2965 ps->winx= ps->reproject_ibuf->x; | |
2966 ps->winy= ps->reproject_ibuf->y; | |
2967 | |
2968 if (ps->source==PROJ_SRC_IMAGE_VIEW) { | |
2969 /* image stores camera data, tricky */ | |
2970 IDProperty *idgroup= IDP_GetProperties(&ps->repr
oject_image->id, 0); | |
2971 IDProperty *view_data= IDP_GetPropertyFromGroup(
idgroup, PROJ_VIEW_DATA_ID); | |
2972 | |
2973 float *array= (float *)IDP_Array(view_data); | |
2974 | |
2975 /* use image array, written when creating image
*/ | |
2976 memcpy(winmat, array, sizeof(winmat)); array +=
sizeof(winmat)/sizeof(float); | |
2977 memcpy(viewmat, array, sizeof(viewmat)); array +
= sizeof(viewmat)/sizeof(float); | |
2978 ps->clipsta= array[0]; | |
2979 ps->clipend= array[1]; | |
2980 ps->is_ortho= array[2] ? 1:0; | |
2981 | |
2982 invert_m4_m4(viewinv, viewmat); | |
2983 } | |
2984 else if (ps->source==PROJ_SRC_IMAGE_CAM) { | |
2985 Object *camera= ps->scene->camera; | |
2986 | |
2987 /* dont actually use these */ | |
2988 float _viewdx, _viewdy, _ycor, _lens=0.0f; | |
2989 rctf _viewplane; | |
2990 | |
2991 /* viewmat & viewinv */ | |
2992 copy_m4_m4(viewinv, ps->scene->camera->obmat); | |
2993 normalize_m4(viewinv); | |
2994 invert_m4_m4(viewmat, viewinv); | |
2995 | |
2996 /* camera winmat */ | |
2997 object_camera_mode(&ps->scene->r, camera); | |
2998 object_camera_matrix(&ps->scene->r, camera, ps->
winx, ps->winy, 0, | |
2999 winmat, &_viewplane, &ps->clipst
a, &ps->clipend, | |
3000 &_lens, &_ycor, &_viewdx, &_view
dy); | |
3001 | |
3002 ps->is_ortho= (ps->scene->r.mode & R_ORTHO) ? 1
: 0; | |
3003 } | |
3004 | |
3005 /* same as view3d_get_object_project_mat */ | |
3006 mul_m4_m4m4(vmat, ps->ob->obmat, viewmat); | |
3007 mul_m4_m4m4(ps->projectMat, vmat, winmat); | |
3008 } | |
3009 | |
3010 | |
3011 /* viewDir - object relative */ | |
3012 invert_m4_m4(ps->ob->imat, ps->ob->obmat); | |
3013 copy_m3_m4(mat, viewinv); | |
3014 mul_m3_v3(mat, ps->viewDir); | |
3015 copy_m3_m4(mat, ps->ob->imat); | |
3016 mul_m3_v3(mat, ps->viewDir); | |
3017 normalize_v3(ps->viewDir); | |
3018 ················ | |
3019 /* viewPos - object relative */ | |
3020 VECCOPY(ps->viewPos, viewinv[3]); | |
3021 copy_m3_m4(mat, ps->ob->imat); | |
3022 mul_m3_v3(mat, ps->viewPos); | |
3023 add_v3_v3(ps->viewPos, ps->ob->imat[3]); | |
3024 } | |
3025 ········ | |
3026 /* calculate vert screen coords | |
3027 * run this early so we can calculate the x/y resolution of our bucket r
ect */ | |
3028 INIT_MINMAX2(ps->screenMin, ps->screenMax); | |
3029 ········ | |
3030 ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "Proj
ectPaint ScreenVerts"); | |
3031 projScreenCo= *ps->screenCoords; | |
3032 ········ | |
3033 if (ps->is_ortho) { | |
3034 for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScr
eenCo+=4) { | |
3035 mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co); | |
3036 ························ | |
3037 /* screen space, not clamped */ | |
3038 projScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)
*projScreenCo[0]; | |
3039 projScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)
*projScreenCo[1]; | |
3040 DO_MINMAX2(projScreenCo, ps->screenMin, ps->screenMax); | |
3041 } | |
3042 } | |
3043 else { | |
3044 for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScr
eenCo+=4) { | |
3045 copy_v3_v3(projScreenCo, mv->co); | |
3046 projScreenCo[3] = 1.0f; | |
3047 | |
3048 mul_m4_v4(ps->projectMat, projScreenCo); | |
3049 | |
3050 if (projScreenCo[3] > ps->clipsta) { | |
3051 /* screen space, not clamped */ | |
3052 projScreenCo[0] = (float)(ps->winx/2.0f)+(ps->wi
nx/2.0f)*projScreenCo[0]/projScreenCo[3]; | |
3053 projScreenCo[1] = (float)(ps->winy/2.0f)+(ps->wi
ny/2.0f)*projScreenCo[1]/projScreenCo[3]; | |
3054 projScreenCo[2] = projScreenCo[2]/projScreenCo[3
]; /* Use the depth for bucket point occlusion */ | |
3055 DO_MINMAX2(projScreenCo, ps->screenMin, ps->scre
enMax); | |
3056 } | |
3057 else { | |
3058 /* TODO - deal with cases where 1 side of a face
goes behind the view ? | |
3059 *· | |
3060 * After some research this is actually very tri
cky, only option is to | |
3061 * clip the derived mesh before painting, which
is a Pain */ | |
3062 projScreenCo[0] = FLT_MAX; | |
3063 } | |
3064 } | |
3065 } | |
3066 ········ | |
3067 /* If this border is not added we get artifacts for faces that | |
3068 * have a parallel edge and at the bounds of the the 2D projected verts
eg | |
3069 * - a single screen aligned quad */ | |
3070 projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f; | |
3071 ps->screenMax[0] += projMargin; | |
3072 ps->screenMin[0] -= projMargin; | |
3073 projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f; | |
3074 ps->screenMax[1] += projMargin; | |
3075 ps->screenMin[1] -= projMargin; | |
3076 ········ | |
3077 if(ps->source==PROJ_SRC_VIEW) { | |
3078 #ifdef PROJ_DEBUG_WINCLIP | |
3079 CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + d
iameter)); | |
3080 CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + d
iameter)); | |
3081 | |
3082 CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + d
iameter)); | |
3083 CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + d
iameter)); | |
3084 #endif | |
3085 } | |
3086 else { /* reprojection, use bounds */ | |
3087 ps->screenMin[0]= 0; | |
3088 ps->screenMax[0]= (float)(ps->winx); | |
3089 | |
3090 ps->screenMin[1]= 0; | |
3091 ps->screenMax[1]= (float)(ps->winy); | |
3092 } | |
3093 | |
3094 /* only for convenience */ | |
3095 ps->screen_width = ps->screenMax[0] - ps->screenMin[0]; | |
3096 ps->screen_height = ps->screenMax[1] - ps->screenMin[1]; | |
3097 ········ | |
3098 ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKE
T_BRUSH_DIV)); | |
3099 ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCK
ET_BRUSH_DIV)); | |
3100 ········ | |
3101 /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps
->buckets_y); */ | |
3102 ········ | |
3103 /* really high values could cause problems since it has to allocate a fe
w | |
3104 * (ps->buckets_x*ps->buckets_y) sized arrays */ | |
3105 CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); | |
3106 CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); | |
3107 ········ | |
3108 ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->bucke
ts_x * ps->buckets_y, "paint-bucketRect"); | |
3109 ps->bucketFaces= (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->bucke
ts_x * ps->buckets_y, "paint-bucketFaces"); | |
3110 ········ | |
3111 ps->bucketFlags= (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets
_x * ps->buckets_y, "paint-bucketFaces"); | |
3112 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
3113 if (ps->seam_bleed_px > 0.0f) { | |
3114 ps->vertFaces= (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps-
>dm_totvert, "paint-vertFaces"); | |
3115 ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_to
tface, "paint-faceSeamFlags"); | |
3116 ps->faceSeamUVs= MEM_mallocN(sizeof(float) * ps->dm_totface * 8,
"paint-faceSeamUVs"); | |
3117 } | |
3118 #endif | |
3119 ········ | |
3120 /* Thread stuff | |
3121 *· | |
3122 * very small brushes run a lot slower multithreaded since the advantage
with | |
3123 * threads is being able to fill in multiple buckets at once. | |
3124 * Only use threads for bigger brushes. */ | |
3125 ········ | |
3126 if (ps->scene->r.mode & R_FIXED_THREADS) { | |
3127 ps->thread_tot = ps->scene->r.threads; | |
3128 } | |
3129 else { | |
3130 ps->thread_tot = BLI_system_thread_count(); | |
3131 } | |
3132 for (a=0; a<ps->thread_tot; a++) { | |
3133 ps->arena_mt[a] = BLI_memarena_new(1<<16, "project paint arena")
; | |
3134 } | |
3135 ········ | |
3136 arena = ps->arena_mt[0];· | |
3137 ········ | |
3138 if (ps->do_backfacecull && ps->do_mask_normal) { | |
3139 float viewDirPersp[3]; | |
3140 ················ | |
3141 ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "pain
t-vertFlags"); | |
3142 ················ | |
3143 for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++) { | |
3144 normal_short_to_float_v3(no, mv->no); | |
3145 ························ | |
3146 if (ps->is_ortho) { | |
3147 if (angle_normalized_v3v3(ps->viewDir, no) >= ps
->normal_angle) { /* 1 vert of this face is towards us */ | |
3148 ps->vertFlags[a] |= PROJ_VERT_CULL; | |
3149 } | |
3150 } | |
3151 else { | |
3152 sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co); | |
3153 normalize_v3(viewDirPersp); | |
3154 if (angle_normalized_v3v3(viewDirPersp, no) >= p
s->normal_angle) { /* 1 vert of this face is towards us */ | |
3155 ps->vertFlags[a] |= PROJ_VERT_CULL; | |
3156 } | |
3157 } | |
3158 } | |
3159 } | |
3160 ········ | |
3161 | |
3162 for(face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index <
ps->dm_totface; mf++, tf++, face_index++) { | |
3163 ················ | |
3164 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
3165 /* add face user if we have bleed enabled, set the UV seam flags
later */ | |
3166 /* annoying but we need to add all faces even ones we never use
elsewhere */ | |
3167 if (ps->seam_bleed_px > 0.0f) { | |
3168 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_I
NT_IN_POINTER(face_index), arena); | |
3169 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_I
NT_IN_POINTER(face_index), arena); | |
3170 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_I
NT_IN_POINTER(face_index), arena); | |
3171 if (mf->v4) { | |
3172 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4
], SET_INT_IN_POINTER(face_index), arena); | |
3173 } | |
3174 } | |
3175 #endif | |
3176 ················ | |
3177 if (tf->tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PA
INT_MASK)==0 || mf->flag & ME_FACE_SEL)) { | |
3178 ························ | |
3179 float *v1coSS, *v2coSS, *v3coSS, *v4coSS=NULL; | |
3180 ························ | |
3181 v1coSS = ps->screenCoords[mf->v1];· | |
3182 v2coSS = ps->screenCoords[mf->v2];· | |
3183 v3coSS = ps->screenCoords[mf->v3]; | |
3184 if (mf->v4) { | |
3185 v4coSS = ps->screenCoords[mf->v4];· | |
3186 } | |
3187 ························ | |
3188 ························ | |
3189 if (!ps->is_ortho) { | |
3190 if ( v1coSS[0]==FLT_MAX || | |
3191 v2coSS[0]==FLT_MAX || | |
3192 v3coSS[0]==FLT_MAX || | |
3193 (mf->v4 && v4coSS[0]==FLT_MAX) | |
3194 ) { | |
3195 continue; | |
3196 } | |
3197 } | |
3198 ························ | |
3199 #ifdef PROJ_DEBUG_WINCLIP | |
3200 /* ignore faces outside the view */ | |
3201 if ( | |
3202 (v1coSS[0] < ps->screenMin[0] && | |
3203 v2coSS[0] < ps->screenMin[0] && | |
3204 v3coSS[0] < ps->screenMin[0] && | |
3205 (mf->v4 && v4coSS[0] < ps->screenMin[0])
) || | |
3206 ········································ | |
3207 (v1coSS[0] > ps->screenMax[0] && | |
3208 v2coSS[0] > ps->screenMax[0] && | |
3209 v3coSS[0] > ps->screenMax[0] && | |
3210 (mf->v4 && v4coSS[0] > ps->screenMax[0])
) || | |
3211 ········································ | |
3212 (v1coSS[1] < ps->screenMin[1] && | |
3213 v2coSS[1] < ps->screenMin[1] && | |
3214 v3coSS[1] < ps->screenMin[1] && | |
3215 (mf->v4 && v4coSS[1] < ps->screenMin[1])
) || | |
3216 ········································ | |
3217 (v1coSS[1] > ps->screenMax[1] && | |
3218 v2coSS[1] > ps->screenMax[1] && | |
3219 v3coSS[1] > ps->screenMax[1] && | |
3220 (mf->v4 && v4coSS[1] > ps->screenMax[1])
) | |
3221 ) { | |
3222 continue; | |
3223 } | |
3224 ························ | |
3225 #endif //PROJ_DEBUG_WINCLIP | |
3226 ········ | |
3227 ························ | |
3228 if (ps->do_backfacecull) { | |
3229 if (ps->do_mask_normal) { | |
3230 /* Since we are interpolating the normal
s of faces, we want to make· | |
3231 * sure all the verts are pointing away
from the view, | |
3232 * not just the face */ | |
3233 if ( (ps->vertFlags[mf->v1] & PROJ_VE
RT_CULL) && | |
3234 (ps->vertFlags[mf->v2] &
PROJ_VERT_CULL) && | |
3235 (ps->vertFlags[mf->v3] &
PROJ_VERT_CULL) && | |
3236 (mf->v4==0 || ps->vertFl
ags[mf->v4] & PROJ_VERT_CULL) | |
3237 ························································ | |
3238 ) { | |
3239 continue; | |
3240 } | |
3241 } | |
3242 else { | |
3243 if (line_point_side_v2(v1coSS, v2coSS, v
3coSS) < 0.0f) { | |
3244 continue; | |
3245 } | |
3246 ········································ | |
3247 } | |
3248 } | |
3249 ························ | |
3250 if (tpage_last != tf->tpage) { | |
3251 ································ | |
3252 image_index = BLI_linklist_index(image_LinkList,
tf->tpage); | |
3253 ································ | |
3254 if (image_index==-1 && BKE_image_get_ibuf(tf->tp
age, NULL)) { /* MemArena dosnt have an append func */ | |
3255 BLI_linklist_append(&image_LinkList, tf-
>tpage); | |
3256 image_index = ps->image_tot; | |
3257 ps->image_tot++; | |
3258 } | |
3259 ································ | |
3260 tpage_last = tf->tpage; | |
3261 } | |
3262 ························ | |
3263 if (image_index != -1) { | |
3264 /* Initialize the faces screen pixels */ | |
3265 /* Add this to a list to initialize later */ | |
3266 project_paint_delayed_face_init(ps, mf, face_ind
ex); | |
3267 } | |
3268 } | |
3269 } | |
3270 ········ | |
3271 /* build an array of images we use*/ | |
3272 projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, s
izeof(ProjPaintImage) * ps->image_tot); | |
3273 ········ | |
3274 for (node= image_LinkList, i=0; node; node= node->next, i++, projIma++)
{ | |
3275 projIma->ima = node->link; | |
3276 projIma->touch = 0; | |
3277 projIma->ibuf = BKE_image_get_ibuf(projIma->ima, NULL); | |
3278 projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(Imag
ePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); | |
3279 memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedra
w) * PROJ_BOUNDBOX_SQUARED); | |
3280 } | |
3281 ········ | |
3282 /* we have built the array, discard the linked list */ | |
3283 BLI_linklist_free(image_LinkList, NULL); | |
3284 } | |
3285 | |
3286 static void project_paint_begin_clone(ProjPaintState *ps, int mouse[2]) | |
3287 { | |
3288 /* setup clone offset */ | |
3289 if (ps->tool == PAINT_TOOL_CLONE) { | |
3290 float projCo[4]; | |
3291 copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d)); | |
3292 mul_m4_v3(ps->ob->imat, projCo); | |
3293 ················ | |
3294 projCo[3] = 1.0f; | |
3295 mul_m4_v4(ps->projectMat, projCo); | |
3296 ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx/2.0f)+(ps->win
x/2.0f)*projCo[0]/projCo[3]); | |
3297 ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy/2.0f)+(ps->win
y/2.0f)*projCo[1]/projCo[3]); | |
3298 }······· | |
3299 }······· | |
3300 | |
3301 static void project_paint_end(ProjPaintState *ps) | |
3302 { | |
3303 int a; | |
3304 ········ | |
3305 /* build undo data from original pixel colors */ | |
3306 if(U.uiflag & USER_GLOBALUNDO) { | |
3307 ProjPixel *projPixel; | |
3308 ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL; | |
3309 LinkNode *pixel_node; | |
3310 void *tilerect; | |
3311 MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for
non threaded case */ | |
3312 ································ | |
3313 int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could ge
t an X/Y but easier to loop through all possible buckets */ | |
3314 int bucket_index;· | |
3315 int tile_index; | |
3316 int x_round, y_round; | |
3317 int x_tile, y_tile; | |
3318 int is_float = -1; | |
3319 ················ | |
3320 /* context */ | |
3321 ProjPaintImage *last_projIma; | |
3322 int last_image_index = -1; | |
3323 int last_tile_width=0; | |
3324 ················ | |
3325 for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, la
st_projIma++) { | |
3326 int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_p
rojIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); | |
3327 last_projIma->undoRect = (void **) BLI_memarena_alloc(ar
ena, size); | |
3328 memset(last_projIma->undoRect, 0, size); | |
3329 last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; | |
3330 } | |
3331 ················ | |
3332 for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++
) { | |
3333 /* loop through all pixels */ | |
3334 for(pixel_node= ps->bucketRect[bucket_index]; pixel_node
; pixel_node= pixel_node->next) { | |
3335 ························ | |
3336 /* ok we have a pixel, was it modified? */ | |
3337 projPixel = (ProjPixel *)pixel_node->link; | |
3338 ································ | |
3339 if (last_image_index != projPixel->image_index)
{ | |
3340 /* set the context */ | |
3341 last_image_index = projPixel->image
_index; | |
3342 last_projIma = ps->projImages +
last_image_index; | |
3343 last_tile_width = IMAPAINT_TILE_NU
MBER(last_projIma->ibuf->x); | |
3344 is_float = last_pro
jIma->ibuf->rect_float ? 1 : 0; | |
3345 } | |
3346 ································ | |
3347 ································ | |
3348 if ( (is_float == 0 && projPixel->origColor.u
int != *projPixel->pixel.uint_pt) ||· | |
3349 ································································ | |
3350 (is_float == 1 &&· | |
3351 ( projPixel->origColor.f[0
] != projPixel->pixel.f_pt[0] ||· | |
3352 projPixel->origColor.f[1
] != projPixel->pixel.f_pt[1] || | |
3353 projPixel->origColor.f[2
] != projPixel->pixel.f_pt[2] || | |
3354 projPixel->origColor.f[3
] != projPixel->pixel.f_pt[3] )) | |
3355 ) { | |
3356 ········································ | |
3357 x_tile = projPixel->x_px >> IMAPAINT_TI
LE_BITS; | |
3358 y_tile = projPixel->y_px >> IMAPAINT_TI
LE_BITS; | |
3359 ········································ | |
3360 x_round = x_tile * IMAPAINT_TILE_SIZE; | |
3361 y_round = y_tile * IMAPAINT_TILE_SIZE; | |
3362 ········································ | |
3363 tile_index = x_tile + y_tile * last_tile
_width; | |
3364 ········································ | |
3365 if (last_projIma->undoRect[tile_index]==
NULL) { | |
3366 /* add the undo tile from the mo
dified image, then write the original colors back into it */ | |
3367 tilerect = last_projIma->undoRec
t[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_f
loat ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile); | |
3368 } | |
3369 else { | |
3370 tilerect = last_projIma->undoRec
t[tile_index]; | |
3371 } | |
3372 ········································ | |
3373 /* This is a BIT ODD, but overwrite the
undo tiles image info with this pixels original color | |
3374 * because allocating the tiles allong t
he way slows down painting */ | |
3375 ········································ | |
3376 if (is_float) { | |
3377 float *rgba_fp = (float *)tilere
ct + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE
_SIZE)) * 4; | |
3378 QUATCOPY(rgba_fp, projPixel->ori
gColor.f); | |
3379 } | |
3380 else { | |
3381 ((unsigned int *)tilerect)[ (pro
jPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = p
rojPixel->origColor.uint; | |
3382 } | |
3383 } | |
3384 } | |
3385 } | |
3386 ················ | |
3387 if (tmpibuf) IMB_freeImBuf(tmpibuf); | |
3388 if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float); | |
3389 } | |
3390 /* done calculating undo data */ | |
3391 ········ | |
3392 MEM_freeN(ps->screenCoords); | |
3393 MEM_freeN(ps->bucketRect); | |
3394 MEM_freeN(ps->bucketFaces); | |
3395 MEM_freeN(ps->bucketFlags); | |
3396 ········ | |
3397 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
3398 if (ps->seam_bleed_px > 0.0f) { | |
3399 MEM_freeN(ps->vertFaces); | |
3400 MEM_freeN(ps->faceSeamFlags); | |
3401 MEM_freeN(ps->faceSeamUVs); | |
3402 } | |
3403 #endif | |
3404 ········ | |
3405 if (ps->vertFlags) MEM_freeN(ps->vertFlags); | |
3406 ········ | |
3407 for (a=0; a<ps->thread_tot; a++) { | |
3408 BLI_memarena_free(ps->arena_mt[a]); | |
3409 } | |
3410 ········ | |
3411 /* copy for subsurf/multires, so throw away */ | |
3412 if(ps->dm->type != DM_TYPE_CDDM) { | |
3413 if(ps->dm_mvert) MEM_freeN(ps->dm_mvert); | |
3414 if(ps->dm_mface) MEM_freeN(ps->dm_mface); | |
3415 /* looks like these dont need copying */ | |
3416 /* | |
3417 if(ps->dm_mtface) MEM_freeN(ps->dm_mtface); | |
3418 if(ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone); | |
3419 if(ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil); | |
3420 */ | |
3421 } | |
3422 | |
3423 if(ps->dm_release) | |
3424 ps->dm->release(ps->dm); | |
3425 } | |
3426 | |
3427 /* 1= an undo, -1 is a redo. */ | |
3428 static void partial_redraw_array_init(ImagePaintPartialRedraw *pr) | |
3429 { | |
3430 int tot = PROJ_BOUNDBOX_SQUARED; | |
3431 while (tot--) { | |
3432 pr->x1 = 10000000; | |
3433 pr->y1 = 10000000; | |
3434 ················ | |
3435 pr->x2 = -1; | |
3436 pr->y2 = -1; | |
3437 ················ | |
3438 pr->enabled = 1; | |
3439 ················ | |
3440 pr++; | |
3441 } | |
3442 } | |
3443 | |
3444 | |
3445 static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPar
tialRedraw *pr_other, int tot) | |
3446 { | |
3447 int touch= 0; | |
3448 while (tot--) { | |
3449 pr->x1 = MIN2(pr->x1, pr_other->x1); | |
3450 pr->y1 = MIN2(pr->y1, pr_other->y1); | |
3451 ················ | |
3452 pr->x2 = MAX2(pr->x2, pr_other->x2); | |
3453 pr->y2 = MAX2(pr->y2, pr_other->y2); | |
3454 ················ | |
3455 if (pr->x2 != -1) | |
3456 touch = 1; | |
3457 ················ | |
3458 pr++; pr_other++; | |
3459 } | |
3460 ········ | |
3461 return touch; | |
3462 } | |
3463 | |
3464 /* Loop over all images on this mesh and update any we have touched */ | |
3465 static int project_image_refresh_tagged(ProjPaintState *ps) | |
3466 { | |
3467 ImagePaintPartialRedraw *pr; | |
3468 ProjPaintImage *projIma; | |
3469 int a,i; | |
3470 int redraw = 0; | |
3471 ········ | |
3472 ········ | |
3473 for (a=0, projIma=ps->projImages; a < ps->image_tot; a++, projIma++) { | |
3474 if (projIma->touch) { | |
3475 /* look over each bound cell */ | |
3476 for (i=0; i<PROJ_BOUNDBOX_SQUARED; i++) { | |
3477 pr = &(projIma->partRedrawRect[i]); | |
3478 if (pr->x2 != -1) { /* TODO - use 'enabled' ? */ | |
3479 imapaintpartial = *pr; | |
3480 imapaint_image_update(NULL, projIma->ima
, projIma->ibuf, 1); /*last 1 is for texpaint*/ | |
3481 redraw = 1; | |
3482 } | |
3483 } | |
3484 ························ | |
3485 projIma->touch = 0; /* clear for reuse */ | |
3486 } | |
3487 } | |
3488 ········ | |
3489 return redraw; | |
3490 } | |
3491 | |
3492 /* run this per painting onto each mouse location */ | |
3493 static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) | |
3494 { | |
3495 if(ps->source==PROJ_SRC_VIEW) { | |
3496 float min_brush[2], max_brush[2]; | |
3497 const float radius = (float)brush_size(ps->brush); | |
3498 | |
3499 /* so we dont have a bucket bounds that is way too small to pain
t into */ | |
3500 // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/ | |
3501 | |
3502 min_brush[0] = mval_f[0] - radius; | |
3503 min_brush[1] = mval_f[1] - radius; | |
3504 | |
3505 max_brush[0] = mval_f[0] + radius; | |
3506 max_brush[1] = mval_f[1] + radius; | |
3507 | |
3508 /* offset to make this a valid bucket index */ | |
3509 project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucket
Min, ps->bucketMax); | |
3510 | |
3511 /* mouse outside the model areas? */ | |
3512 if (ps->bucketMin[0]==ps->bucketMax[0] || ps->bucketMin[1]==ps->
bucketMax[1]) { | |
3513 return 0; | |
3514 } | |
3515 | |
3516 ps->context_bucket_x = ps->bucketMin[0]; | |
3517 ps->context_bucket_y = ps->bucketMin[1]; | |
3518 } | |
3519 else { /* reproject: PROJ_SRC_* */ | |
3520 ps->bucketMin[0]= 0; | |
3521 ps->bucketMin[1]= 0; | |
3522 | |
3523 ps->bucketMax[0]= ps->buckets_x; | |
3524 ps->bucketMax[1]= ps->buckets_y; | |
3525 | |
3526 ps->context_bucket_x = 0; | |
3527 ps->context_bucket_y = 0; | |
3528 } | |
3529 return 1; | |
3530 } | |
3531 | |
3532 | |
3533 static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf
*bucket_bounds, const float mval[2]) | |
3534 { | |
3535 const int diameter= 2*brush_size(ps->brush); | |
3536 | |
3537 if (ps->thread_tot > 1) | |
3538 BLI_lock_thread(LOCK_CUSTOM1); | |
3539 ········ | |
3540 //printf("%d %d \n", ps->context_bucket_x, ps->context_bucket_y); | |
3541 ········ | |
3542 for ( ; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++)
{ | |
3543 for ( ; ps->context_bucket_x < ps->bucketMax[0]; ps->context_buc
ket_x++) { | |
3544 ························ | |
3545 /* use bucket_bounds for project_bucket_isect_circle and
project_bucket_init*/ | |
3546 project_bucket_bounds(ps, ps->context_bucket_x, ps->cont
ext_bucket_y, bucket_bounds); | |
3547 ························ | |
3548 if ( (ps->source != PROJ_SRC_VIEW) || | |
3549 project_bucket_isect_circle(mval, (float
)(diameter*diameter), bucket_bounds) | |
3550 ) { | |
3551 *bucket_index = ps->context_bucket_x + (ps->cont
ext_bucket_y * ps->buckets_x); | |
3552 ps->context_bucket_x++; | |
3553 ································ | |
3554 if (ps->thread_tot > 1) | |
3555 BLI_unlock_thread(LOCK_CUSTOM1); | |
3556 ································ | |
3557 return 1; | |
3558 } | |
3559 } | |
3560 ps->context_bucket_x = ps->bucketMin[0]; | |
3561 } | |
3562 ········ | |
3563 if (ps->thread_tot > 1) | |
3564 BLI_unlock_thread(LOCK_CUSTOM1); | |
3565 return 0; | |
3566 } | |
3567 | |
3568 /* Each thread gets one of these, also used as an argument to pass to project_pa
int_op */ | |
3569 typedef struct ProjectHandle { | |
3570 /* args */ | |
3571 ProjPaintState *ps; | |
3572 float prevmval[2]; | |
3573 float mval[2]; | |
3574 ········ | |
3575 /* annoying but we need to have image bounds per thread, then merge into
ps->projectPartialRedraws */ | |
3576 ProjPaintImage *projImages; /* array of partial redraws */ | |
3577 ········ | |
3578 /* thread settings */ | |
3579 int thread_index; | |
3580 } ProjectHandle; | |
3581 | |
3582 static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const u
nsigned char *cp2, const int fac) | |
3583 { | |
3584 /* this and other blending modes previously used >>8 instead of /255. bo
th | |
3585 are not equivalent (>>8 is /256), and the former results in rounding | |
3586 errors that can turn colors black fast after repeated blending */ | |
3587 const int mfac= 255-fac; | |
3588 | |
3589 cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; | |
3590 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; | |
3591 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; | |
3592 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; | |
3593 } | |
3594 | |
3595 static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2,
const float fac) | |
3596 { | |
3597 const float mfac= 1.0f-fac; | |
3598 cp[0]= mfac*cp1[0] + fac*cp2[0]; | |
3599 cp[1]= mfac*cp1[1] + fac*cp2[1]; | |
3600 cp[2]= mfac*cp1[2] + fac*cp2[2]; | |
3601 cp[3]= mfac*cp1[3] + fac*cp2[3]; | |
3602 } | |
3603 | |
3604 static void blend_color_mix_accum(unsigned char *cp, const unsigned char *cp1, c
onst unsigned char *cp2, const int fac) | |
3605 { | |
3606 /* this and other blending modes previously used >>8 instead of /255. bo
th | |
3607 are not equivalent (>>8 is /256), and the former results in rounding | |
3608 errors that can turn colors black fast after repeated blending */ | |
3609 const int mfac= 255-fac; | |
3610 const int alpha= cp1[3] + ((fac * cp2[3]) / 255); | |
3611 | |
3612 cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; | |
3613 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; | |
3614 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; | |
3615 cp[3]= alpha > 255 ? 255 : alpha; | |
3616 } | |
3617 | |
3618 static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
t alpha, float mask) | |
3619 { | |
3620 if (ps->is_airbrush==0 && mask < 1.0f) { | |
3621 projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.u
int, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*255), ps->blend); | |
3622 blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch
, projPixel->newColor.ch, (int)(mask*255)); | |
3623 } | |
3624 else { | |
3625 *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.ui
nt_pt, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*mask*255), ps->bl
end); | |
3626 } | |
3627 } | |
3628 | |
3629 static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
oat alpha, float mask) | |
3630 { | |
3631 if (ps->is_airbrush==0 && mask < 1.0f) { | |
3632 IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor
.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend); | |
3633 blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origCol
or.f, projPixel->newColor.f, mask); | |
3634 } | |
3635 else { | |
3636 IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_
pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha*mask, ps->blend); | |
3637 } | |
3638 } | |
3639 | |
3640 /* do_projectpaint_smear* | |
3641 *· | |
3642 * note, mask is used to modify the alpha here, this is not correct since it all
ows | |
3643 * accumulation of color greater then 'projPixel->mask' however in the case of s
mear its not· | |
3644 * really that important to be correct as it is with clone and painting· | |
3645 */ | |
3646 static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, floa
t alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2]) | |
3647 { | |
3648 unsigned char rgba_ub[4]; | |
3649 ········ | |
3650 if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0) | |
3651 return;· | |
3652 /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPi
xel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend
); */ | |
3653 blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pi
xel.ch_pt, rgba_ub, (int)(alpha*mask*255)); | |
3654 BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena); | |
3655 }· | |
3656 | |
3657 static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl
oat alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[
2]) | |
3658 { | |
3659 unsigned char rgba_ub[4]; | |
3660 unsigned char rgba_smear[4]; | |
3661 ········ | |
3662 if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0) | |
3663 return; | |
3664 ········ | |
3665 IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, projPixel->pixel.f_pt); | |
3666 /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsig
ned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->bl
end); */ | |
3667 blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, rgba_smear, (
rgba_ub), (int)(alpha*mask*255));· | |
3668 BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena)
; | |
3669 } | |
3670 | |
3671 static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, float
*rgba, float alpha, float mask) | |
3672 { | |
3673 unsigned char rgba_ub[4]; | |
3674 ········ | |
3675 if (ps->is_texbrush) { | |
3676 rgba_ub[0] = FTOCHAR(rgba[0] * ps->brush->rgb[0]); | |
3677 rgba_ub[1] = FTOCHAR(rgba[1] * ps->brush->rgb[1]); | |
3678 rgba_ub[2] = FTOCHAR(rgba[2] * ps->brush->rgb[2]); | |
3679 rgba_ub[3] = FTOCHAR(rgba[3]); | |
3680 } | |
3681 else { | |
3682 IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb); | |
3683 rgba_ub[3] = 255; | |
3684 } | |
3685 ········ | |
3686 if (ps->is_airbrush==0 && mask < 1.0f) { | |
3687 projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.u
int, *((unsigned int *)rgba_ub), (int)(alpha*255), ps->blend); | |
3688 blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch
, projPixel->newColor.ch, (int)(mask*255)); | |
3689 } | |
3690 else { | |
3691 *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.ui
nt_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); | |
3692 } | |
3693 } | |
3694 | |
3695 static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, flo
at *rgba, float alpha, float mask, int use_color_correction) { | |
3696 if (ps->is_texbrush) { | |
3697 /*rgba already holds a texture result here from higher level function*/ | |
3698 float rgba_br[3]; | |
3699 if(use_color_correction){ | |
3700 srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb); | |
3701 mul_v3_v3(rgba, rgba_br); | |
3702 } | |
3703 else{ | |
3704 mul_v3_v3(rgba, ps->brush->rgb); | |
3705 } | |
3706 } | |
3707 else { | |
3708 VECCOPY(rgba, ps->brush->rgb); | |
3709 if(use_color_correction){ | |
3710 srgb_to_linearrgb_v3_v3(rgba, rgba); | |
3711 } | |
3712 rgba[3] = 1.0; | |
3713 } | |
3714 ········ | |
3715 if (ps->is_airbrush==0 && mask < 1.0f) { | |
3716 IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor
.f, rgba, alpha, ps->blend); | |
3717 blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origCol
or.f, projPixel->newColor.f, mask); | |
3718 } | |
3719 else { | |
3720 IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_
pt, rgba, alpha*mask, ps->blend); | |
3721 } | |
3722 } | |
3723 | |
3724 | |
3725 | |
3726 /* run this for single and multithreaded painting */ | |
3727 static void *do_projectpaint_thread(void *ph_v) | |
3728 { | |
3729 /* First unpack args from the struct */ | |
3730 ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps; | |
3731 ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages; | |
3732 const float *lastpos = ((ProjectHandle *)ph_v)->prevmva
l; | |
3733 const float *pos = ((ProjectHandle *)ph_v)-
>mval; | |
3734 const int thread_index = ((ProjectHandle *)ph_v)->thread_
index; | |
3735 /* Done with args from ProjectHandle */ | |
3736 | |
3737 LinkNode *node; | |
3738 ProjPixel *projPixel; | |
3739 ········ | |
3740 int last_index = -1; | |
3741 ProjPaintImage *last_projIma= NULL; | |
3742 ImagePaintPartialRedraw *last_partial_redraw_cell; | |
3743 ········ | |
3744 float rgba[4], alpha, dist_nosqrt, dist; | |
3745 ········ | |
3746 float falloff; | |
3747 int bucket_index; | |
3748 int is_floatbuf = 0; | |
3749 int use_color_correction = 0; | |
3750 const short tool = ps->tool; | |
3751 rctf bucket_bounds; | |
3752 ········ | |
3753 /* for smear only */ | |
3754 float pos_ofs[2] = {0}; | |
3755 float co[2]; | |
3756 float mask = 1.0f; /* airbrush wont use mask */ | |
3757 unsigned short mask_short; | |
3758 const float radius= (float)brush_size(ps->brush); | |
3759 const float radius_squared= radius*radius; /* avoid a square root with e
very dist comparison */ | |
3760 ········ | |
3761 short lock_alpha= ELEM(ps->brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEN
D_ADD_ALPHA) ? 0 : ps->brush->flag & BRUSH_LOCK_ALPHA; | |
3762 ········ | |
3763 LinkNode *smearPixels = NULL; | |
3764 LinkNode *smearPixels_f = NULL; | |
3765 MemArena *smearArena = NULL; /* mem arena for this brush projection only
*/ | |
3766 ········ | |
3767 if (tool==PAINT_TOOL_SMEAR) { | |
3768 pos_ofs[0] = pos[0] - lastpos[0]; | |
3769 pos_ofs[1] = pos[1] - lastpos[1]; | |
3770 ················ | |
3771 smearArena = BLI_memarena_new(1<<16, "paint smear arena"); | |
3772 } | |
3773 ········ | |
3774 /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], buck
etMax[0], bucketMax[1]); */ | |
3775 ········ | |
3776 while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos))
{······························ | |
3777 ················ | |
3778 /* Check this bucket and its faces are initialized */ | |
3779 if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) { | |
3780 /* No pixels initialized */ | |
3781 project_bucket_init(ps, thread_index, bucket_index, &buc
ket_bounds); | |
3782 } | |
3783 | |
3784 if(ps->source != PROJ_SRC_VIEW) { | |
3785 | |
3786 /* Re-Projection, simple, no brushes! */ | |
3787 ························ | |
3788 for (node = ps->bucketRect[bucket_index]; node; node = n
ode->next) { | |
3789 projPixel = (ProjPixel *)node->link; | |
3790 | |
3791 bicubic_interpolation_color(ps->reproject_ibuf,
projPixel->newColor.ch, NULL, projPixel->projCoSS[0], projPixel->projCoSS[1]); | |
3792 if(projPixel->newColor.ch[3]) { | |
3793 mask = ((float)projPixel->mask)/65535.0f
; | |
3794 blend_color_mix_accum(projPixel->pixel.c
h_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*projPixel->ne
wColor.ch[3])); | |
3795 | |
3796 } | |
3797 } | |
3798 } | |
3799 else { | |
3800 /* Normal brush painting */ | |
3801 ························ | |
3802 for (node = ps->bucketRect[bucket_index]; node; node = n
ode->next) { | |
3803 | |
3804 projPixel = (ProjPixel *)node->link; | |
3805 | |
3806 /*dist = len_v2v2(projPixel->projCoSS, pos);*/ /
* correct but uses a sqrtf */ | |
3807 dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoS
S, pos); | |
3808 | |
3809 /*if (dist < radius) {*/ /* correct but uses a s
qrtf */ | |
3810 if (dist_nosqrt <= radius_squared) { | |
3811 dist=sqrtf(dist_nosqrt); | |
3812 | |
3813 falloff = brush_curve_strength_clamp(ps-
>brush, dist, radius); | |
3814 | |
3815 if (falloff > 0.0f) { | |
3816 if (ps->is_texbrush) { | |
3817 /* note, for clone and s
mear, we only use the alpha, could be a special function */ | |
3818 brush_sample_tex(ps->bru
sh, projPixel->projCoSS, rgba, thread_index); | |
3819 alpha = rgba[3]; | |
3820 } else { | |
3821 alpha = 1.0f; | |
3822 } | |
3823 ················································ | |
3824 if (ps->is_airbrush) { | |
3825 /* for an aurbrush there
is no real mask, so just multiply the alpha by it */ | |
3826 alpha *= falloff * brush
_alpha(ps->brush); | |
3827 mask = ((float)projPixel
->mask)/65535.0f; | |
3828 } | |
3829 else { | |
3830 /* This brush dosnt accu
mulate so add some curve to the brushes falloff */ | |
3831 falloff = 1.0f - falloff
; | |
3832 falloff = 1.0f - (fallof
f * falloff); | |
3833 ························································ | |
3834 mask_short = (unsigned s
hort)(projPixel->mask * (brush_alpha(ps->brush) * falloff)); | |
3835 if (mask_short > projPix
el->mask_max) { | |
3836 mask = ((float)m
ask_short)/65535.0f; | |
3837 projPixel->mask_
max = mask_short; | |
3838 } | |
3839 else { | |
3840 /*mask = ((float
)projPixel->mask_max)/65535.0f;*/ | |
3841 | |
3842 /* Go onto the n
ext pixel */ | |
3843 continue; | |
3844 } | |
3845 } | |
3846 ················································ | |
3847 if (alpha > 0.0f) { | |
3848 | |
3849 if (last_index != projPi
xel->image_index) { | |
3850 last_index = pro
jPixel->image_index; | |
3851 last_projIma = p
rojImages + last_index; | |
3852 | |
3853 last_projIma->to
uch = 1; | |
3854 is_floatbuf = la
st_projIma->ibuf->rect_float ? 1 : 0; | |
3855 use_color_correc
tion = (last_projIma->ibuf->profile == IB_PROFILE_LINEAR_RGB) ? 1 : 0; | |
3856 } | |
3857 | |
3858 last_partial_redraw_cell
= last_projIma->partRedrawRect + projPixel->bb_cell_index; | |
3859 last_partial_redraw_cell
->x1 = MIN2(last_partial_redraw_cell->x1, projPixel->x_px); | |
3860 last_partial_redraw_cell
->y1 = MIN2(last_partial_redraw_cell->y1, projPixel->y_px); | |
3861 | |
3862 last_partial_redraw_cell
->x2 = MAX2(last_partial_redraw_cell->x2, projPixel->x_px+1); | |
3863 last_partial_redraw_cell
->y2 = MAX2(last_partial_redraw_cell->y2, projPixel->y_px+1); | |
3864 | |
3865 ························································ | |
3866 switch(tool) { | |
3867 case PAINT_TOOL_CLONE: | |
3868 if (is_floatbuf)
{ | |
3869 if (((Pr
ojPixelClone *)projPixel)->clonepx.f[3]) { | |
3870
do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isnt used for cloni
ng, only alpha */ | |
3871 } | |
3872 } | |
3873 else { | |
3874 if (((Pr
ojPixelClone*)projPixel)->clonepx.ch[3]) { | |
3875
do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isnt used for cloning
, only alpha */ | |
3876 } | |
3877 } | |
3878 break; | |
3879 case PAINT_TOOL_SMEAR: | |
3880 sub_v2_v2v2(co,
projPixel->projCoSS, pos_ofs); | |
3881 | |
3882 if (is_floatbuf)
do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPi
xels_f, co); | |
3883 else
do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &s
mearPixels, co); | |
3884 break; | |
3885 default: | |
3886 if (is_floatbuf)
do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask, use_color_corre
ction); | |
3887 else
do_projectpaint_draw(ps, projPixel, rgba, alpha, mask); | |
3888 break; | |
3889 } | |
3890 } | |
3891 | |
3892 if(lock_alpha) { | |
3893 if (is_floatbuf)
projPixel->pixel.f_pt[3]= projPixel->origColor.f[3]; | |
3894 else
projPixel->pixel.ch_pt[3]= projPixel->origColor.ch[3]; | |
3895 } | |
3896 | |
3897 /* done painting */ | |
3898 } | |
3899 } | |
3900 } | |
3901 } | |
3902 } | |
3903 | |
3904 ········ | |
3905 if (tool==PAINT_TOOL_SMEAR) { | |
3906 ················ | |
3907 for (node= smearPixels; node; node= node->next) { /* this wont r
un for a float image */ | |
3908 projPixel = node->link; | |
3909 *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel
)->clonepx.uint; | |
3910 } | |
3911 ················ | |
3912 for (node= smearPixels_f; node; node= node->next) { | |
3913 projPixel = node->link; | |
3914 IMAPAINT_CHAR_RGBA_TO_FLOAT(projPixel->pixel.f_pt, ((Pr
ojPixelClone *)projPixel)->clonepx.ch); | |
3915 } | |
3916 ················ | |
3917 BLI_memarena_free(smearArena); | |
3918 } | |
3919 ········ | |
3920 return NULL; | |
3921 } | |
3922 | |
3923 static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), float *lastpos, f
loat *pos) | |
3924 { | |
3925 /* First unpack args from the struct */ | |
3926 ProjPaintState *ps = (ProjPaintState *)state; | |
3927 int touch_any = 0;······ | |
3928 ········ | |
3929 ProjectHandle handles[BLENDER_MAX_THREADS]; | |
3930 ListBase threads; | |
3931 int a,i; | |
3932 ········ | |
3933 if (!project_bucket_iter_init(ps, pos)) { | |
3934 return 0; | |
3935 } | |
3936 ········ | |
3937 if (ps->thread_tot > 1) | |
3938 BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_to
t); | |
3939 ········ | |
3940 /* get the threads running */ | |
3941 for(a=0; a < ps->thread_tot; a++) { | |
3942 ················ | |
3943 /* set defaults in handles */ | |
3944 //memset(&handles[a], 0, sizeof(BakeShade)); | |
3945 ················ | |
3946 handles[a].ps = ps; | |
3947 copy_v2_v2(handles[a].mval, pos); | |
3948 copy_v2_v2(handles[a].prevmval, lastpos); | |
3949 ················ | |
3950 /* thread spesific */ | |
3951 handles[a].thread_index = a; | |
3952 ················ | |
3953 handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps-
>arena_mt[a], ps->image_tot * sizeof(ProjPaintImage)); | |
3954 ················ | |
3955 memcpy(handles[a].projImages, ps->projImages, ps->image_tot * si
zeof(ProjPaintImage)); | |
3956 ················ | |
3957 /* image bounds */ | |
3958 for (i=0; i< ps->image_tot; i++) { | |
3959 handles[a].projImages[i].partRedrawRect = (ImagePaintPar
tialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw)
* PROJ_BOUNDBOX_SQUARED); | |
3960 memcpy(handles[a].projImages[i].partRedrawRect, ps->proj
Images[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARE
D);····················· | |
3961 } | |
3962 | |
3963 if (ps->thread_tot > 1) | |
3964 BLI_insert_thread(&threads, &handles[a]); | |
3965 } | |
3966 ········ | |
3967 if (ps->thread_tot > 1) /* wait for everything to be done */ | |
3968 BLI_end_threads(&threads); | |
3969 else | |
3970 do_projectpaint_thread(&handles[0]); | |
3971 ················ | |
3972 ········ | |
3973 /* move threaded bounds back into ps->projectPartialRedraws */ | |
3974 for(i=0; i < ps->image_tot; i++) { | |
3975 int touch = 0; | |
3976 for(a=0; a < ps->thread_tot; a++) { | |
3977 touch |= partial_redraw_array_merge(ps->projImages[i].pa
rtRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED); | |
3978 } | |
3979 ················ | |
3980 if (touch) { | |
3981 ps->projImages[i].touch = 1; | |
3982 touch_any = 1; | |
3983 } | |
3984 } | |
3985 ········ | |
3986 return touch_any; | |
3987 } | |
3988 | |
3989 | |
3990 static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, c
onst int UNUSED(prevmval_i[2]), const int mval_i[2], double time, float pressure
) | |
3991 { | |
3992 ········ | |
3993 /* Use mouse coords as floats for projection painting */ | |
3994 float pos[2]; | |
3995 ········ | |
3996 pos[0] = (float)(mval_i[0]); | |
3997 pos[1] = (float)(mval_i[1]); | |
3998 ········ | |
3999 // we may want to use this later· | |
4000 // brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0
); | |
4001 ········ | |
4002 if (brush_painter_paint(painter, project_paint_op, pos, time, pressure,
ps, 0)) { | |
4003 return 1; | |
4004 } | |
4005 else return 0; | |
4006 } | |
4007 | |
4008 | |
4009 static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, const
int prevmval_i[2], const int mval_i[2], double time, float pressure) | |
4010 { | |
4011 int a, redraw; | |
4012 ········ | |
4013 for (a=0; a < ps->image_tot; a++) | |
4014 partial_redraw_array_init(ps->projImages[a].partRedrawRect); | |
4015 ········ | |
4016 redraw= project_paint_sub_stroke(ps, painter, prevmval_i, mval_i, time,
pressure); | |
4017 ········ | |
4018 if(project_image_refresh_tagged(ps)) | |
4019 return redraw; | |
4020 ········ | |
4021 return 0; | |
4022 } | 313 } |
4023 | 314 |
4024 /* Imagepaint Partial Redraw & Dirty Region */ | 315 /* Imagepaint Partial Redraw & Dirty Region */ |
4025 | 316 |
4026 static void imapaint_clear_partial_redraw(void) | 317 void imapaint_clear_partial_redraw(void) |
4027 { | 318 { |
4028 memset(&imapaintpartial, 0, sizeof(imapaintpartial)); | 319 memset(&imapaintpartial, 0, sizeof(imapaintpartial)); |
4029 } | 320 } |
4030 | 321 |
4031 static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
int h) | 322 void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int
*ty, int *tw, int *th) |
| 323 { |
| 324 » int srcx = 0, srcy = 0; |
| 325 |
| 326 » IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); |
| 327 |
| 328 » *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS); |
| 329 » *th = ((y + h - 1) >> IMAPAINT_TILE_BITS); |
| 330 » *tx = (x >> IMAPAINT_TILE_BITS); |
| 331 » *ty = (y >> IMAPAINT_TILE_BITS); |
| 332 } |
| 333 |
| 334 void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h) |
4032 { | 335 { |
4033 ImBuf *tmpibuf = NULL; | 336 ImBuf *tmpibuf = NULL; |
4034 » int srcx= 0, srcy= 0, origx; | 337 » int tilex, tiley, tilew, tileh, tx, ty; |
| 338 » int srcx = 0, srcy = 0; |
4035 | 339 |
4036 IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); | 340 IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); |
4037 | 341 |
4038 if (w == 0 || h == 0) | 342 if (w == 0 || h == 0) |
4039 return; | 343 return; |
4040 ········ | 344 ········ |
4041 if (!imapaintpartial.enabled) { | 345 if (!imapaintpartial.enabled) { |
4042 imapaintpartial.x1 = x; | 346 imapaintpartial.x1 = x; |
4043 imapaintpartial.y1 = y; | 347 imapaintpartial.y1 = y; |
4044 » » imapaintpartial.x2 = x+w; | 348 » » imapaintpartial.x2 = x + w; |
4045 » » imapaintpartial.y2 = y+h; | 349 » » imapaintpartial.y2 = y + h; |
4046 imapaintpartial.enabled = 1; | 350 imapaintpartial.enabled = 1; |
4047 } | 351 } |
4048 else { | 352 else { |
4049 » » imapaintpartial.x1 = MIN2(imapaintpartial.x1, x); | 353 » » imapaintpartial.x1 = min_ii(imapaintpartial.x1, x); |
4050 » » imapaintpartial.y1 = MIN2(imapaintpartial.y1, y); | 354 » » imapaintpartial.y1 = min_ii(imapaintpartial.y1, y); |
4051 » » imapaintpartial.x2 = MAX2(imapaintpartial.x2, x+w); | 355 » » imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w); |
4052 » » imapaintpartial.y2 = MAX2(imapaintpartial.y2, y+h); | 356 » » imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h); |
4053 » } | 357 » } |
4054 | 358 |
4055 » w = ((x + w - 1) >> IMAPAINT_TILE_BITS); | 359 » imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh); |
4056 » h = ((y + h - 1) >> IMAPAINT_TILE_BITS); | 360 |
4057 » origx = (x >> IMAPAINT_TILE_BITS); | 361 » for (ty = tiley; ty <= tileh; ty++) |
4058 » y = (y >> IMAPAINT_TILE_BITS); | 362 » » for (tx = tilex; tx <= tilew; tx++) |
4059 »······· | 363 » » » image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty); |
4060 » for (; y <= h; y++) | |
4061 » » for (x=origx; x <= w; x++) | |
4062 » » » image_undo_push_tile(ima, ibuf, &tmpibuf, x, y); | |
4063 | 364 |
4064 ibuf->userflags |= IB_BITMAPDIRTY; | 365 ibuf->userflags |= IB_BITMAPDIRTY; |
4065 ········ | 366 ········ |
4066 if (tmpibuf) | 367 if (tmpibuf) |
4067 IMB_freeImBuf(tmpibuf); | 368 IMB_freeImBuf(tmpibuf); |
4068 } | 369 } |
4069 | 370 |
4070 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s
hort texpaint) | 371 void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
xpaint) |
4071 { | 372 { |
4072 » if(ibuf->rect_float) | 373 » if (imapaintpartial.x1 != imapaintpartial.x2 && |
4073 » » ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char re
ct */ | 374 » imapaintpartial.y1 != imapaintpartial.y2) |
4074 »······· | 375 » { |
4075 » if(ibuf->mipmap[0]) | 376 » » IMB_partial_display_buffer_update_delayed(ibuf, imapaintpartial.
x1, imapaintpartial.y1, |
| 377 » » imapaintpartial.x2, im
apaintpartial.y2); |
| 378 » } |
| 379 »······· |
| 380 » if (ibuf->mipmap[0]) |
4076 ibuf->userflags |= IB_MIPMAP_INVALID; | 381 ibuf->userflags |= IB_MIPMAP_INVALID; |
4077 | 382 |
4078 /* todo: should set_tpage create ->rect? */ | 383 /* todo: should set_tpage create ->rect? */ |
4079 » if(texpaint || (sima && sima->lock)) { | 384 » if (texpaint || (sima && sima->lock)) { |
4080 int w = imapaintpartial.x2 - imapaintpartial.x1; | 385 int w = imapaintpartial.x2 - imapaintpartial.x1; |
4081 int h = imapaintpartial.y2 - imapaintpartial.y1; | 386 int h = imapaintpartial.y2 - imapaintpartial.y1; |
4082 » » GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartia
l.y1, w, h, !texpaint); | 387 » » /* Testing with partial update in uv editor too */ |
4083 » } | 388 » » GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartia
l.y1, w, h); //!texpaint); |
4084 } | 389 » } |
4085 | 390 } |
4086 /* Image Paint Operations */ | 391 |
4087 | 392 /************************ image paint poll ************************/ |
4088 static void imapaint_ibuf_get_set_rgb(ImBuf *ibuf, int x, int y, short torus, sh
ort set, float *rgb) | 393 |
4089 { | 394 static Brush *image_paint_brush(bContext *C) |
4090 » if (torus) { | 395 { |
4091 » » x %= ibuf->x; | 396 » Scene *scene = CTX_data_scene(C); |
4092 » » if (x < 0) x += ibuf->x; | 397 » ToolSettings *settings = scene->toolsettings; |
4093 » » y %= ibuf->y; | 398 |
4094 » » if (y < 0) y += ibuf->y; | 399 » return BKE_paint_brush(&settings->imapaint.paint); |
4095 » } | 400 } |
4096 | 401 |
4097 » if (ibuf->rect_float) { | 402 static int image_paint_poll(bContext *C) |
4098 » » float *rrgbf = ibuf->rect_float + (ibuf->x*y + x)*4; | 403 { |
4099 | 404 » Object *obact = CTX_data_active_object(C); |
4100 » » if (set) { | 405 |
4101 » » » IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb); | 406 » if (!image_paint_brush(C)) |
4102 » » } else { | 407 » » return 0; |
4103 » » » IMAPAINT_FLOAT_RGB_COPY(rgb, rrgbf); | 408 |
4104 » » } | 409 » if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view
3d(C)) { |
| 410 » » return 1; |
4105 } | 411 } |
4106 else { | 412 else { |
4107 » » char *rrgb = (char*)ibuf->rect + (ibuf->x*y + x)*4; | 413 » » SpaceImage *sima = CTX_wm_space_image(C); |
4108 | 414 |
4109 » » if (set) { | 415 » » if (sima) { |
4110 » » » IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb) | 416 » » » ARegion *ar = CTX_wm_region(C); |
4111 » » } else { | 417 |
4112 » » » IMAPAINT_CHAR_RGB_TO_FLOAT(rgb, rrgb) | 418 » » » if ((sima->mode == SI_MODE_PAINT) && ar->regiontype == R
GN_TYPE_WINDOW) { |
4113 » » } | 419 » » » » return 1; |
4114 » } | 420 » » » } |
4115 } | 421 » » } |
4116 | 422 » } |
4117 static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
at *outrgb, short torus) | 423 |
4118 { | 424 » return 0; |
4119 » float inrgb[3]; | 425 } |
4120 | 426 |
4121 » // XXX: signed unsigned mismatch | 427 static int image_paint_2d_clone_poll(bContext *C) |
4122 » if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) { | 428 { |
4123 » » if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb); | 429 » Brush *brush = image_paint_brush(C); |
4124 » » else return 0; | 430 |
4125 » } | 431 » if (!CTX_wm_region_view3d(C) && image_paint_poll(C)) |
4126 » else imapaint_ibuf_get_set_rgb(ibuf, x, y, 0, 0, inrgb); | 432 » » if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) |
4127 | 433 » » » if (brush->clone.image) |
4128 » outrgb[0] += inrgb[0]; | 434 » » » » return 1; |
4129 » outrgb[1] += inrgb[1]; | 435 »······· |
4130 » outrgb[2] += inrgb[2]; | 436 » return 0; |
4131 | 437 } |
4132 » return 1; | 438 |
4133 } | 439 /************************ paint operator ************************/ |
4134 | 440 typedef enum TexPaintMode { |
4135 static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, short toru
s) | 441 » PAINT_MODE_2D, |
4136 { | 442 » PAINT_MODE_3D_PROJECT |
4137 » int x, y, count, xi, yi, xo, yo; | 443 } TexPaintMode; |
4138 » int out_off[2], in_off[2], dim[2]; | 444 |
4139 » float outrgb[3]; | 445 typedef struct PaintOperation { |
4140 | 446 » TexPaintMode mode; |
4141 » dim[0] = ibufb->x; | 447 |
4142 » dim[1] = ibufb->y; | 448 » void *custom_paint; |
4143 » in_off[0] = pos[0]; | 449 |
4144 » in_off[1] = pos[1]; | 450 » float prevmouse[2]; |
4145 » out_off[0] = out_off[1] = 0; | 451 » double starttime; |
4146 | 452 |
4147 » if (!torus) { | 453 » ViewContext vc; |
4148 » » IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], | 454 } PaintOperation; |
4149 » » » &out_off[1], &dim[0], &dim[1]); | 455 |
4150 | 456 void paint_brush_init_tex(Brush *brush) |
4151 » » if ((dim[0] == 0) || (dim[1] == 0)) | 457 { |
4152 » » » return; | 458 » /* init mtex nodes */ |
4153 » } | 459 » if (brush) { |
4154 | 460 » » MTex *mtex = &brush->mtex; |
4155 » for (y=0; y < dim[1]; y++) { | 461 » » if (mtex->tex && mtex->tex->nodetree) |
4156 » » for (x=0; x < dim[0]; x++) { | 462 » » » ntreeTexBeginExecTree(mtex->tex->nodetree); /* has inte
rnal flag to detect it only does it once */ |
4157 » » » /* get input pixel */ | 463 » » mtex = &brush->mask_mtex; |
4158 » » » xi = in_off[0] + x; | 464 » » if (mtex->tex && mtex->tex->nodetree) |
4159 » » » yi = in_off[1] + y; | 465 » » » ntreeTexBeginExecTree(mtex->tex->nodetree); |
4160 | 466 » } |
4161 » » » count = 1; | 467 } |
4162 » » » imapaint_ibuf_get_set_rgb(ibuf, xi, yi, torus, 0, outrgb
); | 468 |
4163 | 469 void paint_brush_exit_tex(Brush *brush) |
4164 » » » count += imapaint_ibuf_add_if(ibuf, xi-1, yi-1, outrgb,
torus); | 470 { |
4165 » » » count += imapaint_ibuf_add_if(ibuf, xi-1, yi , outrgb,
torus); | 471 » if (brush) { |
4166 » » » count += imapaint_ibuf_add_if(ibuf, xi-1, yi+1, outrgb,
torus); | 472 » » MTex *mtex = &brush->mtex; |
4167 | 473 » » if (mtex->tex && mtex->tex->nodetree) |
4168 » » » count += imapaint_ibuf_add_if(ibuf, xi , yi-1, outrgb,
torus); | 474 » » » ntreeTexEndExecTree(mtex->tex->nodetree->execdata); |
4169 » » » count += imapaint_ibuf_add_if(ibuf, xi , yi+1, outrgb,
torus); | 475 » » mtex = &brush->mask_mtex; |
4170 | 476 » » if (mtex->tex && mtex->tex->nodetree) |
4171 » » » count += imapaint_ibuf_add_if(ibuf, xi+1, yi-1, outrgb,
torus); | 477 » » » ntreeTexEndExecTree(mtex->tex->nodetree->execdata); |
4172 » » » count += imapaint_ibuf_add_if(ibuf, xi+1, yi , outrgb,
torus); | 478 » } |
4173 » » » count += imapaint_ibuf_add_if(ibuf, xi+1, yi+1, outrgb,
torus); | 479 } |
4174 | 480 |
4175 » » » outrgb[0] /= count; | 481 |
4176 » » » outrgb[1] /= count; | 482 static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mou
se[2]) |
4177 » » » outrgb[2] /= count; | 483 { |
4178 | 484 » Scene *scene = CTX_data_scene(C); |
4179 » » » /* write into brush buffer */ | 485 » ToolSettings *settings = scene->toolsettings; |
4180 » » » xo = out_off[0] + x; | 486 » PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperatio
n"); /* caller frees */ |
4181 » » » yo = out_off[1] + y; | 487 » int mode = RNA_enum_get(op->ptr, "mode"); |
4182 » » » imapaint_ibuf_get_set_rgb(ibufb, xo, yo, 0, 1, outrgb); | 488 » view3d_set_viewcontext(C, &pop->vc); |
4183 » » } | 489 |
4184 » } | 490 » pop->prevmouse[0] = mouse[0]; |
4185 } | 491 » pop->prevmouse[1] = mouse[1]; |
4186 | 492 |
4187 static void imapaint_set_region(ImagePaintRegion *region, int destx, int desty,
int srcx, int srcy, int width, int height) | 493 » /* initialize from context */ |
4188 { | 494 » if (CTX_wm_region_view3d(C)) { |
4189 » region->destx= destx; | 495 » » pop->mode = PAINT_MODE_3D_PROJECT; |
4190 » region->desty= desty; | 496 » » pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmou
se, mode); |
4191 » region->srcx= srcx; | |
4192 » region->srcy= srcy; | |
4193 » region->width= width; | |
4194 » region->height= height; | |
4195 } | |
4196 | |
4197 static int imapaint_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf,
ImBuf *sbuf) | |
4198 { | |
4199 » int destx= region->destx; | |
4200 » int desty= region->desty; | |
4201 » int srcx= region->srcx; | |
4202 » int srcy= region->srcy; | |
4203 » int width= region->width; | |
4204 » int height= region->height; | |
4205 » int origw, origh, w, h, tot= 0; | |
4206 | |
4207 » /* convert destination and source coordinates to be within image */ | |
4208 » destx = destx % dbuf->x; | |
4209 » if (destx < 0) destx += dbuf->x; | |
4210 » desty = desty % dbuf->y; | |
4211 » if (desty < 0) desty += dbuf->y; | |
4212 » srcx = srcx % sbuf->x; | |
4213 » if (srcx < 0) srcx += sbuf->x; | |
4214 » srcy = srcy % sbuf->y; | |
4215 » if (srcy < 0) srcy += sbuf->y; | |
4216 | |
4217 » /* clip width of blending area to destination imbuf, to avoid writing th
e | |
4218 » same pixel twice */ | |
4219 » origw = w = (width > dbuf->x)? dbuf->x: width; | |
4220 » origh = h = (height > dbuf->y)? dbuf->y: height; | |
4221 | |
4222 » /* clip within image */ | |
4223 » IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h); | |
4224 » imapaint_set_region(®ion[tot++], destx, desty, srcx, srcy, w, h); | |
4225 | |
4226 » /* do 3 other rects if needed */ | |
4227 » if (w < origw) | |
4228 » » imapaint_set_region(®ion[tot++], (destx+w)%dbuf->x, desty, (s
rcx+w)%sbuf->x, srcy, origw-w, h); | |
4229 » if (h < origh) | |
4230 » » imapaint_set_region(®ion[tot++], destx, (desty+h)%dbuf->y, sr
cx, (srcy+h)%sbuf->y, w, origh-h); | |
4231 » if ((w < origw) && (h < origh)) | |
4232 » » imapaint_set_region(®ion[tot++], (destx+w)%dbuf->x, (desty+h)
%dbuf->y, (srcx+w)%sbuf->x, (srcy+h)%sbuf->y, origw-w, origh-h); | |
4233 »······· | |
4234 » return tot; | |
4235 } | |
4236 | |
4237 static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) | |
4238 { | |
4239 » ImagePaintRegion region[4]; | |
4240 » int a, tot; | |
4241 | |
4242 » imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y); | |
4243 » tot= imapaint_torus_split_region(region, ibufb, ibuf); | |
4244 | |
4245 » for(a=0; a<tot; a++) | |
4246 » » IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty, | |
4247 » » » region[a].srcx, region[a].srcy, | |
4248 » » » region[a].width, region[a].height, IMB_BLEND_COPY_RGB); | |
4249 } | |
4250 | |
4251 static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) | |
4252 { | |
4253 » /* note: allocImbuf returns zero'd memory, so regions outside image will | |
4254 » have zero alpha, and hence not be blended onto the image */ | |
4255 » int w=ibufb->x, h=ibufb->y, destx=0, desty=0, srcx=pos[0], srcy=pos[1]; | |
4256 » ImBuf *clonebuf= IMB_allocImBuf(w, h, ibufb->depth, ibufb->flags); | |
4257 | |
4258 » IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); | |
4259 » IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h, | |
4260 » » IMB_BLEND_COPY_RGB); | |
4261 » IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h, | |
4262 » » IMB_BLEND_COPY_ALPHA); | |
4263 | |
4264 » return clonebuf; | |
4265 } | |
4266 | |
4267 static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos) | |
4268 { | |
4269 » ipos[0]= (int)(pos[0] - ibufb->x/2); | |
4270 » ipos[1]= (int)(pos[1] - ibufb->y/2); | |
4271 } | |
4272 | |
4273 /* dosnt run for projection painting | |
4274 * only the old style painting in the 3d view */ | |
4275 static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *p
os) | |
4276 { | |
4277 » ImagePaintState *s= ((ImagePaintState*)state); | |
4278 » ImBuf *clonebuf= NULL, *frombuf; | |
4279 » ImagePaintRegion region[4]; | |
4280 » short torus= s->brush->flag & BRUSH_TORUS; | |
4281 » short blend= s->blend; | |
4282 » float *offset= s->brush->clone.offset; | |
4283 » float liftpos[2]; | |
4284 » int bpos[2], blastpos[2], bliftpos[2]; | |
4285 » int a, tot; | |
4286 | |
4287 » imapaint_convert_brushco(ibufb, pos, bpos); | |
4288 | |
4289 » /* lift from canvas */ | |
4290 » if(s->tool == PAINT_TOOL_SOFTEN) { | |
4291 » » imapaint_lift_soften(s->canvas, ibufb, bpos, torus); | |
4292 » } | |
4293 » else if(s->tool == PAINT_TOOL_SMEAR) { | |
4294 » » if (lastpos[0]==pos[0] && lastpos[1]==pos[1]) | |
4295 » » » return 0; | |
4296 | |
4297 » » imapaint_convert_brushco(ibufb, lastpos, blastpos); | |
4298 » » imapaint_lift_smear(s->canvas, ibufb, blastpos); | |
4299 » } | |
4300 » else if(s->tool == PAINT_TOOL_CLONE && s->clonecanvas) { | |
4301 » » liftpos[0]= pos[0] - offset[0]*s->canvas->x; | |
4302 » » liftpos[1]= pos[1] - offset[1]*s->canvas->y; | |
4303 | |
4304 » » imapaint_convert_brushco(ibufb, liftpos, bliftpos); | |
4305 » » clonebuf= imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos); | |
4306 » } | |
4307 | |
4308 » frombuf= (clonebuf)? clonebuf: ibufb; | |
4309 | |
4310 » if(torus) { | |
4311 » » imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x,
frombuf->y); | |
4312 » » tot= imapaint_torus_split_region(region, s->canvas, frombuf); | |
4313 } | 497 } |
4314 else { | 498 else { |
4315 imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x,
frombuf->y); | 499 pop->mode = PAINT_MODE_2D; |
4316 tot= 1; | 500 pop->custom_paint = paint_2d_new_stroke(C, op); |
4317 } | 501 } |
4318 | 502 |
4319 /* blend into canvas */ | 503 if (!pop->custom_paint) { |
4320 for(a=0; a<tot; a++) { | 504 MEM_freeN(pop); |
4321 imapaint_dirty_region(s->image, s->canvas, | 505 return NULL; |
4322 region[a].destx, region[a].desty, | 506 } |
4323 region[a].width, region[a].height); | 507 |
4324 ················ | |
4325 IMB_rectblend(s->canvas, frombuf, | |
4326 region[a].destx, region[a].desty, | |
4327 region[a].srcx, region[a].srcy, | |
4328 region[a].width, region[a].height, blend); | |
4329 } | |
4330 | |
4331 if(clonebuf) IMB_freeImBuf(clonebuf); | |
4332 | |
4333 return 1; | |
4334 } | |
4335 | |
4336 /* 3D TexturePaint */ | |
4337 | |
4338 static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float
*uv) | |
4339 { | |
4340 float d1[2], d2[2]; | |
4341 float mismatch = len_v2v2(fwuv, uv); | |
4342 float len1 = len_v2v2(prevuv, fwuv); | |
4343 float len2 = len_v2v2(bkuv, uv); | |
4344 | |
4345 sub_v2_v2v2(d1, fwuv, prevuv); | |
4346 sub_v2_v2v2(d2, uv, bkuv); | |
4347 | |
4348 return ((dot_v2v2(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2)*2)); | |
4349 } | |
4350 | |
4351 /* ImagePaint Common */ | |
4352 | |
4353 static int imapaint_canvas_set(ImagePaintState *s, Image *ima) | |
4354 { | |
4355 ImBuf *ibuf= BKE_image_get_ibuf(ima, s->sima? &s->sima->iuser: NULL); | |
4356 ········ | |
4357 /* verify that we can paint and set canvas */ | |
4358 if(ima==NULL) { | |
4359 return 0; | |
4360 } | |
4361 else if(ima->packedfile && ima->rr) { | |
4362 s->warnpackedfile = ima->id.name + 2; | |
4363 return 0; | |
4364 }······· | |
4365 else if(ibuf && ibuf->channels!=4) { | |
4366 s->warnmultifile = ima->id.name + 2; | |
4367 return 0; | |
4368 } | |
4369 else if(!ibuf || !(ibuf->rect || ibuf->rect_float)) | |
4370 return 0; | |
4371 | |
4372 s->image= ima; | |
4373 s->canvas= ibuf; | |
4374 | |
4375 /* set clone canvas */ | |
4376 if(s->tool == PAINT_TOOL_CLONE) { | |
4377 ima= s->brush->clone.image; | |
4378 ibuf= BKE_image_get_ibuf(ima, s->sima? &s->sima->iuser: NULL); | |
4379 ················ | |
4380 if(!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) | |
4381 return 0; | |
4382 | |
4383 s->clonecanvas= ibuf; | |
4384 | |
4385 /* temporarily add float rect for cloning */ | |
4386 if(s->canvas->rect_float && !s->clonecanvas->rect_float) { | |
4387 int profile = IB_PROFILE_NONE; | |
4388 ························ | |
4389 /* Don't want to color manage, but don't disturb existin
g profiles */ | |
4390 SWAP(int, s->clonecanvas->profile, profile); | |
4391 | |
4392 IMB_float_from_rect(s->clonecanvas); | |
4393 s->clonefreefloat= 1; | |
4394 ························ | |
4395 SWAP(int, s->clonecanvas->profile, profile); | |
4396 } | |
4397 else if(!s->canvas->rect_float && !s->clonecanvas->rect) | |
4398 IMB_rect_from_float(s->clonecanvas); | |
4399 } | |
4400 | |
4401 return 1; | |
4402 } | |
4403 | |
4404 static void imapaint_canvas_free(ImagePaintState *s) | |
4405 { | |
4406 if (s->clonefreefloat) | |
4407 imb_freerectfloatImBuf(s->clonecanvas); | |
4408 } | |
4409 | |
4410 static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter,
Image *image, short texpaint, float *uv, double time, int update, float pressure
) | |
4411 { | |
4412 ImBuf *ibuf= BKE_image_get_ibuf(image, s->sima? &s->sima->iuser: NULL); | |
4413 float pos[2]; | |
4414 | |
4415 if(!ibuf) | |
4416 return 0; | |
4417 | |
4418 pos[0] = uv[0]*ibuf->x; | |
4419 pos[1] = uv[1]*ibuf->y; | |
4420 | |
4421 brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0); | |
4422 | |
4423 if (brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure,
s, ibuf->profile == IB_PROFILE_LINEAR_RGB)) { | |
4424 if (update) | |
4425 imapaint_image_update(s->sima, image, ibuf, texpaint); | |
4426 return 1; | |
4427 } | |
4428 else return 0; | |
4429 } | |
4430 | |
4431 static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
er *painter, short texpaint, const int prevmval[2], const int mval[2], double ti
me, float pressure) | |
4432 { | |
4433 Image *newimage = NULL; | |
4434 float fwuv[2], bkuv[2], newuv[2]; | |
4435 unsigned int newfaceindex; | |
4436 int breakstroke = 0, redraw = 0; | |
4437 | |
4438 if (texpaint) { | |
4439 /* pick new face and image */ | |
4440 if ( imapaint_pick_face(vc, s->me, mval, &newfaceindex) && | |
4441 ((s->me->editflag & ME_EDIT_PAINT_MASK)==0 || (s
->me->mface+newfaceindex)->flag & ME_FACE_SEL) | |
4442 ) { | |
4443 ImBuf *ibuf; | |
4444 ························ | |
4445 newimage = (s->me->mtface+newfaceindex)->tpage; | |
4446 ibuf= BKE_image_get_ibuf(newimage, s->sima? &s->sima->iu
ser: NULL); | |
4447 | |
4448 if(ibuf && ibuf->rect) | |
4449 imapaint_pick_uv(s->scene, s->ob, newfaceindex,
mval, newuv); | |
4450 else { | |
4451 newimage = NULL; | |
4452 newuv[0] = newuv[1] = 0.0f; | |
4453 } | |
4454 } | |
4455 else | |
4456 newuv[0] = newuv[1] = 0.0f; | |
4457 | |
4458 /* see if stroke is broken, and if so finish painting in old pos
ition */ | |
4459 if (s->image) { | |
4460 imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fw
uv); | |
4461 imapaint_pick_uv(s->scene, s->ob, newfaceindex, prevmval
, bkuv); | |
4462 | |
4463 if (newimage == s->image) | |
4464 breakstroke= texpaint_break_stroke(s->uv, fwuv,
bkuv, newuv); | |
4465 else | |
4466 breakstroke= 1; | |
4467 } | |
4468 else | |
4469 fwuv[0]= fwuv[1]= 0.0f; | |
4470 | |
4471 if (breakstroke) { | |
4472 imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fw
uv); | |
4473 redraw |= imapaint_paint_sub_stroke(s, painter, s->image
, texpaint, | |
4474 fwuv, time, 1, pressure); | |
4475 imapaint_clear_partial_redraw(); | |
4476 brush_painter_break_stroke(painter); | |
4477 } | |
4478 | |
4479 /* set new canvas */ | |
4480 if (newimage && (newimage != s->image)) | |
4481 if (!imapaint_canvas_set(s, newimage)) | |
4482 newimage = NULL; | |
4483 | |
4484 /* paint in new image */ | |
4485 if (newimage) { | |
4486 if (breakstroke) | |
4487 redraw|= imapaint_paint_sub_stroke(s, painter, n
ewimage, | |
4488 texpaint, bkuv, time, 0, pressure); | |
4489 redraw|= imapaint_paint_sub_stroke(s, painter, newimage,
texpaint, | |
4490 newuv, time, 1, pressure); | |
4491 } | |
4492 | |
4493 /* update state */ | |
4494 s->image = newimage; | |
4495 s->faceindex = newfaceindex; | |
4496 s->uv[0] = newuv[0]; | |
4497 s->uv[1] = newuv[1]; | |
4498 } | |
4499 else { | |
4500 UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &n
ewuv[1]); | |
4501 redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpai
nt, newuv, | |
4502 time, 1, pressure); | |
4503 } | |
4504 | |
4505 if (redraw) | |
4506 imapaint_clear_partial_redraw(); | |
4507 | |
4508 return redraw; | |
4509 } | |
4510 | |
4511 /************************ image paint poll ************************/ | |
4512 | |
4513 static Brush *image_paint_brush(bContext *C) | |
4514 { | |
4515 Scene *scene= CTX_data_scene(C); | |
4516 ToolSettings *settings= scene->toolsettings; | |
4517 | |
4518 return paint_brush(&settings->imapaint.paint); | |
4519 } | |
4520 | |
4521 static int image_paint_poll(bContext *C) | |
4522 { | |
4523 Object *obact = CTX_data_active_object(C); | |
4524 | |
4525 if(!image_paint_brush(C)) | |
4526 return 0; | |
4527 | |
4528 if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3
d(C)) { | |
4529 return 1; | |
4530 } | |
4531 else { | |
4532 SpaceImage *sima= CTX_wm_space_image(C); | |
4533 | |
4534 if(sima) { | |
4535 ARegion *ar= CTX_wm_region(C); | |
4536 | |
4537 if((sima->flag & SI_DRAWTOOL) && ar->regiontype==RGN_TYP
E_WINDOW) | |
4538 return 1; | |
4539 } | |
4540 } | |
4541 | |
4542 return 0; | |
4543 } | |
4544 | |
4545 static int image_paint_3d_poll(bContext *C) | |
4546 { | |
4547 if(CTX_wm_region_view3d(C)) | |
4548 return image_paint_poll(C); | |
4549 ········ | |
4550 return 0; | |
4551 } | |
4552 | |
4553 static int image_paint_2d_clone_poll(bContext *C) | |
4554 { | |
4555 Brush *brush= image_paint_brush(C); | |
4556 | |
4557 if(!CTX_wm_region_view3d(C) && image_paint_poll(C)) | |
4558 if(brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) | |
4559 if(brush->clone.image) | |
4560 return 1; | |
4561 ········ | |
4562 return 0; | |
4563 } | |
4564 | |
4565 /************************ paint operator ************************/ | |
4566 | |
4567 typedef enum PaintMode { | |
4568 PAINT_MODE_2D, | |
4569 PAINT_MODE_3D, | |
4570 PAINT_MODE_3D_PROJECT | |
4571 } PaintMode; | |
4572 | |
4573 typedef struct PaintOperation { | |
4574 PaintMode mode; | |
4575 | |
4576 BrushPainter *painter; | |
4577 ImagePaintState s; | |
4578 ProjPaintState ps; | |
4579 | |
4580 int first; | |
4581 int prevmouse[2]; | |
4582 float prev_pressure; /* need this since we dont get tablet events for pr
essure change */ | |
4583 int orig_brush_size; | |
4584 double starttime; | |
4585 | |
4586 ViewContext vc; | |
4587 wmTimer *timer; | |
4588 | |
4589 short restore_projection; | |
4590 } PaintOperation; | |
4591 | |
4592 static void paint_redraw(bContext *C, ImagePaintState *s, int final) | |
4593 { | |
4594 if(final) { | |
4595 if(s->image) | |
4596 GPU_free_image(s->image); | |
4597 | |
4598 /* compositor listener deals with updating */ | |
4599 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, s->image); | |
4600 } | |
4601 else { | |
4602 if(!s->sima || !s->sima->lock) | |
4603 ED_region_tag_redraw(CTX_wm_region(C)); | |
4604 else | |
4605 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, s->image); | |
4606 } | |
4607 } | |
4608 | |
4609 /* initialize project paint settings from context */ | |
4610 static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps) | |
4611 { | |
4612 Scene *scene= CTX_data_scene(C); | |
4613 ToolSettings *settings= scene->toolsettings; | |
4614 Brush *brush= paint_brush(&settings->imapaint.paint); | |
4615 | |
4616 /* brush */ | |
4617 ps->brush = brush; | |
4618 ps->tool = brush->imagepaint_tool; | |
4619 ps->blend = brush->blend; | |
4620 | |
4621 ps->is_airbrush = (brush->flag & BRUSH_AIRBRUSH) ? 1 : 0; | |
4622 ps->is_texbrush = (brush->mtex.tex) ? 1 : 0; | |
4623 | |
4624 | |
4625 /* these can be NULL */ | |
4626 ps->v3d= CTX_wm_view3d(C); | |
4627 ps->rv3d= CTX_wm_region_view3d(C); | |
4628 ps->ar= CTX_wm_region(C); | |
4629 | |
4630 ps->scene= scene; | |
4631 ps->ob= ob; /* allow override of active object */ | |
4632 | |
4633 /* setup projection painting data */ | |
4634 ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACK
FACE) ? 0 : 1; | |
4635 ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0
: 1; | |
4636 ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT)
? 0 : 1; | |
4637 | |
4638 if (ps->tool == PAINT_TOOL_CLONE) | |
4639 ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJE
CT_LAYER_CLONE); | |
4640 | |
4641 ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAY
ER_STENCIL) ? 1 : 0; | |
4642 ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT
_LAYER_STENCIL_INV) ? 1 : 0; | |
4643 | |
4644 | |
4645 #ifndef PROJ_DEBUG_NOSEAMBLEED | |
4646 ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed
*/ | |
4647 #endif | |
4648 | |
4649 if(ps->do_mask_normal) { | |
4650 ps->normal_angle_inner = settings->imapaint.normal_angle; | |
4651 ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f; | |
4652 } | |
4653 else { | |
4654 ps->normal_angle_inner= ps->normal_angle= settings->imapaint.nor
mal_angle; | |
4655 } | |
4656 | |
4657 ps->normal_angle_inner *= (float)(M_PI_2 / 90); | |
4658 ps->normal_angle *= (float)(M_PI_2 / 90); | |
4659 ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner; | |
4660 | |
4661 if(ps->normal_angle_range <= 0.0f) | |
4662 ps->do_mask_normal = 0; /* no need to do blending */ | |
4663 } | |
4664 | |
4665 static void paint_brush_init_tex(Brush *brush) | |
4666 { | |
4667 /* init mtex nodes */· | |
4668 if(brush) { | |
4669 MTex *mtex= &brush->mtex; | |
4670 if(mtex->tex && mtex->tex->nodetree) | |
4671 ntreeBeginExecTree(mtex->tex->nodetree); /* has internal
flag to detect it only does it once */ | |
4672 } | |
4673 ········ | |
4674 } | |
4675 | |
4676 static int texture_paint_init(bContext *C, wmOperator *op) | |
4677 { | |
4678 Scene *scene= CTX_data_scene(C); | |
4679 ToolSettings *settings= scene->toolsettings; | |
4680 Brush *brush= paint_brush(&settings->imapaint.paint); | |
4681 PaintOperation *pop= MEM_callocN(sizeof(PaintOperation), "PaintOperation
"); /* caller frees */ | |
4682 | |
4683 pop->first= 1; | |
4684 op->customdata= pop; | |
4685 ········ | |
4686 /* XXX: Soften tool does not support projection painting atm, so just di
sable | |
4687 projection for this brush */ | |
4688 if(brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { | |
4689 settings->imapaint.flag |= IMAGEPAINT_PROJECT_DISABLE; | |
4690 pop->restore_projection = 1; | |
4691 } | |
4692 | |
4693 /* initialize from context */ | |
4694 if(CTX_wm_region_view3d(C)) { | |
4695 pop->mode= PAINT_MODE_3D; | |
4696 | |
4697 if(!(settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE)) | |
4698 pop->mode= PAINT_MODE_3D_PROJECT; | |
4699 else | |
4700 view3d_set_viewcontext(C, &pop->vc); | |
4701 } | |
4702 else { | |
4703 pop->s.sima= CTX_wm_space_image(C); | |
4704 pop->s.v2d= &CTX_wm_region(C)->v2d; | |
4705 } | |
4706 | |
4707 pop->s.scene= scene; | |
4708 pop->s.screen= CTX_wm_screen(C); | |
4709 | |
4710 pop->s.brush = brush; | |
4711 pop->s.tool = brush->imagepaint_tool; | |
4712 if(pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE)) | |
4713 pop->s.tool = PAINT_TOOL_DRAW; | |
4714 pop->s.blend = brush->blend; | |
4715 pop->orig_brush_size= brush_size(brush); | |
4716 | |
4717 if(pop->mode != PAINT_MODE_2D) { | |
4718 pop->s.ob = OBACT; | |
4719 pop->s.me = get_mesh(pop->s.ob); | |
4720 if (!pop->s.me) return 0; | |
4721 } | |
4722 else { | |
4723 pop->s.image = pop->s.sima->image; | |
4724 | |
4725 if(!imapaint_canvas_set(&pop->s, pop->s.image)) { | |
4726 if(pop->s.warnmultifile) | |
4727 BKE_report(op->reports, RPT_WARNING, "Image requ
ires 4 color channels to paint"); | |
4728 if(pop->s.warnpackedfile) | |
4729 BKE_report(op->reports, RPT_WARNING, "Packed Mul
tiLayer files cannot be painted"); | |
4730 | |
4731 return 0; | |
4732 } | |
4733 } | |
4734 ········ | |
4735 paint_brush_init_tex(pop->s.brush); | |
4736 ········ | |
4737 /* note, if we have no UVs on the derived mesh, then we must return here
*/ | |
4738 if(pop->mode == PAINT_MODE_3D_PROJECT) { | |
4739 | |
4740 /* initialize all data from the context */ | |
4741 project_state_init(C, OBACT, &pop->ps); | |
4742 ················ | |
4743 paint_brush_init_tex(pop->ps.brush); | |
4744 | |
4745 pop->ps.source= PROJ_SRC_VIEW; | |
4746 | |
4747 if (pop->ps.ob==NULL || !(pop->ps.ob->lay & pop->ps.v3d->lay)) | |
4748 return 0; | |
4749 | |
4750 /* Dont allow brush size below 2 */ | |
4751 if (brush_size(brush) < 2) | |
4752 brush_set_size(brush, 2); | |
4753 | |
4754 /* allocate and initialize spacial data structures */ | |
4755 project_paint_begin(&pop->ps); | |
4756 ················ | |
4757 if(pop->ps.dm==NULL) | |
4758 return 0; | |
4759 } | |
4760 ········ | |
4761 settings->imapaint.flag |= IMAGEPAINT_DRAWING; | 508 settings->imapaint.flag |= IMAGEPAINT_DRAWING; |
4762 undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, | 509 undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, |
4763 » » image_undo_restore, image_undo_free); | 510 » image_undo_restore, image_undo_free); |
4764 | 511 |
4765 » /* create painter */ | 512 » { |
4766 » pop->painter= brush_painter_new(pop->s.brush); | 513 » » UnifiedPaintSettings *ups = &settings->unified_paint_settings; |
4767 | 514 » » ups->draw_pressure = true; |
4768 » return 1; | 515 » } |
4769 } | 516 |
4770 | 517 » return pop; |
4771 static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) | 518 } |
4772 { | 519 |
4773 » PaintOperation *pop= op->customdata; | 520 static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
interRNA *itemptr) |
4774 » float time, mousef[2]; | 521 { |
| 522 » PaintOperation *pop = paint_stroke_mode_data(stroke); |
| 523 » Scene *scene = CTX_data_scene(C); |
| 524 » Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint); |
| 525 |
| 526 » /* initial brush values. Maybe it should be considered moving these to s
troke system */ |
| 527 » float startsize = (float)BKE_brush_size_get(scene, brush); |
| 528 » float startalpha = BKE_brush_alpha_get(scene, brush); |
| 529 |
| 530 » float mouse[2]; |
4775 float pressure; | 531 float pressure; |
4776 » int mouse[2], redraw; | 532 » int eraser; |
4777 | 533 |
4778 » RNA_float_get_array(itemptr, "mouse", mousef); | 534 » RNA_float_get_array(itemptr, "mouse", mouse); |
4779 » mouse[0] = (int)(mousef[0]); | 535 » pressure = RNA_float_get(itemptr, "pressure"); |
4780 » mouse[1] = (int)(mousef[1]); | 536 » eraser = RNA_boolean_get(itemptr, "pen_flip"); |
4781 » time= RNA_float_get(itemptr, "time"); | 537 |
4782 » pressure= RNA_float_get(itemptr, "pressure"); | 538 » if (BKE_brush_use_alpha_pressure(scene, brush)) |
4783 | 539 » » BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pres
sure)); |
4784 » if(pop->first) | 540 » if (BKE_brush_use_size_pressure(scene, brush)) |
4785 » » project_paint_begin_clone(&pop->ps, mouse); | 541 » » BKE_brush_size_set(scene, brush, max_ff(1.0f, startsize * pressu
re)); |
4786 | 542 |
4787 » if(pop->mode == PAINT_MODE_3D) | 543 » if (pop->mode == PAINT_MODE_3D_PROJECT) { |
4788 » » view3d_operator_needs_opengl(C); | 544 » » paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse); |
4789 | 545 » } |
4790 » if(pop->mode == PAINT_MODE_3D_PROJECT) { | 546 » else { |
4791 » » redraw= project_paint_stroke(&pop->ps, pop->painter, pop->prevmo
use, mouse, time, pressure); | 547 » » paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser
); |
4792 » » pop->prevmouse[0]= mouse[0]; | 548 » } |
4793 » » pop->prevmouse[1]= mouse[1]; | 549 |
4794 | 550 » pop->prevmouse[0] = mouse[0]; |
4795 » } | 551 » pop->prevmouse[1] = mouse[1]; |
4796 » else {· | 552 |
4797 » » redraw= imapaint_paint_stroke(&pop->vc, &pop->s, pop->painter, p
op->mode == PAINT_MODE_3D, pop->prevmouse, mouse, time, pressure); | 553 » /* restore brush values */ |
4798 » » pop->prevmouse[0]= mouse[0]; | 554 » BKE_brush_alpha_set(scene, brush, startalpha); |
4799 » » pop->prevmouse[1]= mouse[1]; | 555 » BKE_brush_size_set(scene, brush, startsize); |
4800 » } | 556 } |
4801 | 557 |
4802 » if(redraw) | 558 static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, b
ool final) |
4803 » » paint_redraw(C, &pop->s, 0); | 559 { |
4804 | 560 » PaintOperation *pop = paint_stroke_mode_data(stroke); |
4805 » pop->first= 0; | 561 |
4806 } | 562 » if (pop->mode == PAINT_MODE_3D_PROJECT) { |
4807 | 563 » » paint_proj_redraw(C, pop->custom_paint, final); |
4808 static void paint_brush_exit_tex(Brush *brush) | 564 » } |
4809 { | 565 » else { |
4810 » if(brush) { | 566 » » paint_2d_redraw(C, pop->custom_paint, final); |
4811 » » MTex *mtex= &brush->mtex; | 567 » } |
4812 » » if(mtex->tex && mtex->tex->nodetree) | 568 } |
4813 » » » ntreeEndExecTree(mtex->tex->nodetree); | 569 |
4814 » }»······ | 570 static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) |
4815 } | 571 { |
4816 | 572 » Scene *scene = CTX_data_scene(C); |
4817 static void paint_exit(bContext *C, wmOperator *op) | 573 » ToolSettings *settings = scene->toolsettings; |
4818 { | 574 » PaintOperation *pop = paint_stroke_mode_data(stroke); |
4819 » Scene *scene= CTX_data_scene(C); | 575 |
4820 » ToolSettings *settings= scene->toolsettings; | |
4821 » PaintOperation *pop= op->customdata; | |
4822 | |
4823 » if(pop->timer) | |
4824 » » WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->
timer); | |
4825 | |
4826 » if(pop->restore_projection) | |
4827 » » settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE; | |
4828 | |
4829 » paint_brush_exit_tex(pop->s.brush); | |
4830 »······· | |
4831 settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; | 576 settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; |
4832 » imapaint_canvas_free(&pop->s); | 577 |
4833 » brush_painter_free(pop->painter); | 578 » if (pop->mode == PAINT_MODE_3D_PROJECT) { |
4834 | 579 » » paint_proj_stroke_done(pop->custom_paint); |
4835 » if(pop->mode == PAINT_MODE_3D_PROJECT) { | 580 » } |
4836 » » brush_set_size(pop->ps.brush, pop->orig_brush_size); | 581 » else { |
4837 » » paint_brush_exit_tex(pop->ps.brush); | 582 » » paint_2d_stroke_done(pop->custom_paint); |
4838 » »······· | 583 » } |
4839 » » project_paint_end(&pop->ps); | 584 |
4840 » } | |
4841 »······· | |
4842 » paint_redraw(C, &pop->s, 1); | |
4843 undo_paint_push_end(UNDO_PAINT_IMAGE); | 585 undo_paint_push_end(UNDO_PAINT_IMAGE); |
4844 »······· | 586 |
4845 » if(pop->s.warnmultifile) | 587 » /* duplicate warning, see texpaint_init */ |
| 588 #if 0 |
| 589 » if (pop->s.warnmultifile) |
4846 BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color ch
annels to paint: %s", pop->s.warnmultifile); | 590 BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color ch
annels to paint: %s", pop->s.warnmultifile); |
4847 » if(pop->s.warnpackedfile) | 591 » if (pop->s.warnpackedfile) |
4848 BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files c
annot be painted: %s", pop->s.warnpackedfile); | 592 BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files c
annot be painted: %s", pop->s.warnpackedfile); |
4849 | 593 #endif |
4850 MEM_freeN(pop); | 594 MEM_freeN(pop); |
| 595 |
| 596 { |
| 597 UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_
settings; |
| 598 ups->draw_pressure = false; |
| 599 } |
| 600 } |
| 601 |
| 602 static int paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op),
const float UNUSED(mouse[2])) |
| 603 { |
| 604 return true; |
| 605 } |
| 606 |
| 607 |
| 608 static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) |
| 609 { |
| 610 PaintOperation *pop; |
| 611 float mouse[2]; |
| 612 int retval; |
| 613 |
| 614 /* TODO Should avoid putting this here. Instead, last position should be
requested |
| 615 * from stroke system. */ |
| 616 mouse[0] = event->mval[0]; |
| 617 mouse[1] = event->mval[1]; |
| 618 |
| 619 if (!(pop = texture_paint_init(C, op, mouse))) { |
| 620 return OPERATOR_CANCELLED; |
| 621 } |
| 622 |
| 623 op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, |
| 624 paint_stroke_update_step, |
| 625 paint_stroke_redraw, |
| 626 paint_stroke_done, event->type); |
| 627 paint_stroke_set_mode_data(op->customdata, pop); |
| 628 /* add modal handler */ |
| 629 WM_event_add_modal_handler(C, op); |
| 630 |
| 631 retval = op->type->modal(C, op, event); |
| 632 OPERATOR_RETVAL_CHECK(retval); |
| 633 BLI_assert(retval == OPERATOR_RUNNING_MODAL); |
| 634 |
| 635 return OPERATOR_RUNNING_MODAL; |
4851 } | 636 } |
4852 | 637 |
4853 static int paint_exec(bContext *C, wmOperator *op) | 638 static int paint_exec(bContext *C, wmOperator *op) |
4854 { | 639 { |
4855 » if(!texture_paint_init(C, op)) { | 640 » PaintOperation *pop; |
4856 » » MEM_freeN(op->customdata); | 641 » PropertyRNA *strokeprop; |
| 642 » PointerRNA firstpoint; |
| 643 » float mouse[2]; |
| 644 |
| 645 » strokeprop = RNA_struct_find_property(op->ptr, "stroke"); |
| 646 |
| 647 » if (!RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpo
int)) |
4857 return OPERATOR_CANCELLED; | 648 return OPERATOR_CANCELLED; |
4858 » } | 649 |
4859 | 650 » RNA_float_get_array(&firstpoint, "mouse", mouse); |
4860 » RNA_BEGIN(op->ptr, itemptr, "stroke") { | 651 |
4861 » » paint_apply(C, op, &itemptr); | 652 » if (!(pop = texture_paint_init(C, op, mouse))) { |
4862 » } | 653 » » return OPERATOR_CANCELLED; |
4863 » RNA_END; | 654 » } |
4864 | 655 |
4865 » paint_exit(C, op); | 656 » op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, |
| 657 » paint_stroke_update_step, |
| 658 » paint_stroke_redraw, |
| 659 » paint_stroke_done, 0); |
| 660 » paint_stroke_set_mode_data(op->customdata, pop); |
| 661 |
| 662 » /* frees op->customdata */ |
| 663 » paint_stroke_exec(C, op); |
4866 | 664 |
4867 return OPERATOR_FINISHED; | 665 return OPERATOR_FINISHED; |
4868 } | 666 } |
4869 | 667 |
4870 static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) | 668 void PAINT_OT_image_paint(wmOperatorType *ot) |
4871 { | 669 { |
4872 » PaintOperation *pop= op->customdata; | 670 » static EnumPropertyItem stroke_mode_items[] = { |
4873 » wmTabletData *wmtab; | 671 » » {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normal
ly"}, |
4874 » PointerRNA itemptr; | 672 » » {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of b
rush for duration of stroke"}, |
4875 » float pressure, mousef[2]; | 673 » » {0} |
4876 » double time; | 674 » }; |
4877 » int tablet, mouse[2]; | 675 |
4878 | 676 » /* identifiers */ |
4879 » // XXX +1 matches brush location better but | 677 » ot->name = "Image Paint"; |
4880 » // still not exact, find out why and fix .. | 678 » ot->idname = "PAINT_OT_image_paint"; |
4881 » mouse[0]= event->mval[0] + 1; | 679 » ot->description = "Paint a stroke into the image"; |
4882 » mouse[1]= event->mval[1] + 1; | 680 |
4883 | 681 » /* api callbacks */ |
4884 » time= PIL_check_seconds_timer(); | 682 » ot->invoke = paint_invoke; |
4885 | 683 » ot->modal = paint_stroke_modal; |
4886 » tablet= 0; | 684 » ot->exec = paint_exec; |
4887 » pressure= 0; | 685 » ot->poll = image_paint_poll; |
4888 » pop->s.blend= pop->s.brush->blend; | 686 » ot->cancel = paint_stroke_cancel; |
4889 | 687 |
4890 » if(event->custom == EVT_DATA_TABLET) { | 688 » /* flags */ |
4891 » » wmtab= event->customdata; | 689 » ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; |
4892 | 690 |
4893 » » tablet= (wmtab->Active != EVT_TABLET_NONE); | 691 » RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, |
4894 » » pressure= wmtab->Pressure; | 692 » "Paint Stroke Mode", |
4895 » » if(wmtab->Active == EVT_TABLET_ERASER) | 693 » "Action taken when a paint stroke is made"); |
4896 » » » pop->s.blend= IMB_BLEND_ERASE_ALPHA; | 694 |
4897 » } | 695 » RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElemen
t, "Stroke", ""); |
4898 » else /* otherwise airbrush becomes 1.0 pressure instantly */ | 696 } |
4899 » » pressure= pop->prev_pressure ? pop->prev_pressure : 1.0f; | 697 |
4900 | 698 |
4901 » if(pop->first) { | 699 int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) |
4902 » » pop->prevmouse[0]= mouse[0]; | 700 { |
4903 » » pop->prevmouse[1]= mouse[1]; | 701 » RegionView3D *rv3d = CTX_wm_region_view3d(C); |
4904 » » pop->starttime= time; | 702 |
4905 | 703 » if (!rv3d) { |
4906 » » /* special exception here for too high pressure values on first
touch in | 704 » » SpaceImage *sima = CTX_wm_space_image(C); |
4907 » » windows for some tablets, then we just skip first touch .. *
/ | 705 » » ARegion *ar = CTX_wm_region(C); |
4908 » » if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUS
H_SPACING_PRESSURE) || brush_use_alpha_pressure(pop->s.brush) || brush_use_size_
pressure(pop->s.brush))) | 706 |
| 707 » » if (sima->mode == SI_MODE_PAINT) { |
| 708 » » » ED_space_image_get_zoom(sima, ar, zoomx, zoomy); |
| 709 |
| 710 » » » return 1; |
| 711 » » } |
| 712 » } |
| 713 |
| 714 » *zoomx = *zoomy = 1; |
| 715 |
| 716 » return 0; |
| 717 } |
| 718 |
| 719 /************************ cursor drawing *******************************/ |
| 720 |
| 721 void brush_drawcursor_texpaint_uvsculpt(bContext *C, int x, int y, void *UNUSED(
customdata)) |
| 722 { |
| 723 #define PX_SIZE_FADE_MAX 12.0f |
| 724 #define PX_SIZE_FADE_MIN 4.0f |
| 725 |
| 726 » Scene *scene = CTX_data_scene(C); |
| 727 » //Brush *brush = image_paint_brush(C); |
| 728 » Paint *paint = BKE_paint_get_active_from_context(C); |
| 729 » Brush *brush = BKE_paint_brush(paint); |
| 730 |
| 731 » if (paint && brush && paint->flags & PAINT_SHOW_BRUSH) { |
| 732 » » float zoomx, zoomy; |
| 733 » » const float size = (float)BKE_brush_size_get(scene, brush); |
| 734 » » short use_zoom; |
| 735 » » float pixel_size; |
| 736 » » float alpha = 0.5f; |
| 737 |
| 738 » » use_zoom = get_imapaint_zoom(C, &zoomx, &zoomy); |
| 739 |
| 740 » » if (use_zoom) { |
| 741 » » » pixel_size = size * max_ff(zoomx, zoomy); |
| 742 » » } |
| 743 » » else { |
| 744 » » » pixel_size = size; |
| 745 » » } |
| 746 |
| 747 » » /* fade out the brush (cheap trick to work around brush interfer
ing with sampling [#])*/ |
| 748 » » if (pixel_size < PX_SIZE_FADE_MIN) { |
4909 return; | 749 return; |
4910 | 750 » » } |
4911 » » /* This can be removed once fixed properly in | 751 » » else if (pixel_size < PX_SIZE_FADE_MAX) { |
4912 » » brush_painter_paint(BrushPainter *painter, BrushFunc func, floa
t *pos, double time, float pressure, void *user)· | 752 » » » alpha *= (pixel_size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE
_MAX - PX_SIZE_FADE_MIN); |
4913 » » at zero pressure we should do nothing 1/2^12 is .0002 which is
the sensitivity of the most sensitive pen tablet available*/ | 753 » » } |
4914 » » if (tablet && (pressure < .0002f) && ((pop->s.brush->flag & BRUS
H_SPACING_PRESSURE) || brush_use_alpha_pressure(pop->s.brush) || brush_use_size_
pressure(pop->s.brush))) | |
4915 » » » return; | |
4916 »······· | |
4917 » } | |
4918 | |
4919 » /* fill in stroke */ | |
4920 » RNA_collection_add(op->ptr, "stroke", &itemptr); | |
4921 | |
4922 » mousef[0] = (float)(mouse[0]); | |
4923 » mousef[1] = (float)(mouse[1]); | |
4924 » RNA_float_set_array(&itemptr, "mouse", mousef); | |
4925 » RNA_float_set(&itemptr, "time", (float)(time - pop->starttime)); | |
4926 » RNA_float_set(&itemptr, "pressure", pressure); | |
4927 | |
4928 » /* apply */ | |
4929 » paint_apply(C, op, &itemptr); | |
4930 | |
4931 » pop->prev_pressure= pressure; | |
4932 } | |
4933 | |
4934 static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event) | |
4935 { | |
4936 » PaintOperation *pop; | |
4937 | |
4938 » if(!texture_paint_init(C, op)) { | |
4939 » » MEM_freeN(op->customdata); | |
4940 » » return OPERATOR_CANCELLED; | |
4941 » } | |
4942 »······· | |
4943 » paint_apply_event(C, op, event); | |
4944 | |
4945 » pop= op->customdata; | |
4946 » WM_event_add_modal_handler(C, op); | |
4947 | |
4948 » if(pop->s.brush->flag & BRUSH_AIRBRUSH) | |
4949 » » pop->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(
C), TIMER, 0.01f); | |
4950 | |
4951 » return OPERATOR_RUNNING_MODAL; | |
4952 } | |
4953 | |
4954 static int paint_modal(bContext *C, wmOperator *op, wmEvent *event) | |
4955 { | |
4956 » PaintOperation *pop= op->customdata; | |
4957 | |
4958 » switch(event->type) { | |
4959 » » case LEFTMOUSE: | |
4960 » » case MIDDLEMOUSE: | |
4961 » » case RIGHTMOUSE: // XXX hardcoded | |
4962 » » » paint_exit(C, op); | |
4963 » » » return OPERATOR_FINISHED; | |
4964 » » case MOUSEMOVE: | |
4965 » » case INBETWEEN_MOUSEMOVE: | |
4966 » » » paint_apply_event(C, op, event); | |
4967 » » » break; | |
4968 » » case TIMER: | |
4969 » » » if(event->customdata == pop->timer) | |
4970 » » » » paint_apply_event(C, op, event); | |
4971 » » » break; | |
4972 » } | |
4973 | |
4974 » return OPERATOR_RUNNING_MODAL; | |
4975 } | |
4976 | |
4977 static int paint_cancel(bContext *C, wmOperator *op) | |
4978 { | |
4979 » paint_exit(C, op); | |
4980 | |
4981 » return OPERATOR_CANCELLED; | |
4982 } | |
4983 | |
4984 void PAINT_OT_image_paint(wmOperatorType *ot) | |
4985 { | |
4986 » /* identifiers */ | |
4987 » ot->name= "Image Paint"; | |
4988 » ot->idname= "PAINT_OT_image_paint"; | |
4989 »······· | |
4990 » /* api callbacks */ | |
4991 » ot->exec= paint_exec; | |
4992 » ot->invoke= paint_invoke; | |
4993 » ot->modal= paint_modal; | |
4994 » ot->cancel= paint_cancel; | |
4995 » ot->poll= image_paint_poll; | |
4996 | |
4997 » /* flags */ | |
4998 » ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; | |
4999 | |
5000 » /* properties */ | |
5001 » RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElemen
t, "Stroke", ""); | |
5002 } | |
5003 | |
5004 static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) | |
5005 { | |
5006 » RegionView3D *rv3d= CTX_wm_region_view3d(C); | |
5007 | |
5008 » if(!rv3d) { | |
5009 » » SpaceImage *sima= CTX_wm_space_image(C); | |
5010 » » ARegion *ar= CTX_wm_region(C); | |
5011 » »······· | |
5012 » » ED_space_image_zoom(sima, ar, zoomx, zoomy); | |
5013 | |
5014 » » return 1; | |
5015 » } | |
5016 | |
5017 » *zoomx = *zoomy = 1; | |
5018 | |
5019 » return 0; | |
5020 } | |
5021 | |
5022 /************************ cursor drawing *******************************/ | |
5023 | |
5024 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
) | |
5025 { | |
5026 » Brush *brush= image_paint_brush(C); | |
5027 » Paint *paint= paint_get_active(CTX_data_scene(C)); | |
5028 | |
5029 » if(paint && brush) { | |
5030 » » float zoomx, zoomy; | |
5031 | |
5032 » » if(!(paint->flags & PAINT_SHOW_BRUSH)) | |
5033 » » » return; | |
5034 | 754 |
5035 glPushMatrix(); | 755 glPushMatrix(); |
5036 | 756 |
5037 glTranslatef((float)x, (float)y, 0.0f); | 757 glTranslatef((float)x, (float)y, 0.0f); |
5038 | 758 |
5039 » » if(get_imapaint_zoom(C, &zoomx, &zoomy)) | 759 » » /* No need to scale for uv sculpting, on the contrary it might b
e useful to keep un-scaled */ |
| 760 » » if (use_zoom) |
5040 glScalef(zoomx, zoomy, 1.0f); | 761 glScalef(zoomx, zoomy, 1.0f); |
5041 | 762 |
5042 » » glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2
], 0.5f); | 763 » » glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2
], alpha); |
5043 » » glEnable( GL_LINE_SMOOTH ); | 764 » » glEnable(GL_LINE_SMOOTH); |
5044 glEnable(GL_BLEND); | 765 glEnable(GL_BLEND); |
5045 » » glutil_draw_lined_arc(0, (float)(M_PI*2.0), (float)brush_size(br
ush), 40); | 766 » » { |
| 767 » » » UnifiedPaintSettings *ups = &scene->toolsettings->unifie
d_paint_settings; |
| 768 » » » /* hrmf, duplicate paint_draw_cursor logic here */ |
| 769 » » » if (ups->draw_pressure && BKE_brush_use_size_pressure(sc
ene, brush)) { |
| 770 » » » » /* inner at full alpha */ |
| 771 » » » » glutil_draw_lined_arc(0, (float)(M_PI * 2.0), si
ze * ups->pressure_value, 40); |
| 772 » » » » /* outer at half alpha */ |
| 773 » » » » glColor4f(brush->add_col[0], brush->add_col[1],
brush->add_col[2], alpha * 0.5f); |
| 774 » » » } |
| 775 » » } |
| 776 » » glutil_draw_lined_arc(0, (float)(M_PI * 2.0), size, 40); |
5046 glDisable(GL_BLEND); | 777 glDisable(GL_BLEND); |
5047 » » glDisable( GL_LINE_SMOOTH ); | 778 » » glDisable(GL_LINE_SMOOTH); |
5048 | 779 |
5049 glPopMatrix(); | 780 glPopMatrix(); |
5050 } | 781 } |
| 782 #undef PX_SIZE_FADE_MAX |
| 783 #undef PX_SIZE_FADE_MIN |
5051 } | 784 } |
5052 | 785 |
5053 static void toggle_paint_cursor(bContext *C, int enable) | 786 static void toggle_paint_cursor(bContext *C, int enable) |
5054 { | 787 { |
5055 » ToolSettings *settings= CTX_data_scene(C)->toolsettings; | 788 » wmWindowManager *wm = CTX_wm_manager(C); |
5056 | 789 » Scene *scene = CTX_data_scene(C); |
5057 » if(settings->imapaint.paintcursor && !enable) { | 790 » ToolSettings *settings = scene->toolsettings; |
5058 » » WM_paint_cursor_end(CTX_wm_manager(C), settings->imapaint.paintc
ursor); | 791 |
| 792 » if (settings->imapaint.paintcursor && !enable) { |
| 793 » » WM_paint_cursor_end(wm, settings->imapaint.paintcursor); |
5059 settings->imapaint.paintcursor = NULL; | 794 settings->imapaint.paintcursor = NULL; |
5060 » } | 795 » » paint_cursor_delete_textures(); |
5061 » else if(enable) | 796 » } |
5062 » » settings->imapaint.paintcursor= WM_paint_cursor_activate(CTX_wm_
manager(C), image_paint_poll, brush_drawcursor, NULL); | 797 » else if (enable) |
| 798 » » paint_cursor_start(C, image_paint_poll); |
5063 } | 799 } |
5064 | 800 |
5065 /* enable the paint cursor if it isn't already. | 801 /* enable the paint cursor if it isn't already. |
5066 | 802 * |
5067 purpose is to make sure the paint cursor is shown if paint | 803 * purpose is to make sure the paint cursor is shown if paint |
5068 mode is enabled in the image editor. the paint poll will | 804 * mode is enabled in the image editor. the paint poll will |
5069 ensure that the cursor is hidden when not in paint mode */ | 805 * ensure that the cursor is hidden when not in paint mode */ |
5070 void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) | 806 void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) |
5071 { | 807 { |
| 808 wmWindow *win; |
| 809 ScrArea *sa; |
5072 ImagePaintSettings *imapaint = &settings->imapaint; | 810 ImagePaintSettings *imapaint = &settings->imapaint; |
5073 | 811 » int enabled = FALSE; |
5074 » if(!imapaint->paintcursor) { | 812 |
5075 » » imapaint->paintcursor = | 813 » for (win = wm->windows.first; win; win = win->next) |
5076 » » » WM_paint_cursor_activate(wm, image_paint_poll, | 814 » » for (sa = win->screen->areabase.first; sa; sa = sa->next) |
5077 » » » » » » brush_drawcursor, NULL); | 815 » » » if (sa->spacetype == SPACE_IMAGE) |
| 816 » » » » if (((SpaceImage *)sa->spacedata.first)->mode ==
SI_MODE_PAINT) |
| 817 » » » » » enabled = TRUE; |
| 818 |
| 819 » if (enabled) { |
| 820 » » BKE_paint_init(&imapaint->paint, PAINT_CURSOR_TEXTURE_PAINT); |
| 821 |
| 822 » » paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_po
ll); |
| 823 » } |
| 824 » else { |
| 825 » » paint_cursor_delete_textures(); |
5078 } | 826 } |
5079 } | 827 } |
5080 | 828 |
5081 /************************ grab clone operator ************************/ | 829 /************************ grab clone operator ************************/ |
5082 | 830 |
5083 typedef struct GrabClone { | 831 typedef struct GrabClone { |
5084 float startoffset[2]; | 832 float startoffset[2]; |
5085 int startx, starty; | 833 int startx, starty; |
5086 } GrabClone; | 834 } GrabClone; |
5087 | 835 |
5088 static void grab_clone_apply(bContext *C, wmOperator *op) | 836 static void grab_clone_apply(bContext *C, wmOperator *op) |
5089 { | 837 { |
5090 » Brush *brush= image_paint_brush(C); | 838 » Brush *brush = image_paint_brush(C); |
5091 float delta[2]; | 839 float delta[2]; |
5092 | 840 |
5093 RNA_float_get_array(op->ptr, "delta", delta); | 841 RNA_float_get_array(op->ptr, "delta", delta); |
5094 add_v2_v2(brush->clone.offset, delta); | 842 add_v2_v2(brush->clone.offset, delta); |
5095 ED_region_tag_redraw(CTX_wm_region(C)); | 843 ED_region_tag_redraw(CTX_wm_region(C)); |
5096 } | 844 } |
5097 | 845 |
5098 static int grab_clone_exec(bContext *C, wmOperator *op) | 846 static int grab_clone_exec(bContext *C, wmOperator *op) |
5099 { | 847 { |
5100 grab_clone_apply(C, op); | 848 grab_clone_apply(C, op); |
5101 | 849 |
5102 return OPERATOR_FINISHED; | 850 return OPERATOR_FINISHED; |
5103 } | 851 } |
5104 | 852 |
5105 static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event) | 853 static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event) |
5106 { | 854 { |
5107 » Brush *brush= image_paint_brush(C); | 855 » Brush *brush = image_paint_brush(C); |
5108 GrabClone *cmv; | 856 GrabClone *cmv; |
5109 | 857 |
5110 » cmv= MEM_callocN(sizeof(GrabClone), "GrabClone"); | 858 » cmv = MEM_callocN(sizeof(GrabClone), "GrabClone"); |
5111 copy_v2_v2(cmv->startoffset, brush->clone.offset); | 859 copy_v2_v2(cmv->startoffset, brush->clone.offset); |
5112 » cmv->startx= event->x; | 860 » cmv->startx = event->x; |
5113 » cmv->starty= event->y; | 861 » cmv->starty = event->y; |
5114 » op->customdata= cmv; | 862 » op->customdata = cmv; |
5115 | 863 |
5116 WM_event_add_modal_handler(C, op); | 864 WM_event_add_modal_handler(C, op); |
5117 | 865 |
5118 return OPERATOR_RUNNING_MODAL; | 866 return OPERATOR_RUNNING_MODAL; |
5119 } | 867 } |
5120 | 868 |
5121 static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event) | 869 static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event) |
5122 { | 870 { |
5123 » Brush *brush= image_paint_brush(C); | 871 » Brush *brush = image_paint_brush(C); |
5124 » ARegion *ar= CTX_wm_region(C); | 872 » ARegion *ar = CTX_wm_region(C); |
5125 » GrabClone *cmv= op->customdata; | 873 » GrabClone *cmv = op->customdata; |
5126 float startfx, startfy, fx, fy, delta[2]; | 874 float startfx, startfy, fx, fy, delta[2]; |
5127 » int xmin= ar->winrct.xmin, ymin= ar->winrct.ymin; | 875 » int xmin = ar->winrct.xmin, ymin = ar->winrct.ymin; |
5128 | 876 |
5129 » switch(event->type) { | 877 » switch (event->type) { |
5130 case LEFTMOUSE: | 878 case LEFTMOUSE: |
5131 case MIDDLEMOUSE: | 879 case MIDDLEMOUSE: |
5132 case RIGHTMOUSE: // XXX hardcoded | 880 case RIGHTMOUSE: // XXX hardcoded |
5133 MEM_freeN(op->customdata); | 881 MEM_freeN(op->customdata); |
5134 return OPERATOR_FINISHED; | 882 return OPERATOR_FINISHED; |
5135 case MOUSEMOVE: | 883 case MOUSEMOVE: |
5136 /* mouse moved, so move the clone image */ | 884 /* mouse moved, so move the clone image */ |
5137 UI_view2d_region_to_view(&ar->v2d, cmv->startx - xmin, c
mv->starty - ymin, &startfx, &startfy); | 885 UI_view2d_region_to_view(&ar->v2d, cmv->startx - xmin, c
mv->starty - ymin, &startfx, &startfy); |
5138 UI_view2d_region_to_view(&ar->v2d, event->x - xmin, even
t->y - ymin, &fx, &fy); | 886 UI_view2d_region_to_view(&ar->v2d, event->x - xmin, even
t->y - ymin, &fx, &fy); |
5139 | 887 |
5140 » » » delta[0]= fx - startfx; | 888 » » » delta[0] = fx - startfx; |
5141 » » » delta[1]= fy - startfy; | 889 » » » delta[1] = fy - startfy; |
5142 RNA_float_set_array(op->ptr, "delta", delta); | 890 RNA_float_set_array(op->ptr, "delta", delta); |
5143 | 891 |
5144 copy_v2_v2(brush->clone.offset, cmv->startoffset); | 892 copy_v2_v2(brush->clone.offset, cmv->startoffset); |
5145 | 893 |
5146 grab_clone_apply(C, op); | 894 grab_clone_apply(C, op); |
5147 break; | 895 break; |
5148 } | 896 } |
5149 | 897 |
5150 return OPERATOR_RUNNING_MODAL; | 898 return OPERATOR_RUNNING_MODAL; |
5151 } | 899 } |
5152 | 900 |
5153 static int grab_clone_cancel(bContext *UNUSED(C), wmOperator *op) | 901 static void grab_clone_cancel(bContext *UNUSED(C), wmOperator *op) |
5154 { | 902 { |
5155 MEM_freeN(op->customdata); | 903 MEM_freeN(op->customdata); |
5156 return OPERATOR_CANCELLED; | |
5157 } | 904 } |
5158 | 905 |
5159 void PAINT_OT_grab_clone(wmOperatorType *ot) | 906 void PAINT_OT_grab_clone(wmOperatorType *ot) |
5160 { | 907 { |
5161 /* identifiers */ | 908 /* identifiers */ |
5162 » ot->name= "Grab Clone"; | 909 » ot->name = "Grab Clone"; |
5163 » ot->idname= "PAINT_OT_grab_clone"; | 910 » ot->idname = "PAINT_OT_grab_clone"; |
| 911 » ot->description = "Move the clone source image"; |
5164 ········ | 912 ········ |
5165 /* api callbacks */ | 913 /* api callbacks */ |
5166 » ot->exec= grab_clone_exec; | 914 » ot->exec = grab_clone_exec; |
5167 » ot->invoke= grab_clone_invoke; | 915 » ot->invoke = grab_clone_invoke; |
5168 » ot->modal= grab_clone_modal; | 916 » ot->modal = grab_clone_modal; |
5169 » ot->cancel= grab_clone_cancel; | 917 » ot->cancel = grab_clone_cancel; |
5170 » ot->poll= image_paint_2d_clone_poll; | 918 » ot->poll = image_paint_2d_clone_poll; |
5171 | 919 |
5172 /* flags */ | 920 /* flags */ |
5173 » ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; | 921 » ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; |
5174 | 922 |
5175 /* properties */ | 923 /* properties */ |
5176 » RNA_def_float_vector(ot->srna, "delta", 2, NULL, -FLT_MAX, FLT_MAX, "Del
ta", "Delta offset of clone image in 0.0..1.0 coordinates.", -1.0f, 1.0f); | 924 » RNA_def_float_vector(ot->srna, "delta", 2, NULL, -FLT_MAX, FLT_MAX, "Del
ta", "Delta offset of clone image in 0.0..1.0 coordinates", -1.0f, 1.0f); |
5177 } | 925 } |
5178 | 926 |
5179 /******************** sample color operator ********************/ | 927 /******************** sample color operator ********************/ |
| 928 typedef struct { |
| 929 bool show_cursor; |
| 930 short event_type; |
| 931 } SampleColorData; |
5180 | 932 |
5181 static int sample_color_exec(bContext *C, wmOperator *op) | 933 static int sample_color_exec(bContext *C, wmOperator *op) |
5182 { | 934 { |
5183 » Scene *scene= CTX_data_scene(C); | 935 » Paint *paint = BKE_paint_get_active_from_context(C); |
5184 » Brush *brush= image_paint_brush(C); | 936 » Brush *brush = BKE_paint_brush(paint); |
5185 » ARegion *ar= CTX_wm_region(C); | 937 » ARegion *ar = CTX_wm_region(C); |
| 938 » wmWindow *win = CTX_wm_window(C); |
| 939 » bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); |
5186 int location[2]; | 940 int location[2]; |
5187 | 941 |
| 942 paint->flags &= ~PAINT_SHOW_BRUSH; |
| 943 |
| 944 /* force redraw without cursor */ |
| 945 WM_paint_cursor_tag_redraw(win, ar); |
| 946 WM_redraw_windows(C); |
| 947 |
5188 RNA_int_get_array(op->ptr, "location", location); | 948 RNA_int_get_array(op->ptr, "location", location); |
5189 » paint_sample_color(scene, ar, location[0], location[1]); | 949 » paint_sample_color(C, ar, location[0], location[1]); |
5190 | 950 |
5191 » WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); | 951 » if (show_cursor) { |
| 952 » » paint->flags |= PAINT_SHOW_BRUSH; |
| 953 » } |
| 954 |
| 955 » WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); |
5192 ········ | 956 ········ |
5193 return OPERATOR_FINISHED; | 957 return OPERATOR_FINISHED; |
5194 } | 958 } |
5195 | 959 |
5196 static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event) | 960 static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
) |
5197 { | 961 { |
| 962 » Paint *paint = BKE_paint_get_active_from_context(C); |
| 963 » SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample col
or custom data"); |
| 964 » ARegion *ar = CTX_wm_region(C); |
| 965 » wmWindow *win = CTX_wm_window(C); |
| 966 |
| 967 » data->event_type = event->type; |
| 968 » data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); |
| 969 » op->customdata = data; |
| 970 » paint->flags &= ~PAINT_SHOW_BRUSH; |
| 971 |
| 972 » /* force redraw without cursor */ |
| 973 » WM_paint_cursor_tag_redraw(win, ar); |
| 974 » WM_redraw_windows(C); |
| 975 |
5198 RNA_int_set_array(op->ptr, "location", event->mval); | 976 RNA_int_set_array(op->ptr, "location", event->mval); |
5199 » sample_color_exec(C, op); | 977 » paint_sample_color(C, ar, event->mval[0], event->mval[1]); |
5200 | 978 |
5201 WM_event_add_modal_handler(C, op); | 979 WM_event_add_modal_handler(C, op); |
5202 | 980 |
5203 return OPERATOR_RUNNING_MODAL; | 981 return OPERATOR_RUNNING_MODAL; |
5204 } | 982 } |
5205 | 983 |
5206 static int sample_color_modal(bContext *C, wmOperator *op, wmEvent *event) | 984 static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) |
5207 { | 985 { |
5208 » switch(event->type) { | 986 » SampleColorData *data = op->customdata; |
5209 » » case LEFTMOUSE: | 987 » Paint *paint = BKE_paint_get_active_from_context(C); |
5210 » » case RIGHTMOUSE: // XXX hardcoded | 988 » Brush *brush = BKE_paint_brush(paint); |
5211 » » » return OPERATOR_FINISHED; | 989 |
| 990 » if ((event->type == data->event_type) && (event->val == KM_RELEASE)) { |
| 991 » » if (data->show_cursor) { |
| 992 » » » paint->flags |= PAINT_SHOW_BRUSH; |
| 993 » » } |
| 994 |
| 995 » » MEM_freeN(data); |
| 996 » » return OPERATOR_FINISHED; |
| 997 » } |
| 998 |
| 999 » switch (event->type) { |
5212 case MOUSEMOVE: | 1000 case MOUSEMOVE: |
| 1001 { |
| 1002 ARegion *ar = CTX_wm_region(C); |
5213 RNA_int_set_array(op->ptr, "location", event->mval); | 1003 RNA_int_set_array(op->ptr, "location", event->mval); |
5214 » » » sample_color_exec(C, op); | 1004 » » » paint_sample_color(C, ar, event->mval[0], event->mval[1]
); |
| 1005 » » » WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); |
5215 break; | 1006 break; |
| 1007 } |
5216 } | 1008 } |
5217 | 1009 |
5218 return OPERATOR_RUNNING_MODAL; | 1010 return OPERATOR_RUNNING_MODAL; |
5219 } | 1011 } |
5220 | 1012 |
5221 /* same as image_paint_poll but fail when face mask mode is enabled */ | 1013 static int sample_color_poll(bContext *C) |
5222 static int image_paint_sample_color_poll(bContext *C) | 1014 { |
5223 { | 1015 » return (image_paint_poll(C) || vertex_paint_poll(C)); |
5224 » if(image_paint_poll(C)) { | |
5225 » » if(CTX_wm_view3d(C)) { | |
5226 » » » Object *obact = CTX_data_active_object(C); | |
5227 » » » if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { | |
5228 » » » » Mesh *me= get_mesh(obact); | |
5229 » » » » if(me) { | |
5230 » » » » » return !(me->editflag & ME_EDIT_PAINT_MA
SK); | |
5231 » » » » } | |
5232 » » » } | |
5233 » » } | |
5234 | |
5235 » » return 1; | |
5236 » } | |
5237 | |
5238 » return 0; | |
5239 } | 1016 } |
5240 | 1017 |
5241 void PAINT_OT_sample_color(wmOperatorType *ot) | 1018 void PAINT_OT_sample_color(wmOperatorType *ot) |
5242 { | 1019 { |
5243 /* identifiers */ | 1020 /* identifiers */ |
5244 » ot->name= "Sample Color"; | 1021 » ot->name = "Sample Color"; |
5245 » ot->idname= "PAINT_OT_sample_color"; | 1022 » ot->idname = "PAINT_OT_sample_color"; |
| 1023 » ot->description = "Use the mouse to sample a color in the image"; |
5246 ········ | 1024 ········ |
5247 /* api callbacks */ | 1025 /* api callbacks */ |
5248 » ot->exec= sample_color_exec; | 1026 » ot->exec = sample_color_exec; |
5249 » ot->invoke= sample_color_invoke; | 1027 » ot->invoke = sample_color_invoke; |
5250 » ot->modal= sample_color_modal; | 1028 » ot->modal = sample_color_modal; |
5251 » ot->poll= image_paint_sample_color_poll; | 1029 » ot->poll = sample_color_poll; |
5252 | 1030 |
5253 /* flags */ | 1031 /* flags */ |
5254 » ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; | 1032 » ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; |
5255 | 1033 |
5256 /* properties */ | 1034 /* properties */ |
5257 » RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location"
, "Cursor location in region coordinates.", 0, 16384); | 1035 » RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location"
, "Cursor location in region coordinates", 0, 16384); |
5258 } | |
5259 | |
5260 /******************** set clone cursor operator ********************/ | |
5261 | |
5262 static int set_clone_cursor_exec(bContext *C, wmOperator *op) | |
5263 { | |
5264 » Scene *scene= CTX_data_scene(C); | |
5265 » View3D *v3d= CTX_wm_view3d(C); | |
5266 » float *cursor= give_cursor(scene, v3d); | |
5267 | |
5268 » RNA_float_get_array(op->ptr, "location", cursor); | |
5269 »······· | |
5270 » ED_area_tag_redraw(CTX_wm_area(C)); | |
5271 »······· | |
5272 » return OPERATOR_FINISHED; | |
5273 } | |
5274 | |
5275 static int set_clone_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) | |
5276 { | |
5277 » Scene *scene= CTX_data_scene(C); | |
5278 » View3D *v3d= CTX_wm_view3d(C); | |
5279 » ARegion *ar= CTX_wm_region(C); | |
5280 » float location[3]; | |
5281 | |
5282 » view3d_operator_needs_opengl(C); | |
5283 | |
5284 » if(!ED_view3d_autodist(scene, ar, v3d, event->mval, location)) | |
5285 » » return OPERATOR_CANCELLED; | |
5286 | |
5287 » RNA_float_set_array(op->ptr, "location", location); | |
5288 | |
5289 » return set_clone_cursor_exec(C, op); | |
5290 } | |
5291 | |
5292 void PAINT_OT_clone_cursor_set(wmOperatorType *ot) | |
5293 { | |
5294 » /* identifiers */ | |
5295 » ot->name= "Set Clone Cursor"; | |
5296 » ot->idname= "PAINT_OT_clone_cursor_set"; | |
5297 »······· | |
5298 » /* api callbacks */ | |
5299 » ot->exec= set_clone_cursor_exec; | |
5300 » ot->invoke= set_clone_cursor_invoke; | |
5301 » ot->poll= image_paint_3d_poll; | |
5302 | |
5303 » /* flags */ | |
5304 » ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; | |
5305 | |
5306 » /* properties */ | |
5307 » RNA_def_float_vector(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "
Location", "Cursor location in world space coordinates.", -10000.0f, 10000.0f); | |
5308 } | 1036 } |
5309 | 1037 |
5310 /******************** texture paint toggle operator ********************/ | 1038 /******************** texture paint toggle operator ********************/ |
5311 | 1039 |
5312 static int texture_paint_toggle_poll(bContext *C) | 1040 static int texture_paint_toggle_poll(bContext *C) |
5313 { | 1041 { |
5314 » if(CTX_data_edit_object(C)) | 1042 » Object *ob = CTX_data_active_object(C); |
| 1043 » if (ob == NULL || ob->type != OB_MESH) |
5315 return 0; | 1044 return 0; |
5316 » if(CTX_data_active_object(C)==NULL) | 1045 » if (!ob->data || ((ID *)ob->data)->lib) |
5317 return 0; | 1046 return 0; |
| 1047 if (CTX_data_edit_object(C)) |
| 1048 return 0; |
5318 | 1049 |
5319 return 1; | 1050 return 1; |
5320 } | 1051 } |
5321 | 1052 |
5322 static int texture_paint_toggle_exec(bContext *C, wmOperator *op) | 1053 static int texture_paint_toggle_exec(bContext *C, wmOperator *op) |
5323 { | 1054 { |
5324 » Scene *scene= CTX_data_scene(C); | 1055 » Scene *scene = CTX_data_scene(C); |
5325 » Object *ob= CTX_data_active_object(C); | 1056 » Object *ob = CTX_data_active_object(C); |
5326 » Mesh *me= NULL; | 1057 » const int mode_flag = OB_MODE_TEXTURE_PAINT; |
5327 »······· | 1058 » const bool is_mode_set = (ob->mode & mode_flag) != 0; |
5328 » if(ob==NULL) | 1059 » Mesh *me; |
5329 » » return OPERATOR_CANCELLED; | 1060 |
5330 »······· | 1061 » if (!is_mode_set) { |
5331 » if (object_data_is_libdata(ob)) { | 1062 » » if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { |
5332 » » BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata.
"); | 1063 » » » return OPERATOR_CANCELLED; |
5333 » » return OPERATOR_CANCELLED; | 1064 » » } |
5334 » } | 1065 » } |
5335 | 1066 |
5336 » me= get_mesh(ob); | 1067 » me = BKE_mesh_from_object(ob); |
5337 | 1068 |
5338 » if(!(ob->mode & OB_MODE_TEXTURE_PAINT) && !me) { | 1069 » if (ob->mode & mode_flag) { |
5339 » » BKE_report(op->reports, RPT_ERROR, "Can only enter texture paint
mode for mesh objects."); | 1070 » » ob->mode &= ~mode_flag; |
5340 » » return OPERATOR_CANCELLED; | 1071 |
5341 » } | 1072 » » if (U.glreslimit != 0) |
5342 | |
5343 » if(ob->mode & OB_MODE_TEXTURE_PAINT) { | |
5344 » » ob->mode &= ~OB_MODE_TEXTURE_PAINT; | |
5345 | |
5346 » » if(U.glreslimit != 0) | |
5347 GPU_free_images(); | 1073 GPU_free_images(); |
5348 GPU_paint_set_mipmap(1); | 1074 GPU_paint_set_mipmap(1); |
5349 | 1075 |
5350 toggle_paint_cursor(C, 0); | 1076 toggle_paint_cursor(C, 0); |
5351 } | 1077 } |
5352 else { | 1078 else { |
5353 » » ob->mode |= OB_MODE_TEXTURE_PAINT; | 1079 » » ob->mode |= mode_flag; |
5354 | 1080 |
5355 » » if(me->mtface==NULL) | 1081 » » if (me->mtface == NULL) |
5356 » » » me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE,
CD_DEFAULT, | 1082 » » » me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE,
CD_DEFAULT, |
5357 » » » » » » » NULL, me->totface); | 1083 » » » NULL, me->totface); |
5358 | 1084 |
5359 » » paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TE
XTURE_PAINT); | 1085 » » BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSO
R_TEXTURE_PAINT); |
5360 | 1086 |
5361 » » if(U.glreslimit != 0) | 1087 » » if (U.glreslimit != 0) |
5362 GPU_free_images(); | 1088 GPU_free_images(); |
5363 GPU_paint_set_mipmap(0); | 1089 GPU_paint_set_mipmap(0); |
5364 | 1090 |
5365 toggle_paint_cursor(C, 1); | 1091 toggle_paint_cursor(C, 1); |
5366 } | 1092 } |
5367 | 1093 |
5368 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); | 1094 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); |
5369 » WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); | 1095 » WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); |
5370 | 1096 |
5371 return OPERATOR_FINISHED; | 1097 return OPERATOR_FINISHED; |
5372 } | 1098 } |
5373 | 1099 |
5374 void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) | 1100 void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) |
5375 { | 1101 { |
5376 /* identifiers */ | 1102 /* identifiers */ |
5377 » ot->name= "Texture Paint Toggle"; | 1103 » ot->name = "Texture Paint Toggle"; |
5378 » ot->idname= "PAINT_OT_texture_paint_toggle"; | 1104 » ot->idname = "PAINT_OT_texture_paint_toggle"; |
| 1105 » ot->description = "Toggle texture paint mode in 3D view"; |
5379 ········ | 1106 ········ |
5380 /* api callbacks */ | 1107 /* api callbacks */ |
5381 » ot->exec= texture_paint_toggle_exec; | 1108 » ot->exec = texture_paint_toggle_exec; |
5382 » ot->poll= texture_paint_toggle_poll; | 1109 » ot->poll = texture_paint_toggle_poll; |
5383 | 1110 |
5384 /* flags */ | 1111 /* flags */ |
5385 » ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; | 1112 » ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; |
5386 } | 1113 } |
5387 | 1114 |
5388 static int texture_paint_poll(bContext *C) | 1115 static int texture_paint_poll(bContext *C) |
5389 { | 1116 { |
5390 » if(texture_paint_toggle_poll(C)) | 1117 » if (texture_paint_toggle_poll(C)) |
5391 » » if(CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT) | 1118 » » if (CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT) |
5392 return 1; | 1119 return 1; |
5393 ········ | 1120 ········ |
5394 return 0; | 1121 return 0; |
5395 } | 1122 } |
5396 | 1123 |
5397 int image_texture_paint_poll(bContext *C) | 1124 int image_texture_paint_poll(bContext *C) |
5398 { | 1125 { |
5399 return (texture_paint_poll(C) || image_paint_poll(C)); | 1126 return (texture_paint_poll(C) || image_paint_poll(C)); |
5400 } | 1127 } |
5401 | 1128 |
5402 int facemask_paint_poll(bContext *C) | 1129 int facemask_paint_poll(bContext *C) |
5403 { | 1130 { |
5404 return paint_facesel_test(CTX_data_active_object(C)); | 1131 return paint_facesel_test(CTX_data_active_object(C)); |
5405 } | 1132 } |
5406 | 1133 |
5407 /* use project paint to re-apply an image */ | 1134 int vert_paint_poll(bContext *C) |
5408 static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) | 1135 { |
5409 { | 1136 » return paint_vertsel_test(CTX_data_active_object(C)); |
5410 » Image *image= BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->pt
r, "image")); | 1137 } |
5411 » Scene *scene= CTX_data_scene(C); | 1138 |
5412 » ProjPaintState ps= {NULL}; | 1139 int mask_paint_poll(bContext *C) |
5413 » int orig_brush_size; | 1140 { |
5414 » IDProperty *idgroup; | 1141 » return paint_facesel_test(CTX_data_active_object(C)) || paint_vertsel_te
st(CTX_data_active_object(C)); |
5415 » IDProperty *view_data= NULL; | 1142 } |
5416 | 1143 |
5417 » project_state_init(C, OBACT, &ps); | |
5418 | |
5419 » if(ps.ob==NULL || ps.ob->type != OB_MESH) { | |
5420 » » BKE_report(op->reports, RPT_ERROR, "No active mesh object."); | |
5421 » » return OPERATOR_CANCELLED; | |
5422 » } | |
5423 | |
5424 » if(image==NULL) { | |
5425 » » BKE_report(op->reports, RPT_ERROR, "Image could not be found."); | |
5426 » » return OPERATOR_CANCELLED; | |
5427 » } | |
5428 | |
5429 » ps.reproject_image= image; | |
5430 » ps.reproject_ibuf= BKE_image_get_ibuf(image, NULL); | |
5431 | |
5432 » if(ps.reproject_ibuf==NULL || ps.reproject_ibuf->rect==NULL) { | |
5433 » » BKE_report(op->reports, RPT_ERROR, "Image data could not be foun
d."); | |
5434 » » return OPERATOR_CANCELLED; | |
5435 » } | |
5436 | |
5437 » idgroup= IDP_GetProperties(&image->id, 0); | |
5438 | |
5439 » if(idgroup) { | |
5440 » » view_data= IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_
ID, IDP_ARRAY); | |
5441 | |
5442 » » /* type check to make sure its ok */ | |
5443 » » if(view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype !
= IDP_FLOAT) { | |
5444 » » » BKE_report(op->reports, RPT_ERROR, "Image project data i
nvalid."); | |
5445 » » » return OPERATOR_CANCELLED; | |
5446 » » } | |
5447 » } | |
5448 | |
5449 » if(view_data) { | |
5450 » » /* image has stored view projection info */ | |
5451 » » ps.source= PROJ_SRC_IMAGE_VIEW; | |
5452 » } | |
5453 » else { | |
5454 » » ps.source= PROJ_SRC_IMAGE_CAM; | |
5455 | |
5456 » » if(scene->camera==NULL) { | |
5457 » » » BKE_report(op->reports, RPT_ERROR, "No active camera set
."); | |
5458 » » » return OPERATOR_CANCELLED; | |
5459 » » } | |
5460 » } | |
5461 | |
5462 » /* override */ | |
5463 » ps.is_texbrush= 0; | |
5464 » ps.is_airbrush= 1; | |
5465 » orig_brush_size= brush_size(ps.brush); | |
5466 » brush_set_size(ps.brush, 32); /* cover the whole image */ | |
5467 | |
5468 » ps.tool= PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info
*/ | |
5469 | |
5470 » scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; | |
5471 | |
5472 » undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, | |
5473 » » image_undo_restore, image_undo_free); | |
5474 | |
5475 » /* allocate and initialize spacial data structures */ | |
5476 » project_paint_begin(&ps); | |
5477 | |
5478 » if(ps.dm==NULL) { | |
5479 » » brush_set_size(ps.brush, orig_brush_size); | |
5480 » » return OPERATOR_CANCELLED; | |
5481 » } | |
5482 » else { | |
5483 » » float pos[2]= {0.0, 0.0}; | |
5484 » » float lastpos[2]= {0.0, 0.0}; | |
5485 » » int a; | |
5486 | |
5487 » » for (a=0; a < ps.image_tot; a++) | |
5488 » » » partial_redraw_array_init(ps.projImages[a].partRedrawRec
t); | |
5489 | |
5490 » » project_paint_op(&ps, NULL, lastpos, pos); | |
5491 | |
5492 » » project_image_refresh_tagged(&ps); | |
5493 | |
5494 » » for (a=0; a < ps.image_tot; a++) { | |
5495 » » » GPU_free_image(ps.projImages[a].ima); | |
5496 » » » WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ps.projImag
es[a].ima); | |
5497 » » } | |
5498 » } | |
5499 | |
5500 » project_paint_end(&ps); | |
5501 | |
5502 » scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; | |
5503 » brush_set_size(ps.brush, orig_brush_size); | |
5504 | |
5505 » return OPERATOR_FINISHED; | |
5506 } | |
5507 | |
5508 void PAINT_OT_project_image(wmOperatorType *ot) | |
5509 { | |
5510 » PropertyRNA *prop; | |
5511 | |
5512 » /* identifiers */ | |
5513 » ot->name= "Project Image"; | |
5514 » ot->idname= "PAINT_OT_project_image"; | |
5515 » ot->description= "Project an edited render from the active camera back o
nto the object"; | |
5516 | |
5517 » /* api callbacks */ | |
5518 » ot->invoke= WM_enum_search_invoke; | |
5519 » ot->exec= texture_paint_camera_project_exec; | |
5520 | |
5521 » /* flags */ | |
5522 » ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; | |
5523 | |
5524 » prop= RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", "
"); | |
5525 » RNA_def_enum_funcs(prop, RNA_image_itemf); | |
5526 » ot->prop= prop; | |
5527 } | |
5528 | |
5529 static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) | |
5530 { | |
5531 » Image *image; | |
5532 » ImBuf *ibuf; | |
5533 » char filename[FILE_MAX]; | |
5534 | |
5535 » Scene *scene= CTX_data_scene(C); | |
5536 » ToolSettings *settings= scene->toolsettings; | |
5537 » int w= settings->imapaint.screen_grab_size[0]; | |
5538 » int h= settings->imapaint.screen_grab_size[1]; | |
5539 » int maxsize; | |
5540 » char err_out[256]= "unknown"; | |
5541 | |
5542 » RNA_string_get(op->ptr, "filepath", filename); | |
5543 | |
5544 » glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); | |
5545 | |
5546 » if(w > maxsize) w= maxsize; | |
5547 » if(h > maxsize) h= maxsize; | |
5548 | |
5549 » ibuf= ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C)
, CTX_wm_region(C), w, h, IB_rect, err_out); | |
5550 » if(!ibuf) { | |
5551 » » /* Mostly happens when OpenGL offscreen buffer was failed to cre
ate, */ | |
5552 » » /* but could be other reasons. Should be handled in the future.
nazgul */ | |
5553 » » BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off
screen buffer: %s", err_out); | |
5554 » » return OPERATOR_CANCELLED; | |
5555 » } | |
5556 | |
5557 » image= BKE_add_image_imbuf(ibuf); | |
5558 | |
5559 » if(image) { | |
5560 » » /* now for the trickyness. store the view projection here! | |
5561 » » * reprojection will reuse this */ | |
5562 » » View3D *v3d= CTX_wm_view3d(C); | |
5563 » » RegionView3D *rv3d= CTX_wm_region_view3d(C); | |
5564 | |
5565 » » IDPropertyTemplate val; | |
5566 » » IDProperty *idgroup= IDP_GetProperties(&image->id, 1); | |
5567 » » IDProperty *view_data; | |
5568 » » int orth; | |
5569 » » float *array; | |
5570 | |
5571 » » val.array.len = PROJ_VIEW_DATA_SIZE; | |
5572 » » val.array.type = IDP_FLOAT; | |
5573 » » view_data = IDP_New(IDP_ARRAY, val, PROJ_VIEW_DATA_ID); | |
5574 | |
5575 » » array= (float *)IDP_Array(view_data); | |
5576 » » memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += size
of(rv3d->winmat)/sizeof(float); | |
5577 » » memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += si
zeof(rv3d->viewmat)/sizeof(float); | |
5578 » » orth= project_paint_view_clip(v3d, rv3d, &array[0], &array[1]); | |
5579 » » array[2]= orth ? 1.0f : 0.0f; /* using float for a bool is dodgy
but since its an extra member in the array... easier then adding a single bool
prop */ | |
5580 | |
5581 » » IDP_AddToGroup(idgroup, view_data); | |
5582 | |
5583 » » rename_id(&image->id, "image_view"); | |
5584 » } | |
5585 | |
5586 » return OPERATOR_FINISHED; | |
5587 } | |
5588 | |
5589 void PAINT_OT_image_from_view(wmOperatorType *ot) | |
5590 { | |
5591 » /* identifiers */ | |
5592 » ot->name= "Image from View"; | |
5593 » ot->idname= "PAINT_OT_image_from_view"; | |
5594 » ot->description= "Make an image from the current 3D view for re-projecti
on"; | |
5595 | |
5596 » /* api callbacks */ | |
5597 » ot->exec= texture_paint_image_from_view_exec; | |
5598 » ot->poll= ED_operator_region_view3d_active; | |
5599 | |
5600 » /* flags */ | |
5601 » ot->flag= OPTYPE_REGISTER; | |
5602 | |
5603 » RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path"
, "Name of the file"); | |
5604 } | |
LEFT | RIGHT |