Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <math.h> 00034 #include <string.h> 00035 00036 #ifdef WIN32 00037 #include <io.h> 00038 #else 00039 #include <unistd.h> 00040 #endif 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "BLI_blenlib.h" 00045 #include "BLI_math.h" 00046 #include "BLI_utildefines.h" 00047 #include "BLI_ghash.h" 00048 00049 #include "IMB_imbuf.h" 00050 #include "IMB_imbuf_types.h" 00051 00052 #include "DNA_armature_types.h" 00053 #include "DNA_mesh_types.h" 00054 #include "DNA_particle_types.h" 00055 #include "DNA_scene_types.h" 00056 #include "DNA_brush_types.h" 00057 #include "DNA_object_types.h" 00058 #include "DNA_meshdata_types.h" 00059 00060 #include "RNA_access.h" 00061 #include "RNA_define.h" 00062 #include "RNA_enum_types.h" 00063 00064 #include "BKE_DerivedMesh.h" 00065 #include "BKE_armature.h" 00066 #include "BKE_action.h" 00067 #include "BKE_brush.h" 00068 #include "BKE_context.h" 00069 #include "BKE_depsgraph.h" 00070 #include "BKE_deform.h" 00071 #include "BKE_mesh.h" 00072 #include "BKE_modifier.h" 00073 #include "BKE_object.h" 00074 #include "BKE_paint.h" 00075 #include "BKE_report.h" 00076 00077 #include "WM_api.h" 00078 #include "WM_types.h" 00079 00080 00081 #include "ED_armature.h" 00082 #include "ED_mesh.h" 00083 #include "ED_screen.h" 00084 #include "ED_view3d.h" 00085 00086 #include "paint_intern.h" 00087 00088 /* polling - retrieve whether cursor should be set or operator should be done */ 00089 00090 00091 /* Returns true if vertex paint mode is active */ 00092 int vertex_paint_mode_poll(bContext *C) 00093 { 00094 Object *ob = CTX_data_active_object(C); 00095 00096 return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totface; 00097 } 00098 00099 int vertex_paint_poll(bContext *C) 00100 { 00101 if(vertex_paint_mode_poll(C) && 00102 paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) { 00103 ScrArea *sa= CTX_wm_area(C); 00104 if(sa->spacetype==SPACE_VIEW3D) { 00105 ARegion *ar= CTX_wm_region(C); 00106 if(ar->regiontype==RGN_TYPE_WINDOW) 00107 return 1; 00108 } 00109 } 00110 return 0; 00111 } 00112 00113 int weight_paint_mode_poll(bContext *C) 00114 { 00115 Object *ob = CTX_data_active_object(C); 00116 00117 return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totface; 00118 } 00119 00120 int weight_paint_poll(bContext *C) 00121 { 00122 Object *ob= CTX_data_active_object(C); 00123 ScrArea *sa; 00124 00125 if( (ob != NULL) && 00126 (ob->mode & OB_MODE_WEIGHT_PAINT) && 00127 (paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) && 00128 (sa= CTX_wm_area(C)) && 00129 (sa->spacetype == SPACE_VIEW3D) 00130 ) { 00131 ARegion *ar= CTX_wm_region(C); 00132 if(ar->regiontype==RGN_TYPE_WINDOW) { 00133 return 1; 00134 } 00135 } 00136 return 0; 00137 } 00138 00139 static VPaint *new_vpaint(int wpaint) 00140 { 00141 VPaint *vp= MEM_callocN(sizeof(VPaint), "VPaint"); 00142 00143 vp->flag= VP_AREA+VP_SPRAY; 00144 00145 if(wpaint) 00146 vp->flag= VP_AREA; 00147 00148 return vp; 00149 } 00150 00151 static int *get_indexarray(Mesh *me) 00152 { 00153 return MEM_mallocN(sizeof(int)*(me->totface+1), "vertexpaint"); 00154 } 00155 00156 00157 /* in contradiction to cpack drawing colors, the MCOL colors (vpaint colors) are per byte! 00158 so not endian sensitive. Mcol = ABGR!!! so be cautious with cpack calls */ 00159 00160 static unsigned int rgba_to_mcol(float r, float g, float b, float a) 00161 { 00162 int ir, ig, ib, ia; 00163 unsigned int col; 00164 char *cp; 00165 00166 ir= floor(255.0f * r); 00167 if(ir<0) ir= 0; else if(ir>255) ir= 255; 00168 ig= floor(255.0f * g); 00169 if(ig<0) ig= 0; else if(ig>255) ig= 255; 00170 ib= floor(255.0f * b); 00171 if(ib<0) ib= 0; else if(ib>255) ib= 255; 00172 ia= floor(255.0f * a); 00173 if(ia<0) ia= 0; else if(ia>255) ia= 255; 00174 00175 cp= (char *)&col; 00176 cp[0]= ia; 00177 cp[1]= ib; 00178 cp[2]= ig; 00179 cp[3]= ir; 00180 00181 return col; 00182 00183 } 00184 00185 unsigned int vpaint_get_current_col(VPaint *vp) 00186 { 00187 Brush *brush = paint_brush(&vp->paint); 00188 return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f); 00189 } 00190 00191 static void do_shared_vertexcol(Mesh *me) 00192 { 00193 /* if no mcol: do not do */ 00194 /* if tface: only the involved faces, otherwise all */ 00195 MFace *mface; 00196 MTFace *tface; 00197 int a; 00198 short *scolmain, *scol; 00199 char *mcol; 00200 00201 if(me->mcol==NULL || me->totvert==0 || me->totface==0) return; 00202 00203 scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain"); 00204 00205 tface= me->mtface; 00206 mface= me->mface; 00207 mcol= (char *)me->mcol; 00208 for(a=me->totface; a>0; a--, mface++, mcol+=16) { 00209 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) { 00210 scol= scolmain+4*mface->v1; 00211 scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3]; 00212 scol= scolmain+4*mface->v2; 00213 scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7]; 00214 scol= scolmain+4*mface->v3; 00215 scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11]; 00216 if(mface->v4) { 00217 scol= scolmain+4*mface->v4; 00218 scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15]; 00219 } 00220 } 00221 if(tface) tface++; 00222 } 00223 00224 a= me->totvert; 00225 scol= scolmain; 00226 while(a--) { 00227 if(scol[0]>1) { 00228 scol[1]/= scol[0]; 00229 scol[2]/= scol[0]; 00230 scol[3]/= scol[0]; 00231 } 00232 scol+= 4; 00233 } 00234 00235 tface= me->mtface; 00236 mface= me->mface; 00237 mcol= (char *)me->mcol; 00238 for(a=me->totface; a>0; a--, mface++, mcol+=16) { 00239 if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) { 00240 scol= scolmain+4*mface->v1; 00241 mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3]; 00242 scol= scolmain+4*mface->v2; 00243 mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3]; 00244 scol= scolmain+4*mface->v3; 00245 mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3]; 00246 if(mface->v4) { 00247 scol= scolmain+4*mface->v4; 00248 mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3]; 00249 } 00250 } 00251 if(tface) tface++; 00252 } 00253 00254 MEM_freeN(scolmain); 00255 } 00256 00257 static void make_vertexcol(Object *ob) /* single ob */ 00258 { 00259 Mesh *me; 00260 if(!ob || ob->id.lib) return; 00261 me= get_mesh(ob); 00262 if(me==NULL) return; 00263 if(me->edit_mesh) return; 00264 00265 /* copies from shadedisplist to mcol */ 00266 if(!me->mcol) { 00267 CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface); 00268 mesh_update_customdata_pointers(me); 00269 } 00270 00271 //if(shade) 00272 // shadeMeshMCol(scene, ob, me); 00273 //else 00274 00275 memset(me->mcol, 255, 4*sizeof(MCol)*me->totface); 00276 00277 DAG_id_tag_update(&me->id, 0); 00278 00279 } 00280 00281 /* mirror_vgroup is set to -1 when invalid */ 00282 static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) 00283 { 00284 bDeformGroup *defgroup= BLI_findlink(&ob->defbase, vgroup_active); 00285 00286 if(defgroup) { 00287 bDeformGroup *curdef; 00288 int mirrdef; 00289 char name[MAXBONENAME]; 00290 00291 flip_side_name(name, defgroup->name, FALSE); 00292 00293 if(strcmp(name, defgroup->name) != 0) { 00294 for (curdef= ob->defbase.first, mirrdef= 0; curdef; curdef=curdef->next, mirrdef++) { 00295 if (!strcmp(curdef->name, name)) { 00296 break; 00297 } 00298 } 00299 00300 if(curdef==NULL) { 00301 int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ 00302 curdef= ED_vgroup_add_name(ob, name); 00303 ob->actdef= olddef; 00304 } 00305 00306 /* curdef should never be NULL unless this is 00307 * a lamp and ED_vgroup_add_name fails */ 00308 if(curdef) { 00309 return mirrdef; 00310 } 00311 } 00312 } 00313 00314 return -1; 00315 } 00316 00317 static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot) 00318 { 00319 if(vp->vpaint_prev) { 00320 MEM_freeN(vp->vpaint_prev); 00321 vp->vpaint_prev= NULL; 00322 } 00323 vp->tot= tot; 00324 00325 if(mcol==NULL || tot==0) return; 00326 00327 vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev"); 00328 memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot); 00329 00330 } 00331 00332 static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount) 00333 { 00334 if (wp->wpaint_prev) { 00335 free_dverts(wp->wpaint_prev, wp->tot); 00336 wp->wpaint_prev= NULL; 00337 } 00338 00339 if(dverts && dcount) { 00340 00341 wp->wpaint_prev = MEM_mallocN (sizeof(MDeformVert)*dcount, "wpaint prev"); 00342 wp->tot = dcount; 00343 copy_dverts (wp->wpaint_prev, dverts, dcount); 00344 } 00345 } 00346 00347 00348 void vpaint_fill(Object *ob, unsigned int paintcol) 00349 { 00350 Mesh *me; 00351 MFace *mf; 00352 unsigned int *mcol; 00353 int i, selected; 00354 00355 me= get_mesh(ob); 00356 if(me==NULL || me->totface==0) return; 00357 00358 if(!me->mcol) make_vertexcol(ob); 00359 if(!me->mcol) return; /* possible we can't make mcol's */ 00360 00361 00362 selected= (me->editflag & ME_EDIT_PAINT_MASK); 00363 00364 mf = me->mface; 00365 mcol = (unsigned int*)me->mcol; 00366 for (i = 0; i < me->totface; i++, mf++, mcol+=4) { 00367 if (!selected || mf->flag & ME_FACE_SEL) { 00368 mcol[0] = paintcol; 00369 mcol[1] = paintcol; 00370 mcol[2] = paintcol; 00371 mcol[3] = paintcol; 00372 } 00373 } 00374 00375 DAG_id_tag_update(&me->id, 0); 00376 } 00377 00378 00379 /* fills in the selected faces with the current weight and vertex group */ 00380 void wpaint_fill(VPaint *wp, Object *ob, float paintweight) 00381 { 00382 Mesh *me= ob->data; 00383 MFace *mf; 00384 MDeformWeight *dw, *dw_prev; 00385 int vgroup_active, vgroup_mirror= -1; 00386 unsigned int index; 00387 00388 /* mutually exclusive, could be made into a */ 00389 const short paint_selmode= ME_EDIT_PAINT_SEL_MODE(me); 00390 00391 if(me->totface==0 || me->dvert==NULL || !me->mface) return; 00392 00393 vgroup_active = ob->actdef - 1; 00394 00395 /* if mirror painting, find the other group */ 00396 if(me->editflag & ME_EDIT_MIRROR_X) { 00397 vgroup_mirror= wpaint_mirror_vgroup_ensure(ob, vgroup_active); 00398 } 00399 00400 copy_wpaint_prev(wp, me->dvert, me->totvert); 00401 00402 for(index=0, mf= me->mface; index < me->totface; index++, mf++) { 00403 unsigned int fidx= mf->v4 ? 3:2; 00404 00405 if ((paint_selmode == SCE_SELECT_FACE) && !(mf->flag & ME_FACE_SEL)) { 00406 continue; 00407 } 00408 00409 do { 00410 unsigned int vidx= *(&mf->v1 + fidx); 00411 00412 if(!me->dvert[vidx].flag) { 00413 if((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) { 00414 continue; 00415 } 00416 00417 dw= defvert_verify_index(&me->dvert[vidx], vgroup_active); 00418 if(dw) { 00419 dw_prev= defvert_verify_index(wp->wpaint_prev+vidx, vgroup_active); 00420 dw_prev->weight= dw->weight; /* set the undo weight */ 00421 dw->weight= paintweight; 00422 00423 if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ 00424 int j= mesh_get_x_mirror_vert(ob, vidx); 00425 if(j>=0) { 00426 /* copy, not paint again */ 00427 if(vgroup_mirror != -1) { 00428 dw= defvert_verify_index(me->dvert+j, vgroup_mirror); 00429 dw_prev= defvert_verify_index(wp->wpaint_prev+j, vgroup_mirror); 00430 } else { 00431 dw= defvert_verify_index(me->dvert+j, vgroup_active); 00432 dw_prev= defvert_verify_index(wp->wpaint_prev+j, vgroup_active); 00433 } 00434 dw_prev->weight= dw->weight; /* set the undo weight */ 00435 dw->weight= paintweight; 00436 } 00437 } 00438 } 00439 me->dvert[vidx].flag= 1; 00440 } 00441 00442 } while (fidx--); 00443 } 00444 00445 { 00446 MDeformVert *dv= me->dvert; 00447 for(index= me->totvert; index != 0; index--, dv++) { 00448 dv->flag= 0; 00449 } 00450 } 00451 00452 copy_wpaint_prev(wp, NULL, 0); 00453 00454 DAG_id_tag_update(&me->id, 0); 00455 } 00456 00457 /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator 00458 00459 void vpaint_dogamma(Scene *scene) 00460 { 00461 VPaint *vp= scene->toolsettings->vpaint; 00462 Mesh *me; 00463 Object *ob; 00464 float igam, fac; 00465 int a, temp; 00466 unsigned char *cp, gamtab[256]; 00467 00468 ob= OBACT; 00469 me= get_mesh(ob); 00470 00471 if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return; 00472 if(me==0 || me->mcol==0 || me->totface==0) return; 00473 00474 igam= 1.0/vp->gamma; 00475 for(a=0; a<256; a++) { 00476 00477 fac= ((float)a)/255.0; 00478 fac= vp->mul*pow( fac, igam); 00479 00480 temp= 255.9*fac; 00481 00482 if(temp<=0) gamtab[a]= 0; 00483 else if(temp>=255) gamtab[a]= 255; 00484 else gamtab[a]= temp; 00485 } 00486 00487 a= 4*me->totface; 00488 cp= (unsigned char *)me->mcol; 00489 while(a--) { 00490 00491 cp[1]= gamtab[ cp[1] ]; 00492 cp[2]= gamtab[ cp[2] ]; 00493 cp[3]= gamtab[ cp[3] ]; 00494 00495 cp+= 4; 00496 } 00497 } 00498 */ 00499 00500 static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac) 00501 { 00502 char *cp1, *cp2, *cp; 00503 int mfac; 00504 unsigned int col=0; 00505 00506 if(fac==0) return col1; 00507 if(fac>=255) return col2; 00508 00509 mfac= 255-fac; 00510 00511 cp1= (char *)&col1; 00512 cp2= (char *)&col2; 00513 cp= (char *)&col; 00514 00515 cp[0]= 255; 00516 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 00517 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 00518 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 00519 00520 return col; 00521 } 00522 00523 static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac) 00524 { 00525 char *cp1, *cp2, *cp; 00526 int temp; 00527 unsigned int col=0; 00528 00529 if(fac==0) return col1; 00530 00531 cp1= (char *)&col1; 00532 cp2= (char *)&col2; 00533 cp= (char *)&col; 00534 00535 cp[0]= 255; 00536 temp= cp1[1] + ((fac*cp2[1])/255); 00537 if(temp>254) cp[1]= 255; else cp[1]= temp; 00538 temp= cp1[2] + ((fac*cp2[2])/255); 00539 if(temp>254) cp[2]= 255; else cp[2]= temp; 00540 temp= cp1[3] + ((fac*cp2[3])/255); 00541 if(temp>254) cp[3]= 255; else cp[3]= temp; 00542 00543 return col; 00544 } 00545 00546 static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac) 00547 { 00548 char *cp1, *cp2, *cp; 00549 int temp; 00550 unsigned int col=0; 00551 00552 if(fac==0) return col1; 00553 00554 cp1= (char *)&col1; 00555 cp2= (char *)&col2; 00556 cp= (char *)&col; 00557 00558 cp[0]= 255; 00559 temp= cp1[1] - ((fac*cp2[1])/255); 00560 if(temp<0) cp[1]= 0; else cp[1]= temp; 00561 temp= cp1[2] - ((fac*cp2[2])/255); 00562 if(temp<0) cp[2]= 0; else cp[2]= temp; 00563 temp= cp1[3] - ((fac*cp2[3])/255); 00564 if(temp<0) cp[3]= 0; else cp[3]= temp; 00565 00566 return col; 00567 } 00568 00569 static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac) 00570 { 00571 char *cp1, *cp2, *cp; 00572 int mfac; 00573 unsigned int col=0; 00574 00575 if(fac==0) return col1; 00576 00577 mfac= 255-fac; 00578 00579 cp1= (char *)&col1; 00580 cp2= (char *)&col2; 00581 cp= (char *)&col; 00582 00583 /* first mul, then blend the fac */ 00584 cp[0]= 255; 00585 cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255) )/255; 00586 cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255) )/255; 00587 cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255) )/255; 00588 00589 00590 return col; 00591 } 00592 00593 static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac) 00594 { 00595 char *cp1, *cp2, *cp; 00596 int mfac; 00597 unsigned int col=0; 00598 00599 if(fac==0) return col1; 00600 if(fac>=255) return col2; 00601 00602 mfac= 255-fac; 00603 00604 cp1= (char *)&col1; 00605 cp2= (char *)&col2; 00606 cp= (char *)&col; 00607 00608 /* See if are lighter, if so mix, else dont do anything. 00609 if the paint col is darker then the original, then ignore */ 00610 if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3]) 00611 return col1; 00612 00613 cp[0]= 255; 00614 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 00615 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 00616 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 00617 00618 return col; 00619 } 00620 00621 static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac) 00622 { 00623 char *cp1, *cp2, *cp; 00624 int mfac; 00625 unsigned int col=0; 00626 00627 if(fac==0) return col1; 00628 if(fac>=255) return col2; 00629 00630 mfac= 255-fac; 00631 00632 cp1= (char *)&col1; 00633 cp2= (char *)&col2; 00634 cp= (char *)&col; 00635 00636 /* See if were darker, if so mix, else dont do anything. 00637 if the paint col is brighter then the original, then ignore */ 00638 if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3]) 00639 return col1; 00640 00641 cp[0]= 255; 00642 cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; 00643 cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; 00644 cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; 00645 return col; 00646 } 00647 00648 /* wpaint has 'wpaint_blend_tool' */ 00649 static unsigned int vpaint_blend_tool(const int tool, const unsigned int col, 00650 const unsigned int paintcol, const int alpha_i) 00651 { 00652 switch (tool) { 00653 case PAINT_BLEND_MIX: 00654 case PAINT_BLEND_BLUR: 00655 return mcol_blend(col, paintcol, alpha_i); 00656 case PAINT_BLEND_ADD: 00657 return mcol_add(col, paintcol, alpha_i); 00658 case PAINT_BLEND_SUB: 00659 return mcol_sub(col, paintcol, alpha_i); 00660 case PAINT_BLEND_MUL: 00661 return mcol_mul(col, paintcol, alpha_i); 00662 case PAINT_BLEND_LIGHTEN: 00663 return mcol_lighten(col, paintcol, alpha_i); 00664 case PAINT_BLEND_DARKEN: 00665 return mcol_darken(col, paintcol, alpha_i); 00666 default: 00667 BLI_assert(0); 00668 return 0; 00669 } 00670 } 00671 00672 /* wpaint has 'wpaint_blend' */ 00673 static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colorig, const 00674 unsigned int paintcol, const int alpha_i, 00675 /* pre scaled from [0-1] --> [0-255] */ 00676 const int brush_alpha_value_i) 00677 { 00678 Brush *brush = paint_brush(&vp->paint); 00679 const int tool = brush->vertexpaint_tool; 00680 00681 col = vpaint_blend_tool(tool, col, paintcol, alpha_i); 00682 00683 /* if no spray, clip color adding with colorig & orig alpha */ 00684 if((vp->flag & VP_SPRAY)==0) { 00685 unsigned int testcol, a; 00686 char *cp, *ct, *co; 00687 00688 testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i); 00689 00690 cp= (char *)&col; 00691 ct= (char *)&testcol; 00692 co= (char *)&colorig; 00693 00694 for(a=0; a<4; a++) { 00695 if( ct[a]<co[a] ) { 00696 if( cp[a]<ct[a] ) cp[a]= ct[a]; 00697 else if( cp[a]>co[a] ) cp[a]= co[a]; 00698 } 00699 else { 00700 if( cp[a]<co[a] ) cp[a]= co[a]; 00701 else if( cp[a]>ct[a] ) cp[a]= ct[a]; 00702 } 00703 } 00704 } 00705 00706 return col; 00707 } 00708 00709 00710 static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size) 00711 { 00712 struct ImBuf *ibuf; 00713 int a, tot=0, index; 00714 00715 /* brecht: disabled this because it obviously failes for 00716 brushes with size > 64, why is this here? */ 00717 /*if(size>64.0) size= 64.0;*/ 00718 00719 ibuf= view3d_read_backbuf(vc, x-size, y-size, x+size, y+size); 00720 if(ibuf) { 00721 unsigned int *rt= ibuf->rect; 00722 00723 memset(indexar, 0, sizeof(int)*(totface+1)); 00724 00725 size= ibuf->x*ibuf->y; 00726 while(size--) { 00727 00728 if(*rt) { 00729 index= WM_framebuffer_to_index(*rt); 00730 if(index>0 && index<=totface) 00731 indexar[index] = 1; 00732 } 00733 00734 rt++; 00735 } 00736 00737 for(a=1; a<=totface; a++) { 00738 if(indexar[a]) indexar[tot++]= a; 00739 } 00740 00741 IMB_freeImBuf(ibuf); 00742 } 00743 00744 return tot; 00745 } 00746 00747 /* whats _dl mean? */ 00748 static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float *vert_nor, 00749 const float mval[2], const float brush_size_pressure) 00750 { 00751 Brush *brush = paint_brush(&vp->paint); 00752 float dist_squared; 00753 float vertco[2], delta[2]; 00754 00755 project_float_noclip(vc->ar, vert_nor, vertco); 00756 sub_v2_v2v2(delta, mval, vertco); 00757 dist_squared= dot_v2v2(delta, delta); /* len squared */ 00758 if (dist_squared > brush_size_pressure * brush_size_pressure) { 00759 return 0.0f; 00760 } 00761 else { 00762 const float dist = sqrtf(dist_squared); 00763 return brush_curve_strength_clamp(brush, dist, brush_size_pressure); 00764 } 00765 } 00766 00767 static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, 00768 float vpimat[][3], const float *vert_nor, 00769 const float mval[2], 00770 const float brush_size_pressure, const float brush_alpha_pressure) 00771 { 00772 float strength = calc_vp_strength_dl(vp, vc, vert_nor, mval, brush_size_pressure); 00773 00774 if (strength > 0.0f) { 00775 float alpha= brush_alpha_pressure * strength; 00776 00777 if(vp->flag & VP_NORMALS) { 00778 float dvec[3]; 00779 const float *no= vert_nor + 3; 00780 00781 /* transpose ! */ 00782 dvec[2] = dot_v3v3(vpimat[2], no); 00783 if (dvec[2] > 0.0f) { 00784 dvec[0] = dot_v3v3(vpimat[0], no); 00785 dvec[1] = dot_v3v3(vpimat[1], no); 00786 00787 alpha *= dvec[2] / len_v3(dvec); 00788 } 00789 else { 00790 return 0.0f; 00791 } 00792 } 00793 00794 return alpha; 00795 } 00796 00797 return 0.0f; 00798 } 00799 00800 /* vpaint has 'vpaint_blend_tool' */ 00801 /* result is not clamped from [0-1] */ 00802 static float wpaint_blend_tool(const int tool, 00803 /* dw->weight */ 00804 const float weight, 00805 const float paintval, const float alpha) 00806 { 00807 switch (tool) { 00808 case PAINT_BLEND_MIX: 00809 case PAINT_BLEND_BLUR: 00810 return (paintval * alpha) + (weight * (1.0f - alpha)); 00811 case PAINT_BLEND_ADD: 00812 return (paintval * alpha) + weight; 00813 case PAINT_BLEND_SUB: 00814 return (paintval * alpha) - weight; 00815 case PAINT_BLEND_MUL: 00816 /* first mul, then blend the fac */ 00817 return ((1.0f - alpha) + alpha * paintval) * weight; 00818 case PAINT_BLEND_LIGHTEN: 00819 return (weight < paintval) ? (paintval * alpha) + (weight * (1.0f - alpha)) : weight; 00820 case PAINT_BLEND_DARKEN: 00821 return (weight > paintval) ? (paintval * alpha) + (weight * (1.0f - alpha)) : weight; 00822 default: 00823 BLI_assert(0); 00824 return 0.0f; 00825 } 00826 } 00827 00828 /* vpaint has 'vpaint_blend' */ 00829 static float wpaint_blend(VPaint *wp, float weight, float weight_prev, 00830 const float alpha, float paintval, 00831 const float brush_alpha_value, 00832 const short do_flip, const short do_multipaint_totsel) 00833 { 00834 Brush *brush = paint_brush(&wp->paint); 00835 int tool = brush->vertexpaint_tool; 00836 00837 if (do_flip) { 00838 switch(tool) { 00839 case PAINT_BLEND_MIX: 00840 paintval = 1.f - paintval; break; 00841 case PAINT_BLEND_ADD: 00842 tool= PAINT_BLEND_SUB; break; 00843 case PAINT_BLEND_SUB: 00844 tool= PAINT_BLEND_ADD; break; 00845 case PAINT_BLEND_LIGHTEN: 00846 tool= PAINT_BLEND_DARKEN; break; 00847 case PAINT_BLEND_DARKEN: 00848 tool= PAINT_BLEND_LIGHTEN; break; 00849 } 00850 } 00851 00852 weight = wpaint_blend_tool(tool, weight, paintval, alpha); 00853 00854 /* delay clamping until the end so multi-paint can function when the active group is at the limits */ 00855 if(do_multipaint_totsel == FALSE) { 00856 CLAMP(weight, 0.0f, 1.0f); 00857 } 00858 00859 /* if no spray, clip result with orig weight & orig alpha */ 00860 if ((wp->flag & VP_SPRAY) == 0) { 00861 if(do_multipaint_totsel == FALSE) { 00862 float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value); 00863 00864 CLAMP(testw, 0.0f, 1.0f); 00865 if (testw < weight_prev) { 00866 if(weight < testw) weight = testw; 00867 else if(weight > weight_prev) weight = weight_prev; 00868 } 00869 else { 00870 if (weight > testw) weight = testw; 00871 else if (weight < weight_prev) weight = weight_prev; 00872 } 00873 } 00874 } 00875 00876 return weight; 00877 } 00878 00879 /* ----------------------------------------------------- */ 00880 00881 00882 /* sets wp->weight to the closest weight value to vertex */ 00883 /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ 00884 static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) 00885 { 00886 ViewContext vc; 00887 Mesh *me; 00888 short change= FALSE; 00889 00890 view3d_set_viewcontext(C, &vc); 00891 me= get_mesh(vc.obact); 00892 00893 if (me && me->dvert && vc.v3d && vc.rv3d) { 00894 int index; 00895 00896 view3d_operator_needs_opengl(C); 00897 00898 index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]); 00899 00900 if(index && index<=me->totface) { 00901 DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH); 00902 00903 if(dm->getVertCo==NULL) { 00904 BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); 00905 } 00906 else { 00907 MFace *mf= ((MFace *)me->mface) + index-1; 00908 const int vgroup_active= vc.obact->actdef - 1; 00909 ToolSettings *ts= vc.scene->toolsettings; 00910 float mval_f[2]; 00911 int v_idx_best= -1; 00912 int fidx; 00913 float len_best= FLT_MAX; 00914 00915 mval_f[0]= (float)event->mval[0]; 00916 mval_f[1]= (float)event->mval[1]; 00917 00918 fidx= mf->v4 ? 3:2; 00919 do { 00920 float co[3], sco[3], len; 00921 const int v_idx= (*(&mf->v1 + fidx)); 00922 dm->getVertCo(dm, v_idx, co); 00923 project_float_noclip(vc.ar, co, sco); 00924 len= len_squared_v2v2(mval_f, sco); 00925 if(len < len_best) { 00926 len_best= len; 00927 v_idx_best= v_idx; 00928 } 00929 } while (fidx--); 00930 00931 if(v_idx_best != -1) { /* should always be valid */ 00932 ts->vgroup_weight= defvert_find_weight(&me->dvert[v_idx_best], vgroup_active); 00933 change= TRUE; 00934 } 00935 } 00936 dm->release(dm); 00937 } 00938 } 00939 00940 if(change) { 00941 /* not really correct since the brush didnt change, but redraws the toolbar */ 00942 WM_main_add_notifier(NC_BRUSH|NA_EDITED, NULL); /* ts->wpaint->paint.brush */ 00943 00944 return OPERATOR_FINISHED; 00945 } 00946 else { 00947 return OPERATOR_CANCELLED; 00948 } 00949 } 00950 00951 void PAINT_OT_weight_sample(wmOperatorType *ot) 00952 { 00953 /* identifiers */ 00954 ot->name= "Weight Paint Sample Weight"; 00955 ot->idname= "PAINT_OT_weight_sample"; 00956 00957 /* api callbacks */ 00958 ot->invoke= weight_sample_invoke; 00959 ot->poll= weight_paint_mode_poll; 00960 00961 /* flags */ 00962 ot->flag= OPTYPE_UNDO; 00963 } 00964 00965 /* samples cursor location, and gives menu with vertex groups to activate */ 00966 static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 00967 { 00968 if (C) { 00969 wmWindow *win= CTX_wm_window(C); 00970 if(win && win->eventstate) { 00971 ViewContext vc; 00972 Mesh *me; 00973 00974 view3d_set_viewcontext(C, &vc); 00975 me= get_mesh(vc.obact); 00976 00977 if (me && me->dvert && vc.v3d && vc.rv3d) { 00978 int index; 00979 00980 view3d_operator_needs_opengl(C); 00981 00982 index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin); 00983 00984 if(index && index<=me->totface) { 00985 const int defbase_tot= BLI_countlist(&vc.obact->defbase); 00986 if(defbase_tot) { 00987 MFace *mf= ((MFace *)me->mface) + index-1; 00988 unsigned int fidx= mf->v4 ? 3:2; 00989 int *groups= MEM_callocN(defbase_tot*sizeof(int), "groups"); 00990 int found= FALSE; 00991 00992 do { 00993 MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx)); 00994 int i= dvert->totweight; 00995 MDeformWeight *dw; 00996 for(dw= dvert->dw; i > 0; dw++, i--) { 00997 if (dw->def_nr < defbase_tot) { 00998 groups[dw->def_nr]= TRUE; 00999 found= TRUE; 01000 } 01001 } 01002 } while (fidx--); 01003 01004 if(found==FALSE) { 01005 MEM_freeN(groups); 01006 } 01007 else { 01008 EnumPropertyItem *item= NULL, item_tmp= {0}; 01009 int totitem= 0; 01010 int i= 0; 01011 bDeformGroup *dg; 01012 for(dg= vc.obact->defbase.first; dg && i<defbase_tot; i++, dg= dg->next) { 01013 if(groups[i]) { 01014 item_tmp.identifier= item_tmp.name= dg->name; 01015 item_tmp.value= i; 01016 RNA_enum_item_add(&item, &totitem, &item_tmp); 01017 } 01018 } 01019 01020 RNA_enum_item_end(&item, &totitem); 01021 *free= 1; 01022 01023 MEM_freeN(groups); 01024 return item; 01025 } 01026 } 01027 } 01028 } 01029 } 01030 } 01031 01032 return DummyRNA_NULL_items; 01033 } 01034 01035 static int weight_sample_group_exec(bContext *C, wmOperator *op) 01036 { 01037 int type= RNA_enum_get(op->ptr, "group"); 01038 ViewContext vc; 01039 view3d_set_viewcontext(C, &vc); 01040 01041 BLI_assert(type + 1 >= 0); 01042 vc.obact->actdef= type + 1; 01043 01044 DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA); 01045 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, vc.obact); 01046 return OPERATOR_FINISHED; 01047 } 01048 01049 /* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */ 01050 void PAINT_OT_weight_sample_group(wmOperatorType *ot) 01051 { 01052 PropertyRNA *prop= NULL; 01053 01054 /* identifiers */ 01055 ot->name= "Weight Paint Sample Group"; 01056 ot->idname= "PAINT_OT_weight_sample_group"; 01057 01058 /* api callbacks */ 01059 ot->exec= weight_sample_group_exec; 01060 ot->invoke= WM_menu_invoke; 01061 ot->poll= weight_paint_mode_poll; 01062 01063 /* flags */ 01064 ot->flag= OPTYPE_UNDO; 01065 01066 /* keyingset to use (dynamic enum) */ 01067 prop= RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); 01068 RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); 01069 ot->prop= prop; 01070 } 01071 01072 static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const char *vgroup_validmap) 01073 { 01074 float sum= 0.0f, fac; 01075 unsigned int i, tot=0; 01076 MDeformWeight *dw; 01077 01078 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01079 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) { 01080 tot++; 01081 sum += dw->weight; 01082 } 01083 } 01084 01085 if ((tot == 0) || (sum == 1.0f)) { 01086 return; 01087 } 01088 01089 if (sum != 0.0f) { 01090 fac= 1.0f / sum; 01091 01092 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01093 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) { 01094 dw->weight *= fac; 01095 } 01096 } 01097 } 01098 else { 01099 /* hrmf, not a factor in this case */ 01100 fac = 1.0f / tot; 01101 01102 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01103 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) { 01104 dw->weight = fac; 01105 } 01106 } 01107 } 01108 } 01109 01110 /* same as function above except it normalizes against the active vgroup which remains unchanged 01111 * 01112 * note that the active is just the group which is unchanged, it can be any, 01113 * can also be -1 to normalize all but in that case call 'do_weight_paint_normalize_all' */ 01114 static void do_weight_paint_normalize_all_active(MDeformVert *dvert, const int defbase_tot, const char *vgroup_validmap, 01115 const int vgroup_active) 01116 { 01117 float sum= 0.0f, fac; 01118 unsigned int i, tot=0; 01119 MDeformWeight *dw; 01120 float act_weight = 0.0f; 01121 01122 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01123 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) { 01124 if (dw->def_nr != vgroup_active) { 01125 sum += dw->weight; 01126 tot++; 01127 } 01128 else { 01129 act_weight = dw->weight; 01130 } 01131 } 01132 } 01133 01134 if ((tot == 0) || (sum + act_weight == 1.0f)) { 01135 return; 01136 } 01137 01138 if (sum != 0.0f) { 01139 fac = (1.0f / sum) * (1.0f - act_weight); 01140 01141 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01142 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) { 01143 if (dw->def_nr != vgroup_active) { 01144 dw->weight *= fac; 01145 01146 /* paranoid but possibly with float error */ 01147 CLAMP(dw->weight, 0.0f, 1.0f); 01148 } 01149 } 01150 } 01151 } 01152 else { 01153 /* corner case where we need to scale all weights evenly because they're all zero */ 01154 01155 /* hrmf, not a factor in this case */ 01156 fac = (1.0f - act_weight) / tot; 01157 01158 /* paranoid but possibly with float error */ 01159 CLAMP(fac, 0.0f, 1.0f); 01160 01161 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01162 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) { 01163 if (dw->def_nr != vgroup_active) { 01164 dw->weight = fac; 01165 } 01166 } 01167 } 01168 } 01169 } 01170 01171 /* 01172 See if the current deform vertex has a locked group 01173 */ 01174 static char has_locked_group(MDeformVert *dvert, const int defbase_tot, 01175 const char *bone_groups, const char *lock_flags) 01176 { 01177 int i; 01178 MDeformWeight *dw; 01179 01180 for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) { 01181 if (dw->def_nr < defbase_tot) { 01182 if (bone_groups[dw->def_nr] && lock_flags[dw->def_nr] && dw->weight > 0.0f) { 01183 return TRUE; 01184 } 01185 } 01186 } 01187 return FALSE; 01188 } 01189 /* 01190 * gen_lck_flags gets the status of "flag" for each bDeformGroup 01191 *in ob->defbase and returns an array containing them 01192 */ 01193 static char *gen_lock_flags(Object* ob, int defbase_tot) 01194 { 01195 char is_locked = FALSE; 01196 int i; 01197 //int defbase_tot = BLI_countlist(&ob->defbase); 01198 char *lock_flags = MEM_mallocN(defbase_tot*sizeof(char), "defflags"); 01199 bDeformGroup *defgroup; 01200 01201 for(i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) { 01202 lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0); 01203 is_locked |= lock_flags[i]; 01204 } 01205 if (is_locked) { 01206 return lock_flags; 01207 } 01208 01209 MEM_freeN(lock_flags); 01210 return NULL; 01211 } 01212 01213 static int has_locked_group_selected(int defbase_tot, const char *defbase_sel, const char *lock_flags) 01214 { 01215 int i; 01216 for(i = 0; i < defbase_tot; i++) { 01217 if(defbase_sel[i] && lock_flags[i]) { 01218 return TRUE; 01219 } 01220 } 01221 return FALSE; 01222 } 01223 01224 01225 #if 0 /* UNUSED */ 01226 static int has_unselected_unlocked_bone_group(int defbase_tot, char *defbase_sel, int selected, char *lock_flags, char *vgroup_validmap) 01227 { 01228 int i; 01229 if(defbase_tot == selected) { 01230 return FALSE; 01231 } 01232 for(i = 0; i < defbase_tot; i++) { 01233 if(vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) { 01234 return TRUE; 01235 } 01236 } 01237 return FALSE; 01238 } 01239 #endif 01240 01241 01242 static void multipaint_selection(MDeformVert *dvert, const int defbase_tot, float change, const char *defbase_sel) 01243 { 01244 int i; 01245 MDeformWeight *dw; 01246 float val; 01247 /* make sure they are all at most 1 after the change */ 01248 for(i = 0; i < defbase_tot; i++) { 01249 if(defbase_sel[i]) { 01250 dw = defvert_find_index(dvert, i); 01251 if(dw && dw->weight) { 01252 val = dw->weight * change; 01253 if(val > 1) { 01254 /* TODO: when the change is reduced, you need to recheck 01255 * the earlier values to make sure they are not 0 01256 * (precision error) */ 01257 change = 1.0f/dw->weight; 01258 } 01259 /* the value should never reach zero while multi-painting if it 01260 * was nonzero beforehand */ 01261 if(val <= 0) { 01262 return; 01263 } 01264 } 01265 } 01266 } 01267 /* apply the valid change */ 01268 for(i = 0; i < defbase_tot; i++) { 01269 if(defbase_sel[i]) { 01270 dw = defvert_find_index(dvert, i); 01271 if(dw && dw->weight) { 01272 dw->weight = dw->weight * change; 01273 } 01274 } 01275 } 01276 } 01277 01278 /* move all change onto valid, unchanged groups. If there is change left over, 01279 * then return it. 01280 * assumes there are valid groups to shift weight onto */ 01281 static float redistribute_change(MDeformVert *ndv, const int defbase_tot, 01282 char *change_status, const char change_me, int changeto, 01283 float totchange, float total_valid, 01284 char do_auto_normalize) 01285 { 01286 float was_change; 01287 float change; 01288 float oldval; 01289 MDeformWeight *ndw; 01290 int i; 01291 do { 01292 /* assume there is no change until you see one */ 01293 was_change = FALSE; 01294 /* change each group by the same amount each time */ 01295 change = totchange/total_valid; 01296 for(i = 0; i < ndv->totweight && total_valid && totchange; i++) { 01297 ndw = (ndv->dw+i); 01298 01299 /* ignore anything outside the value range */ 01300 if (ndw->def_nr < defbase_tot) { 01301 01302 /* change only the groups with a valid status */ 01303 if(change_status[ndw->def_nr] == change_me) { 01304 oldval = ndw->weight; 01305 /* if auto normalize is active, don't worry about upper bounds */ 01306 if(do_auto_normalize == FALSE && ndw->weight + change > 1) { 01307 totchange -= 1-ndw->weight; 01308 ndw->weight = 1; 01309 /* stop the changes to this group */ 01310 change_status[ndw->def_nr] = changeto; 01311 total_valid--; 01312 } 01313 else if(ndw->weight + change < 0) { /* check the lower bound */ 01314 totchange -= ndw->weight; 01315 ndw->weight = 0; 01316 change_status[ndw->def_nr] = changeto; 01317 total_valid--; 01318 } 01319 else {/* a perfectly valid change occurred to ndw->weight */ 01320 totchange -= change; 01321 ndw->weight += change; 01322 } 01323 /* see if there was a change */ 01324 if(oldval != ndw->weight) { 01325 was_change = TRUE; 01326 } 01327 } 01328 } 01329 } 01330 /* don't go again if there was no change, if there is no valid group, 01331 * or there is no change left */ 01332 } while(was_change && total_valid && totchange); 01333 /* left overs */ 01334 return totchange; 01335 } 01336 static float get_mp_change(MDeformVert *odv, const int defbase_tot, const char *defbase_sel, float brush_change); 01337 /* observe the changes made to the weights of groups. 01338 * make sure all locked groups on the vertex have the same deformation 01339 * by moving the changes made to groups onto other unlocked groups */ 01340 static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, 01341 const int defbase_tot, const char *defbase_sel, 01342 const char *lock_flags, const char *vgroup_validmap, 01343 char do_auto_normalize, char do_multipaint) 01344 { 01345 float totchange = 0.0f; 01346 float totchange_allowed = 0.0f; 01347 float left_over; 01348 01349 int total_valid = 0; 01350 int total_changed = 0; 01351 unsigned int i; 01352 MDeformWeight *ndw; 01353 MDeformWeight *odw; 01354 01355 float changed_sum = 0.0f; 01356 01357 char *change_status; 01358 01359 if(!lock_flags || !has_locked_group(ndv, defbase_tot, vgroup_validmap, lock_flags)) { 01360 return; 01361 } 01362 /* record if a group was changed, unlocked and not changed, or locked */ 01363 change_status = MEM_callocN(sizeof(char)*defbase_tot, "unlocked_unchanged"); 01364 01365 for(i = 0; i < defbase_tot; i++) { 01366 ndw = defvert_find_index(ndv, i); 01367 odw = defvert_find_index(odv, i); 01368 /* the weights are zero, so we can assume a lot */ 01369 if(!ndw || !odw) { 01370 if (!lock_flags[i] && vgroup_validmap[i]) { 01371 defvert_verify_index(odv, i); 01372 defvert_verify_index(ndv, i); 01373 total_valid++; 01374 change_status[i] = 1; /* can be altered while redistributing */ 01375 } 01376 continue; 01377 } 01378 /* locked groups should not be changed */ 01379 if(lock_flags[i]) { 01380 ndw->weight = odw->weight; 01381 } 01382 else if(ndw->weight != odw->weight) { /* changed groups are handled here */ 01383 totchange += ndw->weight - odw->weight; 01384 changed_sum += ndw->weight; 01385 change_status[i] = 2; /* was altered already */ 01386 total_changed++; 01387 } /* unchanged, unlocked bone groups are handled here */ 01388 else if (vgroup_validmap[i]) { 01389 totchange_allowed += ndw->weight; 01390 total_valid++; 01391 change_status[i] = 1; /* can be altered while redistributing */ 01392 } 01393 } 01394 /* if there was any change, redistribute it */ 01395 if(total_changed) { 01396 /* auto normalize will allow weights to temporarily go above 1 in redistribution */ 01397 if(vgroup_validmap && total_changed < 0 && total_valid) { 01398 totchange_allowed = total_valid; 01399 } 01400 /* the way you modify the unlocked+unchanged groups is different depending 01401 * on whether or not you are painting the weight(s) up or down */ 01402 if(totchange < 0) { 01403 totchange_allowed = total_valid - totchange_allowed; 01404 } 01405 else { 01406 totchange_allowed *= -1; 01407 } 01408 /* there needs to be change allowed, or you should not bother */ 01409 if(totchange_allowed) { 01410 left_over = 0; 01411 if(fabsf(totchange_allowed) < fabsf(totchange)) { 01412 /* this amount goes back onto the changed, unlocked weights */ 01413 left_over = fabsf(fabsf(totchange) - fabsf(totchange_allowed)); 01414 if(totchange > 0) { 01415 left_over *= -1; 01416 } 01417 } 01418 else { 01419 /* all of the change will be permitted */ 01420 totchange_allowed = -totchange; 01421 } 01422 /* move the weight evenly between the allowed groups, move excess back onto the used groups based on the change */ 01423 totchange_allowed = redistribute_change(ndv, defbase_tot, change_status, 1, -1, totchange_allowed, total_valid, do_auto_normalize); 01424 left_over += totchange_allowed; 01425 if(left_over) { 01426 /* more than one nonzero weights were changed with the same ratio with multipaint, so keep them changed that way! */ 01427 if(total_changed > 1 && do_multipaint) { 01428 float undo_change = get_mp_change(ndv, defbase_tot, defbase_sel, left_over); 01429 multipaint_selection(ndv, defbase_tot, undo_change, defbase_sel); 01430 } 01431 /* or designatedw is still -1 put weight back as evenly as possible */ 01432 else { 01433 redistribute_change(ndv, defbase_tot, change_status, 2, -2, left_over, total_changed, do_auto_normalize); 01434 } 01435 } 01436 } 01437 else { 01438 /* reset the weights */ 01439 unsigned int i; 01440 MDeformWeight *dw_old= odv->dw; 01441 MDeformWeight *dw_new= ndv->dw; 01442 01443 for (i= odv->totweight; i != 0; i--, dw_old++, dw_new++) { 01444 dw_new->weight= dw_old->weight; 01445 } 01446 } 01447 } 01448 01449 MEM_freeN(change_status); 01450 } 01451 01452 /* multi-paint's initial, potential change is computed here based on the user's stroke */ 01453 static float get_mp_change(MDeformVert *odv, const int defbase_tot, const char *defbase_sel, float brush_change) 01454 { 01455 float selwsum = 0.0f; 01456 unsigned int i; 01457 MDeformWeight *dw= odv->dw; 01458 01459 for (i= odv->totweight; i != 0; i--, dw++) { 01460 if (dw->def_nr < defbase_tot) { 01461 if(defbase_sel[dw->def_nr]) { 01462 selwsum += dw->weight; 01463 } 01464 } 01465 } 01466 if(selwsum && selwsum+brush_change > 0) { 01467 return (selwsum+brush_change)/selwsum; 01468 } 01469 return 0.0f; 01470 } 01471 01472 /* change the weights back to the wv's weights 01473 * it assumes you already have the correct pointer index */ 01474 static void defvert_reset_to_prev(MDeformVert *dv_prev, MDeformVert *dv) 01475 { 01476 MDeformWeight *dw= dv->dw; 01477 MDeformWeight *dw_prev; 01478 unsigned int i; 01479 for (i= dv->totweight; i != 0; i--, dw++) { 01480 dw_prev= defvert_find_index(dv_prev, dw->def_nr); 01481 /* if there was no w when there is a d, then the old weight was 0 */ 01482 dw->weight = dw_prev ? dw_prev->weight : 0.0f; 01483 } 01484 } 01485 01486 static void clamp_weights(MDeformVert *dvert) 01487 { 01488 MDeformWeight *dw= dvert->dw; 01489 unsigned int i; 01490 for (i= dvert->totweight; i != 0; i--, dw++) { 01491 CLAMP(dw->weight, 0.0f, 1.0f); 01492 } 01493 } 01494 01495 /* struct to avoid passing many args each call to do_weight_paint_vertex() 01496 * this _could_ be made a part of the operators 'WPaintData' struct, or at 01497 * least a member, but for now keep its own struct, initialized on every 01498 * paint stroke update - campbell */ 01499 typedef struct WeightPaintInfo { 01500 01501 int defbase_tot; 01502 01503 /* both must add up to 'defbase_tot' */ 01504 int defbase_tot_sel; 01505 int defbase_tot_unsel; 01506 01507 int vgroup_active; /* (ob->actdef - 1) */ 01508 int vgroup_mirror; /* mirror group or -1 */ 01509 01510 const char *lock_flags; /* boolean array for locked bones, 01511 * length of defbase_tot */ 01512 const char *defbase_sel; /* boolean array for selected bones, 01513 * length of defbase_tot, cant be const because of how its passed */ 01514 01515 const char *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap, 01516 * only added here for convenience */ 01517 01518 char do_flip; 01519 char do_multipaint; 01520 char do_auto_normalize; 01521 01522 float brush_alpha_value; /* result of brush_alpha() */ 01523 } WeightPaintInfo; 01524 01525 /* fresh start to make multi-paint and locking modular */ 01526 /* returns TRUE if it thinks you need to reset the weights due to 01527 * normalizing while multi-painting 01528 * 01529 * note: this assumes dw->def_nr range has been checked by the caller 01530 */ 01531 static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi, 01532 const unsigned int index, 01533 MDeformWeight *dw, MDeformWeight *tdw, 01534 float change, float oldChange, 01535 float oldw, float neww) 01536 { 01537 MDeformVert *dv= &me->dvert[index]; 01538 MDeformVert dv_test= {NULL}; 01539 01540 dv_test.dw= MEM_dupallocN(dv->dw); 01541 dv_test.flag = dv->flag; 01542 dv_test.totweight = dv->totweight; 01543 /* do not multi-paint if a locked group is selected or the active group is locked 01544 * !lock_flags[dw->def_nr] helps if nothing is selected, but active group is locked */ 01545 if ( (wpi->lock_flags == NULL) || 01546 ((wpi->lock_flags[dw->def_nr] == FALSE) && /* def_nr range has to be checked for by caller */ 01547 has_locked_group_selected(wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags) == FALSE)) 01548 { 01549 if(wpi->do_multipaint && wpi->defbase_tot_sel > 1) { 01550 if(change && change!=1) { 01551 multipaint_selection(dv, wpi->defbase_tot, change, wpi->defbase_sel); 01552 } 01553 } 01554 else { /* this lets users paint normally, but don't let them paint locked groups */ 01555 dw->weight = neww; 01556 } 01557 } 01558 clamp_weights(dv); 01559 01560 enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags, wpi->vgroup_validmap, wpi->do_auto_normalize, wpi->do_multipaint); 01561 01562 if (wpi->do_auto_normalize) { 01563 /* XXX - should we pass the active group? - currently '-1' */ 01564 do_weight_paint_normalize_all(dv, wpi->defbase_tot, wpi->vgroup_validmap); 01565 } 01566 01567 if(oldChange && wpi->do_multipaint && wpi->defbase_tot_sel > 1) { 01568 if(tdw->weight != oldw) { 01569 if(neww > oldw) { 01570 if(tdw->weight <= oldw) { 01571 MEM_freeN(dv_test.dw); 01572 return TRUE; 01573 } 01574 } 01575 else { 01576 if(tdw->weight >= oldw) { 01577 MEM_freeN(dv_test.dw); 01578 return TRUE; 01579 } 01580 } 01581 } 01582 } 01583 MEM_freeN(dv_test.dw); 01584 return FALSE; 01585 } 01586 01587 /* within the current dvert index, get the dw that is selected and has a weight 01588 * above 0, this helps multi-paint */ 01589 static int get_first_selected_nonzero_weight(MDeformVert *dvert, const int defbase_tot, const char *defbase_sel) 01590 { 01591 int i; 01592 MDeformWeight *dw= dvert->dw; 01593 for(i=0; i< dvert->totweight; i++, dw++) { 01594 if (dw->def_nr < defbase_tot) { 01595 if (defbase_sel[dw->def_nr] && dw->weight > 0.0f) { 01596 return i; 01597 } 01598 } 01599 } 01600 return -1; 01601 } 01602 01603 01604 static char *wpaint_make_validmap(Object *ob); 01605 01606 01607 static void do_weight_paint_vertex(/* vars which remain the same for every vert */ 01608 VPaint *wp, Object *ob, const WeightPaintInfo *wpi, 01609 /* vars which change on each stroke */ 01610 const unsigned int index, float alpha, float paintweight 01611 ) 01612 { 01613 Mesh *me= ob->data; 01614 MDeformVert *dv= &me->dvert[index]; 01615 01616 MDeformWeight *dw, *dw_prev; 01617 01618 /* mirror vars */ 01619 int index_mirr; 01620 int vgroup_mirr; 01621 01622 MDeformVert *dv_mirr; 01623 MDeformWeight *dw_mirr; 01624 01625 const short do_multipaint_totsel = (wpi->do_multipaint && wpi->defbase_tot_sel > 1); 01626 01627 if(wp->flag & VP_ONLYVGROUP) { 01628 dw= defvert_find_index(dv, wpi->vgroup_active); 01629 dw_prev= defvert_find_index(wp->wpaint_prev+index, wpi->vgroup_active); 01630 } 01631 else { 01632 dw= defvert_verify_index(dv, wpi->vgroup_active); 01633 dw_prev= defvert_verify_index(wp->wpaint_prev+index, wpi->vgroup_active); 01634 } 01635 01636 if(dw==NULL || dw_prev==NULL) { 01637 return; 01638 } 01639 01640 01641 /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */ 01642 if (me->editflag & ME_EDIT_MIRROR_X) { 01643 index_mirr = mesh_get_x_mirror_vert(ob, index); 01644 vgroup_mirr = (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : wpi->vgroup_active; 01645 01646 /* another possible error - mirror group _and_ active group are the same (which is fine), 01647 * but we also are painting onto a center vertex - this would paint the same weight twice */ 01648 if (index_mirr == index && vgroup_mirr == wpi->vgroup_active) { 01649 index_mirr = vgroup_mirr = -1; 01650 } 01651 } 01652 else { 01653 index_mirr = vgroup_mirr = -1; 01654 } 01655 01656 01657 /* get the mirror def vars */ 01658 if (index_mirr != -1) { 01659 dv_mirr = &me->dvert[index_mirr]; 01660 if (wp->flag & VP_ONLYVGROUP) { 01661 dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr); 01662 01663 if (dw_mirr == NULL) { 01664 index_mirr = vgroup_mirr = -1; 01665 dv_mirr = NULL; 01666 } 01667 } 01668 else { 01669 if (index != index_mirr) { 01670 dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr); 01671 } 01672 else { 01673 /* dv and dv_mirr are the same */ 01674 int totweight_prev = dv_mirr->totweight; 01675 int dw_offset = (int)(dw - dv_mirr->dw); 01676 dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr); 01677 01678 /* if we added another, get our old one back */ 01679 if (totweight_prev != dv_mirr->totweight) { 01680 dw = &dv_mirr->dw[dw_offset]; 01681 } 01682 } 01683 } 01684 } 01685 else { 01686 dv_mirr = NULL; 01687 dw_mirr = NULL; 01688 } 01689 01690 01691 /* TODO: De-duplicate the simple weight paint - jason */ 01692 /* ... or not, since its <10 SLOC - campbell */ 01693 01694 /* If there are no locks or multipaint, 01695 * then there is no need to run the more complicated checks */ 01696 if ( (do_multipaint_totsel == FALSE) && 01697 (wpi->lock_flags == NULL || has_locked_group(dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags) == FALSE)) 01698 { 01699 dw->weight = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight, 01700 wpi->brush_alpha_value, wpi->do_flip, FALSE); 01701 01702 /* WATCH IT: take care of the ordering of applying mirror -> normalize, 01703 * can give wrong results [#26193], least confusing if normalize is done last */ 01704 01705 /* apply mirror */ 01706 if(index_mirr != -1) { 01707 /* copy, not paint again */ 01708 dw_mirr->weight = dw->weight; 01709 } 01710 01711 /* apply normalize */ 01712 if (wpi->do_auto_normalize) { 01713 /* note on normalize - this used to be applied after painting and normalize all weights, 01714 * in some ways this is good because there is feedback where the more weights involved would 01715 * 'risist' so you couldn't instantly zero out other weights by painting 1.0 on the active. 01716 * 01717 * However this gave a problem since applying mirror, then normalize both verts 01718 * the resulting weight wont match on both sides. 01719 * 01720 * If this 'resisting', slower normalize is nicer, we could call 01721 * do_weight_paint_normalize_all() and only use... 01722 * do_weight_paint_normalize_all_active() when normalizing the mirror vertex. 01723 * - campbell 01724 */ 01725 do_weight_paint_normalize_all_active(dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->vgroup_active); 01726 01727 if (index_mirr != -1) { 01728 /* only normalize if this is not a center vertex, else we get a conflict, normalizing twice */ 01729 if (index != index_mirr) { 01730 do_weight_paint_normalize_all_active(dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, vgroup_mirr); 01731 } 01732 else { 01733 /* this case accounts for... 01734 * - painting onto a center vertex of a mesh 01735 * - x mirror is enabled 01736 * - auto normalize is enabled 01737 * - the group you are painting onto has a L / R version 01738 * 01739 * We wan't L/R vgroups to have the same weight but this cant be if both are over 0.5, 01740 * We _could_ have special check for that, but this would need its own normalize function which 01741 * holds 2 groups from changing at once. 01742 * 01743 * So! just balance out the 2 weights, it keeps them equal and everything normalized. 01744 * 01745 * While it wont hit the desired weight immediatelty as the user waggles their mouse, 01746 * constant painting and re-normalizing will get there. this is also just simpler logic. 01747 * - campbell */ 01748 dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f; 01749 } 01750 } 01751 } 01752 } 01753 else { 01754 /* use locks and/or multipaint */ 01755 float oldw; 01756 float neww; 01757 float testw=0; 01758 float change = 0; 01759 float oldChange = 0; 01760 int i; 01761 MDeformWeight *tdw = NULL, *tdw_prev; 01762 MDeformVert dv_copy= {NULL}; 01763 01764 oldw = dw->weight; 01765 neww = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight, 01766 wpi->brush_alpha_value, wpi->do_flip, do_multipaint_totsel); 01767 01768 /* setup multi-paint */ 01769 if (do_multipaint_totsel) { 01770 dv_copy.dw= MEM_dupallocN(dv->dw); 01771 dv_copy.flag = dv->flag; 01772 dv_copy.totweight = dv->totweight; 01773 tdw = dw; 01774 tdw_prev = dw_prev; 01775 change = get_mp_change(&wp->wpaint_prev[index], wpi->defbase_tot, wpi->defbase_sel, neww - oldw); 01776 if(change) { 01777 if(!tdw->weight) { 01778 i = get_first_selected_nonzero_weight(dv, wpi->defbase_tot, wpi->defbase_sel); 01779 if(i>=0) { 01780 tdw = &(dv->dw[i]); 01781 tdw_prev = defvert_verify_index(&wp->wpaint_prev[index], tdw->def_nr); 01782 } 01783 else { 01784 change = 0; 01785 } 01786 } 01787 if(change && tdw_prev->weight && tdw_prev->weight * change) { 01788 if(tdw->weight != tdw_prev->weight) { 01789 oldChange = tdw->weight/tdw_prev->weight; 01790 testw = tdw_prev->weight*change; 01791 if( testw > tdw_prev->weight ) { 01792 if(change > oldChange) { 01793 /* reset the weights and use the new change */ 01794 defvert_reset_to_prev(wp->wpaint_prev+index, dv); 01795 } 01796 else { 01797 /* the old change was more significant, so set 01798 * the change to 0 so that it will not do another multi-paint */ 01799 change = 0; 01800 } 01801 } 01802 else { 01803 if(change < oldChange) { 01804 defvert_reset_to_prev(wp->wpaint_prev+index, dv); 01805 } 01806 else { 01807 change = 0; 01808 } 01809 } 01810 } 01811 } 01812 else { 01813 change = 0; 01814 } 01815 } 01816 } 01817 01818 if(apply_mp_locks_normalize(me, wpi, index, dw, tdw, change, oldChange, oldw, neww)) { 01819 defvert_reset_to_prev(&dv_copy, dv); 01820 change = 0; 01821 oldChange = 0; 01822 } 01823 if(dv_copy.dw) { 01824 MEM_freeN(dv_copy.dw); 01825 } 01826 #if 0 01827 /* dv may have been altered greatly */ 01828 dw = defvert_find_index(dv, vgroup); 01829 #else 01830 dw = NULL; /* UNUSED after assignment, set to NULL to ensuyre we don't 01831 * use again, we thats needed un-ifdef the line above */ 01832 (void)dw; /* quiet warnigns */ 01833 #endif 01834 01835 /* x mirror painting */ 01836 if(index_mirr != -1) { 01837 /* copy, not paint again */ 01838 01839 /* dw_mirr->weight = dw->weight; */ /* TODO, explain the logic in not assigning weight! - campbell */ 01840 apply_mp_locks_normalize(me, wpi, index_mirr, dw_mirr, tdw, change, oldChange, oldw, neww); 01841 } 01842 } 01843 } 01844 01845 01846 /* *************** set wpaint operator ****************** */ 01847 01848 static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ 01849 { 01850 Object *ob= CTX_data_active_object(C); 01851 Scene *scene= CTX_data_scene(C); 01852 VPaint *wp= scene->toolsettings->wpaint; 01853 Mesh *me; 01854 01855 me= get_mesh(ob); 01856 if(ob->id.lib || me==NULL) return OPERATOR_PASS_THROUGH; 01857 01858 if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT; 01859 else ob->mode |= OB_MODE_WEIGHT_PAINT; 01860 01861 01862 /* Weightpaint works by overriding colors in mesh, 01863 * so need to make sure we recalc on enter and 01864 * exit (exit needs doing regardless because we 01865 * should redeform). 01866 */ 01867 DAG_id_tag_update(&me->id, 0); 01868 01869 if(ob->mode & OB_MODE_WEIGHT_PAINT) { 01870 Object *par; 01871 01872 if(wp==NULL) 01873 wp= scene->toolsettings->wpaint= new_vpaint(1); 01874 01875 paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); 01876 paint_cursor_start(C, weight_paint_poll); 01877 01878 mesh_octree_table(ob, NULL, NULL, 's'); 01879 01880 /* verify if active weight group is also active bone */ 01881 par= modifiers_isDeformedByArmature(ob); 01882 if(par && (par->mode & OB_MODE_POSE)) { 01883 bArmature *arm= par->data; 01884 01885 if(arm->act_bone) 01886 ED_vgroup_select_by_name(ob, arm->act_bone->name); 01887 } 01888 } 01889 else { 01890 mesh_octree_table(NULL, NULL, NULL, 'e'); 01891 mesh_mirrtopo_table(NULL, 'e'); 01892 } 01893 01894 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); 01895 01896 return OPERATOR_FINISHED; 01897 } 01898 01899 /* for switching to/from mode */ 01900 static int paint_poll_test(bContext *C) 01901 { 01902 Object *ob= CTX_data_active_object(C); 01903 if(CTX_data_edit_object(C)) 01904 return 0; 01905 if(CTX_data_active_object(C)==NULL) 01906 return 0; 01907 if(!ob->data || ((ID *)ob->data)->lib) 01908 return 0; 01909 return 1; 01910 } 01911 01912 void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) 01913 { 01914 01915 /* identifiers */ 01916 ot->name= "Weight Paint Mode"; 01917 ot->idname= "PAINT_OT_weight_paint_toggle"; 01918 01919 /* api callbacks */ 01920 ot->exec= set_wpaint; 01921 ot->poll= paint_poll_test; 01922 01923 /* flags */ 01924 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01925 01926 } 01927 01928 /* ************ weight paint operator ********** */ 01929 01930 struct WPaintData { 01931 ViewContext vc; 01932 int *indexar; 01933 int vgroup_active; 01934 int vgroup_mirror; 01935 float *vertexcosnos; 01936 float wpimat[3][3]; 01937 01938 /*variables for auto normalize*/ 01939 const char *vgroup_validmap; /*stores if vgroups tie to deforming bones or not*/ 01940 const char *lock_flags; 01941 int defbase_tot; 01942 }; 01943 01944 static char *wpaint_make_validmap(Object *ob) 01945 { 01946 bDeformGroup *dg; 01947 ModifierData *md; 01948 char *vgroup_validmap; 01949 GHash *gh; 01950 int i, step1=1; 01951 01952 if(ob->defbase.first == NULL) { 01953 return NULL; 01954 } 01955 01956 gh= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wpaint_make_validmap gh"); 01957 01958 /*add all names to a hash table*/ 01959 for (dg=ob->defbase.first; dg; dg=dg->next) { 01960 BLI_ghash_insert(gh, dg->name, NULL); 01961 } 01962 01963 /*now loop through the armature modifiers and identify deform bones*/ 01964 for (md = ob->modifiers.first; md; md= !md->next && step1 ? (step1=0), modifiers_getVirtualModifierList(ob) : md->next) { 01965 if (!(md->mode & (eModifierMode_Realtime|eModifierMode_Virtual))) 01966 continue; 01967 01968 if (md->type == eModifierType_Armature) { 01969 ArmatureModifierData *amd= (ArmatureModifierData*) md; 01970 01971 if(amd->object && amd->object->pose) { 01972 bPose *pose= amd->object->pose; 01973 bPoseChannel *chan; 01974 01975 for (chan=pose->chanbase.first; chan; chan=chan->next) { 01976 if (chan->bone->flag & BONE_NO_DEFORM) 01977 continue; 01978 01979 if (BLI_ghash_haskey(gh, chan->name)) { 01980 BLI_ghash_remove(gh, chan->name, NULL, NULL); 01981 BLI_ghash_insert(gh, chan->name, SET_INT_IN_POINTER(1)); 01982 } 01983 } 01984 } 01985 } 01986 } 01987 01988 vgroup_validmap= MEM_mallocN(BLI_ghash_size(gh), "wpaint valid map"); 01989 01990 /*add all names to a hash table*/ 01991 for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) { 01992 vgroup_validmap[i]= (BLI_ghash_lookup(gh, dg->name) != NULL); 01993 } 01994 01995 BLI_assert(i == BLI_ghash_size(gh)); 01996 01997 BLI_ghash_free(gh, NULL, NULL); 01998 01999 return vgroup_validmap; 02000 } 02001 02002 static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 02003 { 02004 Scene *scene= CTX_data_scene(C); 02005 struct PaintStroke *stroke = op->customdata; 02006 ToolSettings *ts= scene->toolsettings; 02007 VPaint *wp= ts->wpaint; 02008 Object *ob= CTX_data_active_object(C); 02009 struct WPaintData *wpd; 02010 Mesh *me; 02011 bDeformGroup *dg; 02012 02013 float mat[4][4], imat[4][4]; 02014 02015 if(scene->obedit) { 02016 return FALSE; 02017 } 02018 02019 me= get_mesh(ob); 02020 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; 02021 02022 /* if nothing was added yet, we make dverts and a vertex deform group */ 02023 if (!me->dvert) { 02024 ED_vgroup_data_create(&me->id); 02025 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); 02026 } 02027 02028 /* this happens on a Bone select, when no vgroup existed yet */ 02029 if (ob->actdef <= 0) { 02030 Object *modob; 02031 if((modob = modifiers_isDeformedByArmature(ob))) { 02032 Bone *actbone= ((bArmature *)modob->data)->act_bone; 02033 if(actbone) { 02034 bPoseChannel *pchan= get_pose_channel(modob->pose, actbone->name); 02035 02036 if(pchan) { 02037 bDeformGroup *dg= defgroup_find_name(ob, pchan->name); 02038 if(dg==NULL) { 02039 dg= ED_vgroup_add_name(ob, pchan->name); /* sets actdef */ 02040 } 02041 else { 02042 int actdef = 1 + BLI_findindex(&ob->defbase, dg); 02043 BLI_assert(actdef >= 0); 02044 ob->actdef= actdef; 02045 } 02046 } 02047 } 02048 } 02049 } 02050 if(ob->defbase.first==NULL) { 02051 ED_vgroup_add(ob); 02052 } 02053 02054 /* ensure we dont try paint onto an invalid group */ 02055 if (ob->actdef <= 0) { 02056 BKE_report(op->reports, RPT_WARNING, "No active vertex group for painting, aborting"); 02057 return FALSE; 02058 } 02059 02060 /* check if we are attempting to paint onto a locked vertex group, 02061 * and other options disallow it from doing anything useful */ 02062 dg = BLI_findlink(&ob->defbase, (ob->actdef-1)); 02063 if (dg->flag & DG_LOCK_WEIGHT) { 02064 BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting"); 02065 return FALSE; 02066 } 02067 02068 /* ALLOCATIONS! no return after this line */ 02069 /* make mode data storage */ 02070 wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData"); 02071 paint_stroke_set_mode_data(stroke, wpd); 02072 view3d_set_viewcontext(C, &wpd->vc); 02073 02074 wpd->vgroup_active = ob->actdef - 1; 02075 wpd->vgroup_mirror = -1; 02076 02077 /* set up auto-normalize, and generate map for detecting which 02078 * vgroups affect deform bones*/ 02079 wpd->defbase_tot = BLI_countlist(&ob->defbase); 02080 wpd->lock_flags = gen_lock_flags(ob, wpd->defbase_tot); 02081 if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) { 02082 wpd->vgroup_validmap = wpaint_make_validmap(ob); 02083 } 02084 02085 /* painting on subsurfs should give correct points too, this returns me->totvert amount */ 02086 wpd->vertexcosnos= mesh_get_mapped_verts_nors(scene, ob); 02087 wpd->indexar= get_indexarray(me); 02088 copy_wpaint_prev(wp, me->dvert, me->totvert); 02089 02090 /* imat for normals */ 02091 mult_m4_m4m4(mat, wpd->vc.rv3d->viewmat, ob->obmat); 02092 invert_m4_m4(imat, mat); 02093 copy_m3_m4(wpd->wpimat, imat); 02094 02095 /* if mirror painting, find the other group */ 02096 if(me->editflag & ME_EDIT_MIRROR_X) { 02097 wpd->vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, wpd->vgroup_active); 02098 } 02099 02100 return TRUE; 02101 } 02102 02103 static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) 02104 { 02105 Scene *scene= CTX_data_scene(C); 02106 ToolSettings *ts= CTX_data_tool_settings(C); 02107 VPaint *wp= ts->wpaint; 02108 Brush *brush = paint_brush(&wp->paint); 02109 struct WPaintData *wpd= paint_stroke_mode_data(stroke); 02110 ViewContext *vc; 02111 Object *ob; 02112 Mesh *me; 02113 float mat[4][4]; 02114 float paintweight; 02115 int *indexar; 02116 float totw; 02117 unsigned int index, totindex; 02118 float alpha; 02119 float mval[2]; 02120 int use_vert_sel; 02121 char *defbase_sel; 02122 02123 const float pressure = RNA_float_get(itemptr, "pressure"); 02124 const float brush_size_pressure = brush_size(scene, brush) * (brush_use_size_pressure(scene, brush) ? pressure : 1.0f); 02125 const float brush_alpha_value = brush_alpha(scene, brush); 02126 const float brush_alpha_pressure = brush_alpha_value * (brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f); 02127 02128 /* intentionally dont initialize as NULL, make sure we initialize all members below */ 02129 WeightPaintInfo wpi; 02130 02131 /* cannot paint if there is no stroke data */ 02132 if (wpd == NULL) { 02133 /* XXX: force a redraw here, since even though we can't paint, 02134 * at least view won't freeze until stroke ends */ 02135 ED_region_tag_redraw(CTX_wm_region(C)); 02136 return; 02137 } 02138 02139 vc= &wpd->vc; 02140 ob= vc->obact; 02141 me= ob->data; 02142 indexar= wpd->indexar; 02143 02144 view3d_operator_needs_opengl(C); 02145 02146 /* load projection matrix */ 02147 mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); 02148 02149 RNA_float_get_array(itemptr, "mouse", mval); 02150 mval[0]-= vc->ar->winrct.xmin; 02151 mval[1]-= vc->ar->winrct.ymin; 02152 02153 02154 02155 /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ 02156 wpi.defbase_tot= wpd->defbase_tot; 02157 defbase_sel= MEM_mallocN(wpi.defbase_tot*sizeof(char), "wpi.defbase_sel"); 02158 wpi.defbase_tot_sel= get_selected_defgroups(ob, defbase_sel, wpi.defbase_tot); 02159 wpi.defbase_sel= defbase_sel; /* so we can stay const */ 02160 if(wpi.defbase_tot_sel == 0 && ob->actdef > 0) wpi.defbase_tot_sel = 1; 02161 02162 wpi.defbase_tot_unsel= wpi.defbase_tot - wpi.defbase_tot_sel; 02163 wpi.vgroup_active= wpd->vgroup_active; 02164 wpi.vgroup_mirror= wpd->vgroup_mirror; 02165 wpi.lock_flags= wpd->lock_flags; 02166 wpi.vgroup_validmap= wpd->vgroup_validmap; 02167 wpi.do_flip= RNA_boolean_get(itemptr, "pen_flip"); 02168 wpi.do_multipaint= (ts->multipaint != 0); 02169 wpi.do_auto_normalize= ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL)); 02170 wpi.brush_alpha_value= brush_alpha_value; 02171 /* *** done setting up WeightPaintInfo *** */ 02172 02173 02174 02175 swap_m4m4(wpd->vc.rv3d->persmat, mat); 02176 02177 use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 02178 02179 /* which faces are involved */ 02180 if(wp->flag & VP_AREA) { 02181 /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ 02182 me->editflag &= ~ME_EDIT_VERT_SEL; 02183 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size_pressure); 02184 me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0; 02185 } 02186 else { 02187 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); 02188 if(indexar[0]) totindex= 1; 02189 else totindex= 0; 02190 } 02191 02192 if(wp->flag & VP_COLINDEX) { 02193 for(index=0; index<totindex; index++) { 02194 if(indexar[index] && indexar[index]<=me->totface) { 02195 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); 02196 02197 if(mface->mat_nr!=ob->actcol-1) { 02198 indexar[index]= 0; 02199 } 02200 } 02201 } 02202 } 02203 02204 if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) { 02205 for(index=0; index<totindex; index++) { 02206 if(indexar[index] && indexar[index]<=me->totface) { 02207 MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); 02208 02209 if((mface->flag & ME_FACE_SEL)==0) { 02210 indexar[index]= 0; 02211 } 02212 } 02213 } 02214 } 02215 02216 /* make sure each vertex gets treated only once */ 02217 /* and calculate filter weight */ 02218 totw= 0.0f; 02219 if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) 02220 paintweight= 0.0f; 02221 else 02222 paintweight= ts->vgroup_weight; 02223 02224 for(index=0; index<totindex; index++) { 02225 if(indexar[index] && indexar[index]<=me->totface) { 02226 MFace *mface= me->mface + (indexar[index]-1); 02227 02228 if(use_vert_sel) { 02229 me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT); 02230 me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT); 02231 me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT); 02232 if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT); 02233 } 02234 else { 02235 me->dvert[mface->v1].flag= 1; 02236 me->dvert[mface->v2].flag= 1; 02237 me->dvert[mface->v3].flag= 1; 02238 if(mface->v4) me->dvert[mface->v4].flag= 1; 02239 } 02240 02241 if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { 02242 MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); 02243 unsigned int fidx= mface->v4 ? 3:2; 02244 02245 if(wp->flag & VP_ONLYVGROUP) 02246 dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index; 02247 else 02248 dw_func= defvert_verify_index; 02249 02250 do { 02251 unsigned int vidx= *(&mface->v1 + fidx); 02252 const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos+6*vidx, mval, brush_size_pressure); 02253 if (fac > 0.0f) { 02254 dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); 02255 paintweight += dw ? (dw->weight * fac) : 0.0f; 02256 totw += fac; 02257 } 02258 02259 } while (fidx--); 02260 02261 } 02262 } 02263 } 02264 02265 if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { 02266 paintweight /= totw; 02267 } 02268 02269 for(index=0; index<totindex; index++) { 02270 02271 if(indexar[index] && indexar[index]<=me->totface) { 02272 MFace *mf= me->mface + (indexar[index]-1); 02273 unsigned int fidx= mf->v4 ? 3:2; 02274 do { 02275 unsigned int vidx= *(&mf->v1 + fidx); 02276 02277 if(me->dvert[vidx].flag) { 02278 alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, 02279 mval, brush_size_pressure, brush_alpha_pressure); 02280 if(alpha) { 02281 do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); 02282 } 02283 me->dvert[vidx].flag= 0; 02284 } 02285 } while (fidx--); 02286 } 02287 } 02288 02289 02290 /* *** free wpi members */ 02291 MEM_freeN((void *)wpi.defbase_sel); 02292 /* *** dont freeing wpi members */ 02293 02294 02295 swap_m4m4(vc->rv3d->persmat, mat); 02296 02297 DAG_id_tag_update(ob->data, 0); 02298 ED_region_tag_redraw(vc->ar); 02299 } 02300 02301 static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke) 02302 { 02303 ToolSettings *ts= CTX_data_tool_settings(C); 02304 Object *ob= CTX_data_active_object(C); 02305 struct WPaintData *wpd= paint_stroke_mode_data(stroke); 02306 02307 if(wpd) { 02308 if(wpd->vertexcosnos) 02309 MEM_freeN(wpd->vertexcosnos); 02310 MEM_freeN(wpd->indexar); 02311 02312 if (wpd->vgroup_validmap) 02313 MEM_freeN((void *)wpd->vgroup_validmap); 02314 if(wpd->lock_flags) 02315 MEM_freeN((void *)wpd->lock_flags); 02316 02317 MEM_freeN(wpd); 02318 } 02319 02320 /* frees prev buffer */ 02321 copy_wpaint_prev(ts->wpaint, NULL, 0); 02322 02323 /* and particles too */ 02324 if(ob->particlesystem.first) { 02325 ParticleSystem *psys; 02326 int i; 02327 02328 for(psys= ob->particlesystem.first; psys; psys= psys->next) { 02329 for(i=0; i<PSYS_TOT_VG; i++) { 02330 if(psys->vgroup[i]==ob->actdef) { 02331 psys->recalc |= PSYS_RECALC_RESET; 02332 break; 02333 } 02334 } 02335 } 02336 } 02337 02338 DAG_id_tag_update(ob->data, 0); 02339 } 02340 02341 02342 static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) 02343 { 02344 02345 op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, 02346 wpaint_stroke_update_step, 02347 wpaint_stroke_done, event->type); 02348 02349 /* add modal handler */ 02350 WM_event_add_modal_handler(C, op); 02351 02352 op->type->modal(C, op, event); 02353 02354 return OPERATOR_RUNNING_MODAL; 02355 } 02356 02357 static int wpaint_cancel(bContext *C, wmOperator *op) 02358 { 02359 paint_stroke_cancel(C, op); 02360 02361 return OPERATOR_CANCELLED; 02362 } 02363 02364 void PAINT_OT_weight_paint(wmOperatorType *ot) 02365 { 02366 02367 /* identifiers */ 02368 ot->name= "Weight Paint"; 02369 ot->idname= "PAINT_OT_weight_paint"; 02370 02371 /* api callbacks */ 02372 ot->invoke= wpaint_invoke; 02373 ot->modal= paint_stroke_modal; 02374 /* ot->exec= vpaint_exec; <-- needs stroke property */ 02375 ot->poll= weight_paint_poll; 02376 ot->cancel= wpaint_cancel; 02377 02378 /* flags */ 02379 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 02380 02381 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); 02382 } 02383 02384 static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) 02385 { 02386 struct Scene *scene= CTX_data_scene(C); 02387 Object *obact = CTX_data_active_object(C); 02388 02389 wpaint_fill(scene->toolsettings->wpaint, obact, scene->toolsettings->vgroup_weight); 02390 ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ 02391 return OPERATOR_FINISHED; 02392 } 02393 02394 void PAINT_OT_weight_set(wmOperatorType *ot) 02395 { 02396 /* identifiers */ 02397 ot->name= "Set Weight"; 02398 ot->idname= "PAINT_OT_weight_set"; 02399 02400 /* api callbacks */ 02401 ot->exec= weight_paint_set_exec; 02402 ot->poll= mask_paint_poll; /* it was facemask_paint_poll */ 02403 02404 /* flags */ 02405 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02406 } 02407 02408 /* ************ set / clear vertex paint mode ********** */ 02409 02410 02411 static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ 02412 { 02413 Object *ob= CTX_data_active_object(C); 02414 Scene *scene= CTX_data_scene(C); 02415 VPaint *vp= scene->toolsettings->vpaint; 02416 Mesh *me; 02417 02418 me= get_mesh(ob); 02419 02420 if(me==NULL || object_data_is_libdata(ob)) { 02421 ob->mode &= ~OB_MODE_VERTEX_PAINT; 02422 return OPERATOR_PASS_THROUGH; 02423 } 02424 02425 if(me && me->mcol==NULL) make_vertexcol(ob); 02426 02427 /* toggle: end vpaint */ 02428 if(ob->mode & OB_MODE_VERTEX_PAINT) { 02429 02430 ob->mode &= ~OB_MODE_VERTEX_PAINT; 02431 } 02432 else { 02433 ob->mode |= OB_MODE_VERTEX_PAINT; 02434 /* Turn off weight painting */ 02435 if (ob->mode & OB_MODE_WEIGHT_PAINT) 02436 set_wpaint(C, op); 02437 02438 if(vp==NULL) 02439 vp= scene->toolsettings->vpaint= new_vpaint(0); 02440 02441 paint_cursor_start(C, vertex_paint_poll); 02442 02443 paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); 02444 } 02445 02446 if (me) 02447 /* update modifier stack for mapping requirements */ 02448 DAG_id_tag_update(&me->id, 0); 02449 02450 WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); 02451 02452 return OPERATOR_FINISHED; 02453 } 02454 02455 void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) 02456 { 02457 02458 /* identifiers */ 02459 ot->name= "Vertex Paint Mode"; 02460 ot->idname= "PAINT_OT_vertex_paint_toggle"; 02461 02462 /* api callbacks */ 02463 ot->exec= set_vpaint; 02464 ot->poll= paint_poll_test; 02465 02466 /* flags */ 02467 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02468 } 02469 02470 02471 02472 /* ********************** vertex paint operator ******************* */ 02473 02474 /* Implementation notes: 02475 02476 Operator->invoke() 02477 - validate context (add mcol) 02478 - create customdata storage 02479 - call paint once (mouse click) 02480 - add modal handler 02481 02482 Operator->modal() 02483 - for every mousemove, apply vertex paint 02484 - exit on mouse release, free customdata 02485 (return OPERATOR_FINISHED also removes handler and operator) 02486 02487 For future: 02488 - implement a stroke event (or mousemove with past positons) 02489 - revise whether op->customdata should be added in object, in set_vpaint 02490 02491 */ 02492 02493 typedef struct VPaintData { 02494 ViewContext vc; 02495 unsigned int paintcol; 02496 int *indexar; 02497 float *vertexcosnos; 02498 float vpimat[3][3]; 02499 } VPaintData; 02500 02501 static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event)) 02502 { 02503 ToolSettings *ts= CTX_data_tool_settings(C); 02504 struct PaintStroke *stroke = op->customdata; 02505 VPaint *vp= ts->vpaint; 02506 struct VPaintData *vpd; 02507 Object *ob= CTX_data_active_object(C); 02508 Mesh *me; 02509 float mat[4][4], imat[4][4]; 02510 02511 /* context checks could be a poll() */ 02512 me= get_mesh(ob); 02513 if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; 02514 02515 if(me->mcol==NULL) make_vertexcol(ob); 02516 if(me->mcol==NULL) return OPERATOR_CANCELLED; 02517 02518 /* make mode data storage */ 02519 vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); 02520 paint_stroke_set_mode_data(stroke, vpd); 02521 view3d_set_viewcontext(C, &vpd->vc); 02522 02523 vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob); 02524 vpd->indexar= get_indexarray(me); 02525 vpd->paintcol= vpaint_get_current_col(vp); 02526 02527 /* for filtering */ 02528 copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface); 02529 02530 /* some old cruft to sort out later */ 02531 mult_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat); 02532 invert_m4_m4(imat, mat); 02533 copy_m3_m4(vpd->vpimat, imat); 02534 02535 return 1; 02536 } 02537 02538 static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, 02539 const unsigned int index, const float mval[2], 02540 const float brush_size_pressure, const float brush_alpha_pressure, 02541 int UNUSED(flip)) 02542 { 02543 ViewContext *vc = &vpd->vc; 02544 Brush *brush = paint_brush(&vp->paint); 02545 Mesh *me = get_mesh(ob); 02546 MFace *mface= &me->mface[index]; 02547 unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index; 02548 unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index; 02549 float alpha; 02550 int i; 02551 02552 int brush_alpha_pressure_i; 02553 02554 if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) || 02555 ((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL))) 02556 return; 02557 02558 if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { 02559 unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128); 02560 if(mface->v4) { 02561 unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128); 02562 vpd->paintcol= mcol_blend( fcol1, fcol2, 128); 02563 } 02564 else { 02565 vpd->paintcol= mcol_blend( mcol[2], fcol1, 170); 02566 } 02567 } 02568 02569 brush_alpha_pressure_i = (int)(brush_alpha_pressure*255.0f); 02570 02571 for(i = 0; i < (mface->v4 ? 4 : 3); ++i) { 02572 alpha = calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], 02573 mval, brush_size_pressure, brush_alpha_pressure); 02574 if (alpha) { 02575 const int alpha_i = (int)(alpha*255.0f); 02576 mcol[i] = vpaint_blend(vp, mcol[i], mcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i); 02577 } 02578 } 02579 } 02580 02581 static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) 02582 { 02583 Scene *scene= CTX_data_scene(C); 02584 ToolSettings *ts= CTX_data_tool_settings(C); 02585 struct VPaintData *vpd = paint_stroke_mode_data(stroke); 02586 VPaint *vp= ts->vpaint; 02587 Brush *brush = paint_brush(&vp->paint); 02588 ViewContext *vc= &vpd->vc; 02589 Object *ob= vc->obact; 02590 Mesh *me= ob->data; 02591 float mat[4][4]; 02592 int *indexar= vpd->indexar; 02593 int totindex, index, flip; 02594 float mval[2]; 02595 02596 const float pressure = RNA_float_get(itemptr, "pressure"); 02597 const float brush_size_pressure = brush_size(scene, brush) * (brush_use_size_pressure(scene, brush) ? pressure : 1.0f); 02598 const float brush_alpha_pressure = brush_alpha(scene, brush) * (brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f); 02599 02600 RNA_float_get_array(itemptr, "mouse", mval); 02601 flip = RNA_boolean_get(itemptr, "pen_flip"); 02602 02603 view3d_operator_needs_opengl(C); 02604 02605 /* load projection matrix */ 02606 mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); 02607 02608 mval[0]-= vc->ar->winrct.xmin; 02609 mval[1]-= vc->ar->winrct.ymin; 02610 02611 02612 /* which faces are involved */ 02613 if(vp->flag & VP_AREA) { 02614 totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size_pressure); 02615 } 02616 else { 02617 indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); 02618 if(indexar[0]) totindex= 1; 02619 else totindex= 0; 02620 } 02621 02622 swap_m4m4(vc->rv3d->persmat, mat); 02623 02624 for(index=0; index<totindex; index++) { 02625 if (indexar[index] && indexar[index]<=me->totface) { 02626 vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, brush_size_pressure, brush_alpha_pressure, flip); 02627 } 02628 } 02629 02630 swap_m4m4(vc->rv3d->persmat, mat); 02631 02632 /* was disabled because it is slow, but necessary for blur */ 02633 if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) 02634 do_shared_vertexcol(me); 02635 02636 ED_region_tag_redraw(vc->ar); 02637 02638 DAG_id_tag_update(ob->data, 0); 02639 } 02640 02641 static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) 02642 { 02643 ToolSettings *ts= CTX_data_tool_settings(C); 02644 struct VPaintData *vpd= paint_stroke_mode_data(stroke); 02645 02646 if(vpd->vertexcosnos) 02647 MEM_freeN(vpd->vertexcosnos); 02648 MEM_freeN(vpd->indexar); 02649 02650 /* frees prev buffer */ 02651 copy_vpaint_prev(ts->vpaint, NULL, 0); 02652 02653 MEM_freeN(vpd); 02654 } 02655 02656 static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) 02657 { 02658 02659 op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, 02660 vpaint_stroke_update_step, 02661 vpaint_stroke_done, event->type); 02662 02663 /* add modal handler */ 02664 WM_event_add_modal_handler(C, op); 02665 02666 op->type->modal(C, op, event); 02667 02668 return OPERATOR_RUNNING_MODAL; 02669 } 02670 02671 static int vpaint_cancel(bContext *C, wmOperator *op) 02672 { 02673 paint_stroke_cancel(C, op); 02674 02675 return OPERATOR_CANCELLED; 02676 } 02677 02678 void PAINT_OT_vertex_paint(wmOperatorType *ot) 02679 { 02680 /* identifiers */ 02681 ot->name= "Vertex Paint"; 02682 ot->idname= "PAINT_OT_vertex_paint"; 02683 02684 /* api callbacks */ 02685 ot->invoke= vpaint_invoke; 02686 ot->modal= paint_stroke_modal; 02687 /* ot->exec= vpaint_exec; <-- needs stroke property */ 02688 ot->poll= vertex_paint_poll; 02689 ot->cancel= vpaint_cancel; 02690 02691 /* flags */ 02692 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 02693 02694 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); 02695 } 02696 02697 /* ********************** weight from bones operator ******************* */ 02698 02699 static int weight_from_bones_poll(bContext *C) 02700 { 02701 Object *ob= CTX_data_active_object(C); 02702 02703 return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); 02704 } 02705 02706 static int weight_from_bones_exec(bContext *C, wmOperator *op) 02707 { 02708 Scene *scene= CTX_data_scene(C); 02709 Object *ob= CTX_data_active_object(C); 02710 Object *armob= modifiers_isDeformedByArmature(ob); 02711 Mesh *me= ob->data; 02712 int type= RNA_enum_get(op->ptr, "type"); 02713 02714 create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X)); 02715 02716 DAG_id_tag_update(&me->id, 0); 02717 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); 02718 02719 return OPERATOR_FINISHED; 02720 } 02721 02722 void PAINT_OT_weight_from_bones(wmOperatorType *ot) 02723 { 02724 static EnumPropertyItem type_items[]= { 02725 {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights froms bones"}, 02726 {ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"}, 02727 {0, NULL, 0, NULL, NULL}}; 02728 02729 /* identifiers */ 02730 ot->name= "Weight from Bones"; 02731 ot->idname= "PAINT_OT_weight_from_bones"; 02732 02733 /* api callbacks */ 02734 ot->exec= weight_from_bones_exec; 02735 ot->invoke= WM_menu_invoke; 02736 ot->poll= weight_from_bones_poll; 02737 02738 /* flags */ 02739 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02740 02741 /* properties */ 02742 ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); 02743 } 02744