|
Blender
V2.59
|
00001 /* 00002 * $Id: paint_image.c 38893 2011-08-01 08:53:57Z campbellbarton $ 00003 * imagepaint.c 00004 * 00005 * Functions to paint images in 2D and 3D. 00006 * 00007 * ***** BEGIN GPL LICENSE BLOCK ***** 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU General Public License 00011 * as published by the Free Software Foundation; either version 2 00012 * of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00023 * All rights reserved. 00024 * 00025 * The Original Code is: some of this file. 00026 * 00027 * Contributor(s): Jens Ole Wund (bjornmose), Campbell Barton (ideasman42) 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 */ 00031 00037 #include <float.h> 00038 #include <string.h> 00039 #include <stdio.h> 00040 #include <math.h> 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #ifdef WIN32 00045 #include "BLI_winstuff.h" 00046 #endif 00047 #include "BLI_math.h" 00048 #include "BLI_blenlib.h" 00049 #include "BLI_dynstr.h" 00050 #include "BLI_linklist.h" 00051 #include "BLI_memarena.h" 00052 #include "BLI_threads.h" 00053 #include "BLI_utildefines.h" 00054 00055 #include "PIL_time.h" 00056 00057 #include "IMB_imbuf.h" 00058 #include "IMB_imbuf_types.h" 00059 00060 #include "DNA_brush_types.h" 00061 #include "DNA_mesh_types.h" 00062 #include "DNA_meshdata_types.h" 00063 #include "DNA_object_types.h" 00064 #include "DNA_scene_types.h" 00065 #include "DNA_texture_types.h" 00066 00067 #include "BKE_context.h" 00068 #include "BKE_depsgraph.h" 00069 #include "BKE_DerivedMesh.h" 00070 #include "BKE_idprop.h" 00071 #include "BKE_brush.h" 00072 #include "BKE_image.h" 00073 #include "BKE_library.h" 00074 #include "BKE_main.h" 00075 #include "BKE_mesh.h" 00076 #include "BKE_node.h" 00077 #include "BKE_object.h" 00078 #include "BKE_paint.h" 00079 #include "BKE_report.h" 00080 00081 #include "BIF_gl.h" 00082 #include "BIF_glutil.h" 00083 00084 #include "UI_view2d.h" 00085 00086 #include "ED_image.h" 00087 #include "ED_screen.h" 00088 #include "ED_sculpt.h" 00089 #include "ED_view3d.h" 00090 00091 #include "WM_api.h" 00092 #include "WM_types.h" 00093 00094 #include "RNA_access.h" 00095 #include "RNA_define.h" 00096 #include "RNA_enum_types.h" 00097 00098 #include "GPU_draw.h" 00099 00100 #include "paint_intern.h" 00101 00102 /* Defines and Structs */ 00103 00104 #define IMAPAINT_CHAR_TO_FLOAT(c) ((c)/255.0f) 00105 00106 #define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { (c)[0]=FTOCHAR((f)[0]); (c)[1]=FTOCHAR((f)[1]); (c)[2]=FTOCHAR((f)[2]); } 00107 #define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { (c)[0]=FTOCHAR((f)[0]); (c)[1]=FTOCHAR((f)[1]); (c)[2]=FTOCHAR((f)[2]); (c)[3]=FTOCHAR((f)[3]); } 00108 00109 #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]); } 00110 #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]); } 00111 #define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b) 00112 00113 #define IMAPAINT_TILE_BITS 6 00114 #define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS) 00115 #define IMAPAINT_TILE_NUMBER(size) (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS) 00116 00117 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint); 00118 00119 00120 typedef struct ImagePaintState { 00121 SpaceImage *sima; 00122 View2D *v2d; 00123 Scene *scene; 00124 bScreen *screen; 00125 00126 Brush *brush; 00127 short tool, blend; 00128 Image *image; 00129 ImBuf *canvas; 00130 ImBuf *clonecanvas; 00131 short clonefreefloat; 00132 char *warnpackedfile; 00133 char *warnmultifile; 00134 00135 /* texture paint only */ 00136 Object *ob; 00137 Mesh *me; 00138 int faceindex; 00139 float uv[2]; 00140 } ImagePaintState; 00141 00142 typedef struct ImagePaintPartialRedraw { 00143 int x1, y1, x2, y2; 00144 int enabled; 00145 } ImagePaintPartialRedraw; 00146 00147 typedef struct ImagePaintRegion { 00148 int destx, desty; 00149 int srcx, srcy; 00150 int width, height; 00151 } ImagePaintRegion; 00152 00153 /* ProjectionPaint defines */ 00154 00155 /* approx the number of buckets to have under the brush, 00156 * used with the brush size to set the ps->buckets_x and ps->buckets_y value. 00157 * 00158 * When 3 - a brush should have ~9 buckets under it at once 00159 * ...this helps for threading while painting as well as 00160 * avoiding initializing pixels that wont touch the brush */ 00161 #define PROJ_BUCKET_BRUSH_DIV 4 00162 00163 #define PROJ_BUCKET_RECT_MIN 4 00164 #define PROJ_BUCKET_RECT_MAX 256 00165 00166 #define PROJ_BOUNDBOX_DIV 8 00167 #define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV) 00168 00169 //#define PROJ_DEBUG_PAINT 1 00170 //#define PROJ_DEBUG_NOSEAMBLEED 1 00171 //#define PROJ_DEBUG_PRINT_CLIP 1 00172 #define PROJ_DEBUG_WINCLIP 1 00173 00174 /* projectFaceSeamFlags options */ 00175 //#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */ 00176 //#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */ 00177 #define PROJ_FACE_SEAM1 (1<<0) /* If this face has a seam on any of its edges */ 00178 #define PROJ_FACE_SEAM2 (1<<1) 00179 #define PROJ_FACE_SEAM3 (1<<2) 00180 #define PROJ_FACE_SEAM4 (1<<3) 00181 00182 #define PROJ_FACE_NOSEAM1 (1<<4) 00183 #define PROJ_FACE_NOSEAM2 (1<<5) 00184 #define PROJ_FACE_NOSEAM3 (1<<6) 00185 #define PROJ_FACE_NOSEAM4 (1<<7) 00186 00187 #define PROJ_SRC_VIEW 1 00188 #define PROJ_SRC_IMAGE_CAM 2 00189 #define PROJ_SRC_IMAGE_VIEW 3 00190 00191 #define PROJ_VIEW_DATA_ID "view_data" 00192 #define PROJ_VIEW_DATA_SIZE (4*4 + 4*4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */ 00193 00194 00195 /* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams 00196 * as this number approaches 1.0f the likelihood increases of float precision errors where 00197 * it is occluded by an adjacent face */ 00198 #define PROJ_FACE_SCALE_SEAM 0.99f 00199 00200 #define PROJ_BUCKET_NULL 0 00201 #define PROJ_BUCKET_INIT (1<<0) 00202 // #define PROJ_BUCKET_CLONE_INIT (1<<1) 00203 00204 /* used for testing doubles, if a point is on a line etc */ 00205 #define PROJ_GEOM_TOLERANCE 0.00075f 00206 00207 /* vert flags */ 00208 #define PROJ_VERT_CULL 1 00209 00210 #define PI_80_DEG ((M_PI_2 / 9) * 8) 00211 00212 /* This is mainly a convenience struct used so we can keep an array of images we use 00213 * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread 00214 * because 'partRedrawRect' and 'touch' values would not be thread safe */ 00215 typedef struct ProjPaintImage { 00216 Image *ima; 00217 ImBuf *ibuf; 00218 ImagePaintPartialRedraw *partRedrawRect; 00219 void **undoRect; /* only used to build undo tiles after painting */ 00220 int touch; 00221 } ProjPaintImage; 00222 00223 /* Main projection painting struct passed to all projection painting functions */ 00224 typedef struct ProjPaintState { 00225 View3D *v3d; 00226 RegionView3D *rv3d; 00227 ARegion *ar; 00228 Scene *scene; 00229 int source; /* PROJ_SRC_**** */ 00230 00231 Brush *brush; 00232 short tool, blend; 00233 Object *ob; 00234 /* end similarities with ImagePaintState */ 00235 00236 DerivedMesh *dm; 00237 int dm_totface; 00238 int dm_totvert; 00239 int dm_release; 00240 00241 MVert *dm_mvert; 00242 MFace *dm_mface; 00243 MTFace *dm_mtface; 00244 MTFace *dm_mtface_clone; /* other UV layer, use for cloning between layers */ 00245 MTFace *dm_mtface_stencil; 00246 00247 /* projection painting only */ 00248 MemArena *arena_mt[BLENDER_MAX_THREADS];/* for multithreading, the first item is sometimes used for non threaded cases too */ 00249 LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */ 00250 LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */ 00251 unsigned char *bucketFlags; /* store if the bucks have been initialized */ 00252 #ifndef PROJ_DEBUG_NOSEAMBLEED 00253 char *faceSeamFlags; /* store info about faces, if they are initialized etc*/ 00254 float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */ 00255 LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */ 00256 #endif 00257 char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */ 00258 int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */ 00259 int buckets_y; 00260 00261 ProjPaintImage *projImages; 00262 00263 int image_tot; /* size of projectImages array */ 00264 00265 float (*screenCoords)[4]; /* verts projected into floating point screen space */ 00266 00267 float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */ 00268 float screenMax[2]; 00269 float screen_width; /* Calculated from screenMin & screenMax */ 00270 float screen_height; 00271 int winx, winy; /* from the carea or from the projection render */ 00272 00273 /* options for projection painting */ 00274 int do_layer_clone; 00275 int do_layer_stencil; 00276 int do_layer_stencil_inv; 00277 00278 short do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ 00279 short do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ 00280 short do_mask_normal; /* mask out pixels based on their normals */ 00281 float normal_angle; /* what angle to mask at*/ 00282 float normal_angle_inner; 00283 float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */ 00284 00285 short is_ortho; 00286 short is_airbrush; /* only to avoid using (ps.brush->flag & BRUSH_AIRBRUSH) */ 00287 short is_texbrush; /* only to avoid running */ 00288 #ifndef PROJ_DEBUG_NOSEAMBLEED 00289 float seam_bleed_px; 00290 #endif 00291 /* clone vars */ 00292 float cloneOffset[2]; 00293 00294 float projectMat[4][4]; /* Projection matrix, use for getting screen coords */ 00295 float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */ 00296 float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */ 00297 float clipsta, clipend; 00298 00299 /* reproject vars */ 00300 Image *reproject_image; 00301 ImBuf *reproject_ibuf; 00302 00303 00304 /* threads */ 00305 int thread_tot; 00306 int bucketMin[2]; 00307 int bucketMax[2]; 00308 int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */ 00309 } ProjPaintState; 00310 00311 typedef union pixelPointer 00312 { 00313 float *f_pt; /* float buffer */ 00314 unsigned int *uint_pt; /* 2 ways to access a char buffer */ 00315 unsigned char *ch_pt; 00316 } PixelPointer; 00317 00318 typedef union pixelStore 00319 { 00320 unsigned char ch[4]; 00321 unsigned int uint; 00322 float f[4]; 00323 } PixelStore; 00324 00325 typedef struct ProjPixel { 00326 float projCoSS[2]; /* the floating point screen projection of this pixel */ 00327 00328 /* Only used when the airbrush is disabled. 00329 * Store the max mask value to avoid painting over an area with a lower opacity 00330 * with an advantage that we can avoid touching the pixel at all, if the 00331 * new mask value is lower then mask_max */ 00332 unsigned short mask_max; 00333 00334 /* for various reasons we may want to mask out painting onto this pixel */ 00335 unsigned short mask; 00336 00337 short x_px, y_px; 00338 00339 PixelStore origColor; 00340 PixelStore newColor; 00341 PixelPointer pixel; 00342 00343 short image_index; /* if anyone wants to paint onto more then 32768 images they can bite me */ 00344 unsigned char bb_cell_index; 00345 } ProjPixel; 00346 00347 typedef struct ProjPixelClone { 00348 struct ProjPixel __pp; 00349 PixelStore clonepx; 00350 } ProjPixelClone; 00351 00352 /* Finish projection painting structs */ 00353 00354 typedef struct UndoImageTile { 00355 struct UndoImageTile *next, *prev; 00356 00357 char idname[MAX_ID_NAME]; /* name instead of pointer*/ 00358 00359 void *rect; 00360 int x, y; 00361 } UndoImageTile; 00362 00363 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; 00364 00365 /* UNDO */ 00366 00367 static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore) 00368 { 00369 /* copy or swap contents of tile->rect and region in ibuf->rect */ 00370 IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE, 00371 tile->y*IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); 00372 00373 if(ibuf->rect_float) { 00374 SWAP(void*, tmpibuf->rect_float, tile->rect); 00375 } else { 00376 SWAP(void*, tmpibuf->rect, tile->rect); 00377 } 00378 00379 if(restore) 00380 IMB_rectcpy(ibuf, tmpibuf, tile->x*IMAPAINT_TILE_SIZE, 00381 tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); 00382 } 00383 00384 static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile) 00385 { 00386 ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_IMAGE); 00387 UndoImageTile *tile; 00388 int allocsize; 00389 00390 for(tile=lb->first; tile; tile=tile->next) 00391 if(tile->x == x_tile && tile->y == y_tile && strcmp(tile->idname, ima->id.name)==0) 00392 return tile->rect; 00393 00394 if (*tmpibuf==NULL) 00395 *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect); 00396 00397 tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); 00398 strcpy(tile->idname, ima->id.name); 00399 tile->x= x_tile; 00400 tile->y= y_tile; 00401 00402 allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4; 00403 allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char); 00404 tile->rect= MEM_mapallocN(allocsize, "UndeImageTile.rect"); 00405 00406 undo_copy_tile(tile, *tmpibuf, ibuf, 0); 00407 undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); 00408 00409 BLI_addtail(lb, tile); 00410 00411 return tile->rect; 00412 } 00413 00414 static void image_undo_restore(bContext *C, ListBase *lb) 00415 { 00416 Main *bmain= CTX_data_main(C); 00417 Image *ima = NULL; 00418 ImBuf *ibuf, *tmpibuf; 00419 UndoImageTile *tile; 00420 00421 tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 00422 IB_rectfloat|IB_rect); 00423 00424 for(tile=lb->first; tile; tile=tile->next) { 00425 /* find image based on name, pointer becomes invalid with global undo */ 00426 if(ima && strcmp(tile->idname, ima->id.name)==0); 00427 else { 00428 for(ima=bmain->image.first; ima; ima=ima->id.next) 00429 if(strcmp(tile->idname, ima->id.name)==0) 00430 break; 00431 } 00432 00433 ibuf= BKE_image_get_ibuf(ima, NULL); 00434 00435 if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) 00436 continue; 00437 00438 undo_copy_tile(tile, tmpibuf, ibuf, 1); 00439 00440 GPU_free_image(ima); /* force OpenGL reload */ 00441 if(ibuf->rect_float) 00442 ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ 00443 if(ibuf->mipmap[0]) 00444 ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ 00445 00446 } 00447 00448 IMB_freeImBuf(tmpibuf); 00449 } 00450 00451 static void image_undo_free(ListBase *lb) 00452 { 00453 UndoImageTile *tile; 00454 00455 for(tile=lb->first; tile; tile=tile->next) 00456 MEM_freeN(tile->rect); 00457 } 00458 00459 /* fast projection bucket array lookup, use the safe version for bound checking */ 00460 static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2]) 00461 { 00462 /* If we were not dealing with screenspace 2D coords we could simple do... 00463 * ps->bucketRect[x + (y*ps->buckets_y)] */ 00464 00465 /* please explain? 00466 * projCoSS[0] - ps->screenMin[0] : zero origin 00467 * ... / ps->screen_width : range from 0.0 to 1.0 00468 * ... * ps->buckets_x : use as a bucket index 00469 * 00470 * Second multiplication does similar but for vertical offset 00471 */ 00472 return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) + 00473 ( ( (int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x); 00474 } 00475 00476 static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2]) 00477 { 00478 int bucket_index = project_bucket_offset(ps, projCoSS); 00479 00480 if (bucket_index < 0 || bucket_index >= ps->buckets_x*ps->buckets_y) { 00481 return -1; 00482 } 00483 else { 00484 return bucket_index; 00485 } 00486 } 00487 00488 /* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */ 00489 static void barycentric_weights_v2_persp(float v1[4], float v2[4], float v3[4], float co[2], float w[3]) 00490 { 00491 float wtot_inv, wtot; 00492 00493 w[0] = area_tri_signed_v2(v2, v3, co) / v1[3]; 00494 w[1] = area_tri_signed_v2(v3, v1, co) / v2[3]; 00495 w[2] = area_tri_signed_v2(v1, v2, co) / v3[3]; 00496 wtot = w[0]+w[1]+w[2]; 00497 00498 if (wtot != 0.0f) { 00499 wtot_inv = 1.0f/wtot; 00500 00501 w[0] = w[0]*wtot_inv; 00502 w[1] = w[1]*wtot_inv; 00503 w[2] = w[2]*wtot_inv; 00504 } 00505 else /* dummy values for zero area face */ 00506 w[0] = w[1] = w[2] = 1.0f/3.0f; 00507 } 00508 00509 static float VecZDepthOrtho(float pt[2], float v1[3], float v2[3], float v3[3], float w[3]) 00510 { 00511 barycentric_weights_v2(v1, v2, v3, pt, w); 00512 return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]); 00513 } 00514 00515 static float VecZDepthPersp(float pt[2], float v1[3], float v2[3], float v3[3], float w[3]) 00516 { 00517 float wtot_inv, wtot; 00518 float w_tmp[3]; 00519 00520 barycentric_weights_v2_persp(v1, v2, v3, pt, w); 00521 /* for the depth we need the weights to match what 00522 * barycentric_weights_v2 would return, in this case its easiest just to 00523 * undo the 4th axis division and make it unit-sum 00524 * 00525 * don't call barycentric_weights_v2() becaue our callers expect 'w' 00526 * to be weighted from the perspective */ 00527 w_tmp[0]= w[0] * v1[3]; 00528 w_tmp[1]= w[1] * v2[3]; 00529 w_tmp[2]= w[2] * v3[3]; 00530 00531 wtot = w_tmp[0]+w_tmp[1]+w_tmp[2]; 00532 00533 if (wtot != 0.0f) { 00534 wtot_inv = 1.0f/wtot; 00535 00536 w_tmp[0] = w_tmp[0]*wtot_inv; 00537 w_tmp[1] = w_tmp[1]*wtot_inv; 00538 w_tmp[2] = w_tmp[2]*wtot_inv; 00539 } 00540 else /* dummy values for zero area face */ 00541 w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f/3.0f; 00542 /* done mimicing barycentric_weights_v2() */ 00543 00544 return (v1[2]*w_tmp[0]) + (v2[2]*w_tmp[1]) + (v3[2]*w_tmp[2]); 00545 } 00546 00547 00548 /* Return the top-most face index that the screen space coord 'pt' touches (or -1) */ 00549 static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w[3], int *side) 00550 { 00551 LinkNode *node; 00552 float w_tmp[3]; 00553 float *v1, *v2, *v3, *v4; 00554 int bucket_index; 00555 int face_index; 00556 int best_side = -1; 00557 int best_face_index = -1; 00558 float z_depth_best = FLT_MAX, z_depth; 00559 MFace *mf; 00560 00561 bucket_index = project_bucket_offset_safe(ps, pt); 00562 if (bucket_index==-1) 00563 return -1; 00564 00565 00566 00567 /* we could return 0 for 1 face buckets, as long as this function assumes 00568 * that the point its testing is only every originated from an existing face */ 00569 00570 for (node= ps->bucketFaces[bucket_index]; node; node= node->next) { 00571 face_index = GET_INT_FROM_POINTER(node->link); 00572 mf= ps->dm_mface + face_index; 00573 00574 v1= ps->screenCoords[mf->v1]; 00575 v2= ps->screenCoords[mf->v2]; 00576 v3= ps->screenCoords[mf->v3]; 00577 00578 if (isect_point_tri_v2(pt, v1, v2, v3)) { 00579 if (ps->is_ortho) z_depth= VecZDepthOrtho(pt, v1, v2, v3, w_tmp); 00580 else z_depth= VecZDepthPersp(pt, v1, v2, v3, w_tmp); 00581 00582 if (z_depth < z_depth_best) { 00583 best_face_index = face_index; 00584 best_side = 0; 00585 z_depth_best = z_depth; 00586 VECCOPY(w, w_tmp); 00587 } 00588 } 00589 else if (mf->v4) { 00590 v4= ps->screenCoords[mf->v4]; 00591 00592 if (isect_point_tri_v2(pt, v1, v3, v4)) { 00593 if (ps->is_ortho) z_depth= VecZDepthOrtho(pt, v1, v3, v4, w_tmp); 00594 else z_depth= VecZDepthPersp(pt, v1, v3, v4, w_tmp); 00595 00596 if (z_depth < z_depth_best) { 00597 best_face_index = face_index; 00598 best_side= 1; 00599 z_depth_best = z_depth; 00600 VECCOPY(w, w_tmp); 00601 } 00602 } 00603 } 00604 } 00605 00606 *side = best_side; 00607 return best_face_index; /* will be -1 or a valid face */ 00608 } 00609 00610 /* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */ 00611 static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y) 00612 { 00613 /* use */ 00614 *x = (float)fmodf(uv[0], 1.0f); 00615 *y = (float)fmodf(uv[1], 1.0f); 00616 00617 if (*x < 0.0f) *x += 1.0f; 00618 if (*y < 0.0f) *y += 1.0f; 00619 00620 *x = *x * ibuf_x - 0.5f; 00621 *y = *y * ibuf_y - 0.5f; 00622 } 00623 00624 /* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */ 00625 static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float *rgba_fp, unsigned char *rgba, const int interp) 00626 { 00627 float w[3], uv[2]; 00628 int side; 00629 int face_index; 00630 MTFace *tf; 00631 ImBuf *ibuf; 00632 int xi, yi; 00633 00634 00635 face_index = project_paint_PickFace(ps, pt, w, &side); 00636 00637 if (face_index == -1) 00638 return 0; 00639 00640 tf = ps->dm_mtface + face_index; 00641 00642 if (side == 0) { 00643 interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); 00644 } 00645 else { /* QUAD */ 00646 interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); 00647 } 00648 00649 ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before getting here */ 00650 if (!ibuf) return 0; 00651 00652 if (interp) { 00653 float x, y; 00654 uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y); 00655 00656 if (ibuf->rect_float) { 00657 if (rgba_fp) { 00658 bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y); 00659 } 00660 else { 00661 float rgba_tmp_f[4]; 00662 bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y); 00663 IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f); 00664 } 00665 } 00666 else { 00667 if (rgba) { 00668 bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y); 00669 } 00670 else { 00671 unsigned char rgba_tmp[4]; 00672 bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y); 00673 IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp); 00674 } 00675 } 00676 } 00677 else { 00678 //xi = (int)((uv[0]*ibuf->x) + 0.5f); 00679 //yi = (int)((uv[1]*ibuf->y) + 0.5f); 00680 //if (xi<0 || xi>=ibuf->x || yi<0 || yi>=ibuf->y) return 0; 00681 00682 /* wrap */ 00683 xi = ((int)(uv[0]*ibuf->x)) % ibuf->x; 00684 if (xi<0) xi += ibuf->x; 00685 yi = ((int)(uv[1]*ibuf->y)) % ibuf->y; 00686 if (yi<0) yi += ibuf->y; 00687 00688 00689 if (rgba) { 00690 if (ibuf->rect_float) { 00691 float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4); 00692 IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp); 00693 } 00694 else { 00695 *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4)); 00696 } 00697 } 00698 00699 if (rgba_fp) { 00700 if (ibuf->rect_float) { 00701 QUATCOPY(rgba_fp, ((float *)ibuf->rect_float + ((xi + yi * ibuf->x) * 4))); 00702 } 00703 else { 00704 char *tmp_ch= ((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4); 00705 IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch); 00706 } 00707 } 00708 } 00709 return 1; 00710 } 00711 00712 /* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test) 00713 * return... 00714 * 0 : no occlusion 00715 * -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad) 00716 * 1 : occluded 00717 2 : occluded with w[3] weights set (need to know in some cases) */ 00718 00719 static int project_paint_occlude_ptv(float pt[3], float v1[3], float v2[3], float v3[3], float w[3], int is_ortho) 00720 { 00721 /* if all are behind us, return false */ 00722 if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2]) 00723 return 0; 00724 00725 /* do a 2D point in try intersection */ 00726 if (!isect_point_tri_v2(pt, v1, v2, v3)) 00727 return 0; /* we know there is */ 00728 00729 00730 /* From here on we know there IS an intersection */ 00731 /* if ALL of the verts are infront of us then we know it intersects ? */ 00732 if(v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) { 00733 return 1; 00734 } 00735 else { 00736 /* we intersect? - find the exact depth at the point of intersection */ 00737 /* Is this point is occluded by another face? */ 00738 if (is_ortho) { 00739 if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2; 00740 } 00741 else { 00742 if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2; 00743 } 00744 } 00745 return -1; 00746 } 00747 00748 00749 static int project_paint_occlude_ptv_clip( 00750 const ProjPaintState *ps, const MFace *mf, 00751 float pt[3], float v1[3], float v2[3], float v3[3], 00752 const int side ) 00753 { 00754 float w[3], wco[3]; 00755 int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho); 00756 00757 if (ret <= 0) 00758 return ret; 00759 00760 if (ret==1) { /* weights not calculated */ 00761 if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w); 00762 else barycentric_weights_v2_persp(v1, v2, v3, pt, w); 00763 } 00764 00765 /* Test if we're in the clipped area, */ 00766 if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); 00767 else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); 00768 00769 if(!ED_view3d_test_clipping(ps->rv3d, wco, 1)) { 00770 return 1; 00771 } 00772 00773 return -1; 00774 } 00775 00776 00777 /* Check if a screenspace location is occluded by any other faces 00778 * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison 00779 * and dosn't need to be correct in relation to X and Y coords (this is the case in perspective view) */ 00780 static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, float pixelScreenCo[4]) 00781 { 00782 MFace *mf; 00783 int face_index; 00784 int isect_ret; 00785 float w[3]; /* not needed when clipping */ 00786 const short do_clip= ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; 00787 00788 /* we could return 0 for 1 face buckets, as long as this function assumes 00789 * that the point its testing is only every originated from an existing face */ 00790 00791 for (; bucketFace; bucketFace = bucketFace->next) { 00792 face_index = GET_INT_FROM_POINTER(bucketFace->link); 00793 00794 if (orig_face != face_index) { 00795 mf = ps->dm_mface + face_index; 00796 if(do_clip) 00797 isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0); 00798 else 00799 isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho); 00800 00801 /* Note, if isect_ret==-1 then we dont want to test the other side of the quad */ 00802 if (isect_ret==0 && mf->v4) { 00803 if(do_clip) 00804 isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1); 00805 else 00806 isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho); 00807 } 00808 if (isect_ret>=1) { 00809 /* TODO - we may want to cache the first hit, 00810 * it is not possible to swap the face order in the list anymore */ 00811 return 1; 00812 } 00813 } 00814 } 00815 return 0; 00816 } 00817 00818 /* basic line intersection, could move to math_geom.c, 2 points with a horiz line 00819 * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */ 00820 #define ISECT_TRUE 1 00821 #define ISECT_TRUE_P1 2 00822 #define ISECT_TRUE_P2 3 00823 static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect) 00824 { 00825 float y_diff; 00826 00827 if (y_level==p1[1]) { /* are we touching the first point? - no interpolation needed */ 00828 *x_isect = p1[0]; 00829 return ISECT_TRUE_P1; 00830 } 00831 if (y_level==p2[1]) { /* are we touching the second point? - no interpolation needed */ 00832 *x_isect = p2[0]; 00833 return ISECT_TRUE_P2; 00834 } 00835 00836 y_diff= fabsf(p1[1]-p2[1]); /* yuck, horizontal line, we cant do much here */ 00837 00838 if (y_diff < 0.000001f) { 00839 *x_isect = (p1[0]+p2[0]) * 0.5f; 00840 return ISECT_TRUE; 00841 } 00842 00843 if (p1[1] > y_level && p2[1] < y_level) { 00844 *x_isect = (p2[0]*(p1[1]-y_level) + p1[0]*(y_level-p2[1])) / y_diff; /*(p1[1]-p2[1]);*/ 00845 return ISECT_TRUE; 00846 } 00847 else if (p1[1] < y_level && p2[1] > y_level) { 00848 *x_isect = (p2[0]*(y_level-p1[1]) + p1[0]*(p2[1]-y_level)) / y_diff; /*(p2[1]-p1[1]);*/ 00849 return ISECT_TRUE; 00850 } 00851 else { 00852 return 0; 00853 } 00854 } 00855 00856 static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect) 00857 { 00858 float x_diff; 00859 00860 if (x_level==p1[0]) { /* are we touching the first point? - no interpolation needed */ 00861 *y_isect = p1[1]; 00862 return ISECT_TRUE_P1; 00863 } 00864 if (x_level==p2[0]) { /* are we touching the second point? - no interpolation needed */ 00865 *y_isect = p2[1]; 00866 return ISECT_TRUE_P2; 00867 } 00868 00869 x_diff= fabsf(p1[0]-p2[0]); /* yuck, horizontal line, we cant do much here */ 00870 00871 if (x_diff < 0.000001f) { /* yuck, vertical line, we cant do much here */ 00872 *y_isect = (p1[0]+p2[0]) * 0.5f; 00873 return ISECT_TRUE; 00874 } 00875 00876 if (p1[0] > x_level && p2[0] < x_level) { 00877 *y_isect = (p2[1]*(p1[0]-x_level) + p1[1]*(x_level-p2[0])) / x_diff; /*(p1[0]-p2[0]);*/ 00878 return ISECT_TRUE; 00879 } 00880 else if (p1[0] < x_level && p2[0] > x_level) { 00881 *y_isect = (p2[1]*(x_level-p1[0]) + p1[1]*(p2[0]-x_level)) / x_diff; /*(p2[0]-p1[0]);*/ 00882 return ISECT_TRUE; 00883 } 00884 else { 00885 return 0; 00886 } 00887 } 00888 00889 /* simple func use for comparing UV locations to check if there are seams. 00890 * Its possible this gives incorrect results, when the UVs for 1 face go into the next 00891 * tile, but do not do this for the adjacent face, it could return a false positive. 00892 * This is so unlikely that Id not worry about it. */ 00893 #ifndef PROJ_DEBUG_NOSEAMBLEED 00894 static int cmp_uv(const float vec2a[2], const float vec2b[2]) 00895 { 00896 /* if the UV's are not between 0.0 and 1.0 */ 00897 float xa = (float)fmodf(vec2a[0], 1.0f); 00898 float ya = (float)fmodf(vec2a[1], 1.0f); 00899 00900 float xb = (float)fmodf(vec2b[0], 1.0f); 00901 float yb = (float)fmodf(vec2b[1], 1.0f); 00902 00903 if (xa < 0.0f) xa += 1.0f; 00904 if (ya < 0.0f) ya += 1.0f; 00905 00906 if (xb < 0.0f) xb += 1.0f; 00907 if (yb < 0.0f) yb += 1.0f; 00908 00909 return ((fabsf(xa-xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya-yb) < PROJ_GEOM_TOLERANCE)) ? 1:0; 00910 } 00911 #endif 00912 00913 /* set min_px and max_px to the image space bounds of the UV coords 00914 * return zero if there is no area in the returned rectangle */ 00915 #ifndef PROJ_DEBUG_NOSEAMBLEED 00916 static int pixel_bounds_uv( 00917 const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2], 00918 rcti *bounds_px, 00919 const int ibuf_x, const int ibuf_y, 00920 int is_quad 00921 ) { 00922 float min_uv[2], max_uv[2]; /* UV bounds */ 00923 00924 INIT_MINMAX2(min_uv, max_uv); 00925 00926 DO_MINMAX2(uv1, min_uv, max_uv); 00927 DO_MINMAX2(uv2, min_uv, max_uv); 00928 DO_MINMAX2(uv3, min_uv, max_uv); 00929 if (is_quad) 00930 DO_MINMAX2(uv4, min_uv, max_uv); 00931 00932 bounds_px->xmin = (int)(ibuf_x * min_uv[0]); 00933 bounds_px->ymin = (int)(ibuf_y * min_uv[1]); 00934 00935 bounds_px->xmax = (int)(ibuf_x * max_uv[0]) +1; 00936 bounds_px->ymax = (int)(ibuf_y * max_uv[1]) +1; 00937 00938 /*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/ 00939 00940 /* face uses no UV area when quantized to pixels? */ 00941 return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; 00942 } 00943 #endif 00944 00945 static int pixel_bounds_array(float (* uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot) 00946 { 00947 float min_uv[2], max_uv[2]; /* UV bounds */ 00948 00949 if (tot==0) { 00950 return 0; 00951 } 00952 00953 INIT_MINMAX2(min_uv, max_uv); 00954 00955 while (tot--) { 00956 DO_MINMAX2((*uv), min_uv, max_uv); 00957 uv++; 00958 } 00959 00960 bounds_px->xmin = (int)(ibuf_x * min_uv[0]); 00961 bounds_px->ymin = (int)(ibuf_y * min_uv[1]); 00962 00963 bounds_px->xmax = (int)(ibuf_x * max_uv[0]) +1; 00964 bounds_px->ymax = (int)(ibuf_y * max_uv[1]) +1; 00965 00966 /*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/ 00967 00968 /* face uses no UV area when quantized to pixels? */ 00969 return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; 00970 } 00971 00972 #ifndef PROJ_DEBUG_NOSEAMBLEED 00973 00974 /* This function returns 1 if this face has a seam along the 2 face-vert indices 00975 * 'orig_i1_fidx' and 'orig_i2_fidx' */ 00976 static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx) 00977 { 00978 LinkNode *node; 00979 int face_index; 00980 unsigned int i1, i2; 00981 int i1_fidx = -1, i2_fidx = -1; /* index in face */ 00982 MFace *mf; 00983 MTFace *tf; 00984 const MFace *orig_mf = ps->dm_mface + orig_face; 00985 const MTFace *orig_tf = ps->dm_mtface + orig_face; 00986 00987 /* vert indices from face vert order indices */ 00988 i1 = (*(&orig_mf->v1 + orig_i1_fidx)); 00989 i2 = (*(&orig_mf->v1 + orig_i2_fidx)); 00990 00991 for (node = ps->vertFaces[i1]; node; node = node->next) { 00992 face_index = GET_INT_FROM_POINTER(node->link); 00993 00994 if (face_index != orig_face) { 00995 mf = ps->dm_mface + face_index; 00996 /* could check if the 2 faces images match here, 00997 * but then there wouldn't be a way to return the opposite face's info */ 00998 00999 01000 /* We need to know the order of the verts in the adjacent face 01001 * set the i1_fidx and i2_fidx to (0,1,2,3) */ 01002 if (mf->v1==i1) i1_fidx = 0; 01003 else if (mf->v2==i1) i1_fidx = 1; 01004 else if (mf->v3==i1) i1_fidx = 2; 01005 else if (mf->v4 && mf->v4==i1) i1_fidx = 3; 01006 01007 if (mf->v1==i2) i2_fidx = 0; 01008 else if (mf->v2==i2) i2_fidx = 1; 01009 else if (mf->v3==i2) i2_fidx = 2; 01010 else if (mf->v4 && mf->v4==i2) i2_fidx = 3; 01011 01012 /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */ 01013 if (i2_fidx != -1) { 01014 /* This IS an adjacent face!, now lets check if the UVs are ok */ 01015 tf = ps->dm_mtface + face_index; 01016 01017 /* set up the other face */ 01018 *other_face = face_index; 01019 *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx; 01020 01021 /* first test if they have the same image */ 01022 if ( (orig_tf->tpage == tf->tpage) && 01023 cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) && 01024 cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) ) 01025 { 01026 // printf("SEAM (NONE)\n"); 01027 return 0; 01028 01029 } 01030 else { 01031 // printf("SEAM (UV GAP)\n"); 01032 return 1; 01033 } 01034 } 01035 } 01036 } 01037 // printf("SEAM (NO FACE)\n"); 01038 *other_face = -1; 01039 return 1; 01040 } 01041 01042 /* Calculate outset UV's, this is not the same as simply scaling the UVs, 01043 * since the outset coords are a margin that keep an even distance from the original UV's, 01044 * note that the image aspect is taken into account */ 01045 static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, const int ibuf_x, const int ibuf_y, const int is_quad) 01046 { 01047 float a1, a2, a3, a4=0.0f; 01048 float puv[4][2]; /* pixelspace uv's */ 01049 float no1[2], no2[2], no3[2], no4[2]; /* normals */ 01050 float dir1[2], dir2[2], dir3[2], dir4[2]; 01051 float ibuf_inv[2]; 01052 01053 ibuf_inv[0]= 1.0f / (float)ibuf_x; 01054 ibuf_inv[1]= 1.0f / (float)ibuf_y; 01055 01056 /* make UV's in pixel space so we can */ 01057 puv[0][0] = orig_uv[0][0] * ibuf_x; 01058 puv[0][1] = orig_uv[0][1] * ibuf_y; 01059 01060 puv[1][0] = orig_uv[1][0] * ibuf_x; 01061 puv[1][1] = orig_uv[1][1] * ibuf_y; 01062 01063 puv[2][0] = orig_uv[2][0] * ibuf_x; 01064 puv[2][1] = orig_uv[2][1] * ibuf_y; 01065 01066 if (is_quad) { 01067 puv[3][0] = orig_uv[3][0] * ibuf_x; 01068 puv[3][1] = orig_uv[3][1] * ibuf_y; 01069 } 01070 01071 /* face edge directions */ 01072 sub_v2_v2v2(dir1, puv[1], puv[0]); 01073 sub_v2_v2v2(dir2, puv[2], puv[1]); 01074 normalize_v2(dir1); 01075 normalize_v2(dir2); 01076 01077 if (is_quad) { 01078 sub_v2_v2v2(dir3, puv[3], puv[2]); 01079 sub_v2_v2v2(dir4, puv[0], puv[3]); 01080 normalize_v2(dir3); 01081 normalize_v2(dir4); 01082 } 01083 else { 01084 sub_v2_v2v2(dir3, puv[0], puv[2]); 01085 normalize_v2(dir3); 01086 } 01087 01088 /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f) 01089 * This is incorrect. Its already given radians but without it wont work. 01090 * need to look into a fix - campbell */ 01091 if (is_quad) { 01092 a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI/180.0f)); 01093 a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f)); 01094 a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f)); 01095 a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI/180.0f)); 01096 } 01097 else { 01098 a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI/180.0f)); 01099 a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f)); 01100 a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f)); 01101 } 01102 01103 if (is_quad) { 01104 sub_v2_v2v2(no1, dir4, dir1); 01105 sub_v2_v2v2(no2, dir1, dir2); 01106 sub_v2_v2v2(no3, dir2, dir3); 01107 sub_v2_v2v2(no4, dir3, dir4); 01108 normalize_v2(no1); 01109 normalize_v2(no2); 01110 normalize_v2(no3); 01111 normalize_v2(no4); 01112 mul_v2_fl(no1, a1*scaler); 01113 mul_v2_fl(no2, a2*scaler); 01114 mul_v2_fl(no3, a3*scaler); 01115 mul_v2_fl(no4, a4*scaler); 01116 add_v2_v2v2(outset_uv[0], puv[0], no1); 01117 add_v2_v2v2(outset_uv[1], puv[1], no2); 01118 add_v2_v2v2(outset_uv[2], puv[2], no3); 01119 add_v2_v2v2(outset_uv[3], puv[3], no4); 01120 mul_v2_v2(outset_uv[0], ibuf_inv); 01121 mul_v2_v2(outset_uv[1], ibuf_inv); 01122 mul_v2_v2(outset_uv[2], ibuf_inv); 01123 mul_v2_v2(outset_uv[3], ibuf_inv); 01124 } 01125 else { 01126 sub_v2_v2v2(no1, dir3, dir1); 01127 sub_v2_v2v2(no2, dir1, dir2); 01128 sub_v2_v2v2(no3, dir2, dir3); 01129 normalize_v2(no1); 01130 normalize_v2(no2); 01131 normalize_v2(no3); 01132 mul_v2_fl(no1, a1*scaler); 01133 mul_v2_fl(no2, a2*scaler); 01134 mul_v2_fl(no3, a3*scaler); 01135 add_v2_v2v2(outset_uv[0], puv[0], no1); 01136 add_v2_v2v2(outset_uv[1], puv[1], no2); 01137 add_v2_v2v2(outset_uv[2], puv[2], no3); 01138 01139 mul_v2_v2(outset_uv[0], ibuf_inv); 01140 mul_v2_v2(outset_uv[1], ibuf_inv); 01141 mul_v2_v2(outset_uv[2], ibuf_inv); 01142 } 01143 } 01144 01145 /* 01146 * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4 01147 * 1<<i - where i is (0-3) 01148 * 01149 * If we're multithreadng, make sure threads are locked when this is called 01150 */ 01151 static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad) 01152 { 01153 int other_face, other_fidx; /* vars for the other face, we also set its flag */ 01154 int fidx1 = is_quad ? 3 : 2; 01155 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 */ 01156 01157 do { 01158 if ((ps->faceSeamFlags[face_index] & (1<<fidx1|16<<fidx1)) == 0) { 01159 if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) { 01160 ps->faceSeamFlags[face_index] |= 1<<fidx1; 01161 if (other_face != -1) 01162 ps->faceSeamFlags[other_face] |= 1<<other_fidx; 01163 } 01164 else { 01165 ps->faceSeamFlags[face_index] |= 16<<fidx1; 01166 if (other_face != -1) 01167 ps->faceSeamFlags[other_face] |= 16<<other_fidx; /* second 4 bits for disabled */ 01168 } 01169 } 01170 01171 fidx2 = fidx1; 01172 } while (fidx1--); 01173 } 01174 #endif // PROJ_DEBUG_NOSEAMBLEED 01175 01176 01177 /* Converts a UV location to a 3D screenspace location 01178 * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo 01179 * 01180 * This is used for finding a pixels location in screenspace for painting */ 01181 static void screen_px_from_ortho( 01182 float uv[2], 01183 float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */ 01184 float uv1co[2], float uv2co[2], float uv3co[2], 01185 float pixelScreenCo[4], 01186 float w[3]) 01187 { 01188 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); 01189 interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); 01190 } 01191 01192 /* same as screen_px_from_ortho except we need to take into account 01193 * the perspective W coord for each vert */ 01194 static void screen_px_from_persp( 01195 float uv[2], 01196 float v1co[3], float v2co[3], float v3co[3], /* screenspace coords */ 01197 float uv1co[2], float uv2co[2], float uv3co[2], 01198 float pixelScreenCo[4], 01199 float w[3]) 01200 { 01201 01202 float wtot_inv, wtot; 01203 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); 01204 01205 /* re-weight from the 4th coord of each screen vert */ 01206 w[0] *= v1co[3]; 01207 w[1] *= v2co[3]; 01208 w[2] *= v3co[3]; 01209 01210 wtot = w[0]+w[1]+w[2]; 01211 01212 if (wtot > 0.0f) { 01213 wtot_inv = 1.0f / wtot; 01214 w[0] *= wtot_inv; 01215 w[1] *= wtot_inv; 01216 w[2] *= wtot_inv; 01217 } 01218 else { 01219 w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area face */ 01220 } 01221 /* done re-weighting */ 01222 01223 interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); 01224 } 01225 01226 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]) 01227 { 01228 float *uvCo1, *uvCo2, *uvCo3; 01229 float uv_other[2], x, y; 01230 01231 uvCo1 = (float *)tf_other->uv[0]; 01232 if (side==1) { 01233 uvCo2 = (float *)tf_other->uv[2]; 01234 uvCo3 = (float *)tf_other->uv[3]; 01235 } 01236 else { 01237 uvCo2 = (float *)tf_other->uv[1]; 01238 uvCo3 = (float *)tf_other->uv[2]; 01239 } 01240 01241 interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float*)w); 01242 01243 /* use */ 01244 uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y); 01245 01246 01247 if (ibuf_other->rect_float) { /* from float to float */ 01248 bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y); 01249 } 01250 else { /* from char to float */ 01251 bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y); 01252 } 01253 01254 } 01255 01256 /* run this outside project_paint_uvpixel_init since pixels with mask 0 dont need init */ 01257 static float project_paint_uvpixel_mask( 01258 const ProjPaintState *ps, 01259 const int face_index, 01260 const int side, 01261 const float w[3]) 01262 { 01263 float mask; 01264 01265 /* Image Mask */ 01266 if (ps->do_layer_stencil) { 01267 /* another UV layers image is masking this one's */ 01268 ImBuf *ibuf_other; 01269 const MTFace *tf_other = ps->dm_mtface_stencil + face_index; 01270 01271 if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) { 01272 /* BKE_image_get_ibuf - TODO - this may be slow */ 01273 unsigned char rgba_ub[4]; 01274 float rgba_f[4]; 01275 01276 project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f); 01277 01278 if (ibuf_other->rect_float) { /* from float to float */ 01279 mask = ((rgba_f[0]+rgba_f[1]+rgba_f[2])/3.0f) * rgba_f[3]; 01280 } 01281 else { /* from char to float */ 01282 mask = ((rgba_ub[0]+rgba_ub[1]+rgba_ub[2])/(256*3.0f)) * (rgba_ub[3]/256.0f); 01283 } 01284 01285 if (!ps->do_layer_stencil_inv) /* matching the gimps layer mask black/white rules, white==full opacity */ 01286 mask = (1.0f - mask); 01287 01288 if (mask == 0.0f) { 01289 return 0.0f; 01290 } 01291 } 01292 else { 01293 return 0.0f; 01294 } 01295 } else { 01296 mask = 1.0f; 01297 } 01298 01299 /* calculate mask */ 01300 if (ps->do_mask_normal) { 01301 MFace *mf = ps->dm_mface + face_index; 01302 short *no1, *no2, *no3; 01303 float no[3], angle; 01304 no1 = ps->dm_mvert[mf->v1].no; 01305 if (side==1) { 01306 no2 = ps->dm_mvert[mf->v3].no; 01307 no3 = ps->dm_mvert[mf->v4].no; 01308 } 01309 else { 01310 no2 = ps->dm_mvert[mf->v2].no; 01311 no3 = ps->dm_mvert[mf->v3].no; 01312 } 01313 01314 no[0] = w[0]*no1[0] + w[1]*no2[0] + w[2]*no3[0]; 01315 no[1] = w[0]*no1[1] + w[1]*no2[1] + w[2]*no3[1]; 01316 no[2] = w[0]*no1[2] + w[1]*no2[2] + w[2]*no3[2]; 01317 normalize_v3(no); 01318 01319 /* now we can use the normal as a mask */ 01320 if (ps->is_ortho) { 01321 angle = angle_normalized_v3v3((float *)ps->viewDir, no); 01322 } 01323 else { 01324 /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */ 01325 float viewDirPersp[3]; 01326 float *co1, *co2, *co3; 01327 co1 = ps->dm_mvert[mf->v1].co; 01328 if (side==1) { 01329 co2 = ps->dm_mvert[mf->v3].co; 01330 co3 = ps->dm_mvert[mf->v4].co; 01331 } 01332 else { 01333 co2 = ps->dm_mvert[mf->v2].co; 01334 co3 = ps->dm_mvert[mf->v3].co; 01335 } 01336 01337 /* Get the direction from the viewPoint to the pixel and normalize */ 01338 viewDirPersp[0] = (ps->viewPos[0] - (w[0]*co1[0] + w[1]*co2[0] + w[2]*co3[0])); 01339 viewDirPersp[1] = (ps->viewPos[1] - (w[0]*co1[1] + w[1]*co2[1] + w[2]*co3[1])); 01340 viewDirPersp[2] = (ps->viewPos[2] - (w[0]*co1[2] + w[1]*co2[2] + w[2]*co3[2])); 01341 normalize_v3(viewDirPersp); 01342 01343 angle = angle_normalized_v3v3(viewDirPersp, no); 01344 } 01345 01346 if (angle >= ps->normal_angle) { 01347 return 0.0f; /* outsize the normal limit*/ 01348 } 01349 else if (angle > ps->normal_angle_inner) { 01350 mask *= (ps->normal_angle - angle) / ps->normal_angle_range; 01351 } /* otherwise no mask normal is needed, were within the limit */ 01352 } 01353 01354 // This only works when the opacity dosnt change while painting, stylus pressure messes with this 01355 // so dont use it. 01356 // if (ps->is_airbrush==0) mask *= brush_alpha(ps->brush); 01357 01358 return mask; 01359 } 01360 01361 /* run this function when we know a bucket's, face's pixel can be initialized, 01362 * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */ 01363 static ProjPixel *project_paint_uvpixel_init( 01364 const ProjPaintState *ps, 01365 MemArena *arena, 01366 const ImBuf *ibuf, 01367 short x_px, short y_px, 01368 const float mask, 01369 const int face_index, 01370 const int image_index, 01371 const float pixelScreenCo[4], 01372 const int side, 01373 const float w[3]) 01374 { 01375 ProjPixel *projPixel; 01376 short size; 01377 01378 /* wrap pixel location */ 01379 x_px = x_px % ibuf->x; 01380 if (x_px<0) x_px += ibuf->x; 01381 y_px = y_px % ibuf->y; 01382 if (y_px<0) y_px += ibuf->y; 01383 01384 if (ps->tool==PAINT_TOOL_CLONE) { 01385 size = sizeof(ProjPixelClone); 01386 } 01387 else if (ps->tool==PAINT_TOOL_SMEAR) { 01388 size = sizeof(ProjPixelClone); 01389 } 01390 else { 01391 size = sizeof(ProjPixel); 01392 } 01393 01394 projPixel = (ProjPixel *)BLI_memarena_alloc(arena, size); 01395 //memset(projPixel, 0, size); 01396 01397 if (ibuf->rect_float) { 01398 projPixel->pixel.f_pt = (float *)ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4); 01399 projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel->pixel.f_pt[0]; 01400 projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel->pixel.f_pt[1]; 01401 projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel->pixel.f_pt[2]; 01402 projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel->pixel.f_pt[3]; 01403 } 01404 else { 01405 projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4)); 01406 projPixel->origColor.uint = projPixel->newColor.uint = *projPixel->pixel.uint_pt; 01407 } 01408 01409 /* screenspace unclamped, we could keep its z and w values but dont need them at the moment */ 01410 VECCOPY2D(projPixel->projCoSS, pixelScreenCo); 01411 01412 projPixel->x_px = x_px; 01413 projPixel->y_px = y_px; 01414 01415 projPixel->mask = (unsigned short)(mask * 65535); 01416 projPixel->mask_max = 0; 01417 01418 /* which bounding box cell are we in?, needed for undo */ 01419 projPixel->bb_cell_index = ((int)(((float)x_px/(float)ibuf->x) * PROJ_BOUNDBOX_DIV)) + ((int)(((float)y_px/(float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV ; 01420 01421 /* done with view3d_project_float inline */ 01422 if (ps->tool==PAINT_TOOL_CLONE) { 01423 if (ps->dm_mtface_clone) { 01424 ImBuf *ibuf_other; 01425 const MTFace *tf_other = ps->dm_mtface_clone + face_index; 01426 01427 if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) { 01428 /* BKE_image_get_ibuf - TODO - this may be slow */ 01429 01430 if (ibuf->rect_float) { 01431 if (ibuf_other->rect_float) { /* from float to float */ 01432 project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f); 01433 } 01434 else { /* from char to float */ 01435 unsigned char rgba_ub[4]; 01436 project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL); 01437 IMAPAINT_CHAR_RGBA_TO_FLOAT(((ProjPixelClone *)projPixel)->clonepx.f, rgba_ub); 01438 } 01439 } 01440 else { 01441 if (ibuf_other->rect_float) { /* float to char */ 01442 float rgba[4]; 01443 project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba); 01444 IMAPAINT_FLOAT_RGBA_TO_CHAR(((ProjPixelClone *)projPixel)->clonepx.ch, rgba) 01445 } 01446 else { /* char to char */ 01447 project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL); 01448 } 01449 } 01450 } 01451 else { 01452 if (ibuf->rect_float) { 01453 ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; 01454 } 01455 else { 01456 ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; 01457 } 01458 } 01459 01460 } 01461 else { 01462 float co[2]; 01463 sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset); 01464 01465 /* no need to initialize the bucket, we're only checking buckets faces and for this 01466 * the faces are already initialized in project_paint_delayed_face_init(...) */ 01467 if (ibuf->rect_float) { 01468 if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) { 01469 ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */ 01470 } 01471 } 01472 else { 01473 if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) { 01474 ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; /* zero alpha - ignore */ 01475 } 01476 } 01477 } 01478 } 01479 01480 #ifdef PROJ_DEBUG_PAINT 01481 if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0; 01482 else projPixel->pixel.ch_pt[0] = 0; 01483 #endif 01484 projPixel->image_index = image_index; 01485 01486 return projPixel; 01487 } 01488 01489 static int line_clip_rect2f( 01490 rctf *rect, 01491 const float l1[2], const float l2[2], 01492 float l1_clip[2], float l2_clip[2]) 01493 { 01494 /* first account for horizontal, then vertical lines */ 01495 /* horiz */ 01496 if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { 01497 /* is the line out of range on its Y axis? */ 01498 if (l1[1] < rect->ymin || l1[1] > rect->ymax) { 01499 return 0; 01500 } 01501 /* line is out of range on its X axis */ 01502 if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) { 01503 return 0; 01504 } 01505 01506 01507 if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ 01508 if (BLI_in_rctf(rect, l1[0], l1[1])) { 01509 VECCOPY2D(l1_clip, l1); 01510 VECCOPY2D(l2_clip, l2); 01511 return 1; 01512 } 01513 else { 01514 return 0; 01515 } 01516 } 01517 01518 VECCOPY2D(l1_clip, l1); 01519 VECCOPY2D(l2_clip, l2); 01520 CLAMP(l1_clip[0], rect->xmin, rect->xmax); 01521 CLAMP(l2_clip[0], rect->xmin, rect->xmax); 01522 return 1; 01523 } 01524 else if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { 01525 /* is the line out of range on its X axis? */ 01526 if (l1[0] < rect->xmin || l1[0] > rect->xmax) { 01527 return 0; 01528 } 01529 01530 /* line is out of range on its Y axis */ 01531 if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) { 01532 return 0; 01533 } 01534 01535 if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ 01536 if (BLI_in_rctf(rect, l1[0], l1[1])) { 01537 VECCOPY2D(l1_clip, l1); 01538 VECCOPY2D(l2_clip, l2); 01539 return 1; 01540 } 01541 else { 01542 return 0; 01543 } 01544 } 01545 01546 VECCOPY2D(l1_clip, l1); 01547 VECCOPY2D(l2_clip, l2); 01548 CLAMP(l1_clip[1], rect->ymin, rect->ymax); 01549 CLAMP(l2_clip[1], rect->ymin, rect->ymax); 01550 return 1; 01551 } 01552 else { 01553 float isect; 01554 short ok1 = 0; 01555 short ok2 = 0; 01556 01557 /* Done with vertical lines */ 01558 01559 /* are either of the points inside the rectangle ? */ 01560 if (BLI_in_rctf(rect, l1[0], l1[1])) { 01561 VECCOPY2D(l1_clip, l1); 01562 ok1 = 1; 01563 } 01564 01565 if (BLI_in_rctf(rect, l2[0], l2[1])) { 01566 VECCOPY2D(l2_clip, l2); 01567 ok2 = 1; 01568 } 01569 01570 /* line inside rect */ 01571 if (ok1 && ok2) return 1; 01572 01573 /* top/bottom */ 01574 if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) { 01575 if (l1[1] < l2[1]) { /* line 1 is outside */ 01576 l1_clip[0] = isect; 01577 l1_clip[1] = rect->ymin; 01578 ok1 = 1; 01579 } 01580 else { 01581 l2_clip[0] = isect; 01582 l2_clip[1] = rect->ymin; 01583 ok2 = 2; 01584 } 01585 } 01586 01587 if (ok1 && ok2) return 1; 01588 01589 if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) { 01590 if (l1[1] > l2[1]) { /* line 1 is outside */ 01591 l1_clip[0] = isect; 01592 l1_clip[1] = rect->ymax; 01593 ok1 = 1; 01594 } 01595 else { 01596 l2_clip[0] = isect; 01597 l2_clip[1] = rect->ymax; 01598 ok2 = 2; 01599 } 01600 } 01601 01602 if (ok1 && ok2) return 1; 01603 01604 /* left/right */ 01605 if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) { 01606 if (l1[0] < l2[0]) { /* line 1 is outside */ 01607 l1_clip[0] = rect->xmin; 01608 l1_clip[1] = isect; 01609 ok1 = 1; 01610 } 01611 else { 01612 l2_clip[0] = rect->xmin; 01613 l2_clip[1] = isect; 01614 ok2 = 2; 01615 } 01616 } 01617 01618 if (ok1 && ok2) return 1; 01619 01620 if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) { 01621 if (l1[0] > l2[0]) { /* line 1 is outside */ 01622 l1_clip[0] = rect->xmax; 01623 l1_clip[1] = isect; 01624 ok1 = 1; 01625 } 01626 else { 01627 l2_clip[0] = rect->xmax; 01628 l2_clip[1] = isect; 01629 ok2 = 2; 01630 } 01631 } 01632 01633 if (ok1 && ok2) { 01634 return 1; 01635 } 01636 else { 01637 return 0; 01638 } 01639 } 01640 } 01641 01642 01643 01644 /* scale the quad & tri about its center 01645 * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the 01646 * edge of the face but slightly inside it occlusion tests dont return hits on adjacent faces */ 01647 #ifndef PROJ_DEBUG_NOSEAMBLEED 01648 static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset) 01649 { 01650 float cent[3]; 01651 cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0f; 01652 cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f; 01653 cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f; 01654 01655 sub_v3_v3v3(insetCos[0], origCos[0], cent); 01656 sub_v3_v3v3(insetCos[1], origCos[1], cent); 01657 sub_v3_v3v3(insetCos[2], origCos[2], cent); 01658 sub_v3_v3v3(insetCos[3], origCos[3], cent); 01659 01660 mul_v3_fl(insetCos[0], inset); 01661 mul_v3_fl(insetCos[1], inset); 01662 mul_v3_fl(insetCos[2], inset); 01663 mul_v3_fl(insetCos[3], inset); 01664 01665 add_v3_v3(insetCos[0], cent); 01666 add_v3_v3(insetCos[1], cent); 01667 add_v3_v3(insetCos[2], cent); 01668 add_v3_v3(insetCos[3], cent); 01669 } 01670 01671 01672 static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset) 01673 { 01674 float cent[3]; 01675 cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f; 01676 cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f; 01677 cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f; 01678 01679 sub_v3_v3v3(insetCos[0], origCos[0], cent); 01680 sub_v3_v3v3(insetCos[1], origCos[1], cent); 01681 sub_v3_v3v3(insetCos[2], origCos[2], cent); 01682 01683 mul_v3_fl(insetCos[0], inset); 01684 mul_v3_fl(insetCos[1], inset); 01685 mul_v3_fl(insetCos[2], inset); 01686 01687 add_v3_v3(insetCos[0], cent); 01688 add_v3_v3(insetCos[1], cent); 01689 add_v3_v3(insetCos[2], cent); 01690 } 01691 #endif //PROJ_DEBUG_NOSEAMBLEED 01692 01693 static float Vec2Lenf_nosqrt(const float *v1, const float *v2) 01694 { 01695 float x, y; 01696 01697 x = v1[0]-v2[0]; 01698 y = v1[1]-v2[1]; 01699 return x*x+y*y; 01700 } 01701 01702 static float Vec2Lenf_nosqrt_other(const float *v1, const float v2_1, const float v2_2) 01703 { 01704 float x, y; 01705 01706 x = v1[0]-v2_1; 01707 y = v1[1]-v2_2; 01708 return x*x+y*y; 01709 } 01710 01711 /* note, use a squared value so we can use Vec2Lenf_nosqrt 01712 * be sure that you have done a bounds check first or this may fail */ 01713 /* only give bucket_bounds as an arg because we need it elsewhere */ 01714 static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds) 01715 { 01716 01717 /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect 01718 * so we only need to test if the center is inside the vertical or horizontal bounds on either axis, 01719 * this is even less work then an intersection test 01720 * 01721 if (BLI_in_rctf(bucket_bounds, cent[0], cent[1])) 01722 return 1; 01723 */ 01724 01725 if((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) || (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1]) ) { 01726 return 1; 01727 } 01728 01729 /* out of bounds left */ 01730 if (cent[0] < bucket_bounds->xmin) { 01731 /* lower left out of radius test */ 01732 if (cent[1] < bucket_bounds->ymin) { 01733 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0; 01734 } 01735 /* top left test */ 01736 else if (cent[1] > bucket_bounds->ymax) { 01737 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0; 01738 } 01739 } 01740 else if (cent[0] > bucket_bounds->xmax) { 01741 /* lower right out of radius test */ 01742 if (cent[1] < bucket_bounds->ymin) { 01743 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0; 01744 } 01745 /* top right test */ 01746 else if (cent[1] > bucket_bounds->ymax) { 01747 return (Vec2Lenf_nosqrt_other(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0; 01748 } 01749 } 01750 01751 return 0; 01752 } 01753 01754 01755 01756 /* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp() 01757 * in ortho view this function gives good results when bucket_bounds are outside the triangle 01758 * however in some cases, perspective view will mess up with faces that have minimal screenspace area (viewed from the side) 01759 * 01760 * for this reason its not relyable in this case so we'll use the Simple Barycentric' funcs that only account for points inside the triangle. 01761 * however switching back to this for ortho is always an option */ 01762 01763 static void rect_to_uvspace_ortho( 01764 rctf *bucket_bounds, 01765 float *v1coSS, float *v2coSS, float *v3coSS, 01766 float *uv1co, float *uv2co, float *uv3co, 01767 float bucket_bounds_uv[4][2], 01768 const int flip) 01769 { 01770 float uv[2]; 01771 float w[3]; 01772 01773 /* get the UV space bounding box */ 01774 uv[0] = bucket_bounds->xmax; 01775 uv[1] = bucket_bounds->ymin; 01776 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); 01777 interp_v2_v2v2v2(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); 01778 01779 //uv[0] = bucket_bounds->xmax; // set above 01780 uv[1] = bucket_bounds->ymax; 01781 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); 01782 interp_v2_v2v2v2(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); 01783 01784 uv[0] = bucket_bounds->xmin; 01785 //uv[1] = bucket_bounds->ymax; // set above 01786 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); 01787 interp_v2_v2v2v2(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); 01788 01789 //uv[0] = bucket_bounds->xmin; // set above 01790 uv[1] = bucket_bounds->ymin; 01791 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); 01792 interp_v2_v2v2v2(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); 01793 } 01794 01795 /* same as above but use barycentric_weights_v2_persp */ 01796 static void rect_to_uvspace_persp( 01797 rctf *bucket_bounds, 01798 float *v1coSS, float *v2coSS, float *v3coSS, 01799 float *uv1co, float *uv2co, float *uv3co, 01800 float bucket_bounds_uv[4][2], 01801 const int flip 01802 ) 01803 { 01804 float uv[2]; 01805 float w[3]; 01806 01807 /* get the UV space bounding box */ 01808 uv[0] = bucket_bounds->xmax; 01809 uv[1] = bucket_bounds->ymin; 01810 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); 01811 interp_v2_v2v2v2(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); 01812 01813 //uv[0] = bucket_bounds->xmax; // set above 01814 uv[1] = bucket_bounds->ymax; 01815 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); 01816 interp_v2_v2v2v2(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); 01817 01818 uv[0] = bucket_bounds->xmin; 01819 //uv[1] = bucket_bounds->ymax; // set above 01820 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); 01821 interp_v2_v2v2v2(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); 01822 01823 //uv[0] = bucket_bounds->xmin; // set above 01824 uv[1] = bucket_bounds->ymin; 01825 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); 01826 interp_v2_v2v2v2(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); 01827 } 01828 01829 /* This works as we need it to but we can save a few steps and not use it */ 01830 01831 #if 0 01832 static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2]) 01833 { 01834 float v1[2], v2[2]; 01835 01836 v1[0] = p1[0]-p2[0]; v1[1] = p1[1]-p2[1]; 01837 v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; 01838 01839 return -atan2(v1[0]*v2[1] - v1[1]*v2[0], v1[0]*v2[0]+v1[1]*v2[1]); 01840 } 01841 #endif 01842 01843 #define ISECT_1 (1) 01844 #define ISECT_2 (1<<1) 01845 #define ISECT_3 (1<<2) 01846 #define ISECT_4 (1<<3) 01847 #define ISECT_ALL3 ((1<<3)-1) 01848 #define ISECT_ALL4 ((1<<4)-1) 01849 01850 /* limit must be a fraction over 1.0f */ 01851 static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit) 01852 { 01853 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; 01854 } 01855 01856 /* Clip the face by a bucket and set the uv-space bucket_bounds_uv 01857 * so we have the clipped UV's to do pixel intersection tests with 01858 * */ 01859 static int float_z_sort_flip(const void *p1, const void *p2) { 01860 return (((float *)p1)[2] < ((float *)p2)[2] ? 1:-1); 01861 } 01862 01863 static int float_z_sort(const void *p1, const void *p2) { 01864 return (((float *)p1)[2] < ((float *)p2)[2] ?-1:1); 01865 } 01866 01867 static void project_bucket_clip_face( 01868 const int is_ortho, 01869 rctf *bucket_bounds, 01870 float *v1coSS, float *v2coSS, float *v3coSS, 01871 float *uv1co, float *uv2co, float *uv3co, 01872 float bucket_bounds_uv[8][2], 01873 int *tot) 01874 { 01875 int inside_bucket_flag = 0; 01876 int inside_face_flag = 0; 01877 const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); 01878 01879 float bucket_bounds_ss[4][2]; 01880 01881 /* get the UV space bounding box */ 01882 inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v1coSS[0], v1coSS[1]); 01883 inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v2coSS[0], v2coSS[1]) << 1; 01884 inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v3coSS[0], v3coSS[1]) << 2; 01885 01886 if (inside_bucket_flag == ISECT_ALL3) { 01887 /* all screenspace points are inside the bucket bounding box, this means we dont need to clip and can simply return the UVs */ 01888 if (flip) { /* facing the back? */ 01889 VECCOPY2D(bucket_bounds_uv[0], uv3co); 01890 VECCOPY2D(bucket_bounds_uv[1], uv2co); 01891 VECCOPY2D(bucket_bounds_uv[2], uv1co); 01892 } 01893 else { 01894 VECCOPY2D(bucket_bounds_uv[0], uv1co); 01895 VECCOPY2D(bucket_bounds_uv[1], uv2co); 01896 VECCOPY2D(bucket_bounds_uv[2], uv3co); 01897 } 01898 01899 *tot = 3; 01900 return; 01901 } 01902 01903 /* get the UV space bounding box */ 01904 /* use IsectPT2Df_limit here so we catch points are are touching the tri edge (or a small fraction over) */ 01905 bucket_bounds_ss[0][0] = bucket_bounds->xmax; 01906 bucket_bounds_ss[0][1] = bucket_bounds->ymin; 01907 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0); 01908 01909 bucket_bounds_ss[1][0] = bucket_bounds->xmax; 01910 bucket_bounds_ss[1][1] = bucket_bounds->ymax; 01911 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0); 01912 01913 bucket_bounds_ss[2][0] = bucket_bounds->xmin; 01914 bucket_bounds_ss[2][1] = bucket_bounds->ymax; 01915 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0); 01916 01917 bucket_bounds_ss[3][0] = bucket_bounds->xmin; 01918 bucket_bounds_ss[3][1] = bucket_bounds->ymin; 01919 inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1+PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0); 01920 01921 if (inside_face_flag == ISECT_ALL4) { 01922 /* bucket is totally inside the screenspace face, we can safely use weights */ 01923 01924 if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); 01925 else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); 01926 01927 *tot = 4; 01928 return; 01929 } 01930 else { 01931 /* The Complicated Case! 01932 * 01933 * The 2 cases above are where the face is inside the bucket or the bucket is inside the face. 01934 * 01935 * we need to make a convex polyline from the intersection between the screenspace face 01936 * and the bucket bounds. 01937 * 01938 * There are a number of ways this could be done, currently it just collects all intersecting verts, 01939 * and line intersections, then sorts them clockwise, this is a lot easier then evaluating the geometry to 01940 * do a correct clipping on both shapes. */ 01941 01942 01943 /* add a bunch of points, we know must make up the convex hull which is the clipped rect and triangle */ 01944 01945 01946 01947 /* Maximum possible 6 intersections when using a rectangle and triangle */ 01948 float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */ 01949 float v1_clipSS[2], v2_clipSS[2]; 01950 float w[3]; 01951 01952 /* calc center*/ 01953 float cent[2] = {0.0f, 0.0f}; 01954 /*float up[2] = {0.0f, 1.0f};*/ 01955 int i; 01956 short doubles; 01957 01958 (*tot) = 0; 01959 01960 if (inside_face_flag & ISECT_1) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; } 01961 if (inside_face_flag & ISECT_2) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; } 01962 if (inside_face_flag & ISECT_3) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; } 01963 if (inside_face_flag & ISECT_4) { VECCOPY2D(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; } 01964 01965 if (inside_bucket_flag & ISECT_1) { VECCOPY2D(isectVCosSS[*tot], v1coSS); (*tot)++; } 01966 if (inside_bucket_flag & ISECT_2) { VECCOPY2D(isectVCosSS[*tot], v2coSS); (*tot)++; } 01967 if (inside_bucket_flag & ISECT_3) { VECCOPY2D(isectVCosSS[*tot], v3coSS); (*tot)++; } 01968 01969 if ((inside_bucket_flag & (ISECT_1|ISECT_2)) != (ISECT_1|ISECT_2)) { 01970 if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) { 01971 if ((inside_bucket_flag & ISECT_1)==0) { VECCOPY2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; } 01972 if ((inside_bucket_flag & ISECT_2)==0) { VECCOPY2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; } 01973 } 01974 } 01975 01976 if ((inside_bucket_flag & (ISECT_2|ISECT_3)) != (ISECT_2|ISECT_3)) { 01977 if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) { 01978 if ((inside_bucket_flag & ISECT_2)==0) { VECCOPY2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; } 01979 if ((inside_bucket_flag & ISECT_3)==0) { VECCOPY2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; } 01980 } 01981 } 01982 01983 if ((inside_bucket_flag & (ISECT_3|ISECT_1)) != (ISECT_3|ISECT_1)) { 01984 if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) { 01985 if ((inside_bucket_flag & ISECT_3)==0) { VECCOPY2D(isectVCosSS[*tot], v1_clipSS); (*tot)++; } 01986 if ((inside_bucket_flag & ISECT_1)==0) { VECCOPY2D(isectVCosSS[*tot], v2_clipSS); (*tot)++; } 01987 } 01988 } 01989 01990 01991 if ((*tot) < 3) { /* no intersections to speak of */ 01992 *tot = 0; 01993 return; 01994 } 01995 01996 /* now we have all points we need, collect their angles and sort them clockwise */ 01997 01998 for(i=0; i<(*tot); i++) { 01999 cent[0] += isectVCosSS[i][0]; 02000 cent[1] += isectVCosSS[i][1]; 02001 } 02002 cent[0] = cent[0] / (float)(*tot); 02003 cent[1] = cent[1] / (float)(*tot); 02004 02005 02006 02007 /* Collect angles for every point around the center point */ 02008 02009 02010 #if 0 /* uses a few more cycles then the above loop */ 02011 for(i=0; i<(*tot); i++) { 02012 isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]); 02013 } 02014 #endif 02015 02016 v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */ 02017 v1_clipSS[1] = cent[1] + 1.0f; 02018 02019 for(i=0; i<(*tot); i++) { 02020 v2_clipSS[0] = isectVCosSS[i][0] - cent[0]; 02021 v2_clipSS[1] = isectVCosSS[i][1] - cent[1]; 02022 isectVCosSS[i][2] = atan2f(v1_clipSS[0]*v2_clipSS[1] - v1_clipSS[1]*v2_clipSS[0], v1_clipSS[0]*v2_clipSS[0]+v1_clipSS[1]*v2_clipSS[1]); 02023 } 02024 02025 if (flip) qsort(isectVCosSS, *tot, sizeof(float)*3, float_z_sort_flip); 02026 else qsort(isectVCosSS, *tot, sizeof(float)*3, float_z_sort); 02027 02028 /* remove doubles */ 02029 /* first/last check */ 02030 if (fabsf(isectVCosSS[0][0]-isectVCosSS[(*tot)-1][0]) < PROJ_GEOM_TOLERANCE && fabsf(isectVCosSS[0][1]-isectVCosSS[(*tot)-1][1]) < PROJ_GEOM_TOLERANCE) { 02031 (*tot)--; 02032 } 02033 02034 /* its possible there is only a few left after remove doubles */ 02035 if ((*tot) < 3) { 02036 // printf("removed too many doubles A\n"); 02037 *tot = 0; 02038 return; 02039 } 02040 02041 doubles = TRUE; 02042 while (doubles==TRUE) { 02043 doubles = FALSE; 02044 for(i=1; i<(*tot); i++) { 02045 if (fabsf(isectVCosSS[i-1][0]-isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE && 02046 fabsf(isectVCosSS[i-1][1]-isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE) 02047 { 02048 int j; 02049 for(j=i+1; j<(*tot); j++) { 02050 isectVCosSS[j-1][0] = isectVCosSS[j][0]; 02051 isectVCosSS[j-1][1] = isectVCosSS[j][1]; 02052 } 02053 doubles = TRUE; /* keep looking for more doubles */ 02054 (*tot)--; 02055 } 02056 } 02057 } 02058 02059 /* its possible there is only a few left after remove doubles */ 02060 if ((*tot) < 3) { 02061 // printf("removed too many doubles B\n"); 02062 *tot = 0; 02063 return; 02064 } 02065 02066 02067 if (is_ortho) { 02068 for(i=0; i<(*tot); i++) { 02069 barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); 02070 interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); 02071 } 02072 } 02073 else { 02074 for(i=0; i<(*tot); i++) { 02075 barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); 02076 interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); 02077 } 02078 } 02079 } 02080 02081 #ifdef PROJ_DEBUG_PRINT_CLIP 02082 /* include this at the bottom of the above function to debug the output */ 02083 02084 { 02085 /* If there are ever any problems, */ 02086 float test_uv[4][2]; 02087 int i; 02088 if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); 02089 else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); 02090 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]); 02091 02092 printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]); 02093 02094 printf("["); 02095 for (i=0; i < (*tot); i++) { 02096 printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]); 02097 } 02098 printf("]),\\\n"); 02099 } 02100 #endif 02101 } 02102 02103 /* 02104 # This script creates faces in a blender scene from printed data above. 02105 02106 project_ls = [ 02107 ...(output from above block)... 02108 ] 02109 02110 from Blender import Scene, Mesh, Window, sys, Mathutils 02111 02112 import bpy 02113 02114 V = Mathutils.Vector 02115 02116 def main(): 02117 sce = bpy.data.scenes.active 02118 02119 for item in project_ls: 02120 bb = item[0] 02121 uv = item[1] 02122 poly = item[2] 02123 02124 me = bpy.data.meshes.new() 02125 ob = sce.objects.new(me) 02126 02127 me.verts.extend([V(bb[0]).resize3D(), V(bb[1]).resize3D(), V(bb[2]).resize3D(), V(bb[3]).resize3D()]) 02128 me.faces.extend([(0,1,2,3),]) 02129 me.verts.extend([V(uv[0]).resize3D(), V(uv[1]).resize3D(), V(uv[2]).resize3D()]) 02130 me.faces.extend([(4,5,6),]) 02131 02132 vs = [V(p).resize3D() for p in poly] 02133 print len(vs) 02134 l = len(me.verts) 02135 me.verts.extend(vs) 02136 02137 i = l 02138 while i < len(me.verts): 02139 ii = i+1 02140 if ii==len(me.verts): 02141 ii = l 02142 me.edges.extend([i, ii]) 02143 i+=1 02144 02145 if __name__ == '__main__': 02146 main() 02147 */ 02148 02149 02150 #undef ISECT_1 02151 #undef ISECT_2 02152 #undef ISECT_3 02153 #undef ISECT_4 02154 #undef ISECT_ALL3 02155 #undef ISECT_ALL4 02156 02157 02158 /* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise 02159 * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */ 02160 static int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) 02161 { 02162 int i; 02163 if (line_point_side_v2(uv[tot-1], uv[0], pt) < 0.0f) 02164 return 0; 02165 02166 for (i=1; i<tot; i++) { 02167 if (line_point_side_v2(uv[i-1], uv[i], pt) < 0.0f) 02168 return 0; 02169 02170 } 02171 02172 return 1; 02173 } 02174 static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot) 02175 { 02176 int i; 02177 int side = (line_point_side_v2(uv[tot-1], uv[0], pt) > 0.0f); 02178 02179 for (i=1; i<tot; i++) { 02180 if ((line_point_side_v2(uv[i-1], uv[i], pt) > 0.0f) != side) 02181 return 0; 02182 02183 } 02184 02185 return 1; 02186 } 02187 02188 /* One of the most important function for projectiopn painting, since it selects the pixels to be added into each bucket. 02189 * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */ 02190 static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v) 02191 { 02192 /* Projection vars, to get the 3D locations into screen space */ 02193 MemArena *arena = ps->arena_mt[thread_index]; 02194 LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index; 02195 LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index]; 02196 02197 const MFace *mf = ps->dm_mface + face_index; 02198 const MTFace *tf = ps->dm_mtface + face_index; 02199 02200 /* UV/pixel seeking data */ 02201 int x; /* Image X-Pixel */ 02202 int y;/* Image Y-Pixel */ 02203 float mask; 02204 float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */ 02205 02206 int side; 02207 float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */ 02208 02209 float *vCo[4]; /* vertex screenspace coords */ 02210 02211 float w[3], wco[3]; 02212 02213 float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */ 02214 float pixelScreenCo[4]; 02215 02216 rcti bounds_px; /* ispace bounds */ 02217 /* vars for getting uvspace bounds */ 02218 02219 float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */ 02220 float xhalfpx, yhalfpx; 02221 const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y; 02222 02223 int has_x_isect = 0, has_isect = 0; /* for early loop exit */ 02224 02225 int i1, i2, i3; 02226 02227 float uv_clip[8][2]; 02228 int uv_clip_tot; 02229 const short is_ortho = ps->is_ortho; 02230 const short do_backfacecull = ps->do_backfacecull; 02231 const short do_clip= ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; 02232 02233 vCo[0] = ps->dm_mvert[mf->v1].co; 02234 vCo[1] = ps->dm_mvert[mf->v2].co; 02235 vCo[2] = ps->dm_mvert[mf->v3].co; 02236 02237 02238 /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel 02239 * this is done so we can avoid offseting all the pixels by 0.5 which causes 02240 * problems when wrapping negative coords */ 02241 xhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/3.0f) ) / ibuf_xf; 02242 yhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/4.0f) ) / ibuf_yf; 02243 02244 /* Note about (PROJ_GEOM_TOLERANCE/x) above... 02245 Needed to add this offset since UV coords are often quads aligned to pixels. 02246 In this case pixels can be exactly between 2 triangles causing nasty 02247 artifacts. 02248 02249 This workaround can be removed and painting will still work on most cases 02250 but since the first thing most people try is painting onto a quad- better make it work. 02251 */ 02252 02253 02254 02255 tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx; 02256 tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx; 02257 02258 tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx; 02259 tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx; 02260 02261 tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx; 02262 tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx; 02263 02264 if (mf->v4) { 02265 vCo[3] = ps->dm_mvert[ mf->v4 ].co; 02266 02267 tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx; 02268 tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx; 02269 side = 1; 02270 } 02271 else { 02272 side = 0; 02273 } 02274 02275 do { 02276 if (side==1) { 02277 i1=0; i2=2; i3=3; 02278 } 02279 else { 02280 i1=0; i2=1; i3=2; 02281 } 02282 02283 uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1]; 02284 uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2]; 02285 uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3]; 02286 02287 v1coSS = ps->screenCoords[ (*(&mf->v1 + i1)) ]; 02288 v2coSS = ps->screenCoords[ (*(&mf->v1 + i2)) ]; 02289 v3coSS = ps->screenCoords[ (*(&mf->v1 + i3)) ]; 02290 02291 /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/ 02292 project_bucket_clip_face( 02293 is_ortho, bucket_bounds, 02294 v1coSS, v2coSS, v3coSS, 02295 uv1co, uv2co, uv3co, 02296 uv_clip, &uv_clip_tot 02297 ); 02298 02299 /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */ 02300 /* 02301 if (uv_clip_tot>6) { 02302 printf("this should never happen! %d\n", uv_clip_tot); 02303 }*/ 02304 02305 02306 if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) { 02307 02308 if(clamp_u) { 02309 CLAMP(bounds_px.xmin, 0, ibuf->x); 02310 CLAMP(bounds_px.xmax, 0, ibuf->x); 02311 } 02312 02313 if(clamp_v) { 02314 CLAMP(bounds_px.ymin, 0, ibuf->y); 02315 CLAMP(bounds_px.ymax, 0, ibuf->y); 02316 } 02317 02318 /* clip face and */ 02319 02320 has_isect = 0; 02321 for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { 02322 //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; 02323 uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */ 02324 02325 has_x_isect = 0; 02326 for (x = bounds_px.xmin; x < bounds_px.xmax; x++) { 02327 //uv[0] = (((float)x) + 0.5f) / ibuf->x; 02328 uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */ 02329 02330 /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work, 02331 * could check the poly direction but better to do this */ 02332 if( (do_backfacecull && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) || 02333 (do_backfacecull==0 && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) { 02334 02335 has_x_isect = has_isect = 1; 02336 02337 if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); 02338 else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); 02339 02340 /* a pitty we need to get the worldspace pixel location here */ 02341 if(do_clip) { 02342 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); 02343 if(ED_view3d_test_clipping(ps->rv3d, wco, 1)) { 02344 continue; /* Watch out that no code below this needs to run */ 02345 } 02346 } 02347 02348 /* Is this UV visible from the view? - raytrace */ 02349 /* project_paint_PickFace is less complex, use for testing */ 02350 //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) { 02351 if (ps->do_occlude==0 || !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) { 02352 02353 mask = project_paint_uvpixel_mask(ps, face_index, side, w); 02354 02355 if (mask > 0.0f) { 02356 BLI_linklist_prepend_arena( 02357 bucketPixelNodes, 02358 project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w), 02359 arena 02360 ); 02361 } 02362 } 02363 02364 } 02365 //#if 0 02366 else if (has_x_isect) { 02367 /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ 02368 break; 02369 } 02370 //#endif 02371 } 02372 02373 02374 #if 0 /* TODO - investigate why this dosnt work sometimes! it should! */ 02375 /* no intersection for this entire row, after some intersection above means we can quit now */ 02376 if (has_x_isect==0 && has_isect) { 02377 break; 02378 } 02379 #endif 02380 } 02381 } 02382 } while(side--); 02383 02384 02385 02386 #ifndef PROJ_DEBUG_NOSEAMBLEED 02387 if (ps->seam_bleed_px > 0.0f) { 02388 int face_seam_flag; 02389 02390 if (ps->thread_tot > 1) 02391 BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ 02392 02393 face_seam_flag = ps->faceSeamFlags[face_index]; 02394 02395 /* are any of our edges un-initialized? */ 02396 if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 || 02397 (face_seam_flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==0 || 02398 (face_seam_flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==0 || 02399 (face_seam_flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==0 02400 ) { 02401 project_face_seams_init(ps, face_index, mf->v4); 02402 face_seam_flag = ps->faceSeamFlags[face_index]; 02403 //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4); 02404 } 02405 02406 if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4))==0) { 02407 02408 if (ps->thread_tot > 1) 02409 BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ 02410 02411 } 02412 else { 02413 /* we have a seam - deal with it! */ 02414 02415 /* Now create new UV's for the seam face */ 02416 float (*outset_uv)[2] = ps->faceSeamUVs[face_index]; 02417 float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */ 02418 02419 float fac; 02420 float *vCoSS[4]; /* vertex screenspace coords */ 02421 02422 float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */ 02423 float edge_verts_inset_clip[2][3]; 02424 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 */ 02425 02426 float seam_subsection[4][2]; 02427 float fac1, fac2, ftot; 02428 02429 02430 if (outset_uv[0][0]==FLT_MAX) /* first time initialize */ 02431 uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4); 02432 02433 /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */ 02434 if (ps->thread_tot > 1) 02435 BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ 02436 02437 vCoSS[0] = ps->screenCoords[mf->v1]; 02438 vCoSS[1] = ps->screenCoords[mf->v2]; 02439 vCoSS[2] = ps->screenCoords[mf->v3]; 02440 if (mf->v4) 02441 vCoSS[3] = ps->screenCoords[ mf->v4 ]; 02442 02443 /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */ 02444 if (is_ortho) { 02445 if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM); 02446 else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM); 02447 } 02448 else { 02449 if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM); 02450 else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM); 02451 } 02452 02453 side = 0; /* for triangles this wont need to change */ 02454 02455 for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) { 02456 if (mf->v4) fidx2 = (fidx1==3) ? 0 : fidx1+1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */ 02457 else fidx2 = (fidx1==2) ? 0 : fidx1+1; /* next fidx in the face (0,1,2) -> (1,2,0) */ 02458 02459 if ( (face_seam_flag & (1<<fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */ 02460 line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]) 02461 ) { 02462 02463 ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */ 02464 02465 if (ftot > 0.0f) { /* avoid div by zero */ 02466 if (mf->v4) { 02467 if (fidx1==2 || fidx2==2) side= 1; 02468 else side= 0; 02469 } 02470 02471 fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot; 02472 fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot; 02473 02474 interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1); 02475 interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2); 02476 02477 interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2); 02478 interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1); 02479 02480 /* if the bucket_clip_edges values Z values was kept we could avoid this 02481 * Inset needs to be added so occlusion tests wont hit adjacent faces */ 02482 interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1); 02483 interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2); 02484 02485 02486 if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) { 02487 /* bounds between the seam rect and the uvspace bucket pixels */ 02488 02489 has_isect = 0; 02490 for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { 02491 // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; 02492 uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */ 02493 02494 has_x_isect = 0; 02495 for (x = bounds_px.xmin; x < bounds_px.xmax; x++) { 02496 //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x; 02497 uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */ 02498 02499 /* test we're inside uvspace bucket and triangle bounds */ 02500 if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) { 02501 02502 /* We need to find the closest point along the face edge, 02503 * getting the screen_px_from_*** wont work because our actual location 02504 * is not relevent, since we are outside the face, Use VecLerpf to find 02505 * our location on the side of the face's UV */ 02506 /* 02507 if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo); 02508 else screen_px_from_persp(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo); 02509 */ 02510 02511 /* Since this is a seam we need to work out where on the line this pixel is */ 02512 //fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]); 02513 02514 fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]); 02515 if (fac < 0.0f) { VECCOPY(pixelScreenCo, edge_verts_inset_clip[0]); } 02516 else if (fac > 1.0f) { VECCOPY(pixelScreenCo, edge_verts_inset_clip[1]); } 02517 else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); } 02518 02519 if (!is_ortho) { 02520 pixelScreenCo[3] = 1.0f; 02521 mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */ 02522 pixelScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*pixelScreenCo[0]/pixelScreenCo[3]; 02523 pixelScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*pixelScreenCo[1]/pixelScreenCo[3]; 02524 pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */ 02525 } 02526 02527 if (ps->do_occlude==0 || !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) { 02528 02529 /* Only bother calculating the weights if we intersect */ 02530 if (ps->do_mask_normal || ps->dm_mtface_clone) { 02531 #if 1 02532 /* get the UV on the line since we want to copy the pixels from there for bleeding */ 02533 float uv_close[2]; 02534 float fac= closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]); 02535 if (fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]); 02536 else if (fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]); 02537 02538 if (side) { 02539 barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w); 02540 } 02541 else { 02542 barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w); 02543 } 02544 #else /* this is buggy with quads, dont use for now */ 02545 02546 /* Cheat, we know where we are along the edge so work out the weights from that */ 02547 fac = fac1 + (fac * (fac2-fac1)); 02548 02549 w[0]=w[1]=w[2]= 0.0; 02550 if (side) { 02551 w[fidx1?fidx1-1:0] = 1.0f-fac; 02552 w[fidx2?fidx2-1:0] = fac; 02553 } 02554 else { 02555 w[fidx1] = 1.0f-fac; 02556 w[fidx2] = fac; 02557 } 02558 #endif 02559 } 02560 02561 /* a pitty we need to get the worldspace pixel location here */ 02562 if(do_clip) { 02563 if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); 02564 else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); 02565 02566 if(ED_view3d_test_clipping(ps->rv3d, wco, 1)) { 02567 continue; /* Watch out that no code below this needs to run */ 02568 } 02569 } 02570 02571 mask = project_paint_uvpixel_mask(ps, face_index, side, w); 02572 02573 if (mask > 0.0f) { 02574 BLI_linklist_prepend_arena( 02575 bucketPixelNodes, 02576 project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w), 02577 arena 02578 ); 02579 } 02580 02581 } 02582 } 02583 else if (has_x_isect) { 02584 /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ 02585 break; 02586 } 02587 } 02588 02589 #if 0 /* TODO - investigate why this dosnt work sometimes! it should! */ 02590 /* no intersection for this entire row, after some intersection above means we can quit now */ 02591 if (has_x_isect==0 && has_isect) { 02592 break; 02593 } 02594 #endif 02595 } 02596 } 02597 } 02598 } 02599 } 02600 } 02601 } 02602 #endif // PROJ_DEBUG_NOSEAMBLEED 02603 } 02604 02605 02606 /* takes floating point screenspace min/max and returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags */ 02607 static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2]) 02608 { 02609 /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */ 02610 /* 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 */ 02611 bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */ 02612 bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f); 02613 02614 bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f); 02615 bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f); 02616 02617 /* incase the rect is outside the mesh 2d bounds */ 02618 CLAMP(bucketMin[0], 0, ps->buckets_x); 02619 CLAMP(bucketMin[1], 0, ps->buckets_y); 02620 02621 CLAMP(bucketMax[0], 0, ps->buckets_x); 02622 CLAMP(bucketMax[1], 0, ps->buckets_y); 02623 } 02624 02625 /* set bucket_bounds to a screen space-aligned floating point bound-box */ 02626 static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds) 02627 { 02628 bucket_bounds->xmin = ps->screenMin[0]+((bucket_x)*(ps->screen_width / ps->buckets_x)); /* left */ 02629 bucket_bounds->xmax = ps->screenMin[0]+((bucket_x+1)*(ps->screen_width / ps->buckets_x)); /* right */ 02630 02631 bucket_bounds->ymin = ps->screenMin[1]+((bucket_y)*(ps->screen_height / ps->buckets_y)); /* bottom */ 02632 bucket_bounds->ymax = ps->screenMin[1]+((bucket_y+1)*(ps->screen_height / ps->buckets_y)); /* top */ 02633 } 02634 02635 /* Fill this bucket with pixels from the faces that intersect it. 02636 * 02637 * have bucket_bounds as an argument so we don;t need to give bucket_x/y the rect function needs */ 02638 static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds) 02639 { 02640 LinkNode *node; 02641 int face_index, image_index=0; 02642 ImBuf *ibuf = NULL; 02643 Image *ima = NULL; 02644 MTFace *tf; 02645 02646 Image *tpage_last = NULL; 02647 02648 02649 if (ps->image_tot==1) { 02650 /* Simple loop, no context switching */ 02651 ibuf = ps->projImages[0].ibuf; 02652 ima = ps->projImages[0].ima; 02653 02654 for (node = ps->bucketFaces[bucket_index]; node; node= node->next) { 02655 project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); 02656 } 02657 } 02658 else { 02659 02660 /* More complicated loop, switch between images */ 02661 for (node = ps->bucketFaces[bucket_index]; node; node= node->next) { 02662 face_index = GET_INT_FROM_POINTER(node->link); 02663 02664 /* Image context switching */ 02665 tf = ps->dm_mtface+face_index; 02666 if (tpage_last != tf->tpage) { 02667 tpage_last = tf->tpage; 02668 02669 image_index = -1; /* sanity check */ 02670 02671 for (image_index=0; image_index < ps->image_tot; image_index++) { 02672 if (ps->projImages[image_index].ima == tpage_last) { 02673 ibuf = ps->projImages[image_index].ibuf; 02674 ima = ps->projImages[image_index].ima; 02675 break; 02676 } 02677 } 02678 } 02679 /* context switching done */ 02680 02681 project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); 02682 } 02683 } 02684 02685 ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT; 02686 } 02687 02688 02689 /* We want to know if a bucket and a face overlap in screen-space 02690 * 02691 * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels 02692 * calculated when it might not be needed later, (at the moment at least) 02693 * obviously it shouldn't have bugs though */ 02694 02695 static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf) 02696 { 02697 /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */ 02698 rctf bucket_bounds; 02699 float p1[2], p2[2], p3[2], p4[2]; 02700 float *v, *v1,*v2,*v3,*v4=NULL; 02701 int fidx; 02702 02703 project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds); 02704 02705 /* Is one of the faces verts in the bucket bounds? */ 02706 02707 fidx = mf->v4 ? 3:2; 02708 do { 02709 v = ps->screenCoords[ (*(&mf->v1 + fidx)) ]; 02710 if (BLI_in_rctf(&bucket_bounds, v[0], v[1])) { 02711 return 1; 02712 } 02713 } while (fidx--); 02714 02715 v1 = ps->screenCoords[mf->v1]; 02716 v2 = ps->screenCoords[mf->v2]; 02717 v3 = ps->screenCoords[mf->v3]; 02718 if (mf->v4) { 02719 v4 = ps->screenCoords[mf->v4]; 02720 } 02721 02722 p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin; 02723 p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax; 02724 p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax; 02725 p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin; 02726 02727 if (mf->v4) { 02728 if( isect_point_quad_v2(p1, v1, v2, v3, v4) || isect_point_quad_v2(p2, v1, v2, v3, v4) || isect_point_quad_v2(p3, v1, v2, v3, v4) || isect_point_quad_v2(p4, v1, v2, v3, v4) || 02729 /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */ 02730 (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) || 02731 (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) || 02732 (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) || 02733 (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4)) 02734 ) { 02735 return 1; 02736 } 02737 } 02738 else { 02739 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) || 02740 /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */ 02741 (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) || 02742 (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) || 02743 (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) || 02744 (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3)) 02745 ) { 02746 return 1; 02747 } 02748 } 02749 02750 return 0; 02751 } 02752 02753 /* Add faces to the bucket but dont initialize its pixels 02754 * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */ 02755 static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index) 02756 { 02757 float min[2], max[2], *vCoSS; 02758 int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */ 02759 int fidx, bucket_x, bucket_y; 02760 int has_x_isect = -1, has_isect = 0; /* for early loop exit */ 02761 MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */ 02762 02763 INIT_MINMAX2(min, max); 02764 02765 fidx = mf->v4 ? 3:2; 02766 do { 02767 vCoSS = ps->screenCoords[ *(&mf->v1 + fidx) ]; 02768 DO_MINMAX2(vCoSS, min, max); 02769 } while (fidx--); 02770 02771 project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax); 02772 02773 for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) { 02774 has_x_isect = 0; 02775 for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) { 02776 if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) { 02777 int bucket_index= bucket_x + (bucket_y * ps->buckets_x); 02778 BLI_linklist_prepend_arena( 02779 &ps->bucketFaces[ bucket_index ], 02780 SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */ 02781 arena 02782 ); 02783 02784 has_x_isect = has_isect = 1; 02785 } 02786 else if (has_x_isect) { 02787 /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ 02788 break; 02789 } 02790 } 02791 02792 /* no intersection for this entire row, after some intersection above means we can quit now */ 02793 if (has_x_isect==0 && has_isect) { 02794 break; 02795 } 02796 } 02797 02798 #ifndef PROJ_DEBUG_NOSEAMBLEED 02799 if (ps->seam_bleed_px > 0.0f) { 02800 if (!mf->v4) { 02801 ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */ 02802 } 02803 **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized */ 02804 } 02805 #endif 02806 } 02807 02808 static int project_paint_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) 02809 { 02810 int orth= ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend); 02811 02812 if (orth) { /* only needed for ortho */ 02813 float fac = 2.0f / ((*clipend) - (*clipsta)); 02814 *clipsta *= fac; 02815 *clipend *= fac; 02816 } 02817 02818 return orth; 02819 } 02820 02821 /* run once per stroke before projection painting */ 02822 static void project_paint_begin(ProjPaintState *ps) 02823 { 02824 /* Viewport vars */ 02825 float mat[3][3]; 02826 02827 float no[3]; 02828 02829 float *projScreenCo; /* Note, we could have 4D vectors are only needed for */ 02830 float projMargin; 02831 02832 /* Image Vars - keep track of images we have used */ 02833 LinkNode *image_LinkList = NULL; 02834 LinkNode *node; 02835 02836 ProjPaintImage *projIma; 02837 Image *tpage_last = NULL; 02838 02839 /* Face vars */ 02840 MFace *mf; 02841 MTFace *tf; 02842 02843 int a, i; /* generic looping vars */ 02844 int image_index = -1, face_index; 02845 MVert *mv; 02846 02847 MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */ 02848 02849 const int diameter= 2*brush_size(ps->brush); 02850 02851 /* ---- end defines ---- */ 02852 02853 if(ps->source==PROJ_SRC_VIEW) 02854 ED_view3d_local_clipping(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */ 02855 02856 /* paint onto the derived mesh */ 02857 02858 /* Workaround for subsurf selection, try the display mesh first */ 02859 if (ps->source==PROJ_SRC_IMAGE_CAM) { 02860 /* using render mesh, assume only camera was rendered from */ 02861 ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); 02862 ps->dm_release= TRUE; 02863 } 02864 else if(ps->ob->derivedFinal && CustomData_has_layer( &ps->ob->derivedFinal->faceData, CD_MTFACE)) { 02865 ps->dm = ps->ob->derivedFinal; 02866 ps->dm_release= FALSE; 02867 } 02868 else { 02869 ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); 02870 ps->dm_release= TRUE; 02871 } 02872 02873 if ( !CustomData_has_layer( &ps->dm->faceData, CD_MTFACE) ) { 02874 02875 if(ps->dm_release) 02876 ps->dm->release(ps->dm); 02877 02878 ps->dm = NULL; 02879 return; 02880 } 02881 02882 ps->dm_mvert = ps->dm->getVertArray(ps->dm); 02883 ps->dm_mface = ps->dm->getFaceArray(ps->dm); 02884 ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE); 02885 02886 ps->dm_totvert = ps->dm->getNumVerts(ps->dm); 02887 ps->dm_totface = ps->dm->getNumFaces(ps->dm); 02888 02889 /* use clone mtface? */ 02890 02891 02892 /* Note, use the original mesh for getting the clone and mask layer index 02893 * this avoids re-generating the derived mesh just to get the new index */ 02894 if (ps->do_layer_clone) { 02895 //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE); 02896 int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE); 02897 if (layer_num != -1) 02898 ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); 02899 02900 if (ps->dm_mtface_clone==NULL || ps->dm_mtface_clone==ps->dm_mtface) { 02901 ps->do_layer_clone = 0; 02902 ps->dm_mtface_clone= NULL; 02903 printf("ACK!\n"); 02904 } 02905 } 02906 02907 if (ps->do_layer_stencil) { 02908 //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE); 02909 int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE); 02910 if (layer_num != -1) 02911 ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); 02912 02913 if (ps->dm_mtface_stencil==NULL || ps->dm_mtface_stencil==ps->dm_mtface) { 02914 ps->do_layer_stencil = 0; 02915 ps->dm_mtface_stencil = NULL; 02916 } 02917 } 02918 02919 /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ 02920 if(ps->dm->type != DM_TYPE_CDDM) { 02921 ps->dm_mvert= MEM_dupallocN(ps->dm_mvert); 02922 ps->dm_mface= MEM_dupallocN(ps->dm_mface); 02923 /* looks like these are ok for now.*/ 02924 /* 02925 ps->dm_mtface= MEM_dupallocN(ps->dm_mtface); 02926 ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone); 02927 ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil); 02928 */ 02929 } 02930 02931 ps->viewDir[0] = 0.0f; 02932 ps->viewDir[1] = 0.0f; 02933 ps->viewDir[2] = 1.0f; 02934 02935 { 02936 float viewmat[4][4]; 02937 float viewinv[4][4]; 02938 02939 invert_m4_m4(ps->ob->imat, ps->ob->obmat); 02940 02941 if(ps->source==PROJ_SRC_VIEW) { 02942 /* normal drawing */ 02943 ps->winx= ps->ar->winx; 02944 ps->winy= ps->ar->winy; 02945 02946 copy_m4_m4(viewmat, ps->rv3d->viewmat); 02947 copy_m4_m4(viewinv, ps->rv3d->viewinv); 02948 02949 ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat); 02950 02951 ps->is_ortho= project_paint_view_clip(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend); 02952 } 02953 else { 02954 /* reprojection */ 02955 float winmat[4][4]; 02956 float vmat[4][4]; 02957 02958 ps->winx= ps->reproject_ibuf->x; 02959 ps->winy= ps->reproject_ibuf->y; 02960 02961 if (ps->source==PROJ_SRC_IMAGE_VIEW) { 02962 /* image stores camera data, tricky */ 02963 IDProperty *idgroup= IDP_GetProperties(&ps->reproject_image->id, 0); 02964 IDProperty *view_data= IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID); 02965 02966 float *array= (float *)IDP_Array(view_data); 02967 02968 /* use image array, written when creating image */ 02969 memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat)/sizeof(float); 02970 memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat)/sizeof(float); 02971 ps->clipsta= array[0]; 02972 ps->clipend= array[1]; 02973 ps->is_ortho= array[2] ? 1:0; 02974 02975 invert_m4_m4(viewinv, viewmat); 02976 } 02977 else if (ps->source==PROJ_SRC_IMAGE_CAM) { 02978 Object *camera= ps->scene->camera; 02979 02980 /* dont actually use these */ 02981 float _viewdx, _viewdy, _ycor, _lens=0.0f; 02982 rctf _viewplane; 02983 02984 /* viewmat & viewinv */ 02985 copy_m4_m4(viewinv, ps->scene->camera->obmat); 02986 normalize_m4(viewinv); 02987 invert_m4_m4(viewmat, viewinv); 02988 02989 /* camera winmat */ 02990 object_camera_mode(&ps->scene->r, camera); 02991 object_camera_matrix(&ps->scene->r, camera, ps->winx, ps->winy, 0, 02992 winmat, &_viewplane, &ps->clipsta, &ps->clipend, 02993 &_lens, &_ycor, &_viewdx, &_viewdy); 02994 02995 ps->is_ortho= (ps->scene->r.mode & R_ORTHO) ? 1 : 0; 02996 } 02997 02998 /* same as view3d_get_object_project_mat */ 02999 mul_m4_m4m4(vmat, ps->ob->obmat, viewmat); 03000 mul_m4_m4m4(ps->projectMat, vmat, winmat); 03001 } 03002 03003 03004 /* viewDir - object relative */ 03005 invert_m4_m4(ps->ob->imat, ps->ob->obmat); 03006 copy_m3_m4(mat, viewinv); 03007 mul_m3_v3(mat, ps->viewDir); 03008 copy_m3_m4(mat, ps->ob->imat); 03009 mul_m3_v3(mat, ps->viewDir); 03010 normalize_v3(ps->viewDir); 03011 03012 /* viewPos - object relative */ 03013 VECCOPY(ps->viewPos, viewinv[3]); 03014 copy_m3_m4(mat, ps->ob->imat); 03015 mul_m3_v3(mat, ps->viewPos); 03016 add_v3_v3(ps->viewPos, ps->ob->imat[3]); 03017 } 03018 03019 /* calculate vert screen coords 03020 * run this early so we can calculate the x/y resolution of our bucket rect */ 03021 INIT_MINMAX2(ps->screenMin, ps->screenMax); 03022 03023 ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts"); 03024 projScreenCo= *ps->screenCoords; 03025 03026 if (ps->is_ortho) { 03027 for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo+=4) { 03028 mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co); 03029 03030 /* screen space, not clamped */ 03031 projScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*projScreenCo[0]; 03032 projScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*projScreenCo[1]; 03033 DO_MINMAX2(projScreenCo, ps->screenMin, ps->screenMax); 03034 } 03035 } 03036 else { 03037 for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo+=4) { 03038 copy_v3_v3(projScreenCo, mv->co); 03039 projScreenCo[3] = 1.0f; 03040 03041 mul_m4_v4(ps->projectMat, projScreenCo); 03042 03043 if (projScreenCo[3] > ps->clipsta) { 03044 /* screen space, not clamped */ 03045 projScreenCo[0] = (float)(ps->winx/2.0f)+(ps->winx/2.0f)*projScreenCo[0]/projScreenCo[3]; 03046 projScreenCo[1] = (float)(ps->winy/2.0f)+(ps->winy/2.0f)*projScreenCo[1]/projScreenCo[3]; 03047 projScreenCo[2] = projScreenCo[2]/projScreenCo[3]; /* Use the depth for bucket point occlusion */ 03048 DO_MINMAX2(projScreenCo, ps->screenMin, ps->screenMax); 03049 } 03050 else { 03051 /* TODO - deal with cases where 1 side of a face goes behind the view ? 03052 * 03053 * After some research this is actually very tricky, only option is to 03054 * clip the derived mesh before painting, which is a Pain */ 03055 projScreenCo[0] = FLT_MAX; 03056 } 03057 } 03058 } 03059 03060 /* If this border is not added we get artifacts for faces that 03061 * have a parallel edge and at the bounds of the the 2D projected verts eg 03062 * - a single screen aligned quad */ 03063 projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f; 03064 ps->screenMax[0] += projMargin; 03065 ps->screenMin[0] -= projMargin; 03066 projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f; 03067 ps->screenMax[1] += projMargin; 03068 ps->screenMin[1] -= projMargin; 03069 03070 if(ps->source==PROJ_SRC_VIEW) { 03071 #ifdef PROJ_DEBUG_WINCLIP 03072 CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter)); 03073 CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter)); 03074 03075 CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter)); 03076 CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter)); 03077 #endif 03078 } 03079 else { /* reprojection, use bounds */ 03080 ps->screenMin[0]= 0; 03081 ps->screenMax[0]= (float)(ps->winx); 03082 03083 ps->screenMin[1]= 0; 03084 ps->screenMax[1]= (float)(ps->winy); 03085 } 03086 03087 /* only for convenience */ 03088 ps->screen_width = ps->screenMax[0] - ps->screenMin[0]; 03089 ps->screen_height = ps->screenMax[1] - ps->screenMin[1]; 03090 03091 ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); 03092 ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); 03093 03094 /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */ 03095 03096 /* really high values could cause problems since it has to allocate a few 03097 * (ps->buckets_x*ps->buckets_y) sized arrays */ 03098 CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); 03099 CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); 03100 03101 ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect"); 03102 ps->bucketFaces= (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); 03103 03104 ps->bucketFlags= (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); 03105 #ifndef PROJ_DEBUG_NOSEAMBLEED 03106 if (ps->seam_bleed_px > 0.0f) { 03107 ps->vertFaces= (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces"); 03108 ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags"); 03109 ps->faceSeamUVs= MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs"); 03110 } 03111 #endif 03112 03113 /* Thread stuff 03114 * 03115 * very small brushes run a lot slower multithreaded since the advantage with 03116 * threads is being able to fill in multiple buckets at once. 03117 * Only use threads for bigger brushes. */ 03118 03119 if (ps->scene->r.mode & R_FIXED_THREADS) { 03120 ps->thread_tot = ps->scene->r.threads; 03121 } 03122 else { 03123 ps->thread_tot = BLI_system_thread_count(); 03124 } 03125 for (a=0; a<ps->thread_tot; a++) { 03126 ps->arena_mt[a] = BLI_memarena_new(1<<16, "project paint arena"); 03127 } 03128 03129 arena = ps->arena_mt[0]; 03130 03131 if (ps->do_backfacecull && ps->do_mask_normal) { 03132 float viewDirPersp[3]; 03133 03134 ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags"); 03135 03136 for(a=0, mv=ps->dm_mvert; a < ps->dm_totvert; a++, mv++) { 03137 normal_short_to_float_v3(no, mv->no); 03138 03139 if (ps->is_ortho) { 03140 if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */ 03141 ps->vertFlags[a] |= PROJ_VERT_CULL; 03142 } 03143 } 03144 else { 03145 sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co); 03146 normalize_v3(viewDirPersp); 03147 if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */ 03148 ps->vertFlags[a] |= PROJ_VERT_CULL; 03149 } 03150 } 03151 } 03152 } 03153 03154 03155 for(face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) { 03156 03157 #ifndef PROJ_DEBUG_NOSEAMBLEED 03158 /* add face user if we have bleed enabled, set the UV seam flags later */ 03159 /* annoying but we need to add all faces even ones we never use elsewhere */ 03160 if (ps->seam_bleed_px > 0.0f) { 03161 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena); 03162 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena); 03163 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena); 03164 if (mf->v4) { 03165 BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena); 03166 } 03167 } 03168 #endif 03169 03170 if (tf->tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_MASK)==0 || mf->flag & ME_FACE_SEL)) { 03171 03172 float *v1coSS, *v2coSS, *v3coSS, *v4coSS=NULL; 03173 03174 v1coSS = ps->screenCoords[mf->v1]; 03175 v2coSS = ps->screenCoords[mf->v2]; 03176 v3coSS = ps->screenCoords[mf->v3]; 03177 if (mf->v4) { 03178 v4coSS = ps->screenCoords[mf->v4]; 03179 } 03180 03181 03182 if (!ps->is_ortho) { 03183 if ( v1coSS[0]==FLT_MAX || 03184 v2coSS[0]==FLT_MAX || 03185 v3coSS[0]==FLT_MAX || 03186 (mf->v4 && v4coSS[0]==FLT_MAX) 03187 ) { 03188 continue; 03189 } 03190 } 03191 03192 #ifdef PROJ_DEBUG_WINCLIP 03193 /* ignore faces outside the view */ 03194 if ( 03195 (v1coSS[0] < ps->screenMin[0] && 03196 v2coSS[0] < ps->screenMin[0] && 03197 v3coSS[0] < ps->screenMin[0] && 03198 (mf->v4 && v4coSS[0] < ps->screenMin[0])) || 03199 03200 (v1coSS[0] > ps->screenMax[0] && 03201 v2coSS[0] > ps->screenMax[0] && 03202 v3coSS[0] > ps->screenMax[0] && 03203 (mf->v4 && v4coSS[0] > ps->screenMax[0])) || 03204 03205 (v1coSS[1] < ps->screenMin[1] && 03206 v2coSS[1] < ps->screenMin[1] && 03207 v3coSS[1] < ps->screenMin[1] && 03208 (mf->v4 && v4coSS[1] < ps->screenMin[1])) || 03209 03210 (v1coSS[1] > ps->screenMax[1] && 03211 v2coSS[1] > ps->screenMax[1] && 03212 v3coSS[1] > ps->screenMax[1] && 03213 (mf->v4 && v4coSS[1] > ps->screenMax[1])) 03214 ) { 03215 continue; 03216 } 03217 03218 #endif //PROJ_DEBUG_WINCLIP 03219 03220 03221 if (ps->do_backfacecull) { 03222 if (ps->do_mask_normal) { 03223 /* Since we are interpolating the normals of faces, we want to make 03224 * sure all the verts are pointing away from the view, 03225 * not just the face */ 03226 if ( (ps->vertFlags[mf->v1] & PROJ_VERT_CULL) && 03227 (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) && 03228 (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) && 03229 (mf->v4==0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL) 03230 03231 ) { 03232 continue; 03233 } 03234 } 03235 else { 03236 if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) { 03237 continue; 03238 } 03239 03240 } 03241 } 03242 03243 if (tpage_last != tf->tpage) { 03244 03245 image_index = BLI_linklist_index(image_LinkList, tf->tpage); 03246 03247 if (image_index==-1 && BKE_image_get_ibuf(tf->tpage, NULL)) { /* MemArena dosnt have an append func */ 03248 BLI_linklist_append(&image_LinkList, tf->tpage); 03249 image_index = ps->image_tot; 03250 ps->image_tot++; 03251 } 03252 03253 tpage_last = tf->tpage; 03254 } 03255 03256 if (image_index != -1) { 03257 /* Initialize the faces screen pixels */ 03258 /* Add this to a list to initialize later */ 03259 project_paint_delayed_face_init(ps, mf, face_index); 03260 } 03261 } 03262 } 03263 03264 /* build an array of images we use*/ 03265 projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot); 03266 03267 for (node= image_LinkList, i=0; node; node= node->next, i++, projIma++) { 03268 projIma->ima = node->link; 03269 projIma->touch = 0; 03270 projIma->ibuf = BKE_image_get_ibuf(projIma->ima, NULL); 03271 projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); 03272 memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); 03273 } 03274 03275 /* we have built the array, discard the linked list */ 03276 BLI_linklist_free(image_LinkList, NULL); 03277 } 03278 03279 static void project_paint_begin_clone(ProjPaintState *ps, int mouse[2]) 03280 { 03281 /* setup clone offset */ 03282 if (ps->tool == PAINT_TOOL_CLONE) { 03283 float projCo[4]; 03284 copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d)); 03285 mul_m4_v3(ps->ob->imat, projCo); 03286 03287 projCo[3] = 1.0f; 03288 mul_m4_v4(ps->projectMat, projCo); 03289 ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx/2.0f)+(ps->winx/2.0f)*projCo[0]/projCo[3]); 03290 ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy/2.0f)+(ps->winy/2.0f)*projCo[1]/projCo[3]); 03291 } 03292 } 03293 03294 static void project_paint_end(ProjPaintState *ps) 03295 { 03296 int a; 03297 03298 /* build undo data from original pixel colors */ 03299 if(U.uiflag & USER_GLOBALUNDO) { 03300 ProjPixel *projPixel; 03301 ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL; 03302 LinkNode *pixel_node; 03303 void *tilerect; 03304 MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */ 03305 03306 int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */ 03307 int bucket_index; 03308 int tile_index; 03309 int x_round, y_round; 03310 int x_tile, y_tile; 03311 int is_float = -1; 03312 03313 /* context */ 03314 ProjPaintImage *last_projIma; 03315 int last_image_index = -1; 03316 int last_tile_width=0; 03317 03318 for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) { 03319 int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); 03320 last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size); 03321 memset(last_projIma->undoRect, 0, size); 03322 last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; 03323 } 03324 03325 for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { 03326 /* loop through all pixels */ 03327 for(pixel_node= ps->bucketRect[bucket_index]; pixel_node; pixel_node= pixel_node->next) { 03328 03329 /* ok we have a pixel, was it modified? */ 03330 projPixel = (ProjPixel *)pixel_node->link; 03331 03332 if (last_image_index != projPixel->image_index) { 03333 /* set the context */ 03334 last_image_index = projPixel->image_index; 03335 last_projIma = ps->projImages + last_image_index; 03336 last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x); 03337 is_float = last_projIma->ibuf->rect_float ? 1 : 0; 03338 } 03339 03340 03341 if ( (is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) || 03342 03343 (is_float == 1 && 03344 ( projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] || 03345 projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] || 03346 projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] || 03347 projPixel->origColor.f[3] != projPixel->pixel.f_pt[3] )) 03348 ) { 03349 03350 x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS; 03351 y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS; 03352 03353 x_round = x_tile * IMAPAINT_TILE_SIZE; 03354 y_round = y_tile * IMAPAINT_TILE_SIZE; 03355 03356 tile_index = x_tile + y_tile * last_tile_width; 03357 03358 if (last_projIma->undoRect[tile_index]==NULL) { 03359 /* add the undo tile from the modified image, then write the original colors back into it */ 03360 tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile); 03361 } 03362 else { 03363 tilerect = last_projIma->undoRect[tile_index]; 03364 } 03365 03366 /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color 03367 * because allocating the tiles allong the way slows down painting */ 03368 03369 if (is_float) { 03370 float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4; 03371 QUATCOPY(rgba_fp, projPixel->origColor.f); 03372 } 03373 else { 03374 ((unsigned int *)tilerect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint; 03375 } 03376 } 03377 } 03378 } 03379 03380 if (tmpibuf) IMB_freeImBuf(tmpibuf); 03381 if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float); 03382 } 03383 /* done calculating undo data */ 03384 03385 MEM_freeN(ps->screenCoords); 03386 MEM_freeN(ps->bucketRect); 03387 MEM_freeN(ps->bucketFaces); 03388 MEM_freeN(ps->bucketFlags); 03389 03390 #ifndef PROJ_DEBUG_NOSEAMBLEED 03391 if (ps->seam_bleed_px > 0.0f) { 03392 MEM_freeN(ps->vertFaces); 03393 MEM_freeN(ps->faceSeamFlags); 03394 MEM_freeN(ps->faceSeamUVs); 03395 } 03396 #endif 03397 03398 if (ps->vertFlags) MEM_freeN(ps->vertFlags); 03399 03400 for (a=0; a<ps->thread_tot; a++) { 03401 BLI_memarena_free(ps->arena_mt[a]); 03402 } 03403 03404 /* copy for subsurf/multires, so throw away */ 03405 if(ps->dm->type != DM_TYPE_CDDM) { 03406 if(ps->dm_mvert) MEM_freeN(ps->dm_mvert); 03407 if(ps->dm_mface) MEM_freeN(ps->dm_mface); 03408 /* looks like these dont need copying */ 03409 /* 03410 if(ps->dm_mtface) MEM_freeN(ps->dm_mtface); 03411 if(ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone); 03412 if(ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil); 03413 */ 03414 } 03415 03416 if(ps->dm_release) 03417 ps->dm->release(ps->dm); 03418 } 03419 03420 /* 1= an undo, -1 is a redo. */ 03421 static void partial_redraw_array_init(ImagePaintPartialRedraw *pr) 03422 { 03423 int tot = PROJ_BOUNDBOX_SQUARED; 03424 while (tot--) { 03425 pr->x1 = 10000000; 03426 pr->y1 = 10000000; 03427 03428 pr->x2 = -1; 03429 pr->y2 = -1; 03430 03431 pr->enabled = 1; 03432 03433 pr++; 03434 } 03435 } 03436 03437 03438 static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot) 03439 { 03440 int touch= 0; 03441 while (tot--) { 03442 pr->x1 = MIN2(pr->x1, pr_other->x1); 03443 pr->y1 = MIN2(pr->y1, pr_other->y1); 03444 03445 pr->x2 = MAX2(pr->x2, pr_other->x2); 03446 pr->y2 = MAX2(pr->y2, pr_other->y2); 03447 03448 if (pr->x2 != -1) 03449 touch = 1; 03450 03451 pr++; pr_other++; 03452 } 03453 03454 return touch; 03455 } 03456 03457 /* Loop over all images on this mesh and update any we have touched */ 03458 static int project_image_refresh_tagged(ProjPaintState *ps) 03459 { 03460 ImagePaintPartialRedraw *pr; 03461 ProjPaintImage *projIma; 03462 int a,i; 03463 int redraw = 0; 03464 03465 03466 for (a=0, projIma=ps->projImages; a < ps->image_tot; a++, projIma++) { 03467 if (projIma->touch) { 03468 /* look over each bound cell */ 03469 for (i=0; i<PROJ_BOUNDBOX_SQUARED; i++) { 03470 pr = &(projIma->partRedrawRect[i]); 03471 if (pr->x2 != -1) { /* TODO - use 'enabled' ? */ 03472 imapaintpartial = *pr; 03473 imapaint_image_update(NULL, projIma->ima, projIma->ibuf, 1); /*last 1 is for texpaint*/ 03474 redraw = 1; 03475 } 03476 } 03477 03478 projIma->touch = 0; /* clear for reuse */ 03479 } 03480 } 03481 03482 return redraw; 03483 } 03484 03485 /* run this per painting onto each mouse location */ 03486 static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) 03487 { 03488 if(ps->source==PROJ_SRC_VIEW) { 03489 float min_brush[2], max_brush[2]; 03490 const float radius = (float)brush_size(ps->brush); 03491 03492 /* so we dont have a bucket bounds that is way too small to paint into */ 03493 // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/ 03494 03495 min_brush[0] = mval_f[0] - radius; 03496 min_brush[1] = mval_f[1] - radius; 03497 03498 max_brush[0] = mval_f[0] + radius; 03499 max_brush[1] = mval_f[1] + radius; 03500 03501 /* offset to make this a valid bucket index */ 03502 project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax); 03503 03504 /* mouse outside the model areas? */ 03505 if (ps->bucketMin[0]==ps->bucketMax[0] || ps->bucketMin[1]==ps->bucketMax[1]) { 03506 return 0; 03507 } 03508 03509 ps->context_bucket_x = ps->bucketMin[0]; 03510 ps->context_bucket_y = ps->bucketMin[1]; 03511 } 03512 else { /* reproject: PROJ_SRC_* */ 03513 ps->bucketMin[0]= 0; 03514 ps->bucketMin[1]= 0; 03515 03516 ps->bucketMax[0]= ps->buckets_x; 03517 ps->bucketMax[1]= ps->buckets_y; 03518 03519 ps->context_bucket_x = 0; 03520 ps->context_bucket_y = 0; 03521 } 03522 return 1; 03523 } 03524 03525 03526 static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2]) 03527 { 03528 const int diameter= 2*brush_size(ps->brush); 03529 03530 if (ps->thread_tot > 1) 03531 BLI_lock_thread(LOCK_CUSTOM1); 03532 03533 //printf("%d %d \n", ps->context_bucket_x, ps->context_bucket_y); 03534 03535 for ( ; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) { 03536 for ( ; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) { 03537 03538 /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/ 03539 project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds); 03540 03541 if ( (ps->source != PROJ_SRC_VIEW) || 03542 project_bucket_isect_circle(mval, (float)(diameter*diameter), bucket_bounds) 03543 ) { 03544 *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x); 03545 ps->context_bucket_x++; 03546 03547 if (ps->thread_tot > 1) 03548 BLI_unlock_thread(LOCK_CUSTOM1); 03549 03550 return 1; 03551 } 03552 } 03553 ps->context_bucket_x = ps->bucketMin[0]; 03554 } 03555 03556 if (ps->thread_tot > 1) 03557 BLI_unlock_thread(LOCK_CUSTOM1); 03558 return 0; 03559 } 03560 03561 /* Each thread gets one of these, also used as an argument to pass to project_paint_op */ 03562 typedef struct ProjectHandle { 03563 /* args */ 03564 ProjPaintState *ps; 03565 float prevmval[2]; 03566 float mval[2]; 03567 03568 /* annoying but we need to have image bounds per thread, then merge into ps->projectPartialRedraws */ 03569 ProjPaintImage *projImages; /* array of partial redraws */ 03570 03571 /* thread settings */ 03572 int thread_index; 03573 } ProjectHandle; 03574 03575 static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const unsigned char *cp2, const int fac) 03576 { 03577 /* this and other blending modes previously used >>8 instead of /255. both 03578 are not equivalent (>>8 is /256), and the former results in rounding 03579 errors that can turn colors black fast after repeated blending */ 03580 const int mfac= 255-fac; 03581 03582 cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; 03583 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 03584 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 03585 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 03586 } 03587 03588 static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, const float fac) 03589 { 03590 const float mfac= 1.0f-fac; 03591 cp[0]= mfac*cp1[0] + fac*cp2[0]; 03592 cp[1]= mfac*cp1[1] + fac*cp2[1]; 03593 cp[2]= mfac*cp1[2] + fac*cp2[2]; 03594 cp[3]= mfac*cp1[3] + fac*cp2[3]; 03595 } 03596 03597 static void blend_color_mix_accum(unsigned char *cp, const unsigned char *cp1, const unsigned char *cp2, const int fac) 03598 { 03599 /* this and other blending modes previously used >>8 instead of /255. both 03600 are not equivalent (>>8 is /256), and the former results in rounding 03601 errors that can turn colors black fast after repeated blending */ 03602 const int mfac= 255-fac; 03603 const int alpha= cp1[3] + ((fac * cp2[3]) / 255); 03604 03605 cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; 03606 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 03607 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 03608 cp[3]= alpha > 255 ? 255 : alpha; 03609 } 03610 03611 static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) 03612 { 03613 if (ps->is_airbrush==0 && mask < 1.0f) { 03614 projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*255), ps->blend); 03615 blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*255)); 03616 } 03617 else { 03618 *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*mask*255), ps->blend); 03619 } 03620 } 03621 03622 static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) 03623 { 03624 if (ps->is_airbrush==0 && mask < 1.0f) { 03625 IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend); 03626 blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask); 03627 } 03628 else { 03629 IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha*mask, ps->blend); 03630 } 03631 } 03632 03633 /* do_projectpaint_smear* 03634 * 03635 * note, mask is used to modify the alpha here, this is not correct since it allows 03636 * accumulation of color greater then 'projPixel->mask' however in the case of smear its not 03637 * really that important to be correct as it is with clone and painting 03638 */ 03639 static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2]) 03640 { 03641 unsigned char rgba_ub[4]; 03642 03643 if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0) 03644 return; 03645 /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ 03646 blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha*mask*255)); 03647 BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena); 03648 } 03649 03650 static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2]) 03651 { 03652 unsigned char rgba_ub[4]; 03653 unsigned char rgba_smear[4]; 03654 03655 if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0) 03656 return; 03657 03658 IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, projPixel->pixel.f_pt); 03659 /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ 03660 blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, rgba_smear, (rgba_ub), (int)(alpha*mask*255)); 03661 BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena); 03662 } 03663 03664 static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask) 03665 { 03666 unsigned char rgba_ub[4]; 03667 03668 if (ps->is_texbrush) { 03669 rgba_ub[0] = FTOCHAR(rgba[0] * ps->brush->rgb[0]); 03670 rgba_ub[1] = FTOCHAR(rgba[1] * ps->brush->rgb[1]); 03671 rgba_ub[2] = FTOCHAR(rgba[2] * ps->brush->rgb[2]); 03672 rgba_ub[3] = FTOCHAR(rgba[3]); 03673 } 03674 else { 03675 IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb); 03676 rgba_ub[3] = 255; 03677 } 03678 03679 if (ps->is_airbrush==0 && mask < 1.0f) { 03680 projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha*255), ps->blend); 03681 blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*255)); 03682 } 03683 else { 03684 *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); 03685 } 03686 } 03687 03688 static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, int use_color_correction) { 03689 if (ps->is_texbrush) { 03690 /* rgba already holds a texture result here from higher level function */ 03691 float rgba_br[3]; 03692 if(use_color_correction){ 03693 srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb); 03694 mul_v3_v3(rgba, rgba_br); 03695 } 03696 else{ 03697 mul_v3_v3(rgba, ps->brush->rgb); 03698 } 03699 } 03700 else { 03701 if(use_color_correction){ 03702 srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb); 03703 } 03704 else { 03705 VECCOPY(rgba, ps->brush->rgb); 03706 } 03707 rgba[3] = 1.0; 03708 } 03709 03710 if (ps->is_airbrush==0 && mask < 1.0f) { 03711 IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend); 03712 blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask); 03713 } 03714 else { 03715 IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha*mask, ps->blend); 03716 } 03717 } 03718 03719 03720 03721 /* run this for single and multithreaded painting */ 03722 static void *do_projectpaint_thread(void *ph_v) 03723 { 03724 /* First unpack args from the struct */ 03725 ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps; 03726 ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages; 03727 const float *lastpos = ((ProjectHandle *)ph_v)->prevmval; 03728 const float *pos = ((ProjectHandle *)ph_v)->mval; 03729 const int thread_index = ((ProjectHandle *)ph_v)->thread_index; 03730 /* Done with args from ProjectHandle */ 03731 03732 LinkNode *node; 03733 ProjPixel *projPixel; 03734 03735 int last_index = -1; 03736 ProjPaintImage *last_projIma= NULL; 03737 ImagePaintPartialRedraw *last_partial_redraw_cell; 03738 03739 float rgba[4], alpha, dist_nosqrt, dist; 03740 03741 float falloff; 03742 int bucket_index; 03743 int is_floatbuf = 0; 03744 int use_color_correction = 0; 03745 const short tool = ps->tool; 03746 rctf bucket_bounds; 03747 03748 /* for smear only */ 03749 float pos_ofs[2] = {0}; 03750 float co[2]; 03751 float mask = 1.0f; /* airbrush wont use mask */ 03752 unsigned short mask_short; 03753 const float radius= (float)brush_size(ps->brush); 03754 const float radius_squared= radius*radius; /* avoid a square root with every dist comparison */ 03755 03756 short lock_alpha= ELEM(ps->brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : ps->brush->flag & BRUSH_LOCK_ALPHA; 03757 03758 LinkNode *smearPixels = NULL; 03759 LinkNode *smearPixels_f = NULL; 03760 MemArena *smearArena = NULL; /* mem arena for this brush projection only */ 03761 03762 if (tool==PAINT_TOOL_SMEAR) { 03763 pos_ofs[0] = pos[0] - lastpos[0]; 03764 pos_ofs[1] = pos[1] - lastpos[1]; 03765 03766 smearArena = BLI_memarena_new(1<<16, "paint smear arena"); 03767 } 03768 03769 /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */ 03770 03771 while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) { 03772 03773 /* Check this bucket and its faces are initialized */ 03774 if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) { 03775 /* No pixels initialized */ 03776 project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds); 03777 } 03778 03779 if(ps->source != PROJ_SRC_VIEW) { 03780 03781 /* Re-Projection, simple, no brushes! */ 03782 03783 for (node = ps->bucketRect[bucket_index]; node; node = node->next) { 03784 projPixel = (ProjPixel *)node->link; 03785 03786 bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, projPixel->projCoSS[0], projPixel->projCoSS[1]); 03787 if(projPixel->newColor.ch[3]) { 03788 mask = ((float)projPixel->mask)/65535.0f; 03789 blend_color_mix_accum(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask*projPixel->newColor.ch[3])); 03790 03791 } 03792 } 03793 } 03794 else { 03795 /* Normal brush painting */ 03796 03797 for (node = ps->bucketRect[bucket_index]; node; node = node->next) { 03798 03799 projPixel = (ProjPixel *)node->link; 03800 03801 /*dist = len_v2v2(projPixel->projCoSS, pos);*/ /* correct but uses a sqrtf */ 03802 dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos); 03803 03804 /*if (dist < radius) {*/ /* correct but uses a sqrtf */ 03805 if (dist_nosqrt <= radius_squared) { 03806 dist=sqrtf(dist_nosqrt); 03807 03808 falloff = brush_curve_strength_clamp(ps->brush, dist, radius); 03809 03810 if (falloff > 0.0f) { 03811 if (ps->is_texbrush) { 03812 /* note, for clone and smear, we only use the alpha, could be a special function */ 03813 brush_sample_tex(ps->brush, projPixel->projCoSS, rgba, thread_index); 03814 alpha = rgba[3]; 03815 } else { 03816 alpha = 1.0f; 03817 } 03818 03819 if (ps->is_airbrush) { 03820 /* for an aurbrush there is no real mask, so just multiply the alpha by it */ 03821 alpha *= falloff * brush_alpha(ps->brush); 03822 mask = ((float)projPixel->mask)/65535.0f; 03823 } 03824 else { 03825 /* This brush dosnt accumulate so add some curve to the brushes falloff */ 03826 falloff = 1.0f - falloff; 03827 falloff = 1.0f - (falloff * falloff); 03828 03829 mask_short = (unsigned short)(projPixel->mask * (brush_alpha(ps->brush) * falloff)); 03830 if (mask_short > projPixel->mask_max) { 03831 mask = ((float)mask_short)/65535.0f; 03832 projPixel->mask_max = mask_short; 03833 } 03834 else { 03835 /*mask = ((float)projPixel->mask_max)/65535.0f;*/ 03836 03837 /* Go onto the next pixel */ 03838 continue; 03839 } 03840 } 03841 03842 if (alpha > 0.0f) { 03843 03844 if (last_index != projPixel->image_index) { 03845 last_index = projPixel->image_index; 03846 last_projIma = projImages + last_index; 03847 03848 last_projIma->touch = 1; 03849 is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0; 03850 use_color_correction = (last_projIma->ibuf->profile == IB_PROFILE_LINEAR_RGB) ? 1 : 0; 03851 } 03852 03853 last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; 03854 last_partial_redraw_cell->x1 = MIN2(last_partial_redraw_cell->x1, projPixel->x_px); 03855 last_partial_redraw_cell->y1 = MIN2(last_partial_redraw_cell->y1, projPixel->y_px); 03856 03857 last_partial_redraw_cell->x2 = MAX2(last_partial_redraw_cell->x2, projPixel->x_px+1); 03858 last_partial_redraw_cell->y2 = MAX2(last_partial_redraw_cell->y2, projPixel->y_px+1); 03859 03860 03861 switch(tool) { 03862 case PAINT_TOOL_CLONE: 03863 if (is_floatbuf) { 03864 if (((ProjPixelClone *)projPixel)->clonepx.f[3]) { 03865 do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isnt used for cloning, only alpha */ 03866 } 03867 } 03868 else { 03869 if (((ProjPixelClone*)projPixel)->clonepx.ch[3]) { 03870 do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isnt used for cloning, only alpha */ 03871 } 03872 } 03873 break; 03874 case PAINT_TOOL_SMEAR: 03875 sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs); 03876 03877 if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co); 03878 else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co); 03879 break; 03880 default: 03881 if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask, use_color_correction); 03882 else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask); 03883 break; 03884 } 03885 } 03886 03887 if(lock_alpha) { 03888 if (is_floatbuf) projPixel->pixel.f_pt[3]= projPixel->origColor.f[3]; 03889 else projPixel->pixel.ch_pt[3]= projPixel->origColor.ch[3]; 03890 } 03891 03892 /* done painting */ 03893 } 03894 } 03895 } 03896 } 03897 } 03898 03899 03900 if (tool==PAINT_TOOL_SMEAR) { 03901 03902 for (node= smearPixels; node; node= node->next) { /* this wont run for a float image */ 03903 projPixel = node->link; 03904 *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint; 03905 } 03906 03907 for (node= smearPixels_f; node; node= node->next) { 03908 projPixel = node->link; 03909 IMAPAINT_CHAR_RGBA_TO_FLOAT(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.ch); 03910 } 03911 03912 BLI_memarena_free(smearArena); 03913 } 03914 03915 return NULL; 03916 } 03917 03918 static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), float *lastpos, float *pos) 03919 { 03920 /* First unpack args from the struct */ 03921 ProjPaintState *ps = (ProjPaintState *)state; 03922 int touch_any = 0; 03923 03924 ProjectHandle handles[BLENDER_MAX_THREADS]; 03925 ListBase threads; 03926 int a,i; 03927 03928 if (!project_bucket_iter_init(ps, pos)) { 03929 return 0; 03930 } 03931 03932 if (ps->thread_tot > 1) 03933 BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot); 03934 03935 /* get the threads running */ 03936 for(a=0; a < ps->thread_tot; a++) { 03937 03938 /* set defaults in handles */ 03939 //memset(&handles[a], 0, sizeof(BakeShade)); 03940 03941 handles[a].ps = ps; 03942 copy_v2_v2(handles[a].mval, pos); 03943 copy_v2_v2(handles[a].prevmval, lastpos); 03944 03945 /* thread spesific */ 03946 handles[a].thread_index = a; 03947 03948 handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage)); 03949 03950 memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage)); 03951 03952 /* image bounds */ 03953 for (i=0; i< ps->image_tot; i++) { 03954 handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); 03955 memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); 03956 } 03957 03958 if (ps->thread_tot > 1) 03959 BLI_insert_thread(&threads, &handles[a]); 03960 } 03961 03962 if (ps->thread_tot > 1) /* wait for everything to be done */ 03963 BLI_end_threads(&threads); 03964 else 03965 do_projectpaint_thread(&handles[0]); 03966 03967 03968 /* move threaded bounds back into ps->projectPartialRedraws */ 03969 for(i=0; i < ps->image_tot; i++) { 03970 int touch = 0; 03971 for(a=0; a < ps->thread_tot; a++) { 03972 touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED); 03973 } 03974 03975 if (touch) { 03976 ps->projImages[i].touch = 1; 03977 touch_any = 1; 03978 } 03979 } 03980 03981 return touch_any; 03982 } 03983 03984 03985 static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, const int UNUSED(prevmval_i[2]), const int mval_i[2], double time, float pressure) 03986 { 03987 03988 /* Use mouse coords as floats for projection painting */ 03989 float pos[2]; 03990 03991 pos[0] = (float)(mval_i[0]); 03992 pos[1] = (float)(mval_i[1]); 03993 03994 // we may want to use this later 03995 // brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0); 03996 03997 if (brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps, 0)) { 03998 return 1; 03999 } 04000 else return 0; 04001 } 04002 04003 04004 static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, const int prevmval_i[2], const int mval_i[2], double time, float pressure) 04005 { 04006 int a, redraw; 04007 04008 for (a=0; a < ps->image_tot; a++) 04009 partial_redraw_array_init(ps->projImages[a].partRedrawRect); 04010 04011 redraw= project_paint_sub_stroke(ps, painter, prevmval_i, mval_i, time, pressure); 04012 04013 if(project_image_refresh_tagged(ps)) 04014 return redraw; 04015 04016 return 0; 04017 } 04018 04019 /* Imagepaint Partial Redraw & Dirty Region */ 04020 04021 static void imapaint_clear_partial_redraw(void) 04022 { 04023 memset(&imapaintpartial, 0, sizeof(imapaintpartial)); 04024 } 04025 04026 static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h) 04027 { 04028 ImBuf *tmpibuf = NULL; 04029 int srcx= 0, srcy= 0, origx; 04030 04031 IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); 04032 04033 if (w == 0 || h == 0) 04034 return; 04035 04036 if (!imapaintpartial.enabled) { 04037 imapaintpartial.x1 = x; 04038 imapaintpartial.y1 = y; 04039 imapaintpartial.x2 = x+w; 04040 imapaintpartial.y2 = y+h; 04041 imapaintpartial.enabled = 1; 04042 } 04043 else { 04044 imapaintpartial.x1 = MIN2(imapaintpartial.x1, x); 04045 imapaintpartial.y1 = MIN2(imapaintpartial.y1, y); 04046 imapaintpartial.x2 = MAX2(imapaintpartial.x2, x+w); 04047 imapaintpartial.y2 = MAX2(imapaintpartial.y2, y+h); 04048 } 04049 04050 w = ((x + w - 1) >> IMAPAINT_TILE_BITS); 04051 h = ((y + h - 1) >> IMAPAINT_TILE_BITS); 04052 origx = (x >> IMAPAINT_TILE_BITS); 04053 y = (y >> IMAPAINT_TILE_BITS); 04054 04055 for (; y <= h; y++) 04056 for (x=origx; x <= w; x++) 04057 image_undo_push_tile(ima, ibuf, &tmpibuf, x, y); 04058 04059 ibuf->userflags |= IB_BITMAPDIRTY; 04060 04061 if (tmpibuf) 04062 IMB_freeImBuf(tmpibuf); 04063 } 04064 04065 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint) 04066 { 04067 if(ibuf->rect_float) 04068 ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ 04069 04070 if(ibuf->mipmap[0]) 04071 ibuf->userflags |= IB_MIPMAP_INVALID; 04072 04073 /* todo: should set_tpage create ->rect? */ 04074 if(texpaint || (sima && sima->lock)) { 04075 int w = imapaintpartial.x2 - imapaintpartial.x1; 04076 int h = imapaintpartial.y2 - imapaintpartial.y1; 04077 GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, !texpaint); 04078 } 04079 } 04080 04081 /* Image Paint Operations */ 04082 04083 static void imapaint_ibuf_get_set_rgb(ImBuf *ibuf, int x, int y, short torus, short set, float *rgb) 04084 { 04085 if (torus) { 04086 x %= ibuf->x; 04087 if (x < 0) x += ibuf->x; 04088 y %= ibuf->y; 04089 if (y < 0) y += ibuf->y; 04090 } 04091 04092 if (ibuf->rect_float) { 04093 float *rrgbf = ibuf->rect_float + (ibuf->x*y + x)*4; 04094 04095 if (set) { 04096 IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb); 04097 } else { 04098 IMAPAINT_FLOAT_RGB_COPY(rgb, rrgbf); 04099 } 04100 } 04101 else { 04102 char *rrgb = (char*)ibuf->rect + (ibuf->x*y + x)*4; 04103 04104 if (set) { 04105 IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb) 04106 } else { 04107 IMAPAINT_CHAR_RGB_TO_FLOAT(rgb, rrgb) 04108 } 04109 } 04110 } 04111 04112 static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus) 04113 { 04114 float inrgb[3]; 04115 04116 // XXX: signed unsigned mismatch 04117 if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) { 04118 if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb); 04119 else return 0; 04120 } 04121 else imapaint_ibuf_get_set_rgb(ibuf, x, y, 0, 0, inrgb); 04122 04123 outrgb[0] += inrgb[0]; 04124 outrgb[1] += inrgb[1]; 04125 outrgb[2] += inrgb[2]; 04126 04127 return 1; 04128 } 04129 04130 static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, short torus) 04131 { 04132 int x, y, count, xi, yi, xo, yo; 04133 int out_off[2], in_off[2], dim[2]; 04134 float outrgb[3]; 04135 04136 dim[0] = ibufb->x; 04137 dim[1] = ibufb->y; 04138 in_off[0] = pos[0]; 04139 in_off[1] = pos[1]; 04140 out_off[0] = out_off[1] = 0; 04141 04142 if (!torus) { 04143 IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], 04144 &out_off[1], &dim[0], &dim[1]); 04145 04146 if ((dim[0] == 0) || (dim[1] == 0)) 04147 return; 04148 } 04149 04150 for (y=0; y < dim[1]; y++) { 04151 for (x=0; x < dim[0]; x++) { 04152 /* get input pixel */ 04153 xi = in_off[0] + x; 04154 yi = in_off[1] + y; 04155 04156 count = 1; 04157 imapaint_ibuf_get_set_rgb(ibuf, xi, yi, torus, 0, outrgb); 04158 04159 count += imapaint_ibuf_add_if(ibuf, xi-1, yi-1, outrgb, torus); 04160 count += imapaint_ibuf_add_if(ibuf, xi-1, yi , outrgb, torus); 04161 count += imapaint_ibuf_add_if(ibuf, xi-1, yi+1, outrgb, torus); 04162 04163 count += imapaint_ibuf_add_if(ibuf, xi , yi-1, outrgb, torus); 04164 count += imapaint_ibuf_add_if(ibuf, xi , yi+1, outrgb, torus); 04165 04166 count += imapaint_ibuf_add_if(ibuf, xi+1, yi-1, outrgb, torus); 04167 count += imapaint_ibuf_add_if(ibuf, xi+1, yi , outrgb, torus); 04168 count += imapaint_ibuf_add_if(ibuf, xi+1, yi+1, outrgb, torus); 04169 04170 outrgb[0] /= count; 04171 outrgb[1] /= count; 04172 outrgb[2] /= count; 04173 04174 /* write into brush buffer */ 04175 xo = out_off[0] + x; 04176 yo = out_off[1] + y; 04177 imapaint_ibuf_get_set_rgb(ibufb, xo, yo, 0, 1, outrgb); 04178 } 04179 } 04180 } 04181 04182 static void imapaint_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height) 04183 { 04184 region->destx= destx; 04185 region->desty= desty; 04186 region->srcx= srcx; 04187 region->srcy= srcy; 04188 region->width= width; 04189 region->height= height; 04190 } 04191 04192 static int imapaint_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf) 04193 { 04194 int destx= region->destx; 04195 int desty= region->desty; 04196 int srcx= region->srcx; 04197 int srcy= region->srcy; 04198 int width= region->width; 04199 int height= region->height; 04200 int origw, origh, w, h, tot= 0; 04201 04202 /* convert destination and source coordinates to be within image */ 04203 destx = destx % dbuf->x; 04204 if (destx < 0) destx += dbuf->x; 04205 desty = desty % dbuf->y; 04206 if (desty < 0) desty += dbuf->y; 04207 srcx = srcx % sbuf->x; 04208 if (srcx < 0) srcx += sbuf->x; 04209 srcy = srcy % sbuf->y; 04210 if (srcy < 0) srcy += sbuf->y; 04211 04212 /* clip width of blending area to destination imbuf, to avoid writing the 04213 same pixel twice */ 04214 origw = w = (width > dbuf->x)? dbuf->x: width; 04215 origh = h = (height > dbuf->y)? dbuf->y: height; 04216 04217 /* clip within image */ 04218 IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h); 04219 imapaint_set_region(®ion[tot++], destx, desty, srcx, srcy, w, h); 04220 04221 /* do 3 other rects if needed */ 04222 if (w < origw) 04223 imapaint_set_region(®ion[tot++], (destx+w)%dbuf->x, desty, (srcx+w)%sbuf->x, srcy, origw-w, h); 04224 if (h < origh) 04225 imapaint_set_region(®ion[tot++], destx, (desty+h)%dbuf->y, srcx, (srcy+h)%sbuf->y, w, origh-h); 04226 if ((w < origw) && (h < origh)) 04227 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); 04228 04229 return tot; 04230 } 04231 04232 static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) 04233 { 04234 ImagePaintRegion region[4]; 04235 int a, tot; 04236 04237 imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y); 04238 tot= imapaint_torus_split_region(region, ibufb, ibuf); 04239 04240 for(a=0; a<tot; a++) 04241 IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty, 04242 region[a].srcx, region[a].srcy, 04243 region[a].width, region[a].height, IMB_BLEND_COPY_RGB); 04244 } 04245 04246 static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) 04247 { 04248 /* note: allocImbuf returns zero'd memory, so regions outside image will 04249 have zero alpha, and hence not be blended onto the image */ 04250 int w=ibufb->x, h=ibufb->y, destx=0, desty=0, srcx=pos[0], srcy=pos[1]; 04251 ImBuf *clonebuf= IMB_allocImBuf(w, h, ibufb->depth, ibufb->flags); 04252 04253 IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); 04254 IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h, 04255 IMB_BLEND_COPY_RGB); 04256 IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h, 04257 IMB_BLEND_COPY_ALPHA); 04258 04259 return clonebuf; 04260 } 04261 04262 static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos) 04263 { 04264 ipos[0]= (int)floorf((pos[0] - ibufb->x/2) + 1.0f); 04265 ipos[1]= (int)floorf((pos[1] - ibufb->y/2) + 1.0f); 04266 } 04267 04268 /* dosnt run for projection painting 04269 * only the old style painting in the 3d view */ 04270 static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos) 04271 { 04272 ImagePaintState *s= ((ImagePaintState*)state); 04273 ImBuf *clonebuf= NULL, *frombuf; 04274 ImagePaintRegion region[4]; 04275 short torus= s->brush->flag & BRUSH_TORUS; 04276 short blend= s->blend; 04277 float *offset= s->brush->clone.offset; 04278 float liftpos[2]; 04279 int bpos[2], blastpos[2], bliftpos[2]; 04280 int a, tot; 04281 04282 imapaint_convert_brushco(ibufb, pos, bpos); 04283 04284 /* lift from canvas */ 04285 if(s->tool == PAINT_TOOL_SOFTEN) { 04286 imapaint_lift_soften(s->canvas, ibufb, bpos, torus); 04287 } 04288 else if(s->tool == PAINT_TOOL_SMEAR) { 04289 if (lastpos[0]==pos[0] && lastpos[1]==pos[1]) 04290 return 0; 04291 04292 imapaint_convert_brushco(ibufb, lastpos, blastpos); 04293 imapaint_lift_smear(s->canvas, ibufb, blastpos); 04294 } 04295 else if(s->tool == PAINT_TOOL_CLONE && s->clonecanvas) { 04296 liftpos[0]= pos[0] - offset[0]*s->canvas->x; 04297 liftpos[1]= pos[1] - offset[1]*s->canvas->y; 04298 04299 imapaint_convert_brushco(ibufb, liftpos, bliftpos); 04300 clonebuf= imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos); 04301 } 04302 04303 frombuf= (clonebuf)? clonebuf: ibufb; 04304 04305 if(torus) { 04306 imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); 04307 tot= imapaint_torus_split_region(region, s->canvas, frombuf); 04308 } 04309 else { 04310 imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); 04311 tot= 1; 04312 } 04313 04314 /* blend into canvas */ 04315 for(a=0; a<tot; a++) { 04316 imapaint_dirty_region(s->image, s->canvas, 04317 region[a].destx, region[a].desty, 04318 region[a].width, region[a].height); 04319 04320 IMB_rectblend(s->canvas, frombuf, 04321 region[a].destx, region[a].desty, 04322 region[a].srcx, region[a].srcy, 04323 region[a].width, region[a].height, blend); 04324 } 04325 04326 if(clonebuf) IMB_freeImBuf(clonebuf); 04327 04328 return 1; 04329 } 04330 04331 /* 3D TexturePaint */ 04332 04333 static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv) 04334 { 04335 float d1[2], d2[2]; 04336 float mismatch = len_v2v2(fwuv, uv); 04337 float len1 = len_v2v2(prevuv, fwuv); 04338 float len2 = len_v2v2(bkuv, uv); 04339 04340 sub_v2_v2v2(d1, fwuv, prevuv); 04341 sub_v2_v2v2(d2, uv, bkuv); 04342 04343 return ((dot_v2v2(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2)*2)); 04344 } 04345 04346 /* ImagePaint Common */ 04347 04348 static int imapaint_canvas_set(ImagePaintState *s, Image *ima) 04349 { 04350 ImBuf *ibuf= BKE_image_get_ibuf(ima, s->sima? &s->sima->iuser: NULL); 04351 04352 /* verify that we can paint and set canvas */ 04353 if(ima==NULL) { 04354 return 0; 04355 } 04356 else if(ima->packedfile && ima->rr) { 04357 s->warnpackedfile = ima->id.name + 2; 04358 return 0; 04359 } 04360 else if(ibuf && ibuf->channels!=4) { 04361 s->warnmultifile = ima->id.name + 2; 04362 return 0; 04363 } 04364 else if(!ibuf || !(ibuf->rect || ibuf->rect_float)) 04365 return 0; 04366 04367 s->image= ima; 04368 s->canvas= ibuf; 04369 04370 /* set clone canvas */ 04371 if(s->tool == PAINT_TOOL_CLONE) { 04372 ima= s->brush->clone.image; 04373 ibuf= BKE_image_get_ibuf(ima, s->sima? &s->sima->iuser: NULL); 04374 04375 if(!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) 04376 return 0; 04377 04378 s->clonecanvas= ibuf; 04379 04380 /* temporarily add float rect for cloning */ 04381 if(s->canvas->rect_float && !s->clonecanvas->rect_float) { 04382 int profile = IB_PROFILE_NONE; 04383 04384 /* Don't want to color manage, but don't disturb existing profiles */ 04385 SWAP(int, s->clonecanvas->profile, profile); 04386 04387 IMB_float_from_rect(s->clonecanvas); 04388 s->clonefreefloat= 1; 04389 04390 SWAP(int, s->clonecanvas->profile, profile); 04391 } 04392 else if(!s->canvas->rect_float && !s->clonecanvas->rect) 04393 IMB_rect_from_float(s->clonecanvas); 04394 } 04395 04396 return 1; 04397 } 04398 04399 static void imapaint_canvas_free(ImagePaintState *s) 04400 { 04401 if (s->clonefreefloat) 04402 imb_freerectfloatImBuf(s->clonecanvas); 04403 } 04404 04405 static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update, float pressure) 04406 { 04407 ImBuf *ibuf= BKE_image_get_ibuf(image, s->sima? &s->sima->iuser: NULL); 04408 float pos[2]; 04409 04410 if(!ibuf) 04411 return 0; 04412 04413 pos[0] = uv[0]*ibuf->x; 04414 pos[1] = uv[1]*ibuf->y; 04415 04416 brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0); 04417 04418 if (brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s, ibuf->profile == IB_PROFILE_LINEAR_RGB)) { 04419 if (update) 04420 imapaint_image_update(s->sima, image, ibuf, texpaint); 04421 return 1; 04422 } 04423 else return 0; 04424 } 04425 04426 static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPainter *painter, short texpaint, const int prevmval[2], const int mval[2], double time, float pressure) 04427 { 04428 Image *newimage = NULL; 04429 float fwuv[2], bkuv[2], newuv[2]; 04430 unsigned int newfaceindex; 04431 int breakstroke = 0, redraw = 0; 04432 04433 if (texpaint) { 04434 /* pick new face and image */ 04435 if ( imapaint_pick_face(vc, s->me, mval, &newfaceindex) && 04436 ((s->me->editflag & ME_EDIT_PAINT_MASK)==0 || (s->me->mface+newfaceindex)->flag & ME_FACE_SEL) 04437 ) { 04438 ImBuf *ibuf; 04439 04440 newimage = (s->me->mtface+newfaceindex)->tpage; 04441 ibuf= BKE_image_get_ibuf(newimage, s->sima? &s->sima->iuser: NULL); 04442 04443 if(ibuf && ibuf->rect) 04444 imapaint_pick_uv(s->scene, s->ob, newfaceindex, mval, newuv); 04445 else { 04446 newimage = NULL; 04447 newuv[0] = newuv[1] = 0.0f; 04448 } 04449 } 04450 else 04451 newuv[0] = newuv[1] = 0.0f; 04452 04453 /* see if stroke is broken, and if so finish painting in old position */ 04454 if (s->image) { 04455 imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv); 04456 imapaint_pick_uv(s->scene, s->ob, newfaceindex, prevmval, bkuv); 04457 04458 if (newimage == s->image) 04459 breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv); 04460 else 04461 breakstroke= 1; 04462 } 04463 else 04464 fwuv[0]= fwuv[1]= 0.0f; 04465 04466 if (breakstroke) { 04467 imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv); 04468 redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, 04469 fwuv, time, 1, pressure); 04470 imapaint_clear_partial_redraw(); 04471 brush_painter_break_stroke(painter); 04472 } 04473 04474 /* set new canvas */ 04475 if (newimage && (newimage != s->image)) 04476 if (!imapaint_canvas_set(s, newimage)) 04477 newimage = NULL; 04478 04479 /* paint in new image */ 04480 if (newimage) { 04481 if (breakstroke) 04482 redraw|= imapaint_paint_sub_stroke(s, painter, newimage, 04483 texpaint, bkuv, time, 0, pressure); 04484 redraw|= imapaint_paint_sub_stroke(s, painter, newimage, texpaint, 04485 newuv, time, 1, pressure); 04486 } 04487 04488 /* update state */ 04489 s->image = newimage; 04490 s->faceindex = newfaceindex; 04491 s->uv[0] = newuv[0]; 04492 s->uv[1] = newuv[1]; 04493 } 04494 else { 04495 UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]); 04496 redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, newuv, 04497 time, 1, pressure); 04498 } 04499 04500 if (redraw) 04501 imapaint_clear_partial_redraw(); 04502 04503 return redraw; 04504 } 04505 04506 /************************ image paint poll ************************/ 04507 04508 static Brush *image_paint_brush(bContext *C) 04509 { 04510 Scene *scene= CTX_data_scene(C); 04511 ToolSettings *settings= scene->toolsettings; 04512 04513 return paint_brush(&settings->imapaint.paint); 04514 } 04515 04516 static int image_paint_poll(bContext *C) 04517 { 04518 Object *obact = CTX_data_active_object(C); 04519 04520 if(!image_paint_brush(C)) 04521 return 0; 04522 04523 if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) { 04524 return 1; 04525 } 04526 else { 04527 SpaceImage *sima= CTX_wm_space_image(C); 04528 04529 if(sima) { 04530 ARegion *ar= CTX_wm_region(C); 04531 04532 if((sima->flag & SI_DRAWTOOL) && ar->regiontype==RGN_TYPE_WINDOW) 04533 return 1; 04534 } 04535 } 04536 04537 return 0; 04538 } 04539 04540 static int image_paint_3d_poll(bContext *C) 04541 { 04542 if(CTX_wm_region_view3d(C)) 04543 return image_paint_poll(C); 04544 04545 return 0; 04546 } 04547 04548 static int image_paint_2d_clone_poll(bContext *C) 04549 { 04550 Brush *brush= image_paint_brush(C); 04551 04552 if(!CTX_wm_region_view3d(C) && image_paint_poll(C)) 04553 if(brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) 04554 if(brush->clone.image) 04555 return 1; 04556 04557 return 0; 04558 } 04559 04560 /************************ paint operator ************************/ 04561 04562 typedef enum PaintMode { 04563 PAINT_MODE_2D, 04564 PAINT_MODE_3D, 04565 PAINT_MODE_3D_PROJECT 04566 } PaintMode; 04567 04568 typedef struct PaintOperation { 04569 PaintMode mode; 04570 04571 BrushPainter *painter; 04572 ImagePaintState s; 04573 ProjPaintState ps; 04574 04575 int first; 04576 int prevmouse[2]; 04577 float prev_pressure; /* need this since we dont get tablet events for pressure change */ 04578 int orig_brush_size; 04579 double starttime; 04580 04581 ViewContext vc; 04582 wmTimer *timer; 04583 04584 short restore_projection; 04585 } PaintOperation; 04586 04587 static void paint_redraw(bContext *C, ImagePaintState *s, int final) 04588 { 04589 if(final) { 04590 if(s->image) 04591 GPU_free_image(s->image); 04592 04593 /* compositor listener deals with updating */ 04594 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, s->image); 04595 } 04596 else { 04597 if(!s->sima || !s->sima->lock) 04598 ED_region_tag_redraw(CTX_wm_region(C)); 04599 else 04600 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, s->image); 04601 } 04602 } 04603 04604 /* initialize project paint settings from context */ 04605 static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps) 04606 { 04607 Scene *scene= CTX_data_scene(C); 04608 ToolSettings *settings= scene->toolsettings; 04609 Brush *brush= paint_brush(&settings->imapaint.paint); 04610 04611 /* brush */ 04612 ps->brush = brush; 04613 ps->tool = brush->imagepaint_tool; 04614 ps->blend = brush->blend; 04615 04616 ps->is_airbrush = (brush->flag & BRUSH_AIRBRUSH) ? 1 : 0; 04617 ps->is_texbrush = (brush->mtex.tex) ? 1 : 0; 04618 04619 04620 /* these can be NULL */ 04621 ps->v3d= CTX_wm_view3d(C); 04622 ps->rv3d= CTX_wm_region_view3d(C); 04623 ps->ar= CTX_wm_region(C); 04624 04625 ps->scene= scene; 04626 ps->ob= ob; /* allow override of active object */ 04627 04628 /* setup projection painting data */ 04629 ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1; 04630 ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1; 04631 ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1; 04632 04633 if (ps->tool == PAINT_TOOL_CLONE) 04634 ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE); 04635 04636 ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0; 04637 ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0; 04638 04639 04640 #ifndef PROJ_DEBUG_NOSEAMBLEED 04641 ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */ 04642 #endif 04643 04644 if(ps->do_mask_normal) { 04645 ps->normal_angle_inner = settings->imapaint.normal_angle; 04646 ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f; 04647 } 04648 else { 04649 ps->normal_angle_inner= ps->normal_angle= settings->imapaint.normal_angle; 04650 } 04651 04652 ps->normal_angle_inner *= (float)(M_PI_2 / 90); 04653 ps->normal_angle *= (float)(M_PI_2 / 90); 04654 ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner; 04655 04656 if(ps->normal_angle_range <= 0.0f) 04657 ps->do_mask_normal = 0; /* no need to do blending */ 04658 } 04659 04660 static void paint_brush_init_tex(Brush *brush) 04661 { 04662 /* init mtex nodes */ 04663 if(brush) { 04664 MTex *mtex= &brush->mtex; 04665 if(mtex->tex && mtex->tex->nodetree) 04666 ntreeBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */ 04667 } 04668 04669 } 04670 04671 static int texture_paint_init(bContext *C, wmOperator *op) 04672 { 04673 Scene *scene= CTX_data_scene(C); 04674 ToolSettings *settings= scene->toolsettings; 04675 Brush *brush= paint_brush(&settings->imapaint.paint); 04676 PaintOperation *pop= MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ 04677 04678 pop->first= 1; 04679 op->customdata= pop; 04680 04681 /* XXX: Soften tool does not support projection painting atm, so just disable 04682 projection for this brush */ 04683 if(brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { 04684 settings->imapaint.flag |= IMAGEPAINT_PROJECT_DISABLE; 04685 pop->restore_projection = 1; 04686 } 04687 04688 /* initialize from context */ 04689 if(CTX_wm_region_view3d(C)) { 04690 pop->mode= PAINT_MODE_3D; 04691 04692 if(!(settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE)) 04693 pop->mode= PAINT_MODE_3D_PROJECT; 04694 else 04695 view3d_set_viewcontext(C, &pop->vc); 04696 } 04697 else { 04698 pop->s.sima= CTX_wm_space_image(C); 04699 pop->s.v2d= &CTX_wm_region(C)->v2d; 04700 } 04701 04702 pop->s.scene= scene; 04703 pop->s.screen= CTX_wm_screen(C); 04704 04705 pop->s.brush = brush; 04706 pop->s.tool = brush->imagepaint_tool; 04707 if(pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE)) 04708 pop->s.tool = PAINT_TOOL_DRAW; 04709 pop->s.blend = brush->blend; 04710 pop->orig_brush_size= brush_size(brush); 04711 04712 if(pop->mode != PAINT_MODE_2D) { 04713 pop->s.ob = OBACT; 04714 pop->s.me = get_mesh(pop->s.ob); 04715 if (!pop->s.me) return 0; 04716 } 04717 else { 04718 pop->s.image = pop->s.sima->image; 04719 04720 if(!imapaint_canvas_set(&pop->s, pop->s.image)) { 04721 if(pop->s.warnmultifile) 04722 BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint"); 04723 if(pop->s.warnpackedfile) 04724 BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted"); 04725 04726 return 0; 04727 } 04728 } 04729 04730 paint_brush_init_tex(pop->s.brush); 04731 04732 /* note, if we have no UVs on the derived mesh, then we must return here */ 04733 if(pop->mode == PAINT_MODE_3D_PROJECT) { 04734 04735 /* initialize all data from the context */ 04736 project_state_init(C, OBACT, &pop->ps); 04737 04738 paint_brush_init_tex(pop->ps.brush); 04739 04740 pop->ps.source= PROJ_SRC_VIEW; 04741 04742 if (pop->ps.ob==NULL || !(pop->ps.ob->lay & pop->ps.v3d->lay)) 04743 return 0; 04744 04745 /* Dont allow brush size below 2 */ 04746 if (brush_size(brush) < 2) 04747 brush_set_size(brush, 2); 04748 04749 /* allocate and initialize spacial data structures */ 04750 project_paint_begin(&pop->ps); 04751 04752 if(pop->ps.dm==NULL) 04753 return 0; 04754 } 04755 04756 settings->imapaint.flag |= IMAGEPAINT_DRAWING; 04757 undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, 04758 image_undo_restore, image_undo_free); 04759 04760 /* create painter */ 04761 pop->painter= brush_painter_new(pop->s.brush); 04762 04763 return 1; 04764 } 04765 04766 static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) 04767 { 04768 PaintOperation *pop= op->customdata; 04769 float time, mousef[2]; 04770 float pressure; 04771 int mouse[2], redraw; 04772 04773 RNA_float_get_array(itemptr, "mouse", mousef); 04774 mouse[0] = (int)(mousef[0]); 04775 mouse[1] = (int)(mousef[1]); 04776 time= RNA_float_get(itemptr, "time"); 04777 pressure= RNA_float_get(itemptr, "pressure"); 04778 04779 if(pop->first) 04780 project_paint_begin_clone(&pop->ps, mouse); 04781 04782 if(pop->mode == PAINT_MODE_3D) 04783 view3d_operator_needs_opengl(C); 04784 04785 if(pop->mode == PAINT_MODE_3D_PROJECT) { 04786 redraw= project_paint_stroke(&pop->ps, pop->painter, pop->prevmouse, mouse, time, pressure); 04787 pop->prevmouse[0]= mouse[0]; 04788 pop->prevmouse[1]= mouse[1]; 04789 04790 } 04791 else { 04792 redraw= imapaint_paint_stroke(&pop->vc, &pop->s, pop->painter, pop->mode == PAINT_MODE_3D, pop->prevmouse, mouse, time, pressure); 04793 pop->prevmouse[0]= mouse[0]; 04794 pop->prevmouse[1]= mouse[1]; 04795 } 04796 04797 if(redraw) 04798 paint_redraw(C, &pop->s, 0); 04799 04800 pop->first= 0; 04801 } 04802 04803 static void paint_brush_exit_tex(Brush *brush) 04804 { 04805 if(brush) { 04806 MTex *mtex= &brush->mtex; 04807 if(mtex->tex && mtex->tex->nodetree) 04808 ntreeEndExecTree(mtex->tex->nodetree); 04809 } 04810 } 04811 04812 static void paint_exit(bContext *C, wmOperator *op) 04813 { 04814 Scene *scene= CTX_data_scene(C); 04815 ToolSettings *settings= scene->toolsettings; 04816 PaintOperation *pop= op->customdata; 04817 04818 if(pop->timer) 04819 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer); 04820 04821 if(pop->restore_projection) 04822 settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE; 04823 04824 paint_brush_exit_tex(pop->s.brush); 04825 04826 settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; 04827 imapaint_canvas_free(&pop->s); 04828 brush_painter_free(pop->painter); 04829 04830 if(pop->mode == PAINT_MODE_3D_PROJECT) { 04831 brush_set_size(pop->ps.brush, pop->orig_brush_size); 04832 paint_brush_exit_tex(pop->ps.brush); 04833 04834 project_paint_end(&pop->ps); 04835 } 04836 04837 paint_redraw(C, &pop->s, 1); 04838 undo_paint_push_end(UNDO_PAINT_IMAGE); 04839 04840 if(pop->s.warnmultifile) 04841 BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile); 04842 if(pop->s.warnpackedfile) 04843 BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile); 04844 04845 MEM_freeN(pop); 04846 } 04847 04848 static int paint_exec(bContext *C, wmOperator *op) 04849 { 04850 if(!texture_paint_init(C, op)) { 04851 MEM_freeN(op->customdata); 04852 return OPERATOR_CANCELLED; 04853 } 04854 04855 RNA_BEGIN(op->ptr, itemptr, "stroke") { 04856 paint_apply(C, op, &itemptr); 04857 } 04858 RNA_END; 04859 04860 paint_exit(C, op); 04861 04862 return OPERATOR_FINISHED; 04863 } 04864 04865 static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) 04866 { 04867 PaintOperation *pop= op->customdata; 04868 wmTabletData *wmtab; 04869 PointerRNA itemptr; 04870 float pressure, mousef[2]; 04871 double time; 04872 int tablet; 04873 04874 time= PIL_check_seconds_timer(); 04875 04876 tablet= 0; 04877 pressure= 0; 04878 pop->s.blend= pop->s.brush->blend; 04879 04880 if(event->custom == EVT_DATA_TABLET) { 04881 wmtab= event->customdata; 04882 04883 tablet= (wmtab->Active != EVT_TABLET_NONE); 04884 pressure= wmtab->Pressure; 04885 if(wmtab->Active == EVT_TABLET_ERASER) 04886 pop->s.blend= IMB_BLEND_ERASE_ALPHA; 04887 } 04888 else /* otherwise airbrush becomes 1.0 pressure instantly */ 04889 pressure= pop->prev_pressure ? pop->prev_pressure : 1.0f; 04890 04891 if(pop->first) { 04892 pop->prevmouse[0]= event->mval[0]; 04893 pop->prevmouse[1]= event->mval[1]; 04894 pop->starttime= time; 04895 04896 /* special exception here for too high pressure values on first touch in 04897 windows for some tablets, then we just skip first touch .. */ 04898 if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || brush_use_alpha_pressure(pop->s.brush) || brush_use_size_pressure(pop->s.brush))) 04899 return; 04900 04901 /* This can be removed once fixed properly in 04902 brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) 04903 at zero pressure we should do nothing 1/2^12 is .0002 which is the sensitivity of the most sensitive pen tablet available*/ 04904 if (tablet && (pressure < .0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || brush_use_alpha_pressure(pop->s.brush) || brush_use_size_pressure(pop->s.brush))) 04905 return; 04906 04907 } 04908 04909 /* fill in stroke */ 04910 RNA_collection_add(op->ptr, "stroke", &itemptr); 04911 04912 mousef[0] = (float)(event->mval[0]); 04913 mousef[1] = (float)(event->mval[1]); 04914 RNA_float_set_array(&itemptr, "mouse", mousef); 04915 RNA_float_set(&itemptr, "time", (float)(time - pop->starttime)); 04916 RNA_float_set(&itemptr, "pressure", pressure); 04917 04918 /* apply */ 04919 paint_apply(C, op, &itemptr); 04920 04921 pop->prev_pressure= pressure; 04922 } 04923 04924 static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event) 04925 { 04926 PaintOperation *pop; 04927 04928 if(!texture_paint_init(C, op)) { 04929 MEM_freeN(op->customdata); 04930 return OPERATOR_CANCELLED; 04931 } 04932 04933 paint_apply_event(C, op, event); 04934 04935 pop= op->customdata; 04936 WM_event_add_modal_handler(C, op); 04937 04938 if(pop->s.brush->flag & BRUSH_AIRBRUSH) 04939 pop->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); 04940 04941 return OPERATOR_RUNNING_MODAL; 04942 } 04943 04944 static int paint_modal(bContext *C, wmOperator *op, wmEvent *event) 04945 { 04946 PaintOperation *pop= op->customdata; 04947 04948 switch(event->type) { 04949 case LEFTMOUSE: 04950 case MIDDLEMOUSE: 04951 case RIGHTMOUSE: // XXX hardcoded 04952 paint_exit(C, op); 04953 return OPERATOR_FINISHED; 04954 case MOUSEMOVE: 04955 case INBETWEEN_MOUSEMOVE: 04956 paint_apply_event(C, op, event); 04957 break; 04958 case TIMER: 04959 if(event->customdata == pop->timer) 04960 paint_apply_event(C, op, event); 04961 break; 04962 } 04963 04964 return OPERATOR_RUNNING_MODAL; 04965 } 04966 04967 static int paint_cancel(bContext *C, wmOperator *op) 04968 { 04969 paint_exit(C, op); 04970 04971 return OPERATOR_CANCELLED; 04972 } 04973 04974 void PAINT_OT_image_paint(wmOperatorType *ot) 04975 { 04976 /* identifiers */ 04977 ot->name= "Image Paint"; 04978 ot->idname= "PAINT_OT_image_paint"; 04979 04980 /* api callbacks */ 04981 ot->exec= paint_exec; 04982 ot->invoke= paint_invoke; 04983 ot->modal= paint_modal; 04984 ot->cancel= paint_cancel; 04985 ot->poll= image_paint_poll; 04986 04987 /* flags */ 04988 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 04989 04990 /* properties */ 04991 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); 04992 } 04993 04994 static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) 04995 { 04996 RegionView3D *rv3d= CTX_wm_region_view3d(C); 04997 04998 if(!rv3d) { 04999 SpaceImage *sima= CTX_wm_space_image(C); 05000 ARegion *ar= CTX_wm_region(C); 05001 05002 ED_space_image_zoom(sima, ar, zoomx, zoomy); 05003 05004 return 1; 05005 } 05006 05007 *zoomx = *zoomy = 1; 05008 05009 return 0; 05010 } 05011 05012 /************************ cursor drawing *******************************/ 05013 05014 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) 05015 { 05016 #define PX_SIZE_FADE_MAX 12.0f 05017 #define PX_SIZE_FADE_MIN 4.0f 05018 05019 Brush *brush= image_paint_brush(C); 05020 Paint *paint= paint_get_active(CTX_data_scene(C)); 05021 05022 if(paint && brush && paint->flags & PAINT_SHOW_BRUSH) { 05023 float zoomx, zoomy; 05024 const float size= (float)brush_size(brush); 05025 const short use_zoom= get_imapaint_zoom(C, &zoomx, &zoomy); 05026 const float pixel_size= MAX2(size * zoomx, size * zoomy); 05027 float alpha= 0.5f; 05028 05029 /* fade out the brush (cheap trick to work around brush interfearing with sampling [#])*/ 05030 if(pixel_size < PX_SIZE_FADE_MIN) { 05031 return; 05032 } 05033 else if (pixel_size < PX_SIZE_FADE_MAX) { 05034 alpha *= (pixel_size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN); 05035 } 05036 05037 glPushMatrix(); 05038 05039 glTranslatef((float)x, (float)y, 0.0f); 05040 05041 if(use_zoom) 05042 glScalef(zoomx, zoomy, 1.0f); 05043 05044 glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha); 05045 glEnable( GL_LINE_SMOOTH ); 05046 glEnable(GL_BLEND); 05047 glutil_draw_lined_arc(0, (float)(M_PI*2.0), size, 40); 05048 glDisable(GL_BLEND); 05049 glDisable( GL_LINE_SMOOTH ); 05050 05051 glPopMatrix(); 05052 } 05053 #undef PX_SIZE_FADE_MAX 05054 #undef PX_SIZE_FADE_MIN 05055 } 05056 05057 static void toggle_paint_cursor(bContext *C, int enable) 05058 { 05059 ToolSettings *settings= CTX_data_scene(C)->toolsettings; 05060 05061 if(settings->imapaint.paintcursor && !enable) { 05062 WM_paint_cursor_end(CTX_wm_manager(C), settings->imapaint.paintcursor); 05063 settings->imapaint.paintcursor = NULL; 05064 } 05065 else if(enable) 05066 settings->imapaint.paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, brush_drawcursor, NULL); 05067 } 05068 05069 /* enable the paint cursor if it isn't already. 05070 05071 purpose is to make sure the paint cursor is shown if paint 05072 mode is enabled in the image editor. the paint poll will 05073 ensure that the cursor is hidden when not in paint mode */ 05074 void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) 05075 { 05076 ImagePaintSettings *imapaint = &settings->imapaint; 05077 05078 if(!imapaint->paintcursor) { 05079 imapaint->paintcursor = 05080 WM_paint_cursor_activate(wm, image_paint_poll, 05081 brush_drawcursor, NULL); 05082 } 05083 } 05084 05085 /************************ grab clone operator ************************/ 05086 05087 typedef struct GrabClone { 05088 float startoffset[2]; 05089 int startx, starty; 05090 } GrabClone; 05091 05092 static void grab_clone_apply(bContext *C, wmOperator *op) 05093 { 05094 Brush *brush= image_paint_brush(C); 05095 float delta[2]; 05096 05097 RNA_float_get_array(op->ptr, "delta", delta); 05098 add_v2_v2(brush->clone.offset, delta); 05099 ED_region_tag_redraw(CTX_wm_region(C)); 05100 } 05101 05102 static int grab_clone_exec(bContext *C, wmOperator *op) 05103 { 05104 grab_clone_apply(C, op); 05105 05106 return OPERATOR_FINISHED; 05107 } 05108 05109 static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event) 05110 { 05111 Brush *brush= image_paint_brush(C); 05112 GrabClone *cmv; 05113 05114 cmv= MEM_callocN(sizeof(GrabClone), "GrabClone"); 05115 copy_v2_v2(cmv->startoffset, brush->clone.offset); 05116 cmv->startx= event->x; 05117 cmv->starty= event->y; 05118 op->customdata= cmv; 05119 05120 WM_event_add_modal_handler(C, op); 05121 05122 return OPERATOR_RUNNING_MODAL; 05123 } 05124 05125 static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event) 05126 { 05127 Brush *brush= image_paint_brush(C); 05128 ARegion *ar= CTX_wm_region(C); 05129 GrabClone *cmv= op->customdata; 05130 float startfx, startfy, fx, fy, delta[2]; 05131 int xmin= ar->winrct.xmin, ymin= ar->winrct.ymin; 05132 05133 switch(event->type) { 05134 case LEFTMOUSE: 05135 case MIDDLEMOUSE: 05136 case RIGHTMOUSE: // XXX hardcoded 05137 MEM_freeN(op->customdata); 05138 return OPERATOR_FINISHED; 05139 case MOUSEMOVE: 05140 /* mouse moved, so move the clone image */ 05141 UI_view2d_region_to_view(&ar->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy); 05142 UI_view2d_region_to_view(&ar->v2d, event->x - xmin, event->y - ymin, &fx, &fy); 05143 05144 delta[0]= fx - startfx; 05145 delta[1]= fy - startfy; 05146 RNA_float_set_array(op->ptr, "delta", delta); 05147 05148 copy_v2_v2(brush->clone.offset, cmv->startoffset); 05149 05150 grab_clone_apply(C, op); 05151 break; 05152 } 05153 05154 return OPERATOR_RUNNING_MODAL; 05155 } 05156 05157 static int grab_clone_cancel(bContext *UNUSED(C), wmOperator *op) 05158 { 05159 MEM_freeN(op->customdata); 05160 return OPERATOR_CANCELLED; 05161 } 05162 05163 void PAINT_OT_grab_clone(wmOperatorType *ot) 05164 { 05165 /* identifiers */ 05166 ot->name= "Grab Clone"; 05167 ot->idname= "PAINT_OT_grab_clone"; 05168 05169 /* api callbacks */ 05170 ot->exec= grab_clone_exec; 05171 ot->invoke= grab_clone_invoke; 05172 ot->modal= grab_clone_modal; 05173 ot->cancel= grab_clone_cancel; 05174 ot->poll= image_paint_2d_clone_poll; 05175 05176 /* flags */ 05177 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 05178 05179 /* properties */ 05180 RNA_def_float_vector(ot->srna, "delta", 2, NULL, -FLT_MAX, FLT_MAX, "Delta", "Delta offset of clone image in 0.0..1.0 coordinates.", -1.0f, 1.0f); 05181 } 05182 05183 /******************** sample color operator ********************/ 05184 05185 static int sample_color_exec(bContext *C, wmOperator *op) 05186 { 05187 Scene *scene= CTX_data_scene(C); 05188 Brush *brush= image_paint_brush(C); 05189 ARegion *ar= CTX_wm_region(C); 05190 int location[2]; 05191 05192 RNA_int_get_array(op->ptr, "location", location); 05193 paint_sample_color(scene, ar, location[0], location[1]); 05194 05195 WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); 05196 05197 return OPERATOR_FINISHED; 05198 } 05199 05200 static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event) 05201 { 05202 RNA_int_set_array(op->ptr, "location", event->mval); 05203 sample_color_exec(C, op); 05204 05205 WM_event_add_modal_handler(C, op); 05206 05207 return OPERATOR_RUNNING_MODAL; 05208 } 05209 05210 static int sample_color_modal(bContext *C, wmOperator *op, wmEvent *event) 05211 { 05212 switch(event->type) { 05213 case LEFTMOUSE: 05214 case RIGHTMOUSE: // XXX hardcoded 05215 return OPERATOR_FINISHED; 05216 case MOUSEMOVE: 05217 RNA_int_set_array(op->ptr, "location", event->mval); 05218 sample_color_exec(C, op); 05219 break; 05220 } 05221 05222 return OPERATOR_RUNNING_MODAL; 05223 } 05224 05225 /* same as image_paint_poll but fail when face mask mode is enabled */ 05226 static int image_paint_sample_color_poll(bContext *C) 05227 { 05228 if(image_paint_poll(C)) { 05229 if(CTX_wm_view3d(C)) { 05230 Object *obact = CTX_data_active_object(C); 05231 if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { 05232 Mesh *me= get_mesh(obact); 05233 if(me) { 05234 return !(me->editflag & ME_EDIT_PAINT_MASK); 05235 } 05236 } 05237 } 05238 05239 return 1; 05240 } 05241 05242 return 0; 05243 } 05244 05245 void PAINT_OT_sample_color(wmOperatorType *ot) 05246 { 05247 /* identifiers */ 05248 ot->name= "Sample Color"; 05249 ot->idname= "PAINT_OT_sample_color"; 05250 05251 /* api callbacks */ 05252 ot->exec= sample_color_exec; 05253 ot->invoke= sample_color_invoke; 05254 ot->modal= sample_color_modal; 05255 ot->poll= image_paint_sample_color_poll; 05256 05257 /* flags */ 05258 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05259 05260 /* properties */ 05261 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates.", 0, 16384); 05262 } 05263 05264 /******************** set clone cursor operator ********************/ 05265 05266 static int set_clone_cursor_exec(bContext *C, wmOperator *op) 05267 { 05268 Scene *scene= CTX_data_scene(C); 05269 View3D *v3d= CTX_wm_view3d(C); 05270 float *cursor= give_cursor(scene, v3d); 05271 05272 RNA_float_get_array(op->ptr, "location", cursor); 05273 05274 ED_area_tag_redraw(CTX_wm_area(C)); 05275 05276 return OPERATOR_FINISHED; 05277 } 05278 05279 static int set_clone_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) 05280 { 05281 Scene *scene= CTX_data_scene(C); 05282 View3D *v3d= CTX_wm_view3d(C); 05283 ARegion *ar= CTX_wm_region(C); 05284 float location[3]; 05285 05286 view3d_operator_needs_opengl(C); 05287 05288 if(!ED_view3d_autodist(scene, ar, v3d, event->mval, location)) 05289 return OPERATOR_CANCELLED; 05290 05291 RNA_float_set_array(op->ptr, "location", location); 05292 05293 return set_clone_cursor_exec(C, op); 05294 } 05295 05296 void PAINT_OT_clone_cursor_set(wmOperatorType *ot) 05297 { 05298 /* identifiers */ 05299 ot->name= "Set Clone Cursor"; 05300 ot->idname= "PAINT_OT_clone_cursor_set"; 05301 05302 /* api callbacks */ 05303 ot->exec= set_clone_cursor_exec; 05304 ot->invoke= set_clone_cursor_invoke; 05305 ot->poll= image_paint_3d_poll; 05306 05307 /* flags */ 05308 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05309 05310 /* properties */ 05311 RNA_def_float_vector(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in world space coordinates.", -10000.0f, 10000.0f); 05312 } 05313 05314 /******************** texture paint toggle operator ********************/ 05315 05316 static int texture_paint_toggle_poll(bContext *C) 05317 { 05318 if(CTX_data_edit_object(C)) 05319 return 0; 05320 if(CTX_data_active_object(C)==NULL) 05321 return 0; 05322 05323 return 1; 05324 } 05325 05326 static int texture_paint_toggle_exec(bContext *C, wmOperator *op) 05327 { 05328 Scene *scene= CTX_data_scene(C); 05329 Object *ob= CTX_data_active_object(C); 05330 Mesh *me= NULL; 05331 05332 if(ob==NULL) 05333 return OPERATOR_CANCELLED; 05334 05335 if (object_data_is_libdata(ob)) { 05336 BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata."); 05337 return OPERATOR_CANCELLED; 05338 } 05339 05340 me= get_mesh(ob); 05341 05342 if(!(ob->mode & OB_MODE_TEXTURE_PAINT) && !me) { 05343 BKE_report(op->reports, RPT_ERROR, "Can only enter texture paint mode for mesh objects."); 05344 return OPERATOR_CANCELLED; 05345 } 05346 05347 if(ob->mode & OB_MODE_TEXTURE_PAINT) { 05348 ob->mode &= ~OB_MODE_TEXTURE_PAINT; 05349 05350 if(U.glreslimit != 0) 05351 GPU_free_images(); 05352 GPU_paint_set_mipmap(1); 05353 05354 toggle_paint_cursor(C, 0); 05355 } 05356 else { 05357 ob->mode |= OB_MODE_TEXTURE_PAINT; 05358 05359 if(me->mtface==NULL) 05360 me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, 05361 NULL, me->totface); 05362 05363 paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT); 05364 05365 if(U.glreslimit != 0) 05366 GPU_free_images(); 05367 GPU_paint_set_mipmap(0); 05368 05369 toggle_paint_cursor(C, 1); 05370 } 05371 05372 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 05373 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); 05374 05375 return OPERATOR_FINISHED; 05376 } 05377 05378 void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) 05379 { 05380 /* identifiers */ 05381 ot->name= "Texture Paint Toggle"; 05382 ot->idname= "PAINT_OT_texture_paint_toggle"; 05383 05384 /* api callbacks */ 05385 ot->exec= texture_paint_toggle_exec; 05386 ot->poll= texture_paint_toggle_poll; 05387 05388 /* flags */ 05389 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05390 } 05391 05392 static int texture_paint_poll(bContext *C) 05393 { 05394 if(texture_paint_toggle_poll(C)) 05395 if(CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT) 05396 return 1; 05397 05398 return 0; 05399 } 05400 05401 int image_texture_paint_poll(bContext *C) 05402 { 05403 return (texture_paint_poll(C) || image_paint_poll(C)); 05404 } 05405 05406 int facemask_paint_poll(bContext *C) 05407 { 05408 return paint_facesel_test(CTX_data_active_object(C)); 05409 } 05410 05411 /* use project paint to re-apply an image */ 05412 static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) 05413 { 05414 Image *image= BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image")); 05415 Scene *scene= CTX_data_scene(C); 05416 ProjPaintState ps= {NULL}; 05417 int orig_brush_size; 05418 IDProperty *idgroup; 05419 IDProperty *view_data= NULL; 05420 05421 project_state_init(C, OBACT, &ps); 05422 05423 if(ps.ob==NULL || ps.ob->type != OB_MESH) { 05424 BKE_report(op->reports, RPT_ERROR, "No active mesh object."); 05425 return OPERATOR_CANCELLED; 05426 } 05427 05428 if(image==NULL) { 05429 BKE_report(op->reports, RPT_ERROR, "Image could not be found."); 05430 return OPERATOR_CANCELLED; 05431 } 05432 05433 ps.reproject_image= image; 05434 ps.reproject_ibuf= BKE_image_get_ibuf(image, NULL); 05435 05436 if(ps.reproject_ibuf==NULL || ps.reproject_ibuf->rect==NULL) { 05437 BKE_report(op->reports, RPT_ERROR, "Image data could not be found."); 05438 return OPERATOR_CANCELLED; 05439 } 05440 05441 idgroup= IDP_GetProperties(&image->id, 0); 05442 05443 if(idgroup) { 05444 view_data= IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY); 05445 05446 /* type check to make sure its ok */ 05447 if(view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) { 05448 BKE_report(op->reports, RPT_ERROR, "Image project data invalid."); 05449 return OPERATOR_CANCELLED; 05450 } 05451 } 05452 05453 if(view_data) { 05454 /* image has stored view projection info */ 05455 ps.source= PROJ_SRC_IMAGE_VIEW; 05456 } 05457 else { 05458 ps.source= PROJ_SRC_IMAGE_CAM; 05459 05460 if(scene->camera==NULL) { 05461 BKE_report(op->reports, RPT_ERROR, "No active camera set."); 05462 return OPERATOR_CANCELLED; 05463 } 05464 } 05465 05466 /* override */ 05467 ps.is_texbrush= 0; 05468 ps.is_airbrush= 1; 05469 orig_brush_size= brush_size(ps.brush); 05470 brush_set_size(ps.brush, 32); /* cover the whole image */ 05471 05472 ps.tool= PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */ 05473 05474 scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; 05475 05476 undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, 05477 image_undo_restore, image_undo_free); 05478 05479 /* allocate and initialize spacial data structures */ 05480 project_paint_begin(&ps); 05481 05482 if(ps.dm==NULL) { 05483 brush_set_size(ps.brush, orig_brush_size); 05484 return OPERATOR_CANCELLED; 05485 } 05486 else { 05487 float pos[2]= {0.0, 0.0}; 05488 float lastpos[2]= {0.0, 0.0}; 05489 int a; 05490 05491 for (a=0; a < ps.image_tot; a++) 05492 partial_redraw_array_init(ps.projImages[a].partRedrawRect); 05493 05494 project_paint_op(&ps, NULL, lastpos, pos); 05495 05496 project_image_refresh_tagged(&ps); 05497 05498 for (a=0; a < ps.image_tot; a++) { 05499 GPU_free_image(ps.projImages[a].ima); 05500 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ps.projImages[a].ima); 05501 } 05502 } 05503 05504 project_paint_end(&ps); 05505 05506 scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; 05507 brush_set_size(ps.brush, orig_brush_size); 05508 05509 return OPERATOR_FINISHED; 05510 } 05511 05512 void PAINT_OT_project_image(wmOperatorType *ot) 05513 { 05514 PropertyRNA *prop; 05515 05516 /* identifiers */ 05517 ot->name= "Project Image"; 05518 ot->idname= "PAINT_OT_project_image"; 05519 ot->description= "Project an edited render from the active camera back onto the object"; 05520 05521 /* api callbacks */ 05522 ot->invoke= WM_enum_search_invoke; 05523 ot->exec= texture_paint_camera_project_exec; 05524 05525 /* flags */ 05526 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05527 05528 prop= RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", ""); 05529 RNA_def_enum_funcs(prop, RNA_image_itemf); 05530 ot->prop= prop; 05531 } 05532 05533 static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) 05534 { 05535 Image *image; 05536 ImBuf *ibuf; 05537 char filename[FILE_MAX]; 05538 05539 Scene *scene= CTX_data_scene(C); 05540 ToolSettings *settings= scene->toolsettings; 05541 int w= settings->imapaint.screen_grab_size[0]; 05542 int h= settings->imapaint.screen_grab_size[1]; 05543 int maxsize; 05544 char err_out[256]= "unknown"; 05545 05546 RNA_string_get(op->ptr, "filepath", filename); 05547 05548 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); 05549 05550 if(w > maxsize) w= maxsize; 05551 if(h > maxsize) h= maxsize; 05552 05553 ibuf= ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, err_out); 05554 if(!ibuf) { 05555 /* Mostly happens when OpenGL offscreen buffer was failed to create, */ 05556 /* but could be other reasons. Should be handled in the future. nazgul */ 05557 BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL offscreen buffer: %s", err_out); 05558 return OPERATOR_CANCELLED; 05559 } 05560 05561 image= BKE_add_image_imbuf(ibuf); 05562 05563 if(image) { 05564 /* now for the trickyness. store the view projection here! 05565 * reprojection will reuse this */ 05566 View3D *v3d= CTX_wm_view3d(C); 05567 RegionView3D *rv3d= CTX_wm_region_view3d(C); 05568 05569 IDPropertyTemplate val; 05570 IDProperty *idgroup= IDP_GetProperties(&image->id, 1); 05571 IDProperty *view_data; 05572 int orth; 05573 float *array; 05574 05575 val.array.len = PROJ_VIEW_DATA_SIZE; 05576 val.array.type = IDP_FLOAT; 05577 view_data = IDP_New(IDP_ARRAY, val, PROJ_VIEW_DATA_ID); 05578 05579 array= (float *)IDP_Array(view_data); 05580 memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat)/sizeof(float); 05581 memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat)/sizeof(float); 05582 orth= project_paint_view_clip(v3d, rv3d, &array[0], &array[1]); 05583 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 */ 05584 05585 IDP_AddToGroup(idgroup, view_data); 05586 05587 rename_id(&image->id, "image_view"); 05588 } 05589 05590 return OPERATOR_FINISHED; 05591 } 05592 05593 void PAINT_OT_image_from_view(wmOperatorType *ot) 05594 { 05595 /* identifiers */ 05596 ot->name= "Image from View"; 05597 ot->idname= "PAINT_OT_image_from_view"; 05598 ot->description= "Make an image from the current 3D view for re-projection"; 05599 05600 /* api callbacks */ 05601 ot->exec= texture_paint_image_from_view_exec; 05602 ot->poll= ED_operator_region_view3d_active; 05603 05604 /* flags */ 05605 ot->flag= OPTYPE_REGISTER; 05606 05607 RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file"); 05608 }