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